Sun Sep 1 19:26:22 2019 UTC ()
inet6: Re-introduce ND6_LLINFO_WAITDELETE so we can return EHOSTDOWN

Once we've sent nd6_mmaxtries NS messages, send RTM_MISS and move to the
ND6_LLINFO_WAITDELETE state rather than freeing the llentry right away.
Wait for a probe cycle and then free the llentry.

If a connection attempts to re-use the llentry during ND6_LLINFO_WAITDELETE,
return EHOSTDOWN (or EHOSTUNREACH if a gateway) to match inet behaviour.
Continue to ND6_LLINFO_INCOMPLETE and send another NS probe in hope of a
reply. Rinse and repeat.

This reverts part of nd6.c r1.14 - an 18 year old commit!


(roy)
diff -r1.262 -r1.263 src/sys/netinet6/nd6.c
diff -r1.86 -r1.87 src/sys/netinet6/nd6.h

cvs diff -r1.262 -r1.263 src/sys/netinet6/nd6.c (expand / switch to unified diff)

--- src/sys/netinet6/nd6.c 2019/09/01 18:54:38 1.262
+++ src/sys/netinet6/nd6.c 2019/09/01 19:26:21 1.263
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: nd6.c,v 1.262 2019/09/01 18:54:38 roy Exp $ */ 1/* $NetBSD: nd6.c,v 1.263 2019/09/01 19:26:21 roy Exp $ */
2/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ 2/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
3 3
4/* 4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
@@ -21,27 +21,27 @@ @@ -21,27 +21,27 @@
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.262 2019/09/01 18:54:38 roy Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.263 2019/09/01 19:26:21 roy Exp $");
35 35
36#ifdef _KERNEL_OPT 36#ifdef _KERNEL_OPT
37#include "opt_net_mpsafe.h" 37#include "opt_net_mpsafe.h"
38#endif 38#endif
39 39
40#include "bridge.h" 40#include "bridge.h"
41#include "carp.h" 41#include "carp.h"
42 42
43#include <sys/param.h> 43#include <sys/param.h>
44#include <sys/systm.h> 44#include <sys/systm.h>
45#include <sys/callout.h> 45#include <sys/callout.h>
46#include <sys/kmem.h> 46#include <sys/kmem.h>
47#include <sys/mbuf.h> 47#include <sys/mbuf.h>
@@ -470,55 +470,68 @@ nd6_llinfo_timer(void *arg) @@ -470,55 +470,68 @@ nd6_llinfo_timer(void *arg)
470 if ((ln->la_flags & LLE_LINKED) == 0) 470 if ((ln->la_flags & LLE_LINKED) == 0)
471 goto out; 471 goto out;
472 if (ln->ln_ntick > 0) { 472 if (ln->ln_ntick > 0) {
473 nd6_llinfo_settimer(ln, ln->ln_ntick); 473 nd6_llinfo_settimer(ln, ln->ln_ntick);
474 goto out; 474 goto out;
475 } 475 }
476 476
477 ifp = ln->lle_tbl->llt_ifp; 477 ifp = ln->lle_tbl->llt_ifp;
478 KASSERT(ifp != NULL); 478 KASSERT(ifp != NULL);
479 479
480 ndi = ND_IFINFO(ifp); 480 ndi = ND_IFINFO(ifp);
481 481
482 switch (ln->ln_state) { 482 switch (ln->ln_state) {
 483 case ND6_LLINFO_WAITDELETE:
 484 LLE_REMREF(ln);
 485 nd6_free(ln, 0);
 486 ln = NULL;
 487 break;
 488
483 case ND6_LLINFO_INCOMPLETE: 489 case ND6_LLINFO_INCOMPLETE:
484 if (ln->ln_asked < nd6_mmaxtries) { 490 if (ln->ln_asked++ < nd6_mmaxtries) {
485 ln->ln_asked++; 
486 send_ns = true; 491 send_ns = true;
487 break; 492 break;
488 } 493 }
489 494
490 if (ln->ln_hold) { 495 if (ln->ln_hold) {
491 struct mbuf *m = ln->ln_hold, *m0; 496 struct mbuf *m = ln->ln_hold, *m0;
492 497
493 /* 498 /*
494 * assuming every packet in ln_hold has 499 * assuming every packet in ln_hold has
495 * the same IP header 500 * the same IP header
496 */ 501 */
497 m0 = m->m_nextpkt; 502 m0 = m->m_nextpkt;
498 m->m_nextpkt = NULL; 503 m->m_nextpkt = NULL;
499 ln->ln_hold = m0; 504 ln->ln_hold = m0;
500 clear_llinfo_pqueue(ln); 505 clear_llinfo_pqueue(ln);
501 506
502 icmp6_error2(m, ICMP6_DST_UNREACH, 507 icmp6_error2(m, ICMP6_DST_UNREACH,
503 ICMP6_DST_UNREACH_ADDR, 0, ifp); 508 ICMP6_DST_UNREACH_ADDR, 0, ifp);
504 } 509 }
505 510
506 sockaddr_in6_init(&sin6, taddr6, 0, 0, 0); 511 sockaddr_in6_init(&sin6, taddr6, 0, 0, 0);
507 rt_clonedmsg(RTM_MISS, sin6tosa(&sin6), NULL, ifp); 512 rt_clonedmsg(RTM_MISS, sin6tosa(&sin6), NULL, ifp);
508 513
509 LLE_REMREF(ln); 514 /*
510 nd6_free(ln, 0); 515 * Move to the ND6_LLINFO_WAITDELETE state for another
511 ln = NULL; 516 * interval at which point the llentry will be freed
 517 * unless it's attempted to be used again and we'll
 518 * resend NS again, rinse and repeat.
 519 */
 520 ln->ln_state = ND6_LLINFO_WAITDELETE;
 521 if (ln->ln_asked == nd6_mmaxtries)
 522 nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000);
 523 else
 524 send_ns = true;
