Source-Changes-HG archive

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

[src/trunk]: src/sys/net Implement address agnostic Neighbor Detection.



details:   https://anonhg.NetBSD.org/src/rev/3e1c56c0b619
branches:  trunk
changeset: 938580:3e1c56c0b619
user:      roy <roy%NetBSD.org@localhost>
date:      Fri Sep 11 14:59:22 2020 +0000

description:
Implement address agnostic Neighbor Detection.

This is heavily based on IPv6 Neighbor Detection and allows per protocol
timers which also facilitate Neighor Unreachability Detection.

diffstat:

 sys/net/Makefile  |    7 +-
 sys/net/files.net |    3 +-
 sys/net/nd.c      |  420 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/net/nd.h      |   98 ++++++++++++
 4 files changed, 524 insertions(+), 4 deletions(-)

diffs (truncated from 564 to 300 lines):

diff -r f759a10495a2 -r 3e1c56c0b619 sys/net/Makefile
--- a/sys/net/Makefile  Fri Sep 11 14:29:00 2020 +0000
+++ b/sys/net/Makefile  Fri Sep 11 14:59:22 2020 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: Makefile,v 1.43 2020/08/20 21:21:32 riastradh Exp $
+#      $NetBSD: Makefile,v 1.44 2020/09/11 14:59:22 roy Exp $
 
 INCSDIR= /usr/include/net
 
@@ -6,8 +6,9 @@
        if_bridgevar.h if_dl.h if_ether.h if_gif.h \
        if_gre.h if_ieee1394.h if_ipsec.h if_llc.h if_media.h if_mpls.h \
        if_pflog.h if_ppp.h if_pppoe.h if_l2tp.h if_sppp.h if_srt.h if_stats.h \
-       if_stf.h if_tap.h if_tun.h if_types.h if_vlanvar.h if_wg.h net_stats.h \
-       netisr.h pfil.h pfkeyv2.h pfvar.h ppp-comp.h ppp_defs.h radix.h \
+       if_stf.h if_tap.h if_tun.h if_types.h if_vlanvar.h if_wg.h \
+       nd.h net_stats.h netisr.h \
+       pfil.h pfkeyv2.h pfvar.h ppp-comp.h ppp_defs.h radix.h \
        raw_cb.h route.h slcompress.h slip.h zlib.h
 
 SUBDIR=        agr npf
diff -r f759a10495a2 -r 3e1c56c0b619 sys/net/files.net
--- a/sys/net/files.net Fri Sep 11 14:29:00 2020 +0000
+++ b/sys/net/files.net Fri Sep 11 14:59:22 2020 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.net,v 1.26 2020/08/20 21:21:32 riastradh Exp $
+#      $NetBSD: files.net,v 1.27 2020/09/11 14:59:22 roy Exp $
 
 # XXX CLEANUP
 define net
@@ -34,6 +34,7 @@
 file   net/if_vlan.c                   vlan                    needs-flag
 file   net/if_pppoe.c                  pppoe                   needs-flag
 file   net/if_wg.c                     wg                      needs-flag
+file   net/nd.c                        inet | inet6
 file   net/pfil.c                      net
 file   net/ppp-deflate.c               ppp & ppp_deflate
 file   net/ppp_tty.c                   ppp
