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:
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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))
|
||||
|
Reference in New Issue
Block a user