512 break; 525 break;
513 526
514 case ND6_LLINFO_REACHABLE: 527 case ND6_LLINFO_REACHABLE:
515 if (!ND6_LLINFO_PERMANENT(ln)) { 528 if (!ND6_LLINFO_PERMANENT(ln)) {
516 ln->ln_state = ND6_LLINFO_STALE; 529 ln->ln_state = ND6_LLINFO_STALE;
517 nd6_llinfo_settimer(ln, nd6_gctimer * hz); 530 nd6_llinfo_settimer(ln, nd6_gctimer * hz);
518 } 531 }
519 break; 532 break;
520 533
521 case ND6_LLINFO_PURGE: 534 case ND6_LLINFO_PURGE:
522 case ND6_LLINFO_STALE: 535 case ND6_LLINFO_STALE:
523 /* Garbage Collection(RFC 2461 5.3) */ 536 /* Garbage Collection(RFC 2461 5.3) */
524 if (!ND6_LLINFO_PERMANENT(ln)) { 537 if (!ND6_LLINFO_PERMANENT(ln)) {
@@ -2302,26 +2315,27 @@ nd6_slowtimo(void *ignored_arg) @@ -2302,26 +2315,27 @@ nd6_slowtimo(void *ignored_arg)
2302 2315
2303/* 2316/*
2304 * Return 0 if a neighbor cache is found. Return EWOULDBLOCK if a cache is not 2317 * Return 0 if a neighbor cache is found. Return EWOULDBLOCK if a cache is not
2305 * found and trying to resolve a neighbor; in this case the mbuf is queued in 2318 * found and trying to resolve a neighbor; in this case the mbuf is queued in
2306 * the list. Otherwise return errno after freeing the mbuf. 2319 * the list. Otherwise return errno after freeing the mbuf.
2307 */ 2320 */
2308int 2321int
2309nd6_resolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, 2322nd6_resolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m,
2310 const struct sockaddr *_dst, uint8_t *lldst, size_t dstsize) 2323 const struct sockaddr *_dst, uint8_t *lldst, size_t dstsize)
2311{ 2324{
2312 struct llentry *ln = NULL; 2325 struct llentry *ln = NULL;
2313 bool created = false; 2326 bool created = false;
2314 const struct sockaddr_in6 *dst = satocsin6(_dst); 2327 const struct sockaddr_in6 *dst = satocsin6(_dst);
 2328 int error;
2315 2329
2316 /* discard the packet if IPv6 operation is disabled on the interface */ 2330 /* discard the packet if IPv6 operation is disabled on the interface */
2317 if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { 2331 if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) {
2318 m_freem(m); 2332 m_freem(m);
2319 return ENETDOWN; /* better error? */ 2333 return ENETDOWN; /* better error? */
2320 } 2334 }
2321 2335
2322 /* 2336 /*
2323 * Address resolution or Neighbor Unreachability Detection 2337 * Address resolution or Neighbor Unreachability Detection
2324 * for the next hop. 2338 * for the next hop.
2325 * At this point, the destination of the packet must be a unicast 2339 * At this point, the destination of the packet must be a unicast
2326 * or an anycast address(i.e. not a multicast). 2340 * or an anycast address(i.e. not a multicast).
2327 */ 2341 */
@@ -2396,69 +2410,76 @@ nd6_resolve(struct ifnet *ifp, const str @@ -2396,69 +2410,76 @@ nd6_resolve(struct ifnet *ifp, const str
2396 KASSERT((ln->la_flags & LLE_VALID) != 0); 2410 KASSERT((ln->la_flags & LLE_VALID) != 0);
2397 memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); 2411 memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen));
2398 LLE_WUNLOCK(ln); 2412 LLE_WUNLOCK(ln);
2399 return 0; 2413 return 0;
2400 } 2414 }
2401 2415
2402 /* 2416 /*
2403 * There is a neighbor cache entry, but no ethernet address 2417 * There is a neighbor cache entry, but no ethernet address
2404 * response yet. Append this latest packet to the end of the 2418 * response yet. Append this latest packet to the end of the
2405 * packet queue in the mbuf, unless the number of the packet 2419 * packet queue in the mbuf, unless the number of the packet
2406 * does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen, 2420 * does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen,
2407 * the oldest packet in the queue will be removed. 2421 * the oldest packet in the queue will be removed.
2408 */ 2422 */
2409 if (ln->ln_state == ND6_LLINFO_NOSTATE) 2423 if (ln->ln_state == ND6_LLINFO_NOSTATE ||
 2424 ln->ln_state == ND6_LLINFO_WAITDELETE)
