diff options
author | Thomas Haller <thaller@redhat.com> | 2020-09-30 10:41:09 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-09-30 10:41:09 +0200 |
commit | 77ad359442c9d5b8f00435130b7de10935728316 (patch) | |
tree | 4af64255ddf9244d2f94945f04f2b97b94ec917b | |
parent | 1c3f7d823e17dbfc26ab11ef8943135b2c6961c5 (diff) | |
parent | e83a6f5898eec620a3d2e49c267cac618b9deee9 (diff) | |
download | NetworkManager-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.h | 136 | ||||
-rw-r--r-- | shared/nm-std-aux/nm-std-aux.h | 120 | ||||
-rw-r--r-- | src/nm-l3-config-data.c | 80 | ||||
-rw-r--r-- | src/nm-l3-config-data.h | 18 | ||||
-rw-r--r-- | src/nm-l3cfg.c | 336 | ||||
-rw-r--r-- | src/nm-l3cfg.h | 75 | ||||
-rw-r--r-- | src/nm-netns.c | 9 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 5 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 524 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 148 | ||||
-rw-r--r-- | src/tests/test-l3cfg.c | 52 |
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, ¬ify_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, ¬ify_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, ¬ify_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, ¬ify_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); |