From 03efc9e2c94e47383f019a972010057535303fa0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 10 Nov 2017 10:00:46 +0100 Subject: [PATCH 01/12] shared: fix detection of _Generic() support --- shared/nm-utils/nm-macros-internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index d07e298ea2..515e8b5c3e 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -263,7 +263,7 @@ NM_G_ERROR_MSG (GError *error) /*****************************************************************************/ -#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 9 ))) || (defined (__clang__)) +#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 ))) || (defined (__clang__)) #define _NM_CC_SUPPORT_GENERIC 1 #else #define _NM_CC_SUPPORT_GENERIC 0 From bdfdabea51bb19f9bf9a95a57e80ab98d4b3122f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 10 Nov 2017 09:32:14 +0100 Subject: [PATCH 02/12] shared: propagate constness in _NM_GET_PRIVATE_PTR() The _NM_GET_PRIVATE() macro already preserved and propagated the constness of @self to the resulting private pointer. _NM_GET_PRIVATE_PTR() didn't do that. Extend the macro, to make that possible. --- shared/nm-utils/nm-macros-internal.h | 30 ++++++++++++++++++++++++++-- src/devices/nm-device.c | 4 ++-- src/devices/nm-device.h | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 515e8b5c3e..49bc79e582 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -263,6 +263,13 @@ NM_G_ERROR_MSG (GError *error) /*****************************************************************************/ +#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 ))) +#define _NM_CC_SUPPORT_AUTO_TYPE 1 +#define _nm_auto_type __auto_type +#else +#define _NM_CC_SUPPORT_AUTO_TYPE 0 +#endif + #if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 ))) || (defined (__clang__)) #define _NM_CC_SUPPORT_GENERIC 1 #else @@ -372,6 +379,16 @@ NM_G_ERROR_MSG (GError *error) #define _NM_ENSURE_TYPE(type, value) (value) #endif +#if _NM_CC_SUPPORT_GENERIC +#define NM_PROPAGATE_CONST(test_expr, ptr) \ + (_Generic ((test_expr), \ + const typeof (*(test_expr)) *: ((const typeof (*(ptr)) *) (ptr)), \ + default: (_Generic ((test_expr), \ + typeof (*(test_expr)) *: (ptr))))) +#else +#define NM_PROPAGATE_CONST(test_expr, ptr) (ptr) +#endif + /*****************************************************************************/ #define _NM_IN_SET_EVAL_1( op, _x, y) (_x == (y)) @@ -651,8 +668,17 @@ _notify (obj_type *obj, _PropertyEnums prop) \ /*****************************************************************************/ -#define _NM_GET_PRIVATE( self, type, is_check, ...) (&(NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__)->_priv)) -#define _NM_GET_PRIVATE_PTR( self, type, is_check, ...) ( (NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__)->_priv)) +#define _NM_GET_PRIVATE(self, type, is_check, ...) (&(NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__)->_priv)) +#if _NM_CC_SUPPORT_AUTO_TYPE +#define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) \ + ({ \ + _nm_auto_type _self = NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__); \ + \ + NM_PROPAGATE_CONST (_self, _self->_priv); \ + }) +#else +#define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) (NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__)->_priv) +#endif /*****************************************************************************/ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 010172dc06..1fe6f064da 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1164,9 +1164,9 @@ nm_device_get_ip_iface (NMDevice *self) } int -nm_device_get_ip_ifindex (NMDevice *self) +nm_device_get_ip_ifindex (const NMDevice *self) { - NMDevicePrivate *priv; + const NMDevicePrivate *priv; g_return_val_if_fail (self != NULL, 0); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index bd8104b4bf..b0d299e4ea 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -438,7 +438,7 @@ int nm_device_get_ifindex (NMDevice *dev); gboolean nm_device_is_software (NMDevice *dev); gboolean nm_device_is_real (NMDevice *dev); const char * nm_device_get_ip_iface (NMDevice *dev); -int nm_device_get_ip_ifindex (NMDevice *dev); +int nm_device_get_ip_ifindex (const NMDevice *dev); const char * nm_device_get_driver (NMDevice *dev); const char * nm_device_get_driver_version (NMDevice *dev); const char * nm_device_get_type_desc (NMDevice *dev); From 557d83bf2ddf832828a9b85ffffcad0b7d88272a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 10 Nov 2017 12:00:09 +0100 Subject: [PATCH 03/12] build: detect compiler features _Generic() and __auto_type in configure script There is still a fallback detection in "shared/nm-utils/nm-macros-internal.h", so that VPN-plugins and applet don't need to bother about adding these configure checks. --- configure.ac | 16 ++++++++++++++++ shared/nm-utils/nm-macros-internal.h | 9 ++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index ad188a7763..a2405c625b 100644 --- a/configure.ac +++ b/configure.ac @@ -1227,6 +1227,22 @@ fi AC_SUBST(SANITIZERS, [$sanitizers]) +AC_MSG_CHECKING([CC support C11 _Generic()]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[int foo(void); int foo() { int a = 0; int b = _Generic (a, int: 4); return b + a; }]], + [[foo();]])], + [cc_support_generic=1], + [cc_support_generic=0]) +AC_MSG_RESULT($cc_support_generic) +AC_DEFINE_UNQUOTED(_NM_CC_SUPPORT_GENERIC, $cc_support_generic, [Define whether the compiler supports C11 _Generic()]) + +AC_MSG_CHECKING([CC support gcc __auto_type]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[int foo(void); int foo() { int a = 0; __auto_type b = a; return b + a; }]], + [[foo();]])], + [cc_support_auto_type=1], + [cc_support_auto_type=0]) +AC_MSG_RESULT($cc_support_auto_type) +AC_DEFINE_UNQUOTED(_NM_CC_SUPPORT_AUTO_TYPE, $cc_support_auto_type, [Define whether the compiler support gcc __auto_type]) + dnl ------------------------- dnl Vala bindings dnl ------------------------- diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 49bc79e582..2d62ba7d97 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -263,18 +263,25 @@ NM_G_ERROR_MSG (GError *error) /*****************************************************************************/ +#ifndef _NM_CC_SUPPORT_AUTO_TYPE #if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 ))) #define _NM_CC_SUPPORT_AUTO_TYPE 1 -#define _nm_auto_type __auto_type #else #define _NM_CC_SUPPORT_AUTO_TYPE 0 #endif +#endif +#ifndef _NM_CC_SUPPORT_GENERIC #if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 ))) || (defined (__clang__)) #define _NM_CC_SUPPORT_GENERIC 1 #else #define _NM_CC_SUPPORT_GENERIC 0 #endif +#endif + +#if _NM_CC_SUPPORT_AUTO_TYPE +#define _nm_auto_type __auto_type +#endif #if _NM_CC_SUPPORT_GENERIC #define _NM_CONSTCAST_FULL_1(type, obj_expr, obj) \ From d5c9c95e96a376834e7582843cf019fbdba03a7c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 9 Nov 2017 12:09:03 +0100 Subject: [PATCH 04/12] core: use NM_CONSTCAST() for NM_IP_CONFIG_CAST() --- src/nm-ip4-config.h | 74 ++++++++++++++++++++++--------------- src/tests/test-ip4-config.c | 2 + 2 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index e7fb2703eb..12cbd6c17b 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -272,41 +272,57 @@ gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b); #include "nm-ip6-config.h" -#if _NM_CC_SUPPORT_GENERIC -#define NM_IP_CONFIG_CAST(config) \ - ({ \ - const void *const _config = (config); \ - \ - nm_assert (_Generic ((config), \ - const void *: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - void *: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - const NMIPConfig *: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - NMIPConfig *: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - const NMIP4Config *: (NM_IS_IP4_CONFIG (_config)), \ - NMIP4Config *: (NM_IS_IP4_CONFIG (_config)), \ - const NMIP6Config *: (NM_IS_IP6_CONFIG (_config)), \ - NMIP6Config *: (NM_IS_IP6_CONFIG (_config)))); \ - \ - _Generic ((config), \ - const void *: ((const NMIPConfig *) _config), \ - void *: (( NMIPConfig *) _config), \ - const NMIPConfig *: ((const NMIPConfig *) _config), \ - NMIPConfig *: (( NMIPConfig *) _config), \ - const NMIP4Config *: ((const NMIPConfig *) _config), \ - NMIP4Config *: (( NMIPConfig *) _config), \ - const NMIP6Config *: ((const NMIPConfig *) _config), \ - NMIP6Config *: (( NMIPConfig *) _config)); \ - }) -#else -#define NM_IP_CONFIG_CAST(config) ((NMIPConfig *) (config)) -#endif - static inline gboolean NM_IS_IP_CONFIG (gconstpointer config) { return NM_IS_IP4_CONFIG (config) || NM_IS_IP6_CONFIG (config); } +#if _NM_CC_SUPPORT_GENERIC +/* _NM_IS_IP_CONFIG() is a bit unusual. If _Generic() is supported, + * it checks whether @config is either NM_IS_IP4_CONFIG() or NM_IS_IP6_CONFIG(), + * depending on the pointer type of @config. + * + * For example, with _Generic() support, the following assertions would fail: + * NMIP6Config *ptr = (NMIP6Config *) nm_ip4_config_new(...); + * g_assert (_NM_IS_IP_CONFIG (ptr, ptr)); + * but the following would pass: + * NMIP4Config *ptr = nm_ip4_config_new(...); + * g_assert (_NM_IS_IP_CONFIG (ptr, ptr)); + */ +#define _NM_IS_IP_CONFIG(typeexpr, config) \ + ({ \ + const void *const _config = (config); \ + _Generic ((typeexpr), \ + const void *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + const void * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + void *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + void * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + const NMIPConfig *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + const NMIPConfig * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + NMIPConfig *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + NMIPConfig * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + const NMIP4Config *const: (NM_IS_IP4_CONFIG (_config)), \ + const NMIP4Config * : (NM_IS_IP4_CONFIG (_config)), \ + NMIP4Config *const: (NM_IS_IP4_CONFIG (_config)), \ + NMIP4Config * : (NM_IS_IP4_CONFIG (_config)), \ + const NMIP6Config *const: (NM_IS_IP6_CONFIG (_config)), \ + const NMIP6Config * : (NM_IS_IP6_CONFIG (_config)), \ + NMIP6Config *const: (NM_IS_IP6_CONFIG (_config)), \ + NMIP6Config * : (NM_IS_IP6_CONFIG (_config))); \ + }) +#else +#define _NM_IS_IP_CONFIG(typeexpr, config) NM_IS_IP_CONFIG(config) +#endif + +#define NM_IP_CONFIG_CAST(config) \ + ({ \ + const void *const _configx = (config); \ + \ + nm_assert (!_configx || _NM_IS_IP_CONFIG ((config), _configx)); \ + NM_CONSTCAST_FULL (NMIPConfig, (config), _configx, NMIP4Config, NMIP6Config); \ + }) + static inline int nm_ip_config_get_addr_family (const NMIPConfig *config) { diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c index 649b443f2a..4c3c344e46 100644 --- a/src/tests/test-ip4-config.c +++ b/src/tests/test-ip4-config.c @@ -38,6 +38,8 @@ build_test_config (void) /* Build up the config to subtract */ config = nmtst_ip4_config_new (1); + nm_assert (NM_IP_CONFIG_CAST (config)); + addr = *nmtst_platform_ip4_address ("192.168.1.10", "1.2.3.4", 24); nm_ip4_config_add_address (config, &addr); From 8948dbe117c45227f4c7c1e57a0c0785c6f06a1c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Nov 2017 19:58:35 +0100 Subject: [PATCH 05/12] platform: add generic NM_PLATFORM_IP_ROUTE_CAST() macro A cast macro, that does some static type checking (of the pointer). --- src/platform/nm-platform.h | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index d155c1092e..a98f1586ab 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -441,23 +441,11 @@ typedef struct { }; } NMPlatformIPRoute; -#if _NM_CC_SUPPORT_GENERIC +#define NM_PLATFORM_IP_ROUTE_CAST(route) \ + NM_CONSTCAST (NMPlatformIPRoute, (route), NMPlatformIPXRoute, NMPlatformIP4Route, NMPlatformIP6Route) + #define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \ - (_Generic ((route), \ - const NMPlatformIPRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIPRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - const NMPlatformIPXRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIPXRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - const NMPlatformIP4Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIP4Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - const NMPlatformIP6Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIP6Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - const void *: ((const NMPlatformIPRoute *) (route))->plen, \ - void *: ((const NMPlatformIPRoute *) (route))->plen) == 0) -#else -#define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \ - ( ((const NMPlatformIPRoute *) (route))->plen <= 0 ) -#endif + (NM_PLATFORM_IP_ROUTE_CAST (route)->plen <= 0) struct _NMPlatformIP4Route { __NMPlatformIPRoute_COMMON; From 632e8ac885d205c83c6140f8145cd65cd1c98b14 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Nov 2017 19:50:10 +0100 Subject: [PATCH 06/12] shared/trivial: move code --- shared/nm-utils/nm-shared-utils.h | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 96aab5341e..a118cf819a 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -26,23 +26,6 @@ /*****************************************************************************/ -typedef struct { - union { - guint8 addr_ptr[1]; - in_addr_t addr4; - struct in6_addr addr6; - - /* NMIPAddr is really a union for IP addresses. - * However, as ethernet addresses fit in here nicely, use - * it also for an ethernet MAC address. */ - guint8 addr_eth[6 /*ETH_ALEN*/]; - }; -} NMIPAddr; - -extern const NMIPAddr nm_ip_addr_zero; - -/*****************************************************************************/ - static inline char nm_utils_addr_family_to_char (int addr_family) { @@ -68,6 +51,23 @@ nm_utils_addr_family_to_size (int addr_family) /*****************************************************************************/ +typedef struct { + union { + guint8 addr_ptr[1]; + in_addr_t addr4; + struct in6_addr addr6; + + /* NMIPAddr is really a union for IP addresses. + * However, as ethernet addresses fit in here nicely, use + * it also for an ethernet MAC address. */ + guint8 addr_eth[6 /*ETH_ALEN*/]; + }; +} NMIPAddr; + +extern const NMIPAddr nm_ip_addr_zero; + +/*****************************************************************************/ + #define NM_CMP_RETURN(c) \ G_STMT_START { \ const int _cc = (c); \ From a9d1f5e543bba46a5a97a2e440d607550a54a283 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Nov 2017 19:51:25 +0100 Subject: [PATCH 07/12] shared: add nm_ip_addr_set() helper --- shared/nm-utils/nm-shared-utils.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index a118cf819a..a092a6b780 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -66,6 +66,19 @@ typedef struct { extern const NMIPAddr nm_ip_addr_zero; +static inline void +nm_ip_addr_set (int addr_family, gpointer dst, const NMIPAddr *src) +{ + nm_assert_addr_family (addr_family); + nm_assert (dst); + nm_assert (src); + + if (addr_family != AF_INET6) + *((in_addr_t *) dst) = src->addr4; + else + *((struct in6_addr *) dst) = src->addr6; +} + /*****************************************************************************/ #define NM_CMP_RETURN(c) \ From 433d2f8659e31719fe13f16cc48b404d926f6ae3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Nov 2017 19:49:39 +0100 Subject: [PATCH 08/12] core: merge IPv4 and IPv6 version of _nm_ip_config_merge_route_attributes() --- src/nm-ip4-config.c | 96 +++++++++++++++++++++++++++++++-------------- src/nm-ip4-config.h | 5 +++ src/nm-ip6-config.c | 64 ++---------------------------- 3 files changed, 76 insertions(+), 89 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 06137764f5..d63b3103be 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -806,44 +806,79 @@ nm_ip4_config_commit (const NMIP4Config *self, return success; } -static void -merge_route_attributes (NMIPRoute *s_route, - NMPlatformIP4Route *r, - guint32 route_table) +void +_nm_ip_config_merge_route_attributes (int addr_family, + NMIPRoute *s_route, + NMPlatformIPRoute *r, + guint32 route_table) { GVariant *variant; - guint32 u32; - in_addr_t addr; + guint32 table; + NMIPAddr addr; + NMPlatformIP4Route *r4 = (NMPlatformIP4Route *) r; + NMPlatformIP6Route *r6 = (NMPlatformIP6Route *) r; -#define GET_ATTR(name, field, variant_type, type) \ - variant = nm_ip_route_get_attribute (s_route, name); \ - if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \ - r->field = g_variant_get_ ## type (variant); + nm_assert (s_route); + nm_assert_addr_family (addr_family); + nm_assert (r); - variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TABLE); - u32 = variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) - ? g_variant_get_uint32 (variant) - : 0; - r->table_coerced = nm_platform_route_table_coerce (u32 ?: (route_table ?: RT_TABLE_MAIN)); +#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 - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table, UINT32, uint32, 0); + r->table_coerced = nm_platform_route_table_coerce (table ?: (route_table ?: RT_TABLE_MAIN)); + + if (addr_family == AF_INET) + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, r4->tos, BYTE, byte, 0); + + 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 (AF_INET, g_variant_get_string (variant, NULL), &addr) == 1) - r->pref_src = addr; + 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 } @@ -939,7 +974,10 @@ nm_ip4_config_merge_setting (NMIP4Config *self, route.network = nm_utils_ip4_address_clear_host_address (route.network, route.plen); - merge_route_attributes (s_route, &route, route_table); + _nm_ip_config_merge_route_attributes (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 12cbd6c17b..7c345d2052 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -113,6 +113,11 @@ 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 3f0bbfe75c..28841e3434 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -571,65 +571,6 @@ nm_ip6_config_commit (const NMIP6Config *self, return success; } -static void -merge_route_attributes (NMIPRoute *s_route, - NMPlatformIP6Route *r, - guint32 route_table) -{ - GVariant *variant; - guint32 u32; - struct in6_addr addr; - -#define GET_ATTR(name, field, variant_type, type) \ - variant = nm_ip_route_get_attribute (s_route, name); \ - if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \ - r->field = g_variant_get_ ## type (variant); - - variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TABLE); - u32 = variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) - ? g_variant_get_uint32 (variant) - : 0; - r->table_coerced = nm_platform_route_table_coerce (u32 ?: (route_table ?: RT_TABLE_MAIN)); - - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean); - - - 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 (AF_INET6, g_variant_get_string (variant, NULL), &addr) == 1) - r->pref_src = addr; - } - - if ( (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) { - r->src = addr; - r->src_plen = plen; - } - } -#undef GET_ATTR -} - void nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, @@ -716,7 +657,10 @@ nm_ip6_config_merge_setting (NMIP6Config *self, nm_utils_ip6_address_clear_host_address (&route.network, &route.network, route.plen); - merge_route_attributes (s_route, &route, route_table); + _nm_ip_config_merge_route_attributes (AF_INET, + s_route, + NM_PLATFORM_IP_ROUTE_CAST (&route), + route_table); _add_route (self, NULL, &route, NULL); } From 81778f59f2f11fad74fce355561618e6da129939 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Nov 2017 15:32:55 +0100 Subject: [PATCH 09/12] platform: track all rtm_flags for routes --- src/platform/nm-linux-platform.c | 14 +------ src/platform/nm-platform.c | 64 +++++++++++++++++++++++++++----- src/platform/nm-platform.h | 18 +++++---- src/platform/nmp-object.c | 3 +- src/platform/tests/test-route.c | 2 +- 5 files changed, 70 insertions(+), 31 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 9efdd41327..66ca9dc3ac 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2291,17 +2291,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) obj->ip6_route.rt_pref = nla_get_u8 (tb[RTA_PREF]); } - if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) { - /* we must not straight way reject cloned routes, because we might have cached - * a non-cloned route. If we now receive an update of the route with the route - * being cloned, we must still return the object, so that we can remove the old - * one from the cache. - * - * This happens, because this route is not nmp_object_is_alive(). - * */ - obj->ip_route.rt_cloned = TRUE; - } - + obj->ip_route.r_rtm_flags = rtm->rtm_flags; obj->ip_route.rt_source = nmp_utils_ip_config_source_from_rtprot (rtm->rtm_protocol); obj_result = obj; @@ -4189,7 +4179,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event gboolean resync_required = FALSE; gboolean only_dirty = FALSE; - if (obj->ip_route.rt_cloned) { + if (NM_FLAGS_HAS (obj->ip_route.r_rtm_flags, RTM_F_CLONED)) { /* a cloned route might be a response for RTM_GETROUTE. Check, whether it is. */ nm_assert (!nmp_object_is_alive (obj)); priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index ffc4b3956d..076bc409d5 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -4976,6 +4976,40 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *bu return buf; } +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_rtm_flags_to_string, unsigned, + NM_UTILS_FLAGS2STR (RTNH_F_DEAD, "dead"), + NM_UTILS_FLAGS2STR (RTNH_F_PERVASIVE, "pervasive"), + NM_UTILS_FLAGS2STR (RTNH_F_ONLINK, "onlink"), + NM_UTILS_FLAGS2STR (8 /*RTNH_F_OFFLOAD*/, "offload"), + NM_UTILS_FLAGS2STR (16 /*RTNH_F_LINKDOWN*/, "linkdown"), + NM_UTILS_FLAGS2STR (32 /*RTNH_F_UNRESOLVED*/, "unresolved"), + + NM_UTILS_FLAGS2STR (RTM_F_NOTIFY, "notify"), + NM_UTILS_FLAGS2STR (RTM_F_CLONED, "cloned"), + NM_UTILS_FLAGS2STR (RTM_F_EQUALIZE, "equalize"), + NM_UTILS_FLAGS2STR (RTM_F_PREFIX, "prefix"), + NM_UTILS_FLAGS2STR (0x1000 /*RTM_F_LOOKUP_TABLE*/, "lookup-table"), + NM_UTILS_FLAGS2STR (0x2000 /*RTM_F_FIB_MATCH*/, "fib-match"), +); + +#define _RTM_FLAGS_TO_STRING_MAXLEN 200 + +static const char * +_rtm_flags_to_string_full (char *buf, gsize buf_size, unsigned rtm_flags) +{ + const char *buf0 = buf; + + nm_assert (buf_size >= _RTM_FLAGS_TO_STRING_MAXLEN); + + if (!rtm_flags) + return ""; + + nm_utils_strbuf_append_str (&buf, &buf_size, " rtm_flags "); + _rtm_flags_to_string (rtm_flags, buf, buf_size); + nm_assert (strlen (buf) < buf_size); + return buf0; +} + /** * nm_platform_ip4_route_to_string: * @route: pointer to NMPlatformIP4Route route structure @@ -4997,6 +5031,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi char str_table[30]; char str_scope[30], s_source[50]; char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; + char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -5015,7 +5050,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi " metric %"G_GUINT32_FORMAT " mss %"G_GUINT32_FORMAT " rt-src %s" /* protocol */ - "%s" /* cloned */ + "%s" /* rtm_flags */ "%s%s" /* scope */ "%s%s" /* pref-src */ "%s" /* tos */ @@ -5033,7 +5068,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi route->metric, route->mss, nmp_utils_ip_config_source_to_string (route->rt_source, s_source, sizeof (s_source)), - route->rt_cloned ? " cloned" : "", + _rtm_flags_to_string_full (str_rtm_flags, sizeof (str_rtm_flags), route->r_rtm_flags), route->scope_inv ? " scope " : "", route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "", route->pref_src ? " pref-src " : "", @@ -5069,6 +5104,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi char str_pref2[30]; char str_dev[TO_STRING_DEV_BUF_SIZE], s_source[50]; char str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; + char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -5092,7 +5128,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi " mss %"G_GUINT32_FORMAT " rt-src %s" /* protocol */ "%s" /* source */ - "%s" /* cloned */ + "%s" /* rtm_flags */ "%s%s" /* pref-src */ "%s" /* window */ "%s" /* cwnd */ @@ -5112,7 +5148,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi route->src_plen || !IN6_IS_ADDR_UNSPECIFIED (&route->src) ? nm_sprintf_buf (s_src_all, " src %s/%u", nm_utils_inet6_ntop (&route->src, s_src), (unsigned) route->src_plen) : "", - route->rt_cloned ? " cloned" : "", + _rtm_flags_to_string_full (str_rtm_flags, sizeof (str_rtm_flags), route->r_rtm_flags), s_pref_src[0] ? " pref-src " : "", s_pref_src[0] ? s_pref_src : "", route->window || route->lock_window ? nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window) : "", @@ -5563,8 +5599,8 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, + obj->r_rtm_flags & RTM_F_CLONED, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5589,8 +5625,8 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, + obj->r_rtm_flags, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5660,7 +5696,11 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route } NM_CMP_FIELD (a, b, mss); NM_CMP_FIELD (a, b, pref_src); - NM_CMP_FIELD_UNSAFE (a, b, rt_cloned); + if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { + NM_CMP_DIRECT (a->r_rtm_flags & RTM_F_CLONED, + b->r_rtm_flags & RTM_F_CLONED); + } else + NM_CMP_FIELD (a, b, r_rtm_flags); NM_CMP_FIELD (a, b, tos); NM_CMP_FIELD_UNSAFE (a, b, lock_window); NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd); @@ -5717,8 +5757,8 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo obj->src_plen, nmp_utils_ip_config_source_round_trip_rtprot (obj->rt_source), obj->mss, + obj->r_rtm_flags & RTM_F_CLONED, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5744,8 +5784,8 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo obj->src_plen, obj->rt_source, obj->mss, + obj->r_rtm_flags, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5810,7 +5850,11 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route NM_CMP_FIELD (a, b, rt_source); } NM_CMP_FIELD (a, b, mss); - NM_CMP_FIELD_UNSAFE (a, b, rt_cloned); + if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { + NM_CMP_DIRECT (a->r_rtm_flags & RTM_F_CLONED, + b->r_rtm_flags & RTM_F_CLONED); + } else + NM_CMP_FIELD (a, b, r_rtm_flags); NM_CMP_FIELD_UNSAFE (a, b, lock_window); NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd); NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index a98f1586ab..47421318c8 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -375,13 +375,6 @@ typedef union { \ guint8 plen; \ \ - /* the route has rtm_flags set to RTM_F_CLONED. Such a route - * is hidden by platform and does not exist from the point-of-view - * of platform users. This flag is internal to track those hidden - * routes. Such a route is not alive, according to nmp_object_is_alive(). */ \ - bool rt_cloned:1; \ - \ - \ /* RTA_METRICS: * * For IPv4 routes, these properties are part of their @@ -401,6 +394,17 @@ typedef union { bool lock_initrwnd:1; \ bool lock_mtu:1; \ \ + /* rtnh_flags + * + * Routes with rtm_flags RTM_F_CLONED are hidden by platform and + * do not exist from the point-of-view of platform users. + * Such a route is not alive, according to nmp_object_is_alive(). + * + * XXX: currently we ignore all flags except RTM_F_CLONED. + * We also may not properly consider the flags as part of the ID + * in route-cmp. */ \ + unsigned r_rtm_flags; \ + \ /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \ guint32 mss; \ \ diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index a860070545..0c951dd4fc 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -1170,7 +1170,8 @@ _vt_cmd_obj_is_alive_ipx_route (const NMPObject *obj) * Instead we create a dead object, and nmp_cache_update_netlink() * will remove the old version of the update. **/ - return obj->object.ifindex > 0 && !obj->ip_route.rt_cloned; + return obj->object.ifindex > 0 + && !NM_FLAGS_HAS (obj->ip_route.r_rtm_flags, RTM_F_CLONED); } gboolean diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 2c00fadaab..8326239557 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -417,7 +417,7 @@ test_ip_route_get (void) g_assert (!NMP_OBJECT_IS_STACKINIT (route)); g_assert (route->parent._ref_count == 1); r = NMP_OBJECT_CAST_IP4_ROUTE (route); - g_assert (r->rt_cloned); + g_assert (NM_FLAGS_HAS (r->r_rtm_flags, RTM_F_CLONED)); g_assert (r->ifindex == ifindex); g_assert (r->network == a); g_assert (r->plen == 32); From 88a40f960c5d1546f1966ff2223d28f87e2f054b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Nov 2017 16:26:58 +0100 Subject: [PATCH 10/12] platform: consider RTNH_F_ONLINK onlink flag for IPv4 routes The "onlink" flag for IPv4 routes is part of the route ID. Consider it in nm_platform_ip4_route_cmp(). Also, allow configuring the flag when adding a route. Note that for IPv6, the onlink flag is still ignored. Pretty much like kernel does. --- src/platform/nm-linux-platform.c | 4 +++- src/platform/nm-platform.c | 9 ++++++--- src/platform/nm-platform.h | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 66ca9dc3ac..46b7bd209e 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2690,7 +2690,9 @@ _nl_msg_new_route (int nlmsg_type, ? nm_platform_route_scope_inv (obj->ip4_route.scope_inv) : RT_SCOPE_NOWHERE, .rtm_type = RTN_UNICAST, - .rtm_flags = 0, + .rtm_flags = obj->ip_route.r_rtm_flags & (is_v4 + ? (unsigned) (RTNH_F_ONLINK) + : (unsigned) 0), .rtm_dst_len = obj->ip_route.plen, .rtm_src_len = is_v4 ? 0 diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 076bc409d5..f94d93e257 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -5574,6 +5574,7 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, + obj->r_rtm_flags & RTNH_F_ONLINK, NM_HASH_COMBINE_BOOLS (guint8, obj->lock_window, obj->lock_cwnd, @@ -5599,7 +5600,7 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, - obj->r_rtm_flags & RTM_F_CLONED, + obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK), NM_HASH_COMBINE_BOOLS (guint8, obj->lock_window, obj->lock_cwnd, @@ -5663,6 +5664,8 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route NM_CMP_FIELD (a, b, initcwnd); NM_CMP_FIELD (a, b, initrwnd); NM_CMP_FIELD (a, b, mtu); + NM_CMP_DIRECT (a->r_rtm_flags & RTNH_F_ONLINK, + b->r_rtm_flags & RTNH_F_ONLINK); NM_CMP_FIELD_UNSAFE (a, b, lock_window); NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd); NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd); @@ -5697,8 +5700,8 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route NM_CMP_FIELD (a, b, mss); NM_CMP_FIELD (a, b, pref_src); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { - NM_CMP_DIRECT (a->r_rtm_flags & RTM_F_CLONED, - b->r_rtm_flags & RTM_F_CLONED); + NM_CMP_DIRECT (a->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK), + b->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK)); } else NM_CMP_FIELD (a, b, r_rtm_flags); NM_CMP_FIELD (a, b, tos); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 47421318c8..3336642b8b 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -400,7 +400,8 @@ typedef union { * do not exist from the point-of-view of platform users. * Such a route is not alive, according to nmp_object_is_alive(). * - * XXX: currently we ignore all flags except RTM_F_CLONED. + * XXX: currently we ignore all flags except RTM_F_CLONED + * and RTNH_F_ONLINK for IPv4. * We also may not properly consider the flags as part of the ID * in route-cmp. */ \ unsigned r_rtm_flags; \ From 0ed49717ab578622017b5723562503683db473bf Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 7 Nov 2017 19:35:46 +0100 Subject: [PATCH 11/12] all: support route-attribute "onlink" for IPv4 Kernel doesn't support it for IPv6. This is especially useful, if you combine static routes with DHCP. In that case, you might want to get the device-route to the gateway automatically, but add a static-route for it. --- Makefile.am | 1 + libnm-core/nm-setting-ip-config.c | 1 + libnm-core/nm-setting-ip-config.h | 1 + src/nm-ip4-config.c | 10 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 91 +++++++++++-------- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 7 +- ...g-Test_Write_Wired_Static_Routes.cexpected | 20 ++++ .../route-test-wired-static-routes | 6 ++ .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 51 +++++++++-- 9 files changed, 140 insertions(+), 48 deletions(-) create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected diff --git a/Makefile.am b/Makefile.am index af1d445d86..eafc8ca54d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2104,6 +2104,7 @@ EXTRA_DIST += \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_LEAP.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected \ + src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Vlan_test-vlan-interface.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-dcb-test.cexpected \ diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index 7265fdc51e..41ae0993f6 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -1245,6 +1245,7 @@ static const NMVariantAttributeSpec * const ip_route_attribute_spec[] = { ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, TRUE, TRUE, 'a'), ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_FROM, G_VARIANT_TYPE_STRING, FALSE, TRUE, 'p'), ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, TRUE, FALSE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_ONLINK, G_VARIANT_TYPE_BOOLEAN, TRUE, FALSE, 0 ), ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_CWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h index 84ce84657a..96e61bb5c9 100644 --- a/libnm-core/nm-setting-ip-config.h +++ b/libnm-core/nm-setting-ip-config.h @@ -146,6 +146,7 @@ gboolean nm_ip_route_attribute_validate (const char *name, #define NM_IP_ROUTE_ATTRIBUTE_SRC "src" #define NM_IP_ROUTE_ATTRIBUTE_FROM "from" #define NM_IP_ROUTE_ATTRIBUTE_TOS "tos" +#define NM_IP_ROUTE_ATTRIBUTE_ONLINK "onlink" #define NM_IP_ROUTE_ATTRIBUTE_WINDOW "window" #define NM_IP_ROUTE_ATTRIBUTE_CWND "cwnd" #define NM_IP_ROUTE_ATTRIBUTE_INITCWND "initcwnd" diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index d63b3103be..94f4a28e15 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -817,6 +817,7 @@ _nm_ip_config_merge_route_attributes (int addr_family, NMIPAddr addr; NMPlatformIP4Route *r4 = (NMPlatformIP4Route *) r; NMPlatformIP6Route *r6 = (NMPlatformIP6Route *) r; + gboolean onlink; nm_assert (s_route); nm_assert_addr_family (addr_family); @@ -836,8 +837,15 @@ _nm_ip_config_merge_route_attributes (int addr_family, GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table, UINT32, uint32, 0); r->table_coerced = nm_platform_route_table_coerce (table ?: (route_table ?: RT_TABLE_MAIN)); - if (addr_family == AF_INET) + if (addr_family == AF_INET) { GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, r4->tos, BYTE, byte, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_ONLINK, onlink, BOOLEAN, boolean, FALSE); + } else + onlink = FALSE; + + r->r_rtm_flags = 0; + if (onlink) + r->r_rtm_flags = RTNH_F_ONLINK; GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, r->window, UINT32, uint32, 0); GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, r->cwnd, UINT32, uint32, 0); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 66add713b0..b1cf80ad91 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -512,13 +512,13 @@ typedef struct { bool int_base_16:1; - /* the type, one of PARSE_LINE_TYPE_* */ - char type; - /* whether the command line option was found, and @v is * initialized. */ bool has:1; + /* the type, one of PARSE_LINE_TYPE_* */ + char type; + union { guint8 uint8; guint32 uint32; @@ -541,6 +541,7 @@ enum { PARSE_LINE_ATTR_ROUTE_SRC, PARSE_LINE_ATTR_ROUTE_FROM, PARSE_LINE_ATTR_ROUTE_TOS, + PARSE_LINE_ATTR_ROUTE_ONLINK, PARSE_LINE_ATTR_ROUTE_WINDOW, PARSE_LINE_ATTR_ROUTE_CWND, PARSE_LINE_ATTR_ROUTE_INITCWND, @@ -562,6 +563,7 @@ enum { #define PARSE_LINE_TYPE_ADDR 'a' #define PARSE_LINE_TYPE_ADDR_WITH_PREFIX 'p' #define PARSE_LINE_TYPE_IFNAME 'i' +#define PARSE_LINE_TYPE_FLAG 'f' /** * parse_route_line: @@ -601,42 +603,45 @@ parse_route_line (const char *line, char buf1[256]; char buf2[256]; ParseLineInfo infos[] = { - [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, - .type = PARSE_LINE_TYPE_UINT32, }, - [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, - .type = PARSE_LINE_TYPE_ADDR, }, - [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, - .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (addr_family != AF_INET6), }, - [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, - .type = PARSE_LINE_TYPE_UINT8, - .int_base_16 = TRUE, - .ignore = (addr_family != AF_INET), }, - [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, + .type = PARSE_LINE_TYPE_UINT32, }, + [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, + .type = PARSE_LINE_TYPE_ADDR, }, + [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (addr_family != AF_INET6), }, + [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, + .type = PARSE_LINE_TYPE_UINT8, + .int_base_16 = TRUE, + .ignore = (addr_family != AF_INET), }, + [PARSE_LINE_ATTR_ROUTE_ONLINK] = { .key = NM_IP_ROUTE_ATTRIBUTE_ONLINK, + .type = PARSE_LINE_TYPE_FLAG, + .ignore = (addr_family != AF_INET), }, + [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", - .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (options_route != NULL), }, - [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", - .type = PARSE_LINE_TYPE_ADDR, - .disabled = (options_route != NULL), }, - [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", - .type = PARSE_LINE_TYPE_UINT32, - .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", + .type = PARSE_LINE_TYPE_ADDR, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", + .type = PARSE_LINE_TYPE_UINT32, + .disabled = (options_route != NULL), }, - [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", - .type = PARSE_LINE_TYPE_IFNAME, - .ignore = TRUE, - .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", + .type = PARSE_LINE_TYPE_IFNAME, + .ignore = TRUE, + .disabled = (options_route != NULL), }, }; nm_assert (line); @@ -705,6 +710,9 @@ parse_route_line (const char *line, case PARSE_LINE_TYPE_IFNAME: i_words++; goto parse_line_type_ifname; + case PARSE_LINE_TYPE_FLAG: + i_words++; + goto next; default: nm_assert_not_reached (); } @@ -913,6 +921,15 @@ next: ? nm_sprintf_buf (buf2, "/%u", (unsigned) info->v.addr.plen) : "")); break; + case PARSE_LINE_TYPE_FLAG: + /* XXX: the flag (for "onlink") only allows to explictly set "TRUE". + * There is no way to express an explicit "FALSE" setting + * of this attribute, hence, the file format cannot encode + * that configuration. */ + nm_ip_route_set_attribute (route, + info->key, + g_variant_new_boolean (TRUE)); + break; default: nm_assert_not_reached (); break; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 5c8de7d12a..e413da1ef4 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1928,8 +1928,11 @@ get_route_attributes_string (NMIPRoute *route, int family) g_string_append_printf (str, "%s 0x%02x", names[i], (unsigned) g_variant_get_byte (attr)); } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TABLE)) { g_string_append_printf (str, "%s %u", names[i], (unsigned) g_variant_get_uint32 (attr)); - } else if ( nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) - || nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_FROM)) { + } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_ONLINK)) { + if (g_variant_get_boolean (attr)) + g_string_append (str, "onlink"); + } else if (NM_IN_STRSET (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC, + NM_IP_ROUTE_ATTRIBUTE_FROM)) { char *arg = nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) ? "src" : "from"; g_string_append_printf (str, "%s %s", arg, g_variant_get_string (attr, NULL)); diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected new file mode 100644 index 0000000000..c0e47c48d8 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected @@ -0,0 +1,20 @@ +HWADDR=31:33:33:37:BE:CD +MTU=1492 +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=none +IPADDR=1.1.1.3 +PREFIX=24 +IPADDR1=1.1.1.5 +PREFIX1=24 +GATEWAY=1.1.1.1 +DNS1=4.2.2.1 +DNS2=4.2.2.2 +DOMAIN="foobar.com lab.foobar.com" +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write Wired Static Routes" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes index 10a63b674f..8d6aaac2f6 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes @@ -7,3 +7,9 @@ NETMASK1=255.255.255.255 GATEWAY1=192.168.1.7 METRIC1=3 OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 initcwnd lock 13 initrwnd 14" + +ADDRESS2=44.55.66.78 +NETMASK2=255.255.255.255 +GATEWAY2=192.168.1.8 +METRIC2=3 +OPTIONS2="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 onlink window 30000 initcwnd lock 13 initrwnd 14" diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 5044a2d7d8..17b6ca4940 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -1318,7 +1318,7 @@ test_read_wired_static_routes (void) g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); /* Routes */ - g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 2); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 3); ip4_route = nm_setting_ip_config_get_route (s_ip4, 0); g_assert (ip4_route); @@ -1343,6 +1343,23 @@ test_read_wired_static_routes (void) nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); + ip4_route = nm_setting_ip_config_get_route (s_ip4, 2); + g_assert (ip4_route); + g_assert_cmpstr (nm_ip_route_get_dest (ip4_route), ==, "44.55.66.78"); + g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 32); + g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "192.168.1.8"); + g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3); + nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 13); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 14); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); + nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, TRUE); + g_object_unref (connection); } @@ -4748,6 +4765,7 @@ test_write_wired_static_routes (void) NMIPAddress *addr; NMIPRoute *route; GError *error = NULL; + gboolean reread_same = FALSE; connection = nm_simple_connection_new (); @@ -4792,11 +4810,15 @@ test_write_wired_static_routes (void) /* Write out routes */ route = nm_ip_route_new (AF_INET, "1.2.3.0", 24, "222.173.190.239", 0, &error); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32 (3455)); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean (TRUE)); g_assert_no_error (error); nm_setting_ip_config_add_route (s_ip4, route); nm_ip_route_unref (route); route = nm_ip_route_new (AF_INET, "3.2.1.0", 24, "202.254.186.190", 77, &error); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32 (30000)); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean (FALSE)); g_assert_no_error (error); nm_setting_ip_config_add_route (s_ip4, route); nm_ip_route_unref (route); @@ -4818,15 +4840,28 @@ test_write_wired_static_routes (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); - - reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); - - routefile = utils_get_route_path (testfile); + _writer_new_connection_reread (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected", + &reread, + &reread_same); + /* ifcfg does not support setting onlink=0. It gets lost during write+re-read. + * Assert that it's missing, and patch it to check whether the rest of the + * connection equals. */ + g_assert (!reread_same); + nmtst_assert_connection_verifies_without_normalization (reread); + s_ip4 = nm_connection_get_setting_ip4_config (reread); + g_assert (s_ip4); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 2); + route = nm_setting_ip_config_get_route (s_ip4, 1); + g_assert (route); + g_assert (!nm_ip_route_get_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK)); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean (FALSE)); nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); + + routefile = utils_get_route_path (testfile); } static void From cb47ed0fcdddf7a6b13514a117b5566ffbdd4eda Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 13 Nov 2017 10:17:47 +0100 Subject: [PATCH 12/12] platform/tests: add test for onlink route attribute --- src/platform/tests/test-route.c | 202 ++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 60 deletions(-) diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 8326239557..04f4ff494a 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -30,6 +30,42 @@ #define DEVICE_IFINDEX NMTSTP_ENV1_IFINDEX #define EX NMTSTP_ENV1_EX +static void +_wait_for_ipv4_addr_device_route (NMPlatform *platform, + gint64 timeout_ms, + int ifindex, + in_addr_t addr, + guint8 plen) +{ + /* Wait that the addresses gets a device-route. After adding a address, + * the device route is not added immediately. It takes a moment... */ + + addr = nm_utils_ip4_address_clear_host_address (addr, plen); + NMTST_WAIT_ASSERT (400, { + NMDedupMultiIter iter; + NMPLookup lookup; + const NMPObject *o; + + nmp_cache_iter_for_each (&iter, + nm_platform_lookup (platform, + nmp_lookup_init_addrroute (&lookup, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex)), + &o) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (o); + + if ( r->plen == plen + && addr == nm_utils_ip4_address_clear_host_address (r->network, plen) + && r->metric == 0 + && r->scope_inv == nm_platform_route_scope_inv (RT_SCOPE_LINK) + && r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + return; + } + nmtstp_assert_wait_for_signal (platform, + (nmtst_wait_end_us - g_get_monotonic_time ()) / 1000); + }); +} + static void _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, gint64 timeout_ms, @@ -44,7 +80,7 @@ _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, * small amount of time, which prevents the immediate addition of the route * with RTA_PREFSRC */ - NMTST_WAIT_ASSERT (400, { + NMTST_WAIT_ASSERT (timeout_ms, { gboolean should_wait = FALSE; const NMPlatformIP6Address *plt_addr; @@ -63,7 +99,6 @@ _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, }); } - static void ip4_route_callback (NMPlatform *platform, int obj_type_i, int ifindex, const NMPlatformIP4Route *received, int change_type_i, SignalData *data) { @@ -448,63 +483,114 @@ test_ip4_zero_gateway (void) } static void -test_ip4_route_options (void) +test_ip4_route_options (gconstpointer test_data) { - int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); - NMPlatformIP4Route route = { }; - in_addr_t network; - GPtrArray *routes; - NMPlatformIP4Route rts[1]; + const int TEST_IDX = GPOINTER_TO_INT (test_data); + const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + gs_unref_ptrarray GPtrArray *routes = NULL; +#define RTS_MAX 3 + NMPlatformIP4Route rts_add[RTS_MAX] = { }; + NMPlatformIP4Route rts_cmp[RTS_MAX] = { }; + NMPlatformIP4Address addr[1] = { }; + guint i; + guint rts_n = 0; + guint addr_n = 0; - inet_pton (AF_INET, "172.16.1.0", &network); + switch (TEST_IDX) { + case 1: + rts_add[rts_n++] = ((NMPlatformIP4Route) { + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string ("172.16.1.0"), + .plen = 24, + .metric = 20, + .tos = 0x28, + .window = 10000, + .cwnd = 16, + .initcwnd = 30, + .initrwnd = 50, + .mtu = 1350, + .lock_cwnd = TRUE, + }); + break; + case 2: + addr[addr_n++] = ((NMPlatformIP4Address) { + .ifindex = IFINDEX, + .address = nmtst_inet4_from_string ("172.16.1.5"), + .peer_address = nmtst_inet4_from_string ("172.16.1.5"), + .plen = 24, + .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, + .preferred = NM_PLATFORM_LIFETIME_PERMANENT, + .n_ifa_flags = 0, + }); + rts_add[rts_n++] = ((NMPlatformIP4Route) { + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string ("172.17.1.0"), + .gateway = nmtst_inet4_from_string ("172.16.1.1"), + .plen = 24, + .metric = 20, + }); + rts_add[rts_n++] = ((NMPlatformIP4Route) { + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string ("172.19.1.0"), + .gateway = nmtst_inet4_from_string ("172.18.1.1"), + .r_rtm_flags = RTNH_F_ONLINK, + .plen = 24, + .metric = 20, + }); + break; + default: + g_assert_not_reached (); + break; + } + g_assert (rts_n <= G_N_ELEMENTS (rts_add)); + g_assert (addr_n <= G_N_ELEMENTS (addr)); - route.ifindex = ifindex; - route.rt_source = NM_IP_CONFIG_SOURCE_USER; - route.network = network; - route.plen = 24; - route.metric = 20; - route.tos = 0x28; - route.window = 10000; - route.cwnd = 16; - route.initcwnd = 30; - route.initrwnd = 50; - route.mtu = 1350; - route.lock_cwnd = TRUE; + for (i = 0; i < addr_n; i++) { + const NMPlatformIP4Address *a = &addr[i]; - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &route) == NM_PLATFORM_ERROR_SUCCESS); + g_assert (a->ifindex == IFINDEX); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, + a->ifindex, + a->address, + a->plen, + a->peer_address, + a->lifetime, + a->preferred, + a->n_ifa_flags, + a->label)); + if (a->peer_address == a->address) + _wait_for_ipv4_addr_device_route (NM_PLATFORM_GET, 200, a->ifindex, a->address, a->plen); + } - /* Test route listing */ - routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex); - memset (rts, 0, sizeof (rts)); - rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); - rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK); - rts[0].network = network; - rts[0].plen = 24; - rts[0].ifindex = ifindex; - rts[0].metric = 20; - rts[0].tos = 0x28; - rts[0].window = 10000; - rts[0].cwnd = 16; - rts[0].initcwnd = 30; - rts[0].initrwnd = 50; - rts[0].mtu = 1350; - rts[0].lock_cwnd = TRUE; - g_assert_cmpint (routes->len, ==, 1); - nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE); + for (i = 0; i < rts_n; i++) + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]) == NM_PLATFORM_ERROR_SUCCESS); - /* Remove route */ - g_assert (nm_platform_ip_route_delete (NM_PLATFORM_GET, routes->pdata[0])); + for (i = 0; i < rts_n; i++) { + rts_cmp[i] = rts_add[i]; + nm_platform_ip_route_normalize (AF_INET, NM_PLATFORM_IP_ROUTE_CAST (&rts_cmp[i])); + } - g_ptr_array_unref (routes); + routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, IFINDEX); + g_assert_cmpint (routes->len, ==, rts_n); + nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts_cmp, routes->len, TRUE); + + for (i = 0; i < rts_n; i++) { + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, IFINDEX, + rts_add[i].network, rts_add[i].plen, + rts_add[i].metric)); + } +#undef RTS_MAX } - static void test_ip6_route_options (gconstpointer test_data) { const int TEST_IDX = GPOINTER_TO_INT (test_data); const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); - GPtrArray *routes; + gs_unref_ptrarray GPtrArray *routes = NULL; #define RTS_MAX 3 NMPlatformIP6Route rts_add[RTS_MAX] = { }; NMPlatformIP6Route rts_cmp[RTS_MAX] = { }; @@ -582,6 +668,8 @@ test_ip6_route_options (gconstpointer test_data) default: g_assert_not_reached (); } + g_assert (rts_n <= G_N_ELEMENTS (rts_add)); + g_assert (addr_n <= G_N_ELEMENTS (addr)); for (i = 0; i < addr_n; i++) { g_assert (addr[i].ifindex == IFINDEX); @@ -595,28 +683,19 @@ test_ip6_route_options (gconstpointer test_data) addr[i].preferred, addr[i].n_ifa_flags)); } - _wait_for_ipv6_addr_non_tentative (NM_PLATFORM_GET, 400, IFINDEX, addr_n, addr_in6); for (i = 0; i < rts_n; i++) g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]) == NM_PLATFORM_ERROR_SUCCESS); - routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX); - switch (TEST_IDX) { - case 1: - case 2: - case 3: - for (i = 0; i < rts_n; i++) { - rts_cmp[i] = rts_add[i]; - rts_cmp[i].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); - } - break; - default: - g_assert_not_reached (); + for (i = 0; i < rts_n; i++) { + rts_cmp[i] = rts_add[i]; + nm_platform_ip_route_normalize (AF_INET6, NM_PLATFORM_IP_ROUTE_CAST (&rts_cmp[i])); } + + routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX); g_assert_cmpint (routes->len, ==, rts_n); nmtst_platform_ip6_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts_cmp, routes->len, TRUE); - g_ptr_array_unref (routes); for (i = 0; i < rts_n; i++) { g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, IFINDEX, @@ -631,6 +710,7 @@ test_ip6_route_options (gconstpointer test_data) rts_add[i].network, rts_add[i].plen); } +#undef RTS_MAX } /*****************************************************************************/ @@ -771,7 +851,9 @@ _nmtstp_setup_tests (void) add_test_func ("/route/ip4", test_ip4_route); add_test_func ("/route/ip6", test_ip6_route); add_test_func ("/route/ip4_metric0", test_ip4_route_metric0); - add_test_func ("/route/ip4_options", test_ip4_route_options); + add_test_func_data ("/route/ip4_options/1", test_ip4_route_options, GINT_TO_POINTER (1)); + if (nmtstp_is_root_test ()) + add_test_func_data ("/route/ip4_options/2", test_ip4_route_options, GINT_TO_POINTER (2)); add_test_func_data ("/route/ip6_options/1", test_ip6_route_options, GINT_TO_POINTER (1)); add_test_func_data ("/route/ip6_options/2", test_ip6_route_options, GINT_TO_POINTER (2)); add_test_func_data ("/route/ip6_options/3", test_ip6_route_options, GINT_TO_POINTER (3));