2410 ln->ln_state = ND6_LLINFO_INCOMPLETE; 2425 ln->ln_state = ND6_LLINFO_INCOMPLETE;
2411 if (ln->ln_hold) { 2426 if (ln->ln_hold) {
2412 struct mbuf *m_hold; 2427 struct mbuf *m_hold;
2413 int i; 2428 int i;
2414 2429
2415 i = 0; 2430 i = 0;
2416 for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) { 2431 for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) {
2417 i++; 2432 i++;
2418 if (m_hold->m_nextpkt == NULL) { 2433 if (m_hold->m_nextpkt == NULL) {
2419 m_hold->m_nextpkt = m; 2434 m_hold->m_nextpkt = m;
2420 break; 2435 break;
2421 } 2436 }
2422 } 2437 }
2423 while (i >= nd6_maxqueuelen) { 2438 while (i >= nd6_maxqueuelen) {
2424 m_hold = ln->ln_hold; 2439 m_hold = ln->ln_hold;
2425 ln->ln_hold = ln->ln_hold->m_nextpkt; 2440 ln->ln_hold = ln->ln_hold->m_nextpkt;
2426 m_freem(m_hold); 2441 m_freem(m_hold);
2427 i--; 2442 i--;
2428 } 2443 }
2429 } else { 2444 } else {
2430 ln->ln_hold = m; 2445 ln->ln_hold = m;
2431 } 2446 }
2432 2447
 2448 if (ln->ln_asked >= nd6_mmaxtries)
 2449 error = (rt != NULL && rt->rt_flags & RTF_GATEWAY) ?
 2450 EHOSTUNREACH : EHOSTDOWN;
 2451 else
 2452 error = EWOULDBLOCK;
 2453
2433 /* 2454 /*
2434 * If there has been no NS for the neighbor after entering the 2455 * If there has been no NS for the neighbor after entering the
2435 * INCOMPLETE state, send the first solicitation. 2456 * INCOMPLETE state, send the first solicitation.
2436 */ 2457 */
2437 if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) { 2458 if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) {
2438 struct in6_addr src, *psrc; 2459 struct in6_addr src, *psrc;
2439 2460
2440 ln->ln_asked++; 2461 ln->ln_asked++;
2441 nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans * hz / 1000); 2462 nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans * hz / 1000);
2442 psrc = nd6_llinfo_get_holdsrc(ln, &src); 2463 psrc = nd6_llinfo_get_holdsrc(ln, &src);
2443 LLE_WUNLOCK(ln); 2464 LLE_WUNLOCK(ln);
2444 nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, NULL); 2465 nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, NULL);
2445 } else 2466 } else
2446 LLE_WUNLOCK(ln); 2467 LLE_WUNLOCK(ln);
2447 2468
2448 if (created) 2469 if (created)
2449 nd6_gc_neighbors(LLTABLE6(ifp), &dst->sin6_addr); 2470 nd6_gc_neighbors(LLTABLE6(ifp), &dst->sin6_addr);
2450 2471
2451 return EWOULDBLOCK; 2472 return error;
2452} 2473}
2453 2474
2454int 2475int
2455nd6_need_cache(struct ifnet *ifp) 2476nd6_need_cache(struct ifnet *ifp)
2456{ 2477{
2457 /* 2478 /*
2458 * XXX: we currently do not make neighbor cache on any interface 2479 * XXX: we currently do not make neighbor cache on any interface
2459 * other than ARCnet, Ethernet, FDDI and GIF. 2480 * other than ARCnet, Ethernet, FDDI and GIF.
2460 * 2481 *
2461 * RFC2893 says: 2482 * RFC2893 says:
2462 * - unidirectional tunnels needs no ND 2483 * - unidirectional tunnels needs no ND
2463 */ 2484 */
2464 switch (ifp->if_type) { 2485 switch (ifp->if_type) {

cvs diff -r1.86 -r1.87 src/sys/netinet6/nd6.h (expand / switch to unified diff)

--- src/sys/netinet6/nd6.h 2018/03/06 10:57:00 1.86
+++ src/sys/netinet6/nd6.h 2019/09/01 19:26:21 1.87
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: nd6.h,v 1.86 2018/03/06 10:57:00 roy Exp $ */ 1/* $NetBSD: nd6.h,v 1.87 2019/09/01 19:26:21 roy Exp $ */
2/* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */ 2/* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */
3 3
4/* 4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
@@ -28,34 +28,27 @@ @@ -28,34 +28,27 @@
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 */ 31 */
32 32
33#ifndef _NETINET6_ND6_H_ 33#ifndef _NETINET6_ND6_H_
34#define _NETINET6_ND6_H_ 34#define _NETINET6_ND6_H_
35 35
36#include <sys/queue.h> 36#include <sys/queue.h>
37#include <sys/callout.h> 37#include <sys/callout.h>
38 38
39#define ND6_LLINFO_PURGE -3 39#define ND6_LLINFO_PURGE -3
40#define ND6_LLINFO_NOSTATE -2 40#define ND6_LLINFO_NOSTATE -2
41/* 41#define ND6_LLINFO_WAITDELETE -1
42 * We don't need the WAITDELETE state any more, but we keep the definition 
43 * in a comment line instead of removing it. This is necessary to avoid 
44 * unintentionally reusing the value for another purpose, which might 
45 * affect backward compatibility with old applications. 
46 * (20000711 jinmei@kame.net) 
47 */ 
48/* #define ND6_LLINFO_WAITDELETE -1 */ 
49#define ND6_LLINFO_INCOMPLETE 0 42#define ND6_LLINFO_INCOMPLETE 0
50#define ND6_LLINFO_REACHABLE 1 43#define ND6_LLINFO_REACHABLE 1
51#define ND6_LLINFO_STALE 2 44#define ND6_LLINFO_STALE 2
52#define ND6_LLINFO_DELAY 3 45#define ND6_LLINFO_DELAY 3
53#define ND6_LLINFO_PROBE 4 46#define ND6_LLINFO_PROBE 4
54 47
55#define ND6_IS_LLINFO_PROBREACH(n) ((n)->ln_state > ND6_LLINFO_INCOMPLETE) 48#define ND6_IS_LLINFO_PROBREACH(n) ((n)->ln_state > ND6_LLINFO_INCOMPLETE)
56#define ND6_LLINFO_PERMANENT(n) (((n)->ln_expire == 0) && ((n)->ln_state > ND6_LLINFO_INCOMPLETE)) 49#define ND6_LLINFO_PERMANENT(n) (((n)->ln_expire == 0) && ((n)->ln_state > ND6_LLINFO_INCOMPLETE))
57 50
58struct nd_ifinfo { 51struct nd_ifinfo {
59 u_int32_t linkmtu; /* LinkMTU */ 52 u_int32_t linkmtu; /* LinkMTU */
60 u_int32_t maxmtu; /* Upper bound of LinkMTU */ 53 u_int32_t maxmtu; /* Upper bound of LinkMTU */
61 u_int32_t basereachable; /* BaseReachableTime */ 54 u_int32_t basereachable; /* BaseReachableTime */