From 42b4323902f21b15f7c9878524ddde4588d1dbc4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 31 Jul 2013 12:11:51 -0500 Subject: [PATCH] platform: work around missing kernel netlink notifications of default route changes It appears the kernel does not send notifications via netlink if the default route is removed in some cases. This causes the platform route cache to become stale, and thus when the default route is reset by NM the platform thinks the route already exists, and does not add it. But the route doesn't exist, becuase the kernel silently removed it without telling anyone. Fix that with a big hammer by flushing/refilling the route cache when devices are deactivated (deletion of their addresses causes the default route to be removed by the kernel) and when the default route is updated by NM itself. Pavel: if we find a more granular method, we should probably revert this as the cache refill can be expensive. --- src/devices/nm-device.c | 1 + src/nm-policy.c | 1 + src/platform/nm-linux-platform.c | 13 ++++++++++++- src/platform/nm-platform.c | 9 +++++++++ src/platform/nm-platform.h | 3 +++ 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5ac2b23de8..e48672d07d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -4140,6 +4140,7 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason) /* Clean up nameservers and addresses */ nm_device_set_ip4_config (self, NULL, TRUE, &ignored); nm_device_set_ip6_config (self, NULL, TRUE, &ignored); + nm_platform_route_cache_update (); /* Clear legacy IPv4 address property */ priv->ip4_address = 0; diff --git a/src/nm-policy.c b/src/nm-policy.c index 849a1dee16..b51f41c165 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -829,6 +829,7 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) update_ip4_routing (policy, force_update); update_ip6_routing (policy, force_update); + nm_platform_route_cache_update (); /* Update the system hostname */ update_system_hostname (policy, policy->default_device4, policy->default_device6); diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 7c341038f4..20cf7fe5ca 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -244,7 +244,7 @@ add_kernel_object (struct nl_sock *sock, struct nl_object *object) return rtnl_addr_add (sock, (struct rtnl_addr *) object, NLM_F_CREATE | NLM_F_REPLACE); case IP4_ROUTE: case IP6_ROUTE: - return rtnl_route_add (sock, (struct rtnl_route *) object, NLM_F_CREATE); + return rtnl_route_add (sock, (struct rtnl_route *) object, NLM_F_CREATE | NLM_F_REPLACE); default: g_assert_not_reached (); } @@ -2221,6 +2221,16 @@ ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, in return ip_route_exists (platform, AF_INET6, ifindex, &network, plen, metric); } +static void +route_cache_update (NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv; + + priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + + nl_cache_refill (priv->nlh, priv->route_cache); +} + /******************************************************************/ #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) @@ -2577,4 +2587,5 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->ip6_route_delete = ip6_route_delete; platform_class->ip4_route_exists = ip4_route_exists; platform_class->ip6_route_exists = ip6_route_exists; + platform_class->route_cache_update = route_cache_update; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 95de5040fb..cb1535dcd8 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1587,6 +1587,15 @@ nm_platform_route_flush (int ifindex) && nm_platform_ip6_route_sync (ifindex, NULL); } +void +nm_platform_route_cache_update (void) +{ + g_return_if_fail (platform); + + if (NM_PLATFORM_GET_CLASS (platform)->route_cache_update) + NM_PLATFORM_GET_CLASS (platform)->route_cache_update (platform); +} + /******************************************************************/ static void diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index dde754f904..c14e17b7a7 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -282,6 +282,8 @@ typedef struct { gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric); gboolean (*ip4_route_exists) (NMPlatform *, int ifindex, in_addr_t network, int plen, int metric); gboolean (*ip6_route_exists) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric); + + void (*route_cache_update) (NMPlatform *); } NMPlatformClass; /* NMPlatform signals @@ -408,6 +410,7 @@ gboolean nm_platform_ip6_route_exists (int ifindex, struct in6_addr network, int gboolean nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes); gboolean nm_platform_ip6_route_sync (int ifindex, const GArray *known_routes); gboolean nm_platform_route_flush (int ifindex); +void nm_platform_route_cache_update (void); #define auto_g_free __attribute__((cleanup(put_g_free))) static void __attribute__((unused))