Module Name: src Committed By: roy Date: Fri Sep 11 15:03:33 UTC 2020
Modified Files: src/sys/netinet6: icmp6.c nd6.c nd6.h nd6_nbr.c Log Message: inet6: Use generic Neighor Detection rather than IPv6 specific No functional change intended. To generate a diff of this commit: cvs rdiff -u -r1.246 -r1.247 src/sys/netinet6/icmp6.c cvs rdiff -u -r1.271 -r1.272 src/sys/netinet6/nd6.c cvs rdiff -u -r1.90 -r1.91 src/sys/netinet6/nd6.h cvs rdiff -u -r1.180 -r1.181 src/sys/netinet6/nd6_nbr.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/netinet6/icmp6.c diff -u src/sys/netinet6/icmp6.c:1.246 src/sys/netinet6/icmp6.c:1.247 --- src/sys/netinet6/icmp6.c:1.246 Mon Jul 27 14:52:55 2020 +++ src/sys/netinet6/icmp6.c Fri Sep 11 15:03:33 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: icmp6.c,v 1.246 2020/07/27 14:52:55 roy Exp $ */ +/* $NetBSD: icmp6.c,v 1.247 2020/09/11 15:03:33 roy Exp $ */ /* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */ /* @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.246 2020/07/27 14:52:55 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.247 2020/09/11 15:03:33 roy Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -87,6 +87,7 @@ __KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1. #include <net/route.h> #include <net/if_dl.h> #include <net/if_types.h> +#include <net/nd.h> #include <netinet/in.h> #include <netinet/in_var.h> @@ -98,9 +99,9 @@ __KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1. #include <netinet6/icmp6_private.h> #include <netinet6/mld6_var.h> #include <netinet6/in6_pcb.h> -#include <netinet6/nd6.h> #include <netinet6/in6_ifattach.h> #include <netinet6/ip6protosw.h> +#include <netinet6/nd6.h> #include <netinet6/scope6_var.h> #ifdef IPSEC @@ -2953,7 +2954,6 @@ out: static void sysctl_net_inet6_icmp6_setup(struct sysctllog **clog) { - extern int nd6_maxqueuelen; /* defined in nd6.c */ sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT, @@ -3008,23 +3008,37 @@ sysctl_net_inet6_icmp6_setup(struct sysc CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "nd6_delay", SYSCTL_DESCR("First probe delay time"), - NULL, 0, &nd6_delay, 0, + NULL, 0, &nd6_nd_domain.nd_delay, 0, CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DELAY, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "nd6_mmaxtries", + SYSCTL_DESCR("Number of multicast discovery attempts"), + NULL, 0, &nd6_nd_domain.nd_mmaxtries, 0, + CTL_NET, PF_INET6, IPPROTO_ICMPV6, + ICMPV6CTL_ND6_MMAXTRIES, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "nd6_umaxtries", SYSCTL_DESCR("Number of unicast discovery attempts"), - NULL, 0, &nd6_umaxtries, 0, + NULL, 0, &nd6_nd_domain.nd_umaxtries, 0, CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_UMAXTRIES, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "nd6_mmaxtries", - SYSCTL_DESCR("Number of multicast discovery attempts"), - NULL, 0, &nd6_mmaxtries, 0, + CTLTYPE_INT, "nd6_maxnudhint", + SYSCTL_DESCR("Maximum neighbor unreachable hint count"), + NULL, 0, &nd6_nd_domain.nd_maxnudhint, 0, CTL_NET, PF_INET6, IPPROTO_ICMPV6, - ICMPV6CTL_ND6_MMAXTRIES, CTL_EOL); + ICMPV6CTL_ND6_MAXNUDHINT, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "maxqueuelen", + SYSCTL_DESCR("max packet queue len for a unresolved ND"), + NULL, 1, &nd6_nd_domain.nd_maxqueuelen, 0, + CTL_NET, PF_INET6, IPPROTO_ICMPV6, + ICMPV6CTL_ND6_MAXQLEN, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "nd6_useloopback", @@ -3056,13 +3070,6 @@ sysctl_net_inet6_icmp6_setup(struct sysc ICMPV6CTL_ERRPPSLIMIT, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "nd6_maxnudhint", - SYSCTL_DESCR("Maximum neighbor unreachable hint count"), - NULL, 0, &nd6_maxnudhint, 0, - CTL_NET, PF_INET6, IPPROTO_ICMPV6, - ICMPV6CTL_ND6_MAXNUDHINT, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "mtudisc_hiwat", SYSCTL_DESCR("Low mark on MTU Discovery route timers"), NULL, 0, &icmp6_mtudisc_hiwat, 0, @@ -3098,13 +3105,6 @@ sysctl_net_inet6_icmp6_setup(struct sysc CTL_NET, PF_INET6, IPPROTO_ICMPV6, OICMPV6CTL_ND6_PRLIST, CTL_EOL); #endif - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "maxqueuelen", - SYSCTL_DESCR("max packet queue len for a unresolved ND"), - NULL, 1, &nd6_maxqueuelen, 0, - CTL_NET, PF_INET6, IPPROTO_ICMPV6, - ICMPV6CTL_ND6_MAXQLEN, CTL_EOL); } void Index: src/sys/netinet6/nd6.c diff -u src/sys/netinet6/nd6.c:1.271 src/sys/netinet6/nd6.c:1.272 --- src/sys/netinet6/nd6.c:1.271 Fri Jun 12 11:04:45 2020 +++ src/sys/netinet6/nd6.c Fri Sep 11 15:03:33 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6.c,v 1.271 2020/06/12 11:04:45 roy Exp $ */ +/* $NetBSD: nd6.c,v 1.272 2020/09/11 15:03:33 roy Exp $ */ /* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.271 2020/06/12 11:04:45 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.272 2020/09/11 15:03:33 roy Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -62,6 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.27 #include <net/if_dl.h> #include <net/if_llatbl.h> #include <net/if_types.h> +#include <net/nd.h> #include <net/route.h> #include <net/if_ether.h> #include <net/if_arc.h> @@ -86,19 +87,11 @@ __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.27 /* timer values */ int nd6_prune = 1; /* walk list every 1 seconds */ -int nd6_delay = 5; /* delay first probe time 5 second */ -int nd6_umaxtries = 3; /* maximum unicast query */ -int nd6_mmaxtries = 3; /* maximum multicast query */ int nd6_useloopback = 1; /* use loopback interface for local traffic */ -int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */ /* preventing too many loops in ND option parsing */ int nd6_maxndopt = 10; /* max # of ND options allowed */ -int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ - -int nd6_maxqueuelen = 1; /* max # of packets cached in unresolved ND entries */ - #ifdef ND6_DEBUG int nd6_debug = 1; #else @@ -111,10 +104,16 @@ int nd6_recalc_reachtm_interval = ND6_RE static void nd6_slowtimo(void *); static void nd6_free(struct llentry *, int); -static void nd6_llinfo_timer(void *); +static bool nd6_nud_enabled(struct ifnet *); +static unsigned int nd6_llinfo_reachable(struct ifnet *); +static unsigned int nd6_llinfo_retrans(struct ifnet *); +static union nd_addr *nd6_llinfo_holdsrc(struct llentry *, union nd_addr *); +static void nd6_llinfo_output(struct ifnet *, const union nd_addr *, + const union nd_addr *, const uint8_t *, const union nd_addr *); +static void nd6_llinfo_missed(struct ifnet *, const union nd_addr *, + struct mbuf *); static void nd6_timer(void *); static void nd6_timer_work(struct work *, void *); -static void clear_llinfo_pqueue(struct llentry *); static struct nd_opt_hdr *nd6_option(union nd_opts *); static callout_t nd6_slowtimo_ch; @@ -122,6 +121,22 @@ static callout_t nd6_timer_ch; static struct workqueue *nd6_timer_wq; static struct work nd6_timer_wk; +struct nd_domain nd6_nd_domain = { + .nd_family = AF_INET6, + .nd_delay = 5, /* delay first probe time 5 second */ + .nd_mmaxtries = 3, /* maximum unicast query */ + .nd_umaxtries = 3, /* maximum multicast query */ + .nd_maxnudhint = 0, /* max # of subsequent upper layer hints */ + .nd_maxqueuelen = 1, /* max # of packets in unresolved ND entries */ + .nd_nud_enabled = nd6_nud_enabled, + .nd_reachable = nd6_llinfo_reachable, + .nd_retrans = nd6_llinfo_retrans, + .nd_holdsrc = nd6_llinfo_holdsrc, + .nd_output = nd6_llinfo_output, + .nd_missed = nd6_llinfo_missed, + .nd_free = nd6_free, +}; + MALLOC_DEFINE(M_IP6NDP, "NDP", "IPv6 Neighbour Discovery"); void @@ -129,6 +144,7 @@ nd6_init(void) { int error; + nd_attach_domain(&nd6_nd_domain); nd6_nbr_init(); rw_init(&nd6_lock); @@ -326,44 +342,6 @@ skip1: } /* - * ND6 timer routine to handle ND6 entries - */ -void -nd6_llinfo_settimer(struct llentry *ln, time_t xtick) -{ - - CTASSERT(sizeof(time_t) > sizeof(int)); - LLE_WLOCK_ASSERT(ln); - - 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 = 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; - callout_reset(&ln->ln_timer_ch, INT_MAX, - nd6_llinfo_timer, ln); - } else { - ln->ln_ntick = 0; - callout_reset(&ln->ln_timer_ch, xtick, - nd6_llinfo_timer, ln); - } -} - -/* * Gets source address of the first packet in hold queue * and stores it in @src. * Returns pointer to @src (if hold queue is not empty) or NULL. @@ -389,148 +367,67 @@ nd6_llinfo_get_holdsrc(struct llentry *l return src; } -static void -nd6_llinfo_timer(void *arg) +static union nd_addr * +nd6_llinfo_holdsrc(struct llentry *ln, union nd_addr *src) { - struct llentry *ln = arg; - struct ifnet *ifp; - struct nd_kifinfo *ndi; - bool send_ns = false; - const struct in6_addr *daddr6 = NULL; - const struct in6_addr *taddr6 = &ln->r_l3addr.addr6; - struct sockaddr_in6 dsin6, tsin6; - struct mbuf *m = NULL; - bool missed = false; - - SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); - - LLE_WLOCK(ln); - if ((ln->la_flags & LLE_LINKED) == 0) - goto out; - if (ln->ln_ntick > 0) { - nd6_llinfo_settimer(ln, ln->ln_ntick); - goto out; - } - - ifp = ln->lle_tbl->llt_ifp; - KASSERT(ifp != NULL); - - ndi = ND_IFINFO(ifp); - switch (ln->ln_state) { - case ND6_LLINFO_WAITDELETE: - LLE_REMREF(ln); - nd6_free(ln, 0); - ln = NULL; - break; - - case ND6_LLINFO_INCOMPLETE: - if (ln->ln_asked++ < nd6_mmaxtries) { - send_ns = true; - break; - } + if (nd6_llinfo_get_holdsrc(ln, &src->nd_addr6) == NULL) + return NULL; + return src; +} - missed = true; - sockaddr_in6_init(&tsin6, taddr6, 0, 0, 0); +static void +nd6_llinfo_output(struct ifnet *ifp, const union nd_addr *daddr, + const union nd_addr *taddr, __unused const uint8_t *tlladdr, + const union nd_addr *hsrc) +{ - if (ln->ln_hold) { - struct mbuf *m0; + nd6_ns_output(ifp, &daddr->nd_addr6, &taddr->nd_addr6, + &hsrc->nd_addr6, NULL); +} - m = ln->ln_hold; +static bool +nd6_nud_enabled(struct ifnet *ifp) +{ + struct nd_kifinfo *ndi = ND_IFINFO(ifp); - /* - * assuming every packet in ln_hold has - * the same IP header - */ - m0 = m->m_nextpkt; - m->m_nextpkt = NULL; - ln->ln_hold = m0; - clear_llinfo_pqueue(ln); - } + return ndi->flags & ND6_IFF_PERFORMNUD; +} - /* - * Move to the ND6_LLINFO_WAITDELETE state for another - * interval at which point the llentry will be freed - * unless it's attempted to be used again and we'll - * resend NS again, rinse and repeat. - */ - ln->ln_state = ND6_LLINFO_WAITDELETE; - if (ln->ln_asked == nd6_mmaxtries) - nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); - else - send_ns = true; - break; +static unsigned int +nd6_llinfo_reachable(struct ifnet *ifp) +{ + struct nd_kifinfo *ndi = ND_IFINFO(ifp); - case ND6_LLINFO_REACHABLE: - if (!ND6_LLINFO_PERMANENT(ln)) { - ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer(ln, nd6_gctimer * hz); - } - break; + return ndi->reachable; +} - case ND6_LLINFO_PURGE: - case ND6_LLINFO_STALE: - /* Garbage Collection(RFC 2461 5.3) */ - if (!ND6_LLINFO_PERMANENT(ln)) { - LLE_REMREF(ln); - nd6_free(ln, 1); - ln = NULL; - } - break; +static unsigned int +nd6_llinfo_retrans(struct ifnet *ifp) +{ + struct nd_kifinfo *ndi = ND_IFINFO(ifp); - case ND6_LLINFO_DELAY: - if (ndi->flags & ND6_IFF_PERFORMNUD) { - /* We need NUD */ - ln->ln_asked = 1; - ln->ln_state = ND6_LLINFO_PROBE; - daddr6 = &ln->r_l3addr.addr6; - send_ns = true; - } else { - ln->ln_state = ND6_LLINFO_STALE; /* XXX */ - nd6_llinfo_settimer(ln, nd6_gctimer * hz); - } - break; - case ND6_LLINFO_PROBE: - if (ln->ln_asked < nd6_umaxtries) { - ln->ln_asked++; - daddr6 = &ln->r_l3addr.addr6; - send_ns = true; - } else { - LLE_REMREF(ln); - nd6_free(ln, 0); - ln = NULL; - } - break; - } + return ndi->retrans; +} - if (send_ns) { - struct in6_addr src, *psrc; +static void +nd6_llinfo_missed(struct ifnet *ifp, const union nd_addr *taddr, struct mbuf *m) +{ + struct in6_addr mdaddr6 = zeroin6_addr; + struct sockaddr_in6 dsin6, tsin6; + struct sockaddr *sa; - nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); - psrc = nd6_llinfo_get_holdsrc(ln, &src); - LLE_FREE_LOCKED(ln); - ln = NULL; - nd6_ns_output(ifp, daddr6, taddr6, psrc, NULL); - } + if (m != NULL) + icmp6_error2(m, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); + if (!IN6_IS_ADDR_UNSPECIFIED(&mdaddr6)) { + sockaddr_in6_init(&dsin6, &mdaddr6, 0, 0, 0); + sa = sin6tosa(&dsin6); + } else + sa = NULL; -out: - if (ln != NULL) - LLE_FREE_LOCKED(ln); - SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); - if (missed) { - struct in6_addr mdaddr6 = zeroin6_addr; - struct sockaddr *sa; - - if (m != NULL) - icmp6_error2(m, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_ADDR, 0, ifp, &mdaddr6); - if (!IN6_IS_ADDR_UNSPECIFIED(&mdaddr6)) { - sockaddr_in6_init(&dsin6, &mdaddr6, 0, 0, 0); - sa = sin6tosa(&dsin6); - } else - sa = NULL; - rt_clonedmsg(RTM_MISS, sa, sin6tosa(&tsin6), NULL, ifp); - } + sockaddr_in6_init(&tsin6, &taddr->nd_addr6, 0, 0, 0); + rt_clonedmsg(RTM_MISS, sa, sin6tosa(&tsin6), NULL, ifp); } /* @@ -675,7 +572,7 @@ nd6_create(const struct in6_addr *addr6, if (rt != NULL) rt_unref(rt); if (ln != NULL) - ln->ln_state = ND6_LLINFO_NOSTATE; + ln->ln_state = ND_LLINFO_NOSTATE; return ln; } @@ -822,13 +719,9 @@ nd6_free(struct llentry *ln, int gc) * but we intentionally keep it just in case. */ if (!ip6_forwarding && ln->ln_router && - ln->ln_state == ND6_LLINFO_STALE && gc) + ln->ln_state == ND_LLINFO_STALE && gc) { - if (ln->ln_expire > time_uptime) - nd6_llinfo_settimer(ln, - (ln->ln_expire - time_uptime) * hz); - else - nd6_llinfo_settimer(ln, nd6_gctimer * hz); + nd_set_timer(ln, ND_TIMER_EXPIRE); LLE_WUNLOCK(ln); return; } @@ -874,28 +767,7 @@ nd6_nud_hint(struct rtentry *rt) ifp = rt->rt_ifp; ln = nd6_lookup(&(satocsin6(rt_getkey(rt)))->sin6_addr, ifp, true); - if (ln == NULL) - return; - - if (ln->ln_state < ND6_LLINFO_REACHABLE) - goto done; - - /* - * if we get upper-layer reachability confirmation many times, - * it is possible we have false information. - */ - ln->ln_byhint++; - if (ln->ln_byhint > nd6_maxnudhint) - goto done; - - ln->ln_state = ND6_LLINFO_REACHABLE; - if (!ND6_LLINFO_PERMANENT(ln)) - nd6_llinfo_settimer(ln, ND_IFINFO(rt->rt_ifp)->reachable * hz); - -done: - LLE_WUNLOCK(ln); - - return; + nd_nud_hint(ln); } struct gc_args { @@ -913,18 +785,18 @@ nd6_purge_entry(struct lltable *llt, str if (*n <= 0) return 0; - if (ND6_LLINFO_PERMANENT(ln)) + if (ND_IS_LLINFO_PERMANENT(ln)) return 0; if (IN6_ARE_ADDR_EQUAL(&ln->r_l3addr.addr6, skip_in6)) return 0; LLE_WLOCK(ln); - if (ln->ln_state > ND6_LLINFO_INCOMPLETE) - ln->ln_state = ND6_LLINFO_STALE; + if (ln->ln_state > ND_LLINFO_INCOMPLETE) + ln->ln_state = ND_LLINFO_STALE; else - ln->ln_state = ND6_LLINFO_PURGE; - nd6_llinfo_settimer(ln, 0); + ln->ln_state = ND_LLINFO_PURGE; + nd_set_timer(ln, ND_TIMER_IMMEDIATE); LLE_WUNLOCK(ln); (*n)--; @@ -1524,15 +1396,15 @@ nd6_cache_lladdr( if ((!olladdr && lladdr) || /* (3) */ (olladdr && lladdr && llchange)) { /* (5) */ do_update = 1; - newstate = ND6_LLINFO_STALE; + newstate = ND_LLINFO_STALE; } else /* (1-2,4) */ do_update = 0; } else { do_update = 1; if (lladdr == NULL) /* (6) */ - newstate = ND6_LLINFO_NOSTATE; + newstate = ND_LLINFO_NOSTATE; else /* (7) */ - newstate = ND6_LLINFO_STALE; + newstate = ND_LLINFO_STALE; } if (do_update) { @@ -1541,19 +1413,19 @@ nd6_cache_lladdr( */ ln->ln_state = newstate; - if (ln->ln_state == ND6_LLINFO_STALE) { + if (ln->ln_state == ND_LLINFO_STALE) { /* * XXX: since nd6_output() below will cause * state tansition to DELAY and reset the timer, * we must set the timer now, although it is actually * meaningless. */ - nd6_llinfo_settimer(ln, nd6_gctimer * hz); + nd_set_timer(ln, ND_TIMER_GC); nd6_llinfo_release_pkts(ln, ifp); - } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { + } else if (ln->ln_state == ND_LLINFO_INCOMPLETE) { /* probe right away */ - nd6_llinfo_settimer((void *)ln, 0); + nd_set_timer(ln, ND_TIMER_IMMEDIATE); } } @@ -1704,7 +1576,7 @@ nd6_resolve(struct ifnet *ifp, const str ln = nd6_lookup(&dst->sin6_addr, ifp, false); if (ln != NULL && (ln->la_flags & LLE_VALID) != 0 && - ln->ln_state == ND6_LLINFO_REACHABLE) { + ln->ln_state == ND_LLINFO_REACHABLE) { /* Fast path */ memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); LLE_RUNLOCK(ln); @@ -1739,92 +1611,7 @@ nd6_resolve(struct ifnet *ifp, const str return ENETDOWN; /* better error? */ } - LLE_WLOCK_ASSERT(ln); - - /* We don't have to do link-layer address resolution on a p2p link. */ - if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && - ln->ln_state < ND6_LLINFO_REACHABLE) { - ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer(ln, nd6_gctimer * hz); - } - - /* - * The first time we send a packet to a neighbor whose entry is - * STALE, we have to change the state to DELAY and a sets a timer to - * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do - * neighbor unreachability detection on expiration. - * (RFC 2461 7.3.3) - */ - if (ln->ln_state == ND6_LLINFO_STALE) { - ln->ln_asked = 0; - ln->ln_state = ND6_LLINFO_DELAY; - nd6_llinfo_settimer(ln, nd6_delay * hz); - } - - /* - * If the neighbor cache entry has a state other than INCOMPLETE - * (i.e. its link-layer address is already resolved), just - * send the packet. - */ - if (ln->ln_state > ND6_LLINFO_INCOMPLETE) { - KASSERT((ln->la_flags & LLE_VALID) != 0); - memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); - LLE_WUNLOCK(ln); - return 0; - } - - /* - * There is a neighbor cache entry, but no ethernet address - * response yet. Append this latest packet to the end of the - * packet queue in the mbuf, unless the number of the packet - * does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen, - * the oldest packet in the queue will be removed. - */ - if (ln->ln_state == ND6_LLINFO_NOSTATE || - ln->ln_state == ND6_LLINFO_WAITDELETE) - ln->ln_state = ND6_LLINFO_INCOMPLETE; - if (ln->ln_hold) { - struct mbuf *m_hold; - int i; - - i = 0; - for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) { - i++; - if (m_hold->m_nextpkt == NULL) { - m_hold->m_nextpkt = m; - break; - } - } - while (i >= nd6_maxqueuelen) { - m_hold = ln->ln_hold; - ln->ln_hold = ln->ln_hold->m_nextpkt; - m_freem(m_hold); - i--; - } - } else { - ln->ln_hold = m; - } - - if (ln->ln_asked >= nd6_mmaxtries) - error = (rt != NULL && rt->rt_flags & RTF_GATEWAY) ? - EHOSTUNREACH : EHOSTDOWN; - else - error = EWOULDBLOCK; - - /* - * If there has been no NS for the neighbor after entering the - * INCOMPLETE state, send the first solicitation. - */ - if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) { - struct in6_addr src, *psrc; - - ln->ln_asked++; - nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); - psrc = nd6_llinfo_get_holdsrc(ln, &src); - LLE_WUNLOCK(ln); - nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, NULL); - } else - LLE_WUNLOCK(ln); + error = nd_resolve(ln, rt, m, lldst, dstsize); if (created) nd6_gc_neighbors(LLTABLE6(ifp), &dst->sin6_addr); @@ -1856,21 +1643,6 @@ nd6_need_cache(struct ifnet *ifp) } } -static void -clear_llinfo_pqueue(struct llentry *ln) -{ - struct mbuf *m_hold, *m_hold_next; - - for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { - m_hold_next = m_hold->m_nextpkt; - m_hold->m_nextpkt = NULL; - m_freem(m_hold); - } - - ln->ln_hold = NULL; - return; -} - int nd6_sysctl( int name, Index: src/sys/netinet6/nd6.h diff -u src/sys/netinet6/nd6.h:1.90 src/sys/netinet6/nd6.h:1.91 --- src/sys/netinet6/nd6.h:1.90 Thu Aug 20 11:01:02 2020 +++ src/sys/netinet6/nd6.h Fri Sep 11 15:03:33 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6.h,v 1.90 2020/08/20 11:01:02 roy Exp $ */ +/* $NetBSD: nd6.h,v 1.91 2020/09/11 15:03:33 roy Exp $ */ /* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */ /* @@ -36,17 +36,18 @@ #include <sys/queue.h> #include <sys/callout.h> -#define ND6_LLINFO_PURGE -3 -#define ND6_LLINFO_NOSTATE -2 -#define ND6_LLINFO_WAITDELETE -1 -#define ND6_LLINFO_INCOMPLETE 0 -#define ND6_LLINFO_REACHABLE 1 -#define ND6_LLINFO_STALE 2 -#define ND6_LLINFO_DELAY 3 -#define ND6_LLINFO_PROBE 4 - -#define ND6_IS_LLINFO_PROBREACH(n) ((n)->ln_state > ND6_LLINFO_INCOMPLETE) -#define ND6_LLINFO_PERMANENT(n) (((n)->ln_expire == 0) && ((n)->ln_state > ND6_LLINFO_INCOMPLETE)) +#ifndef _KERNEL +/* Backwards compat */ +#include <net/nd.h> +#define ND6_LLINFO_PURGE ND_LLINFO_PURGE +#define ND6_LLINFO_NOSTATE ND_LLINFO_NOSTATE +#define ND6_LLINFO_WAITDELETE ND_LLINFO_WAITDELETE +#define ND6_LLINFO_INCOMPLETE ND_LLINFO_INCOMPLETE +#define ND6_LLINFO_REACHABLE ND_LLINFO_REACHABLE +#define ND6_LLINFO_STALE ND_LLINFO_STALE +#define ND6_LLINFO_DELAY ND_LLINFO_DELAY +#define ND6_LLINFO_PROBE ND_LLINFO_PROBE +#endif struct nd_ifinfo { uint8_t chlim; /* CurHopLimit */ @@ -98,29 +99,16 @@ struct in6_ndireq { #define ND6_INFINITE_LIFETIME ((u_int32_t)~0) #ifdef _KERNEL -/* node constants */ -#define MAX_REACHABLE_TIME 3600000 /* msec */ -#define REACHABLE_TIME 30000 /* msec */ -#define RETRANS_TIMER 1000 /* msec */ -#define MIN_RANDOM_FACTOR 512 /* 1024 * 0.5 */ -#define MAX_RANDOM_FACTOR 1536 /* 1024 * 1.5 */ -#define ND_COMPUTE_RTIME(x) \ - (((MIN_RANDOM_FACTOR * (x >> 10)) + (cprng_fast32() & \ - ((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000) - #include <sys/mallocvar.h> MALLOC_DECLARE(M_IP6NDP); /* nd6.c */ extern int nd6_prune; -extern int nd6_delay; -extern int nd6_umaxtries; -extern int nd6_mmaxtries; extern int nd6_useloopback; -extern int nd6_maxnudhint; -extern int nd6_gctimer; extern int nd6_debug; +extern struct nd_domain nd6_nd_domain; + #define nd6log(level, fmt, args...) \ do { if (nd6_debug) log(level, "%s: " fmt, __func__, ##args);} while (0) @@ -181,7 +169,6 @@ void nd6_option_init(void *, int, union int nd6_options(union nd_opts *); struct llentry *nd6_lookup(const struct in6_addr *, const struct ifnet *, bool); struct llentry *nd6_create(const struct in6_addr *, const struct ifnet *); -void nd6_llinfo_settimer(struct llentry *, time_t); void nd6_purge(struct ifnet *, struct in6_ifextra *); void nd6_nud_hint(struct rtentry *); int nd6_resolve(struct ifnet *, const struct rtentry *, struct mbuf *, Index: src/sys/netinet6/nd6_nbr.c diff -u src/sys/netinet6/nd6_nbr.c:1.180 src/sys/netinet6/nd6_nbr.c:1.181 --- src/sys/netinet6/nd6_nbr.c:1.180 Thu Aug 20 11:01:02 2020 +++ src/sys/netinet6/nd6_nbr.c Fri Sep 11 15:03:33 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6_nbr.c,v 1.180 2020/08/20 11:01:02 roy Exp $ */ +/* $NetBSD: nd6_nbr.c,v 1.181 2020/09/11 15:03:33 roy Exp $ */ /* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.180 2020/08/20 11:01:02 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.181 2020/09/11 15:03:33 roy Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -57,6 +57,8 @@ __KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v #include <net/if.h> #include <net/if_types.h> #include <net/if_dl.h> +#include <net/if_llatbl.h> +#include <net/nd.h> #include <net/route.h> #include <netinet/in.h> @@ -735,7 +737,7 @@ nd6_na_input(struct mbuf *m, int off, in goto freeit; rt_cmd = 0; - if (ln->ln_state <= ND6_LLINFO_INCOMPLETE) { + if (ln->ln_state <= ND_LLINFO_INCOMPLETE) { /* * If the link-layer has address, and no lladdr option came, * discard the packet. @@ -750,15 +752,13 @@ nd6_na_input(struct mbuf *m, int off, in ln->la_flags |= LLE_VALID; rt_cmd = RTM_ADD; if (is_solicited) { - ln->ln_state = ND6_LLINFO_REACHABLE; + ln->ln_state = ND_LLINFO_REACHABLE; ln->ln_byhint = 0; - if (!ND6_LLINFO_PERMANENT(ln)) { - nd6_llinfo_settimer(ln, - ND_IFINFO(ln->lle_tbl->llt_ifp)->reachable * hz); - } + if (!ND_IS_LLINFO_PERMANENT(ln)) + nd_set_timer(ln, ND_TIMER_REACHABLE); } else { - ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer(ln, nd6_gctimer * hz); + ln->ln_state = ND_LLINFO_STALE; + nd_set_timer(ln, ND_TIMER_GC); } } else { bool llchange; @@ -804,9 +804,9 @@ nd6_na_input(struct mbuf *m, int off, in * If state is REACHABLE, make it STALE. * no other updates should be done. */ - if (ln->ln_state == ND6_LLINFO_REACHABLE) { - ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer(ln, nd6_gctimer * hz); + if (ln->ln_state == ND_LLINFO_REACHABLE) { + ln->ln_state = ND_LLINFO_STALE; + nd_set_timer(ln, ND_TIMER_GC); } goto freeit; } else if (is_override /* (2a) */ @@ -826,17 +826,14 @@ nd6_na_input(struct mbuf *m, int off, in * changed, make it STALE. */ if (is_solicited) { - ln->ln_state = ND6_LLINFO_REACHABLE; + ln->ln_state = ND_LLINFO_REACHABLE; ln->ln_byhint = 0; - if (!ND6_LLINFO_PERMANENT(ln)) { - nd6_llinfo_settimer(ln, - ND_IFINFO(ifp)->reachable * hz); - } + if (!ND_IS_LLINFO_PERMANENT(ln)) + nd_set_timer(ln, ND_TIMER_REACHABLE); } else { if (lladdr && llchange) { - ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer(ln, - nd6_gctimer * hz); + ln->ln_state = ND_LLINFO_STALE; + nd_set_timer(ln, ND_TIMER_GC); } } }