Remove routes on an address removal if the routes referencing to the address. Implemented by ozaki-r@n.o.
A route that has a gateway is on a connected route can be invalid if the connected route is deleted, i.e., an associated address is removed. Traditionally NetBSD doesn't sweep such a route on the address removal. Sending packets over the route fails with "No route to host". Also the route holds an orphan ifaddr as rt_ifa that is destructed say by in_purgeaddr. If the same address is assgined again in such a state, there can be two different ifaddr objects with the same address. Until recently it's not a big problem because we can send packets anyway. However after MP-ification of the network stack, we can't send packets because we strictly check if rt_ifa (i.e., the (old) ifaddr) is valid. This change automatically removes such routes on a removal of an associated address to avoid keeping inconsistent routes.
This commit is contained in:
parent
75ded7d598
commit
bf4e44ab86
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: if.c,v 1.525 2022/09/03 02:53:18 thorpej Exp $ */
|
||||
/* $NetBSD: if.c,v 1.526 2022/09/20 02:23:37 knakahara Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -90,7 +90,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.525 2022/09/03 02:53:18 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.526 2022/09/20 02:23:37 knakahara Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_inet.h"
|
||||
|
@ -1479,7 +1479,7 @@ restart:
|
|||
|
||||
/* Delete stray routes from the routing table. */
|
||||
for (i = 0; i <= AF_MAX; i++)
|
||||
rt_delete_matched_entries(i, if_delroute_matcher, ifp);
|
||||
rt_delete_matched_entries(i, if_delroute_matcher, ifp, false);
|
||||
|
||||
DOMAIN_FOREACH(dp) {
|
||||
if (dp->dom_ifdetach != NULL && ifp->if_afdata[dp->dom_family])
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: route.c,v 1.233 2022/08/29 23:48:18 knakahara Exp $ */
|
||||
/* $NetBSD: route.c,v 1.234 2022/09/20 02:23:37 knakahara Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -97,7 +97,7 @@
|
|||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.233 2022/08/29 23:48:18 knakahara Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.234 2022/09/20 02:23:37 knakahara Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#ifdef RTFLUSH_DEBUG
|
||||
|
@ -2291,7 +2291,7 @@ rt_check_reject_route(const struct rtentry *rt, const struct ifnet *ifp)
|
|||
|
||||
void
|
||||
rt_delete_matched_entries(sa_family_t family, int (*f)(struct rtentry *, void *),
|
||||
void *v)
|
||||
void *v, bool notify)
|
||||
{
|
||||
|
||||
for (;;) {
|
||||
|
@ -2308,6 +2308,7 @@ rt_delete_matched_entries(sa_family_t family, int (*f)(struct rtentry *, void *)
|
|||
return;
|
||||
}
|
||||
rt_ref(rt);
|
||||
RT_REFCNT_TRACE(rt);
|
||||
splx(s);
|
||||
RT_UNLOCK();
|
||||
|
||||
|
@ -2316,12 +2317,16 @@ rt_delete_matched_entries(sa_family_t family, int (*f)(struct rtentry *, void *)
|
|||
if (error == 0) {
|
||||
KASSERT(retrt == rt);
|
||||
KASSERT((retrt->rt_flags & RTF_UP) == 0);
|
||||
if (notify)
|
||||
rt_newmsg(RTM_DELETE, retrt);
|
||||
retrt->rt_ifp = NULL;
|
||||
rt_unref(rt);
|
||||
RT_REFCNT_TRACE(rt);
|
||||
rt_free(retrt);
|
||||
} else if (error == ESRCH) {
|
||||
/* Someone deleted the entry already. */
|
||||
rt_unref(rt);
|
||||
RT_REFCNT_TRACE(rt);
|
||||
} else {
|
||||
log(LOG_ERR, "%s: unable to delete rtentry @ %p, "
|
||||
"error = %d\n", rt->rt_ifp->if_xname, rt, error);
|
||||
|
@ -2338,6 +2343,53 @@ rt_walktree_locked(sa_family_t family, int (*f)(struct rtentry *, void *),
|
|||
return rtbl_walktree(family, f, v);
|
||||
}
|
||||
|
||||
void
|
||||
rt_replace_ifa_matched_entries(sa_family_t family,
|
||||
int (*f)(struct rtentry *, void *), void *v, struct ifaddr *ifa)
|
||||
{
|
||||
|
||||
for (;;) {
|
||||
int s;
|
||||
#ifdef NET_MPSAFE
|
||||
int error;
|
||||
#endif
|
||||
struct rtentry *rt;
|
||||
|
||||
RT_RLOCK();
|
||||
s = splsoftnet();
|
||||
rt = rtbl_search_matched_entry(family, f, v);
|
||||
if (rt == NULL) {
|
||||
splx(s);
|
||||
RT_UNLOCK();
|
||||
return;
|
||||
}
|
||||
rt_ref(rt);
|
||||
RT_REFCNT_TRACE(rt);
|
||||
splx(s);
|
||||
RT_UNLOCK();
|
||||
|
||||
#ifdef NET_MPSAFE
|
||||
error = rt_update_prepare(rt);
|
||||
if (error == 0) {
|
||||
rt_replace_ifa(rt, ifa);
|
||||
rt_update_finish(rt);
|
||||
rt_newmsg(RTM_CHANGE, rt);
|
||||
} else {
|
||||
/*
|
||||
* If error != 0, the rtentry is being
|
||||
* destroyed, so doing nothing doesn't
|
||||
* matter.
|
||||
*/
|
||||
}
|
||||
#else
|
||||
rt_replace_ifa(rt, ifa);
|
||||
rt_newmsg(RTM_CHANGE, rt);
|
||||
#endif
|
||||
rt_unref(rt);
|
||||
RT_REFCNT_TRACE(rt);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
rt_walktree(sa_family_t family, int (*f)(struct rtentry *, void *), void *v)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: route.h,v 1.131 2022/08/29 09:14:02 knakahara Exp $ */
|
||||
/* $NetBSD: route.h,v 1.132 2022/09/20 02:23:37 knakahara Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
|
@ -463,7 +463,9 @@ struct sockaddr *
|
|||
|
||||
int rt_check_reject_route(const struct rtentry *, const struct ifnet *);
|
||||
void rt_delete_matched_entries(sa_family_t,
|
||||
int (*)(struct rtentry *, void *), void *);
|
||||
int (*)(struct rtentry *, void *), void *, bool);
|
||||
void rt_replace_ifa_matched_entries(sa_family_t,
|
||||
int (*)(struct rtentry *, void *), void *, struct ifaddr *);
|
||||
int rt_walktree(sa_family_t, int (*)(struct rtentry *, void *), void *);
|
||||
|
||||
static __inline void
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: in.c,v 1.242 2021/09/21 15:05:41 christos Exp $ */
|
||||
/* $NetBSD: in.c,v 1.243 2022/09/20 02:23:37 knakahara Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
|
@ -91,7 +91,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.242 2021/09/21 15:05:41 christos Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.243 2022/09/20 02:23:37 knakahara Exp $");
|
||||
|
||||
#include "arp.h"
|
||||
|
||||
|
@ -1347,6 +1347,17 @@ in_addprefix(struct in_ifaddr *target, int flags)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
in_rt_ifa_matcher(struct rtentry *rt, void *v)
|
||||
{
|
||||
struct ifaddr *ifa = v;
|
||||
|
||||
if (rt->rt_ifa == ifa)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* remove a route to prefix ("connected route" in cisco terminology).
|
||||
* re-installs the route by using another interface address, if there's one
|
||||
|
@ -1403,6 +1414,16 @@ in_scrubprefix(struct in_ifaddr *target)
|
|||
if (error == 0)
|
||||
ia->ia_flags |= IFA_ROUTE;
|
||||
|
||||
if (!ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING))
|
||||
goto skip;
|
||||
/*
|
||||
* Replace rt_ifa of routes that have the removing address
|
||||
* with the new address.
|
||||
*/
|
||||
rt_replace_ifa_matched_entries(AF_INET,
|
||||
in_rt_ifa_matcher, &target->ia_ifa, &ia->ia_ifa);
|
||||
|
||||
skip:
|
||||
ia4_release(ia, &psref);
|
||||
curlwp_bindx(bound);
|
||||
|
||||
|
@ -1416,6 +1437,13 @@ in_scrubprefix(struct in_ifaddr *target)
|
|||
*/
|
||||
rtinit(&target->ia_ifa, RTM_DELETE, rtinitflags(target));
|
||||
target->ia_flags &= ~IFA_ROUTE;
|
||||
|
||||
if (ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING)) {
|
||||
/* Remove routes that have the removing address as rt_ifa. */
|
||||
rt_delete_matched_entries(AF_INET, in_rt_ifa_matcher,
|
||||
&target->ia_ifa, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: in6.c,v 1.285 2021/12/05 04:42:55 msaitoh Exp $ */
|
||||
/* $NetBSD: in6.c,v 1.286 2022/09/20 02:23:37 knakahara Exp $ */
|
||||
/* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -62,7 +62,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.285 2021/12/05 04:42:55 msaitoh Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.286 2022/09/20 02:23:37 knakahara Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_inet.h"
|
||||
|
@ -279,6 +279,17 @@ in6_ifaddprefix(struct in6_ifaddr *ia)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
in6_rt_ifa_matcher(struct rtentry *rt, void *v)
|
||||
{
|
||||
struct ifaddr *ifa = v;
|
||||
|
||||
if (rt->rt_ifa == ifa)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Delete network prefix route if present.
|
||||
* Re-add it to another address if the prefix matches. */
|
||||
static int
|
||||
|
@ -319,6 +330,16 @@ in6_ifremprefix(struct in6_ifaddr *target)
|
|||
|
||||
error = in6_ifaddprefix(ia);
|
||||
|
||||
if (!ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING))
|
||||
goto skip;
|
||||
/*
|
||||
* Replace rt_ifa of routes that have the removing address
|
||||
* with the new address.
|
||||
*/
|
||||
rt_replace_ifa_matched_entries(AF_INET6,
|
||||
in6_rt_ifa_matcher, &target->ia_ifa, &ia->ia_ifa);
|
||||
|
||||
skip:
|
||||
ia6_release(ia, &psref);
|
||||
curlwp_bindx(bound);
|
||||
|
||||
|
@ -332,6 +353,13 @@ in6_ifremprefix(struct in6_ifaddr *target)
|
|||
*/
|
||||
rtinit(&target->ia_ifa, RTM_DELETE, 0);
|
||||
target->ia_flags &= ~IFA_ROUTE;
|
||||
|
||||
if (ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING)) {
|
||||
/* Remove routes that have the removing address as rt_ifa. */
|
||||
rt_delete_matched_entries(AF_INET6, in6_rt_ifa_matcher,
|
||||
&target->ia_ifa, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: nfs_boot.c,v 1.88 2018/05/17 02:34:31 thorpej Exp $ */
|
||||
/* $NetBSD: nfs_boot.c,v 1.89 2022/09/20 02:23:37 knakahara Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
|
||||
|
@ -35,7 +35,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: nfs_boot.c,v 1.88 2018/05/17 02:34:31 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: nfs_boot.c,v 1.89 2022/09/20 02:23:37 knakahara Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_nfs.h"
|
||||
|
@ -576,7 +576,7 @@ void
|
|||
nfs_boot_flushrt(struct ifnet *ifp)
|
||||
{
|
||||
|
||||
rt_delete_matched_entries(AF_INET, nfs_boot_delroute_matcher, ifp);
|
||||
rt_delete_matched_entries(AF_INET, nfs_boot_delroute_matcher, ifp, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue