Module Name: src Committed By: knakahara Date: Tue Sep 20 02:23:38 UTC 2022
Modified Files: src/sys/net: if.c route.c route.h src/sys/netinet: in.c src/sys/netinet6: in6.c src/sys/nfs: nfs_boot.c Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.525 -r1.526 src/sys/net/if.c cvs rdiff -u -r1.233 -r1.234 src/sys/net/route.c cvs rdiff -u -r1.131 -r1.132 src/sys/net/route.h cvs rdiff -u -r1.242 -r1.243 src/sys/netinet/in.c cvs rdiff -u -r1.285 -r1.286 src/sys/netinet6/in6.c cvs rdiff -u -r1.88 -r1.89 src/sys/nfs/nfs_boot.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if.c diff -u src/sys/net/if.c:1.525 src/sys/net/if.c:1.526 --- src/sys/net/if.c:1.525 Sat Sep 3 02:53:18 2022 +++ src/sys/net/if.c Tue Sep 20 02:23:37 2022 @@ -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]) Index: src/sys/net/route.c diff -u src/sys/net/route.c:1.233 src/sys/net/route.c:1.234 --- src/sys/net/route.c:1.233 Mon Aug 29 23:48:18 2022 +++ src/sys/net/route.c Tue Sep 20 02:23:37 2022 @@ -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 rtent 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 fa return; } rt_ref(rt); + RT_REFCNT_TRACE(rt); splx(s); RT_UNLOCK(); @@ -2316,12 +2317,16 @@ rt_delete_matched_entries(sa_family_t fa 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, i 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) { Index: src/sys/net/route.h diff -u src/sys/net/route.h:1.131 src/sys/net/route.h:1.132 --- src/sys/net/route.h:1.131 Mon Aug 29 09:14:02 2022 +++ src/sys/net/route.h Tue Sep 20 02:23:37 2022 @@ -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 Index: src/sys/netinet/in.c diff -u src/sys/netinet/in.c:1.242 src/sys/netinet/in.c:1.243 --- src/sys/netinet/in.c:1.242 Tue Sep 21 15:05:41 2021 +++ src/sys/netinet/in.c Tue Sep 20 02:23:37 2022 @@ -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, i 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; } Index: src/sys/netinet6/in6.c diff -u src/sys/netinet6/in6.c:1.285 src/sys/netinet6/in6.c:1.286 --- src/sys/netinet6/in6.c:1.285 Sun Dec 5 04:42:55 2021 +++ src/sys/netinet6/in6.c Tue Sep 20 02:23:37 2022 @@ -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 *targe 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 *targe */ 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; } Index: src/sys/nfs/nfs_boot.c diff -u src/sys/nfs/nfs_boot.c:1.88 src/sys/nfs/nfs_boot.c:1.89 --- src/sys/nfs/nfs_boot.c:1.88 Thu May 17 02:34:31 2018 +++ src/sys/nfs/nfs_boot.c Tue Sep 20 02:23:37 2022 @@ -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); } /*