diff options
-rw-r--r-- | shared/nm-test-utils.h | 39 | ||||
-rw-r--r-- | src/devices/tests/Makefile.am | 3 | ||||
-rw-r--r-- | src/nm-default-route-manager.c | 40 | ||||
-rw-r--r-- | src/nm-route-manager.c | 26 | ||||
-rw-r--r-- | src/platform/nm-fake-platform.c | 268 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 243 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 408 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 100 | ||||
-rw-r--r-- | src/platform/nmp-object.c | 59 | ||||
-rw-r--r-- | src/platform/nmp-object.h | 4 | ||||
-rw-r--r-- | src/platform/tests/test-cleanup.c | 33 | ||||
-rw-r--r-- | src/platform/tests/test-common.c | 414 | ||||
-rw-r--r-- | src/platform/tests/test-common.h | 70 | ||||
-rw-r--r-- | src/platform/tests/test-link.c | 187 | ||||
-rw-r--r-- | src/platform/tests/test-route.c | 200 | ||||
-rw-r--r-- | src/tests/test-route-manager.c | 126 |
16 files changed, 1530 insertions, 690 deletions
diff --git a/shared/nm-test-utils.h b/shared/nm-test-utils.h index 0875518cdd..e044ae59ac 100644 --- a/shared/nm-test-utils.h +++ b/shared/nm-test-utils.h @@ -1177,6 +1177,13 @@ _nmtst_assert_resolve_relative_path_equals (const char *f1, const char *f2, cons #ifdef __NETWORKMANAGER_PLATFORM_H__ +#define nmtst_ip4_address_to_ptr(addr) \ + ({ \ + guint32 *__addr = g_alloca (sizeof (guint32)); \ + *__addr = (addr); \ + (const NMIPAddr *) __addr; \ + }) + inline static NMPlatformIP4Address * nmtst_platform_ip4_address (const char *address, const char *peer_address, guint plen) { @@ -1251,7 +1258,9 @@ nmtst_platform_ip6_address_full (const char *address, const char *peer_address, } inline static NMPlatformIP4Route * -nmtst_platform_ip4_route (const char *network, guint plen, const char *gateway) +nmtst_platform_ip4_route (const char *network, + guint8 plen, + const char *gateway) { static NMPlatformIP4Route route; @@ -1266,10 +1275,15 @@ nmtst_platform_ip4_route (const char *network, guint plen, const char *gateway) } inline static NMPlatformIP4Route * -nmtst_platform_ip4_route_full (const char *network, guint plen, const char *gateway, - int ifindex, NMIPConfigSource source, - guint metric, guint mss, +nmtst_platform_ip4_route_full (int ifindex, + const char *network, + guint8 plen, + const char *gateway, + NMIPConfigSource source, + guint32 metric, + guint32 mss, guint8 scope, + bool scope_is_set, const char *pref_src) { NMPlatformIP4Route *route = nmtst_platform_ip4_route (network, plen, gateway); @@ -1278,14 +1292,17 @@ nmtst_platform_ip4_route_full (const char *network, guint plen, const char *gate route->rt_source = source; route->metric = metric; route->mss = mss; - route->scope_inv = nm_platform_route_scope_inv (scope); + route->rt_scope = scope; + route->rt_scope_is_set = scope_is_set; route->pref_src = nmtst_inet4_from_string (pref_src); return route; } inline static NMPlatformIP6Route * -nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway) +nmtst_platform_ip6_route (const char *network, + guint8 plen, + const char *gateway) { static NMPlatformIP6Route route; @@ -1300,9 +1317,13 @@ nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway) } inline static NMPlatformIP6Route * -nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gateway, - int ifindex, NMIPConfigSource source, - guint metric, guint mss) +nmtst_platform_ip6_route_full (int ifindex, + const char *network, + guint8 plen, + const char *gateway, + NMIPConfigSource source, + guint32 metric, + guint32 mss) { NMPlatformIP6Route *route = nmtst_platform_ip6_route (network, plen, gateway); diff --git a/src/devices/tests/Makefile.am b/src/devices/tests/Makefile.am index cd1ef6edd3..6fd5f8f5a3 100644 --- a/src/devices/tests/Makefile.am +++ b/src/devices/tests/Makefile.am @@ -12,7 +12,8 @@ AM_CPPFLAGS = \ -I$(top_builddir)/src \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ - $(GLIB_CFLAGS) + $(GLIB_CFLAGS) \ + $(GUDEV_CFLAGS) AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) AM_LDFLAGS = $(GLIB_LIBS) $(CODE_COVERAGE_LDFLAGS) diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index a637c6cb88..4e824c7a6d 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -287,24 +287,25 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g return FALSE; if (vtable->vt->is_ip4) { - success = nm_platform_ip4_route_add (priv->platform, - entry->route.rx.ifindex, - entry->route.rx.rt_source, - 0, - 0, - entry->route.r4.gateway, - 0, - entry->effective_metric, - entry->route.rx.mss); + NMPlatformIP4Route r = { + .ifindex = entry->route.rx.ifindex, + .rt_source = entry->route.rx.rt_source, + .gateway = entry->route.r4.gateway, + .metric = entry->effective_metric, + .mss = entry->route.rx.mss, + }; + + success = nm_platform_ip4_route_add (priv->platform, &r); } else { - success = nm_platform_ip6_route_add (priv->platform, - entry->route.rx.ifindex, - entry->route.rx.rt_source, - in6addr_any, - 0, - entry->route.r6.gateway, - entry->effective_metric, - entry->route.rx.mss); + NMPlatformIP6Route r = { + .ifindex = entry->route.rx.ifindex, + .rt_source = entry->route.rx.rt_source, + .gateway = entry->route.r6.gateway, + .metric = entry->effective_metric, + .mss = entry->route.rx.mss, + }; + + success = nm_platform_ip6_route_add (priv->platform, &r); } if (!success) { _LOGW (vtable->vt->addr_family, "failed to add default route %s with effective metric %u", @@ -332,6 +333,9 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, route = _vt_route_index (vtable, routes, i); + nm_assert (memcmp (route->network_ptr, &nm_ip_addr_zero, vtable->vt->is_ip4 ? sizeof (in_addr_t) : sizeof (struct in6_addr)) == 0); + nm_assert (route->plen == 0); + /* look at all entries and see if the route for this ifindex pair is * a known entry. */ for (j = 0; j < entries->len; j++) { @@ -355,7 +359,7 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, */ if ( !entry && (has_ifindex_synced || ifindex_to_flush == route->ifindex)) { - vtable->vt->route_delete_default (priv->platform, route->ifindex, route->metric); + vtable->vt->route_delete (priv->platform, (NMPlatformIPXRoute *) route); changed = TRUE; } } diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 2d4c7d9595..54b54b84e3 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -574,9 +574,10 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const && cur_plat_route->rx.metric == *p_effective_metric) { /* we are about to delete cur_ipx_route and we have a matching route * in platform. Delete it. */ + nm_assert (cur_plat_route->rx.ifindex == ifindex); _LOGt (vtable->vt->addr_family, "%3d: platform rt-rm #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route, NULL, 0)); - vtable->vt->route_delete (priv->platform, ifindex, cur_plat_route); + vtable->vt->route_delete (priv->platform, cur_plat_route); } } } @@ -741,8 +742,10 @@ next: /* if @cur_ipx_route is not equal to @plat_route, the route must be deleted. */ if ( !cur_ipx_route || route_dest_cmp_result != 0 - || *p_effective_metric != cur_plat_route->rx.metric) - vtable->vt->route_delete (priv->platform, ifindex, cur_plat_route); + || *p_effective_metric != cur_plat_route->rx.metric) { + nm_assert (cur_plat_route->rx.ifindex == ifindex); + vtable->vt->route_delete (priv->platform, cur_plat_route); + } cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes); } @@ -815,15 +818,15 @@ next: gateway_routes = g_array_new (FALSE, FALSE, sizeof (guint)); g_array_append_val (gateway_routes, i_ipx_routes); } else - vtable->vt->route_add (priv->platform, 0, cur_ipx_route, *p_effective_metric); + vtable->vt->route_add (priv->platform, cur_ipx_route, 0, *p_effective_metric); } if (gateway_routes) { for (i = 0; i < gateway_routes->len; i++) { i_ipx_routes = g_array_index (gateway_routes, guint, i); - vtable->vt->route_add (priv->platform, 0, + vtable->vt->route_add (priv->platform, ipx_routes->index->entries[i_ipx_routes], - effective_metrics[i_ipx_routes]); + 0, effective_metrics[i_ipx_routes]); } g_array_unref (gateway_routes); } @@ -872,7 +875,7 @@ next: || route_dest_cmp_result != 0 || !_route_equals_ignoring_ifindex (vtable, cur_plat_route, cur_ipx_route, *p_effective_metric)) { - if (!vtable->vt->route_add (priv->platform, ifindex, cur_ipx_route, *p_effective_metric)) { + if (!vtable->vt->route_add (priv->platform, cur_ipx_route, ifindex, *p_effective_metric)) { if (cur_ipx_route->rx.rt_source < NM_IP_CONFIG_SOURCE_USER) { _LOGD (vtable->vt->addr_family, "ignore error adding IPv%c route to kernel: %s", @@ -986,6 +989,7 @@ _ip4_device_routes_idle_cb (IP4DeviceRoutePurgeEntry *entry) { NMRouteManager *self; NMRouteManagerPrivate *priv; + NMPObject obj; nm_clear_g_source (&entry->idle_id); @@ -998,11 +1002,9 @@ _ip4_device_routes_idle_cb (IP4DeviceRoutePurgeEntry *entry) _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); + nmp_object_stackinit_id_ip4_route (&obj, &entry->obj->ip4_route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); + + nm_platform_ip4_route_delete (priv->platform, &obj.ip4_route); g_hash_table_remove (priv->ip4_device_routes.entries, entry->obj); _ip4_device_routes_cancel (self); diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 6582b0cf03..69e4982a78 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -69,8 +69,8 @@ typedef struct { GArray *links; GArray *ip4_addresses; GArray *ip6_addresses; - GArray *ip4_routes; - GArray *ip6_routes; + GPtrArray *ip4_routes; + GPtrArray *ip6_routes; } NMFakePlatformPrivate; typedef struct { @@ -109,6 +109,37 @@ _ip4_address_equal_peer_net (in_addr_t peer1, in_addr_t peer2, guint8 plen) /******************************************************************/ +static NMPObject * +_get_at_idx (GPtrArray *array, gsize idx, NMPObjectType expected_type) +{ + NMPObject *obj; + + g_assert (array); + g_assert (idx < array->len); + + obj = array->pdata[idx]; + + g_assert (NMP_OBJECT_IS_VALID (obj)); + if (expected_type != NMP_OBJECT_TYPE_UNKNOWN) + g_assert (expected_type == NMP_OBJECT_GET_TYPE (obj)); + + return obj; +} + +static NMPlatformIP4Route * +_get_at_idx_ip4_route (GPtrArray *array, gsize idx) +{ + return &(_get_at_idx (array, idx, NMP_OBJECT_TYPE_IP4_ROUTE))->ip4_route; +} + +static NMPlatformIP6Route * +_get_at_idx_ip6_route (GPtrArray *array, gsize idx) +{ + return &(_get_at_idx (array, idx, NMP_OBJECT_TYPE_IP6_ROUTE))->ip6_route; +} + +/******************************************************************/ + static gboolean sysctl_set (NMPlatform *platform, const char *path, const char *value) { @@ -352,13 +383,13 @@ link_delete (NMPlatform *platform, int ifindex) memset (address, 0, sizeof (*address)); } for (i = 0; i < priv->ip4_routes->len; i++) { - NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); + NMPlatformIP4Route *route = _get_at_idx_ip4_route (priv->ip4_routes, i); if (route->ifindex == ifindex) memset (route, 0, sizeof (*route)); } for (i = 0; i < priv->ip6_routes->len; i++) { - NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); + NMPlatformIP6Route *route = _get_at_idx_ip6_route (priv->ip6_routes, i); if (route->ifindex == ifindex) memset (route, 0, sizeof (*route)); @@ -1098,7 +1129,7 @@ ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl /* Fill routes */ for (i = 0; i < priv->ip4_routes->len; i++) { - route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); + route = _get_at_idx_ip4_route (priv->ip4_routes, i); if (route && (!ifindex || route->ifindex == ifindex)) { if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT)) @@ -1128,7 +1159,7 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl /* Fill routes */ for (i = 0; i < priv->ip6_routes->len; i++) { - route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); + route = _get_at_idx_ip6_route (priv->ip6_routes, i); if (route && (!ifindex || route->ifindex == ifindex)) { if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT)) @@ -1144,224 +1175,191 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl } static gboolean -ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric) +ip4_route_delete (NMPlatform *platform, const NMPlatformIP4Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); - int i; + NMPObject obj, o; + NMPlatformIP4Route *r; + guint i; + + nmp_object_stackinit_id_ip4_route (&obj, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); for (i = 0; i < priv->ip4_routes->len; i++) { - NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); - NMPlatformIP4Route deleted_route; + r = _get_at_idx_ip4_route (priv->ip4_routes, i); - if ( route->ifindex != ifindex - || route->network != network - || route->plen != plen - || route->metric != metric) + nmp_object_stackinit_id_ip4_route (&o, r, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); + if (!nmp_object_id_equal (&obj, &o)) continue; - memcpy (&deleted_route, route, sizeof (deleted_route)); - g_array_remove_index (priv->ip4_routes, i); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &deleted_route, NM_PLATFORM_SIGNAL_REMOVED); + g_ptr_array_remove_index (priv->ip4_routes, i); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, obj.ip_route.ifindex, &obj.ip4_route, NM_PLATFORM_SIGNAL_REMOVED); } return TRUE; } static gboolean -ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) +ip6_route_delete (NMPlatform *platform, const NMPlatformIP6Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); - int i; + NMPObject obj, o; + NMPlatformIP6Route *r; + guint i; - metric = nm_utils_ip6_route_metric_normalize (metric); + nmp_object_stackinit_id_ip6_route (&obj, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); for (i = 0; i < priv->ip6_routes->len; i++) { - NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); - NMPlatformIP6Route deleted_route; + r = _get_at_idx_ip6_route (priv->ip6_routes, i); - if ( route->ifindex != ifindex - || !IN6_ARE_ADDR_EQUAL (&route->network, &network) - || route->plen != plen - || route->metric != metric) + nmp_object_stackinit_id_ip6_route (&o, r, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); + if (!nmp_object_id_equal (&obj, &o)) continue; - memcpy (&deleted_route, route, sizeof (deleted_route)); - g_array_remove_index (priv->ip6_routes, i); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &deleted_route, NM_PLATFORM_SIGNAL_REMOVED); + g_ptr_array_remove_index (priv->ip6_routes, i); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, obj.ip_route.ifindex, &obj.ip6_route, NM_PLATFORM_SIGNAL_REMOVED); } return TRUE; } static gboolean -ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss) +ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); - NMPlatformIP4Route route; + NMPObject obj, o; + NMPlatformIP4Route *r; guint i; - guint8 scope; + NMPlatformSignalChangeType change_type = NM_PLATFORM_SIGNAL_CHANGED; - g_assert (plen <= 32); + g_assert (route && route->plen <= 32); - scope = gateway == 0 ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; + nmp_object_stackinit_id_ip4_route (&obj, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); - memset (&route, 0, sizeof (route)); - route.ifindex = ifindex; - route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source); - route.network = nm_utils_ip4_address_clear_host_address (network, plen); - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; - route.scope_inv = nm_platform_route_scope_inv (scope); - - if (gateway) { + if (obj.ip4_route.gateway) { for (i = 0; i < priv->ip4_routes->len; i++) { - NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, - NMPlatformIP4Route, i); - guint32 gate = ntohl (item->network) >> (32 - item->plen); - guint32 host = ntohl (gateway) >> (32 - item->plen); + guint32 gate, host; + + r = _get_at_idx_ip4_route (priv->ip4_routes, i); - if (ifindex == item->ifindex && gate == host) + gate = ntohl (r->network) >> (32 - r->plen); + host = ntohl (obj.ip4_route.gateway) >> (32 - r->plen); + + if (obj.ip_route.ifindex == r->ifindex && gate == host) break; } if (i == priv->ip4_routes->len) { - nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable", - route.ifindex, nm_utils_inet4_ntop (route.network, NULL), route.plen, route.metric); + nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%s': Network Unreachable", + nm_platform_ip4_route_to_string (route, NULL, 0)); return FALSE; } } for (i = 0; i < priv->ip4_routes->len; i++) { - NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); - - if (item->network != route.network) - continue; - if (item->plen != route.plen) - continue; - if (item->metric != metric) - continue; + r = _get_at_idx_ip4_route (priv->ip4_routes, i); - if (item->ifindex != route.ifindex) { - ip4_route_delete (platform, item->ifindex, item->network, item->plen, item->metric); - i--; + nmp_object_stackinit_id_ip4_route (&o, r, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); + if (!nmp_object_id_equal (&obj, &o)) continue; - } - memcpy (item, &route, sizeof (route)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED); - return TRUE; + *r = obj.ip4_route; + goto out; } - g_array_append_val (priv->ip4_routes, route); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_ADDED); - + g_ptr_array_add (priv->ip4_routes, nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, &obj.object)); + r = _get_at_idx_ip4_route (priv->ip4_routes, priv->ip4_routes->len - 1); + change_type = NM_PLATFORM_SIGNAL_ADDED; +out: + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, r->ifindex, r, change_type); return TRUE; } static gboolean -ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss) +ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); - NMPlatformIP6Route route; + NMPObject obj, o; + NMPlatformIP6Route *r; guint i; + NMPlatformSignalChangeType change_type = NM_PLATFORM_SIGNAL_CHANGED; - metric = nm_utils_ip6_route_metric_normalize (metric); + g_assert (route && route->plen <= 128); - memset (&route, 0, sizeof (route)); - route.ifindex = ifindex; - route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source); - nm_utils_ip6_address_clear_host_address (&route.network, &network, plen); - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; + nmp_object_stackinit_id_ip6_route (&obj, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); - if (!IN6_IS_ADDR_UNSPECIFIED(&gateway)) { + if (!IN6_IS_ADDR_UNSPECIFIED (&obj.ip6_route.gateway)) { for (i = 0; i < priv->ip6_routes->len; i++) { - NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, - NMPlatformIP6Route, i); - guint8 gate_bits = gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8); - guint8 host_bits = item->network.s6_addr[item->plen / 8] >> (8 - item->plen % 8); - - if ( ifindex == item->ifindex - && memcmp (&gateway, &item->network, item->plen / 8) == 0 - && gate_bits == host_bits) + struct in6_addr a_gateway, a_network; + + r = _get_at_idx_ip6_route (priv->ip6_routes, i); + if (obj.ip_route.ifindex != r->ifindex) + continue; + + nm_utils_ip6_address_clear_host_address (&a_gateway, &obj.ip6_route.gateway, r->plen); + nm_utils_ip6_address_clear_host_address (&a_network, &r->network, r->plen); + if (memcmp (&a_gateway, &a_network, sizeof (struct in6_addr)) == 0) break; } if (i == priv->ip6_routes->len) { - nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable", - route.ifindex, nm_utils_inet6_ntop (&route.network, NULL), route.plen, route.metric); + nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%s': Network Unreachable", + nm_platform_ip6_route_to_string (route, NULL, 0)); return FALSE; } } for (i = 0; i < priv->ip6_routes->len; i++) { - NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); - - if (!IN6_ARE_ADDR_EQUAL (&item->network, &route.network)) - continue; - if (item->plen != route.plen) - continue; - if (item->metric != metric) - continue; + r = _get_at_idx_ip6_route (priv->ip6_routes, i); - if (item->ifindex != route.ifindex) { - ip6_route_delete (platform, item->ifindex, item->network, item->plen, item->metric); - i--; + nmp_object_stackinit_id_ip6_route (&o, r, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); + if (!nmp_object_id_equal (&obj, &o)) continue; - } - memcpy (item, &route, sizeof (route)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED); - return TRUE; + *r = obj.ip6_route; + goto out; } - g_array_append_val (priv->ip6_routes, route); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_ADDED); - + g_ptr_array_add (priv->ip6_routes, nmp_object_new (NMP_OBJECT_TYPE_IP6_ROUTE, &obj.object)); + r = _get_at_idx_ip6_route (priv->ip6_routes, priv->ip6_routes->len - 1); + change_type = NM_PLATFORM_SIGNAL_ADDED; +out: + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, r->ifindex, r, change_type); return TRUE; } static const NMPlatformIP4Route * -ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric) +ip4_route_get (NMPlatform *platform, const NMPlatformIP4Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); - int i; + guint i; + NMPObject obj_id, o; + + nmp_object_stackinit_id_ip4_route (&obj_id, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); for (i = 0; i < priv->ip4_routes->len; i++) { - NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); + const NMPlatformIP4Route *r = _get_at_idx_ip4_route (priv->ip4_routes, i); - if (route->ifindex == ifindex - && route->network == network - && route->plen == plen - && route->metric == metric) - return route; + nmp_object_stackinit_id_ip4_route (&o, r, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); + if (nmp_object_id_equal (&obj_id, &o)) + return r; } return NULL; } static const NMPlatformIP6Route * -ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) +ip6_route_get (NMPlatform *platform, const NMPlatformIP6Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); - int i; + guint i; + NMPObject obj_id, o; - metric = nm_utils_ip6_route_metric_normalize (metric); + nmp_object_stackinit_id_ip6_route (&obj_id, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); for (i = 0; i < priv->ip6_routes->len; i++) { - NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); + NMPlatformIP6Route *r = _get_at_idx_ip6_route (priv->ip6_routes, i); - if (route->ifindex == ifindex - && IN6_ARE_ADDR_EQUAL (&route->network, &network) - && route->plen == plen - && route->metric == metric) - return route; + nmp_object_stackinit_id_ip6_route (&o, r, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); + if (nmp_object_id_equal (&obj_id, &o)) + return r; } return NULL; @@ -1378,8 +1376,8 @@ nm_fake_platform_init (NMFakePlatform *fake_platform) priv->links = g_array_new (TRUE, TRUE, sizeof (NMFakePlatformLink)); priv->ip4_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Address)); priv->ip6_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Address)); - priv->ip4_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route)); - priv->ip6_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route)); + priv->ip4_routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); + priv->ip6_routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); } void @@ -1419,8 +1417,8 @@ nm_fake_platform_finalize (GObject *object) g_array_unref (priv->links); g_array_unref (priv->ip4_addresses); g_array_unref (priv->ip6_addresses); - g_array_unref (priv->ip4_routes); - g_array_unref (priv->ip6_routes); + g_ptr_array_unref (priv->ip4_routes); + g_ptr_array_unref (priv->ip6_routes); G_OBJECT_CLASS (nm_fake_platform_parent_class)->finalize (object); } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 82e673a3c1..baf4d7ccab 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1864,8 +1864,10 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) else obj->ip6_route.gateway = nh.gateway.addr6; - if (is_v4) - obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope); + if (is_v4) { + obj->ip4_route.rt_scope = rtm->rtm_scope; + obj->ip4_route.rt_scope_is_set = TRUE; + } if (is_v4) { if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) @@ -2229,77 +2231,79 @@ nla_put_failure: static struct nl_msg * _nl_msg_new_route (int nlmsg_type, int nlmsg_flags, - int family, - int ifindex, - NMIPConfigSource source, - unsigned char scope, - gconstpointer network, - guint8 plen, - gconstpointer gateway, - guint32 metric, - guint32 mss, - gconstpointer pref_src) + const NMPObject *obj) { - struct nl_msg *msg; - struct rtmsg rtmsg = { - .rtm_family = family, - .rtm_tos = 0, - .rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */ - .rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot (source), - .rtm_scope = scope, - .rtm_type = RTN_UNICAST, - .rtm_flags = 0, - .rtm_dst_len = plen, - .rtm_src_len = 0, - }; + int addr_family; + gboolean is_v4; + const NMIPAddr *gateway; NMIPAddr network_clean; - gsize addr_len; + struct nl_msg *msg; - nm_assert (NM_IN_SET (family, AF_INET, AF_INET6)); + nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE)); - nm_assert (network); msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); if (!msg) - g_return_val_if_reached (NULL); + return NULL; - if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0) - goto nla_put_failure; + addr_family = NMP_OBJECT_GET_CLASS (obj)->addr_family; + is_v4 = (addr_family == AF_INET); + addr_len = is_v4 ? sizeof (in_addr_t) : sizeof (struct in6_addr); + + gateway = is_v4 + ? (gpointer) &obj->ip4_route.gateway + : (gpointer) &obj->ip6_route.gateway; + + { + struct rtmsg rtmsg = { + .rtm_family = addr_family, + .rtm_tos = 0, + .rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */ + .rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot (obj->ip_route.rt_source), + .rtm_scope = is_v4 + ? nm_platform_route_scope_from_ip4_route (&obj->ip4_route) + : nm_platform_route_scope_for_ip6_gateway (&gateway->addr6), + .rtm_type = RTN_UNICAST, + .rtm_flags = 0, + .rtm_dst_len = obj->ip_route.plen, + .rtm_src_len = 0, + }; - addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr); + if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + } - nm_utils_ipx_address_clear_host_address (family, &network_clean, network, plen); + nm_utils_ipx_address_clear_host_address (addr_family, &network_clean, obj->ip_route.network_ptr, obj->ip_route.plen); NLA_PUT (msg, RTA_DST, addr_len, &network_clean); - NLA_PUT_U32 (msg, RTA_PRIORITY, metric); + NLA_PUT_U32 (msg, RTA_PRIORITY, obj->ip_route.metric); - if (pref_src) - NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src); + if (is_v4 && obj->ip4_route.pref_src) + NLA_PUT (msg, RTA_PREFSRC, addr_len, &obj->ip4_route.pref_src); - if (mss > 0) { + if (obj->ip_route.mss > 0) { struct nlattr *metrics; metrics = nla_nest_start (msg, RTA_METRICS); if (!metrics) goto nla_put_failure; - NLA_PUT_U32 (msg, RTAX_ADVMSS, mss); + NLA_PUT_U32 (msg, RTAX_ADVMSS, obj->ip_route.mss); nla_nest_end(msg, metrics); } /* We currently don't have need for multi-hop routes... */ - if ( gateway - && memcmp (gateway, &nm_ip_addr_zero, addr_len) != 0) + if (memcmp (gateway, &nm_ip_addr_zero, addr_len) != 0) NLA_PUT (msg, RTA_GATEWAY, addr_len, gateway); - NLA_PUT_U32 (msg, RTA_OIF, ifindex); + NLA_PUT_U32 (msg, RTA_OIF, obj->ip_route.ifindex); return msg; nla_put_failure: nlmsg_free (msg); - g_return_val_if_reached (NULL); + return NULL; } /******************************************************************/ @@ -3902,6 +3906,7 @@ do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + gboolean success = FALSE; int nle; char s_buf[256]; const NMPObject *obj; @@ -3925,9 +3930,15 @@ do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * nm_assert (seq_result); - _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK - ? LOGL_DEBUG - : LOGL_ERR, + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) + success = TRUE; + else if ( (int) seq_result == -EEXIST + && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE)) + success = TRUE; + + _NMLOG (success ? LOGL_DEBUG : LOGL_ERR, "do-add-%s[%s]: %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), @@ -3950,7 +3961,7 @@ do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * /* Adding is only successful, if kernel reported success *and* we have the * expected object in cache afterwards. */ - return obj && seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + return obj && success; } static gboolean @@ -3963,8 +3974,6 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * gboolean success = TRUE; const char *log_detail = ""; - event_handler_read_netlink (platform, FALSE); - nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL); if (nle < 0) { _LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)", @@ -4122,6 +4131,8 @@ link_delete (NMPlatform *platform, int ifindex) NMPObject obj_id; const NMPObject *obj; + delayed_action_handle_all (platform, TRUE); + obj = nmp_cache_lookup_link (priv->cache, ifindex); if (!obj || !obj->_link.netlink.is_in_netlink) return FALSE; @@ -4132,6 +4143,8 @@ link_delete (NMPlatform *platform, int ifindex) NULL, 0, 0); + if (!nlmsg) + g_return_val_if_reached (FALSE); nmp_object_stackinit_id_link (&obj_id, ifindex); return do_delete_object (platform, &obj_id, nlmsg); @@ -5494,6 +5507,8 @@ ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, guint8 pl nm_auto_nlmsg struct nl_msg *nlmsg = NULL; NMPObject obj_id; + delayed_action_handle_all (platform, TRUE); + nlmsg = _nl_msg_new_address (RTM_DELADDR, 0, AF_INET, @@ -5519,6 +5534,8 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, gui nm_auto_nlmsg struct nl_msg *nlmsg = NULL; NMPObject obj_id; + delayed_action_handle_all (platform, TRUE); + nlmsg = _nl_msg_new_address (RTM_DELADDR, 0, AF_INET6, @@ -5618,146 +5635,93 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl } static gboolean -ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss) +ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route) { NMPObject obj_id; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + nmp_object_stackinit_id_ip4_route (&obj_id, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); + nlmsg = _nl_msg_new_route (RTM_NEWROUTE, - NLM_F_CREATE | NLM_F_REPLACE, - AF_INET, - ifindex, - source, - gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, - &network, - plen, - &gateway, - metric, - mss, - pref_src ? &pref_src : NULL); - - nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); + NLM_F_CREATE | NLM_F_APPEND, + &obj_id); + if (!nlmsg) + g_return_val_if_reached (FALSE); + return do_add_addrroute (platform, &obj_id, nlmsg); } static gboolean -ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss) +ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route) { NMPObject obj_id; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + nmp_object_stackinit_id_ip6_route (&obj_id, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); + nlmsg = _nl_msg_new_route (RTM_NEWROUTE, - NLM_F_CREATE | NLM_F_REPLACE, - AF_INET6, - ifindex, - source, - !IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, - &network, - plen, - &gateway, - metric, - mss, - NULL); - - nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); + NLM_F_CREATE | NLM_F_APPEND, + &obj_id); + if (!nlmsg) + g_return_val_if_reached (FALSE); + return do_add_addrroute (platform, &obj_id, nlmsg); } static gboolean -ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric) +ip4_route_delete (NMPlatform *platform, const NMPlatformIP4Route *route) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); nm_auto_nlmsg struct nl_msg *nlmsg = NULL; NMPObject obj_id; - nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); + nmp_object_stackinit_id_ip4_route (&obj_id, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); - if (metric == 0) { - /* Deleting an IPv4 route with metric 0 does not only delete an exectly matching route. - * If no route with metric 0 exists, it might delete another route to the same destination. - * For nm_platform_ip4_route_delete() we don't want this semantic. - * - * Instead, make sure that we have the most recent state and process all - * delayed actions (including re-reading data from netlink). */ - delayed_action_handle_all (platform, TRUE); - - if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) { - /* hmm... we are about to delete an IP4 route with metric 0. We must only - * send the delete request if such a route really exists. Above we refreshed - * the platform cache, still no such route exists. - * - * Be extra careful and reload the routes. We must be sure that such a - * route doesn't exists, because when we add an IPv4 address, we immediately - * afterwards try to delete the kernel-added device route with metric 0. - * It might be, that we didn't yet get the notification about that route. - * - * FIXME: once our ip4_address_add() is sure that upon return we have - * the latest state from in the platform cache, we might save this - * additional expensive cache-resync. */ - do_request_one_type (platform, NMP_OBJECT_TYPE_IP4_ROUTE); + delayed_action_handle_all (platform, TRUE); - if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) - return TRUE; - } - } + if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) + return TRUE; nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, - AF_INET, - ifindex, - NM_IP_CONFIG_SOURCE_UNKNOWN, - RT_SCOPE_NOWHERE, - &network, - plen, - NULL, - metric, - 0, - NULL); + &obj_id); if (!nlmsg) - return FALSE; + g_return_val_if_reached (FALSE); return do_delete_object (platform, &obj_id, nlmsg); } static gboolean -ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) +ip6_route_delete (NMPlatform *platform, const NMPlatformIP6Route *route) { + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); nm_auto_nlmsg struct nl_msg *nlmsg = NULL; NMPObject obj_id; - metric = nm_utils_ip6_route_metric_normalize (metric); + nmp_object_stackinit_id_ip6_route (&obj_id, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); + + delayed_action_handle_all (platform, TRUE); + + if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) + return TRUE; nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, - AF_INET6, - ifindex, - NM_IP_CONFIG_SOURCE_UNKNOWN, - RT_SCOPE_NOWHERE, - &network, - plen, - NULL, - metric, - 0, - NULL); + &obj_id); if (!nlmsg) - return FALSE; - - nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); + g_return_val_if_reached (FALSE); return do_delete_object (platform, &obj_id, nlmsg); } static const NMPlatformIP4Route * -ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric) +ip4_route_get (NMPlatform *platform, const NMPlatformIP4Route *route) { NMPObject obj_id; const NMPObject *obj; - nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); + nmp_object_stackinit_id_ip4_route (&obj_id, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); + obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip4_route; @@ -5765,14 +5729,13 @@ ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen } static const NMPlatformIP6Route * -ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) +ip6_route_get (NMPlatform *platform, const NMPlatformIP6Route *route) { NMPObject obj_id; const NMPObject *obj; - metric = nm_utils_ip6_route_metric_normalize (metric); + nmp_object_stackinit_id_ip6_route (&obj_id, route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); - nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip6_route; @@ -5928,7 +5891,7 @@ continue_reading: int errsv = e->error > 0 ? e->error : -e->error; /* Error message reported back from kernel. */ - _LOGD ("netlink: recvmsg: error message from kernel: %s (%d) for request %d", + _LOGT ("netlink: recvmsg: error message from kernel: %s (%d) for request %d", strerror (errsv), errsv, nlmsg_hdr (msg)->nlmsg_seq); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 500db9b621..6fdfda27a2 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2870,14 +2870,7 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute /** * nm_platform_ip4_route_add: * @self: - * @ifindex: - * @source: - * network: - * plen: - * gateway: - * pref_src: - * metric: - * mss: + * @route: * * For kernel, a gateway can be either explicitly set or left * at zero (0.0.0.0). In addition, there is the scope of the IPv4 @@ -2898,99 +2891,69 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute * Returns: %TRUE in case of success. */ gboolean -nm_platform_ip4_route_add (NMPlatform *self, - int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, - in_addr_t gateway, in_addr_t pref_src, - guint32 metric, guint32 mss) +nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route) { _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (plen <= 32, FALSE); + g_return_val_if_fail (route, FALSE); + g_return_val_if_fail (route->plen <= 32, FALSE); - if (_LOGD_ENABLED ()) { - NMPlatformIP4Route route = { 0 }; - - route.ifindex = ifindex; - route.rt_source = source; - route.network = network; - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; - route.pref_src = pref_src; - - _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route, NULL, 0)); - } - return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss); + _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (route, NULL, 0)); + return klass->ip4_route_add (self, route); } gboolean -nm_platform_ip6_route_add (NMPlatform *self, - int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss) +nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route) { _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (plen <= 128, FALSE); + g_return_val_if_fail (route, FALSE); + g_return_val_if_fail (route->plen <= 128, FALSE); - if (_LOGD_ENABLED ()) { - NMPlatformIP6Route route = { 0 }; - - route.ifindex = ifindex; - route.rt_source = source; - route.network = network; - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; - - _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route, NULL, 0)); - } - return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, metric, mss); + _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (route, NULL, 0)); + return klass->ip6_route_add (self, route); } gboolean -nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric) +nm_platform_ip4_route_delete (NMPlatform *self, const NMPlatformIP4Route *route) { - char str_dev[TO_STRING_DEV_BUF_SIZE]; - _CHECK_SELF (self, klass, FALSE); - _LOGD ("route: deleting IPv4 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", - nm_utils_inet4_ntop (network, NULL), plen, metric, ifindex, - _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); - return klass->ip4_route_delete (self, ifindex, network, plen, metric); + g_return_val_if_fail (route, FALSE); + + _LOGD ("route: deleting IPv4 route %s", nm_platform_ip4_route_to_string (route, NULL, 0)); + return klass->ip4_route_delete (self, route); } gboolean -nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) +nm_platform_ip6_route_delete (NMPlatform *self, const NMPlatformIP6Route *route) { - char str_dev[TO_STRING_DEV_BUF_SIZE]; - _CHECK_SELF (self, klass, FALSE); - _LOGD ("route: deleting IPv6 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", - nm_utils_inet6_ntop (&network, NULL), plen, metric, ifindex, - _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); - return klass->ip6_route_delete (self, ifindex, network, plen, metric); + g_return_val_if_fail (route, FALSE); + + _LOGD ("route: deleting IPv6 route %s", nm_platform_ip6_route_to_string (route, NULL, 0)); + return klass->ip6_route_delete (self, route); } const NMPlatformIP4Route * -nm_platform_ip4_route_get (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric) +nm_platform_ip4_route_get (NMPlatform *self, const NMPlatformIP4Route *route) { _CHECK_SELF (self, klass, FALSE); - return klass->ip4_route_get (self ,ifindex, network, plen, metric); + g_return_val_if_fail (route, NULL); + + return klass->ip4_route_get (self, route); } const NMPlatformIP6Route * -nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) +nm_platform_ip6_route_get (NMPlatform *self, const NMPlatformIP6Route *route) { _CHECK_SELF (self, klass, FALSE); - return klass->ip6_route_get (self, ifindex, network, plen, metric); + g_return_val_if_fail (route, NULL); + + return klass->ip6_route_get (self, route); } /******************************************************************/ @@ -3626,6 +3589,8 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi char s_pref_src[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; char str_scope[30], s_source[50]; + guint8 scope; + gboolean scope_print; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -3635,6 +3600,9 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); + scope = nm_platform_route_scope_from_ip4_route (route); + scope_print = route->rt_scope_is_set || scope != RT_SCOPE_NOWHERE; + g_snprintf (buf, len, "%s/%d" " via %s" @@ -3654,8 +3622,8 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi route->mss, nmp_utils_ip_config_source_to_string (route->rt_source, s_source, sizeof (s_source)), route->rt_cloned ? " cloned" : "", - route->scope_inv ? " scope " : "", - route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "", + scope_print ? " scope " : "", + scope_print ? nm_platform_route_scope2str (scope, 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 buf; @@ -3960,35 +3928,256 @@ nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6A int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b) { + return nm_platform_ip4_route_cmp_full (a, b, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); +} + +int +nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, NMPlatformIPRouteIdType id_type) +{ + guint8 rtprot_a, rtprot_b; + guint8 scope_a, scope_b; + guint32 network_a, network_b; + _CMP_SELF (a, b); + _CMP_FIELD (a, b, ifindex); - _CMP_FIELD (a, b, network); + + network_a = nm_utils_ip4_address_clear_host_address (a->network, a->plen); + network_b = nm_utils_ip4_address_clear_host_address (b->network, b->plen); + _CMP_DIRECT (network_a, network_b); + _CMP_FIELD (a, b, plen); _CMP_FIELD (a, b, metric); _CMP_FIELD (a, b, gateway); - _CMP_FIELD (a, b, rt_source); + + rtprot_a = nmp_utils_ip_config_source_coerce_to_rtprot (a->rt_source); + rtprot_b = nmp_utils_ip_config_source_coerce_to_rtprot (b->rt_source); + _CMP_DIRECT (rtprot_a, rtprot_b); + _CMP_FIELD (a, b, mss); - _CMP_FIELD (a, b, scope_inv); + + scope_a = nm_platform_route_scope_from_ip4_route (a); + scope_b = nm_platform_route_scope_from_ip4_route (b); + _CMP_DIRECT (scope_a, scope_b); + _CMP_FIELD (a, b, pref_src); _CMP_FIELD (a, b, rt_cloned); + + /* currently we have two id-types, ID and ALL. Let ALL be a stricter + * ordering then ID, but yield the same order. Thus, above we first check + * all the ID fields, only if those are all equal, dig deeper. */ + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + break; + default: + _CMP_FIELD (a, b, network); + _CMP_FIELD (a, b, rt_source); + _CMP_FIELD (a, b, rt_scope); + _CMP_FIELD (a, b, rt_scope_is_set); + break; + } return 0; } +guint +nm_platform_ip4_route_hash_full (const NMPlatformIP4Route *a, NMPlatformIPRouteIdType id_type) +{ + guint h = 0x8202baf9; + + if (!a) + return h; + + h += (h * 33) + ((guint) a->ifindex); + + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + h += (h * 33) + ((guint) nm_utils_ip4_address_clear_host_address (a->network, a->plen)); + break; + default: + h += (h * 33) + ((guint) a->network); + break; + } + + h += (h * 33) + ((guint) a->plen); + h += (h * 33) + ((guint) a->metric); + h += (h * 33) + ((guint) a->gateway); + + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + h += (h * 33) + ((guint) nmp_utils_ip_config_source_coerce_to_rtprot (a->rt_source)); + break; + default: + h += (h * 33) + ((guint) a->rt_source); + break; + } + + h += (h * 33) + ((guint) a->mss); + + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + h += (h * 33) + ((guint) nm_platform_route_scope_from_ip4_route (a)); + break; + default: + h += (h * 33) + (((guint) a->rt_scope) + (((guint) a->rt_scope_is_set) << 8)); + break; + } + + h += (h * 33) + ((guint) a->pref_src); + h += (h * 33) + ((guint) a->rt_cloned); + + return h; +} + +NMPlatformIP4Route * +nm_platform_ip4_route_normalize (NMPlatformIP4Route *dst, const NMPlatformIP4Route *src, NMPlatformIPRouteIdType id_type) +{ + nm_assert (dst); + + if (src && src != dst) + *dst = *src; + + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + dst->network = nm_utils_ip4_address_clear_host_address (dst->network, dst->plen); + dst->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (dst->rt_source); + dst->rt_scope = nm_platform_route_scope_from_ip4_route (dst); + dst->rt_scope_is_set = TRUE; + break; + default: + break; + } + return dst; +} + int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b) { + return nm_platform_ip6_route_cmp_full (a, b, NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL); +} + +int +nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, NMPlatformIPRouteIdType id_type) +{ + struct in6_addr network_a, network_b; + guint32 metric_a, metric_b; + guint8 rtprot_a, rtprot_b; + _CMP_SELF (a, b); + _CMP_FIELD (a, b, ifindex); - _CMP_FIELD_MEMCMP (a, b, network); + + nm_utils_ip6_address_clear_host_address (&network_a, &a->network, a->plen); + nm_utils_ip6_address_clear_host_address (&network_b, &b->network, b->plen); + _CMP_DIRECT_MEMCMP (&network_a, &network_b, sizeof (struct in6_addr)); + _CMP_FIELD (a, b, plen); - _CMP_FIELD (a, b, metric); + + metric_a = nm_utils_ip6_route_metric_normalize (a->metric); + metric_b = nm_utils_ip6_route_metric_normalize (b->metric); + _CMP_DIRECT (metric_a, metric_b); + _CMP_FIELD_MEMCMP (a, b, gateway); - _CMP_FIELD (a, b, rt_source); + + rtprot_a = nmp_utils_ip_config_source_coerce_to_rtprot (a->rt_source); + rtprot_b = nmp_utils_ip_config_source_coerce_to_rtprot (b->rt_source); + _CMP_DIRECT (rtprot_a, rtprot_b); + _CMP_FIELD (a, b, mss); _CMP_FIELD (a, b, rt_cloned); + + /* currently we have two id-types, ID and ALL. Let ALL be a stricter + * ordering then ID, but yield the same order. Thus, above we first check + * all the ID fields, only if those are all equal, dig deeper. */ + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + break; + default: + _CMP_FIELD_MEMCMP (a, b, network); + _CMP_FIELD (a, b, metric); + _CMP_FIELD (a, b, rt_source); + break; + } return 0; } +guint +nm_platform_ip6_route_hash_full (const NMPlatformIP6Route *a, NMPlatformIPRouteIdType id_type) +{ + struct in6_addr network; + + guint h = 0x0569b8f4; + + if (!a) + return h; + + h += (h * 33) + ((guint) a->ifindex); + + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + nm_utils_ip6_address_clear_host_address (&network, &a->network, a->plen); + h += (h * 33) + ((guint) network.s6_addr32[0]); + h += (h * 33) + ((guint) network.s6_addr32[1]); + h += (h * 33) + ((guint) network.s6_addr32[2]); + h += (h * 33) + ((guint) network.s6_addr32[3]); + break; + default: + h += (h * 33) + ((guint) a->network.s6_addr32[0]); + h += (h * 33) + ((guint) a->network.s6_addr32[1]); + h += (h * 33) + ((guint) a->network.s6_addr32[2]); + h += (h * 33) + ((guint) a->network.s6_addr32[3]); + break; + } + + h += (h * 33) + ((guint) a->plen); + + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + h += (h * 33) + ((guint) nm_utils_ip6_route_metric_normalize (a->metric)); + break; + default: + h += (h * 33) + ((guint) a->metric); + break; + } + + h += (h * 33) + ((guint) a->gateway.s6_addr32[0]); + h += (h * 33) + ((guint) a->gateway.s6_addr32[1]); + h += (h * 33) + ((guint) a->gateway.s6_addr32[2]); + h += (h * 33) + ((guint) a->gateway.s6_addr32[3]); + + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + h += (h * 33) + ((guint) nmp_utils_ip_config_source_coerce_to_rtprot (a->rt_source)); + break; + default: + h += (h * 33) + ((guint) a->rt_source); + break; + } + + h += (h * 33) + ((guint) a->mss); + h += (h * 33) + ((guint) a->rt_cloned); + return h; +} + +NMPlatformIP6Route * +nm_platform_ip6_route_normalize (NMPlatformIP6Route *dst, const NMPlatformIP6Route *src, NMPlatformIPRouteIdType id_type) +{ + nm_assert (dst); + + if (src && src != dst) + *dst = *src; + + switch (id_type) { + case NM_PLATFORM_IP_ROUTE_ID_TYPE_ID: + nm_utils_ip6_address_clear_host_address (&dst->network, &dst->network, dst->plen); + dst->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (dst->rt_source); + dst->metric = nm_utils_ip6_route_metric_normalize (dst->metric); + break; + default: + break; + } + return dst; +} + /** * nm_platform_ip_address_cmp_expiry: * @a: a NMPlatformIPAddress to compare @@ -4114,50 +4303,45 @@ nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns) /******************************************************************/ static gboolean -_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric) +_vtr_v4_route_add (NMPlatform *self, const NMPlatformIPXRoute *route, int ifindex, gint64 metric) { - return nm_platform_ip4_route_add (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->rx.rt_source, - route->r4.network, - route->rx.plen, - route->r4.gateway, - route->r4.pref_src, - metric >= 0 ? (guint32) metric : route->rx.metric, - route->rx.mss); + NMPlatformIPXRoute r_storage; + + if ( (ifindex > 0 && ifindex != route->rx.ifindex) + || (metric >= 0 && metric != route->rx.metric)) { + r_storage.r4 = route->r4; + r_storage.rx.ifindex = ifindex; + r_storage.rx.metric = metric; + route = &r_storage; + } + return nm_platform_ip4_route_add (self, &route->r4); } static gboolean -_vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric) +_vtr_v6_route_add (NMPlatform *self, const NMPlatformIPXRoute *route, int ifindex, gint64 metric) { - return nm_platform_ip6_route_add (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->rx.rt_source, - route->r6.network, - route->rx.plen, - route->r6.gateway, - metric >= 0 ? (guint32) metric : route->rx.metric, - route->rx.mss); + NMPlatformIPXRoute r_storage; + + if ( (ifindex > 0 && ifindex != route->rx.ifindex) + || (metric >= 0 && metric != route->rx.metric)) { + r_storage.r6 = route->r6; + r_storage.rx.ifindex = ifindex; + r_storage.rx.metric = nm_utils_ip6_route_metric_normalize (metric); + route = &r_storage; + } + return nm_platform_ip6_route_add (self, &route->r6); } static gboolean -_vtr_v4_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route) +_vtr_v4_route_delete (NMPlatform *self, const NMPlatformIPXRoute *route) { - return nm_platform_ip4_route_delete (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->r4.network, - route->rx.plen, - route->rx.metric); + return nm_platform_ip4_route_delete (self, &route->r4); } static gboolean -_vtr_v6_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route) +_vtr_v6_route_delete (NMPlatform *self, const NMPlatformIPXRoute *route) { - return nm_platform_ip6_route_delete (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->r6.network, - route->rx.plen, - route->rx.metric); + return nm_platform_ip6_route_delete (self, &route->r6); } static guint32 @@ -4166,18 +4350,6 @@ _vtr_v4_metric_normalize (guint32 metric) return metric; } -static gboolean -_vtr_v4_route_delete_default (NMPlatform *self, int ifindex, guint32 metric) -{ - return nm_platform_ip4_route_delete (self, ifindex, 0, 0, metric); -} - -static gboolean -_vtr_v6_route_delete_default (NMPlatform *self, int ifindex, guint32 metric) -{ - return nm_platform_ip6_route_delete (self, ifindex, in6addr_any, 0, metric); -} - /******************************************************************/ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = { @@ -4189,7 +4361,6 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = { .route_get_all = nm_platform_ip4_route_get_all, .route_add = _vtr_v4_route_add, .route_delete = _vtr_v4_route_delete, - .route_delete_default = _vtr_v4_route_delete_default, .metric_normalize = _vtr_v4_metric_normalize, }; @@ -4202,7 +4373,6 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v6 = { .route_get_all = nm_platform_ip6_route_get_all, .route_add = _vtr_v6_route_add, .route_delete = _vtr_v6_route_delete, - .route_delete_default = _vtr_v6_route_delete_default, .metric_normalize = nm_utils_ip6_route_metric_normalize, }; diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index ae12aa8e95..28d7b39689 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -338,13 +338,20 @@ struct _NMPlatformIP4Route { in_addr_t network; in_addr_t gateway; - /* 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. */ in_addr_t pref_src; + + /* The route scope rtm_scope. + * + * Note, that for IPv4, the scope is part of the ID for a route. + * That means, when we receive a route from kernel, we set rt_scope + * and rt_scope_is_set=1 to indicate that the scope is fully determined. + * + * When adding a route, we allow the user to autodetect the scope based + * on the gateway. That is controlled by leaving rt_scope_is_set=0. */ + guint8 rt_scope; + bool rt_scope_is_set:1; }; struct _NMPlatformIP6Route { @@ -372,9 +379,8 @@ typedef struct { int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b); const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len); GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); - gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric); - gboolean (*route_delete) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route); - gboolean (*route_delete_default) (NMPlatform *self, int ifindex, guint32 metric); + gboolean (*route_add) (NMPlatform *self, const NMPlatformIPXRoute *route, int ifindex, gint64 metric); + gboolean (*route_delete) (NMPlatform *self, const NMPlatformIPXRoute *route); guint32 (*metric_normalize) (guint32 metric); } NMPlatformVTableRoute; @@ -630,16 +636,12 @@ typedef struct { 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, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss); - gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss); - gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric); - gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); - const NMPlatformIP4Route *(*ip4_route_get) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric); - const NMPlatformIP6Route *(*ip6_route_get) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); + gboolean (*ip4_route_add) (NMPlatform *, const NMPlatformIP4Route *route); + gboolean (*ip6_route_add) (NMPlatform *, const NMPlatformIP6Route *route); + gboolean (*ip4_route_delete) (NMPlatform *, const NMPlatformIP4Route *route); + gboolean (*ip6_route_delete) (NMPlatform *, const NMPlatformIP6Route *route); + const NMPlatformIP4Route *(*ip4_route_get) (NMPlatform *, const NMPlatformIP4Route *route); + const NMPlatformIP6Route *(*ip6_route_get) (NMPlatform *, const NMPlatformIP6Route *route); gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *); gboolean (*check_support_user_ipv6ll) (NMPlatform *); @@ -676,23 +678,37 @@ NMPlatform *nm_platform_try_get (void); /******************************************************************/ -/** - * nm_platform_route_scope_inv: - * @scope: the route scope, either its original value, or its inverse. - * - * This function is useful, because the constants such as RT_SCOPE_NOWHERE - * are 'int', so ~scope also gives an 'int'. This function gets the type - * casts to guint8 right. - * - * Returns: the bitwise inverse of the route scope. - * */ -#define nm_platform_route_scope_inv _nm_platform_uint8_inv static inline guint8 _nm_platform_uint8_inv (guint8 scope) { return (guint8) ~scope; } +static inline guint8 +nm_platform_route_scope_for_ip4_gateway (guint32 gateway) +{ + return gateway + ? 0 /* RT_SCOPE_UNIVERSE */ + : 253 /* RT_SCOPE_LINK */; +} + +static inline guint8 +nm_platform_route_scope_for_ip6_gateway (const struct in6_addr *gateway) +{ + return gateway && !IN6_IS_ADDR_UNSPECIFIED (gateway) + ? 0 /* RT_SCOPE_UNIVERSE */ + : 253 /* RT_SCOPE_LINK */; +} + +static inline guint8 +nm_platform_route_scope_from_ip4_route (const NMPlatformIP4Route *route) +{ + nm_assert (route); + return route->rt_scope_is_set + ? route->rt_scope + : nm_platform_route_scope_for_ip4_gateway (route->gateway); +} + NMPNetns *nm_platform_netns_get (NMPlatform *self); gboolean nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns); @@ -907,18 +923,14 @@ gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArr 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); -const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric); -const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); +const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, const NMPlatformIP4Route *route); +const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, const NMPlatformIP6Route *route); 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, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss); -gboolean nm_platform_ip6_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss); -gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric); -gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); +gboolean nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route); +gboolean nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route); +gboolean nm_platform_ip4_route_delete (NMPlatform *self, const NMPlatformIP4Route *route); +gboolean nm_platform_ip6_route_delete (NMPlatform *self, const NMPlatformIP6Route *route); const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len); @@ -954,6 +966,18 @@ int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatform int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b); int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b); +typedef enum { + NM_PLATFORM_IP_ROUTE_ID_TYPE_ID, + NM_PLATFORM_IP_ROUTE_ID_TYPE_ALL, +} NMPlatformIPRouteIdType; + +int nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, NMPlatformIPRouteIdType id_type); +int nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, NMPlatformIPRouteIdType id_type); +guint nm_platform_ip4_route_hash_full (const NMPlatformIP4Route *a, NMPlatformIPRouteIdType id_type); +guint nm_platform_ip6_route_hash_full (const NMPlatformIP6Route *a, NMPlatformIPRouteIdType id_type); +NMPlatformIP4Route *nm_platform_ip4_route_normalize (NMPlatformIP4Route *dst, const NMPlatformIP4Route *src, NMPlatformIPRouteIdType id_type); +NMPlatformIP6Route *nm_platform_ip6_route_normalize (NMPlatformIP6Route *dst, const NMPlatformIP6Route *src, NMPlatformIPRouteIdType id_type); + gboolean nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self); gboolean nm_platform_check_support_user_ipv6ll (NMPlatform *self); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 55ffd7cffb..8902881642 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -377,38 +377,33 @@ _vt_cmd_obj_stackinit_id_ip6_address (NMPObject *obj, const NMPObject *src) } const NMPObject * -nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex, guint32 network, guint8 plen, guint32 metric) +nmp_object_stackinit_id_ip4_route (NMPObject *obj, const NMPlatformIP4Route *route, NMPlatformIPRouteIdType id_type) { nmp_object_stackinit (obj, NMP_OBJECT_TYPE_IP4_ROUTE, NULL); - obj->ip4_route.ifindex = ifindex; - obj->ip4_route.network = network; - obj->ip4_route.plen = plen; - obj->ip4_route.metric = metric; + if (route) + nm_platform_ip4_route_normalize (&obj->ip4_route, route, id_type); return obj; } static void _vt_cmd_obj_stackinit_id_ip4_route (NMPObject *obj, const NMPObject *src) { - nmp_object_stackinit_id_ip4_route (obj, src->ip_route.ifindex, src->ip4_route.network, src->ip_route.plen, src->ip_route.metric); + nmp_object_stackinit_id_ip4_route (obj, &src->ip4_route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); } const NMPObject * -nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric) +nmp_object_stackinit_id_ip6_route (NMPObject *obj, const NMPlatformIP6Route *route, NMPlatformIPRouteIdType id_type) { nmp_object_stackinit (obj, NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - obj->ip6_route.ifindex = ifindex; - if (network) - obj->ip6_route.network = *network; - obj->ip6_route.plen = plen; - obj->ip6_route.metric = metric; + if (route) + nm_platform_ip6_route_normalize (&obj->ip6_route, route, id_type); return obj; } static void _vt_cmd_obj_stackinit_id_ip6_route (NMPObject *obj, const NMPObject *src) { - nmp_object_stackinit_id_ip6_route (obj, src->ip_route.ifindex, &src->ip6_route.network, src->ip_route.plen, src->ip_route.metric); + nmp_object_stackinit_id_ip6_route (obj, &src->ip6_route, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); } /******************************************************************/ @@ -567,8 +562,6 @@ _vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->peer_address != obj->address ? "," : "", obj->peer_address != obj->address ? nm_utils_inet4_ntop (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen), buf2) : ""); _vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1)); -_vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric); -_vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric); int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2) @@ -733,16 +726,10 @@ _vt_cmd_plobj_id_copy (ip6_address, NMPlatformIP6Address, { dst->address = src->address; }); _vt_cmd_plobj_id_copy (ip4_route, NMPlatformIP4Route, { - dst->ifindex = src->ifindex; - dst->plen = src->plen; - dst->metric = src->metric; - dst->network = src->network; + nm_platform_ip4_route_normalize (dst, src, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); }); _vt_cmd_plobj_id_copy (ip6_route, NMPlatformIP6Route, { - dst->ifindex = src->ifindex; - dst->plen = src->plen; - dst->metric = src->metric; - dst->network = src->network; + nm_platform_ip6_route_normalize (dst, src, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); }); /* Uses internally nmp_object_copy(), hence it also violates the const @@ -804,15 +791,9 @@ _vt_cmd_plobj_id_equal (ip6_address, NMPlatformIP6Address, /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ && IN6_ARE_ADDR_EQUAL (&obj1->address, &obj2->address)); _vt_cmd_plobj_id_equal (ip4_route, NMPlatformIP4Route, - obj1->ifindex == obj2->ifindex - && obj1->plen == obj2->plen - && obj1->metric == obj2->metric - && obj1->network == obj2->network); + nm_platform_ip4_route_cmp_full (obj1, obj2, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID) == 0); _vt_cmd_plobj_id_equal (ip6_route, NMPlatformIP6Route, - obj1->ifindex == obj2->ifindex - && obj1->plen == obj2->plen - && obj1->metric == obj2->metric - && IN6_ARE_ADDR_EQUAL( &obj1->network, &obj2->network)); + nm_platform_ip6_route_cmp_full (obj1, obj2, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID) == 0); guint nmp_object_id_hash (const NMPObject *obj) @@ -862,18 +843,10 @@ _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, { hash = hash * 33 + _id_hash_ip6_addr (&obj->address); }) _vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, { - hash = (guint) 2569857221u; - hash = hash + ((guint) obj->ifindex); - hash = hash * 33 + ((guint) obj->plen); - hash = hash * 33 + ((guint) obj->metric); - hash = hash * 33 + ((guint) obj->network); + hash = nm_platform_ip4_route_hash_full (obj, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); }) _vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, { - hash = (guint) 3999787007u; - hash = hash + ((guint) obj->ifindex); - hash = hash * 33 + ((guint) obj->plen); - hash = hash * 33 + ((guint) obj->metric); - hash = hash * 33 + _id_hash_ip6_addr (&obj->network); + hash = nm_platform_ip6_route_hash_full (obj, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); }) gboolean @@ -2172,7 +2145,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route, .cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip4_route, .cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_route, - .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_route, + .cmd_plobj_to_string_id = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_route_to_string, .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_route_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_route_cmp, }, @@ -2192,7 +2165,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route, .cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip6_route, .cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_route, - .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_route, + .cmd_plobj_to_string_id = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_route_to_string, .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_route_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp, }, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 062d01d29d..55c7d57766 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -373,8 +373,8 @@ const NMPObject *nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src) const NMPObject *nmp_object_stackinit_id_link (NMPObject *obj, int ifindex); const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, guint8 plen, guint32 peer_address); const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifindex, const struct in6_addr *address, guint8 plen); -const NMPObject *nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex, guint32 network, guint8 plen, guint32 metric); -const NMPObject *nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric); +const NMPObject *nmp_object_stackinit_id_ip4_route (NMPObject *obj, const NMPlatformIP4Route *route, NMPlatformIPRouteIdType id_type); +const NMPObject *nmp_object_stackinit_id_ip6_route (NMPObject *obj, const NMPlatformIP6Route *route, NMPlatformIPRouteIdType id_type); const char *nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size); int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 3b52487a56..15af4909c7 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -33,26 +33,21 @@ test_cleanup_internal (void) GArray *addresses6; GArray *routes4; GArray *routes6; - in_addr_t addr4; - in_addr_t network4; int plen4 = 24; - in_addr_t gateway4; - struct in6_addr addr6; - struct in6_addr network6; int plen6 = 64; - struct in6_addr gateway6; int lifetime = NM_PLATFORM_LIFETIME_PERMANENT; int preferred = NM_PLATFORM_LIFETIME_PERMANENT; int metric = 20; int mss = 1000; guint32 flags = 0; - - inet_pton (AF_INET, "192.0.2.1", &addr4); - inet_pton (AF_INET, "192.0.3.0", &network4); - inet_pton (AF_INET, "198.51.100.1", &gateway4); - inet_pton (AF_INET6, "2001:db8:a:b:1:2:3:4", &addr6); - inet_pton (AF_INET6, "2001:db8:c:d:0:0:0:0", &network6); - inet_pton (AF_INET6, "2001:db8:e:f:1:2:3:4", &gateway6); + const char *const ADDR4 = "192.0.2.1"; + const char *const NETWORK4 = "192.0.3.0"; + const char *const GATEWAY4 = "198.51.100.1"; + const char *const ADDR6 = "2001:db8:a:b:1:2:3:4"; + const char *const NETWORK6 = "2001:db8:c:d:0:0:0:0"; + const char *const GATEWAY6 = "2001:db8:e:f:1:2:3:4"; + const guint32 addr4 = nmtst_inet4_from_string (ADDR4); + const struct in6_addr addr6 = *nmtst_inet6_from_string (ADDR6); /* Create and set up device */ g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS); @@ -65,12 +60,12 @@ test_cleanup_internal (void) /* Add routes and addresses */ g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, 0, NULL)); g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags)); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss)); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss)); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, metric, mss)); + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, nmtst_platform_ip4_route_full (ifindex, GATEWAY4, 32, NULL, NM_IP_CONFIG_SOURCE_USER, metric, mss, 0, FALSE, NULL))); + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, nmtst_platform_ip4_route_full (ifindex, NETWORK4, plen4, GATEWAY4, NM_IP_CONFIG_SOURCE_USER, metric, mss, 0, FALSE, NULL))); + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, nmtst_platform_ip4_route_full (ifindex, NULL, 0, GATEWAY4, NM_IP_CONFIG_SOURCE_USER, metric, mss, 0, FALSE, NULL))); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, nmtst_platform_ip6_route_full (ifindex, GATEWAY6, 128, NULL, NM_IP_CONFIG_SOURCE_USER, metric, mss))); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, nmtst_platform_ip6_route_full (ifindex, NETWORK6, plen6, GATEWAY6, NM_IP_CONFIG_SOURCE_USER, metric, mss))); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, nmtst_platform_ip6_route_full (ifindex, NULL, 0, GATEWAY6, NM_IP_CONFIG_SOURCE_USER, metric, mss))); addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index b1947a6d11..2177d58252 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -25,6 +25,9 @@ #include <sys/wait.h> #include <fcntl.h> +#include "nm-platform-utils.h" +#include "nmp-object.h" + #include "test-common.h" #define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)" @@ -196,8 +199,156 @@ link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlat /*****************************************************************************/ +static int +_sort_routes (gconstpointer p_a, gconstpointer p_b, gpointer user_data) +{ + gboolean is_v4 = GPOINTER_TO_INT (user_data); + + if (is_v4) + return nm_platform_ip4_route_cmp (p_a, p_b); + else + return nm_platform_ip6_route_cmp (p_a, p_b); +} + +const NMPlatformIPXRoute ** +nmtstp_ip_route_get_by_destination (NMPlatform *platform, + gboolean is_v4, + int ifindex, + const NMIPAddr *network, + guint8 plen, + guint32 metric, + const NMIPAddr *gateway, + guint *out_len) +{ + gs_unref_array GArray *routes = NULL; + GPtrArray *result = NULL; + gs_unref_hashtable GHashTable *check_dupes = NULL; + NMIPAddr network_clean; + guint i; + + g_assert (ifindex >= 0); + g_assert (plen >= 0 && plen <= (is_v4 ? 32 : 128)); + + NM_SET_OUT (out_len, 0); + + _init_platform (&platform, FALSE); + + check_dupes = g_hash_table_new ((GHashFunc) nmp_object_id_hash, (GEqualFunc) nmp_object_id_equal); + result = g_ptr_array_new (); + + network = nm_utils_ipx_address_clear_host_address (is_v4 ? AF_INET : AF_INET6, + &network_clean, + network ?: &nm_ip_addr_zero, + plen); + + if (!is_v4) + metric = nm_utils_ip6_route_metric_normalize (metric); + + if (is_v4) + routes = nm_platform_ip4_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL); + else + routes = nm_platform_ip6_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL); + + for (i = 0; routes && i < routes->len; i++) { + const NMPlatformIPXRoute *r_i = is_v4 + ? (NMPlatformIPXRoute *) &g_array_index (routes, NMPlatformIP4Route, i) + : (NMPlatformIPXRoute *) &g_array_index (routes, NMPlatformIP6Route, i); + const NMPlatformIPXRoute *r_2; + const NMPObject *o_2; + + g_assert (r_i->rx.ifindex == ifindex); + + if ( r_i->rx.plen != plen + || r_i->rx.metric != metric) + continue; + + if (is_v4) { + if (r_i->r4.network != *((guint32 *) network)) + continue; + if ( gateway + && r_i->r4.gateway != *((guint32 *) gateway)) + continue; + } else { + if (!IN6_ARE_ADDR_EQUAL (&r_i->r6.network, network)) + continue; + if ( gateway + && !IN6_ARE_ADDR_EQUAL (&r_i->r6.gateway, gateway)) + continue; + } + + r_2 = is_v4 + ? (NMPlatformIPXRoute *) nm_platform_ip4_route_get (platform, &r_i->r4) + : (NMPlatformIPXRoute *) nm_platform_ip6_route_get (platform, &r_i->r6); + g_assert (r_2); + g_assert ( ( is_v4 && nm_platform_ip4_route_cmp (&r_i->r4, &r_2->r4) == 0) + || (!is_v4 && nm_platform_ip6_route_cmp (&r_i->r6, &r_2->r6) == 0)); + + o_2 = NMP_OBJECT_UP_CAST (r_2); + g_assert (NMP_OBJECT_IS_VALID (o_2)); + g_assert (NMP_OBJECT_GET_TYPE (o_2) == (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE)); + + g_ptr_array_add (result, (gpointer) r_2); + if (!nm_g_hash_table_add (check_dupes, (gpointer) o_2)) + g_assert_not_reached (); + } + + /* check whether the multi-index of the platform cache agrees... */ + if (NM_IS_LINUX_PLATFORM (platform)) { + const NMPlatformObject *const *routes_cached; + NMPCacheId cache_id; + guint len; + + if (is_v4) + nmp_cache_id_init_routes_by_destination_ip4 (&cache_id, network->addr4, plen, metric); + else + nmp_cache_id_init_routes_by_destination_ip6 (&cache_id, &network->addr6, plen, metric); + + routes_cached = nm_linux_platform_lookup (platform, &cache_id, &len); + + if (len) + g_assert (routes_cached && routes_cached[len] == NULL); + else + g_assert (!routes_cached); + + for (i =0; routes_cached && i < len; i++) { + const NMPObject *o; + const NMPObject *o_2; + + g_assert (routes_cached [i]); + o = NMP_OBJECT_UP_CAST (routes_cached [i]); + g_assert (NMP_OBJECT_IS_VALID (o)); + g_assert (NMP_OBJECT_GET_TYPE (o) == (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE)); + + if (gateway) { + if ( ( is_v4 && o->ip4_route.gateway != *((guint32 *) gateway)) + || (!is_v4 && !IN6_ARE_ADDR_EQUAL (&o->ip6_route.gateway, gateway))) + continue; + } + + o_2 = g_hash_table_lookup (check_dupes, o); + g_assert (o_2); + g_assert (o_2 == o); + + if (!g_hash_table_remove (check_dupes, o)) + g_assert_not_reached (); + } + + g_assert (g_hash_table_size (check_dupes) == 0); + } + + if (result->len > 0) { + g_ptr_array_sort_with_data (result, _sort_routes, GINT_TO_POINTER (!!is_v4)); + NM_SET_OUT (out_len, result->len); + g_ptr_array_add (result, NULL); + return (gpointer) g_ptr_array_free (result, FALSE); + } + g_ptr_array_unref (result); + return NULL; +} + + gboolean -nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric) +nmtstp_ip4_route_exists (const char *ifname, guint32 network, guint8 plen, guint32 metric, const guint32 *gateway) { gs_free char *arg_network = NULL; const char *argv[] = { @@ -216,6 +367,7 @@ nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 gboolean success; gs_free_error GError *error = NULL; gs_free char *metric_pattern = NULL; + gs_free char *via_pattern = NULL; g_assert (ifname && nm_utils_iface_valid_name (ifname)); g_assert (!strstr (ifname, " metric ")); @@ -253,6 +405,7 @@ nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 g_assert (std_out); metric_pattern = g_strdup_printf (" metric %u", metric); + via_pattern = gateway ? g_strdup_printf (" via %s", nm_utils_inet4_ntop (*gateway, NULL)) : NULL; out = std_out; while (out) { char *eol = strchr (out, '\n'); @@ -264,44 +417,93 @@ nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 continue; if (metric == 0) { - if (!strstr (line, " metric ")) - return TRUE; + if (strstr (line, " metric ")) + continue; + } else { + p = strstr (line, metric_pattern); + if (!p || !NM_IN_SET (p[strlen (metric_pattern)], ' ', '\0')) + continue; + } + + if (gateway) { + if (*gateway == 0) { + if (strstr (line, " via ")) + continue; + } else { + p = strstr (line, via_pattern); + if (!p || !NM_IN_SET (p[strlen (via_pattern)], ' ', '\0')) + continue; + } } - p = strstr (line, metric_pattern); - if (p && NM_IN_SET (p[strlen (metric_pattern)], ' ', '\0')) - return TRUE; + return TRUE; } return FALSE; } -void -_nmtstp_assert_ip4_route_exists (const char *file, guint line, const char *func, NMPlatform *platform, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric) +const NMPlatformIP4Route * +_nmtstp_assert_ip4_route_exists (const char *file, + guint line, + const char *func, + NMPlatform *platform, + gboolean exists, + const char *ifname, + guint32 network, + guint8 plen, + guint32 metric, + const guint32 *gateway) { int ifindex; gboolean exists_checked; + char s_buf[NM_UTILS_INET_ADDRSTRLEN]; + gs_free const NMPlatformIP4Route **routes = NULL; + guint len; _init_platform (&platform, FALSE); /* Check for existance of the route by spawning iproute2. Do this because platform * code might be entirely borked, but we expect ip-route to give a correct result. * If the ip command cannot be found, we accept this as success. */ - exists_checked = nmtstp_ip4_route_exists (ifname, network, plen, metric); + exists_checked = nmtstp_ip4_route_exists (ifname, network, plen, metric, gateway); if (exists_checked != -1 && !exists_checked != !exists) { - g_error ("[%s:%u] %s(): We expect the ip4 route %s/%d metric %u %s, but it %s", + g_error ("[%s:%u] %s(): We expect the ip4 route %s/%d%s metric %u %s, but it %s", file, line, func, - nm_utils_inet4_ntop (network, NULL), plen, metric, + nm_utils_inet4_ntop (network, NULL), plen, + gateway ? nm_sprintf_bufa (100, " gateway %s", nm_utils_inet4_ntop (*gateway, s_buf)) : " no-gateway", + metric, exists ? "to exist" : "not to exist", exists ? "doesn't" : "does"); } ifindex = nm_platform_link_get_ifindex (platform, ifname); g_assert (ifindex > 0); - if (!nm_platform_ip4_route_get (platform, ifindex, network, plen, metric) != !exists) { - g_error ("[%s:%u] %s(): The ip4 route %s/%d metric %u %s, but platform thinks %s", - file, line, func, - nm_utils_inet4_ntop (network, NULL), plen, metric, - exists ? "exists" : "does not exist", - exists ? "it doesn't" : "it does"); + + routes = (gpointer) nmtstp_ip_route_get_by_destination (platform, TRUE, ifindex, (NMIPAddr *) &network, + plen, metric, (NMIPAddr *) gateway, &len); + if (routes) { + if (!exists) { + g_error ("[%s:%u] %s(): The ip4 route %s/%d via %s metric %u %s, but platform thinks %s", + file, line, func, + nm_utils_inet4_ntop (network, NULL), + plen, + nm_utils_inet4_ntop (gateway ? *gateway : 0, s_buf), + metric, + exists ? "exists" : "does not exist", + exists ? "it doesn't" : "it does"); + } + g_assert (len == 1); + return routes[0]; + } else { + if (exists) { + g_error ("[%s:%u] %s(): The ip4 route %s/%d via %s metric %u %s, but platform thinks %s", + file, line, func, + nm_utils_inet4_ntop (network, NULL), + plen, + nm_utils_inet4_ntop (gateway ? *gateway : 0, s_buf), + metric, + exists ? "exists" : "does not exist", + exists ? "it doesn't" : "it does"); + } + return NULL; } } @@ -414,7 +616,7 @@ nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms) const NMPlatformLink * nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms) { - return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); + return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + (gint64) timeout_ms); } const NMPlatformLink * @@ -443,7 +645,7 @@ nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType const NMPlatformLink * nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms) { - return nmtstp_assert_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); + return nmtstp_assert_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + (gint64) timeout_ms); } const NMPlatformLink * @@ -458,6 +660,55 @@ nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NML /*****************************************************************************/ +static const void * +_wait_for_ip_route_until (NMPlatform *platform, int is_v4, int ifindex, const NMIPAddr *network, guint8 plen, guint32 metric, const NMIPAddr *gateway, gint64 until_ms) +{ + gint64 now; + + _init_platform (&platform, FALSE); + + while (TRUE) { + gs_free const NMPlatformIPXRoute **routes = NULL; + + now = nm_utils_get_monotonic_timestamp_ms (); + + routes = nmtstp_ip_route_get_by_destination (platform, is_v4, ifindex, network, plen, metric, gateway, NULL); + if (routes) + return routes[0]; + + if (until_ms < now) + return NULL; + + nmtstp_wait_for_signal (platform, MAX (1, until_ms - now)); + } +} + +const NMPlatformIP4Route * +nmtstp_wait_for_ip4_route (NMPlatform *platform, int ifindex, guint32 network, guint8 plen, guint32 metric, guint32 gateway, guint timeout_ms) +{ + return _wait_for_ip_route_until (platform, TRUE, ifindex, (NMIPAddr *) &network, plen, metric, (NMIPAddr *) &gateway, nm_utils_get_monotonic_timestamp_ms () + (gint64) timeout_ms); +} + +const NMPlatformIP4Route * +nmtstp_wait_for_ip4_route_until (NMPlatform *platform, int ifindex, guint32 network, guint8 plen, guint32 metric, guint32 gateway, gint64 until_ms) +{ + return _wait_for_ip_route_until (platform, TRUE, ifindex, (NMIPAddr *) &network, plen, metric, (NMIPAddr *) &gateway, until_ms); +} + +const NMPlatformIP6Route * +nmtstp_wait_for_ip6_route (NMPlatform *platform, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric, const struct in6_addr *gateway, guint timeout_ms) +{ + return _wait_for_ip_route_until (platform, FALSE, ifindex, (NMIPAddr *) network, plen, metric, (NMIPAddr *) gateway, nm_utils_get_monotonic_timestamp_ms () + (gint64) timeout_ms); +} + +const NMPlatformIP6Route * +nmtstp_wait_for_ip6_route_until (NMPlatform *platform, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric, const struct in6_addr *gateway, gint64 until_ms) +{ + return _wait_for_ip_route_until (platform, FALSE, ifindex, (NMIPAddr *) network, plen, metric, (NMIPAddr *) gateway, until_ms); +} + +/*****************************************************************************/ + int nmtstp_run_command_check_external_global (void) { @@ -592,7 +843,7 @@ _ip_address_add (NMPlatform *platform, gboolean is_v4, int ifindex, const NMIPAddr *address, - int plen, + guint8 plen, const NMIPAddr *peer_address, guint32 lifetime, guint32 preferred, @@ -730,7 +981,7 @@ nmtstp_ip4_address_add (NMPlatform *platform, gboolean external_command, int ifindex, in_addr_t address, - int plen, + guint8 plen, in_addr_t peer_address, guint32 lifetime, guint32 preferred, @@ -755,7 +1006,7 @@ nmtstp_ip6_address_add (NMPlatform *platform, gboolean external_command, int ifindex, struct in6_addr address, - int plen, + guint8 plen, struct in6_addr peer_address, guint32 lifetime, guint32 preferred, @@ -782,7 +1033,7 @@ _ip_address_del (NMPlatform *platform, gboolean is_v4, int ifindex, const NMIPAddr *address, - int plen, + guint8 plen, const NMIPAddr *peer_address) { gint64 end_time; @@ -873,7 +1124,7 @@ nmtstp_ip4_address_del (NMPlatform *platform, gboolean external_command, int ifindex, in_addr_t address, - int plen, + guint8 plen, in_addr_t peer_address) { _ip_address_del (platform, @@ -890,7 +1141,7 @@ nmtstp_ip6_address_del (NMPlatform *platform, gboolean external_command, int ifindex, struct in6_addr address, - int plen) + guint8 plen) { _ip_address_del (platform, external_command, @@ -903,6 +1154,119 @@ nmtstp_ip6_address_del (NMPlatform *platform, /*****************************************************************************/ +static gconstpointer +_ip_route_add (NMPlatform *platform, + gboolean external_command, + gboolean is_v4, + const NMPlatformIPXRoute *route) +{ + gint64 end_time; + char s_network[NM_UTILS_INET_ADDRSTRLEN]; + char s_gateway[NM_UTILS_INET_ADDRSTRLEN]; + char s_pref_src[NM_UTILS_INET_ADDRSTRLEN]; + const NMPlatformLink *pllink; + NMPObject obj_normalized; + const NMPlatformIPXRoute *route_orig; + guint i, len; + + g_assert (route); + g_assert (route->rx.ifindex > 0); + + external_command = nmtstp_run_command_check_external (external_command); + + _init_platform (&platform, external_command); + + route_orig = route; + if (is_v4) + nmp_object_stackinit_id_ip4_route (&obj_normalized, &route->r4, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); + else + nmp_object_stackinit_id_ip6_route (&obj_normalized, &route->r6, NM_PLATFORM_IP_ROUTE_ID_TYPE_ID); + route = &obj_normalized.ipx_route; + + pllink = nmtstp_link_get (platform, route->rx.ifindex, NULL); + g_assert (pllink); + + if (external_command) { + s_network[0] = '\0'; + s_gateway[0] = '\0'; + s_pref_src[0] = '\0'; + if (is_v4) { + nm_utils_inet4_ntop (route->r4.network, s_network); + if (route->r4.gateway) + nm_utils_inet4_ntop (route->r4.gateway, s_gateway); + if (route->r4.pref_src) + nm_utils_inet4_ntop (route->r4.pref_src, s_pref_src); + } else { + nm_utils_inet6_ntop (&route->r6.network, s_network); + if (!IN6_IS_ADDR_UNSPECIFIED (&route->r6.gateway)) + nm_utils_inet6_ntop (&route->r6.gateway, s_gateway); + } + + nmtstp_run_command_check ("ip route append %s/%u%s dev '%s' metric %u proto %u%s%s", + s_network, + route->rx.plen, + s_gateway[0] ? nm_sprintf_bufa (100, " via %s", s_gateway) : "", + pllink->name, + route->rx.metric, + nmp_utils_ip_config_source_coerce_to_rtprot (route->r4.rt_source), + s_pref_src[0] ? nm_sprintf_bufa (100, " src %s", s_pref_src) : "", + route->rx.mss ? nm_sprintf_bufa (100, " advmss %u", route->rx.mss) : ""); + } else { + gboolean success; + + if (is_v4) + success = nm_platform_ip4_route_add (platform, &route_orig->r4); + else + success = nm_platform_ip6_route_add (platform, &route_orig->r6); + g_assert (success); + } + + /* Let's wait until we see the address. */ + end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + do { + gs_free const NMPlatformIPXRoute **routes = NULL; + + if (external_command) + nm_platform_process_events (platform); + + /* let's wait until we see the address as we added it. */ + routes = nmtstp_ip_route_get_by_destination (platform, is_v4, route->rx.ifindex, + (NMIPAddr *) route->rx.network_ptr, + route->rx.plen, + route->rx.metric, + is_v4 ? (NMIPAddr *) &route->r4.gateway : (NMIPAddr *) &route->r6.gateway, + &len); + for (i = 0; i < len; i++) { + const NMPObject *o2; + + o2 = NMP_OBJECT_UP_CAST (routes[i]); + if (nmp_object_equal (o2, &obj_normalized)) + return &o2->ipx_route; + } + + /* for internal command, we expect not to reach this line.*/ + g_assert (external_command); + + nmtstp_assert_wait_for_signal_until (platform, end_time); + } while (TRUE); +} + +const NMPlatformIP4Route * +nmtstp_ip4_route_add (NMPlatform *platform, gboolean external_command, + const NMPlatformIP4Route *route) +{ + return _ip_route_add (platform, external_command, TRUE, (const NMPlatformIPXRoute *) route); +} + +const NMPlatformIP6Route * +nmtstp_ip6_route_add (NMPlatform *platform, gboolean external_command, + const NMPlatformIP6Route *route) +{ + return _ip_route_add (platform, external_command, FALSE, (const NMPlatformIPXRoute *) route); +} + +/*****************************************************************************/ + #define _assert_pllink(platform, success, pllink, name, type) \ G_STMT_START { \ const NMPlatformLink *_pllink = (pllink); \ diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 0e3cf10ba4..c4c0e4abd7 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -109,6 +109,47 @@ const NMPlatformLink *nmtstp_wait_for_link_until (NMPlatform *platform, const ch const NMPlatformLink *nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms); const NMPlatformLink *nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms); +const NMPlatformIP4Route *nmtstp_wait_for_ip4_route (NMPlatform *platform, int ifindex, guint32 network, guint8 plen, guint32 metric, guint32 gateway, guint timeout_ms); +const NMPlatformIP4Route *nmtstp_wait_for_ip4_route_until (NMPlatform *platform, int ifindex, guint32 network, guint8 plen, guint32 metric, guint32 gateway, gint64 until_ms); +const NMPlatformIP6Route *nmtstp_wait_for_ip6_route (NMPlatform *platform, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric, const struct in6_addr *gateway, guint timeout_ms); +const NMPlatformIP6Route *nmtstp_wait_for_ip6_route_until (NMPlatform *platform, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric, const struct in6_addr *gateway, gint64 until_ms); + +#define nmtstp_assert_wait_for_ip4_route(platform, ifindex, network, plen, metric, gateway, timeout_ms) \ + ({ \ + const NMPlatformIP4Route *_plroute; \ + \ + _plroute = nmtstp_wait_for_ip4_route (platform, ifindex, network, plen, metric, gateway, timeout_ms); \ + g_assert (_plroute); \ + _plroute; \ + }) + +#define nmtstp_assert_wait_for_ip4_route_until(platform, ifindex, network, plen, metric, gateway, until_ms) \ + ({ \ + const NMPlatformIP4Route *_plroute; \ + \ + _plroute = nmtstp_wait_for_ip4_route_until (platform, ifindex, network, plen, metric, gateway, until_ms); \ + g_assert (_plroute); \ + _plroute; \ + }) + +#define nmtstp_assert_wait_for_ip6_route(platform, ifindex, network, plen, metric, gateway, timeout_ms) \ + ({ \ + const NMPlatformIP6Route *_plroute; \ + \ + _plroute = nmtstp_wait_for_ip6_route (platform, ifindex, network, plen, metric, gateway, timeout_ms); \ + g_assert (_plroute); \ + _plroute; \ + }) + +#define nmtstp_assert_wait_for_ip6_route_until(platform, ifindex, network, plen, metric, gateway, until_ms) \ + ({ \ + const NMPlatformIP6Route *_plroute; \ + \ + _plroute = nmtstp_wait_for_ip6_route_until (platform, ifindex, network, plen, metric, gateway, until_ms); \ + g_assert (_plroute); \ + _plroute; \ + }) + /*****************************************************************************/ int nmtstp_run_command_check_external_global (void); @@ -116,10 +157,19 @@ gboolean nmtstp_run_command_check_external (int external_command); /*****************************************************************************/ -gboolean nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric); +const NMPlatformIPXRoute **nmtstp_ip_route_get_by_destination (NMPlatform *platform, + gboolean is_v4, + int ifindex, + const NMIPAddr *network, + guint8 plen, + guint32 metric, + const NMIPAddr *gateway, + guint *out_len); + +gboolean nmtstp_ip4_route_exists (const char *ifname, guint32 network, guint8 plen, guint32 metric, const guint32 *gateway); -void _nmtstp_assert_ip4_route_exists (const char *file, guint line, const char *func, NMPlatform *platform, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric); -#define nmtstp_assert_ip4_route_exists(platform, exists, ifname, network, plen, metric) _nmtstp_assert_ip4_route_exists (__FILE__, __LINE__, G_STRFUNC, platform, exists, ifname, network, plen, metric) +const NMPlatformIP4Route *_nmtstp_assert_ip4_route_exists (const char *file, guint line, const char *func, NMPlatform *platform, gboolean exists, const char *ifname, guint32 network, guint8 plen, guint32 metric, const guint32 *gateway); +#define nmtstp_assert_ip4_route_exists(platform, exists, ifname, network, plen, metric, gateway) _nmtstp_assert_ip4_route_exists (__FILE__, __LINE__, G_STRFUNC, platform, exists, ifname, network, plen, metric, gateway) /*****************************************************************************/ @@ -136,7 +186,7 @@ void nmtstp_ip4_address_add (NMPlatform *platform, gboolean external_command, int ifindex, in_addr_t address, - int plen, + guint8 plen, in_addr_t peer_address, guint32 lifetime, guint32 preferred, @@ -146,7 +196,7 @@ void nmtstp_ip6_address_add (NMPlatform *platform, gboolean external_command, int ifindex, struct in6_addr address, - int plen, + guint8 plen, struct in6_addr peer_address, guint32 lifetime, guint32 preferred, @@ -155,13 +205,19 @@ void nmtstp_ip4_address_del (NMPlatform *platform, gboolean external_command, int ifindex, in_addr_t address, - int plen, + guint8 plen, in_addr_t peer_address); void nmtstp_ip6_address_del (NMPlatform *platform, gboolean external_command, int ifindex, struct in6_addr address, - int plen); + guint8 plen); + +const NMPlatformIP4Route *nmtstp_ip4_route_add (NMPlatform *platform, gboolean external_command, + const NMPlatformIP4Route *route); + +const NMPlatformIP6Route *nmtstp_ip6_route_add (NMPlatform *platform, gboolean external_command, + const NMPlatformIP6Route *route); /*****************************************************************************/ diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 9d548aabdb..258b6f3476 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -2292,6 +2292,188 @@ test_netns_bind_to_path (gpointer fixture, gconstpointer test_data) /*****************************************************************************/ +static void +test_route_external (gconstpointer user_data) +{ + const gboolean EX = (nmtst_get_rand_int () % 3) - 1; + const char *const MODE = user_data; + const char *IF[2] = { "IF0", "IF1" }; + int ifindex[2]; + const char *gateway[2] = { + "192.168.171.1", + "192.168.172.1", + }; + gs_unref_object NMPlatform *pl = NULL; + int delete_idx; + gs_free const NMPlatformIPXRoute **routes = NULL; + guint routes_len; + + g_object_unref (NM_PLATFORM_GET); + + g_assert (NM_IN_STRSET (MODE, "change", "append")); + + pl = nm_linux_platform_new (NM_PLATFORM_NETNS_SUPPORT_DEFAULT); + + ifindex[0] = nmtstp_link_dummy_add (pl, EX, IF[0])->ifindex; + ifindex[1] = nmtstp_link_dummy_add (pl, EX, IF[1])->ifindex; + nmtstp_link_set_updown (pl, EX, ifindex[0], TRUE); + nmtstp_link_set_updown (pl, EX, ifindex[1], TRUE); + + nmtstp_ip4_address_add (pl, EX, ifindex[0], + nmtst_inet4_from_string ("192.168.171.5"), 24, + nmtst_inet4_from_string ("192.168.171.5"), + NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0, NULL); + nmtstp_ip4_address_add (pl, EX, ifindex[1], + nmtst_inet4_from_string ("192.168.172.5"), 24, + nmtst_inet4_from_string ("192.168.172.5"), + NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0, NULL); + +#define ADDR4(addr_str) (nmtst_ip4_address_to_ptr (nmtst_inet4_from_string (addr_str))) + + nmtstp_run_command_check ("ip route add 192.168.200.0/24 via %s metric 423", gateway[0]); + nmtstp_assert_wait_for_ip4_route (pl, ifindex[0], nmtst_inet4_from_string ("192.168.200.0"), 24, + 423, nmtst_inet4_from_string (gateway[0]), 100); + + nmtstp_run_command_check ("ip route %s 192.168.200.0/24 via 192.168.172.1 metric 423", MODE); + + if (NM_IN_STRSET (MODE, "changed")) { + + nmtstp_assert_wait_for_ip4_route (pl, ifindex[1], nmtst_inet4_from_string ("192.168.200.0"), 24, + 423, nmtst_inet4_from_string (gateway[1]), 100); + /* is the route still on ifindex[0]? */ + routes = nmtstp_ip_route_get_by_destination (pl, TRUE, ifindex[0], + ADDR4 ("192.168.200.0"), 24, 423, + ADDR4 (gateway[0]), NULL); + g_assert (!routes); + } else if (NM_IN_STRSET (MODE, "append")) { + nmtstp_assert_wait_for_ip4_route (pl, ifindex[1], nmtst_inet4_from_string ("192.168.200.0"), 24, + 423, nmtst_inet4_from_string (gateway[1]), 100); + /* the route on ifindex[0] should continue to exist */ + routes = nmtstp_ip_route_get_by_destination (pl, TRUE, ifindex[0], + ADDR4 ("192.168.200.0"), 24, 423, + ADDR4 (gateway[0]), &routes_len); + g_assert (routes_len == 1); + g_clear_pointer (&routes, g_free); + + delete_idx = nmtst_get_rand_int () % 2; + + routes = nmtstp_ip_route_get_by_destination (pl, TRUE, ifindex[delete_idx], + ADDR4 ("192.168.200.0"), 24, 423, + ADDR4 (gateway[delete_idx]), &routes_len); + g_assert (routes_len == 1); + if (!nm_platform_ip4_route_delete (pl, &routes[0]->r4)) + g_assert_not_reached (); + g_clear_pointer (&routes, g_free); + + routes = nmtstp_ip_route_get_by_destination (pl, TRUE, ifindex[delete_idx], + ADDR4 ("192.168.200.0"), 24, 423, + ADDR4 (gateway[delete_idx]), &routes_len); + g_assert (!routes); + + routes = nmtstp_ip_route_get_by_destination (pl, TRUE, ifindex[!delete_idx], + ADDR4 ("192.168.200.0"), 24, 423, + ADDR4 (gateway[!delete_idx]), &routes_len); + g_assert (routes_len == 1); + g_clear_pointer (&routes, g_free); + } + + nmtstp_link_del (pl, EX, ifindex[0], IF[0]); + nmtstp_link_del (pl, EX, ifindex[1], IF[1]); + + SETUP (); +} + +/*****************************************************************************/ + +static void +test_route_modify (gconstpointer test_data) +{ +#if 0 + const char *const MODE = test_data; + const gboolean EX = (nmtst_get_rand_int () % 3) - 1; + const char *IF = "IF0"; + int ifindex; + const char *gateway[2] = { + "192.168.181.1", + "192.168.181.2", + }; + guint idx[2] = { 0, 1, }; + guint i; + gs_unref_object NMPlatform *pl = NULL; + + g_assert (NM_IN_STRSET (MODE, "delete", "update")); + + g_object_unref (NM_PLATFORM_GET); + + pl = nm_linux_platform_new (NM_PLATFORM_NETNS_SUPPORT_DEFAULT); + + nmtst_rand_perm (NULL, idx, idx, sizeof (idx[0]), G_N_ELEMENTS (idx)); + + ifindex = nmtstp_link_dummy_add (pl, EX, IF)->ifindex; + nmtstp_link_set_updown (pl, EX, ifindex, TRUE); + + nmtstp_ip4_address_add (pl, EX, ifindex, + nmtst_inet4_from_string ("192.168.181.5"), 24, + nmtst_inet4_from_string ("192.168.181.5"), + NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0, NULL); + + nmtstp_run_command_check ("ip route add 192.168.213.0/24 via %s metric 423", gateway[idx[0]]); + if (nmtst_get_rand_int () % 2) { + nmtstp_assert_wait_for_ip4_route (pl, ifindex, nmtst_inet4_from_string ("192.168.213.0"), 24, + 423, nmtst_inet4_from_string (gateway[idx[0]]), 100); + } + + if (nmtst_get_rand_int () % 2) { + nmtstp_run_command_check ("ip route append 192.168.213.0/24 via %s metric 423", gateway[idx[1]]); + nmtstp_assert_wait_for_ip4_route (pl, ifindex, nmtst_inet4_from_string ("192.168.213.0"), 24, + 423, nmtst_inet4_from_string (gateway[idx[1]]), 100); + } else { + nmtstp_ip4_route_add (pl, EX, ifindex, NM_IP_CONFIG_SOURCE_RTPROT_BOOT, + nmtst_inet4_from_string ("192.168.213.0"), 24, + nmtst_inet4_from_string (gateway[idx[1]]), 0, + 423, 0); + } + + g_assert (nm_platform_ip4_route_get (pl, ifindex, + nmtst_inet4_from_string ("192.168.213.0"), 24, 423, + nmtst_inet4_from_string (gateway[idx[0]]))); + g_assert (nm_platform_ip4_route_get (pl, ifindex, + nmtst_inet4_from_string ("192.168.213.0"), 24, 423, + nmtst_inet4_from_string (gateway[idx[1]]))); + + nmtst_rand_perm (NULL, idx, idx, sizeof (idx[0]), G_N_ELEMENTS (idx)); + + for (i = 0; i < G_N_ELEMENTS (idx); i++) { + const NMPlatformIP4Route *plroute; + + if (NM_IN_STRSET (MODE, "delete")) { + g_assert (nm_platform_ip4_route_delete (pl, ifindex, + nmtst_inet4_from_string ("192.168.213.0"), 24, 423, + nmtst_inet4_from_string (gateway[idx[i]]))); + g_assert (!nm_platform_ip4_route_get (pl, ifindex, + nmtst_inet4_from_string ("192.168.213.0"), 24, 423, + nmtst_inet4_from_string (gateway[idx[i]]))); + + plroute = nm_platform_ip4_route_get (pl, ifindex, + nmtst_inet4_from_string ("192.168.213.0"), 24, 423, + nmtst_inet4_from_string (gateway[idx[!i]])); + g_assert ((i == 0 && plroute) || (i == 1 && !plroute)); + } else if (NM_IN_STRSET (MODE, "update")) { + plroute = nmtstp_ip4_route_add (pl, FALSE, ifindex, NM_IP_CONFIG_SOURCE_USER, + nmtst_inet4_from_string ("192.168.213.0"), 24, + nmtst_inet4_from_string (gateway[idx[i]]), 0, + 423, 1400); + } + } + + nmtstp_link_del (pl, EX, ifindex, IF); + + SETUP (); +#endif +} + +/*****************************************************************************/ + void _nmtstp_init_tests (int *argc, char ***argv) { @@ -2335,6 +2517,11 @@ _nmtstp_setup_tests (void) g_test_add_data_func ("/link/create-many-links/20", GUINT_TO_POINTER (20), test_create_many_links); g_test_add_data_func ("/link/create-many-links/1000", GUINT_TO_POINTER (1000), test_create_many_links); + g_test_add_data_func ("/route/external/change", "change", test_route_external); + g_test_add_data_func ("/route/external/append", "append", test_route_external); + g_test_add_data_func ("/route/modify/delete", "delete", test_route_modify); + g_test_add_data_func ("/route/modify/update", "update", test_route_modify); + g_test_add_func ("/link/nl-bugs/veth", test_nl_bugs_veth); g_test_add_func ("/link/nl-bugs/spurious-newlink", test_nl_bugs_spuroius_newlink); g_test_add_func ("/link/nl-bugs/spurious-dellink", test_nl_bugs_spuroius_dellink); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 360404e944..781d6d922b 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -76,56 +76,70 @@ test_ip4_route_metric0 (void) SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_route_callback); SignalData *route_changed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip4_route_callback); SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_route_callback); - in_addr_t network = nmtst_inet4_from_string ("192.0.2.5"); /* from 192.0.2.0/24 (TEST-NET-1) (rfc5737) */ + const char *const NETWORK = "192.0.2.5"; /* from 192.0.2.0/24 (TEST-NET-1) (rfc5737) */ + const guint32 network = nmtst_inet4_from_string (NETWORK); int plen = 32; int metric = 22987; int mss = 1000; + NMPlatformIP4Route r = { + .ifindex = ifindex, + .network = network, + .plen = plen, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .metric = metric, + .mss = mss, + }; + NMPlatformIP4Route r_metric0; + + r_metric0 = r; + r_metric0.metric = 0; /* No routes initially */ - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0, NULL); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric, NULL); /* add the first route */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss)); + + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &r)); accept_signal (route_added); - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); - nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0, NULL); + nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric, NULL); /* Deleting route with metric 0 does nothing */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0)); + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, &r_metric0)); ensure_no_signal (route_removed); - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); - nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0, NULL); + nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric, NULL); /* add the second route */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss)); + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &r_metric0)); accept_signal (route_added); - nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, 0); - nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); + nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, 0, NULL); + nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric, NULL); /* Delete route with metric 0 */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0)); + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, &r_metric0)); accept_signal (route_removed); - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); - nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0, NULL); + nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric, NULL); /* Delete route with metric 0 again (we expect nothing to happen) */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0)); + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, &r_metric0)); ensure_no_signal (route_removed); - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); - nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0, NULL); + nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric, NULL); /* Delete the other route */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, &r)); accept_signal (route_removed); - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0, NULL); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric, NULL); free_signal (route_added); free_signal (route_changed); @@ -141,38 +155,61 @@ test_ip4_route (void) SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_route_callback); GArray *routes; NMPlatformIP4Route rts[3]; - in_addr_t network; guint8 plen = 24; - in_addr_t gateway; /* Choose a high metric so that we hopefully don't conflict. */ int metric = 22986; int mss = 1000; - - inet_pton (AF_INET, "192.0.3.0", &network); - inet_pton (AF_INET, "198.51.100.1", &gateway); + const char *const NETWORK = "192.0.3.0"; + const char *const GATEWAY = "198.51.100.1"; + const guint32 network = nmtst_inet4_from_string (NETWORK); + const guint32 gateway = nmtst_inet4_from_string (GATEWAY); + NMPlatformIP4Route r = { + .ifindex = ifindex, + .network = network, + .plen = plen, + .gateway = gateway, + .metric = metric, + .mss = mss, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; + NMPlatformIP4Route r_gateway = { + .ifindex = ifindex, + .network = gateway, + .plen = 32, + .metric = metric, + .mss = mss, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; + NMPlatformIP4Route r_default = { + .ifindex = ifindex, + .gateway = gateway, + .metric = metric, + .mss = mss, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; /* Add route to gateway */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss)); + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &r_gateway)); accept_signal (route_added); /* Add route */ - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss)); - nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric, NULL); + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &r)); + nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric, NULL); accept_signal (route_added); /* Add route again */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss)); + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &r)); accept_signals (route_changed, 0, 1); /* Add default route */ - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, 0, 0, metric); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss)); - nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, 0, 0, metric); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, 0, 0, metric, NULL); + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &r_default)); + nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, 0, 0, metric, NULL); accept_signal (route_added); /* Add default route again */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss)); + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &r_default)); accept_signals (route_changed, 0, 1); /* Test route listing */ @@ -185,7 +222,8 @@ test_ip4_route (void) rts[0].gateway = INADDR_ANY; rts[0].metric = metric; rts[0].mss = mss; - rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK); + rts[0].rt_scope = RT_SCOPE_LINK; + rts[0].rt_scope_is_set = TRUE; rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); rts[1].network = network; rts[1].plen = plen; @@ -193,7 +231,8 @@ test_ip4_route (void) rts[1].gateway = gateway; rts[1].metric = metric; rts[1].mss = mss; - rts[1].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE); + rts[1].rt_scope = RT_SCOPE_UNIVERSE; + rts[1].rt_scope_is_set = TRUE; rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); rts[2].network = 0; rts[2].plen = 0; @@ -201,18 +240,19 @@ test_ip4_route (void) rts[2].gateway = gateway; rts[2].metric = metric; rts[2].mss = mss; - rts[2].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE); + rts[2].rt_scope = RT_SCOPE_UNIVERSE; + rts[2].rt_scope_is_set = TRUE; g_assert_cmpint (routes->len, ==, 3); nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE); g_array_unref (routes); /* Remove route */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); - nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric); + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, &r)); + nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric, NULL); accept_signal (route_removed); /* Remove route again */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, &r)); free_signal (route_added); free_signal (route_changed); @@ -228,38 +268,60 @@ test_ip6_route (void) SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_route_callback); GArray *routes; NMPlatformIP6Route rts[3]; - struct in6_addr network; + const char *const NETWORK = "2001:db8:a:b:0:0:0:0"; + const char *const GATEWAY = "2001:db8:c:d:1:2:3:4"; + const struct in6_addr network = *nmtst_inet6_from_string (NETWORK); + const struct in6_addr gateway = *nmtst_inet6_from_string (GATEWAY); guint8 plen = 64; - struct in6_addr gateway; - /* Choose a high metric so that we hopefully don't conflict. */ int metric = 22987; int mss = 1000; - - inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network); - inet_pton (AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway); + NMPlatformIP6Route r = { + .ifindex = ifindex, + .network = network, + .plen = plen, + .gateway = gateway, + .metric = metric, + .mss = mss, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; + NMPlatformIP6Route r_gateway = { + .ifindex = ifindex, + .network = gateway, + .plen = 128, + .metric = metric, + .mss = mss, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; + NMPlatformIP6Route r_default = { + .ifindex = ifindex, + .gateway = gateway, + .metric = metric, + .mss = mss, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; /* Add route to gateway */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, metric, mss)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &r_gateway)); accept_signal (route_added); /* Add route */ - g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss)); - g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, &r)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &r)); + g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, &r)); accept_signal (route_added); /* Add route again */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &r)); accept_signals (route_changed, 0, 1); /* Add default route */ - g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss)); - g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); + g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, &r_default)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &r_default)); + g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, &r_default)); accept_signal (route_added); /* Add default route again */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &r_default)); accept_signals (route_changed, 0, 1); /* Test route listing */ @@ -291,12 +353,12 @@ test_ip6_route (void) g_array_unref (routes); /* Remove route */ - g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); - g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, &r)); + g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, &r)); accept_signal (route_removed); /* Remove route again */ - g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, &r)); free_signal (route_added); free_signal (route_changed); @@ -309,14 +371,30 @@ static void test_ip4_zero_gateway (void) { int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + NMPlatformIP4Route r_global = { + .ifindex = ifindex, + .network = nmtst_inet4_from_string ("1.2.3.1"), + .plen = 32, + .rt_source = NM_IP_CONFIG_SOURCE_RTPROT_BOOT, + .rt_scope = RT_SCOPE_UNIVERSE, + .rt_scope_is_set = TRUE, + }; + NMPlatformIP4Route r_local = { + .ifindex = ifindex, + .network = nmtst_inet4_from_string ("1.2.3.2"), + .plen = 32, + .rt_source = NM_IP_CONFIG_SOURCE_RTPROT_BOOT, + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, + }; nmtstp_run_command_check ("ip route add 1.2.3.1/32 via 0.0.0.0 dev %s", DEVICE_NAME); nmtstp_run_command_check ("ip route add 1.2.3.2/32 dev %s", DEVICE_NAME); NMTST_WAIT_ASSERT (100, { nmtstp_wait_for_signal (NM_PLATFORM_GET, 10); - if ( nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.1"), 32, 0) - && nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.2"), 32, 0)) + if ( nm_platform_ip4_route_get (NM_PLATFORM_GET, &r_global) + && nm_platform_ip4_route_get (NM_PLATFORM_GET, &r_local)) break; }); diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index b81c263c08..d79dcd2bd7 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -76,14 +76,9 @@ setup_dev1_ip4 (int ifindex) /* Add some route outside of route manager. The route manager * should get rid of it upon sync. */ if (!nm_platform_ip4_route_add (NM_PLATFORM_GET, - route.ifindex, - NM_IP_CONFIG_SOURCE_USER, - nmtst_inet4_from_string ("9.0.0.0"), - 8, - INADDR_ANY, - 0, - 10, - route.mss)) + nmtst_platform_ip4_route_full (route.ifindex, "9.0.0.0", 8, NULL, + NM_IP_CONFIG_SOURCE_USER, 10, route.mss, + 0, FALSE, NULL))) g_assert_not_reached (); route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); @@ -169,7 +164,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = INADDR_ANY, .metric = 20, .mss = 1000, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -179,7 +175,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = nmtst_inet4_from_string ("6.6.6.1"), .metric = 21021, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE), + .rt_scope = RT_SCOPE_UNIVERSE, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -189,7 +186,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = INADDR_ANY, .metric = 22, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -199,7 +197,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = INADDR_ANY, .metric = 21, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -209,7 +208,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = nmtst_inet4_from_string ("6.6.6.2"), .metric = 22, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE), + .rt_scope = RT_SCOPE_UNIVERSE, + .rt_scope_is_set = TRUE, }, }; @@ -222,7 +222,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = INADDR_ANY, .metric = 20, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -232,7 +233,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = INADDR_ANY, .metric = 21, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -242,7 +244,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = INADDR_ANY, .metric = 22, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -252,7 +255,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = INADDR_ANY, .metric = 21, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -262,7 +266,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = nmtst_inet4_from_string ("6.6.6.2"), .metric = 22, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE), + .rt_scope = RT_SCOPE_UNIVERSE, + .rt_scope_is_set = TRUE, }, }; @@ -275,7 +280,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = INADDR_ANY, .metric = 22, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -285,7 +291,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = INADDR_ANY, .metric = 20, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -295,7 +302,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) .gateway = nmtst_inet4_from_string ("6.6.6.2"), .metric = 22, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE), + .rt_scope = RT_SCOPE_UNIVERSE, + .rt_scope_is_set = TRUE, }, { .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER), @@ -307,7 +315,8 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data) * with metric 20 (above). But we don't remove the metric 21. */ .metric = 21, .mss = 0, - .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK), + .rt_scope = RT_SCOPE_LINK, + .rt_scope_is_set = TRUE, }, }; @@ -382,28 +391,28 @@ setup_dev0_ip6 (int ifindex) 3600, 0); - route = nmtst_platform_ip6_route_full ("2001:db8:8086::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:8086::", 48, NULL, - ifindex, NM_IP_CONFIG_SOURCE_USER, 20, 0); g_array_append_val (routes, *route); - route = nmtst_platform_ip6_route_full ("2001:db8:1337::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:1337::", 48, NULL, - ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0); g_array_append_val (routes, *route); - route = nmtst_platform_ip6_route_full ("2001:db8:abad:c0de::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:abad:c0de::", 64, "2001:db8:8086::1", - ifindex, NM_IP_CONFIG_SOURCE_USER, 21, 0); @@ -422,46 +431,41 @@ setup_dev1_ip6 (int ifindex) /* Add some route outside of route manager. The route manager * should get rid of it upon sync. */ if (!nm_platform_ip6_route_add (NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - *nmtst_inet6_from_string ("2001:db8:8088::"), - 48, - in6addr_any, - 10, - 0)) + nmtst_platform_ip6_route_full (ifindex, "2001:db8:8088::", 48, NULL, + NM_IP_CONFIG_SOURCE_USER, 10, 0))) g_assert_not_reached (); - route = nmtst_platform_ip6_route_full ("2001:db8:8086::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:8086::", 48, NULL, - ifindex, NM_IP_CONFIG_SOURCE_USER, 20, 0); g_array_append_val (routes, *route); - route = nmtst_platform_ip6_route_full ("2001:db8:1337::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:1337::", 48, NULL, - ifindex, NM_IP_CONFIG_SOURCE_USER, 1024, 0); g_array_append_val (routes, *route); - route = nmtst_platform_ip6_route_full ("2001:db8:d34d::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:d34d::", 64, "2001:db8:8086::2", - ifindex, NM_IP_CONFIG_SOURCE_USER, 20, 0); g_array_append_val (routes, *route); - route = nmtst_platform_ip6_route_full ("2001:db8:abad:c0de::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:abad:c0de::", 64, NULL, - ifindex, NM_IP_CONFIG_SOURCE_USER, 22, 0); @@ -487,28 +491,28 @@ update_dev0_ip6 (int ifindex) 3600, 0); - route = nmtst_platform_ip6_route_full ("2001:db8:8086::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:8086::", 48, NULL, - ifindex, NM_IP_CONFIG_SOURCE_USER, 20, 0); g_array_append_val (routes, *route); - route = nmtst_platform_ip6_route_full ("2001:db8:1337::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:1337::", 48, NULL, - ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0); g_array_append_val (routes, *route); - route = nmtst_platform_ip6_route_full ("2001:db8:abad:c0de::", + route = nmtst_platform_ip6_route_full (ifindex, + "2001:db8:abad:c0de::", 64, NULL, - ifindex, NM_IP_CONFIG_SOURCE_USER, 21, 0); @@ -791,9 +795,9 @@ _assert_route_check (const NMPlatformVTableRoute *vtable, gboolean has, const NM g_assert (route); if (vtable->is_ip4) - r = (const NMPlatformIPXRoute *) nm_platform_ip4_route_get (NM_PLATFORM_GET, route->rx.ifindex, route->r4.network, route->rx.plen, route->rx.metric); + r = (const NMPlatformIPXRoute *) nm_platform_ip4_route_get (NM_PLATFORM_GET, &route->r4); else - r = (const NMPlatformIPXRoute *) nm_platform_ip6_route_get (NM_PLATFORM_GET, route->rx.ifindex, route->r6.network, route->rx.plen, route->rx.metric); + r = (const NMPlatformIPXRoute *) nm_platform_ip6_route_get (NM_PLATFORM_GET, &route->r6); if (!has) { g_assert (!r); @@ -824,15 +828,15 @@ test_ip4_full_sync (test_fixture *fixture, gconstpointer user_data) nm_log_dbg (LOGD_CORE, "TEST start test_ip4_full_sync(): start"); - r01 = *nmtst_platform_ip4_route_full ("12.3.4.0", 24, NULL, - fixture->ifindex0, NM_IP_CONFIG_SOURCE_USER, - 100, 0, RT_SCOPE_LINK, NULL); - r02 = *nmtst_platform_ip4_route_full ("13.4.5.6", 32, "12.3.4.1", - fixture->ifindex0, NM_IP_CONFIG_SOURCE_USER, - 100, 0, RT_SCOPE_UNIVERSE, NULL); - r03 = *nmtst_platform_ip4_route_full ("14.5.6.7", 32, "12.3.4.1", - fixture->ifindex0, NM_IP_CONFIG_SOURCE_USER, - 110, 0, RT_SCOPE_UNIVERSE, NULL); + r01 = *nmtst_platform_ip4_route_full (fixture->ifindex0, "12.3.4.0", 24, NULL, + NM_IP_CONFIG_SOURCE_USER, + 100, 0, RT_SCOPE_LINK, TRUE, NULL); + r02 = *nmtst_platform_ip4_route_full (fixture->ifindex0, "13.4.5.6", 32, "12.3.4.1", + NM_IP_CONFIG_SOURCE_USER, + 100, 0, RT_SCOPE_UNIVERSE, TRUE, NULL); + r03 = *nmtst_platform_ip4_route_full (fixture->ifindex0, "14.5.6.7", 32, "12.3.4.1", + NM_IP_CONFIG_SOURCE_USER, + 110, 0, RT_SCOPE_UNIVERSE, TRUE, NULL); g_array_set_size (routes, 2); g_array_index (routes, NMPlatformIP4Route, 0) = r01; g_array_index (routes, NMPlatformIP4Route, 1) = r02; @@ -842,7 +846,7 @@ test_ip4_full_sync (test_fixture *fixture, gconstpointer user_data) _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02); _assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r03); - vtable->route_add (NM_PLATFORM_GET, 0, (const NMPlatformIPXRoute *) &r03, -1); + vtable->route_add (NM_PLATFORM_GET, (const NMPlatformIPXRoute *) &r03, 0, -1); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01); _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02); |