summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-04-05 14:10:51 +0200
committerThomas Haller <thaller@redhat.com>2016-04-11 20:23:24 +0200
commit43151b42e7c5e1d361f6054a4ad2917c9e56f0b9 (patch)
tree2fa6a20f85291afa7ad3b4595b8c4a32e901b0cf
parent50812dfa38c29d371dd72eb83bbe305fa2a5c490 (diff)
downloadNetworkManager-th/platform-route-gateway.tar.gz
platform: properly handle same routes in platform cacheth/platform-route-gateway
From kernels point of view, you can add a new routes as long as there is no existing route that is exactly identical. That effectively means, that every field of the route is part of the ID. Currently, we handle that wrong, thus when kernel notifies platform about two such routes, we would wrongly merge them together. For example: ip link add dev0 type dummy ip link add dev1 type dummy ip link set dev0 up ip link set dev1 up ip addr add 192.168.200.4/24 dev dev0 ip addr add 192.168.201.4/24 dev dev1 ip route add 10.132.5.0/24 dev dev0 ip route append 10.132.5.0/24 via 192.168.212.1 dev dev0 ip route append 10.132.5.0/24 via 192.168.212.1 dev dev0 proto 5 ip route show dev dev0 ip route add 1:2:3:4:5::/64 via fe80::1:a dev dev0 ip route append 1:2:3:4:5::/64 via fe80::1:b dev dev0 ip route append 1:2:3:4:5::/64 via fe80::1:b dev dev0 proto 5 ip -6 route show dev dev0 Note the difference here are the netlink flags: `ip route append` (NLM_F_CREATE|NLM_F_APPEND) `ip route prepend` (NLM_F_CREATE) `ip route add` (NLM_F_CREATE|NLM_F_EXCL) `ip route change` (NLM_F_REPLACE) `ip route replace` (NLM_F_CREATE|NLM_F_REPLACE) Extend platform to consider every property of a route to be part of the ID. Also update the API like route_add(), route_get() and route_delete() to accept full route structures as arguments. For delete, that means you can only delete a route that you know about. But that isn't really actually a problem.
-rw-r--r--src/devices/tests/Makefile.am3
-rw-r--r--src/nm-default-route-manager.c5
-rw-r--r--src/nm-route-manager.c3
-rw-r--r--src/platform/nm-fake-platform.c36
-rw-r--r--src/platform/nm-linux-platform.c119
-rw-r--r--src/platform/nm-platform.c133
-rw-r--r--src/platform/nm-platform.h29
-rw-r--r--src/platform/nmp-object.c65
-rw-r--r--src/platform/nmp-object.h4
-rw-r--r--src/platform/tests/test-common.c294
-rw-r--r--src/platform/tests/test-common.h59
-rw-r--r--src/platform/tests/test-link.c173
-rw-r--r--src/platform/tests/test-route.c68
-rw-r--r--src/tests/test-route-manager.c4
14 files changed, 772 insertions, 223 deletions
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..3c5737585f 100644
--- a/src/nm-default-route-manager.c
+++ b/src/nm-default-route-manager.c
@@ -355,7 +355,10 @@ _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_default (priv->platform, route->ifindex, route->metric,
+ vtable->vt->is_ip4
+ ? (NMIPAddr *) &((NMPlatformIP4Route *) route)->gateway
+ : (NMIPAddr *) &((NMPlatformIP6Route *) route)->gateway);
changed = TRUE;
}
}
diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c
index 2d4c7d9595..64b8889a9f 100644
--- a/src/nm-route-manager.c
+++ b/src/nm-route-manager.c
@@ -1002,7 +1002,8 @@ _ip4_device_routes_idle_cb (IP4DeviceRoutePurgeEntry *entry)
entry->obj->ip4_route.ifindex,
entry->obj->ip4_route.network,
entry->obj->ip4_route.plen,
- entry->obj->ip4_route.metric);
+ entry->obj->ip4_route.metric,
+ entry->obj->ip4_route.gateway);
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 39b5f3c080..1971149229 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -1131,7 +1131,7 @@ 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, int ifindex, in_addr_t network, guint8 plen, guint32 metric, guint32 gateway)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
int i;
@@ -1143,7 +1143,8 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
if ( route->ifindex != ifindex
|| route->network != network
|| route->plen != plen
- || route->metric != metric)
+ || route->metric != metric
+ || route->gateway != gateway)
continue;
memcpy (&deleted_route, route, sizeof (deleted_route));
@@ -1155,7 +1156,7 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
}
static gboolean
-ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric)
+ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric, const struct in6_addr *gateway)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
int i;
@@ -1169,7 +1170,8 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu
if ( route->ifindex != ifindex
|| !IN6_ARE_ADDR_EQUAL (&route->network, &network)
|| route->plen != plen
- || route->metric != metric)
+ || route->metric != metric
+ || !IN6_ARE_ADDR_EQUAL (&route->gateway, gateway ?: &nm_ip_addr_zero.addr6))
continue;
memcpy (&deleted_route, route, sizeof (deleted_route));
@@ -1232,7 +1234,7 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
continue;
if (item->ifindex != route.ifindex) {
- ip4_route_delete (platform, item->ifindex, item->network, item->plen, item->metric);
+ ip4_route_delete (platform, item->ifindex, item->network, item->plen, item->metric, item->gateway);
i--;
continue;
}
@@ -1298,7 +1300,7 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
continue;
if (item->ifindex != route.ifindex) {
- ip6_route_delete (platform, item->ifindex, item->network, item->plen, item->metric);
+ ip6_route_delete (platform, item->ifindex, item->network, item->plen, item->metric, &item->gateway);
i--;
continue;
}
@@ -1315,7 +1317,7 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
}
static const NMPlatformIP4Route *
-ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric)
+ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric, guint32 gateway)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
int i;
@@ -1323,10 +1325,11 @@ ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen
for (i = 0; i < priv->ip4_routes->len; i++) {
NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
- if (route->ifindex == ifindex
- && route->network == network
- && route->plen == plen
- && route->metric == metric)
+ if ( route->ifindex == ifindex
+ && route->network == network
+ && route->plen == plen
+ && route->metric == metric
+ && route->gateway == gateway)
return route;
}
@@ -1334,7 +1337,7 @@ 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, int ifindex, struct in6_addr network, guint8 plen, guint32 metric, const struct in6_addr *gateway)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
int i;
@@ -1344,10 +1347,11 @@ ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, guint
for (i = 0; i < priv->ip6_routes->len; i++) {
NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
- if (route->ifindex == ifindex
- && IN6_ARE_ADDR_EQUAL (&route->network, &network)
- && route->plen == plen
- && route->metric == metric)
+ if ( route->ifindex == ifindex
+ && IN6_ARE_ADDR_EQUAL (&route->network, &network)
+ && route->plen == plen
+ && route->metric == metric
+ && IN6_ARE_ADDR_EQUAL (&route->gateway, gateway ?: &nm_ip_addr_zero.addr6))
return route;
}
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 11c2e965b2..885b066b17 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -304,6 +304,16 @@ _support_user_ipv6ll_detect (struct nlattr **tb)
******************************************************************/
static void
+_ip6_route_normalize_metric (const NMPlatformIP6Route **route, NMPlatformIP6Route *r_storage)
+{
+ if ((*route)->metric != nm_utils_ip6_route_metric_normalize ((*route)->metric)) {
+ *r_storage = **route;
+ r_storage->metric = nm_utils_ip6_route_metric_normalize ((*route)->metric);
+ *route = r_storage;
+ }
+}
+
+static void
clear_host_address (int family, const void *network, guint8 plen, void *dst)
{
g_return_if_fail (network);
@@ -3876,6 +3886,16 @@ do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
event_handler_read_netlink (platform, FALSE);
+ if (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)) {
+ /* for routes, we set the flags to NLM_F_CREATE | NLM_F_APPEND. This will fail with EEXIST
+ * if the route already exists, which is just splendind.
+ *
+ * So, first check the cache whether we expect the route to exist, and if so, set the
+ * flags to REPLACE. */
+ if (nmp_cache_lookup_obj (priv->cache, obj_id))
+ nlmsg_hdr (nlmsg)->nlmsg_flags |= NLM_F_REPLACE;
+ }
+
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
if (nle < 0) {
_LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)",
@@ -5548,65 +5568,64 @@ 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;
nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
- NLM_F_CREATE | NLM_F_REPLACE,
+ NLM_F_CREATE | NLM_F_APPEND,
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);
+ route->ifindex,
+ route->rt_source,
+ route->gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
+ &route->network,
+ route->plen,
+ &route->gateway,
+ route->metric,
+ route->mss,
+ route->pref_src ? &route->pref_src : NULL);
+
+ nmp_object_stackinit_id_ip4_route (&obj_id, route);
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;
+ NMPlatformIP6Route r_storage;
+
+ _ip6_route_normalize_metric (&route, &r_storage);
nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
- NLM_F_CREATE | NLM_F_REPLACE,
+ NLM_F_CREATE | NLM_F_APPEND,
AF_INET6,
- ifindex,
- source,
- !IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
- &network,
- plen,
- &gateway,
- metric,
- mss,
+ route->ifindex,
+ route->rt_source,
+ !IN6_IS_ADDR_UNSPECIFIED (&route->gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
+ &route->network,
+ route->plen,
+ &route->gateway,
+ route->metric,
+ route->mss,
NULL);
- nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
+ nmp_object_stackinit_id_ip6_route (&obj_id, route);
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);
- if (metric == 0) {
+ if (route->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.
@@ -5638,13 +5657,13 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
nlmsg = _nl_msg_new_route (RTM_DELROUTE,
0,
AF_INET,
- ifindex,
+ route->ifindex,
NM_IP_CONFIG_SOURCE_UNKNOWN,
RT_SCOPE_NOWHERE,
- &network,
- plen,
- NULL,
- metric,
+ &route->network,
+ route->plen,
+ &route->gateway,
+ route->metric,
0,
NULL);
if (!nlmsg)
@@ -5654,40 +5673,41 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
}
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)
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
NMPObject obj_id;
+ NMPlatformIP6Route r_storage;
- metric = nm_utils_ip6_route_metric_normalize (metric);
+ _ip6_route_normalize_metric (&route, &r_storage);
nlmsg = _nl_msg_new_route (RTM_DELROUTE,
0,
AF_INET6,
- ifindex,
+ route->ifindex,
NM_IP_CONFIG_SOURCE_UNKNOWN,
RT_SCOPE_NOWHERE,
- &network,
- plen,
- NULL,
- metric,
+ &route->network,
+ route->plen,
+ &route->gateway,
+ route->metric,
0,
NULL);
if (!nlmsg)
return FALSE;
- nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
+ nmp_object_stackinit_id_ip6_route (&obj_id, route);
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);
obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
if (nmp_object_is_visible (obj))
return &obj->ip4_route;
@@ -5695,14 +5715,15 @@ 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;
+ NMPlatformIP6Route r_storage;
- metric = nm_utils_ip6_route_metric_normalize (metric);
+ _ip6_route_normalize_metric (&route, &r_storage);
- nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
+ nmp_object_stackinit_id_ip6_route (&obj_id, route);
obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
if (nmp_object_is_visible (obj))
return &obj->ip6_route;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index afbe5f8263..e382370446 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -2908,45 +2908,49 @@ nm_platform_ip6_route_add (NMPlatform *self,
}
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, int ifindex, in_addr_t network, guint8 plen, guint32 metric, guint32 gateway)
{
char str_dev[TO_STRING_DEV_BUF_SIZE];
+ char str_gateway[NM_UTILS_INET_ADDRSTRLEN];
_CHECK_SELF (self, klass, FALSE);
- _LOGD ("route: deleting IPv4 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s",
+ _LOGD ("route: deleting IPv4 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s, gateway=%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);
+ _to_string_dev (self, ifindex, str_dev, sizeof (str_dev)),
+ nm_utils_inet4_ntop (gateway, str_gateway));
+ return klass->ip4_route_delete (self, ifindex, network, plen, metric, gateway);
}
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, int ifindex, struct in6_addr network, guint8 plen, guint32 metric, const struct in6_addr *gateway)
{
char str_dev[TO_STRING_DEV_BUF_SIZE];
+ char str_gateway[NM_UTILS_INET_ADDRSTRLEN];
_CHECK_SELF (self, klass, FALSE);
- _LOGD ("route: deleting IPv6 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s",
+ _LOGD ("route: deleting IPv6 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s, gateway=%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);
+ _to_string_dev (self, ifindex, str_dev, sizeof (str_dev)),
+ nm_utils_inet6_ntop (gateway ?: &nm_ip_addr_zero.addr6, str_gateway));
+ return klass->ip6_route_delete (self, ifindex, network, plen, metric, gateway);
}
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, int ifindex, in_addr_t network, guint8 plen, guint32 metric, guint32 gateway)
{
_CHECK_SELF (self, klass, FALSE);
- return klass->ip4_route_get (self ,ifindex, network, plen, metric);
+ return klass->ip4_route_get (self ,ifindex, network, plen, metric, gateway);
}
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, int ifindex, struct in6_addr network, guint8 plen, guint32 metric, const struct in6_addr *gateway)
{
_CHECK_SELF (self, klass, FALSE);
- return klass->ip6_route_get (self, ifindex, network, plen, metric);
+ return klass->ip6_route_get (self, ifindex, network, plen, metric, gateway);
}
/******************************************************************/
@@ -3917,6 +3921,9 @@ int
nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b)
{
_CMP_SELF (a, b);
+
+ /* for nmp_object_id_equal(), all fields of the route are considered here. */
+
_CMP_FIELD (a, b, ifindex);
_CMP_FIELD (a, b, network);
_CMP_FIELD (a, b, plen);
@@ -3930,10 +3937,35 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
return 0;
}
+guint
+nm_platform_ip4_route_hash (const NMPlatformIP4Route *a)
+{
+ guint h = 0x8202baf9;
+
+ /* goes together with nm_platform_ip4_route_cmp(). */
+
+ if (a) {
+ h += (h * 33) + ((guint) a->ifindex);
+ h += (h * 33) + ((guint) a->network);
+ h += (h * 33) + ((guint) a->plen);
+ h += (h * 33) + ((guint) a->metric);
+ h += (h * 33) + ((guint) a->gateway);
+ h += (h * 33) + ((guint) a->rt_source);
+ h += (h * 33) + ((guint) a->mss);
+ h += (h * 33) + ((guint) a->scope_inv);
+ h += (h * 33) + ((guint) a->pref_src);
+ h += (h * 33) + ((guint) a->rt_cloned);
+ }
+ return h;
+}
+
int
nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b)
{
_CMP_SELF (a, b);
+
+ /* for nmp_object_id_equal(), all fields of the route are considered here. */
+
_CMP_FIELD (a, b, ifindex);
_CMP_FIELD_MEMCMP (a, b, network);
_CMP_FIELD (a, b, plen);
@@ -3945,6 +3977,32 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route
return 0;
}
+guint
+nm_platform_ip6_route_hash (const NMPlatformIP6Route *a)
+{
+ guint h = 0x0569b8f4;
+
+ /* goes together with nm_platform_ip6_route_cmp(). */
+
+ if (a) {
+ h += (h * 33) + ((guint) a->ifindex);
+ 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]);
+ h += (h * 33) + ((guint) a->plen);
+ h += (h * 33) + ((guint) a->metric);
+ 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]);
+ h += (h * 33) + ((guint) a->rt_source);
+ h += (h * 33) + ((guint) a->mss);
+ h += (h * 33) + ((guint) a->rt_cloned);
+ }
+ return h;
+}
+
/**
* nm_platform_ip_address_cmp_expiry:
* @a: a NMPlatformIPAddress to compare
@@ -4072,28 +4130,31 @@ nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns)
static gboolean
_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, 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
+ || (metric >= 0 && route->metric != 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);
}
static gboolean
_vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, 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
+ || (metric >= 0 && route->metric != 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);
}
static gboolean
@@ -4103,7 +4164,8 @@ _vtr_v4_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *r
ifindex > 0 ? ifindex : route->rx.ifindex,
route->r4.network,
route->rx.plen,
- route->rx.metric);
+ route->rx.metric,
+ route->r4.gateway);
}
static gboolean
@@ -4113,7 +4175,8 @@ _vtr_v6_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *r
ifindex > 0 ? ifindex : route->rx.ifindex,
route->r6.network,
route->rx.plen,
- route->rx.metric);
+ route->rx.metric,
+ &route->r6.gateway);
}
static guint32
@@ -4123,15 +4186,15 @@ _vtr_v4_metric_normalize (guint32 metric)
}
static gboolean
-_vtr_v4_route_delete_default (NMPlatform *self, int ifindex, guint32 metric)
+_vtr_v4_route_delete_default (NMPlatform *self, int ifindex, guint32 metric, const NMIPAddr *gateway)
{
- return nm_platform_ip4_route_delete (self, ifindex, 0, 0, metric);
+ return nm_platform_ip4_route_delete (self, ifindex, 0, 0, metric, gateway ? gateway->addr4 : 0);
}
static gboolean
-_vtr_v6_route_delete_default (NMPlatform *self, int ifindex, guint32 metric)
+_vtr_v6_route_delete_default (NMPlatform *self, int ifindex, guint32 metric, const NMIPAddr *gateway)
{
- return nm_platform_ip6_route_delete (self, ifindex, in6addr_any, 0, metric);
+ return nm_platform_ip6_route_delete (self, ifindex, in6addr_any, 0, metric, gateway ? &gateway->addr6 : NULL);
}
/******************************************************************/
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 2c1823c21d..ee3d849078 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -374,7 +374,7 @@ typedef struct {
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_delete_default) (NMPlatform *self, int ifindex, guint32 metric, const NMIPAddr *gateway);
guint32 (*metric_normalize) (guint32 metric);
} NMPlatformVTableRoute;
@@ -635,10 +635,10 @@ typedef struct {
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_delete) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric, guint32 gateway);
+ gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric, const struct in6_addr *gateway);
+ 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 *);
@@ -903,18 +903,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);
@@ -950,6 +946,9 @@ 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);
+guint nm_platform_ip4_route_hash (const NMPlatformIP4Route *a);
+guint nm_platform_ip6_route_hash (const NMPlatformIP6Route *a);
+
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..50a9a0d860 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)
{
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)
+ obj->ip4_route = *route;
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);
}
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)
{
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)
+ obj->ip6_route = *route;
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);
}
/******************************************************************/
@@ -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;
+ *dst = *src;
});
_vt_cmd_plobj_id_copy (ip6_route, NMPlatformIP6Route, {
- dst->ifindex = src->ifindex;
- dst->plen = src->plen;
- dst->metric = src->metric;
- dst->network = src->network;
+ *dst = *src;
});
/* 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 (obj1, obj2) == 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 (obj1, obj2) == 0);
guint
nmp_object_id_hash (const NMPObject *obj)
@@ -861,20 +842,6 @@ _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, {
/* for IPv6 addresses, the prefix length is not part of the primary identifier. */
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);
-})
-_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);
-})
gboolean
nmp_object_is_alive (const NMPObject *obj)
@@ -2171,8 +2138,8 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
.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_id_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip4_route_hash,
+ .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,
},
@@ -2191,8 +2158,8 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
.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_id_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip6_route_hash,
+ .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 c5241037d5..95d7fab1c1 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -372,8 +372,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);
+const NMPObject *nmp_object_stackinit_id_ip6_route (NMPObject *obj, const NMPlatformIP6Route *route);
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-common.c b/src/platform/tests/test-common.c
index b1947a6d11..34783c3ea4 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -25,6 +25,8 @@
#include <sys/wait.h>
#include <fcntl.h>
+#include "nm-platform-utils.h"
+
#include "test-common.h"
#define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)"
@@ -197,7 +199,7 @@ link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlat
/*****************************************************************************/
gboolean
-nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric)
+nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric, const guint32 *gateway)
{
gs_free char *arg_network = NULL;
const char *argv[] = {
@@ -216,6 +218,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 +256,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,45 +268,104 @@ 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;
}
- p = strstr (line, metric_pattern);
- if (p && NM_IN_SET (p[strlen (metric_pattern)], ' ', '\0'))
- return TRUE;
+
+ 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;
+ }
+ }
+ 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)
+_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 guint32 *gateway)
{
int ifindex;
gboolean exists_checked;
+ char s_buf[NM_UTILS_INET_ADDRSTRLEN];
+ guint32 g = 0;
+ gboolean found_fuzzy = FALSE;
_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",
+
+ if (gateway)
+ g = *gateway;
+ else {
+ gs_unref_array GArray *routes = NULL;
+ guint i;
+
+ routes = nm_platform_ip4_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL);
+ for (i = 0; routes && i < routes->len; i++) {
+ const NMPlatformIP4Route *r = &g_array_index (routes, NMPlatformIP4Route, i);
+
+ g_assert (r->ifindex == ifindex);
+ if ( r->network == network
+ && r->plen == plen
+ && r->metric == metric) {
+ g_assert (!found_fuzzy);
+ found_fuzzy = TRUE;
+ g = r->gateway;
+ }
+ }
+ if (found_fuzzy)
+ goto found;
+ if (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");
+ }
+ return;
+ }
+found:
+ if (!nm_platform_ip4_route_get (platform, ifindex, network, plen, metric, g) != !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, metric,
+ nm_utils_inet4_ntop (network, NULL),
+ plen,
+ nm_utils_inet4_ntop (g, s_buf),
+ metric,
exists ? "exists" : "does not exist",
exists ? "it doesn't" : "it does");
}
+
+ /* when we found the route via fuzzy-match (without gateway), we expect that
+ * exists and nm_platform_ip4_route_get() agree. */
+ g_assert (!found_fuzzy || exists);
}
/*****************************************************************************/
@@ -414,7 +477,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 +506,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 +521,61 @@ 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)
+{
+ const void *plroute = NULL;
+ gint64 now;
+
+ _init_platform (&platform, FALSE);
+
+ while (TRUE) {
+ now = nm_utils_get_monotonic_timestamp_ms ();
+
+ if (is_v4)
+ plroute = nm_platform_ip4_route_get (platform, ifindex, network->addr4, plen, metric, gateway->addr4);
+ else {
+ plroute = nm_platform_ip6_route_get (platform, ifindex,
+ network ? network->addr6 : in6addr_any,
+ plen, metric,
+ gateway ? &gateway->addr6 : &in6addr_any);
+ }
+ if (plroute)
+ return plroute;
+
+ 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)
{
@@ -903,6 +1021,152 @@ nmtstp_ip6_address_del (NMPlatform *platform,
/*****************************************************************************/
+static gconstpointer
+_ip_route_add (NMPlatform *platform,
+ gboolean external_command,
+ gboolean is_v4,
+ int ifindex,
+ NMIPConfigSource source,
+ const NMIPAddr *network,
+ guint8 plen,
+ const NMIPAddr *gateway,
+ guint32 *pref_src,
+ guint32 metric,
+ guint32 mss)
+{
+ 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;
+
+ external_command = nmtstp_run_command_check_external (external_command);
+
+ _init_platform (&platform, external_command);
+
+ pllink = nmtstp_link_get (platform, 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 (network->addr4, s_network);
+ if (gateway->addr4)
+ nm_utils_inet4_ntop (gateway->addr4, s_gateway);
+ if (*pref_src)
+ nm_utils_inet4_ntop (*pref_src, s_pref_src);
+ } else {
+ nm_utils_inet6_ntop (network ? &network->addr6 : &in6addr_any, s_network);
+ if (gateway && !IN6_IS_ADDR_UNSPECIFIED (&gateway->addr6))
+ nm_utils_inet6_ntop (&gateway->addr6, s_gateway);
+ g_assert (!pref_src);
+ }
+
+ nmtstp_run_command_check ("ip route append %s/%u%s dev '%s' metric %u protocol %d%s%s",
+ s_network,
+ plen,
+ s_gateway[0] ? nm_sprintf_bufa (100, " via %s", s_gateway) : "",
+ pllink->name,
+ metric,
+ nmp_utils_ip_config_source_coerce_to_rtprot (source),
+ s_pref_src[0] ? nm_sprintf_bufa (100, " src %s", s_pref_src) : "",
+ mss ? nm_sprintf_bufa (100, " advmss %u", mss) : "");
+ } else {
+ gboolean success;
+
+ if (is_v4) {
+ success = nm_platform_ip4_route_add (platform,
+ ifindex,
+ source,
+ network->addr4,
+ plen,
+ gateway->addr4,
+ *pref_src,
+ metric,
+ mss);
+ } else {
+ g_assert (pref_src == NULL);
+ success = nm_platform_ip6_route_add (platform,
+ ifindex,
+ source,
+ network ? network->addr6 : in6addr_any,
+ plen,
+ gateway ? gateway->addr6 : in6addr_any,
+ metric,
+ mss);
+ }
+ g_assert (success);
+ }
+
+ /* Let's wait until we see the address. */
+ end_time = nm_utils_get_monotonic_timestamp_ms () + 250;
+ do {
+ if (external_command)
+ nm_platform_process_events (platform);
+
+ /* let's wait until we see the address as we added it. */
+ if (is_v4) {
+ const NMPlatformIP4Route *r;
+
+ r = nm_platform_ip4_route_get (platform, ifindex, network->addr4, plen, metric, gateway->addr4);
+ if (r) {
+ g_assert (r->ifindex == ifindex);
+ g_assert (r->network == network->addr4);
+ g_assert (r->plen == plen);
+ g_assert (r->metric == metric);
+ g_assert (r->gateway == gateway->addr4);
+ if ( r->mss == mss
+ && r->pref_src == *pref_src
+ && r->rt_source == nmp_utils_ip_config_source_round_trip_rtprot (source))
+ return r;
+ }
+ } else {
+ const NMPlatformIP6Route *r;
+
+ r = nm_platform_ip6_route_get (platform, ifindex, network ? network->addr6 : in6addr_any, plen, metric, gateway ? &gateway->addr6 : NULL);
+ if (r) {
+ g_assert (r->ifindex == ifindex);
+ g_assert (IN6_ARE_ADDR_EQUAL (&r->network, network ? &network->addr6 : &in6addr_any));
+ g_assert (r->plen == plen);
+ g_assert (r->metric == metric);
+ g_assert (IN6_ARE_ADDR_EQUAL (&r->gateway, gateway ? &gateway->addr6 : &in6addr_any));
+ if ( r->mss == mss
+ && r->rt_source == nmp_utils_ip_config_source_round_trip_rtprot (source))
+ return r;
+ }
+ }
+
+ /* 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,
+ int ifindex, NMIPConfigSource source,
+ guint32 network, guint8 plen,
+ guint32 gateway, guint32 pref_src,
+ guint32 metric, guint32 mss)
+{
+ return _ip_route_add (platform, external_command, TRUE, ifindex, source, (NMIPAddr *) &network, plen, (NMIPAddr *) &gateway, &pref_src, metric, mss);
+}
+
+const NMPlatformIP4Route *
+nmtstp_ip6_route_add (NMPlatform *platform, gboolean external_command,
+ int ifindex, NMIPConfigSource source,
+ const struct in6_addr *network, guint8 plen,
+ const struct in6_addr *gateway,
+ guint32 metric, guint32 mss)
+{
+ return _ip_route_add (platform, external_command, FALSE, ifindex, source, (NMIPAddr *) &network, plen, (NMIPAddr *) &gateway, NULL, metric, mss);
+}
+
+/*****************************************************************************/
+
#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..5a7c8963d1 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,10 @@ gboolean nmtstp_run_command_check_external (int external_command);
/*****************************************************************************/
-gboolean nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric);
+gboolean nmtstp_ip4_route_exists (const char *ifname, guint32 network, int 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)
+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 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)
/*****************************************************************************/
@@ -163,6 +204,18 @@ void nmtstp_ip6_address_del (NMPlatform *platform,
struct in6_addr address,
int plen);
+const NMPlatformIP4Route *nmtstp_ip4_route_add (NMPlatform *platform, gboolean external_command,
+ int ifindex, NMIPConfigSource source,
+ guint32 network, guint8 plen,
+ guint32 gateway, guint32 pref_src,
+ guint32 metric, guint32 mss);
+
+const NMPlatformIP4Route *nmtstp_ip6_route_add (NMPlatform *platform, gboolean external_command,
+ int ifindex, NMIPConfigSource source,
+ const struct in6_addr *network, guint8 plen,
+ const struct in6_addr *gateway,
+ guint32 metric, guint32 mss);
+
/*****************************************************************************/
const NMPlatformLink *nmtstp_link_get_typed (NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type);
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 9d548aabdb..c834944b97 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -2292,6 +2292,174 @@ 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;;
+
+ 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);
+
+ 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]? */
+ if (nm_platform_ip4_route_get (pl, ifindex[0],
+ nmtst_inet4_from_string ("192.168.200.0"), 24,
+ 423, nmtst_inet4_from_string (gateway[0])))
+ g_assert_not_reached ();
+ } 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 */
+ if (!nm_platform_ip4_route_get (pl, ifindex[0],
+ nmtst_inet4_from_string ("192.168.200.0"), 24,
+ 423, nmtst_inet4_from_string (gateway[0])))
+ g_assert_not_reached ();
+
+ delete_idx = nmtst_get_rand_int () % 2;
+
+ if (!nm_platform_ip4_route_delete (pl, ifindex[delete_idx],
+ nmtst_inet4_from_string ("192.168.200.0"), 24, 423,
+ nmtst_inet4_from_string (gateway[delete_idx])))
+ g_assert_not_reached ();
+ if (nm_platform_ip4_route_get (pl, ifindex[delete_idx],
+ nmtst_inet4_from_string ("192.168.200.0"), 24, 423,
+ nmtst_inet4_from_string (gateway[delete_idx])))
+ g_assert_not_reached ();
+ if (!nm_platform_ip4_route_get (pl, ifindex[!delete_idx],
+ nmtst_inet4_from_string ("192.168.200.0"), 24, 423,
+ nmtst_inet4_from_string (gateway[!delete_idx])))
+ g_assert_not_reached ();
+ }
+
+ 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)
+{
+ 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 ();
+}
+
+/*****************************************************************************/
+
void
_nmtstp_init_tests (int *argc, char ***argv)
{
@@ -2335,6 +2503,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..a0b70c4e89 100644
--- a/src/platform/tests/test-route.c
+++ b/src/platform/tests/test-route.c
@@ -82,50 +82,50 @@ test_ip4_route_metric0 (void)
int mss = 1000;
/* 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));
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, ifindex, network, plen, 0, INADDR_ANY));
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));
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, ifindex, network, plen, 0, INADDR_ANY));
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, ifindex, network, plen, 0, INADDR_ANY));
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, ifindex, network, plen, metric, INADDR_ANY));
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);
@@ -156,9 +156,9 @@ test_ip4_route (void)
accept_signal (route_added);
/* Add route */
- nmtstp_assert_ip4_route_exists (NULL, FALSE, 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, 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, TRUE, DEVICE_NAME, network, plen, metric, NULL);
accept_signal (route_added);
/* Add route again */
@@ -166,9 +166,9 @@ test_ip4_route (void)
accept_signals (route_changed, 0, 1);
/* Add default route */
- nmtstp_assert_ip4_route_exists (NULL, FALSE, 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, 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, TRUE, DEVICE_NAME, 0, 0, metric, NULL);
accept_signal (route_added);
/* Add default route again */
@@ -207,12 +207,12 @@ test_ip4_route (void)
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, ifindex, network, plen, metric, gateway));
+ 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, ifindex, network, plen, metric, gateway));
free_signal (route_added);
free_signal (route_changed);
@@ -243,9 +243,9 @@ test_ip6_route (void)
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_get (NM_PLATFORM_GET, ifindex, network, plen, metric, &gateway));
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, ifindex, network, plen, metric, &gateway));
accept_signal (route_added);
/* Add route again */
@@ -253,9 +253,9 @@ test_ip6_route (void)
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_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric, &gateway));
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, ifindex, in6addr_any, 0, metric, &gateway));
accept_signal (route_added);
/* Add default route again */
@@ -291,12 +291,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, ifindex, network, plen, metric, &gateway));
+ g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric, &gateway));
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, ifindex, network, plen, metric, &gateway));
free_signal (route_added);
free_signal (route_changed);
@@ -315,8 +315,8 @@ test_ip4_zero_gateway (void)
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, ifindex, nmtst_inet4_from_string ("1.2.3.1"), 32, 0, 0)
+ && nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.2"), 32, 0, 0))
break;
});
diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c
index b81c263c08..6fa5d72bff 100644
--- a/src/tests/test-route-manager.c
+++ b/src/tests/test-route-manager.c
@@ -791,9 +791,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->rx.ifindex, route->r4.network, route->rx.plen, route->rx.metric, route->r4.gateway);
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->rx.ifindex, route->r6.network, route->rx.plen, route->rx.metric, &route->r6.gateway);
if (!has) {
g_assert (!r);