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.
This commit is contained in:
Dan Williams
2013-07-31 12:11:51 -05:00
parent 802d4cdad2
commit 42b4323902
5 changed files with 26 additions and 1 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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))