diff options
author | Thomas Haller <thaller@redhat.com> | 2014-02-23 14:57:50 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-05-19 15:22:50 +0200 |
commit | 019bf7512d0c8ece3e9051f609f10ecc1df7223a (patch) | |
tree | 2ba2d4c981b787c5da0ca5b2de4b0e17a155b083 | |
parent | ff801bcafc43d385bc11890140cfd7eb1e5f0adb (diff) | |
download | NetworkManager-019bf7512d0c8ece3e9051f609f10ecc1df7223a.tar.gz |
platform: improve workaround for deleting IPv4 route with libnl guessing route scope
Previously, we always lookup the cache for libnl objects and used those for
delete_object(). This was necessary, because libnl guesses and overwrites
the IPv4 route scope.
Newer libnl no longer overwrites the scope if set explicitly to RT_SCOPE_NOWHERE.
So, this workaround is no longer needed. Indeed there might be cases, where it is
harmful, because we might guess the wrong scope.
This was fixed in libnl3 in commits
https://github.com/thom311/libnl/commit/85ec9c7ad80c60f4f619472f2bb9d9595da93b26
https://github.com/thom311/libnl/commit/015c4ee59b786fec35118c2a963532b3e05ba5a2
https://bugzilla.gnome.org/show_bug.cgi?id=726273
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | src/platform/nm-linux-platform.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 68ed1966a5..2ecd92bcb7 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1494,17 +1494,13 @@ delete_object (NMPlatform *platform, struct nl_object *obj) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); auto_nl_object struct nl_object *obj_cleanup = obj; - auto_nl_object struct nl_object *cached_object = NULL; - struct nl_object *object; + struct nl_object *object = obj; int object_type; int nle; object_type = object_type_from_nl_object (obj); g_return_val_if_fail (object_type != OBJECT_TYPE_UNKNOWN, FALSE); - cached_object = nm_nl_cache_search (choose_cache_by_type (platform, object_type), obj); - object = cached_object ? cached_object : obj; - switch (object_type) { case OBJECT_TYPE_LINK: nle = rtnl_link_delete (priv->nlh, (struct rtnl_link *) object); @@ -3327,25 +3323,40 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen { in_addr_t gateway = 0; struct nl_object *route = build_rtnl_route (AF_INET, ifindex, &network, plen, &gateway, metric, 0); + uint8_t scope = RT_SCOPE_NOWHERE; g_return_val_if_fail (route, FALSE); - /* When searching for a matching IPv4 route to delete, the kernel - * searches for a matching scope, unless the RTM_DELROUTE message - * specifies RT_SCOPE_NOWHERE (see fib_table_delete()). - * - * However, if we set the scope of @rtnlroute to RT_SCOPE_NOWHERE (or - * leave it unset), rtnl_route_build_msg() will reset the scope to - * rtnl_route_guess_scope() -- which might be the wrong scope. - * - * As a workaround, we set the scope to RT_SCOPE_UNIVERSE, so libnl - * will not overwrite it. But this only works if we guess correctly. - * - * As a better workaround, we don't use @rtnlroute as argument for - * rtnl_route_delete(), but we look into our cache, if we already have - * this route ready. - **/ - rtnl_route_set_scope ((struct rtnl_route *) route, RT_SCOPE_UNIVERSE); + if (!_nl_has_capability (1 /* NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE */)) { + /* When searching for a matching IPv4 route to delete, the kernel + * searches for a matching scope, unless the RTM_DELROUTE message + * specifies RT_SCOPE_NOWHERE (see fib_table_delete()). + * + * However, if we set the scope of @rtnlroute to RT_SCOPE_NOWHERE (or + * leave it unset), rtnl_route_build_msg() will reset the scope to + * rtnl_route_guess_scope() -- which probably guesses wrong. + * + * As a workaround, we look at the cached route and use that scope. + * + * Newer versions of libnl, no longer reset the scope if explicitly set to RT_SCOPE_NOWHERE. + * So, this workaround is only needed unless we have NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE. + **/ + struct nl_object *cached_object; + + cached_object = nm_nl_cache_search (choose_cache_by_type (platform, OBJECT_TYPE_IP4_ROUTE), route); + if (cached_object) { + scope = rtnl_route_get_scope ((struct rtnl_route *) cached_object); + nl_object_put (cached_object); + } + + if (scope == RT_SCOPE_NOWHERE) { + /* If we would set the scope to RT_SCOPE_NOWHERE, libnl would guess the scope. + * But probably it will guess 'link' because we don't set the next hop + * of the route we are about to delete. A better guess is 'global'. */ + scope = RT_SCOPE_UNIVERSE; + } + } + rtnl_route_set_scope ((struct rtnl_route *) route, scope); return delete_object (platform, route); } |