From a3c4bf81bba6aeb920806a1c2ebf7b2d2a11cfe8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2015 15:45:10 +0200 Subject: [PATCH 01/14] platform: move address lifetime utils function to nm-platform-utils.c (cherry picked from commit 626a85530ee646a2333c89818b273f0598f9bc6d) --- src/platform/nm-platform-utils.c | 83 ++++++++++++++++++++++++++++++++ src/platform/nm-platform-utils.h | 12 +++++ src/platform/nm-platform.c | 79 +++--------------------------- 3 files changed, 101 insertions(+), 73 deletions(-) diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 407b91fbcc..2be2e4d9b0 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -347,4 +347,87 @@ out: return g_intern_string (driver); } +/****************************************************************** + * utils + ******************************************************************/ + +/** + * Takes a pair @timestamp and @duration, and returns the remaining duration based + * on the new timestamp @now. + */ +guint32 +nmp_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp, + guint32 duration, + guint32 now, + guint32 padding) +{ + gint64 t; + + if (duration == NM_PLATFORM_LIFETIME_PERMANENT) + return NM_PLATFORM_LIFETIME_PERMANENT; + + if (timestamp == 0) { + /* if the @timestamp is zero, assume it was just left unset and that the relative + * @duration starts counting from @now. This is convenient to construct an address + * and print it in nm_platform_ip4_address_to_string(). + * + * In general it does not make sense to set the @duration without anchoring at + * @timestamp because you don't know the absolute expiration time when looking + * at the address at a later moment. */ + timestamp = now; + } + + /* For timestamp > now, just accept it and calculate the expected(?) result. */ + t = (gint64) timestamp + (gint64) duration - (gint64) now; + + /* Optional padding to avoid potential races. */ + t += (gint64) padding; + + if (t <= 0) + return 0; + if (t >= NM_PLATFORM_LIFETIME_PERMANENT) + return NM_PLATFORM_LIFETIME_PERMANENT - 1; + return t; +} + +gboolean +nmp_utils_lifetime_get (guint32 timestamp, + guint32 lifetime, + guint32 preferred, + guint32 now, + guint32 padding, + guint32 *out_lifetime, + guint32 *out_preferred) +{ + guint32 t_lifetime, t_preferred; + + if (lifetime == 0) { + *out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + *out_preferred = NM_PLATFORM_LIFETIME_PERMANENT; + + /* We treat lifetime==0 as permanent addresses to allow easy creation of such addresses + * (without requiring to set the lifetime fields to NM_PLATFORM_LIFETIME_PERMANENT). + * In that case we also expect that the other fields (timestamp and preferred) are left unset. */ + g_return_val_if_fail (timestamp == 0 && preferred == 0, TRUE); + } else { + t_lifetime = nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now, padding); + if (!t_lifetime) + return FALSE; + t_preferred = nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, preferred, now, padding); + + *out_lifetime = t_lifetime; + *out_preferred = MIN (t_preferred, t_lifetime); + + /* Assert that non-permanent addresses have a (positive) @timestamp. nmp_utils_lifetime_rebase_relative_time_on_now() + * treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always + * should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew. + */ + g_return_val_if_fail ( timestamp != 0 + || ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT + && preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE); + g_return_val_if_fail (t_preferred <= t_lifetime, TRUE); + } + return TRUE; +} + diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index d0032f5d69..557de8440b 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -50,5 +50,17 @@ gboolean nmp_utils_mii_supports_carrier_detect (const char *ifname); const char *nmp_utils_udev_get_driver (GUdevDevice *device); +guint32 nmp_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp, + guint32 duration, + guint32 now, + guint32 padding); + +gboolean nmp_utils_lifetime_get (guint32 timestamp, + guint32 lifetime, + guint32 preferred, + guint32 now, + guint32 padding, + guint32 *out_lifetime, + guint32 *out_preferred); #endif /* __NM_PLATFORM_UTILS_H__ */ diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 7c3be22ac6..52e5e51aa4 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -33,6 +33,7 @@ #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-platform.h" +#include "nm-platform-utils.h" #include "NetworkManagerUtils.h" #include "nm-logging.h" #include "nm-enum-types.h" @@ -1978,76 +1979,6 @@ array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address return FALSE; } -/** - * Takes a pair @timestamp and @duration, and returns the remaining duration based - * on the new timestamp @now. - */ -static guint32 -_rebase_relative_time_on_now (guint32 timestamp, guint32 duration, guint32 now, guint32 padding) -{ - gint64 t; - - if (duration == NM_PLATFORM_LIFETIME_PERMANENT) - return NM_PLATFORM_LIFETIME_PERMANENT; - - if (timestamp == 0) { - /* if the @timestamp is zero, assume it was just left unset and that the relative - * @duration starts counting from @now. This is convenient to construct an address - * and print it in nm_platform_ip4_address_to_string(). - * - * In general it does not make sense to set the @duration without anchoring at - * @timestamp because you don't know the absolute expiration time when looking - * at the address at a later moment. */ - timestamp = now; - } - - /* For timestamp > now, just accept it and calculate the expected(?) result. */ - t = (gint64) timestamp + (gint64) duration - (gint64) now; - - /* Optional padding to avoid potential races. */ - t += (gint64) padding; - - if (t <= 0) - return 0; - if (t >= NM_PLATFORM_LIFETIME_PERMANENT) - return NM_PLATFORM_LIFETIME_PERMANENT - 1; - return t; -} - -static gboolean -_address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32 padding, guint32 *out_lifetime, guint32 *out_preferred) -{ - guint32 lifetime, preferred; - - if (address->lifetime == 0) { - *out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; - *out_preferred = NM_PLATFORM_LIFETIME_PERMANENT; - - /* We treat lifetime==0 as permanent addresses to allow easy creation of such addresses - * (without requiring to set the lifetime fields to NM_PLATFORM_LIFETIME_PERMANENT). - * In that case we also expect that the other fields (timestamp and preferred) are left unset. */ - g_return_val_if_fail (address->timestamp == 0 && address->preferred == 0, TRUE); - } else { - lifetime = _rebase_relative_time_on_now (address->timestamp, address->lifetime, now, padding); - if (!lifetime) - return FALSE; - preferred = _rebase_relative_time_on_now (address->timestamp, address->preferred, now, padding); - - *out_lifetime = lifetime; - *out_preferred = MIN (preferred, lifetime); - - /* Assert that non-permanent addresses have a (positive) @timestamp. _rebase_relative_time_on_now() - * treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always - * should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew. - */ - g_return_val_if_fail ( address->timestamp != 0 - || ( address->lifetime == NM_PLATFORM_LIFETIME_PERMANENT - && address->preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE); - g_return_val_if_fail (preferred <= lifetime, TRUE); - } - return TRUE; -} - gboolean nm_platform_ip4_check_reinstall_device_route (NMPlatform *self, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric) { @@ -2112,7 +2043,8 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known gboolean reinstall_device_route = FALSE; /* add a padding of 5 seconds to avoid potential races. */ - if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &lifetime, &preferred)) + if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, 5, &lifetime, &preferred)) continue; if (nm_platform_ip4_check_reinstall_device_route (self, ifindex, known_address, device_route_metric)) @@ -2185,7 +2117,8 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known guint32 lifetime, preferred; /* add a padding of 5 seconds to avoid potential races. */ - if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &lifetime, &preferred)) + if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, 5, &lifetime, &preferred)) continue; if (!nm_platform_ip6_address_add (self, ifindex, known_address->address, @@ -2380,7 +2313,7 @@ _lifetime_to_string (guint32 timestamp, guint32 lifetime, gint32 now, char *buf, return "forever"; g_snprintf (buf, buf_size, "%usec", - _rebase_relative_time_on_now (timestamp, lifetime, now, 0)); + nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now, 0)); return buf; } From af0d99cdccab5320833e41183fdf1a1cb145b5c2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2015 15:56:00 +0200 Subject: [PATCH 02/14] platform: fix setting valid lifetimes when constructing rtnl_addr object build_rtnl_addr() has two parameters "lifetime" and "preferred". Both count from *now*. Fix nmp_object_to_nl() to properly set these timestamps. This bug had not real consequences, because the only place where we use nmp_object_to_nl() the arguments are 0. (cherry picked from commit d0ed4de10466bc838429450dfd8243f99481f5e1) --- src/platform/nm-linux-platform.c | 26 +++++++++++++++----------- src/platform/nm-platform-utils.c | 7 ++++++- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 789216af83..1299dea7a5 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4023,13 +4023,9 @@ build_rtnl_addr (NMPlatform *platform, } _nl_rtnl_addr_set_prefixlen (rtnladdr, plen); - if (lifetime) { - /* note that here we set the relative timestamps (ticking from *now*). - * Contrary to the rtnl_addr objects from our cache, which have absolute - * timestamps (see _rtnl_addr_hack_lifetimes_rel_to_abs()). - * - * This is correct, because we only use build_rtnl_addr() for - * add_object(), delete_object() and cache search (ip_address_exists). */ + if ( lifetime != 0 || lifetime != NM_PLATFORM_LIFETIME_PERMANENT + || preferred != 0 || preferred != NM_PLATFORM_LIFETIME_PERMANENT) { + /* note that here we set the relative timestamps (ticking from *now*). */ rtnl_addr_set_valid_lifetime (rtnladdr, lifetime); rtnl_addr_set_preferred_lifetime (rtnladdr, preferred); } @@ -4058,6 +4054,10 @@ struct nl_object * _nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only) { const NMPlatformIP4Address *obj = (const NMPlatformIP4Address *) _obj; + guint32 lifetime, preferred; + + nmp_utils_lifetime_get (obj->timestamp, obj->lifetime, obj->preferred, + 0, 0, &lifetime, &preferred); return build_rtnl_addr (platform, AF_INET, @@ -4065,8 +4065,8 @@ _nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObjec &obj->address, obj->peer_address ? &obj->peer_address : NULL, obj->plen, - obj->lifetime, - obj->preferred, + lifetime, + preferred, 0, obj->label[0] ? obj->label : NULL); } @@ -4075,6 +4075,10 @@ struct nl_object * _nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only) { const NMPlatformIP6Address *obj = (const NMPlatformIP6Address *) _obj; + guint32 lifetime, preferred; + + nmp_utils_lifetime_get (obj->timestamp, obj->lifetime, obj->preferred, + 0, 0, &lifetime, &preferred); return build_rtnl_addr (platform, AF_INET6, @@ -4082,8 +4086,8 @@ _nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObjec &obj->address, !IN6_IS_ADDR_UNSPECIFIED (&obj->peer_address) ? &obj->peer_address : NULL, obj->plen, - obj->lifetime, - obj->preferred, + lifetime, + preferred, 0, NULL); } diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 2be2e4d9b0..02773512c8 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -410,9 +410,14 @@ nmp_utils_lifetime_get (guint32 timestamp, * In that case we also expect that the other fields (timestamp and preferred) are left unset. */ g_return_val_if_fail (timestamp == 0 && preferred == 0, TRUE); } else { + if (!now) + now = nm_utils_get_monotonic_timestamp_s (); t_lifetime = nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now, padding); - if (!t_lifetime) + if (!t_lifetime) { + *out_lifetime = 0; + *out_preferred = 0; return FALSE; + } t_preferred = nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, preferred, now, padding); *out_lifetime = t_lifetime; From e04d0c6e6b5aaa001b010336c21c7fc9e8a3334e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2015 13:22:48 +0200 Subject: [PATCH 03/14] platform: track pref_src field of IPv4 routes (cherry picked from commit 7594e3122045081050c031a5e8b1179d1cd561df) --- src/nm-route-manager.c | 4 ++-- src/platform/nm-linux-platform.c | 11 ++++++++++- src/platform/nm-platform.c | 20 +++++++++++--------- src/platform/nm-platform.h | 6 +++++- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 77cc761456..8c4c6a14f7 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -515,7 +515,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const * device routes, on the second the others (gateway routes). */ continue; } - vtable->vt->route_add (NM_PLATFORM_GET, 0, rest_route, 0); + vtable->vt->route_add (NM_PLATFORM_GET, 0, rest_route); } } g_array_unref (to_restore_routes); @@ -559,7 +559,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const || route_id_cmp_result != 0 || !_route_equals_ignoring_ifindex (vtable, cur_plat_route, cur_ipx_route)) { - if (!vtable->vt->route_add (NM_PLATFORM_GET, ifindex, cur_ipx_route, 0)) { + if (!vtable->vt->route_add (NM_PLATFORM_GET, ifindex, cur_ipx_route)) { if (cur_ipx_route->rx.source < NM_IP_CONFIG_SOURCE_USER) { _LOGD (vtable->vt->addr_family, "ignore error adding IPv%c route to kernel: %s", diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 1299dea7a5..0582c0d714 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1289,6 +1289,7 @@ _nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject struct rtnl_route *nlo = (struct rtnl_route *) _nlo; struct nl_addr *dst, *gw; struct rtnl_nexthop *nexthop; + struct nl_addr *pref_src; if (rtnl_route_get_type (nlo) != RTN_UNICAST || rtnl_route_get_table (nlo) != RT_TABLE_MAIN || @@ -1334,6 +1335,14 @@ _nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject } else obj->source = _nm_ip_config_source_from_rtprot (rtnl_route_get_protocol (nlo)); + pref_src = rtnl_route_get_pref_src (nlo); + if (pref_src) { + if (nl_addr_get_len (pref_src) != sizeof (obj->pref_src)) + g_warn_if_reached (); + else + memcpy (&obj->pref_src, nl_addr_get_binary_addr (pref_src), sizeof (obj->pref_src)); + } + return TRUE; } @@ -4346,7 +4355,7 @@ _nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject &obj->network, obj->plen, &obj->gateway, - NULL, + obj->pref_src ? &obj->pref_src : NULL, obj->metric, obj->mss); } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 52e5e51aa4..8439191d18 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2177,7 +2177,6 @@ nm_platform_ip4_route_add (NMPlatform *self, if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { NMPlatformIP4Route route = { 0 }; - char pref_src_buf[NM_UTILS_INET_ADDRSTRLEN]; route.ifindex = ifindex; route.source = source; @@ -2186,11 +2185,9 @@ nm_platform_ip4_route_add (NMPlatform *self, route.gateway = gateway; route.metric = metric; route.mss = mss; + route.pref_src = pref_src; - debug ("route: adding or updating IPv4 route: %s%s%s%s", nm_platform_ip4_route_to_string (&route), - pref_src ? " (src: " : "", - pref_src ? nm_utils_inet4_ntop (pref_src, pref_src_buf) : "", - pref_src ? ")" : ""); + debug ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route)); } return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss); } @@ -2595,6 +2592,7 @@ const char * nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route) { char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN]; + char s_pref_src[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; char str_scope[30]; @@ -2613,6 +2611,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route) " mss %"G_GUINT32_FORMAT " src %s" /* source */ "%s%s" /* scope */ + "%s%s" /* pref-src */ "", s_network, route->plen, s_gateway, @@ -2621,7 +2620,9 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route) route->mss, source_to_string (route->source), route->scope_inv ? " scope " : "", - route->scope_inv ? (rtnl_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : ""); + route->scope_inv ? (rtnl_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "", + route->pref_src ? " pref-src " : "", + route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : ""); return _nm_platform_to_string_buffer; } @@ -2800,6 +2801,7 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route _CMP_FIELD (a, b, metric); _CMP_FIELD (a, b, mss); _CMP_FIELD (a, b, scope_inv); + _CMP_FIELD (a, b, pref_src); return 0; } @@ -2922,7 +2924,7 @@ log_ip6_route (NMPlatform *p, NMPObjectType obj_type, int ifindex, NMPlatformIP6 /******************************************************************/ static gboolean -_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src) +_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route) { return nm_platform_ip4_route_add (self, ifindex > 0 ? ifindex : route->rx.ifindex, @@ -2930,13 +2932,13 @@ _vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *rout route->r4.network, route->rx.plen, route->r4.gateway, - v4_pref_src, + route->r4.pref_src, route->rx.metric, route->rx.mss); } static gboolean -_vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src) +_vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route) { return nm_platform_ip6_route_add (self, ifindex > 0 ? ifindex : route->rx.ifindex, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 4ad30b7de1..89f218b363 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -276,6 +276,10 @@ struct _NMPlatformIP4Route { /* The bitwise inverse of the route scope. It is inverted so that the * default value (RT_SCOPE_NOWHERE) is nul. */ guint8 scope_inv; + + /* RTA_PREFSRC/rtnl_route_get_pref_src(). A value of zero means that + * no pref-src is set. */ + guint32 pref_src; }; G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Route, network)); @@ -305,7 +309,7 @@ typedef struct { int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b); const char *(*route_to_string) (const NMPlatformIPXRoute *route); GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode); - gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src); + gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route); gboolean (*route_delete) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route); gboolean (*route_delete_default) (NMPlatform *self, int ifindex, guint32 metric); guint32 (*metric_normalize) (guint32 metric); From 1d2ff90a5c73a051287fa84347123b22ea6aa36c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2015 18:11:24 +0200 Subject: [PATCH 04/14] core: minor refactoring iterating and removing list of routes The previous version causes an unsigned integer underflow. That is not wrong, but still change it. Also use g_array_remove_index_fast() because the list of routes is unsorted anyway. (cherry picked from commit e7f3ccf7cdb5b5d1765b434c71cf622a6a31a966) --- src/nm-ip4-config.c | 7 ++++--- src/nm-ip6-config.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index db34eb14c9..b0c46a7464 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -201,7 +201,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) /* Extract gateway from default route */ old_gateway = priv->gateway; - for (i = 0; i < priv->routes->len; i++) { + for (i = 0; i < priv->routes->len; ) { const NMPlatformIP4Route *route = &g_array_index (priv->routes, NMPlatformIP4Route, i); if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { @@ -211,9 +211,10 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) } has_gateway = TRUE; /* Remove the default route from the list */ - g_array_remove_index (priv->routes, i); - i--; + g_array_remove_index_fast (priv->routes, i); + continue; } + i++; } /* If there is a host route to the gateway, ignore that route. It is diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index cbad11ad01..4d1718fd52 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -313,7 +313,7 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co /* Extract gateway from default route */ old_gateway = priv->gateway; - for (i = 0; i < priv->routes->len; i++) { + for (i = 0; i < priv->routes->len; ) { const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i); if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { @@ -323,9 +323,10 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co } has_gateway = TRUE; /* Remove the default route from the list */ - g_array_remove_index (priv->routes, i); - i--; + g_array_remove_index_fast (priv->routes, i); + continue; } + i++; } /* If there is a host route to the gateway, ignore that route. It is From 44cb5b6b6232d4631e39c68621fb240778dd3c65 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Jun 2015 17:00:24 +0200 Subject: [PATCH 05/14] platform/trivial: rename enum value NM_IP_CONFIG_SOURCE_RTPROT_KERNEL This source type was platform internal up to now. Next we will expose it. (cherry picked from commit 85bf9ded2ef37938d92fd64f003713bee4ca492e) --- src/nm-types.h | 4 ++-- src/platform/nm-linux-platform.c | 4 ++-- src/platform/nm-platform.c | 2 +- src/platform/nmp-object.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/nm-types.h b/src/nm-types.h index 60b8885424..1a002ac3f0 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -51,8 +51,8 @@ typedef enum { /* platform internal flag used to mark routes with RTM_F_CLONED. */ _NM_IP_CONFIG_SOURCE_RTM_F_CLONED, - /* platform internal flag used to mark routes with protocol RTPROT_KERNEL. */ - _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL, + /* routes from platform with protocol RTPROT_KERNEL. */ + NM_IP_CONFIG_SOURCE_RTPROT_KERNEL, NM_IP_CONFIG_SOURCE_KERNEL, NM_IP_CONFIG_SOURCE_SHARED, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 0582c0d714..553022c1cf 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -597,7 +597,7 @@ _nm_ip_config_source_to_rtprot (NMIPConfigSource source) case NM_IP_CONFIG_SOURCE_UNKNOWN: return RTPROT_UNSPEC; case NM_IP_CONFIG_SOURCE_KERNEL: - case _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL: + case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL: return RTPROT_KERNEL; case NM_IP_CONFIG_SOURCE_DHCP: return RTPROT_DHCP; @@ -616,7 +616,7 @@ _nm_ip_config_source_from_rtprot (guint rtprot) case RTPROT_UNSPEC: return NM_IP_CONFIG_SOURCE_UNKNOWN; case RTPROT_KERNEL: - return _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL; + return NM_IP_CONFIG_SOURCE_RTPROT_KERNEL; case RTPROT_REDIRECT: return NM_IP_CONFIG_SOURCE_KERNEL; case RTPROT_RA: diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 8439191d18..522b041daa 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2275,7 +2275,7 @@ static const char * source_to_string (NMIPConfigSource source) { switch (source) { - case _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL: + case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL: return "rtprot-kernel"; case _NM_IP_CONFIG_SOURCE_RTM_F_CLONED: return "rtm-f-cloned"; diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 77e7b15b99..0750fa7492 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -786,7 +786,7 @@ _vt_cmd_obj_is_visible_ipx_route (const NMPObject *obj) { NMIPConfigSource source = obj->ip_route.source; - return obj->object.ifindex > 0 && (source != _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL && source != _NM_IP_CONFIG_SOURCE_RTM_F_CLONED); + return obj->object.ifindex > 0 && (source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL && source != _NM_IP_CONFIG_SOURCE_RTM_F_CLONED); } /******************************************************************/ From 7082f44c2f0fa08508a7de26bbd63af83a9b5a6c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2015 17:28:37 +0200 Subject: [PATCH 06/14] platform: change NMPlatformGetRouteMode enum to NMPlatformGetRouteFlags flags By having flags instead of an enum/mode, we can encode more combinations of filtering the result. (cherry picked from commit d9dba6b6624cab655f3cf8a7bcb8734d938d801a) --- src/devices/nm-device.c | 4 ++-- src/nm-default-route-manager.c | 4 ++-- src/nm-ip4-config.c | 2 +- src/nm-ip6-config.c | 2 +- src/nm-route-manager.c | 2 +- src/platform/nm-fake-platform.c | 22 ++++++++++++---------- src/platform/nm-linux-platform.c | 26 +++++++++----------------- src/platform/nm-platform.c | 10 ++++------ src/platform/nm-platform.h | 22 +++++++++++++--------- src/platform/tests/dump.c | 4 ++-- src/platform/tests/platform.c | 4 ++-- src/platform/tests/test-cleanup.c | 8 ++++---- src/platform/tests/test-route.c | 4 ++-- src/tests/test-route-manager.c | 8 ++++---- 14 files changed, 59 insertions(+), 63 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 7a114c52aa..3d0bd936aa 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3076,9 +3076,9 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat GArray *routes; if (addr_family == AF_INET) - routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); + routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); else - routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); + routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); if (routes) { guint route_metric = G_MAXUINT32, m; diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index e28d92f652..8107ae9274 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -292,7 +292,7 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, gboolean changed = FALSE; /* prune all other default routes from this device. */ - routes = vtable->vt->route_get_all (NM_PLATFORM_GET, 0, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); + routes = vtable->vt->route_get_all (NM_PLATFORM_GET, 0, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); for (i = 0; i < routes->len; i++) { const NMPlatformIPRoute *route; @@ -478,7 +478,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c entries = vtable->get_entries (priv); - routes = vtable->vt->route_get_all (NM_PLATFORM_GET, 0, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); + routes = vtable->vt->route_get_all (NM_PLATFORM_GET, 0, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); assumed_metrics = _get_assumed_interface_metrics (vtable, self, routes); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index b0c46a7464..0efc30babe 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -197,7 +197,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) g_array_unref (priv->routes); priv->addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); - priv->routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); + priv->routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); /* Extract gateway from default route */ old_gateway = priv->gateway; diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 4d1718fd52..65cd711bc6 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -309,7 +309,7 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co g_array_unref (priv->routes); priv->addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); - priv->routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); + priv->routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); /* Extract gateway from default route */ old_gateway = priv->gateway; diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 8c4c6a14f7..cefa7fbd5b 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -358,7 +358,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const NMPlatformIPXRoute *cur_ipx_route; ipx_routes = vtable->vt->is_ip4 ? &priv->ip4_routes : &priv->ip6_routes; - plat_routes = vtable->vt->route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT); + plat_routes = vtable->vt->route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); plat_routes_idx = _route_index_create (vtable, plat_routes); known_routes_idx = _route_index_create (vtable, known_routes); diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 96fd17b716..37bec90884 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -1034,26 +1034,27 @@ ip4_check_reinstall_device_route (NMPlatform *platform, int ifindex, const NMPla /******************************************************************/ static GArray * -ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode) +ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); GArray *routes; NMPlatformIP4Route *route; guint i; - g_return_val_if_fail (NM_IN_SET (mode, NM_PLATFORM_GET_ROUTE_MODE_ALL, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT), NULL); - routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route)); + if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT)) + flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT; + /* Fill routes */ for (i = 0; i < priv->ip4_routes->len; i++) { route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); if (route && (!ifindex || route->ifindex == ifindex)) { if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { - if (mode != NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT) + if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT)) g_array_append_val (routes, *route); } else { - if (mode != NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT) + if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT)) g_array_append_val (routes, *route); } } @@ -1063,26 +1064,27 @@ ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mod } static GArray * -ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode) +ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); GArray *routes; NMPlatformIP6Route *route; guint i; - g_return_val_if_fail (NM_IN_SET (mode, NM_PLATFORM_GET_ROUTE_MODE_ALL, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT), NULL); - routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route)); + if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT)) + flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT; + /* Fill routes */ for (i = 0; i < priv->ip6_routes->len; i++) { route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); if (route && (!ifindex || route->ifindex == ifindex)) { if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { - if (mode != NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT) + if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT)) g_array_append_val (routes, *route); } else { - if (mode != NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT) + if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT)) g_array_append_val (routes, *route); } } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 553022c1cf..911ec928ee 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4243,42 +4243,34 @@ ip4_check_reinstall_device_route (NMPlatform *platform, int ifindex, const NMPla /******************************************************************/ static GArray * -ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteMode mode) +ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - gboolean with_default = FALSE, with_non_default = FALSE; nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - if (mode == NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT) - with_non_default = TRUE; - else if (mode == NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT) - with_default = TRUE; - else if (mode == NM_PLATFORM_GET_ROUTE_MODE_ALL) { - with_non_default = TRUE; - with_default = TRUE; - } else - g_return_val_if_reached (NULL); + if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT)) + flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT; return nmp_cache_lookup_multi_to_array (priv->cache, obj_type, nmp_cache_id_init_routes_visible (NMP_CACHE_ID_STATIC, obj_type, - with_default, - with_non_default, + NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT), + NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT), ifindex)); } static GArray * -ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode) +ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags) { - return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, mode); + return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, flags); } static GArray * -ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode) +ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags) { - return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, mode); + return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags); } static void diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 522b041daa..cdf7cfd4b7 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2142,25 +2142,23 @@ nm_platform_address_flush (NMPlatform *self, int ifindex) /******************************************************************/ GArray * -nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode) +nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags) { _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (ifindex >= 0, NULL); - g_return_val_if_fail (klass->ip4_route_get_all, NULL); - return klass->ip4_route_get_all (self, ifindex, mode); + return klass->ip4_route_get_all (self, ifindex, flags); } GArray * -nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode) +nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags) { _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (ifindex >= 0, NULL); - g_return_val_if_fail (klass->ip6_route_get_all, NULL); - return klass->ip6_route_get_all (self, ifindex, mode); + return klass->ip6_route_get_all (self, ifindex, flags); } gboolean diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 89f218b363..7d101ff452 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -151,10 +151,14 @@ typedef enum { #define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32 typedef enum { - NM_PLATFORM_GET_ROUTE_MODE_ALL, - NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, - NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT, -} NMPlatformGetRouteMode; + NM_PLATFORM_GET_ROUTE_FLAGS_NONE = 0, + + /* Whether to include default-routes/non-default-routes. Omitting + * both WITH_DEFAULT and WITH_NON_DEFAULT, is equal to specifying + * both of them. */ + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT = (1LL << 0), + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT = (1LL << 1), +} NMPlatformGetRouteFlags; typedef struct { __NMPlatformObject_COMMON; @@ -308,7 +312,7 @@ typedef struct { gsize sizeof_route; int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b); const char *(*route_to_string) (const NMPlatformIPXRoute *route); - GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode); + GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route); gboolean (*route_delete) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route); gboolean (*route_delete_default) (NMPlatform *self, int ifindex, guint32 metric); @@ -516,8 +520,8 @@ typedef struct { gboolean (*ip4_check_reinstall_device_route) (NMPlatform *, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric); - GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteMode mode); - GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteMode mode); + GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); + GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, in_addr_t network, int plen, in_addr_t gateway, guint32 pref_src, guint32 metric, guint32 mss); @@ -706,8 +710,8 @@ gboolean nm_platform_address_flush (NMPlatform *self, int ifindex); gboolean nm_platform_ip4_check_reinstall_device_route (NMPlatform *self, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric); -GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode); -GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode); +GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); +GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); gboolean nm_platform_ip4_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, in_addr_t network, int plen, in_addr_t gateway, guint32 pref_src, guint32 metric, guint32 mss); diff --git a/src/platform/tests/dump.c b/src/platform/tests/dump.c index 575ce6fb34..54de1da70c 100644 --- a/src/platform/tests/dump.c +++ b/src/platform/tests/dump.c @@ -86,8 +86,8 @@ dump_interface (NMPlatformLink *link) g_array_unref (ip4_addresses); g_array_unref (ip6_addresses); - ip4_routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); - ip6_routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); + ip4_routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + ip6_routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); g_assert (ip4_routes); g_assert (ip6_routes); diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c index f87588a30b..60555414da 100644 --- a/src/platform/tests/platform.c +++ b/src/platform/tests/platform.c @@ -640,7 +640,7 @@ do_ip4_route_get_all (char **argv) int i; if (ifindex) { - routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); + routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); for (i = 0; i < routes->len; i++) { route = &g_array_index (routes, NMPlatformIP4Route, i); inet_ntop (AF_INET, &route->network, networkstr, sizeof (networkstr)); @@ -664,7 +664,7 @@ do_ip6_route_get_all (char **argv) int i; if (ifindex) { - routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); + routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); for (i = 0; i < routes->len; i++) { route = &g_array_index (routes, NMPlatformIP6Route, i); inet_ntop (AF_INET6, &route->network, networkstr, sizeof (networkstr)); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index f14d9c07ac..0b825114aa 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -54,8 +54,8 @@ test_cleanup_internal (void) addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); - routes4 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); - routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); + routes4 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); g_assert_cmpint (addresses4->len, ==, 1); g_assert_cmpint (addresses6->len, ==, 2); /* also has a IPv6 LL address. */ @@ -72,8 +72,8 @@ test_cleanup_internal (void) addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); - routes4 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); - routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); + routes4 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); g_assert_cmpint (addresses4->len, ==, 0); g_assert_cmpint (addresses6->len, ==, 0); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 29e7c89851..79d6fce75e 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -155,7 +155,7 @@ test_ip4_route (void) accept_signals (route_changed, 0, 1); /* Test route listing */ - routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); + routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); memset (rts, 0, sizeof (rts)); rts[0].source = NM_IP_CONFIG_SOURCE_USER; rts[0].network = gateway; @@ -242,7 +242,7 @@ test_ip6_route (void) accept_signals (route_changed, 0, 1); /* Test route listing */ - routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL); + routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); memset (rts, 0, sizeof (rts)); rts[0].source = NM_IP_CONFIG_SOURCE_USER; rts[0].network = gateway; diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index c57bcd365c..bcc5f3f1be 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -144,10 +144,10 @@ ip4_routes (test_fixture *fixture) { GArray *routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, fixture->ifindex0, - NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT); + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); GArray *routes1 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, fixture->ifindex1, - NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT); + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); g_array_append_vals (routes, routes1->data, routes1->len); g_array_free (routes1, TRUE); @@ -459,10 +459,10 @@ ip6_routes (test_fixture *fixture) { GArray *routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, fixture->ifindex0, - NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT); + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); GArray *routes1 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, fixture->ifindex1, - NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT); + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); g_array_append_vals (routes, routes1->data, routes1->len); g_array_free (routes1, TRUE); From 300a7ab4d149a563208436fb13458d048701e6d8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2015 17:08:58 +0200 Subject: [PATCH 07/14] platform: expose routes with "proto kernel" too Also expose routes with "proto kernel". But add a flag to nm_platform_ipx_route_get_all() to hide them by default. (cherry picked from commit 42664e87521eb2c04600b6f0399d49ebdca4b46a) --- src/platform/nm-linux-platform.c | 34 +++++++++++++++++++++++++------- src/platform/nm-platform.h | 2 ++ src/platform/nmp-object.c | 2 +- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 911ec928ee..a993d3fe1d 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4246,19 +4246,39 @@ static GArray * ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + NMPCacheId cache_id; + const NMPlatformIPRoute *const* routes; + GArray *array; + const NMPClass *klass; + gboolean with_rtprot_kernel; + guint i, len; nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT)) flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT; - return nmp_cache_lookup_multi_to_array (priv->cache, - obj_type, - nmp_cache_id_init_routes_visible (NMP_CACHE_ID_STATIC, - obj_type, - NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT), - NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT), - ifindex)); + klass = nmp_class_from_type (obj_type); + + nmp_cache_id_init_routes_visible (&cache_id, + obj_type, + NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT), + NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT), + ifindex); + + routes = (const NMPlatformIPRoute *const*) nmp_cache_lookup_multi (priv->cache, &cache_id, &len); + + array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, len); + + with_rtprot_kernel = NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL); + for (i = 0; i < len; i++) { + nm_assert (NMP_OBJECT_GET_CLASS (NMP_OBJECT_UP_CAST (routes[i])) == klass); + + if ( with_rtprot_kernel + || routes[i]->source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + g_array_append_vals (array, routes[i], 1); + } + return array; } static GArray * diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 7d101ff452..e6305c325e 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -158,6 +158,8 @@ typedef enum { * both of them. */ NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT = (1LL << 0), NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT = (1LL << 1), + + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL = (1LL << 2), } NMPlatformGetRouteFlags; typedef struct { diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 0750fa7492..51684b93c7 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -786,7 +786,7 @@ _vt_cmd_obj_is_visible_ipx_route (const NMPObject *obj) { NMIPConfigSource source = obj->ip_route.source; - return obj->object.ifindex > 0 && (source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL && source != _NM_IP_CONFIG_SOURCE_RTM_F_CLONED); + return obj->object.ifindex > 0 && source != _NM_IP_CONFIG_SOURCE_RTM_F_CLONED; } /******************************************************************/ From 976726f22166dd315e41f285310b8a5a0096ffc8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Jun 2015 15:05:25 +0200 Subject: [PATCH 08/14] libnm: add _nm_utils_ptrarray_find_binary_search() helper (cherry picked from commit 650fec81e22389a24d641971552c67e476b9ce71) --- libnm-core/nm-core-internal.h | 2 + libnm-core/nm-utils.c | 33 ++++++++++ libnm-core/tests/test-general.c | 105 ++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+) diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 8512c0bf05..2f42ab52ac 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -112,6 +112,8 @@ GPtrArray *_nm_utils_copy_object_array (const GPtrArray *array); gssize _nm_utils_ptrarray_find_first (gpointer *list, gssize len, gconstpointer needle); +gssize _nm_utils_ptrarray_find_binary_search (gpointer *list, gsize len, gpointer needle, GCompareDataFunc cmpfcn, gpointer user_data); + gboolean _nm_utils_string_in_list (const char *str, const char **valid_strings); diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index b2e7faeb30..abd5a56e5b 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -657,6 +657,39 @@ _nm_utils_ptrarray_find_first (gpointer *list, gssize len, gconstpointer needle) return -1; } +gssize +_nm_utils_ptrarray_find_binary_search (gpointer *list, gsize len, gpointer needle, GCompareDataFunc cmpfcn, gpointer user_data) +{ + gssize imin, imax, imid; + int cmp; + + g_return_val_if_fail (list || !len, ~((gssize) 0)); + g_return_val_if_fail (cmpfcn, ~((gssize) 0)); + + imin = 0; + if (len == 0) + return ~imin; + + imax = len - 1; + + while (imin <= imax) { + imid = imin + (imax - imin) / 2; + + cmp = cmpfcn (list[imid], needle, user_data); + if (cmp == 0) + return imid; + + if (cmp < 0) + imin = imid + 1; + else + imax = imid - 1; + } + + /* return the inverse of @imin. This is a negative number, but + * also is ~imin the position where the value should be inserted. */ + return ~imin; +} + GVariant * _nm_utils_bytes_to_dbus (const GValue *prop_value) { diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 03c2eaf5b2..5ffe5c5660 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -4297,6 +4297,110 @@ test_g_ptr_array_insert (void) /******************************************************************************/ +static int +_test_find_binary_search_cmp (gconstpointer a, gconstpointer b, gpointer dummy) +{ + int ia, ib; + + ia = GPOINTER_TO_INT (a); + ib = GPOINTER_TO_INT (b); + + if (ia == ib) + return 0; + if (ia < ib) + return -1; + return 1; +} + +static void +_test_find_binary_search_do (const int *array, gsize len) +{ + gsize i; + gssize idx; + gs_free gpointer *parray = g_new (gpointer, len); + const int needle = 0; + gpointer pneedle = GINT_TO_POINTER (needle); + gssize expected_result; + + for (i = 0; i < len; i++) + parray[i] = GINT_TO_POINTER (array[i]); + + expected_result = _nm_utils_ptrarray_find_first (parray, len, pneedle); + + idx = _nm_utils_ptrarray_find_binary_search (parray, len, pneedle, _test_find_binary_search_cmp, NULL); + if (expected_result >= 0) + g_assert_cmpint (expected_result, ==, idx); + else { + gssize idx2 = ~idx; + g_assert_cmpint (idx, <, 0); + + g_assert (idx2 >= 0); + g_assert (idx2 <= len); + g_assert (idx2 - 1 < 0 || _test_find_binary_search_cmp (parray[idx2 - 1], pneedle, NULL) < 0); + g_assert (idx2 >= len || _test_find_binary_search_cmp (parray[idx2], pneedle, NULL) > 0); + } + for (i = 0; i < len; i++) { + int cmp; + + cmp = _test_find_binary_search_cmp (parray[i], pneedle, NULL); + if (cmp == 0) { + g_assert (pneedle == parray[i]); + g_assert (idx >= 0); + g_assert (i == idx); + } else { + g_assert (pneedle != parray[i]); + if (cmp < 0) { + if (idx < 0) + g_assert (i < ~idx); + else + g_assert (i < idx); + } else { + if (idx < 0) + g_assert (i >= ~idx); + else + g_assert (i >= idx); + } + } + } +} +#define test_find_binary_search_do(...) \ + G_STMT_START { \ + const int _array[] = { __VA_ARGS__ } ; \ + _test_find_binary_search_do (_array, G_N_ELEMENTS (_array)); \ + } G_STMT_END + +static void +test_nm_utils_ptrarray_find_binary_search (void) +{ +#define _NOT(idx) (~ ((gssize) (idx))) + test_find_binary_search_do ( 0); + test_find_binary_search_do ( -1, 0); + test_find_binary_search_do ( -2, -1, 0); + test_find_binary_search_do (-3, -2, -1, 0); + test_find_binary_search_do ( 0, 1); + test_find_binary_search_do ( 0, 1, 2); + test_find_binary_search_do ( -1, 0, 1, 2); + test_find_binary_search_do ( -2, -1, 0, 1, 2); + test_find_binary_search_do (-3, -2, -1, 0, 1, 2); + test_find_binary_search_do (-3, -2, -1, 0, 1, 2); + test_find_binary_search_do (-3, -2, -1, 0, 1, 2, 3); + test_find_binary_search_do (-3, -2, -1, 0, 1, 2, 3, 4); + + test_find_binary_search_do ( -1); + test_find_binary_search_do ( -2, -1); + test_find_binary_search_do (-3, -2, -1); + test_find_binary_search_do ( 1); + test_find_binary_search_do ( 1, 2); + test_find_binary_search_do ( -1, 1, 2); + test_find_binary_search_do ( -2, -1, 1, 2); + test_find_binary_search_do (-3, -2, -1, 1, 2); + test_find_binary_search_do (-3, -2, -1, 1, 2); + test_find_binary_search_do (-3, -2, -1, 1, 2, 3); + test_find_binary_search_do (-3, -2, -1, 1, 2, 3, 4); +} + +/******************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -4398,6 +4502,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/_nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64); g_test_add_func ("/core/general/nm_utils_is_power_of_two", test_nm_utils_is_power_of_two); g_test_add_func ("/core/general/_glib_compat_g_ptr_array_insert", test_g_ptr_array_insert); + g_test_add_func ("/core/general/_nm_utils_ptrarray_find_binary_search", test_nm_utils_ptrarray_find_binary_search); return g_test_run (); } From 74da44e3dfb5ffb93a54b587bb214dde82178e08 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Jun 2015 15:11:38 +0200 Subject: [PATCH 09/14] route-manager: keep a reference of the platform instance Soon we will subscribe to the platform instance for change signals. If a singleton instance uses another singleton instance, it should keep a reference to it, especially if it subscribes to a signal (that will be disconnected on dispose()). (cherry picked from commit b79ade897510d3fc05aef56ac265538ebfa2322a) --- src/nm-route-manager.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index cefa7fbd5b..fcc204dff0 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -39,6 +39,8 @@ typedef struct { } RouteEntries; typedef struct { + NMPlatform *platform; + RouteEntries ip4_routes; RouteEntries ip6_routes; } NMRouteManagerPrivate; @@ -358,7 +360,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const NMPlatformIPXRoute *cur_ipx_route; ipx_routes = vtable->vt->is_ip4 ? &priv->ip4_routes : &priv->ip6_routes; - plat_routes = vtable->vt->route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + plat_routes = vtable->vt->route_get_all (priv->platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); plat_routes_idx = _route_index_create (vtable, plat_routes); known_routes_idx = _route_index_create (vtable, known_routes); @@ -494,7 +496,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const /* if @cur_ipx_route is not equal to @plat_route, the route must be deleted. */ if (!(cur_ipx_route && route_id_cmp_result == 0)) - vtable->vt->route_delete (NM_PLATFORM_GET, ifindex, cur_plat_route); + vtable->vt->route_delete (priv->platform, ifindex, cur_plat_route); cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes); } @@ -515,7 +517,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const * device routes, on the second the others (gateway routes). */ continue; } - vtable->vt->route_add (NM_PLATFORM_GET, 0, rest_route); + vtable->vt->route_add (priv->platform, 0, rest_route); } } g_array_unref (to_restore_routes); @@ -559,7 +561,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const || route_id_cmp_result != 0 || !_route_equals_ignoring_ifindex (vtable, cur_plat_route, cur_ipx_route)) { - if (!vtable->vt->route_add (NM_PLATFORM_GET, ifindex, cur_ipx_route)) { + if (!vtable->vt->route_add (priv->platform, ifindex, cur_ipx_route)) { if (cur_ipx_route->rx.source < NM_IP_CONFIG_SOURCE_USER) { _LOGD (vtable->vt->addr_family, "ignore error adding IPv%c route to kernel: %s", @@ -646,12 +648,24 @@ nm_route_manager_init (NMRouteManager *self) { NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); + priv->platform = g_object_ref (NM_PLATFORM_GET); + priv->ip4_routes.entries = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route)); priv->ip6_routes.entries = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route)); priv->ip4_routes.index = _route_index_create (&vtable_v4, priv->ip4_routes.entries); priv->ip6_routes.index = _route_index_create (&vtable_v6, priv->ip6_routes.entries); } +static void +dispose (GObject *object) +{ + NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (object); + + g_clear_object (&priv->platform); + + G_OBJECT_CLASS (nm_route_manager_parent_class)->dispose (object); +} + static void finalize (GObject *object) { @@ -673,5 +687,6 @@ nm_route_manager_class_init (NMRouteManagerClass *klass) g_type_class_add_private (klass, sizeof (NMRouteManagerPrivate)); /* virtual methods */ + object_class->dispose = dispose; object_class->finalize = finalize; } From a698b70d0f274f9f8abb9730d30309aa881fdcaf Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 24 Jun 2015 11:26:17 +0200 Subject: [PATCH 10/14] route-manager: process platform events before syncing routes Let's ensure we have a fresh platform cache before starting to sync. (cherry picked from commit c5c612d711e4477af84bb28566ed52f5968cdbb5) --- src/nm-route-manager.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index fcc204dff0..ac8ded374a 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -359,6 +359,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const const NMPlatformIPXRoute *cur_known_route, *cur_plat_route; NMPlatformIPXRoute *cur_ipx_route; + nm_platform_process_events (priv->platform); + ipx_routes = vtable->vt->is_ip4 ? &priv->ip4_routes : &priv->ip6_routes; plat_routes = vtable->vt->route_get_all (priv->platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); plat_routes_idx = _route_index_create (vtable, plat_routes); From 8532b83f46fac73d3a19c7b77a68de8fb237fdff Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 24 Jun 2015 11:21:43 +0200 Subject: [PATCH 11/14] route-manager: add argument @ignore_kernel_routes to route_sync() Will be used later, no behavioral change yet. (cherry picked from commit 347555795f405263fb117b0472ca916f0b79b486) --- src/nm-ip4-config.c | 2 +- src/nm-ip6-config.c | 2 +- src/nm-route-manager.c | 21 +++++++++++++-------- src/nm-route-manager.h | 4 ++-- src/tests/test-route-manager.c | 12 ++++++------ 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 0efc30babe..e5fd25df06 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -284,7 +284,7 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_ro g_array_append_vals (routes, route, 1); } - success = nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes); + success = nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE); g_array_unref (routes); if (!success) return FALSE; diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 65cd711bc6..2f3dc3f487 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -398,7 +398,7 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex) g_array_append_vals (routes, route, 1); } - success = nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes); + success = nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE); g_array_unref (routes); } diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index ac8ded374a..5986196fc5 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -345,7 +345,7 @@ _sort_indexes_cmp (guint *a, guint *b) /*********************************************************************************************/ static gboolean -_vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const GArray *known_routes) +_vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes) { NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); GArray *plat_routes; @@ -362,7 +362,10 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const nm_platform_process_events (priv->platform); ipx_routes = vtable->vt->is_ip4 ? &priv->ip4_routes : &priv->ip6_routes; - plat_routes = vtable->vt->route_get_all (priv->platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + plat_routes = vtable->vt->route_get_all (priv->platform, ifindex, + ignore_kernel_routes + ? NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT + : NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL); plat_routes_idx = _route_index_create (vtable, plat_routes); known_routes_idx = _route_index_create (vtable, known_routes); @@ -590,6 +593,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const * nm_route_manager_ip4_route_sync: * @ifindex: Interface index * @known_routes: List of routes + * @ignore_kernel_routes: if %TRUE, ignore kernel routes. * * A convenience function to synchronize routes for a specific interface * with the least possible disturbance. It simply removes routes that are @@ -600,15 +604,16 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const * Returns: %TRUE on success. */ gboolean -nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes) +nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes) { - return _vx_route_sync (&vtable_v4, self, ifindex, known_routes); + return _vx_route_sync (&vtable_v4, self, ifindex, known_routes, ignore_kernel_routes); } /** * nm_route_manager_ip6_route_sync: * @ifindex: Interface index * @known_routes: List of routes + * @ignore_kernel_routes: if %TRUE, ignore kernel routes. * * A convenience function to synchronize routes for a specific interface * with the least possible disturbance. It simply removes routes that are @@ -619,16 +624,16 @@ nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray * Returns: %TRUE on success. */ gboolean -nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes) +nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes) { - return _vx_route_sync (&vtable_v6, self, ifindex, known_routes); + return _vx_route_sync (&vtable_v6, self, ifindex, known_routes, ignore_kernel_routes); } gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex) { - return nm_route_manager_ip4_route_sync (self, ifindex, NULL) - && nm_route_manager_ip6_route_sync (self, ifindex, NULL); + return nm_route_manager_ip4_route_sync (self, ifindex, NULL, TRUE) + && nm_route_manager_ip6_route_sync (self, ifindex, NULL, TRUE); } /*********************************************************************************************/ diff --git a/src/nm-route-manager.h b/src/nm-route-manager.h index 4c66ffcd94..7b2d16f756 100644 --- a/src/nm-route-manager.h +++ b/src/nm-route-manager.h @@ -42,8 +42,8 @@ typedef struct { GType nm_route_manager_get_type (void); -gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes); -gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes); +gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes); +gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes); gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex); NMRouteManager *nm_route_manager_get (void); diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index bcc5f3f1be..6b0a86ca3b 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -61,7 +61,7 @@ setup_dev0_ip4 (int ifindex, guint mss_of_first_route, guint32 metric_of_second_ route.mss = 0; g_array_append_val (routes, route); - nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes); + nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE); g_array_free (routes, TRUE); } @@ -107,7 +107,7 @@ setup_dev1_ip4 (int ifindex) route.metric = 22; g_array_append_val (routes, route); - nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes); + nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE); g_array_free (routes, TRUE); } @@ -134,7 +134,7 @@ update_dev0_ip4 (int ifindex) route.metric = 21; g_array_append_val (routes, route); - nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes); + nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE); g_array_free (routes, TRUE); } @@ -346,7 +346,7 @@ setup_dev0_ip6 (int ifindex) 0); g_array_append_val (routes, *route); - nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes); + nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE); g_array_free (routes, TRUE); } @@ -403,7 +403,7 @@ setup_dev1_ip6 (int ifindex) 0); g_array_append_val (routes, *route); - nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes); + nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE); g_array_free (routes, TRUE); } @@ -450,7 +450,7 @@ update_dev0_ip6 (int ifindex) 0); g_array_append_val (routes, *route); - nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes); + nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE); g_array_free (routes, TRUE); } From accf3d0f17071fc3caca27c3ab3cd8395a1c040a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 24 Jun 2015 12:00:22 +0200 Subject: [PATCH 12/14] platform: properly consider address lifetimes in nm_platform_ip4_address_sync() When checking whether an address from platform should be deleted, we compare the address with our list of @known_addresses. For that we must also check for expired lifetimes, because @known_addresses might contain expired addresses. (cherry picked from commit 8336bd2a83a8a941bd0793a6a8e009e9241d0b64) --- src/platform/nm-platform.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index cdf7cfd4b7..41bc19a0b5 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -39,6 +39,8 @@ #include "nm-enum-types.h" #include "nm-core-internal.h" +#define ADDRESS_LIFETIME_PADDING 5 + G_STATIC_ASSERT (sizeof ( ((NMPlatformLink *) NULL)->addr.data ) == NM_UTILS_HWADDR_LEN_MAX); #define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__) @@ -1948,7 +1950,7 @@ nm_platform_ip6_address_exists (NMPlatform *self, int ifindex, struct in6_addr a } static gboolean -array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address) +array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address, gint64 now, guint32 padding) { guint len = addresses ? addresses->len : 0; guint i; @@ -1956,15 +1958,20 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address for (i = 0; i < len; i++) { NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i); - if (candidate->address == address->address && candidate->plen == address->plen) - return TRUE; + if (candidate->address == address->address && candidate->plen == address->plen) { + guint32 lifetime, preferred; + + if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, + now, padding, &lifetime, &preferred)) + return TRUE; + } } return FALSE; } static gboolean -array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address) +array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address, gint64 now, guint32 padding) { guint len = addresses ? addresses->len : 0; guint i; @@ -1972,8 +1979,13 @@ array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address for (i = 0; i < len; i++) { NMPlatformIP6Address *candidate = &g_array_index (addresses, NMPlatformIP6Address, i); - if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) - return TRUE; + if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) { + guint32 lifetime, preferred; + + if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, + now, padding, &lifetime, &preferred)) + return TRUE; + } } return FALSE; @@ -2027,7 +2039,7 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known for (i = 0; i < addresses->len; i++) { address = &g_array_index (addresses, NMPlatformIP4Address, i); - if (!array_contains_ip4_address (known_addresses, address)) + if (!array_contains_ip4_address (known_addresses, address, now, ADDRESS_LIFETIME_PADDING)) nm_platform_ip4_address_delete (self, ifindex, address->address, address->plen, address->peer_address); } g_array_free (addresses, TRUE); @@ -2042,9 +2054,8 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known guint32 network; gboolean reinstall_device_route = FALSE; - /* add a padding of 5 seconds to avoid potential races. */ if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, - now, 5, &lifetime, &preferred)) + now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred)) continue; if (nm_platform_ip4_check_reinstall_device_route (self, ifindex, known_address, device_route_metric)) @@ -2103,7 +2114,7 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address)) continue; - if (!array_contains_ip6_address (known_addresses, address)) + if (!array_contains_ip6_address (known_addresses, address, now, ADDRESS_LIFETIME_PADDING)) nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen); } g_array_free (addresses, TRUE); @@ -2116,9 +2127,8 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known const NMPlatformIP6Address *known_address = &g_array_index (known_addresses, NMPlatformIP6Address, i); guint32 lifetime, preferred; - /* add a padding of 5 seconds to avoid potential races. */ if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, - now, 5, &lifetime, &preferred)) + now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred)) continue; if (!nm_platform_ip6_address_add (self, ifindex, known_address->address, From 4f161e4beaf0062451efc4e436565242977af2bd Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 24 Jun 2015 12:26:17 +0200 Subject: [PATCH 13/14] route-manager: consider also 'proto kernel' routes during route_flush() (cherry picked from commit a96cba8845534ed076e00509fe9c47b9c16c1c0e) --- src/nm-route-manager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 5986196fc5..a6763a2f83 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -632,8 +632,8 @@ nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex) { - return nm_route_manager_ip4_route_sync (self, ifindex, NULL, TRUE) - && nm_route_manager_ip6_route_sync (self, ifindex, NULL, TRUE); + return nm_route_manager_ip4_route_sync (self, ifindex, NULL, FALSE) + && nm_route_manager_ip6_route_sync (self, ifindex, NULL, FALSE); } /*********************************************************************************************/ From 42ac15c86f10c66bdfd317ca6bd42ec61d8405d4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2015 18:21:53 +0200 Subject: [PATCH 14/14] route-manager: manage IPv4 device-routes with NMRouteManager When adding an IPv4 address, kernel will also add a device-route. We don't want that route because it has the wrong metric. Instead, we add our own route (with a different metric) and remove the kernel-added one. This could be avoided if kernel would support an IPv4 address flag IFA_F_NOPREFIXROUTE like it does for IPv6 (see related bug rh#1221311). One important thing is, that we want don't want to manage the device-route on assumed devices. Note that this is correct behavior if "assumed" means "do-not-touch". If "assumed" means "seamlessly-takeover", then this is wrong. Imagine we get a new DHCP address. In this case, we would not manage the device-route on the assumed device. This cannot be fixed without splitting unmanaged/assumed with related bug bgo 746440. This is no regression as we would also not manage device-routes for assumed devices previously. We also don't want to remove the device-route if the user added it externally. Note that here we behave wrongly too, because we don't record externally added kernel routes in update_ip_config(). This still needs fixing. Let IPv4 device-routes also be managed by NMRouteManager. NMRouteManager has a list of all routes and can properly add, remove, and restore the device route as needed. One problem is, that the device-route does not get added immediately with the address. It only appears some time later. This is solved by NMRouteManager watching platform and if a matchin device-route shows up within a short time after configuring addresses, remove it. If the route appears after the short timeout, assume they were added for other reasons (e.g. by the user) and don't remove them. https://bugzilla.gnome.org/show_bug.cgi?id=751264 https://bugzilla.redhat.com/show_bug.cgi?id=1211287 (cherry picked from commit 5f54a323d10d2907c6cb5cdcfe223e3cff33b317) --- src/devices/nm-device.c | 12 +- src/nm-ip4-config.c | 47 +++++- src/nm-ip4-config.h | 2 +- src/nm-route-manager.c | 244 +++++++++++++++++++++++++++++++ src/nm-route-manager.h | 2 + src/platform/nm-fake-platform.c | 8 - src/platform/nm-linux-platform.c | 60 -------- src/platform/nm-platform.c | 57 ++------ src/platform/nm-platform.h | 6 +- 9 files changed, 314 insertions(+), 124 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 3d0bd936aa..ab105b5a7a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -6332,10 +6332,11 @@ nm_device_set_ip4_config (NMDevice *self, nm_device_set_mtu (self, nm_ip4_config_get_mtu (new_config)); - /* for assumed devices we set the device_route_metric to the default which will - * stop nm_platform_ip4_address_sync() to replace the device routes. */ + /* For assumed devices we must not touch the kernel-routes, such as the device-route. + * FIXME: this is wrong in case where "assumed" means "take-over-seamlessly". In this + * case, we should manage the device route, for example on new DHCP lease. */ success = nm_ip4_config_commit (new_config, ip_ifindex, - assumed ? NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE : default_route_metric); + assumed ? (gint64) -1 : (gint64) default_route_metric); if (!success) reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED; } @@ -7133,6 +7134,11 @@ update_ip4_config (NMDevice *self, gboolean initial) capture_lease_config (self, priv->ext_ip4_config, &priv->dev_ip4_config, NULL, NULL); } + /* FIXME: ext_ip4_config does not contain routes with source==RTPROT_KERNEL. + * Hence, we will wrongly remove device-routes with metric=0 if they were added by + * the user on purpose. This should be fixed by also tracking and exposing + * kernel routes. */ + /* This function was called upon external changes. Remove the configuration * (adresses,routes) that is no longer present externally from the interal * config. This way, we don't readd addresses that were manually removed diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index e5fd25df06..e32f750395 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -34,6 +34,7 @@ #include "NetworkManagerUtils.h" #include "nm-core-internal.h" #include "nm-route-manager.h" +#include "gsystem-local-alloc.h" G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT) @@ -253,25 +254,59 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) } gboolean -nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_route_metric) +nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gint64 default_route_metric) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); int i; + gs_unref_ptrarray GPtrArray *added_addresses = NULL; g_return_val_if_fail (ifindex > 0, FALSE); g_return_val_if_fail (config != NULL, FALSE); /* Addresses */ - nm_platform_ip4_address_sync (NM_PLATFORM_GET, ifindex, priv->addresses, default_route_metric); + nm_platform_ip4_address_sync (NM_PLATFORM_GET, ifindex, priv->addresses, + default_route_metric >= 0 ? &added_addresses : NULL); /* Routes */ { int count = nm_ip4_config_get_num_routes (config); GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), count); - const NMPlatformIP4Route *route; gboolean success; + gs_unref_array GArray *device_route_purge_list = NULL; + + if ( default_route_metric >= 0 + && added_addresses) { + /* For IPv6, we explicitly add the device-routes (onlink) to NMIP6Config. + * As we don't do that for IPv4, add it here shortly before syncing + * the routes. For NMRouteManager these routes are very much important. */ + for (i = 0; i < added_addresses->len; i++) { + const NMPlatformIP4Address *addr = added_addresses->pdata[i]; + NMPlatformIP4Route route = { 0 }; + + if (addr->plen == 0) + continue; + + route.ifindex = ifindex; + route.source = NM_IP_CONFIG_SOURCE_KERNEL; + route.network = nm_utils_ip4_address_clear_host_address (addr->address, addr->plen); + route.plen = addr->plen; + route.pref_src = addr->address; + route.metric = default_route_metric; + + g_array_append_val (routes, route); + + if (default_route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) { + if (!device_route_purge_list) + device_route_purge_list = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route)); + route.metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE; + g_array_append_val (device_route_purge_list, route); + } + } + } for (i = 0; i < count; i++) { + const NMPlatformIP4Route *route; + route = nm_ip4_config_get_route (config, i); /* Don't add the route if it's more specific than one of the subnets @@ -281,10 +316,14 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_ro && nm_ip4_config_destination_is_direct (config, route->network, route->plen)) continue; + /* duplicates in @routes are no problem as route-manager handles them + * gracefully (by ignoring them). */ g_array_append_vals (routes, route, 1); } - success = nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE); + nm_route_manager_ip4_route_register_device_route_purge_list (nm_route_manager_get (), device_route_purge_list); + + success = nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, default_route_metric < 0); g_array_unref (routes); if (!success) return FALSE; diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 2b3b24e6af..cd6efcc5c5 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -64,7 +64,7 @@ const char * nm_ip4_config_get_dbus_path (const NMIP4Config *config); /* Integration with nm-platform and nm-setting */ NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf); -gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_route_metric); +gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gint64 default_route_metric); void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric); NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config); diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index a6763a2f83..403d9e7a2f 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -24,10 +24,18 @@ #include "nm-route-manager.h" #include "nm-platform.h" +#include "nmp-object.h" +#include "nm-core-internal.h" #include "nm-logging.h" #include "gsystem-local-alloc.h" #include "NetworkManagerUtils.h" +/* if within half a second after adding an IP address a matching device-route shows + * up, we delete it. */ +#define IP4_DEVICE_ROUTES_WAIT_TIME_NS (NM_UTILS_NS_PER_SECOND / 2) + +#define IP4_DEVICE_ROUTES_GC_INTERVAL_SEC (IP4_DEVICE_ROUTES_WAIT_TIME_NS * 2) + typedef struct { guint len; NMPlatformIPXRoute *entries[1]; @@ -38,11 +46,22 @@ typedef struct { RouteIndex *index; } RouteEntries; +typedef struct { + NMRouteManager *self; + gint64 scheduled_at_ns; + guint idle_id; + NMPObject *obj; +} IP4DeviceRoutePurgeEntry; + typedef struct { NMPlatform *platform; RouteEntries ip4_routes; RouteEntries ip6_routes; + struct { + GHashTable *entries; + guint gc_id; + } ip4_device_routes; } NMRouteManagerPrivate; #define NM_ROUTE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ROUTE_MANAGER, NMRouteManagerPrivate)) @@ -125,6 +144,10 @@ static const VTableIP vtable_v4, vtable_v6; /*********************************************************************************************/ +static gboolean _ip4_device_routes_cancel (NMRouteManager *self); + +/*********************************************************************************************/ + #if defined (NM_MORE_ASSERTS) && !defined (G_DISABLE_ASSERT) inline static void ASSERT_route_index_valid (const VTableIP *vtable, const GArray *entries, const RouteIndex *index, gboolean unique_ifindexes) @@ -234,6 +257,41 @@ _route_index_create (const VTableIP *vtable, const GArray *routes) return index; } +static int +_vx_route_id_cmp_full (const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2, const VTableIP *vtable) +{ + return vtable->route_id_cmp (r1, r2); +} + +static gssize +_route_index_find (const VTableIP *vtable, const RouteIndex *index, const NMPlatformIPXRoute *needle) +{ + gssize idx, idx2; + + idx = _nm_utils_ptrarray_find_binary_search ((gpointer *) index->entries, index->len, (gpointer) needle, (GCompareDataFunc) _vx_route_id_cmp_full, (gpointer) vtable); + if (idx < 0) + return idx; + + /* we only know that the route at index @idx has matching destination. Also find the one with the right + * ifindex by searching the neighbours */ + + idx2 = idx; + do { + if (index->entries[idx2]->rx.ifindex == needle->rx.ifindex) + return idx2; + } while ( idx2 > 0 + && vtable->route_id_cmp (index->entries[--idx2], needle) != 0); + + for (idx++; idx < index->len; idx++ ){ + if (vtable->route_id_cmp (index->entries[idx], needle) != 0) + break; + if (index->entries[idx]->rx.ifindex == needle->rx.ifindex) + return idx; + } + + return ~idx; +} + static guint _route_index_reverse_idx (const VTableIP *vtable, const RouteIndex *index, guint idx_idx, const GArray *routes) { @@ -638,6 +696,182 @@ nm_route_manager_route_flush (NMRouteManager *self, int ifindex) /*********************************************************************************************/ +static gboolean +_ip4_device_routes_entry_expired (const IP4DeviceRoutePurgeEntry *entry, gint64 now) +{ + return entry->scheduled_at_ns + IP4_DEVICE_ROUTES_WAIT_TIME_NS < now; +} + +static IP4DeviceRoutePurgeEntry * +_ip4_device_routes_purge_entry_create (NMRouteManager *self, const NMPlatformIP4Route *route, gint64 now_ns) +{ + IP4DeviceRoutePurgeEntry *entry; + + entry = g_slice_new (IP4DeviceRoutePurgeEntry); + + entry->self = self; + entry->scheduled_at_ns = now_ns; + entry->idle_id = 0; + entry->obj = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, (NMPlatformObject *) route); + return entry; +} + +static void +_ip4_device_routes_purge_entry_free (IP4DeviceRoutePurgeEntry *entry) +{ + nmp_object_unref (entry->obj); + nm_clear_g_source (&entry->idle_id); + g_slice_free (IP4DeviceRoutePurgeEntry, entry); +} + +static gboolean +_ip4_device_routes_idle_cb (IP4DeviceRoutePurgeEntry *entry) +{ + NMRouteManager *self; + NMRouteManagerPrivate *priv; + + nm_clear_g_source (&entry->idle_id); + + self = entry->self; + priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); + if (_route_index_find (&vtable_v4, priv->ip4_routes.index, &entry->obj->ipx_route) >= 0) { + /* we have an identical route in our list. Don't delete it. */ + return G_SOURCE_REMOVE; + } + + _LOGT (vtable_v4.vt->addr_family, "device-route: delete %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); + + nm_platform_ip4_route_delete (priv->platform, + entry->obj->ip4_route.ifindex, + entry->obj->ip4_route.network, + entry->obj->ip4_route.plen, + entry->obj->ip4_route.metric); + + g_hash_table_remove (priv->ip4_device_routes.entries, entry->obj); + _ip4_device_routes_cancel (self); + return G_SOURCE_REMOVE; +} + +static void +_ip4_device_routes_ip4_route_changed (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex, + const NMPlatformIP4Route *route, + NMPlatformSignalChangeType change_type, + NMPlatformReason reason, + NMRouteManager *self) +{ + NMRouteManagerPrivate *priv; + NMPObject obj_needle; + IP4DeviceRoutePurgeEntry *entry; + + if (change_type == NM_PLATFORM_SIGNAL_REMOVED) + return; + + if ( route->source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL + || route->metric != 0) { + /* we don't have an automatically created device route at hand. Bail out early. */ + return; + } + + priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); + + entry = g_hash_table_lookup (priv->ip4_device_routes.entries, + nmp_object_stackinit (&obj_needle, NMP_OBJECT_TYPE_IP4_ROUTE, (NMPlatformObject *) route)); + if (!entry) + return; + + if (_ip4_device_routes_entry_expired (entry, nm_utils_get_monotonic_timestamp_ns ())) { + _LOGT (vtable_v4.vt->addr_family, "device-route: cleanup-ch %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); + g_hash_table_remove (priv->ip4_device_routes.entries, entry->obj); + _ip4_device_routes_cancel (self); + return; + } + + if (entry->idle_id == 0) { + _LOGT (vtable_v4.vt->addr_family, "device-route: schedule %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); + entry->idle_id = g_idle_add ((GSourceFunc) _ip4_device_routes_idle_cb, entry); + } +} + +static gboolean +_ip4_device_routes_cancel (NMRouteManager *self) +{ + NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); + + if (priv->ip4_device_routes.gc_id) { + if (g_hash_table_size (priv->ip4_device_routes.entries) > 0) + return G_SOURCE_CONTINUE; + _LOGT (vtable_v4.vt->addr_family, "device-route: cancel"); + if (priv->platform) + g_signal_handlers_disconnect_by_func (priv->platform, G_CALLBACK (_ip4_device_routes_ip4_route_changed), self); + nm_clear_g_source (&priv->ip4_device_routes.gc_id); + } + return G_SOURCE_REMOVE; +} + +static gboolean +_ip4_device_routes_gc (NMRouteManager *self) +{ + NMRouteManagerPrivate *priv; + GHashTableIter iter; + IP4DeviceRoutePurgeEntry *entry; + gint64 now = nm_utils_get_monotonic_timestamp_ns (); + + priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); + + g_hash_table_iter_init (&iter, priv->ip4_device_routes.entries); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry)) { + if (_ip4_device_routes_entry_expired (entry, now)) { + _LOGT (vtable_v4.vt->addr_family, "device-route: cleanup-gc %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); + g_hash_table_iter_remove (&iter); + } + } + + return _ip4_device_routes_cancel (self); +} + +/** + * nm_route_manager_ip4_route_register_device_route_purge_list: + * + * When adding an IPv4 address, kernel will automatically add a device route with + * metric zero. We don't want that route and want to delete it. However, the route + * by kernel immediately, but some time after. That means during nm_route_manager_ip4_route_sync() + * such a route doesn't exist yet. We must remember that we expect such a route to appear later + * and to remove it. */ +void +nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *self, GArray *device_route_purge_list) +{ + NMRouteManagerPrivate *priv; + guint i; + gint64 now_ns; + + if (!device_route_purge_list || device_route_purge_list->len == 0) + return; + + priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); + + now_ns = nm_utils_get_monotonic_timestamp_ns (); + for (i = 0; i < device_route_purge_list->len; i++) { + IP4DeviceRoutePurgeEntry *entry; + + entry = _ip4_device_routes_purge_entry_create (self, &g_array_index (device_route_purge_list, NMPlatformIP4Route, i), now_ns); + _LOGT (vtable_v4.vt->addr_family, "device-route: watch (%s) %s", + g_hash_table_contains (priv->ip4_device_routes.entries, entry->obj) + ? "update" : "new", + nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); + g_hash_table_replace (priv->ip4_device_routes.entries, + nmp_object_ref (entry->obj), + entry); + } + if (priv->ip4_device_routes.gc_id == 0) { + g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_ip4_device_routes_ip4_route_changed), self); + priv->ip4_device_routes.gc_id = g_timeout_add (IP4_DEVICE_ROUTES_GC_INTERVAL_SEC, (GSourceFunc) _ip4_device_routes_gc, self); + } +} + +/*********************************************************************************************/ + static const VTableIP vtable_v4 = { .vt = &nm_platform_vtable_route_v4, .route_id_cmp = (int (*) (const NMPlatformIPXRoute *, const NMPlatformIPXRoute *)) _v4_route_id_cmp, @@ -661,13 +895,21 @@ nm_route_manager_init (NMRouteManager *self) priv->ip6_routes.entries = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route)); priv->ip4_routes.index = _route_index_create (&vtable_v4, priv->ip4_routes.entries); priv->ip6_routes.index = _route_index_create (&vtable_v6, priv->ip6_routes.entries); + priv->ip4_device_routes.entries = g_hash_table_new_full ((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal, + (GDestroyNotify) nmp_object_unref, + (GDestroyNotify) _ip4_device_routes_purge_entry_free); } static void dispose (GObject *object) { + NMRouteManager *self = NM_ROUTE_MANAGER (object); NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (object); + g_hash_table_remove_all (priv->ip4_device_routes.entries); + _ip4_device_routes_cancel (self); + g_clear_object (&priv->platform); G_OBJECT_CLASS (nm_route_manager_parent_class)->dispose (object); @@ -683,6 +925,8 @@ finalize (GObject *object) g_free (priv->ip4_routes.index); g_free (priv->ip6_routes.index); + g_hash_table_unref (priv->ip4_device_routes.entries); + G_OBJECT_CLASS (nm_route_manager_parent_class)->finalize (object); } diff --git a/src/nm-route-manager.h b/src/nm-route-manager.h index 7b2d16f756..fdd310b73b 100644 --- a/src/nm-route-manager.h +++ b/src/nm-route-manager.h @@ -46,6 +46,8 @@ gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, con gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes); gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex); +void nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *self, GArray *device_route_purge_list); + NMRouteManager *nm_route_manager_get (void); #endif /* NM_ROUTE_MANAGER_H */ diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 37bec90884..147e956167 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -1025,12 +1025,6 @@ ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int return FALSE; } -static gboolean -ip4_check_reinstall_device_route (NMPlatform *platform, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric) -{ - return FALSE; -} - /******************************************************************/ static GArray * @@ -1468,8 +1462,6 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->ip4_address_exists = ip4_address_exists; platform_class->ip6_address_exists = ip6_address_exists; - platform_class->ip4_check_reinstall_device_route = ip4_check_reinstall_device_route; - platform_class->ip4_route_get_all = ip4_route_get_all; platform_class->ip6_route_get_all = ip6_route_get_all; platform_class->ip4_route_add = ip4_route_add; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index a993d3fe1d..7d457fe4eb 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4182,64 +4182,6 @@ ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int return nmp_object_is_visible (nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle)); } -static gboolean -ip4_check_reinstall_device_route (NMPlatform *platform, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - guint32 device_network; - NMPObject obj_needle; - const NMPlatformIP4Address *const *addresses; - const NMPlatformIP4Route *const *routes; - - device_network = nm_utils_ip4_address_clear_host_address (address->address, address->plen); - - /* in many cases we expect the route to already exist. So first do an exact lookup - * to save the O(n) access below. */ - nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, device_network, address->plen, device_route_metric); - if (nmp_cache_lookup_obj (priv->cache, &obj_needle)) { - /* There is already a route with metric 0 or the metric we want to install - * for the same subnet. */ - return FALSE; - } - if (obj_needle.ip4_route.metric != 0) { - obj_needle.ip4_route.metric = 0; - if (nmp_cache_lookup_obj (priv->cache, &obj_needle)) - return FALSE; - } - - /* also check whether we already have the same address configured on *any* device. */ - addresses = cache_lookup_all_objects (NMPlatformIP4Address, platform, NMP_OBJECT_TYPE_IP4_ADDRESS, FALSE); - if (addresses) { - for (; *addresses; addresses++) { - const NMPlatformIP4Address *addr_candidate = *addresses; - - if ( addr_candidate->plen == address->plen - && addr_candidate->address == device_network) { - /* If we already have the same address installed on any interface, - * we back off. */ - return FALSE; - } - } - } - - routes = cache_lookup_all_objects (NMPlatformIP4Route, platform, NMP_OBJECT_TYPE_IP4_ROUTE, FALSE); - if (routes) { - for (; *routes; routes++) { - const NMPlatformIP4Route *route_candidate = *routes; - - if ( route_candidate->network == device_network - && route_candidate->plen == address->plen - && (route_candidate->metric == 0 || route_candidate->metric == device_route_metric)) { - /* If we already have the same address installed on any interface, - * we back off. */ - return FALSE; - } - } - } - - return TRUE; -} - /******************************************************************/ static GArray * @@ -5053,8 +4995,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->ip4_address_exists = ip4_address_exists; platform_class->ip6_address_exists = ip6_address_exists; - platform_class->ip4_check_reinstall_device_route = ip4_check_reinstall_device_route; - platform_class->ip4_route_get_all = ip4_route_get_all; platform_class->ip6_route_get_all = ip6_route_get_all; platform_class->ip4_route_add = ip4_route_add; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 41bc19a0b5..6faad3b2ce 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1991,32 +1991,15 @@ array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address return FALSE; } -gboolean -nm_platform_ip4_check_reinstall_device_route (NMPlatform *self, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric) -{ - _CHECK_SELF (self, klass, FALSE); - - if ( ifindex <= 0 - || address->plen <= 0 - || address->plen >= 32) - return FALSE; - - if (device_route_metric == NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) { - /* The automatically added route would be already our desired priority. - * Nothing to do. */ - return FALSE; - } - - return klass->ip4_check_reinstall_device_route (self, ifindex, address, device_route_metric); -} - /** * nm_platform_ip4_address_sync: * @self: platform instance * @ifindex: Interface index * @known_addresses: List of addresses - * @device_route_metric: the route metric for adding subnet routes (replaces - * the kernel added routes). + * @out_added_addresses: (out): (allow-none): if not %NULL, return a #GPtrArray + * with the addresses added. The pointers point into @known_addresses. + * It possibly does not contain all addresses from @known_address because + * some addresses might be expired. * * A convenience function to synchronize addresses for a specific interface * with the least possible disturbance. It simply removes addresses that are @@ -2025,7 +2008,7 @@ nm_platform_ip4_check_reinstall_device_route (NMPlatform *self, int ifindex, con * Returns: %TRUE on success. */ gboolean -nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, guint32 device_route_metric) +nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, GPtrArray **out_added_addresses) { GArray *addresses; NMPlatformIP4Address *address; @@ -2044,6 +2027,9 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known } g_array_free (addresses, TRUE); + if (out_added_addresses) + *out_added_addresses = NULL; + if (!known_addresses) return TRUE; @@ -2051,33 +2037,18 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known for (i = 0; i < known_addresses->len; i++) { const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i); guint32 lifetime, preferred; - guint32 network; - gboolean reinstall_device_route = FALSE; if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred)) continue; - if (nm_platform_ip4_check_reinstall_device_route (self, ifindex, known_address, device_route_metric)) - reinstall_device_route = TRUE; - if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label)) return FALSE; - if (reinstall_device_route) { - /* Kernel automatically adds a device route for us with metric 0. That is not what we want. - * Remove it, and re-add it. - * - * In face of having the same subnets on two different interfaces with the same metric, - * this is a problem. Surprisingly, kernel is able to add two routes for the same subnet/prefix,metric - * to different interfaces. We cannot. Adding one, would replace the other. This is avoided - * by the above nm_platform_ip4_check_reinstall_device_route() check. - */ - network = nm_utils_ip4_address_clear_host_address (known_address->address, known_address->plen); - (void) nm_platform_ip4_route_add (self, ifindex, NM_IP_CONFIG_SOURCE_KERNEL, network, known_address->plen, - 0, known_address->address, device_route_metric, 0); - (void) nm_platform_ip4_route_delete (self, ifindex, network, known_address->plen, - NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE); + if (out_added_addresses) { + if (!*out_added_addresses) + *out_added_addresses = g_ptr_array_new (); + g_ptr_array_add (*out_added_addresses, (gpointer) known_address); } } @@ -2145,8 +2116,8 @@ nm_platform_address_flush (NMPlatform *self, int ifindex) { _CHECK_SELF (self, klass, FALSE); - return nm_platform_ip4_address_sync (self, ifindex, NULL, 0) - && nm_platform_ip6_address_sync (self, ifindex, NULL, FALSE); + return nm_platform_ip4_address_sync (self, ifindex, NULL, NULL) + && nm_platform_ip6_address_sync (self, ifindex, NULL, FALSE); } /******************************************************************/ diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index e6305c325e..a8bc5a43b2 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -520,8 +520,6 @@ typedef struct { gboolean (*ip4_address_exists) (NMPlatform *, int ifindex, in_addr_t address, int plen); gboolean (*ip6_address_exists) (NMPlatform *, int ifindex, struct in6_addr address, int plen); - gboolean (*ip4_check_reinstall_device_route) (NMPlatform *, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric); - GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, @@ -706,12 +704,10 @@ gboolean nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_ gboolean nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, int plen); gboolean nm_platform_ip4_address_exists (NMPlatform *self, int ifindex, in_addr_t address, int plen); gboolean nm_platform_ip6_address_exists (NMPlatform *self, int ifindex, struct in6_addr address, int plen); -gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, guint32 device_route_metric); +gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, GPtrArray **out_added_addresses); gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, gboolean keep_link_local); gboolean nm_platform_address_flush (NMPlatform *self, int ifindex); -gboolean nm_platform_ip4_check_reinstall_device_route (NMPlatform *self, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric); - GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); gboolean nm_platform_ip4_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source,