Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Remove routes on an address removal if the routes refere...



details:   https://anonhg.NetBSD.org/src/rev/d1244fd3b1ed
branches:  trunk
changeset: 370160:d1244fd3b1ed
user:      knakahara <knakahara%NetBSD.org@localhost>
date:      Tue Sep 20 02:23:37 2022 +0000

description:
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.

diffstat:

 sys/net/if.c       |   6 ++--
 sys/net/route.c    |  58 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 sys/net/route.h    |   6 +++-
 sys/netinet/in.c   |  32 +++++++++++++++++++++++++++-
 sys/netinet6/in6.c |  32 +++++++++++++++++++++++++++-
 sys/nfs/nfs_boot.c |   6 ++--
 6 files changed, 125 insertions(+), 15 deletions(-)

diffs (truncated from 314 to 300 lines):

diff -r 0f4ed5a7514c -r d1244fd3b1ed sys/net/if.c
--- a/sys/net/if.c      Mon Sep 19 22:30:19 2022 +0000
+++ b/sys/net/if.c      Tue Sep 20 02:23:37 2022 +0000
@@ -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 @@
 
        /* 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])
diff -r 0f4ed5a7514c -r d1244fd3b1ed sys/net/route.c
--- a/sys/net/route.c   Mon Sep 19 22:30:19 2022 +0000
+++ b/sys/net/route.c   Tue Sep 20 02:23:37 2022 +0000
@@ -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 @@
 
 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 @@
                        return;
                }
                rt_ref(rt);
+               RT_REFCNT_TRACE(rt);
                splx(s);
                RT_UNLOCK();
 
@@ -2316,12 +2317,16 @@
                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 @@
        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)
 {
diff -r 0f4ed5a7514c -r d1244fd3b1ed sys/net/route.h
--- a/sys/net/route.h   Mon Sep 19 22:30:19 2022 +0000
+++ b/sys/net/route.h   Tue Sep 20 02:23:37 2022 +0000
@@ -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 @@
 
 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
diff -r 0f4ed5a7514c -r d1244fd3b1ed sys/netinet/in.c
--- a/sys/netinet/in.c  Mon Sep 19 22:30:19 2022 +0000
+++ b/sys/netinet/in.c  Tue Sep 20 02:23:37 2022 +0000
@@ -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 @@
        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 @@
                        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 @@
         */
        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;
 }
 
diff -r 0f4ed5a7514c -r d1244fd3b1ed sys/netinet6/in6.c
--- a/sys/netinet6/in6.c        Mon Sep 19 22:30:19 2022 +0000
+++ b/sys/netinet6/in6.c        Tue Sep 20 02:23:37 2022 +0000
@@ -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 @@
        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 @@
 
                        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 @@
         */
        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;
 }
 
diff -r 0f4ed5a7514c -r d1244fd3b1ed sys/nfs/nfs_boot.c
--- a/sys/nfs/nfs_boot.c        Mon Sep 19 22:30:19 2022 +0000
+++ b/sys/nfs/nfs_boot.c        Tue Sep 20 02:23:37 2022 +0000
@@ -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>



Home | Main Index | Thread Index | Old Index