Commit 8aafa7a0 authored by Alexander V. Chernikov's avatar Alexander V. Chernikov
Browse files

Flush remaining routes from the routing table during VNET shutdown.

Summary:
This fixes rtentry leak for the cloned interfaces created inside the
 VNET.

Loopback teardown order is `SI_SUB_INIT_IF`, which happens after `SI_SUB_PROTO_DOMAIN` (route table teardown).
Thus, any route table operations are too late to schedule.
As the intent of the vnet teardown procedures to minimise the amount of effort by doing global cleanups instead of per-interface ones, address this by adding a relatively light-weight routing table cleanup function, `rib_flush_routes()`.
It removes all remaining routes from the routing table and schedules the deletion, which will happen later, when `rtables_destroy()` waits for the current epoch to finish.

Test Plan:
```
set_skip:set_skip_group_lo  ->  passed  [0.053s]
tail -n 200 /var/log/messages | grep rtentry
```

PR:	253998
Reported by:	rashey at superbox.pl
Reviewed By: kp
Differential Revision: https://reviews.freebsd.org/D29116

(cherry picked from commit b1d63265)
parent d81b3bb4
...@@ -495,21 +495,6 @@ rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg) ...@@ -495,21 +495,6 @@ rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg)
return (1); return (1);
} }
/*
* Delete all remaining routes using this interface
* Unfortuneatly the only way to do this is to slog through
* the entire routing table looking for routes which point
* to this interface...oh well...
*/
void
rt_flushifroutes_af(struct ifnet *ifp, int af)
{
KASSERT((af >= 1 && af <= AF_MAX), ("%s: af %d not >= 1 and <= %d",
__func__, af, AF_MAX));
rib_foreach_table_walk_del(af, rt_ifdelroute, ifp);
}
void void
rt_flushifroutes(struct ifnet *ifp) rt_flushifroutes(struct ifnet *ifp)
{ {
......
...@@ -429,7 +429,6 @@ struct sockaddr *rtsock_fix_netmask(const struct sockaddr *dst, ...@@ -429,7 +429,6 @@ struct sockaddr *rtsock_fix_netmask(const struct sockaddr *dst,
void rt_updatemtu(struct ifnet *); void rt_updatemtu(struct ifnet *);
void rt_flushifroutes_af(struct ifnet *, int);
void rt_flushifroutes(struct ifnet *ifp); void rt_flushifroutes(struct ifnet *ifp);
/* XXX MRT NEW VERSIONS THAT USE FIBs /* XXX MRT NEW VERSIONS THAT USE FIBs
...@@ -442,6 +441,7 @@ int rib_lookup_info(uint32_t, const struct sockaddr *, uint32_t, uint32_t, ...@@ -442,6 +441,7 @@ int rib_lookup_info(uint32_t, const struct sockaddr *, uint32_t, uint32_t,
void rib_free_info(struct rt_addrinfo *info); void rib_free_info(struct rt_addrinfo *info);
/* New API */ /* New API */
void rib_flush_routes_family(int family);
struct nhop_object *rib_lookup(uint32_t fibnum, const struct sockaddr *dst, struct nhop_object *rib_lookup(uint32_t fibnum, const struct sockaddr *dst,
uint32_t flags, uint32_t flowid); uint32_t flags, uint32_t flowid);
#endif #endif
......
...@@ -1341,6 +1341,42 @@ rib_walk_del(u_int fibnum, int family, rib_filter_f_t *filter_f, void *arg, bool ...@@ -1341,6 +1341,42 @@ rib_walk_del(u_int fibnum, int family, rib_filter_f_t *filter_f, void *arg, bool
NET_EPOCH_EXIT(et); NET_EPOCH_EXIT(et);
} }
static int
rt_delete_unconditional(struct radix_node *rn, void *arg)
{
struct rtentry *rt = RNTORT(rn);
struct rib_head *rnh = (struct rib_head *)arg;
rn = rnh->rnh_deladdr(rt_key(rt), rt_mask(rt), &rnh->head);
if (RNTORT(rn) == rt)
rtfree(rt);
return (0);
}
/*
* Removes all routes from the routing table without executing notifications.
* rtentres will be removed after the end of a current epoch.
*/
static void
rib_flush_routes(struct rib_head *rnh)
{
RIB_WLOCK(rnh);
rnh->rnh_walktree(&rnh->head, rt_delete_unconditional, rnh);
RIB_WUNLOCK(rnh);
}
void
rib_flush_routes_family(int family)
{
struct rib_head *rnh;
for (uint32_t fibnum = 0; fibnum < rt_numfibs; fibnum++) {
if ((rnh = rt_tables_get_rnh(fibnum, family)) != NULL)
rib_flush_routes(rnh);
}
}
static void static void
rib_notify(struct rib_head *rnh, enum rib_subscription_type type, rib_notify(struct rib_head *rnh, enum rib_subscription_type type,
struct rib_cmd_info *rc) struct rib_cmd_info *rc)
......
...@@ -379,7 +379,6 @@ ip_init(void) ...@@ -379,7 +379,6 @@ ip_init(void)
static void static void
ip_destroy(void *unused __unused) ip_destroy(void *unused __unused)
{ {
struct ifnet *ifp;
int error; int error;
#ifdef RSS #ifdef RSS
...@@ -405,10 +404,7 @@ ip_destroy(void *unused __unused) ...@@ -405,10 +404,7 @@ ip_destroy(void *unused __unused)
in_ifscrub_all(); in_ifscrub_all();
/* Make sure the IPv4 routes are gone as well. */ /* Make sure the IPv4 routes are gone as well. */
IFNET_RLOCK(); rib_flush_routes_family(AF_INET);
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link)
rt_flushifroutes_af(ifp, AF_INET);
IFNET_RUNLOCK();
/* Destroy IP reassembly queue. */ /* Destroy IP reassembly queue. */
ipreass_destroy(); ipreass_destroy();
......
...@@ -386,11 +386,12 @@ ip6_destroy(void *unused __unused) ...@@ -386,11 +386,12 @@ ip6_destroy(void *unused __unused)
/* IF_ADDR_UNLOCK(ifp); */ /* IF_ADDR_UNLOCK(ifp); */
in6_ifdetach_destroy(ifp); in6_ifdetach_destroy(ifp);
mld_domifdetach(ifp); mld_domifdetach(ifp);
/* Make sure any routes are gone as well. */
rt_flushifroutes_af(ifp, AF_INET6);
} }
IFNET_RUNLOCK(); IFNET_RUNLOCK();
/* Make sure any routes are gone as well. */
rib_flush_routes_family(AF_INET6);
frag6_destroy(); frag6_destroy();
nd6_destroy(); nd6_destroy();
in6_ifattach_destroy(); in6_ifattach_destroy();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment