summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-09-30 10:41:09 +0200
committerThomas Haller <thaller@redhat.com>2020-09-30 10:41:09 +0200
commit77ad359442c9d5b8f00435130b7de10935728316 (patch)
tree4af64255ddf9244d2f94945f04f2b97b94ec917b
parent1c3f7d823e17dbfc26ab11ef8943135b2c6961c5 (diff)
parente83a6f5898eec620a3d2e49c267cac618b9deee9 (diff)
downloadNetworkManager-77ad359442c9d5b8f00435130b7de10935728316.tar.gz
l3cfg: merge branch 'th/l3cfg-11'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/637
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h136
-rw-r--r--shared/nm-std-aux/nm-std-aux.h120
-rw-r--r--src/nm-l3-config-data.c80
-rw-r--r--src/nm-l3-config-data.h18
-rw-r--r--src/nm-l3cfg.c336
-rw-r--r--src/nm-l3cfg.h75
-rw-r--r--src/nm-netns.c9
-rw-r--r--src/platform/nm-linux-platform.c5
-rw-r--r--src/platform/nm-platform.c524
-rw-r--r--src/platform/nm-platform.h148
-rw-r--r--src/tests/test-l3cfg.c52
11 files changed, 893 insertions, 610 deletions
diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h
index d3a7194212..06e442f5f1 100644
--- a/shared/nm-glib-aux/nm-shared-utils.h
+++ b/shared/nm-glib-aux/nm-shared-utils.h
@@ -96,6 +96,22 @@ typedef struct {
.ether_addr_octet = {__VA_ARGS__}, \
}
+static inline int
+nm_ether_addr_cmp(const NMEtherAddr *a, const NMEtherAddr *b)
+{
+ NM_CMP_SELF(a, b);
+ NM_CMP_DIRECT_MEMCMP(a, b, sizeof(NMEtherAddr));
+ return 0;
+}
+
+static inline gboolean
+nm_ether_addr_equal(const NMEtherAddr *a, const NMEtherAddr *b)
+{
+ return nm_ether_addr_cmp(a, b) == 0;
+}
+
+/*****************************************************************************/
+
typedef struct {
union {
guint8 addr_ptr[1];
@@ -248,126 +264,6 @@ gboolean nm_utils_ipaddr_is_normalized(int addr_family, const char *str_addr);
/*****************************************************************************/
-#define NM_CMP_RETURN(c) \
- G_STMT_START \
- { \
- const int _cc = (c); \
- if (_cc) \
- return _cc < 0 ? -1 : 1; \
- } \
- G_STMT_END
-
-#define NM_CMP_RETURN_DIRECT(c) \
- G_STMT_START \
- { \
- const int _cc = (c); \
- if (_cc) \
- return _cc; \
- } \
- G_STMT_END
-
-#define NM_CMP_SELF(a, b) \
- G_STMT_START \
- { \
- typeof(a) _a = (a); \
- typeof(b) _b = (b); \
- \
- if (_a == _b) \
- return 0; \
- if (!_a) \
- return -1; \
- if (!_b) \
- return 1; \
- } \
- G_STMT_END
-
-#define NM_CMP_DIRECT(a, b) \
- G_STMT_START \
- { \
- typeof(a) _a = (a); \
- typeof(b) _b = (b); \
- \
- if (_a != _b) \
- return (_a < _b) ? -1 : 1; \
- } \
- G_STMT_END
-
-#define NM_CMP_DIRECT_UNSAFE(a, b) \
- G_STMT_START \
- { \
- if ((a) != (b)) \
- return ((a) < (b)) ? -1 : 1; \
- } \
- G_STMT_END
-
-/* In the general case, direct pointer comparison is undefined behavior in C.
- * Avoid that by casting pointers to void* and then to uintptr_t. This comparison
- * is not really meaningful, except that it provides some kind of stable sort order
- * between pointers (that can otherwise not be compared). */
-#define NM_CMP_DIRECT_PTR(a, b) NM_CMP_DIRECT((uintptr_t)((void *) (a)), (uintptr_t)((void *) (b)))
-
-#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size)))
-
-#define NM_CMP_DIRECT_STRCMP(a, b) NM_CMP_RETURN_DIRECT(strcmp((a), (b)))
-
-#define NM_CMP_DIRECT_STRCMP0(a, b) NM_CMP_RETURN_DIRECT(nm_strcmp0((a), (b)))
-
-#define NM_CMP_DIRECT_IN6ADDR(a, b) \
- G_STMT_START \
- { \
- const struct in6_addr *const _a = (a); \
- const struct in6_addr *const _b = (b); \
- NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
- } \
- G_STMT_END
-
-#define NM_CMP_FIELD(a, b, field) NM_CMP_DIRECT(((a)->field), ((b)->field))
-
-#define NM_CMP_FIELD_UNSAFE(a, b, field) \
- G_STMT_START \
- { \
- /* it's unsafe, because it evaluates the arguments more then once.
- * This is necessary for bitfields, for which typeof() doesn't work. */ \
- if (((a)->field) != ((b)->field)) \
- return ((a)->field < ((b)->field)) ? -1 : 1; \
- } \
- G_STMT_END
-
-#define NM_CMP_FIELD_BOOL(a, b, field) NM_CMP_DIRECT(!!((a)->field), !!((b)->field))
-
-#define NM_CMP_FIELD_STR(a, b, field) NM_CMP_RETURN(strcmp(((a)->field), ((b)->field)))
-
-#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \
- G_STMT_START \
- { \
- const char *_a = ((a)->field); \
- const char *_b = ((b)->field); \
- \
- if (_a != _b) { \
- NM_CMP_RETURN_DIRECT(nm_strcmp0(_a, _b)); \
- } \
- } \
- G_STMT_END
-
-#define NM_CMP_FIELD_STR0(a, b, field) NM_CMP_RETURN_DIRECT(nm_strcmp0(((a)->field), ((b)->field)))
-
-#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \
- NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), NM_MIN(len, sizeof((a)->field))))
-
-#define NM_CMP_FIELD_MEMCMP(a, b, field) \
- NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), sizeof((a)->field)))
-
-#define NM_CMP_FIELD_IN6ADDR(a, b, field) \
- G_STMT_START \
- { \
- const struct in6_addr *const _a = &((a)->field); \
- const struct in6_addr *const _b = &((b)->field); \
- NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
- } \
- G_STMT_END
-
-/*****************************************************************************/
-
gboolean nm_utils_memeqzero(gconstpointer data, gsize length);
/*****************************************************************************/
diff --git a/shared/nm-std-aux/nm-std-aux.h b/shared/nm-std-aux/nm-std-aux.h
index 9a5b217238..762f104be3 100644
--- a/shared/nm-std-aux/nm-std-aux.h
+++ b/shared/nm-std-aux/nm-std-aux.h
@@ -6,6 +6,7 @@
#include <assert.h>
#include <string.h>
#include <stdbool.h>
+#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
@@ -43,6 +44,23 @@
/*****************************************************************************/
+#ifdef __CHECKER__
+ #define _nm_bitwise __attribute__((__bitwise__))
+ #define _nm_force __attribute__((__force__))
+#else
+ #define _nm_bitwise
+ #define _nm_force
+#endif
+
+typedef uint16_t _nm_bitwise nm_le16_t;
+typedef uint16_t _nm_bitwise nm_be16_t;
+typedef uint32_t _nm_bitwise nm_le32_t;
+typedef uint32_t _nm_bitwise nm_be32_t;
+typedef uint64_t _nm_bitwise nm_le64_t;
+typedef uint64_t _nm_bitwise nm_be64_t;
+
+/*****************************************************************************/
+
#ifdef thread_local
#define _nm_thread_local thread_local
/*
@@ -749,6 +767,108 @@ nm_steal_fd(int *p_fd)
/*****************************************************************************/
+#define NM_CMP_RETURN(c) \
+ do { \
+ const int _cc = (c); \
+ if (_cc) \
+ return _cc < 0 ? -1 : 1; \
+ } while (0)
+
+#define NM_CMP_RETURN_DIRECT(c) \
+ do { \
+ const int _cc = (c); \
+ if (_cc) \
+ return _cc; \
+ } while (0)
+
+#define NM_CMP_SELF(a, b) \
+ do { \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ \
+ if (_a == _b) \
+ return 0; \
+ if (!_a) \
+ return -1; \
+ if (!_b) \
+ return 1; \
+ } while (0)
+
+#define NM_CMP_DIRECT(a, b) \
+ do { \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ \
+ if (_a != _b) \
+ return (_a < _b) ? -1 : 1; \
+ } while (0)
+
+#define NM_CMP_DIRECT_UNSAFE(a, b) \
+ do { \
+ if ((a) != (b)) \
+ return ((a) < (b)) ? -1 : 1; \
+ } while (0)
+
+/* In the general case, direct pointer comparison is undefined behavior in C.
+ * Avoid that by casting pointers to void* and then to uintptr_t. This comparison
+ * is not really meaningful, except that it provides some kind of stable sort order
+ * between pointers (that can otherwise not be compared). */
+#define NM_CMP_DIRECT_PTR(a, b) NM_CMP_DIRECT((uintptr_t)((void *) (a)), (uintptr_t)((void *) (b)))
+
+#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size)))
+
+#define NM_CMP_DIRECT_STRCMP(a, b) NM_CMP_RETURN_DIRECT(strcmp((a), (b)))
+
+#define NM_CMP_DIRECT_STRCMP0(a, b) NM_CMP_RETURN_DIRECT(nm_strcmp0((a), (b)))
+
+#define NM_CMP_DIRECT_IN6ADDR(a, b) \
+ do { \
+ const struct in6_addr *const _a = (a); \
+ const struct in6_addr *const _b = (b); \
+ NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
+ } while (0)
+
+#define NM_CMP_FIELD(a, b, field) NM_CMP_DIRECT(((a)->field), ((b)->field))
+
+#define NM_CMP_FIELD_UNSAFE(a, b, field) \
+ do { \
+ /* it's unsafe, because it evaluates the arguments more then once.
+ * This is necessary for bitfields, for which typeof() doesn't work. */ \
+ if (((a)->field) != ((b)->field)) \
+ return ((a)->field < ((b)->field)) ? -1 : 1; \
+ } while (0)
+
+#define NM_CMP_FIELD_BOOL(a, b, field) NM_CMP_DIRECT(!!((a)->field), !!((b)->field))
+
+#define NM_CMP_FIELD_STR(a, b, field) NM_CMP_RETURN(strcmp(((a)->field), ((b)->field)))
+
+#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \
+ do { \
+ const char *_a = ((a)->field); \
+ const char *_b = ((b)->field); \
+ \
+ if (_a != _b) { \
+ NM_CMP_RETURN_DIRECT(nm_strcmp0(_a, _b)); \
+ } \
+ } while (0)
+
+#define NM_CMP_FIELD_STR0(a, b, field) NM_CMP_RETURN_DIRECT(nm_strcmp0(((a)->field), ((b)->field)))
+
+#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \
+ NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), NM_MIN(len, sizeof((a)->field))))
+
+#define NM_CMP_FIELD_MEMCMP(a, b, field) \
+ NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), sizeof((a)->field)))
+
+#define NM_CMP_FIELD_IN6ADDR(a, b, field) \
+ do { \
+ const struct in6_addr *const _a = &((a)->field); \
+ const struct in6_addr *const _b = &((b)->field); \
+ NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
+ } while (0)
+
+/*****************************************************************************/
+
#define NM_AF_UNSPEC 0 /* AF_UNSPEC */
#define NM_AF_INET 2 /* AF_INET */
#define NM_AF_INET6 10 /* AF_INET6 */
diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c
index c73036ebd8..3cc5d67041 100644
--- a/src/nm-l3-config-data.c
+++ b/src/nm-l3-config-data.c
@@ -2514,17 +2514,34 @@ void
nm_l3_config_data_merge(NML3ConfigData * self,
const NML3ConfigData *src,
NML3ConfigMergeFlags merge_flags,
+ const guint32 * default_route_table_x /* length 2, for IS_IPv4 */,
+ const guint32 * default_route_metric_x /* length 2, for IS_IPv4 */,
const guint32 * default_route_penalty_x /* length 2, for IS_IPv4 */,
NML3ConfigMergeHookAddObj hook_add_addr,
gpointer hook_user_data)
{
- NMDedupMultiIter iter;
- const NMPObject *obj;
- int IS_IPv4;
+ static const guint32 x_default_route_table_x[2] = {RT_TABLE_MAIN, RT_TABLE_MAIN};
+ static const guint32 x_default_route_metric_x[2] = {NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
+ NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4};
+ static const guint32 x_default_route_penalty_x[2] = {0, 0};
+ NMDedupMultiIter iter;
+ const NMPObject * obj;
+ int IS_IPv4;
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
nm_assert(_NM_IS_L3_CONFIG_DATA(src, TRUE));
+ if (!default_route_table_x)
+ default_route_table_x = x_default_route_table_x;
+ if (!default_route_metric_x)
+ default_route_metric_x = x_default_route_metric_x;
+ if (!default_route_penalty_x)
+ default_route_penalty_x = x_default_route_penalty_x;
+
+ nm_assert(default_route_table_x[0] != 0);
+ nm_assert(default_route_table_x[1] != 0);
+ nm_assert(default_route_metric_x[0] != 0); /* IPv6 route metric cannot be zero. */
+
for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
const int addr_family = IS_IPv4 ? AF_INET : AF_INET6;
const NML3ConfigDatFlags has_dns_priority_flag =
@@ -2546,41 +2563,58 @@ nm_l3_config_data_merge(NML3ConfigData * self,
if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES)) {
nm_l3_config_data_iter_obj_for_each(&iter, src, &obj, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))
{
- if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(NMP_OBJECT_CAST_IP_ROUTE(obj))) {
+ const NMPlatformIPRoute *r_src = NMP_OBJECT_CAST_IP_ROUTE(obj);
+ NMPlatformIPXRoute r;
+
+#define _ensure_r() \
+ G_STMT_START \
+ { \
+ if (r_src != &r.rx) { \
+ r_src = &r.rx; \
+ if (IS_IPv4) \
+ r.r4 = *NMP_OBJECT_CAST_IP4_ROUTE(obj); \
+ else \
+ r.r6 = *NMP_OBJECT_CAST_IP6_ROUTE(obj); \
+ r.rx.ifindex = self->ifindex; \
+ } \
+ } \
+ G_STMT_END
+
+ if (r_src->table_any) {
+ _ensure_r();
+ r.rx.table_any = FALSE;
+ r.rx.table_coerced = default_route_table_x[IS_IPv4];
+ }
+
+ if (r_src->metric_any) {
+ _ensure_r();
+ r.rx.metric_any = FALSE;
+ r.rx.metric_any = default_route_metric_x[IS_IPv4];
+ }
+
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) {
if (NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES)
&& !NM_FLAGS_HAS(src->flags,
NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES))
continue;
-
if (default_route_penalty_x && default_route_penalty_x[IS_IPv4] > 0) {
- NMPlatformIPXRoute r;
-
- if (IS_IPv4)
- r.r4 = *NMP_OBJECT_CAST_IP4_ROUTE(obj);
- else
- r.r6 = *NMP_OBJECT_CAST_IP6_ROUTE(obj);
- r.rx.ifindex = self->ifindex;
+ _ensure_r();
r.rx.metric =
nm_utils_ip_route_metric_penalize(r.rx.metric,
default_route_penalty_x[IS_IPv4]);
- nm_l3_config_data_add_route_full(self,
- addr_family,
- NULL,
- &r.rx,
- NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE,
- NULL,
- NULL);
- continue;
}
}
+
nm_l3_config_data_add_route_full(self,
addr_family,
- obj,
- NULL,
+ r_src == &r.rx ? NULL : obj,
+ r_src == &r.rx ? r_src : NULL,
NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE,
NULL,
NULL);
}
+
+#undef _ensure_r
}
if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS))
@@ -2666,6 +2700,6 @@ nm_l3_config_data_new_clone(const NML3ConfigData *src, int ifindex)
ifindex = src->ifindex;
self = nm_l3_config_data_new(src->multi_idx, ifindex);
- nm_l3_config_data_merge(self, src, NM_L3_CONFIG_MERGE_FLAGS_NONE, NULL, NULL, NULL);
+ nm_l3_config_data_merge(self, src, NM_L3_CONFIG_MERGE_FLAGS_NONE, NULL, NULL, NULL, NULL, NULL);
return self;
}
diff --git a/src/nm-l3-config-data.h b/src/nm-l3-config-data.h
index a91b0dc2d5..81dae7dea4 100644
--- a/src/nm-l3-config-data.h
+++ b/src/nm-l3-config-data.h
@@ -46,6 +46,15 @@ typedef enum {
/**
* NML3ConfigMergeFlags:
* @NM_L3_CONFIG_MERGE_FLAGS_NONE: no flags set
+ * @NM_L3_CONFIG_MERGE_FLAGS_ONLY_FOR_ACD: if this merge flag is set,
+ * the the NML3ConfigData doesn't get merged and it's information won't be
+ * synced. The only purpose is to run ACD on its IPv4 addresses, but
+ * regardless whether ACD succeeds/fails, the IP addresses won't be configured.
+ * The point is to run ACD first (without configuring it), and only
+ * commit the settings if requested. That can either happen by
+ * nm_l3cfg_add_config() the same NML3Cfg again (with a different
+ * tag), or by calling nm_l3cfg_add_config() again with this flag
+ * cleared (and the same tag).
* @NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES: don't merge routes
* @NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES: don't merge default routes.
* Note that if the respective NML3ConfigData has NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES
@@ -54,9 +63,10 @@ typedef enum {
*/
typedef enum _nm_packed {
NM_L3_CONFIG_MERGE_FLAGS_NONE = 0,
- NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES = (1LL << 0),
- NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES = (1LL << 1),
- NM_L3_CONFIG_MERGE_FLAGS_NO_DNS = (1LL << 2),
+ NM_L3_CONFIG_MERGE_FLAGS_ONLY_FOR_ACD = (1LL << 0),
+ NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES = (1LL << 1),
+ NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES = (1LL << 2),
+ NM_L3_CONFIG_MERGE_FLAGS_NO_DNS = (1LL << 3),
} NML3ConfigMergeFlags;
/*****************************************************************************/
@@ -136,6 +146,8 @@ typedef gboolean (*NML3ConfigMergeHookAddObj)(const NML3ConfigData *l3cd,
void nm_l3_config_data_merge(NML3ConfigData * self,
const NML3ConfigData *src,
NML3ConfigMergeFlags merge_flags,
+ const guint32 *default_route_table_x /* length 2, for IS_IPv4 */,
+ const guint32 *default_route_metric_x /* length 2, for IS_IPv4 */,
const guint32 *default_route_penalty_x /* length 2, for IS_IPv4 */,
NML3ConfigMergeHookAddObj hook_add_addr,
gpointer hook_user_data);
diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c
index c54db03dce..36aaf0fdc2 100644
--- a/src/nm-l3cfg.c
+++ b/src/nm-l3cfg.c
@@ -6,6 +6,7 @@
#include <net/if.h>
#include <linux/if_addr.h>
+#include <linux/rtnetlink.h>
#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
@@ -113,6 +114,20 @@ typedef struct {
NML3ConfigMergeFlags merge_flags;
union {
struct {
+ guint32 default_route_table_6;
+ guint32 default_route_table_4;
+ };
+ guint32 default_route_table_x[2];
+ };
+ union {
+ struct {
+ guint32 default_route_metric_6;
+ guint32 default_route_metric_4;
+ };
+ guint32 default_route_metric_x[2];
+ };
+ union {
+ struct {
guint32 default_route_penalty_6;
guint32 default_route_penalty_4;
};
@@ -163,7 +178,7 @@ typedef struct _NML3CfgPrivate {
/* This is for rate-limiting the creation of nacd instance. */
GSource *nacd_instance_ensure_retry;
- GSource *acd_ready_on_idle_source;
+ GSource *commit_on_idle_source;
guint64 pseudo_timestamp_counter;
@@ -232,6 +247,8 @@ G_DEFINE_TYPE(NML3Cfg, nm_l3cfg, G_TYPE_OBJECT)
/*****************************************************************************/
+static void _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle);
+
static void _property_emit_notify(NML3Cfg *self, NML3CfgPropertyEmitType emit_type);
static void _l3_acd_data_notify_acd_completed_all(NML3Cfg *self);
@@ -266,6 +283,7 @@ static NM_UTILS_ENUM2STR_DEFINE(
_l3_config_notify_type_to_string,
NML3ConfigNotifyType,
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED, "acd-complete"),
+ NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE, "platform-change"),
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, "platform-change-on-idle"),
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, "post-commit"),
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
@@ -275,10 +293,9 @@ static NM_UTILS_ENUM2STR_DEFINE(
/*****************************************************************************/
static const char *
-_l3_config_notify_type_and_payload_to_string(NML3ConfigNotifyType notify_type,
- const NML3ConfigNotifyPayload *payload,
- char * sbuf,
- gsize sbuf_size)
+_l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data,
+ char * sbuf,
+ gsize sbuf_size)
{
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
char *s = sbuf;
@@ -287,22 +304,31 @@ _l3_config_notify_type_and_payload_to_string(NML3ConfigNotifyType noti
nm_assert(sbuf);
nm_assert(sbuf_size > 0);
- _l3_config_notify_type_to_string(notify_type, s, l);
+ _l3_config_notify_type_to_string(notify_data->notify_type, s, l);
nm_utils_strbuf_seek_end(&s, &l);
- switch (notify_type) {
+ switch (notify_data->notify_type) {
case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
nm_utils_strbuf_append(&s,
&l,
", addr=%s, probe-result=%d",
- _nm_utils_inet4_ntop(payload->acd_completed.addr, sbuf_addr),
- (int) payload->acd_completed.probe_result);
+ _nm_utils_inet4_ntop(notify_data->acd_completed.addr, sbuf_addr),
+ (int) notify_data->acd_completed.probe_result);
+ break;
+ case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE:
+ nm_utils_strbuf_append(
+ &s,
+ &l,
+ ", obj-type=%s, change=%s, obj=",
+ NMP_OBJECT_GET_CLASS(notify_data->platform_change.obj)->obj_type_name,
+ nm_platform_signal_change_type_to_string(notify_data->platform_change.change_type));
+ nmp_object_to_string(notify_data->platform_change.obj, NMP_OBJECT_TO_STRING_PUBLIC, s, l);
break;
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE:
nm_utils_strbuf_append(&s,
&l,
", obj-type-flags=0x%x",
- payload->platform_change_on_idle.obj_type_flags);
+ notify_data->platform_change_on_idle.obj_type_flags);
break;
default:
break;
@@ -312,23 +338,26 @@ _l3_config_notify_type_and_payload_to_string(NML3ConfigNotifyType noti
}
void
-_nm_l3cfg_emit_signal_notify(NML3Cfg * self,
- NML3ConfigNotifyType notify_type,
- const NML3ConfigNotifyPayload *payload)
+_nm_l3cfg_emit_signal_notify(NML3Cfg *self, const NML3ConfigNotifyData *notify_data)
{
- char sbuf[100];
+ char sbuf[sizeof(_nm_utils_to_string_buffer)];
- nm_assert(_NM_INT_NOT_NEGATIVE(notify_type));
- nm_assert(notify_type < _NM_L3_CONFIG_NOTIFY_TYPE_NUM);
- nm_assert((!!payload)
- == NM_IN_SET(notify_type,
- NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED,
- NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE));
+ nm_assert(notify_data);
+ nm_assert(_NM_INT_NOT_NEGATIVE(notify_data->notify_type));
+ nm_assert(notify_data->notify_type < _NM_L3_CONFIG_NOTIFY_TYPE_NUM);
- _LOGT("emit signal (%s)",
- _l3_config_notify_type_and_payload_to_string(notify_type, payload, sbuf, sizeof(sbuf)));
+ _LOGT("emit signal (%s)", _l3_config_notify_data_to_string(notify_data, sbuf, sizeof(sbuf)));
- g_signal_emit(self, signals[SIGNAL_NOTIFY], 0, (int) notify_type, payload);
+ g_signal_emit(self, signals[SIGNAL_NOTIFY], 0, notify_data);
+}
+
+static void
+_nm_l3cfg_emit_signal_notify_simple(NML3Cfg *self, NML3ConfigNotifyType notify_type)
+{
+ NML3ConfigNotifyData notify_data;
+
+ notify_data.notify_type = notify_type;
+ _nm_l3cfg_emit_signal_notify(self, &notify_data);
}
/*****************************************************************************/
@@ -581,13 +610,19 @@ _load_link(NML3Cfg *self, gboolean initial)
gboolean nacd_link_now_up;
AcdData * acd_data;
- obj = nm_platform_link_get_obj(self->priv.platform, self->priv.ifindex, TRUE);
+ if (initial) {
+ obj = nm_platform_link_get_obj(self->priv.platform, self->priv.ifindex, TRUE);
+ self->priv.plobj_next = nmp_object_ref(obj);
+ } else {
+ obj = self->priv.plobj_next;
+ nm_assert(obj == nm_platform_link_get_obj(self->priv.platform, self->priv.ifindex, TRUE));
+ }
- if (initial && obj == self->priv.pllink)
+ if (initial && obj == self->priv.plobj)
return;
- obj_old = g_steal_pointer(&self->priv.pllink);
- self->priv.pllink = nmp_object_ref(obj);
+ obj_old = g_steal_pointer(&self->priv.plobj);
+ self->priv.plobj = nmp_object_ref(obj);
if (obj && NM_FLAGS_HAS(NMP_OBJECT_CAST_LINK(obj)->n_ifi_flags, IFF_UP)
&& (!obj_old || !NM_FLAGS_HAS(NMP_OBJECT_CAST_LINK(obj_old)->n_ifi_flags, IFF_UP)))
@@ -613,7 +648,7 @@ _load_link(NML3Cfg *self, gboolean initial)
} else if (nacd_new_valid)
nacd_changed = TRUE;
ifname_old = nmp_object_link_get_ifname(obj_old);
- ifname = nmp_object_link_get_ifname(self->priv.pllink);
+ ifname = nmp_object_link_get_ifname(self->priv.plobj);
if (initial) {
_LOGT("link ifname changed: %s%s%s (initial)", NM_PRINT_FMT_QUOTE_STRING(ifname));
@@ -641,18 +676,16 @@ _load_link(NML3Cfg *self, gboolean initial)
void
_nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint32 obj_type_flags)
{
- NML3ConfigNotifyPayload payload;
+ NML3ConfigNotifyData notify_data;
- if (NM_FLAGS_ANY(obj_type_flags, nmp_object_type_to_flags(NMP_OBJECT_TYPE_LINK)))
+ if (self->priv.plobj_next != self->priv.plobj)
_load_link(self, FALSE);
- payload = (NML3ConfigNotifyPayload){
- .platform_change_on_idle =
- {
- .obj_type_flags = obj_type_flags,
- },
+ notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE;
+ notify_data.platform_change_on_idle = (typeof(notify_data.platform_change_on_idle)){
+ .obj_type_flags = obj_type_flags,
};
- _nm_l3cfg_emit_signal_notify(self, NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, &payload);
+ _nm_l3cfg_emit_signal_notify(self, &notify_data);
_l3_acd_data_notify_acd_completed_all(self);
@@ -667,9 +700,23 @@ _nm_l3cfg_notify_platform_change(NML3Cfg * self,
NMPlatformSignalChangeType change_type,
const NMPObject * obj)
{
+ NML3ConfigNotifyData notify_data;
+ NMPObjectType obj_type;
+
nm_assert(NMP_OBJECT_IS_VALID(obj));
- switch (NMP_OBJECT_GET_TYPE(obj)) {
+ obj_type = NMP_OBJECT_GET_TYPE(obj);
+
+ switch (obj_type) {
+ case NMP_OBJECT_TYPE_LINK:
+ {
+ const NMPObject *plobj;
+
+ plobj = (change_type != NM_PLATFORM_SIGNAL_REMOVED) ? obj : NULL;
+ nm_assert(plobj == nm_platform_link_get_obj(self->priv.platform, self->priv.ifindex, TRUE));
+ nmp_object_ref_set(&self->priv.plobj_next, plobj);
+ break;
+ }
case NMP_OBJECT_TYPE_IP4_ADDRESS:
_l3_acd_ipv4_addresses_on_link_update(self,
NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address,
@@ -682,6 +729,15 @@ _nm_l3cfg_notify_platform_change(NML3Cfg * self,
default:
break;
}
+
+ notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE;
+ notify_data.platform_change = (typeof(notify_data.platform_change)){
+ .obj = obj,
+ .change_type = change_type,
+ };
+ _nm_l3cfg_emit_signal_notify(self, &notify_data);
+
+ nm_assert(NMP_OBJECT_IS_VALID(obj));
}
/*****************************************************************************/
@@ -920,18 +976,6 @@ _acd_data_find_track(const AcdData * acd_data,
/*****************************************************************************/
-static void
-_l3_acd_platform_commit_acd_update(NML3Cfg *self)
-{
- /* The idea with NML3Cfg is that multiple users (NMDevice/NMVpnConnection) share one layer 3 configuration
- * and push their (portion of) IP configuration to it. That implies, that any user may issue nm_l3cfg_platform_commit()
- * at any time, in order to say that a new configuration is ready.
- *
- * This makes the mechanism also suitable for internally triggering a commit when ACD completes. */
- _LOGT("acd: acd update now");
- nm_l3cfg_platform_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
-}
-
static gboolean
_acd_has_valid_link(const NMPObject *obj,
const guint8 ** out_addr_bin,
@@ -1035,9 +1079,9 @@ _l3_acd_nacd_event(int fd, GIOCondition condition, gpointer user_data)
_LOGW("IPv4 address collision detection sees conflict on interface %i%s%s%s for "
"address %s from host %s",
self->priv.ifindex,
- NM_PRINT_FMT_QUOTED(self->priv.pllink,
+ NM_PRINT_FMT_QUOTED(self->priv.plobj,
" (",
- NMP_OBJECT_CAST_LINK(self->priv.pllink)->name,
+ NMP_OBJECT_CAST_LINK(self->priv.plobj)->name,
")",
""),
addr_str ?: _nm_utils_inet4_ntop(acd_data->addr, sbuf_addr),
@@ -1084,8 +1128,7 @@ _l3_acd_nacd_instance_ensure_retry_cb(gpointer user_data)
nm_clear_g_source_inst(&self->priv.p->nacd_instance_ensure_retry);
_l3_changed_configs_set_dirty(self);
- _l3_acd_platform_commit_acd_update(self);
-
+ nm_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
return G_SOURCE_REMOVE;
}
@@ -1106,12 +1149,8 @@ _l3_acd_nacd_instance_reset(NML3Cfg *self, NMTernary start_timer, gboolean acd_d
switch (start_timer) {
case NM_TERNARY_FALSE:
- self->priv.p->nacd_instance_ensure_retry =
- nm_g_idle_source_new(G_PRIORITY_DEFAULT,
- _l3_acd_nacd_instance_ensure_retry_cb,
- self,
- NULL);
- g_source_attach(self->priv.p->nacd_instance_ensure_retry, NULL);
+ _l3_changed_configs_set_dirty(self);
+ nm_l3cfg_commit_on_idle_schedule(self);
break;
case NM_TERNARY_TRUE:
self->priv.p->nacd_instance_ensure_retry =
@@ -1161,7 +1200,7 @@ again:
return NULL;
}
- valid = _acd_has_valid_link(self->priv.pllink, &addr_bin, &acd_not_supported);
+ valid = _acd_has_valid_link(self->priv.plobj, &addr_bin, &acd_not_supported);
if (!valid)
goto failed_create_acd;
@@ -1384,20 +1423,6 @@ _l3_acd_data_add_all(NML3Cfg *self, const L3ConfigData *const *infos, guint info
}
static gboolean
-_l3_acd_ready_on_idle_cb(gpointer user_data)
-{
- NML3Cfg *self = user_data;
-
- nm_clear_g_source_inst(&self->priv.p->acd_ready_on_idle_source);
-
- _LOGT("acd: handle ACD changes on idle");
-
- _l3_acd_platform_commit_acd_update(self);
-
- return G_SOURCE_REMOVE;
-}
-
-static gboolean
_l3_acd_data_timeout_cb(gpointer user_data)
{
AcdData *acd_data = user_data;
@@ -1502,7 +1527,7 @@ _l3_acd_data_notify_acd_completed(NML3Cfg *self, AcdData *acd_data, gboolean for
{
gs_free NML3ConfigNotifyPayloadAcdFailedSource *sources_free = NULL;
NML3ConfigNotifyPayloadAcdFailedSource * sources = NULL;
- NML3ConfigNotifyPayload payload;
+ NML3ConfigNotifyData notify_data;
AcdTrackData * acd_track;
guint i, n;
NMTernary acd_failed_notified_selector;
@@ -1547,17 +1572,14 @@ _l3_acd_data_notify_acd_completed(NML3Cfg *self, AcdData *acd_data, gboolean for
}
nm_assert(i == n);
- payload = (NML3ConfigNotifyPayload){
- .acd_completed =
- {
- .addr = acd_data->addr,
- .probe_result = acd_data->probe_result,
- .sources_len = n,
- .sources = sources,
- },
+ notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED;
+ notify_data.acd_completed = (typeof(notify_data.acd_completed)){
+ .addr = acd_data->addr,
+ .probe_result = acd_data->probe_result,
+ .sources_len = n,
+ .sources = sources,
};
-
- _nm_l3cfg_emit_signal_notify(self, NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED, &payload);
+ _nm_l3cfg_emit_signal_notify(self, &notify_data);
for (i = 0; i < n; i++) {
nmp_object_unref(sources[i].obj);
@@ -2131,13 +2153,9 @@ handle_probe_done:
/* probing just completed. Schedule handling the change. */
_LOGT_acd(acd_data, "state: acd probe succeed");
_l3_acd_data_notify_acd_completed_queue(self, acd_data);
- if (!self->priv.p->acd_ready_on_idle_source) {
- if (state_change_mode != ACD_STATE_CHANGE_MODE_POST_COMMIT)
- _l3_changed_configs_set_dirty(self);
- self->priv.p->acd_ready_on_idle_source =
- nm_g_idle_source_new(G_PRIORITY_DEFAULT, _l3_acd_ready_on_idle_cb, self, NULL);
- g_source_attach(self->priv.p->acd_ready_on_idle_source, NULL);
- }
+ if (state_change_mode != ACD_STATE_CHANGE_MODE_POST_COMMIT)
+ _l3_changed_configs_set_dirty(self);
+ nm_l3cfg_commit_on_idle_schedule(self);
}
if (!acd_data->nacd_probe) {
@@ -2213,6 +2231,33 @@ _l3_acd_data_process_changes(NML3Cfg *self)
/*****************************************************************************/
+static gboolean
+_l3_commit_on_idle_cb(gpointer user_data)
+{
+ NML3Cfg *self = user_data;
+
+ nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source);
+
+ _LOGT("platform commit on idle");
+ _l3_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO, TRUE);
+ return G_SOURCE_REMOVE;
+}
+
+void
+nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self)
+{
+ nm_assert(NM_IS_L3CFG(self));
+
+ if (self->priv.p->commit_on_idle_source)
+ return;
+
+ self->priv.p->commit_on_idle_source =
+ nm_g_idle_source_new(G_PRIORITY_DEFAULT, _l3_commit_on_idle_cb, self, NULL);
+ g_source_attach(self->priv.p->commit_on_idle_source, NULL);
+}
+
+/*****************************************************************************/
+
#define _l3_config_datas_at(l3_config_datas, idx) \
(&g_array_index((l3_config_datas), L3ConfigData, (idx)))
@@ -2342,6 +2387,10 @@ nm_l3cfg_add_config(NML3Cfg * self,
gboolean replace_same_tag,
const NML3ConfigData *l3cd,
int priority,
+ guint32 default_route_table_4,
+ guint32 default_route_table_6,
+ guint32 default_route_metric_4,
+ guint32 default_route_metric_6,
guint32 default_route_penalty_4,
guint32 default_route_penalty_6,
guint32 acd_timeout_msec,
@@ -2356,6 +2405,13 @@ nm_l3cfg_add_config(NML3Cfg * self,
nm_assert(l3cd);
nm_assert(nm_l3_config_data_get_ifindex(l3cd) == self->priv.ifindex);
+ nm_assert(default_route_metric_6 != 0u); /* IPv6 default route metric cannot be zero. */
+
+ if (default_route_table_4 == 0u)
+ default_route_table_4 = RT_TABLE_MAIN;
+ if (default_route_table_6 == 0u)
+ default_route_table_6 = RT_TABLE_MAIN;
+
if (!self->priv.p->l3_config_datas) {
self->priv.p->l3_config_datas = g_array_new(FALSE, FALSE, sizeof(L3ConfigData));
g_object_ref(self);
@@ -2396,6 +2452,10 @@ nm_l3cfg_add_config(NML3Cfg * self,
.tag = tag,
.l3cd = nm_l3_config_data_ref_and_seal(l3cd),
.merge_flags = merge_flags,
+ .default_route_table_4 = default_route_table_4,
+ .default_route_table_6 = default_route_table_6,
+ .default_route_metric_4 = default_route_metric_4,
+ .default_route_metric_6 = default_route_metric_6,
.default_route_penalty_4 = default_route_penalty_4,
.default_route_penalty_6 = default_route_penalty_6,
.acd_timeout_msec = acd_timeout_msec,
@@ -2417,6 +2477,22 @@ nm_l3cfg_add_config(NML3Cfg * self,
l3_config_data->merge_flags = merge_flags;
changed = TRUE;
}
+ if (l3_config_data->default_route_table_4 != default_route_table_4) {
+ l3_config_data->default_route_table_4 = default_route_table_4;
+ changed = TRUE;
+ }
+ if (l3_config_data->default_route_table_6 != default_route_table_6) {
+ l3_config_data->default_route_table_6 = default_route_table_6;
+ changed = TRUE;
+ }
+ if (l3_config_data->default_route_metric_4 != default_route_metric_4) {
+ l3_config_data->default_route_metric_4 = default_route_metric_4;
+ changed = TRUE;
+ }
+ if (l3_config_data->default_route_metric_6 != default_route_metric_6) {
+ l3_config_data->default_route_metric_6 = default_route_metric_6;
+ changed = TRUE;
+ }
if (l3_config_data->default_route_penalty_4 != default_route_penalty_4) {
l3_config_data->default_route_penalty_4 = default_route_penalty_4;
changed = TRUE;
@@ -2569,11 +2645,18 @@ _l3cfg_update_combined_config(NML3Cfg * self,
self->priv.ifindex);
for (i = 0; i < l3_config_datas_len; i++) {
- hook_data.tag = l3_config_datas_sorted[i]->tag;
+ const L3ConfigData *l3cd_data = l3_config_datas_sorted[i];
+
+ if (NM_FLAGS_HAS(l3cd_data->merge_flags, NM_L3_CONFIG_MERGE_FLAGS_ONLY_FOR_ACD))
+ continue;
+
+ hook_data.tag = l3cd_data->tag;
nm_l3_config_data_merge(l3cd,
- l3_config_datas_sorted[i]->l3cd,
- l3_config_datas_sorted[i]->merge_flags,
- l3_config_datas_sorted[i]->default_route_penalty_x,
+ l3cd_data->l3cd,
+ l3cd_data->merge_flags,
+ l3cd_data->default_route_table_x,
+ l3cd_data->default_route_metric_x,
+ l3cd_data->default_route_penalty_x,
_l3_hook_add_addr_cb,
&hook_data);
}
@@ -2666,11 +2749,10 @@ _routes_temporary_not_available_timeout(gpointer user_data)
if (any_expired) {
/* a route expired. We emit a signal, but we don't schedule it again. That will
- * only happen if the user calls nm_l3cfg_platform_commit() again. */
- _nm_l3cfg_emit_signal_notify(
+ * only happen if the user calls nm_l3cfg_commit() again. */
+ _nm_l3cfg_emit_signal_notify_simple(
self,
- NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
- NULL);
+ NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED);
return G_SOURCE_REMOVE;
}
@@ -2792,10 +2874,7 @@ out_prune:
/*****************************************************************************/
static gboolean
-_platform_commit(NML3Cfg * self,
- int addr_family,
- NML3CfgCommitType commit_type,
- gboolean * out_final_failure_for_temporary_not_available)
+_l3_commit_one(NML3Cfg *self, int addr_family, NML3CfgCommitType commit_type)
{
const gboolean IS_IPv4 = NM_IS_IPv4(addr_family);
nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL;
@@ -2920,19 +2999,19 @@ _platform_commit(NML3Cfg * self,
routes_temporary_not_available_arr))
final_failure_for_temporary_not_available = TRUE;
- if (final_failure_for_temporary_not_available)
- NM_SET_OUT(out_final_failure_for_temporary_not_available, TRUE);
+ /* FIXME(l3cfg) */
+ (void) final_failure_for_temporary_not_available;
+
return success;
}
-gboolean
-nm_l3cfg_platform_commit(NML3Cfg *self, NML3CfgCommitType commit_type)
+static void
+_l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle)
{
gboolean commit_type_detected = FALSE;
- gboolean success = TRUE;
char sbuf_ct[30];
- g_return_val_if_fail(NM_IS_L3CFG(self), FALSE);
+ g_return_if_fail(NM_IS_L3CFG(self));
nm_assert(NM_IN_SET(commit_type,
NM_L3_CFG_COMMIT_TYPE_NONE,
NM_L3_CFG_COMMIT_TYPE_AUTO,
@@ -2964,30 +3043,33 @@ nm_l3cfg_platform_commit(NML3Cfg *self, NML3CfgCommitType commit_type)
break;
}
- _LOGT("platform-commit %s%s",
+ _LOGT("platform-commit %s%s%s",
_l3_cfg_commit_type_to_string(commit_type, sbuf_ct, sizeof(sbuf_ct)),
- commit_type_detected ? " (auto)" : "");
+ commit_type_detected ? " (auto)" : "",
+ is_idle ? " (idle handler)" : "");
if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE)
- return TRUE;
+ return;
- nm_clear_g_source_inst(&self->priv.p->acd_ready_on_idle_source);
+ nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source);
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY)
_l3cfg_externally_removed_objs_drop(self);
/* FIXME(l3cfg): handle items currently not configurable in kernel. */
- if (!_platform_commit(self, AF_INET, commit_type, NULL))
- success = FALSE;
- if (!_platform_commit(self, AF_INET6, commit_type, NULL))
- success = FALSE;
+ _l3_commit_one(self, AF_INET, commit_type);
+ _l3_commit_one(self, AF_INET6, commit_type);
_l3_acd_data_process_changes(self);
- _nm_l3cfg_emit_signal_notify(self, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, NULL);
+ _nm_l3cfg_emit_signal_notify_simple(self, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT);
+}
- return success;
+void
+nm_l3cfg_commit(NML3Cfg *self, NML3CfgCommitType commit_type)
+{
+ _l3_commit(self, commit_type, FALSE);
}
/*****************************************************************************/
@@ -3015,7 +3097,7 @@ nm_l3cfg_commit_type_get(NML3Cfg *self)
* NML3Cfg needs to know whether it is in charge of an interface (and how "much").
* By default, it is not in charge, but various users can register themself with
* a certain @commit_type. The "higher" commit type is the used one when calling
- * nm_l3cfg_platform_commit() with %NM_L3_CFG_COMMIT_TYPE_AUTO.
+ * nm_l3cfg_commit() with %NM_L3_CFG_COMMIT_TYPE_AUTO.
*
* Returns: a handle tracking the registration, or %NULL of @commit_type
* is %NM_L3_CFG_COMMIT_TYPE_NONE.
@@ -3231,7 +3313,7 @@ finalize(GObject *object)
nm_assert(c_list_is_empty(&self->priv.p->commit_type_lst_head));
- nm_clear_g_source_inst(&self->priv.p->acd_ready_on_idle_source);
+ nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source);
nm_assert(nm_g_array_len(self->priv.p->property_emit_list) == 0u);
@@ -3257,7 +3339,8 @@ finalize(GObject *object)
nm_clear_l3cd(&self->priv.p->combined_l3cd_merged);
nm_clear_l3cd(&self->priv.p->combined_l3cd_commited);
- nm_clear_pointer(&self->priv.pllink, nmp_object_unref);
+ nm_clear_pointer(&self->priv.plobj, nmp_object_unref);
+ nm_clear_pointer(&self->priv.plobj_next, nmp_object_unref);
nm_clear_pointer(&self->priv.p->acd_ipv4_addresses_on_link, g_hash_table_unref);
@@ -3300,9 +3383,8 @@ nm_l3cfg_class_init(NML3CfgClass *klass)
0,
NULL,
NULL,
- NULL,
+ g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
- 2,
- G_TYPE_INT /* NML3ConfigNotifyType */,
- G_TYPE_POINTER /* (const NML3ConfigNotifyPayload *) */);
+ 1,
+ G_TYPE_POINTER /* (const NML3ConfigNotifyData *) */);
}
diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h
index a74ce6b43b..9f957ae10c 100644
--- a/src/nm-l3cfg.h
+++ b/src/nm-l3cfg.h
@@ -27,6 +27,12 @@ typedef enum {
NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT,
/* NML3Cfg hooks to the NMPlatform signals for link, addresses and routes.
+ * It re-emits the platform signal.
+ * Contrary to NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, this even
+ * is re-emitted synchronously. */
+ NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE,
+
+ /* NML3Cfg hooks to the NMPlatform signals for link, addresses and routes.
* It re-emits the signal on an idle handler. The purpose is for something
* like NMDevice which is already subscribed to these signals, it can get the
* notifications without also subscribing directly to the platform. */
@@ -42,6 +48,7 @@ typedef struct {
} NML3ConfigNotifyPayloadAcdFailedSource;
typedef struct {
+ NML3ConfigNotifyType notify_type;
union {
struct {
in_addr_t addr;
@@ -51,10 +58,15 @@ typedef struct {
} acd_completed;
struct {
+ const NMPObject * obj;
+ NMPlatformSignalChangeType change_type;
+ } platform_change;
+
+ struct {
guint32 obj_type_flags;
} platform_change_on_idle;
};
-} NML3ConfigNotifyPayload;
+} NML3ConfigNotifyData;
struct _NML3CfgPrivate;
@@ -64,7 +76,8 @@ struct _NML3Cfg {
struct _NML3CfgPrivate *p;
NMNetns * netns;
NMPlatform * platform;
- const NMPObject * pllink;
+ const NMPObject * plobj;
+ const NMPObject * plobj_next;
int ifindex;
bool changed_configs : 1;
} priv;
@@ -86,42 +99,56 @@ void _nm_l3cfg_notify_platform_change(NML3Cfg * self,
/*****************************************************************************/
-static inline int
-nm_l3cfg_get_ifindex(const NML3Cfg *self)
-{
- nm_assert(NM_IS_L3CFG(self));
+struct _NMDedupMultiIndex;
- return self->priv.ifindex;
+struct _NMDedupMultiIndex *nm_netns_get_multi_idx(NMNetns *self);
+
+static inline struct _NMDedupMultiIndex *
+nm_l3cfg_get_multi_idx(const NML3Cfg *self)
+{
+ return nm_netns_get_multi_idx(self->priv.netns);
}
-static inline const char *
-nm_l3cfg_get_ifname(const NML3Cfg *self)
+/*****************************************************************************/
+
+static inline int
+nm_l3cfg_get_ifindex(const NML3Cfg *self)
{
nm_assert(NM_IS_L3CFG(self));
- return nmp_object_link_get_ifname(self->priv.pllink);
+ return self->priv.ifindex;
}
static inline const NMPObject *
-nm_l3cfg_get_plobj(const NML3Cfg *self)
+nm_l3cfg_get_plobj(const NML3Cfg *self, gboolean get_next)
{
if (!self)
return NULL;
nm_assert(NM_IS_L3CFG(self));
- return self->priv.pllink;
+ if (get_next) {
+ /* This is the instance that we just got reported in the last signal from
+ * the platform cache. It's probably exactly the same as if you would look
+ * into the platform cache.
+ *
+ * On the other hand, we pick up changes only on an idle handler. So the last
+ * decisions were not made based on this, but instead of "plobj". */
+ return self->priv.plobj_next;
+ }
+ return self->priv.plobj;
}
static inline const NMPlatformLink *
-nm_l3cfg_get_pllink(const NML3Cfg *self)
+nm_l3cfg_get_pllink(const NML3Cfg *self, gboolean get_next)
{
- if (!self)
- return NULL;
-
- nm_assert(NM_IS_L3CFG(self));
+ return NMP_OBJECT_CAST_LINK(nm_l3cfg_get_plobj(self, get_next));
+}
- return NMP_OBJECT_CAST_LINK(self->priv.pllink);
+static inline const char *
+nm_l3cfg_get_ifname(const NML3Cfg *self, gboolean get_next)
+{
+ return nmp_object_link_get_ifname(nm_l3cfg_get_plobj(self, get_next));
}
static inline NMNetns *
@@ -144,9 +171,7 @@ gboolean nm_l3cfg_get_acd_is_pending(NML3Cfg *self);
/*****************************************************************************/
-void _nm_l3cfg_emit_signal_notify(NML3Cfg * self,
- NML3ConfigNotifyType notify_type,
- const NML3ConfigNotifyPayload *pay_load);
+void _nm_l3cfg_emit_signal_notify(NML3Cfg *self, const NML3ConfigNotifyData *notify_data);
/*****************************************************************************/
@@ -174,6 +199,10 @@ gboolean nm_l3cfg_add_config(NML3Cfg * self,
gboolean replace_same_tag,
const NML3ConfigData *l3cd,
int priority,
+ guint32 default_route_table_4,
+ guint32 default_route_table_6,
+ guint32 default_route_metric_4,
+ guint32 default_route_metric_6,
guint32 default_route_penalty_4,
guint32 default_route_penalty_6,
guint32 acd_timeout_msec,
@@ -215,7 +244,9 @@ typedef enum _nm_packed {
} NML3CfgCommitType;
-gboolean nm_l3cfg_platform_commit(NML3Cfg *self, NML3CfgCommitType commit_type);
+void nm_l3cfg_commit(NML3Cfg *self, NML3CfgCommitType commit_type);
+
+void nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self);
/*****************************************************************************/
diff --git a/src/nm-netns.c b/src/nm-netns.c
index 8497b7c783..2970e45c91 100644
--- a/src/nm-netns.c
+++ b/src/nm-netns.c
@@ -95,7 +95,7 @@ nm_netns_get_multi_idx(NMNetns *self)
typedef struct {
int ifindex;
- guint32 signal_pending_flag;
+ guint32 signal_pending_obj_type_flags;
NML3Cfg *l3cfg;
CList signal_pending_lst;
} L3CfgData;
@@ -192,8 +192,9 @@ _platform_signal_on_idle_cb(gpointer user_data)
while ((l3cfg_data = c_list_first_entry(&work_list, L3CfgData, signal_pending_lst))) {
nm_assert(NM_IS_L3CFG(l3cfg_data->l3cfg));
c_list_unlink(&l3cfg_data->signal_pending_lst);
- _nm_l3cfg_notify_platform_change_on_idle(l3cfg_data->l3cfg,
- nm_steal_int(&l3cfg_data->signal_pending_flag));
+ _nm_l3cfg_notify_platform_change_on_idle(
+ l3cfg_data->l3cfg,
+ nm_steal_int(&l3cfg_data->signal_pending_obj_type_flags));
}
return G_SOURCE_REMOVE;
@@ -217,7 +218,7 @@ _platform_signal_cb(NMPlatform * platform,
if (!l3cfg_data)
return;
- l3cfg_data->signal_pending_flag |= nmp_object_type_to_flags(obj_type);
+ l3cfg_data->signal_pending_obj_type_flags |= nmp_object_type_to_flags(obj_type);
if (c_list_is_empty(&l3cfg_data->signal_pending_lst)) {
c_list_link_tail(&priv->l3cfg_signal_pending_lst_head, &l3cfg_data->signal_pending_lst);
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index d716e5bbbb..05125fa836 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -4704,7 +4704,10 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj)
NLA_PUT(msg, RTA_SRC, addr_len, &obj->ip6_route.src);
}
- NLA_PUT_U32(msg, RTA_PRIORITY, obj->ip_route.metric);
+ NLA_PUT_U32(msg,
+ RTA_PRIORITY,
+ is_v4 ? nm_platform_ip4_route_get_effective_metric(&obj->ip4_route)
+ : nm_platform_ip6_route_get_effective_metric(&obj->ip6_route));
if (table > 0xFF)
NLA_PUT_U32(msg, RTA_TABLE, table);
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 72d524f144..0c83a8ee69 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -3437,7 +3437,8 @@ nm_platform_lookup_predicate_routes_main(const NMPObject *obj, gpointer user_dat
{
nm_assert(
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
- return nm_platform_route_table_is_main(obj->ip_route.table_coerced);
+ return nm_platform_route_table_is_main(
+ nm_platform_ip_route_get_effective_table(&obj->ip_route));
}
gboolean
@@ -3446,7 +3447,7 @@ nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel(const NMPObject *obj
{
nm_assert(
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
- return nm_platform_route_table_is_main(obj->ip_route.table_coerced)
+ return nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&obj->ip_route))
&& obj->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
}
@@ -4395,11 +4396,12 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self,
const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) {
- if (nm_platform_route_table_uncoerce(NMP_OBJECT_CAST_IP_ROUTE(obj)->table_coerced, TRUE)
+ if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))
== RT_TABLE_LOCAL)
continue;
} else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) {
- if (!nm_platform_route_table_is_main(NMP_OBJECT_CAST_IP_ROUTE(obj)->table_coerced))
+ if (!nm_platform_route_table_is_main(
+ nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))))
continue;
} else
nm_assert(route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL);
@@ -4488,7 +4490,9 @@ nm_platform_ip_route_sync(NMPlatform *self,
continue;
}
- if (!IS_IPv4 && NMP_OBJECT_CAST_IP6_ROUTE(conf_o)->metric == 0) {
+ if (!IS_IPv4
+ && nm_platform_ip6_route_get_effective_metric(NMP_OBJECT_CAST_IP6_ROUTE(conf_o))
+ == 0) {
/* User space cannot add routes with metric 0. However, kernel can, and we might track such
* routes in @route as they are present external. Skip them silently. */
continue;
@@ -4582,29 +4586,33 @@ sync_route_add:
if (vt->is_ip4) {
const NMPlatformIP4Route *rt = NMP_OBJECT_CAST_IP4_ROUTE(conf_o);
- nmp_object_stackinit(&oo,
- NMP_OBJECT_TYPE_IP4_ROUTE,
- &((NMPlatformIP4Route){
- .ifindex = rt->ifindex,
- .network = rt->gateway,
- .plen = 32,
- .metric = rt->metric,
- .rt_source = rt->rt_source,
- .table_coerced = rt->table_coerced,
- }));
+ nmp_object_stackinit(
+ &oo,
+ NMP_OBJECT_TYPE_IP4_ROUTE,
+ &((NMPlatformIP4Route){
+ .ifindex = rt->ifindex,
+ .network = rt->gateway,
+ .plen = 32,
+ .metric = nm_platform_ip4_route_get_effective_metric(rt),
+ .rt_source = rt->rt_source,
+ .table_coerced = nm_platform_ip_route_get_effective_table(
+ NM_PLATFORM_IP_ROUTE_CAST(rt)),
+ }));
} else {
const NMPlatformIP6Route *rt = NMP_OBJECT_CAST_IP6_ROUTE(conf_o);
- nmp_object_stackinit(&oo,
- NMP_OBJECT_TYPE_IP6_ROUTE,
- &((NMPlatformIP6Route){
- .ifindex = rt->ifindex,
- .network = rt->gateway,
- .plen = 128,
- .metric = rt->metric,
- .rt_source = rt->rt_source,
- .table_coerced = rt->table_coerced,
- }));
+ nmp_object_stackinit(
+ &oo,
+ NMP_OBJECT_TYPE_IP6_ROUTE,
+ &((NMPlatformIP6Route){
+ .ifindex = rt->ifindex,
+ .network = rt->gateway,
+ .plen = 128,
+ .metric = nm_platform_ip6_route_get_effective_metric(rt),
+ .rt_source = rt->rt_source,
+ .table_coerced = nm_platform_ip_route_get_effective_table(
+ NM_PLATFORM_IP_ROUTE_CAST(rt)),
+ }));
}
_LOG3D("route-sync: failure to add IPv%c route: %s: %s; try adding direct "
@@ -4760,21 +4768,25 @@ nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route)
NMPlatformIP4Route *r4;
NMPlatformIP6Route *r6;
+ route->table_coerced =
+ nm_platform_route_table_coerce(nm_platform_ip_route_get_effective_table(route));
+ route->table_any = FALSE;
+
+ route->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(route->rt_source);
+
switch (addr_family) {
case AF_INET:
r4 = (NMPlatformIP4Route *) route;
- r4->table_coerced = nm_platform_route_table_coerce(
- nm_platform_route_table_uncoerce(r4->table_coerced, TRUE));
- r4->network = nm_utils_ip4_address_clear_host_address(r4->network, r4->plen);
- r4->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(r4->rt_source);
- r4->scope_inv = _ip_route_scope_inv_get_normalized(r4);
+ route->metric = nm_platform_ip4_route_get_effective_metric(r4);
+ route->metric_any = FALSE;
+ r4->network = nm_utils_ip4_address_clear_host_address(r4->network, r4->plen);
+ r4->scope_inv = _ip_route_scope_inv_get_normalized(r4);
break;
case AF_INET6:
r6 = (NMPlatformIP6Route *) route;
- r6->table_coerced = nm_platform_route_table_coerce(
- nm_platform_route_table_uncoerce(r6->table_coerced, TRUE));
+ route->metric = nm_platform_ip6_route_get_effective_metric(r6);
+ route->metric_any = FALSE;
nm_utils_ip6_address_clear_host_address(&r6->network, &r6->network, r6->plen);
- r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(r6->rt_source),
nm_utils_ip6_address_clear_host_address(&r6->src, &r6->src, r6->src_plen);
break;
default:
@@ -6453,6 +6465,7 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32];
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
char str_type[30];
+ char str_metric[30];
if (!nm_utils_to_string_buffer_init_null(route, &buf, &len))
return buf;
@@ -6470,30 +6483,33 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
"%s/%d"
" via %s"
"%s"
- " metric %" G_GUINT32_FORMAT " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
- "%s" /* rtm_flags */
- "%s%s" /* scope */
- "%s%s" /* pref-src */
- "%s" /* tos */
- "%s" /* window */
- "%s" /* cwnd */
- "%s" /* initcwnd */
- "%s" /* initrwnd */
- "%s" /* mtu */
+ " metric %s"
+ " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
+ "%s" /* rtm_flags */
+ "%s%s" /* scope */
+ "%s%s" /* pref-src */
+ "%s" /* tos */
+ "%s" /* window */
+ "%s" /* cwnd */
+ "%s" /* initcwnd */
+ "%s" /* initrwnd */
+ "%s" /* mtu */
"",
nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced),
str_type,
sizeof(str_type)),
- route->table_coerced
- ? nm_sprintf_buf(str_table,
- "table %u ",
- nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
- : "",
+ route->table_any
+ ? "table ?? "
+ : (route->table_coerced
+ ? nm_sprintf_buf(str_table,
+ "table %u ",
+ nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
+ : ""),
s_network,
route->plen,
s_gateway,
str_dev,
- route->metric,
+ route->metric_any ? "??" : nm_sprintf_buf(str_metric, "%u", route->metric),
route->mss,
nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)),
_rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
@@ -6568,6 +6584,7 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
char str_initrwnd[32];
char str_mtu[32];
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
+ char str_metric[30];
if (!nm_utils_to_string_buffer_init_null(route, &buf, &len))
return buf;
@@ -6582,81 +6599,84 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
_to_string_dev(NULL, route->ifindex, str_dev, sizeof(str_dev));
- g_snprintf(buf,
- len,
- "type %s " /* type */
- "%s" /* table */
- "%s/%d"
- " via %s"
- "%s"
- " metric %" G_GUINT32_FORMAT " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
- "%s" /* source */
- "%s" /* rtm_flags */
- "%s%s" /* pref-src */
- "%s" /* window */
- "%s" /* cwnd */
- "%s" /* initcwnd */
- "%s" /* initrwnd */
- "%s" /* mtu */
- "%s" /* pref */
- "",
- nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced),
- str_type,
- sizeof(str_type)),
- route->table_coerced
+ g_snprintf(
+ buf,
+ len,
+ "type %s " /* type */
+ "%s" /* table */
+ "%s/%d"
+ " via %s"
+ "%s"
+ " metric %s"
+ " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
+ "%s" /* source */
+ "%s" /* rtm_flags */
+ "%s%s" /* pref-src */
+ "%s" /* window */
+ "%s" /* cwnd */
+ "%s" /* initcwnd */
+ "%s" /* initrwnd */
+ "%s" /* mtu */
+ "%s" /* pref */
+ "",
+ nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced),
+ str_type,
+ sizeof(str_type)),
+ route->table_any
+ ? "table ?? "
+ : (route->table_coerced
? nm_sprintf_buf(str_table,
"table %u ",
nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
- : "",
- s_network,
- route->plen,
- s_gateway,
- str_dev,
- route->metric,
- route->mss,
- nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)),
- route->src_plen || !IN6_IS_ADDR_UNSPECIFIED(&route->src)
- ? nm_sprintf_buf(s_src_all,
- " src %s/%u",
- _nm_utils_inet6_ntop(&route->src, s_src),
- (unsigned) route->src_plen)
- : "",
- _rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
- s_pref_src[0] ? " pref-src " : "",
- s_pref_src[0] ? s_pref_src : "",
- route->window || route->lock_window
- ? nm_sprintf_buf(str_window,
- " window %s%" G_GUINT32_FORMAT,
- route->lock_window ? "lock " : "",
- route->window)
- : "",
- route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd,
- " cwnd %s%" G_GUINT32_FORMAT,
- route->lock_cwnd ? "lock " : "",
- route->cwnd)
- : "",
- route->initcwnd || route->lock_initcwnd
- ? nm_sprintf_buf(str_initcwnd,
- " initcwnd %s%" G_GUINT32_FORMAT,
- route->lock_initcwnd ? "lock " : "",
- route->initcwnd)
- : "",
- route->initrwnd || route->lock_initrwnd
- ? nm_sprintf_buf(str_initrwnd,
- " initrwnd %s%" G_GUINT32_FORMAT,
- route->lock_initrwnd ? "lock " : "",
- route->initrwnd)
- : "",
- route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu,
- " mtu %s%" G_GUINT32_FORMAT,
- route->lock_mtu ? "lock " : "",
- route->mtu)
- : "",
- route->rt_pref ? nm_sprintf_buf(
- str_pref,
- " pref %s",
- nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
- : "");
+ : ""),
+ s_network,
+ route->plen,
+ s_gateway,
+ str_dev,
+ route->metric_any ? "??" : nm_sprintf_buf(str_metric, "%u", route->metric),
+ route->mss,
+ nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)),
+ route->src_plen || !IN6_IS_ADDR_UNSPECIFIED(&route->src)
+ ? nm_sprintf_buf(s_src_all,
+ " src %s/%u",
+ _nm_utils_inet6_ntop(&route->src, s_src),
+ (unsigned) route->src_plen)
+ : "",
+ _rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
+ s_pref_src[0] ? " pref-src " : "",
+ s_pref_src[0] ? s_pref_src : "",
+ route->window || route->lock_window ? nm_sprintf_buf(str_window,
+ " window %s%" G_GUINT32_FORMAT,
+ route->lock_window ? "lock " : "",
+ route->window)
+ : "",
+ route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd,
+ " cwnd %s%" G_GUINT32_FORMAT,
+ route->lock_cwnd ? "lock " : "",
+ route->cwnd)
+ : "",
+ route->initcwnd || route->lock_initcwnd
+ ? nm_sprintf_buf(str_initcwnd,
+ " initcwnd %s%" G_GUINT32_FORMAT,
+ route->lock_initcwnd ? "lock " : "",
+ route->initcwnd)
+ : "",
+ route->initrwnd || route->lock_initrwnd
+ ? nm_sprintf_buf(str_initrwnd,
+ " initrwnd %s%" G_GUINT32_FORMAT,
+ route->lock_initrwnd ? "lock " : "",
+ route->initrwnd)
+ : "",
+ route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu,
+ " mtu %s%" G_GUINT32_FORMAT,
+ route->lock_mtu ? "lock " : "",
+ route->mtu)
+ : "",
+ route->rt_pref ? nm_sprintf_buf(
+ str_pref,
+ " pref %s",
+ nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
+ : "");
return buf;
}
@@ -7891,67 +7911,75 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
{
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
- nm_hash_update_vals(h,
- nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
- nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
- obj->plen,
- obj->metric,
- obj->tos);
+ nm_hash_update_vals(
+ h,
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
+ nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
+ obj->plen,
+ nm_platform_ip4_route_get_effective_metric(obj),
+ obj->tos,
+ NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
- nm_hash_update_vals(h,
- obj->type_coerced,
- nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
- nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
- obj->plen,
- obj->metric,
- obj->tos,
- /* on top of WEAK_ID: */
- obj->ifindex,
- nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
- _ip_route_scope_inv_get_normalized(obj),
- obj->gateway,
- obj->mss,
- obj->pref_src,
- obj->window,
- obj->cwnd,
- obj->initcwnd,
- obj->initrwnd,
- obj->mtu,
- obj->r_rtm_flags & RTNH_F_ONLINK,
- NM_HASH_COMBINE_BOOLS(guint8,
- obj->lock_window,
- obj->lock_cwnd,
- obj->lock_initcwnd,
- obj->lock_initrwnd,
- obj->lock_mtu));
+ nm_hash_update_vals(
+ h,
+ obj->type_coerced,
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
+ nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
+ obj->plen,
+ nm_platform_ip4_route_get_effective_metric(obj),
+ obj->tos,
+ /* on top of WEAK_ID: */
+ obj->ifindex,
+ nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
+ _ip_route_scope_inv_get_normalized(obj),
+ obj->gateway,
+ obj->mss,
+ obj->pref_src,
+ obj->window,
+ obj->cwnd,
+ obj->initcwnd,
+ obj->initrwnd,
+ obj->mtu,
+ obj->r_rtm_flags & RTNH_F_ONLINK,
+ NM_HASH_COMBINE_BOOLS(guint8,
+ obj->metric_any,
+ obj->table_any,
+ obj->lock_window,
+ obj->lock_cwnd,
+ obj->lock_initcwnd,
+ obj->lock_initrwnd,
+ obj->lock_mtu));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
- nm_hash_update_vals(h,
- obj->type_coerced,
- nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
- obj->ifindex,
- nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
- obj->plen,
- obj->metric,
- obj->gateway,
- nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
- _ip_route_scope_inv_get_normalized(obj),
- obj->tos,
- obj->mss,
- obj->pref_src,
- obj->window,
- obj->cwnd,
- obj->initcwnd,
- obj->initrwnd,
- obj->mtu,
- obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK),
- NM_HASH_COMBINE_BOOLS(guint8,
- obj->lock_window,
- obj->lock_cwnd,
- obj->lock_initcwnd,
- obj->lock_initrwnd,
- obj->lock_mtu));
+ nm_hash_update_vals(
+ h,
+ obj->type_coerced,
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
+ obj->ifindex,
+ nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
+ obj->plen,
+ nm_platform_ip4_route_get_effective_metric(obj),
+ obj->gateway,
+ nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
+ _ip_route_scope_inv_get_normalized(obj),
+ obj->tos,
+ obj->mss,
+ obj->pref_src,
+ obj->window,
+ obj->cwnd,
+ obj->initcwnd,
+ obj->initrwnd,
+ obj->mtu,
+ obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK),
+ NM_HASH_COMBINE_BOOLS(guint8,
+ obj->metric_any,
+ obj->table_any,
+ obj->lock_window,
+ obj->lock_cwnd,
+ obj->lock_initcwnd,
+ obj->lock_initrwnd,
+ obj->lock_mtu));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
nm_hash_update_vals(h,
@@ -7960,7 +7988,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
obj->ifindex,
obj->network,
obj->plen,
- obj->metric,
+ nm_platform_ip4_route_get_effective_metric(obj),
obj->gateway,
obj->rt_source,
obj->scope_inv,
@@ -7974,6 +8002,8 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
obj->mtu,
obj->r_rtm_flags,
NM_HASH_COMBINE_BOOLS(guint8,
+ obj->metric_any,
+ obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
@@ -7992,11 +8022,14 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
- NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
- nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
+ NM_CMP_FIELD_UNSAFE(a, b, table_any);
+ NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->network, b->network, MIN(a->plen, b->plen));
NM_CMP_FIELD(a, b, plen);
- NM_CMP_FIELD(a, b, metric);
+ NM_CMP_FIELD_UNSAFE(a, b, metric_any);
+ if (!a->metric_any)
+ NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD(a, b, tos);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
NM_CMP_FIELD(a, b, ifindex);
@@ -8024,9 +8057,10 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD(a, b, type_coerced);
+ NM_CMP_FIELD_UNSAFE(a, b, table_any);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
- NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
- nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
+ NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
} else
NM_CMP_FIELD(a, b, table_coerced);
NM_CMP_FIELD(a, b, ifindex);
@@ -8035,7 +8069,9 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
else
NM_CMP_FIELD(a, b, network);
NM_CMP_FIELD(a, b, plen);
- NM_CMP_FIELD(a, b, metric);
+ NM_CMP_FIELD_UNSAFE(a, b, metric_any);
+ if (!a->metric_any)
+ NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD(a, b, gateway);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source),
@@ -8078,54 +8114,61 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
- nm_hash_update_vals(h,
- nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
- *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
- obj->plen,
- obj->metric,
- *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
- obj->src_plen);
+ nm_hash_update_vals(
+ h,
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
+ *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
+ obj->plen,
+ nm_platform_ip6_route_get_effective_metric(obj),
+ *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
+ obj->src_plen,
+ NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
- nm_hash_update_vals(h,
- obj->type_coerced,
- nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
- *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
- obj->plen,
- obj->metric,
- *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
- obj->src_plen,
- /* on top of WEAK_ID: */
- obj->ifindex,
- obj->gateway);
+ nm_hash_update_vals(
+ h,
+ obj->type_coerced,
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
+ *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
+ obj->plen,
+ nm_platform_ip6_route_get_effective_metric(obj),
+ *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
+ obj->src_plen,
+ NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any),
+ /* on top of WEAK_ID: */
+ obj->ifindex,
+ obj->gateway);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
- nm_hash_update_vals(h,
- obj->type_coerced,
- nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
- obj->ifindex,
- *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
- obj->plen,
- obj->metric,
- obj->gateway,
- obj->pref_src,
- *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
- obj->src_plen,
- nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
- obj->mss,
- obj->r_rtm_flags & RTM_F_CLONED,
- NM_HASH_COMBINE_BOOLS(guint8,
- obj->lock_window,
- obj->lock_cwnd,
- obj->lock_initcwnd,
- obj->lock_initrwnd,
- obj->lock_mtu),
- obj->window,
- obj->cwnd,
- obj->initcwnd,
- obj->initrwnd,
- obj->mtu,
- _route_pref_normalize(obj->rt_pref));
+ nm_hash_update_vals(
+ h,
+ obj->type_coerced,
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
+ obj->ifindex,
+ *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
+ obj->plen,
+ nm_platform_ip6_route_get_effective_metric(obj),
+ obj->gateway,
+ obj->pref_src,
+ *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
+ obj->src_plen,
+ nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
+ obj->mss,
+ obj->r_rtm_flags & RTM_F_CLONED,
+ NM_HASH_COMBINE_BOOLS(guint8,
+ obj->metric_any,
+ obj->table_any,
+ obj->lock_window,
+ obj->lock_cwnd,
+ obj->lock_initcwnd,
+ obj->lock_initrwnd,
+ obj->lock_mtu),
+ obj->window,
+ obj->cwnd,
+ obj->initcwnd,
+ obj->initrwnd,
+ obj->mtu,
+ _route_pref_normalize(obj->rt_pref));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
nm_hash_update_vals(h,
@@ -8133,8 +8176,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
obj->table_coerced,
obj->ifindex,
obj->network,
- obj->plen,
- obj->metric,
+ nm_platform_ip6_route_get_effective_metric(obj),
obj->gateway,
obj->pref_src,
obj->src,
@@ -8143,6 +8185,8 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
obj->mss,
obj->r_rtm_flags,
NM_HASH_COMBINE_BOOLS(guint8,
+ obj->metric_any,
+ obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
@@ -8167,11 +8211,14 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
- NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
- nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
+ NM_CMP_FIELD_UNSAFE(a, b, table_any);
+ NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->network, &b->network, MIN(a->plen, b->plen));
NM_CMP_FIELD(a, b, plen);
- NM_CMP_FIELD(a, b, metric);
+ NM_CMP_FIELD_UNSAFE(a, b, metric_any);
+ if (!a->metric_any)
+ NM_CMP_FIELD(a, b, metric);
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->src, &b->src, MIN(a->src_plen, b->src_plen));
NM_CMP_FIELD(a, b, src_plen);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
@@ -8183,9 +8230,10 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD(a, b, type_coerced);
+ NM_CMP_FIELD_UNSAFE(a, b, table_any);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
- NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
- nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
+ NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
+ nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
} else
NM_CMP_FIELD(a, b, table_coerced);
NM_CMP_FIELD(a, b, ifindex);
@@ -8194,7 +8242,9 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
else
NM_CMP_FIELD_IN6ADDR(a, b, network);
NM_CMP_FIELD(a, b, plen);
- NM_CMP_FIELD(a, b, metric);
+ NM_CMP_FIELD_UNSAFE(a, b, metric_any);
+ if (!a->metric_any)
+ NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_IN6ADDR(a, b, gateway);
NM_CMP_FIELD_IN6ADDR(a, b, pref_src);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 93c4ee68ad..c7b8017a40 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -148,10 +148,17 @@ typedef enum {
} NMPlatformRoutingRuleCmpType;
typedef struct {
- guint8 data[20 /* NM_UTILS_HWADDR_LEN_MAX */];
+ union {
+ guint8 data[20 /* NM_UTILS_HWADDR_LEN_MAX */];
+ NMEtherAddr ether_addr;
+ };
guint8 len;
} NMPLinkAddress;
+/* assert that NMEtherAddr does not affect the alignment of NMPLinkAddress struct. */
+G_STATIC_ASSERT(_nm_alignof(NMEtherAddr) == 1);
+G_STATIC_ASSERT(_nm_alignof(NMPLinkAddress) == 1);
+
gconstpointer nmp_link_address_get(const NMPLinkAddress *addr, size_t *length);
GBytes * nmp_link_address_get_as_bytes(const NMPLinkAddress *addr);
@@ -390,22 +397,22 @@ typedef union {
* Note that contrary to IPv6, you can add routes with metric 0 and it is even
* the default.
*/
-#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 0
+#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 ((guint32) 0u)
/* Default value for adding an IPv6 route. This is also what iproute2 does.
* Adding an IPv6 route with metric 0, kernel translates to IP6_RT_PRIO_USER (1024).
*
* Note that kernel doesn't allow adding IPv6 routes with metric zero via netlink.
* It however can itself add routes with metric zero. */
-#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 1024
+#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 ((guint32) 1024u)
/* For IPv4, kernel adds a device route (subnet routes) with metric 0 when user
* configures addresses. */
-#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE 0
+#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE ((guint32) 0u)
-#define __NMPlatformIPRoute_COMMON \
- __NMPlatformObjWithIfindex_COMMON; \
- \
+#define __NMPlatformIPRoute_COMMON \
+ __NMPlatformObjWithIfindex_COMMON; \
+ \
/* The NMIPConfigSource. For routes that we receive from cache this corresponds
* to the rtm_protocol field (and is one of the NM_IP_CONFIG_SOURCE_RTPROT_* values).
* When adding a route, the source will be coerced to the protocol using
@@ -417,11 +424,11 @@ typedef union {
*
* When deleting an IPv4/IPv6 route, the rtm_protocol field must match (even
* if it is not part of the primary key for IPv6) -- unless rtm_protocol is set
- * to zero, in which case the first matching route (with proto ignored) is deleted. */ \
- NMIPConfigSource rt_source; \
- \
- guint8 plen; \
- \
+ * to zero, in which case the first matching route (with proto ignored) is deleted. */ \
+ NMIPConfigSource rt_source; \
+ \
+ guint8 plen; \
+ \
/* RTA_METRICS:
*
* For IPv4 routes, these properties are part of their
@@ -432,15 +439,24 @@ typedef union {
*
* When deleting a route, kernel seems to ignore the RTA_METRICS properties.
* That is a problem/bug for IPv4 because you cannot explicitly select which
- * route to delete. Kernel just picks the first. See rh#1475642. */ \
- \
- /* RTA_METRICS.RTAX_LOCK (iproute2: "lock" arguments) */ \
- bool lock_window : 1; \
- bool lock_cwnd : 1; \
- bool lock_initcwnd : 1; \
- bool lock_initrwnd : 1; \
- bool lock_mtu : 1; \
- \
+ * route to delete. Kernel just picks the first. See rh#1475642. */ \
+ \
+ /* RTA_METRICS.RTAX_LOCK (iproute2: "lock" arguments) */ \
+ bool lock_window : 1; \
+ bool lock_cwnd : 1; \
+ bool lock_initcwnd : 1; \
+ bool lock_initrwnd : 1; \
+ bool lock_mtu : 1; \
+ \
+ /* if TRUE, the "metric" field gets ignored and can be overridden with settings from
+ * the device. This is to track routes that should be configured (e.g. from a DHCP
+ * lease), but where the actual metric is determined by NMDevice. */ \
+ bool metric_any : 1; \
+ \
+ /* like "metric_any", the table is determined by other layers of the code.
+ * This field overrides "table_coerced" field. */ \
+ bool table_any : 1; \
+ \
/* rtnh_flags
*
* Routes with rtm_flags RTM_F_CLONED are hidden by platform and
@@ -450,44 +466,44 @@ typedef union {
* NOTE: currently we ignore all flags except RTM_F_CLONED
* and RTNH_F_ONLINK.
* We also may not properly consider the flags as part of the ID
- * in route-cmp. */ \
- unsigned r_rtm_flags; \
- \
- /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \
- guint32 mss; \
- \
- /* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \
- guint32 window; \
- \
- /* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \
- guint32 cwnd; \
- \
- /* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \
- guint32 initcwnd; \
- \
- /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \
- guint32 initrwnd; \
- \
- /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \
- guint32 mtu; \
- \
- /* RTA_PRIORITY (iproute2: metric) */ \
- guint32 metric; \
- \
+ * in route-cmp. */ \
+ unsigned r_rtm_flags; \
+ \
+ /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \
+ guint32 mss; \
+ \
+ /* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \
+ guint32 window; \
+ \
+ /* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \
+ guint32 cwnd; \
+ \
+ /* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \
+ guint32 initcwnd; \
+ \
+ /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \
+ guint32 initrwnd; \
+ \
+ /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \
+ guint32 mtu; \
+ \
+ /* RTA_PRIORITY (iproute2: metric) */ \
+ guint32 metric; \
+ \
/* rtm_table, RTA_TABLE.
*
* This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and
* zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main
- * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \
- guint32 table_coerced; \
- \
+ * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \
+ guint32 table_coerced; \
+ \
/* rtm_type.
*
* This is not the original type, if type_coerced is 0 then
* it means RTN_UNSPEC otherwise the type value is preserved.
- * */ \
- guint8 type_coerced; \
- \
+ * */ \
+ guint8 type_coerced; \
+ \
/*end*/
typedef struct {
@@ -1311,7 +1327,7 @@ nm_platform_route_table_coerce(guint32 table)
/**
* nm_platform_route_table_uncoerce:
- * @table: the route table, in its coerced value
+ * @table_coerced: the route table, in its coerced value
* @normalize: whether to normalize RT_TABLE_UNSPEC to
* RT_TABLE_MAIN. For kernel, routes with a table id
* RT_TABLE_UNSPEC do not exist and are treated like
@@ -2053,6 +2069,34 @@ nm_platform_ip_address_get_peer_address(int addr_family, const NMPlatformIPAddre
void nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route);
+static inline guint32
+nm_platform_ip4_route_get_effective_metric(const NMPlatformIP4Route *r)
+{
+ nm_assert(r);
+ nm_assert(!r->metric_any || r->metric == 0);
+
+ return r->metric_any ? NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 : r->metric;
+}
+
+static inline guint32
+nm_platform_ip6_route_get_effective_metric(const NMPlatformIP6Route *r)
+{
+ nm_assert(r);
+ nm_assert(!r->metric_any || r->metric == 0);
+
+ return r->metric_any ? NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 : r->metric;
+}
+
+static inline guint32
+nm_platform_ip_route_get_effective_table(const NMPlatformIPRoute *r)
+{
+ nm_assert(r);
+ nm_assert(!r->table_any || r->table_coerced == 0);
+
+ return r->table_any ? 254u /* RT_TABLE_MAIN */
+ : nm_platform_route_table_uncoerce(r->table_coerced, TRUE);
+}
+
static inline gconstpointer
nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route)
{
diff --git a/src/tests/test-l3cfg.c b/src/tests/test-l3cfg.c
index 74a4dcc523..d55dcfbcaa 100644
--- a/src/tests/test-l3cfg.c
+++ b/src/tests/test-l3cfg.c
@@ -116,43 +116,45 @@ _test_l3cfg_data_set_notify_type(TestL3cfgData *tdata, TestL3cfgNotifyType notif
}
static void
-_test_l3cfg_signal_notify(NML3Cfg * l3cfg,
- int notify_type_i,
- const NML3ConfigNotifyPayload *payload,
- TestL3cfgData * tdata)
+_test_l3cfg_signal_notify(NML3Cfg * l3cfg,
+ const NML3ConfigNotifyData *notify_data,
+ TestL3cfgData * tdata)
{
- NML3ConfigNotifyType l3_notify_type = notify_type_i;
-
g_assert(NM_IS_L3CFG(l3cfg));
g_assert(tdata);
- g_assert((!!payload)
- == NM_IN_SET(l3_notify_type,
- NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE,
- NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED));
-
- if (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE)
- g_assert(payload->platform_change_on_idle.obj_type_flags != 0u);
+ g_assert(notify_data);
+ g_assert(_NM_INT_NOT_NEGATIVE(notify_data->notify_type));
+ g_assert(notify_data->notify_type < _NM_L3_CONFIG_NOTIFY_TYPE_NUM);
+
+ if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE)
+ g_assert(notify_data->platform_change_on_idle.obj_type_flags != 0u);
+ else if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE) {
+ g_assert(NMP_OBJECT_IS_VALID(notify_data->platform_change.obj));
+ g_assert(notify_data->platform_change.change_type != 0);
+ }
switch (tdata->notify_type) {
case TEST_L3CFG_NOTIFY_TYPE_NONE:
g_assert_not_reached();
break;
case TEST_L3CFG_NOTIFY_TYPE_IDLE_ASSERT_NO_SIGNAL:
- if (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE)
+ if (NM_IN_SET(notify_data->notify_type,
+ NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE,
+ NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE))
return;
g_assert_not_reached();
return;
case TEST_L3CFG_NOTIFY_TYPE_COMMIT_1:
g_assert_cmpint(tdata->post_commit_event_count, ==, 0);
- switch (l3_notify_type) {
+ switch (notify_data->notify_type) {
case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT:
tdata->post_commit_event_count++;
return;
case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
switch (tdata->f->test_idx) {
case 2:
- nmtst_assert_ip4_address(payload->acd_completed.addr, "192.167.133.45");
- g_assert(payload->acd_completed.probe_result);
+ nmtst_assert_ip4_address(notify_data->acd_completed.addr, "192.167.133.45");
+ g_assert(notify_data->acd_completed.probe_result);
g_assert(tdata->general_event_count == 0);
tdata->general_event_count++;
return;
@@ -160,19 +162,23 @@ _test_l3cfg_signal_notify(NML3Cfg * l3cfg,
g_assert_not_reached();
return;
}
+ case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE:
+ return;
default:
g_assert_not_reached();
return;
}
case TEST_L3CFG_NOTIFY_TYPE_WAIT_FOR_ACD_READY_1:
- if (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE)
+ if (NM_IN_SET(notify_data->notify_type,
+ NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE,
+ NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE))
return;
- if (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED) {
+ if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED) {
g_assert(tdata->notify_data.wait_for_acd_ready_1.cb_count == 0);
tdata->notify_data.wait_for_acd_ready_1.cb_count++;
return;
}
- if (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT) {
+ if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT) {
g_assert(tdata->notify_data.wait_for_acd_ready_1.cb_count == 1);
tdata->notify_data.wait_for_acd_ready_1.cb_count++;
nmtstp_platform_ip_addresses_assert(tdata->f->platform,
@@ -276,6 +282,10 @@ test_l3cfg(gconstpointer test_data)
'a',
0,
0,
+ NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4,
+ NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
+ 0,
+ 0,
acd_timeout_msec,
NM_L3_CONFIG_MERGE_FLAGS_NONE);
}
@@ -287,7 +297,7 @@ test_l3cfg(gconstpointer test_data)
LOGD_PLATFORM);
_test_l3cfg_data_set_notify_type(tdata, TEST_L3CFG_NOTIFY_TYPE_COMMIT_1);
- nm_l3cfg_platform_commit(l3cfg0, NM_L3_CFG_COMMIT_TYPE_REAPPLY);
+ nm_l3cfg_commit(l3cfg0, NM_L3_CFG_COMMIT_TYPE_REAPPLY);
g_assert_cmpint(tdata->post_commit_event_count, ==, 1);
_test_l3cfg_data_set_notify_type(tdata, TEST_L3CFG_NOTIFY_TYPE_NONE);