From abce54822249374b01010c73ac676a360581e22c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 20 Jul 2020 14:43:13 +0200 Subject: [PATCH 01/25] shared: don't freeze in nm_gobject_notify_together() unless necessary nm_gobject_notify_together() is supposed to emit one or more property changed notifications, but with freezing (and thawing) the notifications. Also, we want to allow the user to pass PROP_0, for skipping emitions. The point is code like nm_gobject_notify_together (obj, PROP_FOO, bar_changed ? PROP_BAR : PROP_0); Optimize the code to only freeze/thaw the notifications, if we are actually notifying more than one properties. --- shared/nm-glib-aux/nm-macros-internal.h | 34 ++++++++++++++++++------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h index 9173d2792d..41f701f98e 100644 --- a/shared/nm-glib-aux/nm-macros-internal.h +++ b/shared/nm-glib-aux/nm-macros-internal.h @@ -700,24 +700,40 @@ static GParamSpec *obj_properties##suffix[_PROPERTY_ENUMS_LAST##suffix] = { NULL static inline void \ _nm_gobject_notify_together_impl##suffix (obj_type *obj, guint n, const _PropertyEnums##suffix *props) \ { \ - const gboolean freeze_thaw = (n > 1); \ + GObject *const gobj = (GObject *) obj; \ + GParamSpec *pspec_first = NULL; \ + gboolean frozen = FALSE; \ \ nm_assert (G_IS_OBJECT (obj)); \ nm_assert (n > 0); \ \ - if (freeze_thaw) \ - g_object_freeze_notify ((GObject *) obj); \ while (n-- > 0) { \ const _PropertyEnums##suffix prop = *props++; \ + GParamSpec *pspec; \ \ - if (prop != PROP_0##suffix) { \ - nm_assert ((gsize) prop < G_N_ELEMENTS (obj_properties##suffix)); \ - nm_assert (obj_properties##suffix[prop]); \ - g_object_notify_by_pspec ((GObject *) obj, obj_properties##suffix[prop]); \ + if (prop == PROP_0##suffix) \ + continue; \ + \ + nm_assert ((gsize) prop < G_N_ELEMENTS (obj_properties##suffix)); \ + pspec = obj_properties##suffix[prop]; \ + nm_assert (pspec); \ + \ + if (!frozen) { \ + if (!pspec_first) { \ + pspec_first = pspec; \ + continue; \ + } \ + frozen = TRUE; \ + g_object_freeze_notify (gobj); \ + g_object_notify_by_pspec (gobj, pspec_first); \ } \ + g_object_notify_by_pspec (gobj, pspec); \ } \ - if (freeze_thaw) \ - g_object_thaw_notify ((GObject *) obj); \ + \ + if (frozen) \ + g_object_thaw_notify (gobj); \ + else if (pspec_first) \ + g_object_notify_by_pspec (gobj, pspec_first); \ } \ \ _nm_unused static inline void \ From e9b84221de7d8fe0aae39f0946d1c1473bc45949 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 20 Jul 2020 14:54:15 +0200 Subject: [PATCH 02/25] device: emit rx-bytes/tx-bytes change notification together This also groups the PropertiesChanged signal on D-Bus. --- src/devices/nm-device.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 90ca3eddd5..797de61488 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2197,17 +2197,23 @@ _stats_update_counters (NMDevice *self, guint64 rx_bytes) { NMDevicePrivate *priv; + gboolean tx_changed = FALSE; + gboolean rx_changed = FALSE; priv = NM_DEVICE_GET_PRIVATE (self); if (priv->stats.tx_bytes != tx_bytes) { priv->stats.tx_bytes = tx_bytes; - _notify (self, PROP_STATISTICS_TX_BYTES); + tx_changed = TRUE; } if (priv->stats.rx_bytes != rx_bytes) { priv->stats.rx_bytes = rx_bytes; - _notify (self, PROP_STATISTICS_RX_BYTES); + rx_changed = TRUE; } + + nm_gobject_notify_together (self, + tx_changed ? PROP_STATISTICS_TX_BYTES : PROP_0, + rx_changed ? PROP_STATISTICS_RX_BYTES : PROP_0); } static void From 1e870c675d09f997156cf6771281ccb5a7c7cf10 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 22 Jul 2020 10:51:00 +0200 Subject: [PATCH 03/25] shared: avoid heap allocation for temporary string in nm_utils_parse_inaddr_prefix_bin() --- shared/nm-glib-aux/nm-shared-utils.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index ee917fdf6e..f7ae5b88de 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -965,7 +965,7 @@ nm_utils_parse_inaddr_prefix_bin (int addr_family, slash = strchr (text, '/'); if (slash) - addrstr = addrstr_free = g_strndup (text, slash - text); + addrstr = nm_strndup_a (300, text, slash - text, &addrstr_free); else addrstr = text; @@ -975,9 +975,12 @@ nm_utils_parse_inaddr_prefix_bin (int addr_family, if (slash) { /* For IPv4, `ip addr add` supports the prefix-length as a netmask. We don't * do that. */ - prefix = _nm_utils_ascii_str_to_int64 (slash + 1, 10, + prefix = _nm_utils_ascii_str_to_int64 (&slash[1], + 10, 0, - addr_family == AF_INET ? 32 : 128, + addr_family == AF_INET + ? 32 + : 128, -1); if (prefix == -1) return FALSE; From ace515e697798659df5fc958e53765c94f8c1574 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 09:27:56 +0200 Subject: [PATCH 04/25] shared: add nm_hash_obfuscated_ptr_str() helper --- shared/nm-glib-aux/nm-hash-utils.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/shared/nm-glib-aux/nm-hash-utils.h b/shared/nm-glib-aux/nm-hash-utils.h index d1ab8dbc83..d1c76ea9a5 100644 --- a/shared/nm-glib-aux/nm-hash-utils.h +++ b/shared/nm-glib-aux/nm-hash-utils.h @@ -352,6 +352,19 @@ nm_hash_obfuscate_ptr (guint static_seed, gconstpointer val) * values in a global context. */ #define NM_HASH_OBFUSCATE_PTR(ptr) (nm_hash_obfuscate_ptr (1678382159u, ptr)) +static inline const char * +nm_hash_obfuscated_ptr_str (gconstpointer ptr, char buf[static 17]) +{ + int l; + + nm_assert (buf); + l = g_snprintf (buf, 17, NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR (ptr)); + nm_assert (l < 17); + return buf; +} + +#define nm_hash_obfuscated_ptr_str_a(ptr) (nm_hash_obfuscated_ptr_str ((ptr), g_alloca (17))) + /*****************************************************************************/ #endif /* __NM_HASH_UTILS_H__ */ From 97770bc7a834158dad449b09cc70991b7409f91f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 20 Jul 2020 15:17:36 +0200 Subject: [PATCH 05/25] shared: add nm_g_object_ref_set_take() helper macro --- shared/nm-glib-aux/nm-macros-internal.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h index 41f701f98e..a8a5360548 100644 --- a/shared/nm-glib-aux/nm-macros-internal.h +++ b/shared/nm-glib-aux/nm-macros-internal.h @@ -825,6 +825,26 @@ nm_g_object_unref (gpointer obj) _changed; \ }) +#define nm_g_object_ref_set_take(pp, obj) \ + ({ \ + typeof (*(pp)) *const _pp = (pp); \ + typeof (*_pp) const _obj = (obj); \ + typeof (*_pp) _p; \ + gboolean _changed = FALSE; \ + \ + nm_assert (!_pp || !*_pp || G_IS_OBJECT (*_pp)); \ + nm_assert (!_obj || G_IS_OBJECT (_obj)); \ + \ + if ( _pp \ + && ((_p = *_pp) != _obj)) { \ + *_pp = _obj; \ + nm_g_object_unref (_p); \ + _changed = TRUE; \ + } else \ + nm_g_object_unref (_obj); \ + _changed; \ + }) + /* basically, replaces * g_clear_pointer (&location, g_free) * with From 56a0aa06ac005fa991cfdbe5866857fbb9c865d3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 22 Jul 2020 11:38:14 +0200 Subject: [PATCH 06/25] shared: move addr-family helpers to "nm-std-aux.h" Handling address families is something we do all over the place. Move some simple helper code to "nm-std-aux.h". --- shared/nm-glib-aux/nm-shared-utils.h | 36 --------------- .../nm-glib-aux/tests/test-shared-general.c | 10 +++++ shared/nm-std-aux/nm-std-aux.h | 45 +++++++++++++++++++ 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 0f7c36e609..889b5f517a 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -68,42 +68,6 @@ G_STATIC_ASSERT (sizeof (int) == sizeof (gint32)); /*****************************************************************************/ -static inline char -nm_utils_addr_family_to_char (int addr_family) -{ - switch (addr_family) { - case AF_UNSPEC: return 'X'; - case AF_INET: return '4'; - case AF_INET6: return '6'; - } - g_return_val_if_reached ('?'); -} - -static inline gsize -nm_utils_addr_family_to_size (int addr_family) -{ - switch (addr_family) { - case AF_INET: return sizeof (in_addr_t); - case AF_INET6: return sizeof (struct in6_addr); - } - g_return_val_if_reached (0); -} - -static inline int -nm_utils_addr_family_from_size (gsize len) -{ - switch (len) { - case sizeof (in_addr_t): return AF_INET; - case sizeof (struct in6_addr): return AF_INET6; - } - return AF_UNSPEC; -} - -#define nm_assert_addr_family(addr_family) \ - nm_assert (NM_IN_SET ((addr_family), AF_INET, AF_INET6)) - -/*****************************************************************************/ - typedef struct { union { guint8 addr_ptr[1]; diff --git a/shared/nm-glib-aux/tests/test-shared-general.c b/shared/nm-glib-aux/tests/test-shared-general.c index f389770a7a..02b2f4e1ea 100644 --- a/shared/nm-glib-aux/tests/test-shared-general.c +++ b/shared/nm-glib-aux/tests/test-shared-general.c @@ -17,6 +17,16 @@ /*****************************************************************************/ +G_STATIC_ASSERT (NM_AF_UNSPEC == AF_UNSPEC); +G_STATIC_ASSERT (NM_AF_INET == AF_INET); +G_STATIC_ASSERT (NM_AF_INET6 == AF_INET6); + +G_STATIC_ASSERT (NM_AF_INET_SIZE == sizeof (in_addr_t)); +G_STATIC_ASSERT (NM_AF_INET_SIZE == sizeof (struct in_addr)); +G_STATIC_ASSERT (NM_AF_INET6_SIZE == sizeof (struct in6_addr)); + +/*****************************************************************************/ + static void test_gpid (void) { diff --git a/shared/nm-std-aux/nm-std-aux.h b/shared/nm-std-aux/nm-std-aux.h index 3262ef4c9d..ea43c96965 100644 --- a/shared/nm-std-aux/nm-std-aux.h +++ b/shared/nm-std-aux/nm-std-aux.h @@ -622,4 +622,49 @@ nm_steal_fd (int *p_fd) return -1; } +/*****************************************************************************/ + +#define NM_AF_UNSPEC 0 /* AF_UNSPEC */ +#define NM_AF_INET 2 /* AF_INET */ +#define NM_AF_INET6 10 /* AF_INET6 */ + +#define NM_AF_INET_SIZE 4 /* sizeof (in_addr_t) */ +#define NM_AF_INET6_SIZE 16 /* sizeof (stuct in6_addr) */ + +static inline char +nm_utils_addr_family_to_char (int addr_family) +{ + switch (addr_family) { + case NM_AF_UNSPEC: return 'X'; + case NM_AF_INET: return '4'; + case NM_AF_INET6: return '6'; + } + nm_assert_not_reached (); + return '?'; +} + +static inline size_t +nm_utils_addr_family_to_size (int addr_family) +{ + switch (addr_family) { + case NM_AF_INET: return NM_AF_INET_SIZE; + case NM_AF_INET6: return NM_AF_INET6_SIZE; + } + nm_assert_not_reached (); + return 0; +} + +static inline int +nm_utils_addr_family_from_size (size_t len) +{ + switch (len) { + case NM_AF_INET_SIZE: return NM_AF_INET; + case NM_AF_INET6_SIZE: return NM_AF_INET6; + } + return NM_AF_UNSPEC; +} + +#define nm_assert_addr_family(addr_family) \ + nm_assert (NM_IN_SET ((addr_family), NM_AF_INET, NM_AF_INET6)) + #endif /* __NM_STD_AUX_H__ */ From 7ae8100d7a6674c01414e50dbe27d1fb62b96d87 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 22 Jul 2020 11:56:00 +0200 Subject: [PATCH 07/25] shared: add NM_IS_IPv4() macro This is of course trivial. However, we use this macro at several places as and index into an array of length 2, to lookup either the IPv4 or IPv6 element. As such, this MUST return 0 or 1. This promise is what the macro should convey. --- shared/nm-std-aux/nm-std-aux.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/shared/nm-std-aux/nm-std-aux.h b/shared/nm-std-aux/nm-std-aux.h index ea43c96965..91cd6c37fa 100644 --- a/shared/nm-std-aux/nm-std-aux.h +++ b/shared/nm-std-aux/nm-std-aux.h @@ -667,4 +667,13 @@ nm_utils_addr_family_from_size (size_t len) #define nm_assert_addr_family(addr_family) \ nm_assert (NM_IN_SET ((addr_family), NM_AF_INET, NM_AF_INET6)) +#define NM_IS_IPv4(addr_family) \ + ({ \ + const int _addr_family = (addr_family); \ + \ + nm_assert_addr_family (_addr_family); \ + \ + (_addr_family == NM_AF_INET); \ + }) + #endif /* __NM_STD_AUX_H__ */ From 99296d4c6caee60065286210f1f5fb4d653861bd Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 22 Jul 2020 12:24:59 +0200 Subject: [PATCH 08/25] shared: add nm_strv_ptrarray_ensure() and nm_strv_ptrarray_find_first() helpers --- shared/nm-glib-aux/nm-shared-utils.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 889b5f517a..1fbf01131a 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1743,6 +1743,17 @@ GSource *nm_utils_g_main_context_create_integrate_source (GMainContext *internal /*****************************************************************************/ +static inline GPtrArray * +nm_strv_ptrarray_ensure (GPtrArray **p_arr) +{ + nm_assert (p_arr); + + if (G_UNLIKELY (!*p_arr)) + *p_arr = g_ptr_array_new_with_free_func (g_free); + + return *p_arr; +} + static inline void nm_strv_ptrarray_add_string_take (GPtrArray *cmd, char *str) @@ -1781,6 +1792,22 @@ nm_strv_ptrarray_take_gstring (GPtrArray *cmd, FALSE)); } +static inline gssize +nm_strv_ptrarray_find_first (const GPtrArray *strv, + const char *str) +{ + if (!strv) + return -1; + return nm_utils_strv_find_first ((char **) strv->pdata, strv->len, str); +} + +static inline gboolean +nm_strv_ptrarray_contains (const GPtrArray *strv, + const char *str) +{ + return nm_strv_ptrarray_find_first (strv, str) >= 0; +} + /*****************************************************************************/ int nm_utils_getpagesize (void); From fb6e9795b7cf8a2d3e94a3460c009a2451d18db8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 12:52:24 +0200 Subject: [PATCH 09/25] shared: add nm_g_array_append_new() helper --- shared/nm-glib-aux/nm-shared-utils.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 1fbf01131a..6aafd09e98 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1519,6 +1519,18 @@ nm_g_array_len (const GArray *arr) return arr ? arr->len : 0u; } +#define nm_g_array_append_new(arr, type) \ + ({ \ + GArray *_arr = (arr); \ + gsize _l; \ + \ + nm_assert (_arr); \ + _l = ((gsize) _arr->len) + 1u; \ + nm_assert (_l > _arr->len); \ + g_array_set_size (_arr, _l); \ + &g_array_index (arr, type, _l); \ + }) + /*****************************************************************************/ static inline guint From bc3439d14ffcd41488d10aefe6961221aaa63398 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 12:14:17 +0200 Subject: [PATCH 10/25] platform: add nmp_object_link_get_ifname() helper --- src/platform/nmp-object.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 7866caa428..14287d1d2f 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -995,4 +995,14 @@ nm_platform_lookup_object_by_addr_family (NMPlatform *platform, return nm_platform_lookup (platform, &lookup); } +/*****************************************************************************/ + +static inline const char * +nmp_object_link_get_ifname (const NMPObject *obj) +{ + if (!obj) + return NULL; + return NMP_OBJECT_CAST_LINK (obj)->name; +} + #endif /* __NMP_OBJECT_H__ */ From 04be1dbd80e068199c9cb579d620ed53b36d0bd1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 17:35:45 +0200 Subject: [PATCH 11/25] platform: add NMP_OBJECT_GET_ADDR_FAMILY() helper --- src/platform/nmp-object.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 14287d1d2f..f83f27d7f8 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -556,6 +556,21 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX (NMPObjectType obj_type) #define NMP_OBJECT_CAST_TFILTER(obj) _NMP_OBJECT_CAST (obj, tfilter, NMP_OBJECT_TYPE_TFILTER) #define NMP_OBJECT_CAST_LNK_WIREGUARD(obj) _NMP_OBJECT_CAST (obj, lnk_wireguard, NMP_OBJECT_TYPE_LNK_WIREGUARD) +static inline int +NMP_OBJECT_GET_ADDR_FAMILY (const NMPObject *obj) +{ + switch (NMP_OBJECT_GET_TYPE (obj)) { + case NMP_OBJECT_TYPE_IP4_ADDRESS: + case NMP_OBJECT_TYPE_IP4_ROUTE: + return AF_INET; + case NMP_OBJECT_TYPE_IP6_ADDRESS: + case NMP_OBJECT_TYPE_IP6_ROUTE: + return AF_INET6; + default: + return AF_UNSPEC; + } +} + static inline const NMPObject * nmp_object_ref (const NMPObject *obj) { From d4b7a3c27eeabb2cc220de84997436cc078edd62 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 17:48:30 +0200 Subject: [PATCH 12/25] platform: add nmp_object_ref_set() helper --- src/platform/nmp-object.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index f83f27d7f8..cef25ea79b 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -614,6 +614,25 @@ nmp_object_unref (const NMPObject *obj) _changed; \ }) +static inline gboolean +nmp_object_ref_set (const NMPObject **pp, const NMPObject *obj) +{ + gboolean _changed = FALSE; + const NMPObject *p; + + nm_assert (!pp || !*pp || NMP_OBJECT_IS_VALID (*pp)); + nm_assert (!obj || NMP_OBJECT_IS_VALID (obj)); + + if ( pp + && ((p = *pp) != obj)) { + nmp_object_ref (obj); + *pp = obj; + nmp_object_unref (p); + _changed = TRUE; + } + return _changed; +} + NMPObject *nmp_object_new (NMPObjectType obj_type, gconstpointer plobj); NMPObject *nmp_object_new_link (int ifindex); From 84d93315d81182deec59ca0365fc9ad0cd79f28c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 18:18:18 +0200 Subject: [PATCH 13/25] platform: add nmp_object_ip_route_is_best_defaut_route() helper --- src/platform/nmp-object.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index cef25ea79b..dd00522064 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -1039,4 +1039,22 @@ nmp_object_link_get_ifname (const NMPObject *obj) return NMP_OBJECT_CAST_LINK (obj)->name; } +static inline gboolean +nmp_object_ip_route_is_best_defaut_route (const NMPObject *obj) +{ + const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (obj); + + /* return whether @obj is considered a default-route. + * + * NMIP4Config/NMIP6Config tracks the (best) default-route explicitly, because + * at various places we act differently depending on whether there is a default-route + * configured. + * + * Note that this only considers the main routing table. */ + return r + && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r) + && nm_platform_route_table_is_main (r->table_coerced) + && r->type_coerced == nm_platform_route_type_coerce (1 /* RTN_UNICAST */); +} + #endif /* __NMP_OBJECT_H__ */ From 3f771c55ac9ee6b3179e9bf8b0743a2e544a108c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 17:49:23 +0200 Subject: [PATCH 14/25] core: use nmp_object_ref_set() instead of _nm_ip_config_best_default_route_set() _nm_ip_config_best_default_route_set() doesn't really do anything special. Use the generic helper function for the same job. Also because NMIP4Config in the current form will be replaced by something else, and this code needs to change. --- src/nm-ip4-config.c | 25 +++++++------------------ src/nm-ip4-config.h | 1 - src/nm-ip6-config.c | 14 +++++++------- 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 9ad8116423..35e7fb8f4b 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -436,23 +436,12 @@ _nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NM return obj_cur; } -gboolean -_nm_ip_config_best_default_route_set (const NMPObject **best_default_route, const NMPObject *new_candidate) -{ - if (new_candidate == *best_default_route) - return FALSE; - nmp_object_ref (new_candidate); - nm_clear_nmp_object (best_default_route); - *best_default_route = new_candidate; - return TRUE; -} - gboolean _nm_ip_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate) { new_candidate = _nm_ip_config_best_default_route_find_better (*best_default_route, new_candidate); - return _nm_ip_config_best_default_route_set (best_default_route, new_candidate); + return nmp_object_ref_set (best_default_route, new_candidate); } const NMPObject * @@ -1505,8 +1494,8 @@ nm_ip4_config_subtract (NMIP4Config *dst, } } if (changed_default_route) { - _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, - _nm_ip4_config_best_default_route_find (dst)); + nmp_object_ref_set (&dst_priv->best_default_route, + _nm_ip4_config_best_default_route_find (dst)); _notify (dst, PROP_GATEWAY); } if (changed) @@ -1659,7 +1648,7 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, nm_assert_not_reached (); changed = TRUE; } - if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) { + if (nmp_object_ref_set (&dst_priv->best_default_route, new_best_default_route)) { nm_assert (changed); _notify (dst, PROP_GATEWAY); } @@ -1896,7 +1885,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); } nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes, FALSE); - if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) + if (nmp_object_ref_set (&dst_priv->best_default_route, new_best_default_route)) _notify (dst, PROP_GATEWAY); _notify_routes (dst); } @@ -2990,8 +2979,8 @@ nm_ip4_config_nmpobj_remove (NMIP4Config *self, break; case NMP_OBJECT_TYPE_IP4_ROUTE: if (priv->best_default_route == obj_old) { - if (_nm_ip_config_best_default_route_set (&priv->best_default_route, - _nm_ip4_config_best_default_route_find (self))) + if (nmp_object_ref_set (&priv->best_default_route, + _nm_ip4_config_best_default_route_find (self))) _notify (self, PROP_GATEWAY); } _notify_routes (self); diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index ea06174976..f09d99134c 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -88,7 +88,6 @@ nm_ip_config_best_default_route_is (const NMPObject *obj) } const NMPObject *_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp); -gboolean _nm_ip_config_best_default_route_set (const NMPObject **best_default_route, const NMPObject *new_candidate); gboolean _nm_ip_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate); /*****************************************************************************/ diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index deb30e77d7..9c596bf95d 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -1120,8 +1120,8 @@ nm_ip6_config_subtract (NMIP6Config *dst, } } if (changed_default_route) { - _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, - _nm_ip6_config_best_default_route_find (dst)); + nmp_object_ref_set (&dst_priv->best_default_route, + _nm_ip6_config_best_default_route_find (dst)); _notify (dst, PROP_GATEWAY); } if (changed) @@ -1244,7 +1244,7 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, nm_assert_not_reached (); changed = TRUE; } - if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) { + if (nmp_object_ref_set (&dst_priv->best_default_route, new_best_default_route)) { nm_assert (changed); _notify (dst, PROP_GATEWAY); } @@ -1481,7 +1481,7 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); } nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE); - if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) + if (nmp_object_ref_set (&dst_priv->best_default_route, new_best_default_route)) _notify (dst, PROP_GATEWAY); _notify_routes (dst); } @@ -1955,7 +1955,7 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0) changed = TRUE; - if (_nm_ip_config_best_default_route_set (&priv->best_default_route, new_best_default_route)) { + if (nmp_object_ref_set (&priv->best_default_route, new_best_default_route)) { changed = TRUE; _notify (self, PROP_GATEWAY); } @@ -2458,8 +2458,8 @@ nm_ip6_config_nmpobj_remove (NMIP6Config *self, break; case NMP_OBJECT_TYPE_IP6_ROUTE: if (priv->best_default_route == obj_old) { - if (_nm_ip_config_best_default_route_set (&priv->best_default_route, - _nm_ip6_config_best_default_route_find (self))) + if (nmp_object_ref_set (&priv->best_default_route, + _nm_ip6_config_best_default_route_find (self))) _notify (self, PROP_GATEWAY); } _notify_routes (self); From 348d721b3fffbf187361380b3779b611bab353c1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 18:30:23 +0200 Subject: [PATCH 15/25] core: use nmp_object_ip_route_is_best_defaut_route() in NMIP4Config --- src/nm-ip4-config.c | 4 ++-- src/nm-ip4-config.h | 18 ------------------ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 35e7fb8f4b..45b91300d8 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -400,12 +400,12 @@ _nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NM && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cmp), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)) || NMP_OBJECT_GET_TYPE (obj_cur) == NMP_OBJECT_GET_TYPE (obj_cmp)); nm_assert ( !obj_cur - || nm_ip_config_best_default_route_is (obj_cur)); + || nmp_object_ip_route_is_best_defaut_route (obj_cur)); /* assumes that @obj_cur is already the best default route (or NULL). It checks whether * @obj_cmp is also a default route and returns the best of both. */ if ( obj_cmp - && nm_ip_config_best_default_route_is (obj_cmp)) { + && nmp_object_ip_route_is_best_defaut_route (obj_cmp)) { guint32 metric_cur, metric_cmp; if (!obj_cur) diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index f09d99134c..e57b456eb1 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -69,24 +69,6 @@ nm_ip_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatfor /*****************************************************************************/ -static inline gboolean -nm_ip_config_best_default_route_is (const NMPObject *obj) -{ - const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (obj); - - /* return whether @obj is considered a default-route. - * - * NMIP4Config/NMIP6Config tracks the (best) default-route explicitly, because - * at various places we act differently depending on whether there is a default-route - * configured. - * - * Note that this only considers the main routing table. */ - return r - && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r) - && nm_platform_route_table_is_main (r->table_coerced) - && r->type_coerced == nm_platform_route_type_coerce (1 /*RTN_UNICAST*/); -} - const NMPObject *_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp); gboolean _nm_ip_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate); From 4127c88ad2120ce9ad7cac78d972d90aaee0d3d0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 22 Jul 2020 10:33:16 +0200 Subject: [PATCH 16/25] core: move _nm_ip_config_merge_route_attributes() to "NetworkManagerUtils.c" and rename to nm_utils_ip_route_attribute_to_platform(). The function is independent from NMIP4Config. We also will use it outside of NMIP4Config. Also, "NetworkManagerUtils.c" already has similar functions that parse libnm structures to internal structures. --- src/NetworkManagerUtils.c | 108 +++++++++++++++++++++++++++++++++++- src/NetworkManagerUtils.h | 5 ++ src/nm-ip4-config.c | 112 ++------------------------------------ src/nm-ip4-config.h | 5 -- src/nm-ip6-config.c | 8 +-- 5 files changed, 120 insertions(+), 118 deletions(-) diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 7eaffb7dfc..aadafb5898 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -1186,7 +1186,7 @@ nm_utils_qdiscs_from_tc_setting (NMPlatform *platform, GET_ATTR ("limit", qdisc->tbf.limit, UINT32, uint32, 0); GET_ATTR ("latency", qdisc->tbf.latency, UINT32, uint32, 0); } -#undef GET_ADDR +#undef GET_ATTR g_ptr_array_add (qdiscs, q); } @@ -1263,3 +1263,109 @@ nm_utils_tfilters_from_tc_setting (NMPlatform *platform, return tfilters; } + +void +nm_utils_ip_route_attribute_to_platform (int addr_family, + NMIPRoute *s_route, + NMPlatformIPRoute *r, + guint32 route_table) +{ + GVariant *variant; + guint32 table; + NMIPAddr addr; + NMPlatformIP4Route *r4 = (NMPlatformIP4Route *) r; + NMPlatformIP6Route *r6 = (NMPlatformIP6Route *) r; + gboolean onlink; + + nm_assert (s_route); + nm_assert_addr_family (addr_family); + nm_assert (r); + +#define GET_ATTR(name, dst, variant_type, type, dflt) \ + G_STMT_START { \ + GVariant *_variant = nm_ip_route_get_attribute (s_route, ""name""); \ + \ + if ( _variant \ + && g_variant_is_of_type (_variant, G_VARIANT_TYPE_ ## variant_type)) \ + (dst) = g_variant_get_ ## type (_variant); \ + else \ + (dst) = (dflt); \ + } G_STMT_END + + if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TYPE)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + guint8 type; + + type = nm_utils_route_type_by_name (g_variant_get_string (variant, NULL)); + nm_assert (NM_IN_SET (type, + RTN_UNICAST, + RTN_LOCAL)); + + r->type_coerced = nm_platform_route_type_coerce (type); + } else + r->type_coerced = nm_platform_route_type_coerce (RTN_UNICAST); + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table, UINT32, uint32, 0); + + if ( !table + && r->type_coerced == nm_platform_route_type_coerce (RTN_LOCAL)) + r->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); + else + r->table_coerced = nm_platform_route_table_coerce (table ?: (route_table ?: RT_TABLE_MAIN)); + + if (addr_family == AF_INET) { + guint8 scope; + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, r4->tos, BYTE, byte, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_SCOPE, scope, BYTE, byte, RT_SCOPE_NOWHERE); + r4->scope_inv = nm_platform_route_scope_inv (scope); + } + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_ONLINK, onlink, BOOLEAN, boolean, FALSE); + + r->r_rtm_flags = ((onlink) ? (unsigned) RTNH_F_ONLINK : 0u); + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, r->window, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, r->cwnd, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, r->initcwnd, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, r->initrwnd, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, r->mtu, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, r->lock_window, BOOLEAN, boolean, FALSE); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, r->lock_cwnd, BOOLEAN, boolean, FALSE); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, r->lock_initcwnd, BOOLEAN, boolean, FALSE); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, r->lock_initrwnd, BOOLEAN, boolean, FALSE); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, r->lock_mtu, BOOLEAN, boolean, FALSE); + + if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + if (inet_pton (addr_family, g_variant_get_string (variant, NULL), &addr) == 1) { + if (addr_family == AF_INET) + r4->pref_src = addr.addr4; + else + r6->pref_src = addr.addr6; + } + } + + if ( addr_family == AF_INET6 + && (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_FROM)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + gs_free char *string = NULL; + guint8 plen = 128; + char *sep; + + string = g_variant_dup_string (variant, NULL); + sep = strchr (string, '/'); + if (sep) { + *sep = 0; + plen = _nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, 128, 255); + } + if ( plen <= 128 + && inet_pton (AF_INET6, string, &addr) == 1) { + r6->src = addr.addr6; + r6->src_plen = plen; + } + } +#undef GET_ATTR +} + + diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 38386c3dab..b0cb68e306 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -141,4 +141,9 @@ GPtrArray *nm_utils_tfilters_from_tc_setting (NMPlatform *platform, NMSettingTCConfig *s_tc, int ip_ifindex); +void nm_utils_ip_route_attribute_to_platform (int addr_family, + NMIPRoute *s_route, + NMPlatformIPRoute *r, + guint32 route_table); + #endif /* __NETWORKMANAGER_UTILS_H__ */ diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 45b91300d8..bd09ed511f 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -847,110 +847,6 @@ nm_ip4_config_commit (const NMIP4Config *self, return success; } -void -_nm_ip_config_merge_route_attributes (int addr_family, - NMIPRoute *s_route, - NMPlatformIPRoute *r, - guint32 route_table) -{ - GVariant *variant; - guint32 table; - NMIPAddr addr; - NMPlatformIP4Route *r4 = (NMPlatformIP4Route *) r; - NMPlatformIP6Route *r6 = (NMPlatformIP6Route *) r; - gboolean onlink; - - nm_assert (s_route); - nm_assert_addr_family (addr_family); - nm_assert (r); - -#define GET_ATTR(name, dst, variant_type, type, dflt) \ - G_STMT_START { \ - GVariant *_variant = nm_ip_route_get_attribute (s_route, ""name""); \ - \ - if ( _variant \ - && g_variant_is_of_type (_variant, G_VARIANT_TYPE_ ## variant_type)) \ - (dst) = g_variant_get_ ## type (_variant); \ - else \ - (dst) = (dflt); \ - } G_STMT_END - - if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TYPE)) - && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { - guint8 type; - - type = nm_utils_route_type_by_name (g_variant_get_string (variant, NULL)); - nm_assert (NM_IN_SET (type, - RTN_UNICAST, - RTN_LOCAL)); - - r->type_coerced = nm_platform_route_type_coerce (type); - } else - r->type_coerced = nm_platform_route_type_coerce (RTN_UNICAST); - - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table, UINT32, uint32, 0); - - if ( !table - && r->type_coerced == nm_platform_route_type_coerce (RTN_LOCAL)) - r->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); - else - r->table_coerced = nm_platform_route_table_coerce (table ?: (route_table ?: RT_TABLE_MAIN)); - - if (addr_family == AF_INET) { - guint8 scope; - - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, r4->tos, BYTE, byte, 0); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_SCOPE, scope, BYTE, byte, RT_SCOPE_NOWHERE); - r4->scope_inv = nm_platform_route_scope_inv (scope); - } - - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_ONLINK, onlink, BOOLEAN, boolean, FALSE); - - r->r_rtm_flags = ((onlink) ? (unsigned) RTNH_F_ONLINK : 0u); - - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, r->window, UINT32, uint32, 0); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, r->cwnd, UINT32, uint32, 0); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, r->initcwnd, UINT32, uint32, 0); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, r->initrwnd, UINT32, uint32, 0); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, r->mtu, UINT32, uint32, 0); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, r->lock_window, BOOLEAN, boolean, FALSE); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, r->lock_cwnd, BOOLEAN, boolean, FALSE); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, r->lock_initcwnd, BOOLEAN, boolean, FALSE); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, r->lock_initrwnd, BOOLEAN, boolean, FALSE); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, r->lock_mtu, BOOLEAN, boolean, FALSE); - - if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) - && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { - if (inet_pton (addr_family, g_variant_get_string (variant, NULL), &addr) == 1) { - if (addr_family == AF_INET) - r4->pref_src = addr.addr4; - else - r6->pref_src = addr.addr6; - } - } - - if ( addr_family == AF_INET6 - && (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_FROM)) - && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { - gs_free char *string = NULL; - guint8 plen = 128; - char *sep; - - string = g_variant_dup_string (variant, NULL); - sep = strchr (string, '/'); - if (sep) { - *sep = 0; - plen = _nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, 128, 255); - } - if ( plen <= 128 - && inet_pton (AF_INET6, string, &addr) == 1) { - r6->src = addr.addr6; - r6->src_plen = plen; - } - } -#undef GET_ATTR -} - void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, @@ -1040,10 +936,10 @@ nm_ip4_config_merge_setting (NMIP4Config *self, route.network = nm_utils_ip4_address_clear_host_address (route.network, route.plen); - _nm_ip_config_merge_route_attributes (AF_INET, - s_route, - NM_PLATFORM_IP_ROUTE_CAST (&route), - route_table); + nm_utils_ip_route_attribute_to_platform (AF_INET, + s_route, + NM_PLATFORM_IP_ROUTE_CAST (&route), + route_table); _add_route (self, NULL, &route, NULL); } diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index e57b456eb1..f1c4a57e85 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -89,11 +89,6 @@ const NMDedupMultiEntry *_nm_ip_config_lookup_ip_route (const NMDedupMultiIndex const NMPObject *needle, NMPlatformIPRouteCmpType cmp_type); -void _nm_ip_config_merge_route_attributes (int addr_family, - NMIPRoute *s_route, - NMPlatformIPRoute *r, - guint32 route_table); - /*****************************************************************************/ #define NM_TYPE_IP4_CONFIG (nm_ip4_config_get_type ()) diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 9c596bf95d..6c15e99765 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -721,10 +721,10 @@ nm_ip6_config_merge_setting (NMIP6Config *self, nm_utils_ip6_address_clear_host_address (&route.network, &route.network, route.plen); - _nm_ip_config_merge_route_attributes (AF_INET6, - s_route, - NM_PLATFORM_IP_ROUTE_CAST (&route), - route_table); + nm_utils_ip_route_attribute_to_platform (AF_INET6, + s_route, + NM_PLATFORM_IP_ROUTE_CAST (&route), + route_table); _add_route (self, NULL, &route, NULL); } From 5c273efb36b506d5fab326d0d45491a09222d232 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 22 Jul 2020 10:51:39 +0200 Subject: [PATCH 17/25] core: use nm_utils_parse_inaddr_prefix_bin() in nm_utils_ip_route_attribute_to_platform() We already have an implementation for parsing an address/plen string. Use it. --- src/NetworkManagerUtils.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index aadafb5898..230ffcda53 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -1349,20 +1349,17 @@ nm_utils_ip_route_attribute_to_platform (int addr_family, if ( addr_family == AF_INET6 && (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_FROM)) && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { - gs_free char *string = NULL; - guint8 plen = 128; - char *sep; + int prefix; - string = g_variant_dup_string (variant, NULL); - sep = strchr (string, '/'); - if (sep) { - *sep = 0; - plen = _nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, 128, 255); - } - if ( plen <= 128 - && inet_pton (AF_INET6, string, &addr) == 1) { + if (nm_utils_parse_inaddr_prefix_bin (addr_family, + g_variant_get_string (variant, NULL), + NULL, + &addr, + &prefix)) { + if (prefix < 0) + prefix = 128; r6->src = addr.addr6; - r6->src_plen = plen; + r6->src_plen = prefix; } } #undef GET_ATTR From d32074e2b6e637aab7e64c985c6da35a748344cc Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 20 Jul 2020 14:30:30 +0200 Subject: [PATCH 18/25] device: simplify device_ip_link_changed() for setting ip_iface _ip_iface_update() only had one caller. The code is simpler to understand by inlining it. Also, it is relevant where and how we set ip_iface_ and ip_ifindex_ fields. Keep the places few and easily understandable. --- src/devices/nm-device.c | 55 +++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 797de61488..a5eface7e4 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2003,36 +2003,6 @@ nm_device_set_ip_iface (NMDevice *self, const char *ifname) return ifindex > 0; } -static gboolean -_ip_iface_update (NMDevice *self, const char *ip_iface) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE (self); - - g_return_val_if_fail (priv->ip_iface, FALSE); - g_return_val_if_fail (priv->ip_ifindex > 0, FALSE); - g_return_val_if_fail (ip_iface, FALSE); - - if (!ip_iface[0]) - return FALSE; - - if (nm_streq (priv->ip_iface, ip_iface)) - return FALSE; - - _LOGI (LOGD_DEVICE, "ip-ifname: interface index %d renamed ip_iface (%d) from '%s' to '%s'", - priv->ifindex, - priv->ip_ifindex, - priv->ip_iface, - ip_iface); - g_free (priv->ip_iface_); - priv->ip_iface_ = g_strdup (ip_iface); - _notify (self, PROP_IP_IFACE); - return TRUE; -} - /*****************************************************************************/ int @@ -4469,23 +4439,42 @@ device_ip_link_changed (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const NMPlatformLink *pllink; + const char *ip_iface; priv->device_ip_link_changed_id = 0; - if (!priv->ip_ifindex) + if (priv->ip_ifindex <= 0) return G_SOURCE_REMOVE; + nm_assert (priv->ip_iface); + pllink = nm_platform_link_get (nm_device_get_platform (self), priv->ip_ifindex); if (!pllink) return G_SOURCE_REMOVE; - if (priv->ifindex <= 0 && pllink->mtu) + if ( priv->ifindex <= 0 + && pllink->mtu) _set_mtu (self, pllink->mtu); _stats_update_counters_from_pllink (self, pllink); - if (_ip_iface_update (self, pllink->name)) + ip_iface = pllink->name; + + if (!ip_iface[0]) + return FALSE; + + if (!nm_streq (priv->ip_iface, ip_iface)) { + _LOGI (LOGD_DEVICE, "ip-ifname: interface index %d renamed ip_iface (%d) from '%s' to '%s'", + priv->ifindex, + priv->ip_ifindex, + priv->ip_iface, + ip_iface); + g_free (priv->ip_iface_); + priv->ip_iface_ = g_strdup (ip_iface); + _notify (self, PROP_IP_IFACE); + nm_device_update_dynamic_ip_setup (self); + } return G_SOURCE_REMOVE; } From 88d057978d6f2c40f7d72ab7db4f723768cfef10 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 18 Jul 2020 19:01:04 +0200 Subject: [PATCH 19/25] core: add "nm-l3cfg.[hc]" --- Makefile.am | 3 ++ src/meson.build | 1 + src/nm-l3cfg.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ src/nm-l3cfg.h | 55 +++++++++++++++++++ src/nm-netns.c | 93 ++++++++++++++++++++++++++++++++ src/nm-netns.h | 3 ++ src/nm-types.h | 1 + 7 files changed, 293 insertions(+) create mode 100644 src/nm-l3cfg.c create mode 100644 src/nm-l3cfg.h diff --git a/Makefile.am b/Makefile.am index 01fd835e17..20bc92cb3d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2170,6 +2170,9 @@ src_libNetworkManager_la_SOURCES = \ src/nm-checkpoint-manager.c \ src/nm-checkpoint-manager.h \ \ + src/nm-l3cfg.c \ + src/nm-l3cfg.h \ + \ src/devices/nm-acd-manager.c \ src/devices/nm-acd-manager.h \ src/devices/nm-lldp-listener.c \ diff --git a/src/meson.build b/src/meson.build index 8ff9bd11de..eaba2b4ea5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -131,6 +131,7 @@ sources = files( 'nm-auth-manager.c', 'nm-auth-utils.c', 'nm-dbus-manager.c', + 'nm-l3cfg.c', 'nm-checkpoint.c', 'nm-checkpoint-manager.c', 'nm-config.c', diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c new file mode 100644 index 0000000000..aaaad02b6e --- /dev/null +++ b/src/nm-l3cfg.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include "nm-l3cfg.h" + +#include "platform/nm-platform.h" +#include "nm-netns.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NML3Cfg, + PROP_NETNS, + PROP_IFINDEX, +); + +struct _NML3CfgClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE (NML3Cfg, nm_l3cfg, G_TYPE_OBJECT) + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_CORE +#define _NMLOG_PREFIX_NAME "l3cfg" +#define _NMLOG(level, ...) \ + G_STMT_START { \ + nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \ + "l3cfg["NM_HASH_OBFUSCATE_PTR_FMT",ifindex=%d]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_HASH_OBFUSCATE_PTR (self), \ + nm_l3cfg_get_ifindex (self) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } G_STMT_END + +/*****************************************************************************/ + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NML3Cfg *self = NM_L3CFG (object); + + switch (prop_id) { + case PROP_NETNS: + /* construct-only */ + self->priv.netns = g_object_ref (g_value_get_pointer (value)); + nm_assert (NM_IS_NETNS (self->priv.netns)); + break; + case PROP_IFINDEX: + /* construct-only */ + self->priv.ifindex = g_value_get_int (value); + nm_assert (self->priv.ifindex > 0); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_l3cfg_init (NML3Cfg *self) +{ +} + +static void +constructed (GObject *object) +{ + NML3Cfg *self = NM_L3CFG (object); + + nm_assert (NM_IS_NETNS (self->priv.netns)); + nm_assert (self->priv.ifindex > 0); + + self->priv.platform = g_object_ref (nm_netns_get_platform (self->priv.netns)); + nm_assert (NM_IS_PLATFORM (self->priv.platform)); + + _LOGT ("created (netns="NM_HASH_OBFUSCATE_PTR_FMT")", + NM_HASH_OBFUSCATE_PTR (self->priv.netns)); + + G_OBJECT_CLASS (nm_l3cfg_parent_class)->constructed (object); +} + +NML3Cfg * +nm_l3cfg_new (NMNetns *netns, int ifindex) +{ + nm_assert (NM_IS_NETNS (netns)); + nm_assert (ifindex > 0); + + return g_object_new (NM_TYPE_L3CFG, + NM_L3CFG_NETNS, netns, + NM_L3CFG_IFINDEX, ifindex, + NULL); +} + +static void +finalize (GObject *object) +{ + NML3Cfg *self = NM_L3CFG (object); + + g_clear_object (&self->priv.netns); + g_clear_object (&self->priv.platform); + + _LOGT ("finalized"); + + G_OBJECT_CLASS (nm_l3cfg_parent_class)->finalize (object); +} + +static void +nm_l3cfg_class_init (NML3CfgClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = set_property; + object_class->constructed = constructed; + object_class->finalize = finalize; + + obj_properties[PROP_NETNS] = + g_param_spec_pointer (NM_L3CFG_NETNS, "", "", + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_IFINDEX] = + g_param_spec_int (NM_L3CFG_IFINDEX, "", "", + 0, + G_MAXINT, + 0, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h new file mode 100644 index 0000000000..4f035e231a --- /dev/null +++ b/src/nm-l3cfg.h @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#ifndef __NM_L3CFG_H__ +#define __NM_L3CFG_H__ + +#define NM_TYPE_L3CFG (nm_l3cfg_get_type ()) +#define NM_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_L3CFG, NML3Cfg)) +#define NM_L3CFG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_L3CFG, NML3CfgClass)) +#define NM_IS_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_L3CFG)) +#define NM_IS_L3CFG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_L3CFG)) +#define NM_L3CFG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_L3CFG, NML3CfgClass)) + +#define NM_L3CFG_NETNS "netns" +#define NM_L3CFG_IFINDEX "ifindex" + +struct _NML3Cfg { + GObject parent; + struct { + NMNetns *netns; + NMPlatform *platform; + int ifindex; + } priv; +}; + +typedef struct _NML3CfgClass NML3CfgClass; + +GType nm_l3cfg_get_type (void); + +NML3Cfg *nm_l3cfg_new (NMNetns *netns, int ifindex); + +static inline int +nm_l3cfg_get_ifindex (const NML3Cfg *self) +{ + nm_assert (NM_IS_L3CFG (self)); + + return self->priv.ifindex; +} + +static inline NMNetns * +nm_l3cfg_get_netns (const NML3Cfg *self) +{ + nm_assert (NM_IS_L3CFG (self)); + + return self->priv.netns; +} + +static inline NMPlatform * +nm_l3cfg_get_platform (const NML3Cfg *self) +{ + nm_assert (NM_IS_L3CFG (self)); + + return self->priv.platform; +} + +#endif /* __NM_L3CFG_H__ */ diff --git a/src/nm-netns.c b/src/nm-netns.c index 3652384ad9..cafb73164c 100644 --- a/src/nm-netns.c +++ b/src/nm-netns.c @@ -11,6 +11,7 @@ #include "NetworkManagerUtils.h" #include "nm-core-internal.h" +#include "nm-l3cfg.h" #include "platform/nm-platform.h" #include "platform/nmp-netns.h" #include "platform/nmp-rules-manager.h" @@ -25,6 +26,7 @@ typedef struct { NMPlatform *platform; NMPNetns *platform_netns; NMPRulesManager *rules_manager; + GHashTable *l3cfgs; } NMNetnsPrivate; struct _NMNetns { @@ -42,6 +44,18 @@ G_DEFINE_TYPE (NMNetns, nm_netns, G_TYPE_OBJECT); /*****************************************************************************/ +#define _NMLOG_DOMAIN LOGD_CORE +#define _NMLOG_PREFIX_NAME "netns" +#define _NMLOG(level, ...) \ + G_STMT_START { \ + nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \ + "netns["NM_HASH_OBFUSCATE_PTR_FMT"]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_HASH_OBFUSCATE_PTR (self) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } G_STMT_END + +/*****************************************************************************/ + NM_DEFINE_SINGLETON_GETTER (NMNetns, nm_netns_get, NM_TYPE_NETNS); /*****************************************************************************/ @@ -72,6 +86,80 @@ nm_netns_get_multi_idx (NMNetns *self) /*****************************************************************************/ +typedef struct { + int ifindex; + NML3Cfg *l3cfg; +} L3CfgData; + +static void +_l3cfg_data_free (gpointer ptr) +{ + L3CfgData *l3cfg_data = ptr; + + nm_g_slice_free (l3cfg_data); +} + +static void +_l3cfg_weak_notify (gpointer data, + GObject *where_the_object_was) +{ + NMNetns *self = NM_NETNS (data); + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE(data); + NML3Cfg *l3cfg = NM_L3CFG (where_the_object_was); + int ifindex = nm_l3cfg_get_ifindex (l3cfg); + + if (!g_hash_table_remove (priv->l3cfgs, &ifindex)) + nm_assert_not_reached (); + + if (NM_UNLIKELY (g_hash_table_size (priv->l3cfgs) == 0)) + g_object_unref (self); +} + +NML3Cfg * +nm_netns_access_l3cfg (NMNetns *self, + int ifindex) +{ + NMNetnsPrivate *priv; + L3CfgData *l3cfg_data; + + g_return_val_if_fail (NM_IS_NETNS (self), NULL); + g_return_val_if_fail (ifindex > 0, NULL); + + priv = NM_NETNS_GET_PRIVATE (self); + + l3cfg_data = g_hash_table_lookup (priv->l3cfgs, &ifindex); + + if (l3cfg_data) { + nm_log_trace (LOGD_CORE, + "l3cfg["NM_HASH_OBFUSCATE_PTR_FMT",ifindex=%d] %s", + NM_HASH_OBFUSCATE_PTR (l3cfg_data->l3cfg), + ifindex, + "referenced"); + return g_object_ref (l3cfg_data->l3cfg); + } + + l3cfg_data = g_slice_new (L3CfgData); + *l3cfg_data = (L3CfgData) { + .ifindex = ifindex, + .l3cfg = nm_l3cfg_new (self, ifindex), + }; + + if (!g_hash_table_add (priv->l3cfgs, l3cfg_data)) + nm_assert_not_reached (); + + if (NM_UNLIKELY (g_hash_table_size (priv->l3cfgs) == 1)) + g_object_ref (self); + + g_object_weak_ref (G_OBJECT (l3cfg_data->l3cfg), + _l3cfg_weak_notify, + self); + + /* Transfer ownership! We keep only a weak ref. */ + return l3cfg_data->l3cfg; +} + +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) @@ -109,6 +197,8 @@ constructed (GObject *object) if (!priv->platform) g_return_if_reached (); + priv->l3cfgs = g_hash_table_new_full (nm_pint_hash, nm_pint_equals, _l3cfg_data_free, NULL); + priv->platform_netns = nm_platform_netns_get (priv->platform); priv->rules_manager = nmp_rules_manager_new (priv->platform); @@ -152,7 +242,10 @@ dispose (GObject *object) NMNetns *self = NM_NETNS (object); NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + nm_assert (nm_g_hash_table_size (priv->l3cfgs) == 0); + g_clear_object (&priv->platform); + g_clear_pointer (&priv->l3cfgs, g_hash_table_unref); nm_clear_pointer (&priv->rules_manager, nmp_rules_manager_unref); diff --git a/src/nm-netns.h b/src/nm-netns.h index c65dd9076c..2af0242b8d 100644 --- a/src/nm-netns.h +++ b/src/nm-netns.h @@ -31,4 +31,7 @@ struct _NMDedupMultiIndex *nm_netns_get_multi_idx (NMNetns *self); #define NM_NETNS_GET (nm_netns_get ()) +NML3Cfg *nm_netns_access_l3cfg (NMNetns *netns, + int ifindex); + #endif /* __NM_NETNS_H__ */ diff --git a/src/nm-types.h b/src/nm-types.h index d2c999fada..5835c64188 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -23,6 +23,7 @@ typedef struct _NMDBusManager NMDBusManager; typedef struct _NMConfig NMConfig; typedef struct _NMConfigData NMConfigData; typedef struct _NMConnectivity NMConnectivity; +typedef struct _NML3Cfg NML3Cfg; typedef struct _NMDevice NMDevice; typedef struct _NMDhcpConfig NMDhcpConfig; typedef struct _NMProxyConfig NMProxyConfig; From ea1f0fc0a6350c78f06121720c6b1af58f1f987a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 11:11:50 +0200 Subject: [PATCH 20/25] device: let NMDevice track a NML3Cfg instance for each ifindex --- src/devices/nm-device.c | 84 ++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index a5eface7e4..e3d7ae3d46 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -285,6 +285,16 @@ typedef struct _NMDevicePrivate { char * udi; char * path; + union { + NML3Cfg *const l3cfg; + NML3Cfg *l3cfg_; + }; + + union { + NML3Cfg *const ip_l3cfg; + NML3Cfg *ip_l3cfg_; + }; + union { const char *const iface; char * iface_; @@ -1761,6 +1771,45 @@ nm_device_get_iface (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->iface; } +static gboolean +_set_ifindex (NMDevice *self, int ifindex, gboolean is_ip_ifindex) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gs_unref_object NML3Cfg *l3cfg_old = NULL; + NML3Cfg **p_l3cfg; + int *p_ifindex; + + if (ifindex < 0) + ifindex = 0; + + p_ifindex = is_ip_ifindex + ? &priv->ip_ifindex_ + : &priv->ifindex_; + + if (*p_ifindex == ifindex) + return FALSE; + + *p_ifindex = ifindex; + + p_l3cfg = is_ip_ifindex + ? &priv->ip_l3cfg_ + : &priv->l3cfg_; + + l3cfg_old = g_steal_pointer (p_l3cfg); + if (ifindex > 0) + *p_l3cfg = nm_netns_access_l3cfg (priv->netns, ifindex); + + _LOGD (LOGD_DEVICE, + "ifindex: set %sifindex %d%s%s%s%s%s%s", + is_ip_ifindex ? "ip-" : "", + ifindex, + NM_PRINT_FMT_QUOTED (l3cfg_old, " (old-l3cfg: ", nm_hash_obfuscated_ptr_str_a (l3cfg_old), ")", ""), + NM_PRINT_FMT_QUOTED (*p_l3cfg, " (l3cfg: ", nm_hash_obfuscated_ptr_str_a (*p_l3cfg), ")", "")); + + _notify (self, PROP_IFINDEX); + return TRUE; +} + /** * nm_device_take_over_link: * @self: the #NMDevice @@ -1825,10 +1874,7 @@ nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name, GError * NM_SET_OUT (old_name, g_steal_pointer (&name)); } - if (priv->ifindex != ifindex) { - priv->ifindex_ = ifindex; - _notify (self, PROP_IFINDEX); - } + _set_ifindex (self, ifindex, FALSE); return TRUE; } @@ -1931,7 +1977,8 @@ _set_ip_ifindex (NMDevice *self, NM_PRINT_FMT_QUOTE_STRING (ifname), ifindex); - priv->ip_ifindex_ = ifindex; + _set_ifindex (self, ifindex, TRUE); + if (!eq_name) { g_free (priv->ip_iface_); priv->ip_iface_ = g_strdup (ifname); @@ -4690,7 +4737,7 @@ nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const char *str; - int ifindex; + gboolean ifindex_changed; guint32 mtu; if (!NM_DEVICE_GET_CLASS (self)->can_update_from_platform_link (self, plink)) @@ -4735,12 +4782,12 @@ nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink mtu = plink ? plink->mtu : 0; _set_mtu (self, mtu); - ifindex = plink ? plink->ifindex : 0; - if (priv->ifindex != ifindex) { - priv->ifindex_ = ifindex; - _notify (self, PROP_IFINDEX); + ifindex_changed = _set_ifindex (self, + plink ? plink->ifindex : 0, + FALSE); + + if (ifindex_changed) NM_DEVICE_GET_CLASS (self)->link_changed (self, plink); - } device_update_interface_flags (self, plink); } @@ -5210,11 +5257,8 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) _parent_set_ifindex (self, 0, FALSE); - if (priv->ifindex > 0) { - priv->ifindex_ = 0; - _notify (self, PROP_IFINDEX); - } - priv->ip_ifindex_ = 0; + _set_ifindex (self, 0, FALSE); + _set_ifindex (self, 0, TRUE); if (nm_clear_g_free (&priv->ip_iface_)) _notify (self, PROP_IP_IFACE); @@ -17783,7 +17827,7 @@ constructor (GType type, pllink = nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface); if (pllink && link_type_compatible (self, pllink->type, NULL, NULL)) { - priv->ifindex_ = pllink->ifindex; + _set_ifindex (self, pllink->ifindex, FALSE); priv->up = NM_FLAGS_HAS (pllink->n_ifi_flags, IFF_UP); } } @@ -17903,10 +17947,8 @@ dispose (GObject *object) carrier_disconnected_action_cancel (self); - if (priv->ifindex > 0) { - priv->ifindex_ = 0; - _notify (self, PROP_IFINDEX); - } + _set_ifindex (self, 0, FALSE); + _set_ifindex (self, 0, TRUE); if (priv->settings) { g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_added, self); From b5c563329ac3edc8334bd05ad8f8e8d7fd9c8a8d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 11:21:44 +0200 Subject: [PATCH 21/25] l3cfg: notify NML3Cfg about NMPlatform changes in an idle handler We need to react to platform changes. Also, we usually want to delay the reaction to an idle handler. Instead of subscribing each NML3Cfg instance itself to platform changes, let only NMNetns do that. The goal is of course that each platform event only needs to notify the NML3Cfg instance, which collects the events and schedules them on the idle handler. --- src/nm-l3cfg.c | 7 +++++ src/nm-l3cfg.h | 6 +++++ src/nm-netns.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/nm-types.h | 11 ++++++++ 4 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index aaaad02b6e..6d2f26b8d8 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -35,6 +35,13 @@ G_DEFINE_TYPE (NML3Cfg, nm_l3cfg, G_TYPE_OBJECT) /*****************************************************************************/ +void +_nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags) +{ +} + +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index 4f035e231a..731b2b46fe 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -28,6 +28,12 @@ GType nm_l3cfg_get_type (void); NML3Cfg *nm_l3cfg_new (NMNetns *netns, int ifindex); +/*****************************************************************************/ + +void _nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags); + +/*****************************************************************************/ + static inline int nm_l3cfg_get_ifindex (const NML3Cfg *self) { diff --git a/src/nm-netns.c b/src/nm-netns.c index cafb73164c..ebefeea649 100644 --- a/src/nm-netns.c +++ b/src/nm-netns.c @@ -23,10 +23,13 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( ); typedef struct { + NMNetns *_self_signal_user_data; NMPlatform *platform; NMPNetns *platform_netns; NMPRulesManager *rules_manager; GHashTable *l3cfgs; + CList l3cfg_signal_pending_lst_head; + guint signal_pending_idle_id; } NMNetnsPrivate; struct _NMNetns { @@ -88,7 +91,9 @@ nm_netns_get_multi_idx (NMNetns *self) typedef struct { int ifindex; + guint32 signal_pending_flag; NML3Cfg *l3cfg; + CList signal_pending_lst; } L3CfgData; static void @@ -96,6 +101,8 @@ _l3cfg_data_free (gpointer ptr) { L3CfgData *l3cfg_data = ptr; + c_list_unlink_stale (&l3cfg_data->signal_pending_lst); + nm_g_slice_free (l3cfg_data); } @@ -140,8 +147,9 @@ nm_netns_access_l3cfg (NMNetns *self, l3cfg_data = g_slice_new (L3CfgData); *l3cfg_data = (L3CfgData) { - .ifindex = ifindex, - .l3cfg = nm_l3cfg_new (self, ifindex), + .ifindex = ifindex, + .l3cfg = nm_l3cfg_new (self, ifindex), + .signal_pending_lst = C_LIST_INIT (l3cfg_data->signal_pending_lst), }; if (!g_hash_table_add (priv->l3cfgs, l3cfg_data)) @@ -160,6 +168,52 @@ nm_netns_access_l3cfg (NMNetns *self, /*****************************************************************************/ +static gboolean +_platform_signal_on_idle_cb (gpointer user_data) +{ + gs_unref_object NMNetns *self = g_object_ref (NM_NETNS (user_data)); + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + L3CfgData *l3cfg_data; + + while ((l3cfg_data = c_list_first_entry (&priv->l3cfg_signal_pending_lst_head, L3CfgData, signal_pending_lst))) { + 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)); + } + + priv->signal_pending_idle_id = 0; + return G_SOURCE_REMOVE; +} + +static void +_platform_signal_cb (NMPlatform *platform, + int obj_type_i, + int ifindex, + gconstpointer platform_object, + int change_type_i, + NMNetns **p_self) +{ + NMNetns *self = NM_NETNS (*p_self); + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + const NMPObjectType obj_type = obj_type_i; + L3CfgData *l3cfg_data; + + l3cfg_data = g_hash_table_lookup (priv->l3cfgs, &ifindex); + if (!l3cfg_data) + return; + + l3cfg_data->signal_pending_flag |= nmp_object_type_to_flags (obj_type); + + if (!c_list_is_empty (&l3cfg_data->signal_pending_lst)) + return; + + c_list_link_tail (&priv->l3cfg_signal_pending_lst_head, &l3cfg_data->signal_pending_lst); + if (priv->signal_pending_idle_id == 0) + priv->signal_pending_idle_id = g_idle_add (_platform_signal_on_idle_cb, self); +} + +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) @@ -186,6 +240,10 @@ set_property (GObject *object, guint prop_id, static void nm_netns_init (NMNetns *self) { + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + + priv->_self_signal_user_data = self; + c_list_init (&priv->l3cfg_signal_pending_lst_head); } static void @@ -226,6 +284,8 @@ constructed (GObject *object) NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object); + + g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data); } NMNetns * @@ -243,6 +303,12 @@ dispose (GObject *object) NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); nm_assert (nm_g_hash_table_size (priv->l3cfgs) == 0); + nm_assert (c_list_is_empty (&priv->l3cfg_signal_pending_lst_head)); + + nm_clear_g_source (&priv->signal_pending_idle_id); + + if (priv->platform) + g_signal_handlers_disconnect_by_data (priv->platform, &priv->_self_signal_user_data); g_clear_object (&priv->platform); g_clear_pointer (&priv->l3cfgs, g_hash_table_unref); diff --git a/src/nm-types.h b/src/nm-types.h index 5835c64188..6277e4d811 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -236,6 +236,17 @@ typedef enum { NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1, } NMPObjectType; +static inline guint32 +nmp_object_type_to_flags (NMPObjectType obj_type) +{ + G_STATIC_ASSERT_EXPR (NMP_OBJECT_TYPE_MAX < 32); + + nm_assert (_NM_INT_NOT_NEGATIVE (obj_type)); + nm_assert (obj_type < NMP_OBJECT_TYPE_MAX); + + return ((guint32) 1u) << obj_type; +} + /** * NMIPConfigMergeFlags: * @NM_IP_CONFIG_MERGE_DEFAULT: no flags set From 62ea998d326424ffeec672db6a386ec2e1c813c9 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 11:57:31 +0200 Subject: [PATCH 22/25] l3cfg: track ifname in NML3Cfg --- src/nm-l3cfg.c | 39 +++++++++++++++++++++++++++++++++++++++ src/nm-l3cfg.h | 11 +++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index 6d2f26b8d8..5a0c08a492 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -5,6 +5,7 @@ #include "nm-l3cfg.h" #include "platform/nm-platform.h" +#include "platform/nmp-object.h" #include "nm-netns.h" /*****************************************************************************/ @@ -35,9 +36,43 @@ G_DEFINE_TYPE (NML3Cfg, nm_l3cfg, G_TYPE_OBJECT) /*****************************************************************************/ +static void +_load_link (NML3Cfg *self, gboolean initial) +{ + nm_auto_nmpobj const NMPObject *obj_old = NULL; + const NMPObject *obj; + const char *ifname; + const char *ifname_old; + + obj = nm_platform_link_get_obj (self->priv.platform, self->priv.ifindex, TRUE); + + if ( initial + && obj == self->priv.pllink) + return; + + obj_old = g_steal_pointer (&self->priv.pllink); + self->priv.pllink = nmp_object_ref (obj); + + ifname_old = nmp_object_link_get_ifname (obj_old); + ifname = nmp_object_link_get_ifname (self->priv.pllink); + + if (initial) { + _LOGT ("link ifname changed: %s%s%s (initial)", + NM_PRINT_FMT_QUOTE_STRING (ifname)); + } else if (!nm_streq0 (ifname, ifname_old)) { + _LOGT ("link ifname changed: %s%s%s (was %s%s%s)", + NM_PRINT_FMT_QUOTE_STRING (ifname), + NM_PRINT_FMT_QUOTE_STRING (ifname_old)); + } +} + +/*****************************************************************************/ + void _nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags) { + if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_LINK))) + _load_link (self, FALSE); } /*****************************************************************************/ @@ -89,6 +124,8 @@ constructed (GObject *object) NM_HASH_OBFUSCATE_PTR (self->priv.netns)); G_OBJECT_CLASS (nm_l3cfg_parent_class)->constructed (object); + + _load_link (self, TRUE); } NML3Cfg * @@ -111,6 +148,8 @@ finalize (GObject *object) g_clear_object (&self->priv.netns); g_clear_object (&self->priv.platform); + nm_clear_pointer (&self->priv.pllink, nmp_object_unref); + _LOGT ("finalized"); G_OBJECT_CLASS (nm_l3cfg_parent_class)->finalize (object); diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index 731b2b46fe..d612161c07 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -3,6 +3,8 @@ #ifndef __NM_L3CFG_H__ #define __NM_L3CFG_H__ +#include "platform/nmp-object.h" + #define NM_TYPE_L3CFG (nm_l3cfg_get_type ()) #define NM_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_L3CFG, NML3Cfg)) #define NM_L3CFG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_L3CFG, NML3CfgClass)) @@ -19,6 +21,7 @@ struct _NML3Cfg { NMNetns *netns; NMPlatform *platform; int ifindex; + const NMPObject *pllink; } priv; }; @@ -42,6 +45,14 @@ nm_l3cfg_get_ifindex (const NML3Cfg *self) return self->priv.ifindex; } +static inline const char * +nm_l3cfg_get_ifname (const NML3Cfg *self) +{ + nm_assert (NM_IS_L3CFG (self)); + + return nmp_object_link_get_ifname (self->priv.pllink); +} + static inline NMNetns * nm_l3cfg_get_netns (const NML3Cfg *self) { From 2eb5639a30de575a3ad13e8f554ac98496f1416c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 12:39:31 +0200 Subject: [PATCH 23/25] l3cfg: add NML3CfgPrivate data We have several fields in the header file, so that the frequently used accessors can be inlined. However, we also want some private data. Add a structure for that. --- src/nm-l3cfg.c | 11 +++++++++++ src/nm-l3cfg.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index 5a0c08a492..f415a2fc44 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -15,6 +15,10 @@ NM_GOBJECT_PROPERTIES_DEFINE (NML3Cfg, PROP_IFINDEX, ); +typedef struct _NML3CfgPrivate { + int dummy; +} NML3CfgPrivate; + struct _NML3CfgClass { GObjectClass parent; }; @@ -107,6 +111,11 @@ set_property (GObject *object, static void nm_l3cfg_init (NML3Cfg *self) { + NML3CfgPrivate *p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_L3CFG, NML3CfgPrivate); + + self->priv.p = p; } static void @@ -160,6 +169,8 @@ nm_l3cfg_class_init (NML3CfgClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + g_type_class_add_private (klass, sizeof (NML3CfgPrivate)); + object_class->set_property = set_property; object_class->constructed = constructed; object_class->finalize = finalize; diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index d612161c07..c7e3062269 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -15,6 +15,8 @@ #define NM_L3CFG_NETNS "netns" #define NM_L3CFG_IFINDEX "ifindex" +struct _NML3CfgPrivate; + struct _NML3Cfg { GObject parent; struct { @@ -22,6 +24,7 @@ struct _NML3Cfg { NMPlatform *platform; int ifindex; const NMPObject *pllink; + struct _NML3CfgPrivate *p; } priv; }; From 6e8a98776340fd0005021655f07d15135b62695c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 12:52:42 +0200 Subject: [PATCH 24/25] l3cfg: add nm_l3cfg_property_emit_register() API The NML3Cfg instance tracks and prepares the IP configuration. However, that is also partly exposed on other objects, like NMIP4Config's "route-data" property. Add an API, so that NMIP4Config can register itself to be notified when something relevant changes. This is an alternative to standard GObject properties and signals. They often seem more effort than worth. That is, because in this case, NMIP4Config.route-data has no other task then to re-emit the signal. So, to implement that with GObject properties/signals, we would have to add a property/signal to NML3Cfg, subscribe to it from NMIP4Config, and remit the signal. An alternative is to bind properties, but that would still be quite some extra code, and unclear that it would be simpler. Not to mention the overhead, as bindings are themself full GObject instances, that register to and emit signals by name. --- src/nm-l3cfg.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++- src/nm-l3cfg.h | 17 ++++++ src/nm-netns.c | 2 + 3 files changed, 167 insertions(+), 1 deletion(-) diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index f415a2fc44..aefaef1cd8 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -16,7 +16,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NML3Cfg, ); typedef struct _NML3CfgPrivate { - int dummy; + GArray *property_emit_list; } NML3CfgPrivate; struct _NML3CfgClass { @@ -40,6 +40,10 @@ G_DEFINE_TYPE (NML3Cfg, nm_l3cfg, G_TYPE_OBJECT) /*****************************************************************************/ +static void _property_emit_notify (NML3Cfg *self, NML3CfgPropertyEmitType emit_type); + +/*****************************************************************************/ + static void _load_link (NML3Cfg *self, gboolean initial) { @@ -77,6 +81,147 @@ _nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags) { if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_LINK))) _load_link (self, FALSE); + if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_IP4_ROUTE))) + _property_emit_notify (self, NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE); + if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_IP6_ROUTE))) + _property_emit_notify (self, NM_L3CFG_PROPERTY_EMIT_TYPE_IP6_ROUTE); +} + +/*****************************************************************************/ + +typedef struct { + GObject *target_obj; + const GParamSpec *target_property; + NML3CfgPropertyEmitType emit_type; +} PropertyEmitData; + +static void +_property_emit_notify (NML3Cfg *self, NML3CfgPropertyEmitType emit_type) +{ + gs_free PropertyEmitData *collected_heap = NULL; + PropertyEmitData *collected = NULL; + PropertyEmitData *emit_data; + guint num; + guint i; + guint j; + + if (!self->priv.p->property_emit_list) + return; + + num = 0; + emit_data = &g_array_index (self->priv.p->property_emit_list, PropertyEmitData, 0); + for (i = 0; i < self->priv.p->property_emit_list->len; i++, emit_data++) { + if (emit_data->emit_type == emit_type) { + collected = emit_data; + num++; + } + } + + if (num == 0) + return; + + if (num == 1) { + g_object_notify_by_pspec (collected->target_obj, (GParamSpec *) collected->target_property); + return; + } + + if (num < 300u / sizeof (*collected)) + collected = g_alloca (sizeof (PropertyEmitData) * num); + else { + collected_heap = g_new (PropertyEmitData, num); + collected = collected_heap; + } + + emit_data = &g_array_index (self->priv.p->property_emit_list, PropertyEmitData, 0); + for (i = 0, j = 0; i < self->priv.p->property_emit_list->len; i++, emit_data++) { + if (emit_data->emit_type == emit_type) { + collected[j++] = *emit_data; + g_object_ref (collected->target_obj); + } + } + + nm_assert (j == num); + + for (i = 0; i < num; i++) { + g_object_notify_by_pspec (collected[i].target_obj, (GParamSpec *) collected[i].target_property); + if (i > 0) + g_object_unref (collected[i].target_obj); + } +} + +void +nm_l3cfg_property_emit_register (NML3Cfg *self, + GObject *target_obj, + const GParamSpec *target_property, + NML3CfgPropertyEmitType emit_type) +{ + PropertyEmitData *emit_data; + guint i; + + nm_assert (NM_IS_L3CFG (self)); + nm_assert (G_IS_OBJECT (target_obj)); + nm_assert (target_property); + nm_assert (NM_IN_SET (emit_type, NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE, + NM_L3CFG_PROPERTY_EMIT_TYPE_IP6_ROUTE)); + nm_assert (target_property == nm_g_object_class_find_property_from_gtype (G_OBJECT_TYPE (target_obj), + target_property->name)); + + if (!self->priv.p->property_emit_list) + self->priv.p->property_emit_list = g_array_new (FALSE, FALSE, sizeof (PropertyEmitData)); + else { + emit_data = &g_array_index (self->priv.p->property_emit_list, PropertyEmitData, 0); + for (i = 0; i < self->priv.p->property_emit_list->len; i++, emit_data++) { + if ( emit_data->target_obj != target_obj + || emit_data->target_property != target_property) + continue; + nm_assert (emit_data->emit_type == emit_type); + emit_data->emit_type = emit_type; + return; + } + } + + emit_data = nm_g_array_append_new (self->priv.p->property_emit_list, PropertyEmitData); + *emit_data = (PropertyEmitData) { + .target_obj = target_obj, + .target_property = target_property, + .emit_type = emit_type, + }; +} + +void +nm_l3cfg_property_emit_unregister (NML3Cfg *self, + GObject *target_obj, + const GParamSpec *target_property) +{ + PropertyEmitData *emit_data; + guint i; + + nm_assert (NM_IS_L3CFG (self)); + nm_assert (G_IS_OBJECT (target_obj)); + nm_assert ( !target_property + || target_property == nm_g_object_class_find_property_from_gtype (G_OBJECT_TYPE (target_obj), + target_property->name)); + + if (!self->priv.p->property_emit_list) + return; + + for (i = self->priv.p->property_emit_list->len; i > 0; i--) { + emit_data = &g_array_index (self->priv.p->property_emit_list, PropertyEmitData, i); + + if (emit_data->target_obj != target_obj) + continue; + if ( target_property + && emit_data->target_property != target_property) + continue; + + g_array_remove_index_fast (self->priv.p->property_emit_list, i); + + if (target_property) { + /* if a target-property is given, we don't have another entry in + * the list. */ + return; + } + } } /*****************************************************************************/ @@ -154,6 +299,8 @@ finalize (GObject *object) { NML3Cfg *self = NM_L3CFG (object); + nm_assert (nm_g_array_len (self->priv.p->property_emit_list) == 0u); + g_clear_object (&self->priv.netns); g_clear_object (&self->priv.platform); diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index c7e3062269..7fc4b4b7d2 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -72,4 +72,21 @@ nm_l3cfg_get_platform (const NML3Cfg *self) return self->priv.platform; } +/*****************************************************************************/ + +typedef enum { + NM_L3CFG_PROPERTY_EMIT_TYPE_ANY, + NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE, + NM_L3CFG_PROPERTY_EMIT_TYPE_IP6_ROUTE, +} NML3CfgPropertyEmitType; + +void nm_l3cfg_property_emit_register (NML3Cfg *self, + GObject *target_obj, + const GParamSpec *target_property, + NML3CfgPropertyEmitType emit_type); + +void nm_l3cfg_property_emit_unregister (NML3Cfg *self, + GObject *target_obj, + const GParamSpec *target_property); + #endif /* __NM_L3CFG_H__ */ diff --git a/src/nm-netns.c b/src/nm-netns.c index ebefeea649..5b170c036b 100644 --- a/src/nm-netns.c +++ b/src/nm-netns.c @@ -286,6 +286,8 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object); g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data); + g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data); + g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data); } NMNetns * From a1dbaf5799420f91f54bdd629376b4d69f256eac Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 14:27:48 +0200 Subject: [PATCH 25/25] l3cfg: add NML3ConfigData Currently NMIP4Config and NMIP6Config both track the data to be configured, they expose properties on D-Bus, and they have logic for capturing and applying settings to platform. We will split that. - NMIP4Config and NMIP6Config will expose data on D-Bus. - NML3Cfg will have the logic for handling IP configuration. - NML3ConfigData will track data to be configured. NML3ConfigData mirrors NMIP4Config/NMIP6Config in many aspects. For now, this duplicates a lot of code. More will be done later. Eventually, NMIP4Config/NMIP6Config will drop the duplicated functionality. --- Makefile.am | 2 + src/meson.build | 1 + src/nm-l3-config-data.c | 868 ++++++++++++++++++++++++++++++++++++++++ src/nm-l3-config-data.h | 63 +++ 4 files changed, 934 insertions(+) create mode 100644 src/nm-l3-config-data.c create mode 100644 src/nm-l3-config-data.h diff --git a/Makefile.am b/Makefile.am index 20bc92cb3d..e8e72febaf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2170,6 +2170,8 @@ src_libNetworkManager_la_SOURCES = \ src/nm-checkpoint-manager.c \ src/nm-checkpoint-manager.h \ \ + src/nm-l3-config-data.c \ + src/nm-l3-config-data.h \ src/nm-l3cfg.c \ src/nm-l3cfg.h \ \ diff --git a/src/meson.build b/src/meson.build index eaba2b4ea5..468f2159da 100644 --- a/src/meson.build +++ b/src/meson.build @@ -131,6 +131,7 @@ sources = files( 'nm-auth-manager.c', 'nm-auth-utils.c', 'nm-dbus-manager.c', + 'nm-l3-config-data.c', 'nm-l3cfg.c', 'nm-checkpoint.c', 'nm-checkpoint-manager.c', diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c new file mode 100644 index 0000000000..d20df9dc36 --- /dev/null +++ b/src/nm-l3-config-data.c @@ -0,0 +1,868 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include "nm-l3-config-data.h" + +#include "nm-core-internal.h" +#include "platform/nm-platform.h" +#include "platform/nmp-object.h" +#include "NetworkManagerUtils.h" + +/*****************************************************************************/ + +typedef struct { + NMDedupMultiIdxType parent; + NMPObjectType obj_type; +} DedupMultiIdxType; + +struct _NML3ConfigData { + NMDedupMultiIndex *multi_idx; + + union { + struct { + DedupMultiIdxType idx_addresses_6; + DedupMultiIdxType idx_addresses_4; + }; + DedupMultiIdxType idx_addresses_x[2]; + }; + + union { + struct { + DedupMultiIdxType idx_routes_6; + DedupMultiIdxType idx_routes_4; + }; + DedupMultiIdxType idx_routes_x[2]; + }; + + union { + struct { + const NMPObject *best_default_route_6; + const NMPObject *best_default_route_4; + }; + const NMPObject *best_default_route_x[2]; + }; + + union { + struct { + GArray *nameservers_6; + GArray *nameservers_4; + }; + GArray *nameservers_x[2]; + }; + + union { + struct { + GPtrArray *domains_6; + GPtrArray *domains_4; + }; + GPtrArray *domains_x[2]; + }; + + union { + struct { + GPtrArray *searches_6; + GPtrArray *searches_4; + }; + GPtrArray *searches_x[2]; + }; + + union { + struct { + GPtrArray *dns_options_6; + GPtrArray *dns_options_4; + }; + GPtrArray *dns_options_x[2]; + }; + + union { + struct { + int dns_priority_6; + int dns_priority_4; + }; + int dns_priority_x[2]; + }; + + NMSettingConnectionMdns mdns; + NMSettingConnectionLlmnr llmnr; + + int ref_count; + + bool is_sealed:1; +}; + +/*****************************************************************************/ + +static gboolean +_route_valid_4 (const NMPlatformIP4Route *r) +{ + return r + && r->plen <= 32 + && r->network == nm_utils_ip4_address_clear_host_address (r->network, r->plen); +} + +static gboolean +_route_valid_6 (const NMPlatformIP6Route *r) +{ + struct in6_addr n; + + return r + && r->plen <= 128 + && (memcmp (&r->network, + nm_utils_ip6_address_clear_host_address (&n, &r->network, r->plen), + sizeof (n)) == 0); +} + +static gboolean +_route_valid (int addr_family, gconstpointer r) +{ + nm_assert_addr_family (addr_family); + + return addr_family == AF_INET + ? _route_valid_4 (r) + : _route_valid_6 (r); +} + +static gboolean +NM_IS_L3_CONFIG_DATA (const NML3ConfigData *self, gboolean allow_sealed) +{ + return self + && self->ref_count > 0 + && ( allow_sealed + || !self->is_sealed); +} + +static GArray * +_garray_ensure_for_addrbin (GArray **p_arr, + int addr_family) +{ + nm_assert (p_arr); + nm_assert_addr_family (addr_family); + + if (G_UNLIKELY (!*p_arr)) { + *p_arr = g_array_new (FALSE, + FALSE, + nm_utils_addr_family_to_size (addr_family)); + } + return *p_arr; +} + +static void +_idx_obj_id_hash_update (const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj *obj, + NMHashState *h) +{ + nmp_object_id_hash_update ((NMPObject *) obj, h); +} + +static gboolean +_idx_obj_id_equal (const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj *obj_a, + const NMDedupMultiObj *obj_b) +{ + return nmp_object_id_equal ((NMPObject *) obj_a, (NMPObject *) obj_b); +} + +static void +_idx_type_init (DedupMultiIdxType *idx_type, + NMPObjectType obj_type) +{ + static const NMDedupMultiIdxTypeClass idx_type_class = { + .idx_obj_id_hash_update = _idx_obj_id_hash_update, + .idx_obj_id_equal = _idx_obj_id_equal, + }; + + nm_dedup_multi_idx_type_init (&idx_type->parent, + &idx_type_class); + idx_type->obj_type = obj_type; +} + +NML3ConfigData * +nm_l3_config_data_new (NMDedupMultiIndex *multi_idx) +{ + NML3ConfigData *self; + + nm_assert (multi_idx); + + self = g_slice_new (NML3ConfigData); + *self = (NML3ConfigData) { + .ref_count = 1, + .multi_idx = nm_dedup_multi_index_ref (multi_idx), + .mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT, + .llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT, + }; + + _idx_type_init (&self->idx_addresses_4, NMP_OBJECT_TYPE_IP4_ADDRESS); + _idx_type_init (&self->idx_addresses_6, NMP_OBJECT_TYPE_IP4_ADDRESS); + _idx_type_init (&self->idx_routes_4, NMP_OBJECT_TYPE_IP4_ROUTE); + _idx_type_init (&self->idx_routes_6, NMP_OBJECT_TYPE_IP6_ROUTE); + + return self; +} + +NML3ConfigData * +nm_l3_config_data_ref (NML3ConfigData *self) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); + self->ref_count++; + return self; +} + +NML3ConfigData * +nm_l3_config_data_ref_and_seal (NML3ConfigData *self) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); + self->is_sealed = TRUE; + self->ref_count++; + return self; +} + +NML3ConfigData * +nm_l3_config_data_seal (NML3ConfigData *self) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); + self->is_sealed = TRUE; + return self; +} + +gboolean +nm_l3_config_data_is_sealed (NML3ConfigData *self) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); + return self->is_sealed; +} + +void +nm_l3_config_data_unref (NML3ConfigData *self) +{ + if (!self) + return; + + nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); + if (--self->ref_count > 0) + return; + + nm_dedup_multi_index_remove_idx (self->multi_idx, &self->idx_addresses_4.parent); + nm_dedup_multi_index_remove_idx (self->multi_idx, &self->idx_addresses_6.parent); + nm_dedup_multi_index_remove_idx (self->multi_idx, &self->idx_routes_4.parent); + nm_dedup_multi_index_remove_idx (self->multi_idx, &self->idx_routes_6.parent); + + nmp_object_unref (self->best_default_route_4); + nmp_object_unref (self->best_default_route_6); + + nm_clear_pointer (&self->nameservers_4, g_array_unref); + nm_clear_pointer (&self->nameservers_6, g_array_unref); + + nm_clear_pointer (&self->domains_4, g_ptr_array_unref); + nm_clear_pointer (&self->domains_6, g_ptr_array_unref); + + nm_clear_pointer (&self->searches_4, g_ptr_array_unref); + nm_clear_pointer (&self->searches_6, g_ptr_array_unref); + + nm_clear_pointer (&self->dns_options_4, g_ptr_array_unref); + nm_clear_pointer (&self->dns_options_6, g_ptr_array_unref); + + nm_dedup_multi_index_unref (self->multi_idx); + + nm_g_slice_free (self); +} + +/*****************************************************************************/ + +const NMDedupMultiHeadEntry * +nm_l3_config_data_lookup_addresses (const NML3ConfigData *self, + int addr_family) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); + nm_assert_addr_family (addr_family); + + return nm_dedup_multi_index_lookup_head (self->multi_idx, + &self->idx_addresses_x[NM_IS_IPv4 (addr_family)].parent, + NULL); +} + +const NMDedupMultiHeadEntry * +nm_l3_config_data_lookup_routes (const NML3ConfigData *self, + int addr_family) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); + nm_assert_addr_family (addr_family); + + return nm_dedup_multi_index_lookup_head (self->multi_idx, + &self->idx_routes_x[NM_IS_IPv4 (addr_family)].parent, + NULL); +} + +/*****************************************************************************/ + +static gboolean +_l3_config_data_add_obj (NMDedupMultiIndex *multi_idx, + DedupMultiIdxType *idx_type, + int ifindex, + const NMPObject *obj_new, + const NMPlatformObject *pl_new, + gboolean merge, + gboolean append_force, + const NMPObject **out_obj_old /* returns a reference! */, + const NMPObject **out_obj_new /* does not return a reference */) +{ + NMPObject obj_new_stackinit; + const NMDedupMultiEntry *entry_old; + const NMDedupMultiEntry *entry_new; + + nm_assert (multi_idx); + nm_assert (idx_type); + nm_assert (NM_IN_SET (idx_type->obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ADDRESS, + NMP_OBJECT_TYPE_IP6_ROUTE)); + nm_assert (ifindex > 0); + + /* we go through extra lengths to accept a full obj_new object. That one, + * can be reused by increasing the ref-count. */ + if (!obj_new) { + nm_assert (pl_new); + obj_new = nmp_object_stackinit (&obj_new_stackinit, idx_type->obj_type, pl_new); + NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (&obj_new_stackinit)->ifindex = ifindex; + } else { + nm_assert (!pl_new); + nm_assert (NMP_OBJECT_GET_TYPE (obj_new) == idx_type->obj_type); + if (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj_new)->ifindex != ifindex) { + obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new); + NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (&obj_new_stackinit)->ifindex = ifindex; + } + } + nm_assert (NMP_OBJECT_GET_TYPE (obj_new) == idx_type->obj_type); + nm_assert (nmp_object_is_alive (obj_new)); + + entry_old = nm_dedup_multi_index_lookup_obj (multi_idx, &idx_type->parent, obj_new); + + if (entry_old) { + gboolean modified = FALSE; + const NMPObject *obj_old = entry_old->obj; + + if (nmp_object_equal (obj_new, obj_old)) { + nm_dedup_multi_entry_set_dirty (entry_old, FALSE); + goto append_force_and_out; + } + + /* if @merge, we merge the new object with the existing one. + * Otherwise, we replace it entirely. */ + if (merge) { + switch (idx_type->obj_type) { + case NMP_OBJECT_TYPE_IP4_ADDRESS: + case NMP_OBJECT_TYPE_IP6_ADDRESS: + /* for addresses that we read from the kernel, we keep the timestamps as defined + * by the previous source (item_old). The reason is, that the other source configured the lifetimes + * with "what should be" and the kernel values are "what turned out after configuring it". + * + * For other sources, the longer lifetime wins. */ + if ( ( obj_new->ip_address.addr_source == NM_IP_CONFIG_SOURCE_KERNEL + && obj_old->ip_address.addr_source != NM_IP_CONFIG_SOURCE_KERNEL) + || nm_platform_ip_address_cmp_expiry (NMP_OBJECT_CAST_IP_ADDRESS (obj_old), NMP_OBJECT_CAST_IP_ADDRESS(obj_new)) > 0) { + obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_address.timestamp = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->timestamp; + obj_new_stackinit.ip_address.lifetime = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->lifetime; + obj_new_stackinit.ip_address.preferred = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->preferred; + modified = TRUE; + } + + /* keep the maximum addr_source. */ + if (obj_new->ip_address.addr_source < obj_old->ip_address.addr_source) { + obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_address.addr_source = obj_old->ip_address.addr_source; + modified = TRUE; + } + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + case NMP_OBJECT_TYPE_IP6_ROUTE: + /* keep the maximum rt_source. */ + if (obj_new->ip_route.rt_source < obj_old->ip_route.rt_source) { + obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_route.rt_source = obj_old->ip_route.rt_source; + modified = TRUE; + } + break; + default: + nm_assert_not_reached (); + break; + } + + if ( modified + && nmp_object_equal (obj_new, obj_old)) { + nm_dedup_multi_entry_set_dirty (entry_old, FALSE); + goto append_force_and_out; + } + } + } + + if (!nm_dedup_multi_index_add_full (multi_idx, + &idx_type->parent, + obj_new, + append_force + ? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE + : NM_DEDUP_MULTI_IDX_MODE_APPEND, + NULL, + entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING, + NULL, + &entry_new, + out_obj_old)) { + nm_assert_not_reached (); + NM_SET_OUT (out_obj_new, NULL); + return FALSE; + } + + NM_SET_OUT (out_obj_new, entry_new->obj); + return TRUE; + +append_force_and_out: + NM_SET_OUT (out_obj_old, nmp_object_ref (entry_old->obj)); + NM_SET_OUT (out_obj_new, entry_old->obj); + if (append_force) { + if (nm_dedup_multi_entry_reorder (entry_old, NULL, TRUE)) + return TRUE; + } + return FALSE; +} + +static const NMPObject * +_l3_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp) +{ + nm_assert ( !obj_cur + || NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cur), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); + nm_assert ( !obj_cmp + || ( !obj_cur + && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cmp), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)) + || NMP_OBJECT_GET_TYPE (obj_cur) == NMP_OBJECT_GET_TYPE (obj_cmp)); + nm_assert ( !obj_cur + || nmp_object_ip_route_is_best_defaut_route (obj_cur)); + + /* assumes that @obj_cur is already the best default route (or NULL). It checks whether + * @obj_cmp is also a default route and returns the best of both. */ + if ( obj_cmp + && nmp_object_ip_route_is_best_defaut_route (obj_cmp)) { + guint32 metric_cur, metric_cmp; + + if (!obj_cur) + return obj_cmp; + + if (obj_cur == obj_cmp) + return obj_cmp; + + metric_cur = NMP_OBJECT_CAST_IP_ROUTE (obj_cur)->metric; + metric_cmp = NMP_OBJECT_CAST_IP_ROUTE (obj_cmp)->metric; + + if (metric_cmp < metric_cur) + return obj_cmp; + + if (metric_cmp == metric_cur) { + int c; + + /* Routes have the same metric. We still want to deterministically + * prefer one or the other. It's important to consistently choose one + * or the other, so that the order doesn't matter how routes are added + * (and merged). */ + c = nmp_object_cmp (obj_cur, obj_cmp); + if (c != 0) + return c < 0 ? obj_cur : obj_cmp; + + /* as last resort, compare pointers. */ + if (((uintptr_t) ((void *) (obj_cmp))) < ((uintptr_t) ((void *) (obj_cur)))) + return obj_cmp; + } + } + return obj_cur; +} + +static gboolean +_l3_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate) +{ + new_candidate = _l3_config_best_default_route_find_better (*best_default_route, + new_candidate); + return nmp_object_ref_set (best_default_route, new_candidate); +} + +gboolean +_nm_l3_config_data_add_route (NML3ConfigData *self, + int addr_family, + int ifindex, + const NMPObject *obj_new, + const NMPlatformIPRoute *pl_new, + const NMPObject **out_obj_new, + gboolean *out_changed_best_default_route) +{ + const gboolean IS_IPv4 = NM_IS_IPv4 (addr_family); + nm_auto_nmpobj const NMPObject *obj_old = NULL; + const NMPObject *obj_new_2; + gboolean changed = FALSE; + gboolean changed_best_default_route = FALSE; + + nm_assert_addr_family (addr_family); + nm_assert (ifindex > 0); + nm_assert ((!pl_new) != (!obj_new)); + nm_assert ( !pl_new + || _route_valid (addr_family, pl_new)); + nm_assert ( !obj_new + || ( NMP_OBJECT_GET_ADDR_FAMILY (obj_new) == addr_family + && _route_valid (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_new)))); + + if (_l3_config_data_add_obj (self->multi_idx, + addr_family == AF_INET + ? &self->idx_routes_4 + : &self->idx_routes_6, + ifindex, + obj_new, + (const NMPlatformObject *) pl_new, + TRUE, + FALSE, + &obj_old, + &obj_new_2)) { + + if ( self->best_default_route_x[IS_IPv4] == obj_old + && obj_old != obj_new_2) { + changed_best_default_route = TRUE; + nm_clear_nmp_object (&self->best_default_route_x[IS_IPv4]); + } + + if (_l3_config_best_default_route_merge (&self->best_default_route_x[IS_IPv4], + obj_new_2)) + changed_best_default_route = TRUE; + + changed = TRUE; + } + + NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2)); + NM_SET_OUT (out_changed_best_default_route, changed_best_default_route); + return changed; +} + +gboolean +_nm_l3_config_data_add_address (NML3ConfigData *self, + int addr_family, + int ifindex, + const NMPObject *obj_new, + const NMPlatformIPAddress *pl_new) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + nm_assert (ifindex > 0); + nm_assert ((!pl_new) != (!obj_new)); + nm_assert ( !obj_new + || NMP_OBJECT_GET_ADDR_FAMILY (obj_new) == addr_family); + + return _l3_config_data_add_obj (self->multi_idx, + addr_family == AF_INET + ? &self->idx_addresses_4 + : &self->idx_addresses_6, + ifindex, + obj_new, + (const NMPlatformObject *) pl_new, + TRUE, + FALSE, + NULL, + NULL); +} + +/*****************************************************************************/ + +static gboolean +_check_and_add_domain (GPtrArray **p_arr, const char *domain) +{ + gs_free char *copy = NULL; + gsize len; + + nm_assert (p_arr); + g_return_val_if_fail (domain, FALSE); + + if (domain[0] == '\0') + g_return_val_if_reached (FALSE); + + if (domain[0] == '.' || strstr (domain, "..")) + return FALSE; + + len = strlen (domain); + if (domain[len - 1] == '.') { + copy = g_strndup (domain, len - 1); + domain = copy; + } + + if (nm_strv_ptrarray_contains (*p_arr, domain)) + return FALSE; + + nm_strv_ptrarray_add_string_take (nm_strv_ptrarray_ensure (p_arr), + g_steal_pointer (©) + ?: g_strdup (domain)); + return TRUE; +} + +gboolean +_nm_l3_config_data_add_domain (NML3ConfigData *self, + int addr_family, + const char *domain) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + + return _check_and_add_domain (&self->domains_x[NM_IS_IPv4 (addr_family)], domain); +} + +gboolean +_nm_l3_config_data_add_search (NML3ConfigData *self, + int addr_family, + const char *search) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + + return _check_and_add_domain (&self->searches_x[NM_IS_IPv4 (addr_family)], search); +} + +gboolean +_nm_l3_config_data_add_dns_option (NML3ConfigData *self, + int addr_family, + const char *dns_option) +{ + GPtrArray **p_arr; + + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + + g_return_val_if_fail (dns_option, FALSE); + + if (!dns_option[0]) + g_return_val_if_reached (FALSE); + + p_arr = &self->dns_options_x[NM_IS_IPv4 (addr_family)]; + + if (nm_strv_ptrarray_contains (*p_arr, dns_option)) + return FALSE; + + nm_strv_ptrarray_add_string_dup (nm_strv_ptrarray_ensure (p_arr), + dns_option); + return TRUE; +} + +gboolean +_nm_l3_config_data_set_dns_priority (NML3ConfigData *self, + int addr_family, + int dns_priority) +{ + int *p_val; + + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + + p_val = &self->dns_priority_x[NM_IS_IPv4 (addr_family)]; + if (*p_val == dns_priority) + return FALSE; + + *p_val = dns_priority; + return TRUE; +} + +/*****************************************************************************/ + +static void +_init_from_connection_ip (NML3ConfigData *self, + int addr_family, + int ifindex, + NMConnection *connection, + guint32 route_table, + guint32 route_metric) +{ + const gboolean IS_IPv4 = NM_IS_IPv4 (addr_family); + NMSettingIPConfig *s_ip; + guint naddresses; + guint nroutes; + guint nnameservers; + guint nsearches; + const char *gateway_str; + NMIPAddr gateway_bin; + guint i; + int idx; + + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert (ifindex > 0); + nm_assert_addr_family (addr_family); + nm_assert (!connection || NM_IS_CONNECTION (connection)); + + if (!connection) + return; + + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); + if (!s_ip) + return; + + if ( !nm_setting_ip_config_get_never_default (s_ip) + && (gateway_str = nm_setting_ip_config_get_gateway (s_ip)) + && inet_pton (addr_family, gateway_str, &gateway_bin) == 1 + && !nm_ip_addr_is_null (addr_family, &gateway_bin)) { + NMPlatformIPXRoute r; + + if (IS_IPv4) { + r.r4 = (NMPlatformIP4Route) { + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .gateway = gateway_bin.addr4, + .table_coerced = nm_platform_route_table_coerce (route_table), + .metric = route_metric, + }; + } else { + r.r6 = (NMPlatformIP6Route) { + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .gateway = gateway_bin.addr6, + .table_coerced = nm_platform_route_table_coerce (route_table), + .metric = route_metric, + }; + } + + _nm_l3_config_data_add_route (self, addr_family, ifindex, NULL, &r.rx, NULL, NULL); + } + + naddresses = nm_setting_ip_config_get_num_addresses (s_ip); + for (i = 0; i < naddresses; i++) { + NMIPAddress *s_addr = nm_setting_ip_config_get_address (s_ip, i); + NMPlatformIPXAddress a; + NMIPAddr addr_bin; + GVariant *label; + + nm_assert (nm_ip_address_get_family (s_addr) == addr_family); + + nm_ip_address_get_address_binary (s_addr, &addr_bin); + + if (IS_IPv4) { + a.a4 = (NMPlatformIP4Address) { + .address = addr_bin.addr4, + .peer_address = addr_bin.addr4, + .plen = nm_ip_address_get_prefix (s_addr), + .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, + .preferred = NM_PLATFORM_LIFETIME_PERMANENT, + .addr_source = NM_IP_CONFIG_SOURCE_USER, + }; + label = nm_ip_address_get_attribute (s_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL); + if (label) + g_strlcpy (a.a4.label, g_variant_get_string (label, NULL), sizeof (a.a4.label)); + + nm_assert (a.a4.plen <= 32); + } else { + a.a6 = (NMPlatformIP6Address) { + .address = addr_bin.addr6, + .plen = nm_ip_address_get_prefix (s_addr), + .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, + .preferred = NM_PLATFORM_LIFETIME_PERMANENT, + .addr_source = NM_IP_CONFIG_SOURCE_USER, + }; + + nm_assert (a.a6.plen <= 128); + } + + _nm_l3_config_data_add_address (self, addr_family, ifindex, NULL, &a.ax); + } + + nroutes = nm_setting_ip_config_get_num_routes (s_ip); + for (i = 0; i < nroutes; i++) { + NMIPRoute *s_route = nm_setting_ip_config_get_route (s_ip, i); + NMPlatformIPXRoute r; + NMIPAddr network_bin; + NMIPAddr next_hop_bin; + gint64 metric64; + guint32 metric; + guint plen; + + nm_assert (nm_ip_route_get_family (s_route) == addr_family); + + nm_ip_route_get_dest_binary (s_route, &network_bin); + nm_ip_route_get_next_hop_binary (s_route, &next_hop_bin); + + metric64 = nm_ip_route_get_metric (s_route); + if (metric64 < 0) + metric = route_metric; + else + metric = metric64; + metric = nm_utils_ip_route_metric_normalize (addr_family, metric); + + plen = nm_ip_route_get_prefix (s_route); + + nm_utils_ipx_address_clear_host_address (addr_family, &network_bin, &network_bin, plen); + + if (IS_IPv4) { + r.r4 = (NMPlatformIP4Route) { + .network = network_bin.addr4, + .plen = nm_ip_route_get_prefix (s_route), + .gateway = next_hop_bin.addr4, + .metric = metric, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; + nm_assert (r.r4.plen <= 32); + } else { + r.r6 = (NMPlatformIP6Route) { + .network = network_bin.addr6, + .plen = nm_ip_route_get_prefix (s_route), + .gateway = next_hop_bin.addr6, + .metric = metric, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; + nm_assert (r.r6.plen <= 128); + } + + nm_utils_ip_route_attribute_to_platform (addr_family, + s_route, + &r.rx, + route_table); + + _nm_l3_config_data_add_route (self, addr_family, ifindex, NULL, &r.rx, NULL, NULL); + } + + nnameservers = nm_setting_ip_config_get_num_dns (s_ip); + for (i = 0; i < nnameservers; i++) { + const char *s; + NMIPAddr ip; + + s = nm_setting_ip_config_get_dns (s_ip, i); + if (!nm_utils_parse_inaddr_bin (addr_family, s, NULL, &ip)) + continue; + g_array_append_vals (_garray_ensure_for_addrbin (&self->nameservers_x[IS_IPv4], addr_family), + &ip, + 1); + } + + nsearches = nm_setting_ip_config_get_num_dns_searches (s_ip); + for (i = 0; i < nsearches; i++) { + _nm_l3_config_data_add_search (self, + addr_family, + nm_setting_ip_config_get_dns_search (s_ip, i)); + } + + idx = 0; + while ((idx = nm_setting_ip_config_next_valid_dns_option (s_ip, i)) >= 0) { + _nm_l3_config_data_add_dns_option (self, + addr_family, + nm_setting_ip_config_get_dns_option (s_ip, i)); + idx++; + } + + _nm_l3_config_data_set_dns_priority (self, + addr_family, + nm_setting_ip_config_get_dns_priority (s_ip)); +} + +NML3ConfigData * +nm_l3_config_data_new_from_connection (NMDedupMultiIndex *multi_index, + int ifindex, + NMConnection *connection, + NMSettingConnectionMdns mdns, + NMSettingConnectionLlmnr llmnr, + guint32 route_table, + guint32 route_metric) +{ + NML3ConfigData *self; + + self = nm_l3_config_data_new (multi_index); + + _init_from_connection_ip (self, AF_INET, ifindex, connection, route_table, route_metric); + _init_from_connection_ip (self, AF_INET6, ifindex, connection, route_table, route_metric); + + self->mdns = mdns; + self->llmnr = llmnr; + + return self; +} diff --git a/src/nm-l3-config-data.h b/src/nm-l3-config-data.h new file mode 100644 index 0000000000..f7b87d7d16 --- /dev/null +++ b/src/nm-l3-config-data.h @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#ifndef __NM_L3_CONFIG_DATA_H__ +#define __NM_L3_CONFIG_DATA_H__ + +#include "nm-glib-aux/nm-dedup-multi.h" +#include "nm-setting-connection.h" +#include "platform/nm-platform.h" + +typedef struct _NML3ConfigData NML3ConfigData; + +NML3ConfigData *nm_l3_config_data_new (NMDedupMultiIndex *multi_idx); +NML3ConfigData *nm_l3_config_data_ref (NML3ConfigData *self); +NML3ConfigData *nm_l3_config_data_ref_and_seal (NML3ConfigData *self); +NML3ConfigData *nm_l3_config_data_seal (NML3ConfigData *self); +void nm_l3_config_data_unref (NML3ConfigData *self); + +gboolean nm_l3_config_data_is_sealed (NML3ConfigData *self); + +const NMDedupMultiHeadEntry *nm_l3_config_data_lookup_addresses (const NML3ConfigData *self, int addr_family); +const NMDedupMultiHeadEntry *nm_l3_config_data_lookup_routes (const NML3ConfigData *self, int addr_family); + +NML3ConfigData *nm_l3_config_data_new_from_connection (NMDedupMultiIndex *multi_index, + int ifindex, + NMConnection *connection, + NMSettingConnectionMdns mdns, + NMSettingConnectionLlmnr llmnr, + guint32 route_table, + guint32 route_metric); + +/*****************************************************************************/ + +gboolean _nm_l3_config_data_add_address (NML3ConfigData *self, + int addr_family, + int ifindex, + const NMPObject *obj_new, + const NMPlatformIPAddress *pl_new); + +gboolean _nm_l3_config_data_add_route (NML3ConfigData *self, + int addr_family, + int ifindex, + const NMPObject *obj_new, + const NMPlatformIPRoute *pl_new, + const NMPObject **out_obj_new, + gboolean *out_changed_best_default_route); + +gboolean _nm_l3_config_data_add_domain (NML3ConfigData *self, + int addr_family, + const char *domain); + +gboolean _nm_l3_config_data_add_search (NML3ConfigData *self, + int addr_family, + const char *search); + +gboolean _nm_l3_config_data_add_dns_option (NML3ConfigData *self, + int addr_family, + const char *dns_option); + +gboolean _nm_l3_config_data_set_dns_priority (NML3ConfigData *self, + int addr_family, + int dns_priority); + +#endif /* __NM_L3_CONFIG_DATA_H__ */