summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-02-23 14:57:50 +0100
committerThomas Haller <thaller@redhat.com>2014-05-19 15:22:50 +0200
commit019bf7512d0c8ece3e9051f609f10ecc1df7223a (patch)
tree2ba2d4c981b787c5da0ca5b2de4b0e17a155b083
parentff801bcafc43d385bc11890140cfd7eb1e5f0adb (diff)
downloadNetworkManager-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.c53
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);
}