diff options
author | Thomas Haller <thaller@redhat.com> | 2015-07-01 16:05:41 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-07-01 16:06:36 +0200 |
commit | 1749ad4068b27ab3955b35128c833096e7c195e4 (patch) | |
tree | 74efbca22ea2923d88fbada23a90d5d03b44f99a | |
parent | 871c4d90c7cfcb291874fbabcff000d0d2a691b2 (diff) | |
parent | 5f54a323d10d2907c6cb5cdcfe223e3cff33b317 (diff) | |
download | NetworkManager-1749ad4068b27ab3955b35128c833096e7c195e4.tar.gz |
core: merge branch 'th/device-route-bgo751264'
Several fixes to route and address handling in platform.
Especially refactor managing of IPv4 device routes and
let NMRouteManager handle them.
https://bugzilla.gnome.org/show_bug.cgi?id=751264
https://bugzilla.redhat.com/show_bug.cgi?id=1211287
-rw-r--r-- | libnm-core/nm-core-internal.h | 2 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 33 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 105 | ||||
-rw-r--r-- | src/devices/nm-device.c | 16 | ||||
-rw-r--r-- | src/nm-default-route-manager.c | 4 | ||||
-rw-r--r-- | src/nm-ip4-config.c | 56 | ||||
-rw-r--r-- | src/nm-ip4-config.h | 2 | ||||
-rw-r--r-- | src/nm-ip6-config.c | 11 | ||||
-rw-r--r-- | src/nm-route-manager.c | 288 | ||||
-rw-r--r-- | src/nm-route-manager.h | 6 | ||||
-rw-r--r-- | src/nm-types.h | 4 | ||||
-rw-r--r-- | src/platform/nm-fake-platform.c | 30 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 155 | ||||
-rw-r--r-- | src/platform/nm-platform-utils.c | 88 | ||||
-rw-r--r-- | src/platform/nm-platform-utils.h | 12 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 198 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 36 | ||||
-rw-r--r-- | src/platform/nmp-object.c | 2 | ||||
-rw-r--r-- | src/platform/tests/dump.c | 4 | ||||
-rw-r--r-- | src/platform/tests/platform.c | 4 | ||||
-rw-r--r-- | src/platform/tests/test-cleanup.c | 8 | ||||
-rw-r--r-- | src/platform/tests/test-route.c | 4 | ||||
-rw-r--r-- | src/tests/test-route-manager.c | 20 |
23 files changed, 761 insertions, 327 deletions
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 27288df022..f9ae42ecdd 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -114,6 +114,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 8ce59b0eeb..f9325e2a47 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 2f330357d6..082015c040 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -4484,6 +4484,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) @@ -4587,6 +4691,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); g_test_add_func ("/core/general/_nm_utils_dns_option_validate", test_nm_utils_dns_option_validate); g_test_add_func ("/core/general/_nm_utils_dns_option_find_idx", test_nm_utils_dns_option_find_idx); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 9a70bc6f53..a317ca6ac8 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3114,9 +3114,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; @@ -6345,10 +6345,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; } @@ -7174,6 +7175,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 * (addresses,routes) that is no longer present externally from the internal * config. This way, we don't re-add addresses that were manually removed 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 a3ef072b90..c811e24d34 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -35,6 +35,7 @@ #include "nm-core-internal.h" #include "nm-route-manager.h" #include "nm-core-internal.h" +#include "gsystem-local-alloc.h" G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT) @@ -229,11 +230,11 @@ 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; - 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)) { @@ -243,9 +244,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++; } /* we detect the route metric based on the default route. All non-default @@ -288,25 +290,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 @@ -316,10 +352,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); + 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 69880c1322..0088934a45 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -71,7 +71,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-ip6-config.c b/src/nm-ip6-config.c index dcb318b7e3..082f1d2db7 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -342,11 +342,11 @@ 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; - 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)) { @@ -356,9 +356,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++; } /* we detect the route metric based on the default route. All non-default @@ -436,7 +437,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 3e1d5b5bd8..5afce85489 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]; @@ -39,8 +47,21 @@ typedef struct { } 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)) @@ -123,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) @@ -232,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) { @@ -343,7 +403,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; @@ -357,8 +417,13 @@ _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 (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_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); @@ -494,7 +559,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 +580,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 (priv->platform, 0, rest_route); } } g_array_unref (to_restore_routes); @@ -559,7 +624,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 (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", @@ -586,6 +651,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 @@ -596,15 +662,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 @@ -615,16 +682,192 @@ 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, FALSE) + && nm_route_manager_ip6_route_sync (self, ifindex, NULL, FALSE); +} + +/*********************************************************************************************/ + +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); + } } /*********************************************************************************************/ @@ -646,10 +889,30 @@ 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); + 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); } static void @@ -662,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); } @@ -673,5 +938,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; } diff --git a/src/nm-route-manager.h b/src/nm-route-manager.h index 4c66ffcd94..fdd310b73b 100644 --- a/src/nm-route-manager.h +++ b/src/nm-route-manager.h @@ -42,10 +42,12 @@ 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); +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/nm-types.h b/src/nm-types.h index 426aba5a27..530f9f7b5b 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -55,8 +55,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-fake-platform.c b/src/platform/nm-fake-platform.c index 96fd17b716..147e956167 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -1025,35 +1025,30 @@ 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 * -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 +1058,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); } } @@ -1466,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 4f12596bd0..9642484513 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: @@ -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; } @@ -4022,13 +4031,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); } @@ -4057,6 +4062,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, @@ -4064,8 +4073,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); } @@ -4074,6 +4083,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, @@ -4081,8 +4094,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); } @@ -4168,103 +4181,57 @@ 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) +/******************************************************************/ + +static GArray * +ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags) { 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; - } + NMPCacheId cache_id; + const NMPlatformIPRoute *const* routes; + GArray *array; + const NMPClass *klass; + gboolean with_rtprot_kernel; + guint i, len; - /* 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; - } - } - } + nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - 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; - } - } - } + 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 TRUE; -} + 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); -static GArray * -ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteMode mode) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - gboolean with_default = FALSE, with_non_default = FALSE; + routes = (const NMPlatformIPRoute *const*) nmp_cache_lookup_multi (priv->cache, &cache_id, &len); - nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); + array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, len); - 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); + 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); - 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, - ifindex)); + 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 * -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 @@ -4341,7 +4308,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); } @@ -5027,8 +4994,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-utils.c b/src/platform/nm-platform-utils.c index 407b91fbcc..02773512c8 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -347,4 +347,92 @@ 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 { + 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) { + *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; + *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 dddc7219f1..911b4516d2 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -33,11 +33,14 @@ #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" #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__) @@ -1953,7 +1956,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; @@ -1961,15 +1964,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; @@ -1977,100 +1985,16 @@ 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; - } - - 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; -} + if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) { + guint32 lifetime, preferred; -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; + if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, + now, padding, &lifetime, &preferred)) + return TRUE; + } } - return klass->ip4_check_reinstall_device_route (self, ifindex, address, device_route_metric); + return FALSE; } /** @@ -2078,8 +2002,10 @@ nm_platform_ip4_check_reinstall_device_route (NMPlatform *self, int ifindex, con * @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 @@ -2088,7 +2014,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; @@ -2102,11 +2028,14 @@ 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); + if (out_added_addresses) + *out_added_addresses = NULL; + if (!known_addresses) return TRUE; @@ -2114,33 +2043,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; - /* 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, 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); } } @@ -2177,7 +2091,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); @@ -2190,8 +2104,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 (!_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, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred)) continue; if (!nm_platform_ip6_address_add (self, ifindex, known_address->address, @@ -2208,32 +2122,30 @@ 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); } /******************************************************************/ 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 @@ -2250,7 +2162,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; @@ -2259,11 +2170,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); } @@ -2351,7 +2260,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"; @@ -2386,7 +2295,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; } @@ -2668,6 +2577,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]; @@ -2686,6 +2596,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, @@ -2694,7 +2605,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; } @@ -2873,6 +2786,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; } @@ -2995,7 +2909,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, @@ -3003,13 +2917,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 4896783078..a8a6caa6fd 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -151,10 +151,16 @@ 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), + + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL = (1LL << 2), +} NMPlatformGetRouteFlags; typedef struct { __NMPlatformObject_COMMON; @@ -276,6 +282,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)); @@ -304,8 +314,8 @@ 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); - gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src); + 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); guint32 (*metric_normalize) (guint32 metric); @@ -511,10 +521,8 @@ 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, 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); @@ -697,14 +705,12 @@ 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, 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/nmp-object.c b/src/platform/nmp-object.c index 77e7b15b99..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; } /******************************************************************/ 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 60199c523f..d62ffea33d 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); } @@ -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); @@ -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); } @@ -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); |