diff -r f759a10495a2 -r 3e1c56c0b619 sys/net/nd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/nd.c      Fri Sep 11 14:59:22 2020 +0000
@@ -0,0 +1,420 @@
+/* $NetBSD: */
+
+/*
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Roy Marples.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: nd.c,v 1.1 2020/09/11 14:59:22 roy Exp $");
+
+#include <sys/callout.h>
+#include <sys/mbuf.h>
+#include <sys/socketvar.h> /* for softnet_lock */
+
+#include <net/if_llatbl.h>
+#include <net/nd.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+static struct nd_domain *nd_domains[AF_MAX];
+
+static int nd_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */
+
+static void nd_set_timertick(struct llentry *, time_t);
+static struct nd_domain *nd_find_domain(int);
+
+static void
+nd_timer(void *arg)
+{
+       struct llentry *ln = arg;
+       struct nd_domain *nd;
+       struct ifnet *ifp = NULL;
+       struct psref psref;
+       struct mbuf *m = NULL;
+       bool send_ns = false, missed = false;
+       union nd_addr taddr, *daddrp = NULL;
+
+       SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
+       LLE_WLOCK(ln);
+
+       if (!(ln->la_flags & LLE_LINKED))
+               goto out;
+       if (ln->ln_ntick > 0) {
+               nd_set_timer(ln, ND_TIMER_TICK);
+               goto out;
+       }
+
+       nd = nd_find_domain(ln->lle_tbl->llt_af);
+       ifp = ln->lle_tbl->llt_ifp;
+       KASSERT(ifp != NULL);
+       if_acquire(ifp, &psref);
+
+       memcpy(&taddr, &ln->r_l3addr, sizeof(taddr));
+
+       switch (ln->ln_state) {
+       case ND_LLINFO_WAITDELETE:
+               LLE_REMREF(ln);
+               nd->nd_free(ln, 0);
+               ln = NULL;
+               break;
+
+       case ND_LLINFO_INCOMPLETE:
+               if (ln->ln_asked++ < nd->nd_mmaxtries) {
+                       send_ns = true;
+                       break;
+               }
+
+               if (ln->ln_hold) {
+                       struct mbuf *m0, *mnxt;
+
+                       /*
+                        * Assuming every packet in ln_hold
+                        * has the same IP header.
+                        */
+                       m = ln->ln_hold;
+                       for (m0 = m->m_nextpkt; m0 != NULL; m0 = mnxt) {
+                               mnxt = m0->m_nextpkt;
+                               m0->m_nextpkt = NULL;
+                               m_freem(m0);
+                       }
+
+                       m->m_nextpkt = NULL;
+                       ln->ln_hold = NULL;
+               }
+
+               missed = true;
+               ln->ln_state = ND_LLINFO_WAITDELETE;
+               if (ln->ln_asked == nd->nd_mmaxtries)
+                       nd_set_timer(ln, ND_TIMER_RETRANS);
+               else
+                       send_ns = true;
+               break;
+
+       case ND_LLINFO_REACHABLE:
+               if (!ND_IS_LLINFO_PERMANENT(ln)) {
+                       ln->ln_state = ND_LLINFO_STALE;
+                       nd_set_timer(ln, ND_TIMER_GC);
+               }
+               break;
+
+       case ND_LLINFO_PURGE: /* FALLTHROUGH */
+       case ND_LLINFO_STALE:
+               if (!ND_IS_LLINFO_PERMANENT(ln)) {
+                       LLE_REMREF(ln);
+                       nd->nd_free(ln, 1);
+                       ln = NULL;
+               }
+               break;
+
+       case ND_LLINFO_DELAY:
+               if (nd->nd_nud_enabled(ifp)) {
+                       ln->ln_asked = 1;
+                       ln->ln_state = ND_LLINFO_PROBE;
+                       send_ns = true;
+                       daddrp = &taddr;
+               } else {
+                       ln->ln_state = ND_LLINFO_STALE;
+                       nd_set_timer(ln, ND_TIMER_GC);
+               }
+               break;
+
+       case ND_LLINFO_PROBE:
+               if (ln->ln_asked < nd->nd_umaxtries) {
+                       ln->ln_asked++;
+                       send_ns = true;
+                       daddrp = &taddr;
+               } else {
+                       LLE_REMREF(ln);
+                       nd->nd_free(ln, 0);
+                       ln = NULL;
+               }
+               break;
+       }
+
+       if (send_ns) {
+               uint8_t lladdr[255], *lladdrp;
+               union nd_addr src, *psrc;
+
+               nd_set_timer(ln, ND_TIMER_RETRANS);
+               if (ln->ln_state > ND_LLINFO_INCOMPLETE &&
+                   ln->la_flags & LLE_VALID)
+               {
+                       KASSERT(sizeof(lladdr) >= ifp->if_addrlen);
+                       memcpy(lladdr, &ln->ll_addr, ifp->if_addrlen);
+                       lladdrp = lladdr;
+               } else
+                       lladdrp = NULL;
+               psrc = nd->nd_holdsrc(ln, &src);
+               LLE_FREE_LOCKED(ln);
+               ln = NULL;
+               nd->nd_output(ifp, daddrp, &taddr, lladdrp, psrc);
+       }
+
+out:
+       if (ln != NULL)
+               LLE_FREE_LOCKED(ln);
+       SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
+
+       if (missed)
+               nd->nd_missed(ifp, &taddr, m);
+       if (ifp != NULL)
+               if_release(ifp, &psref);
+}
+
+static void
+nd_set_timertick(struct llentry *ln, time_t xtick)
+{
+
+       CTASSERT(sizeof(time_t) > sizeof(int));
+       KASSERT(xtick >= 0);
+
+       /*
+        * We have to take care of a reference leak which occurs if
+        * callout_reset overwrites a pending callout schedule.  Unfortunately
+        * we don't have a mean to know the overwrite, so we need to know it
+        * using callout_stop.  We need to call callout_pending first to exclude
+        * the case that the callout has never been scheduled.
+        */
+       if (callout_pending(&ln->la_timer)) {
+               bool expired;
+
+               expired = callout_stop(&ln->la_timer);
+               if (!expired)
+                       LLE_REMREF(ln);
+       }
+
+       ln->ln_expire = time_uptime + xtick / hz;
+       LLE_ADDREF(ln);
+       if (xtick > INT_MAX) {
+               ln->ln_ntick = xtick - INT_MAX;
+               xtick = INT_MAX;
+       } else {
+               ln->ln_ntick = 0;
+       }
+       callout_reset(&ln->ln_timer_ch, xtick, nd_timer, ln);
+}
+
+void
+nd_set_timer(struct llentry *ln, int type)
+{
+       time_t xtick;
+       struct ifnet *ifp;
+       struct nd_domain *nd;
+
+       LLE_WLOCK_ASSERT(ln);
+
+       ifp = ln->lle_tbl->llt_ifp;
+       nd = nd_find_domain(ln->lle_tbl->llt_af);
+
+       switch (type) {
+       case ND_TIMER_IMMEDIATE:
+               xtick = 0;
+               break;
+       case ND_TIMER_TICK:
+               xtick = ln->ln_ntick;
+               break;
+       case ND_TIMER_RETRANS:
+               xtick = nd->nd_retrans(ifp) * hz / 1000;
+               break;
+       case ND_TIMER_REACHABLE:
+               xtick = nd->nd_reachable(ifp) * hz / 1000;
+               break;
+       case ND_TIMER_EXPIRE:
+               if (ln->ln_expire > time_uptime)
+                       xtick = (ln->ln_expire - time_uptime) * hz;
+               else
+                       xtick = nd_gctimer * hz;
+               break;
+       case ND_TIMER_DELAY:
+               xtick = nd->nd_delay * hz;
+               break;
+       case ND_TIMER_GC:
+               xtick = nd_gctimer * hz;
+               break;



Home | Main Index | Thread Index | Old Index