Wed Apr 15 14:52:29 2020 UTC ()
Pull up following revision(s) (requested by kim in ticket #1727):

	sys/netinet6/nd6_rtr.c: revision 1.148 (via patch)

Fix default route selection

The primary issue was that in revision 1.79 a check was added in the
nd6_defrouter_select() search loop to ignore the entry if RA processing
is enabled on its interface.  In practice this results in all entries
being ignored.

This fix reverses the condition, so that an entry is ignored when RA
processing is NOT enabled on its interface.  Further, the entry is
only ignored for being selected as the default router.  The currently
installed router must be identified regardless of the (current) status
of its interface, so that we can delete the route before installing a
new one.

I also added error logging when adding or deleting a route fails. This
should help the administrator (or kernel developer) in noticing possible
problems.

Finally, if deleting a route fails, the corresponding default route
entry no longer has its "installed" flag cleared, so that deletion will
be retried.  At a minimum, this will cause repeated messages about the
failed deletion as opposed to only getting repeated messages about the
installation of a new default route failing.

Fixes PR kern/55091 and also PR bin/54997 as far as the behaviour
observed with ndp(8).


(martin)
diff -r1.93.2.3 -r1.93.2.4 src/sys/netinet6/nd6_rtr.c

cvs diff -r1.93.2.3 -r1.93.2.4 src/sys/netinet6/nd6_rtr.c (expand / switch to unified diff)

--- src/sys/netinet6/nd6_rtr.c 2015/05/02 18:23:25 1.93.2.3
+++ src/sys/netinet6/nd6_rtr.c 2020/04/15 14:52:28 1.93.2.4
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: nd6_rtr.c,v 1.93.2.3 2015/05/02 18:23:25 martin Exp $ */ 1/* $NetBSD: nd6_rtr.c,v 1.93.2.4 2020/04/15 14:52:28 martin Exp $ */
2/* $KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $ */ 2/* $KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 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_rtr.c,v 1.93.2.3 2015/05/02 18:23:25 martin Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.93.2.4 2020/04/15 14:52:28 martin Exp $");
35 35
36#include <sys/param.h> 36#include <sys/param.h>
37#include <sys/systm.h> 37#include <sys/systm.h>
38#include <sys/malloc.h> 38#include <sys/malloc.h>
39#include <sys/mbuf.h> 39#include <sys/mbuf.h>
40#include <sys/socket.h> 40#include <sys/socket.h>
41#include <sys/sockio.h> 41#include <sys/sockio.h>
42#include <sys/time.h> 42#include <sys/time.h>
43#include <sys/kernel.h> 43#include <sys/kernel.h>
44#include <sys/errno.h> 44#include <sys/errno.h>
45#include <sys/ioctl.h> 45#include <sys/ioctl.h>
46#include <sys/syslog.h> 46#include <sys/syslog.h>
47#include <sys/cprng.h> 47#include <sys/cprng.h>
@@ -462,26 +462,30 @@ defrouter_addreq(struct nd_defrouter *ne @@ -462,26 +462,30 @@ defrouter_addreq(struct nd_defrouter *ne
462 gate.sin6.sin6_scope_id = 0; /* XXX */ 462 gate.sin6.sin6_scope_id = 0; /* XXX */
463#endif 463#endif
464 464
465 s = splsoftnet(); 465 s = splsoftnet();
466 error = rtrequest(RTM_ADD, &def.sa, &gate.sa, &mask.sa, 466 error = rtrequest(RTM_ADD, &def.sa, &gate.sa, &mask.sa,
467 RTF_GATEWAY, &newrt); 467 RTF_GATEWAY, &newrt);
468 if (newrt) { 468 if (newrt) {
469 nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 469 nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
470 newrt->rt_refcnt--; 470 newrt->rt_refcnt--;
471 nd6_numroutes++; 471 nd6_numroutes++;
472 } 472 }
473 if (error == 0) 473 if (error == 0)
474 new->installed = 1; 474 new->installed = 1;
 475 else
 476 log(LOG_ERR, "defrouter_addreq: "
 477 "error %d adding default router %s on %s\n",
 478 error, ip6_sprintf(&new->rtaddr), new->ifp->if_xname);
475 splx(s); 479 splx(s);
476 return; 480 return;
477} 481}
478 482
479struct nd_defrouter * 483struct nd_defrouter *
480defrouter_lookup(const struct in6_addr *addr, struct ifnet *ifp) 484defrouter_lookup(const struct in6_addr *addr, struct ifnet *ifp)
481{ 485{
482 struct nd_defrouter *dr; 486 struct nd_defrouter *dr;
483 487
484 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) { 488 TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) {
485 if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 489 if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
486 break; 490 break;
487 } 491 }
@@ -549,59 +553,65 @@ defrtrlist_del(struct nd_defrouter *dr,  @@ -549,59 +553,65 @@ defrtrlist_del(struct nd_defrouter *dr,
549/* 553/*
550 * Remove the default route for a given router. 554 * Remove the default route for a given router.
551 * This is just a subroutine function for defrouter_select(), and should 555 * This is just a subroutine function for defrouter_select(), and should
552 * not be called from anywhere else. 556 * not be called from anywhere else.
553 */ 557 */
554static void 558static void
555defrouter_delreq(struct nd_defrouter *dr) 559defrouter_delreq(struct nd_defrouter *dr)
556{ 560{
557 union { 561 union {
558 struct sockaddr_in6 sin6; 562 struct sockaddr_in6 sin6;
559 struct sockaddr sa; 563 struct sockaddr sa;
560 } def, mask, gw; 564 } def, mask, gw;
561 struct rtentry *oldrt = NULL; 565 struct rtentry *oldrt = NULL;
 566 int error;
562 567
563#ifdef DIAGNOSTIC 568#ifdef DIAGNOSTIC
564 if (dr == NULL) 569 if (dr == NULL)
565 panic("dr == NULL in defrouter_delreq"); 570 panic("dr == NULL in defrouter_delreq");
566#endif 571#endif
567 572
568 memset(&def, 0, sizeof(def)); 573 memset(&def, 0, sizeof(def));
569 memset(&mask, 0, sizeof(mask)); 574 memset(&mask, 0, sizeof(mask));
570 memset(&gw, 0, sizeof(gw)); /* for safety */ 575 memset(&gw, 0, sizeof(gw)); /* for safety */
571 576
572 def.sin6.sin6_len = mask.sin6.sin6_len = gw.sin6.sin6_len = 577 def.sin6.sin6_len = mask.sin6.sin6_len = gw.sin6.sin6_len =
573 sizeof(struct sockaddr_in6); 578 sizeof(struct sockaddr_in6);
574 def.sin6.sin6_family = mask.sin6.sin6_family = gw.sin6.sin6_family = AF_INET6; 579 def.sin6.sin6_family = mask.sin6.sin6_family = gw.sin6.sin6_family = AF_INET6;
575 gw.sin6.sin6_addr = dr->rtaddr; 580 gw.sin6.sin6_addr = dr->rtaddr;
576#ifndef SCOPEDROUTING 581#ifndef SCOPEDROUTING
577 gw.sin6.sin6_scope_id = 0; /* XXX */ 582 gw.sin6.sin6_scope_id = 0; /* XXX */
578#endif 583#endif
579 584
580 rtrequest(RTM_DELETE, &def.sa, &gw.sa, &mask.sa, RTF_GATEWAY, &oldrt); 585 error = rtrequest(RTM_DELETE, &def.sa, &gw.sa, &mask.sa, RTF_GATEWAY, &oldrt);
581 if (oldrt) { 586 if (oldrt) {
582 nd6_rtmsg(RTM_DELETE, oldrt); 587 nd6_rtmsg(RTM_DELETE, oldrt);
583 if (oldrt->rt_refcnt <= 0) { 588 if (oldrt->rt_refcnt <= 0) {
584 /* 589 /*
585 * XXX: borrowed from the RTM_DELETE case of 590 * XXX: borrowed from the RTM_DELETE case of
586 * rtrequest(). 591 * rtrequest().
587 */ 592 */
588 oldrt->rt_refcnt++; 593 oldrt->rt_refcnt++;
589 rtfree(oldrt); 594 rtfree(oldrt);
590 nd6_numroutes--; 595 nd6_numroutes--;
591 } 596 }
592 } 597 }
593 598
594 dr->installed = 0; 599 if (error == 0)
 600 dr->installed = 0;
 601 else
 602 log(LOG_ERR, "defrouter_delreq: "
 603 "error %d deleting default router %s on %s\n",
 604 error, ip6_sprintf(&dr->rtaddr), dr->ifp->if_xname);
595} 605}
596 606
597/* 607/*
598 * remove all default routes from default router list 608 * remove all default routes from default router list
599 */ 609 */
600void 610void
601defrouter_reset(void) 611defrouter_reset(void)
602{ 612{
603 struct nd_defrouter *dr; 613 struct nd_defrouter *dr;
604 614
605 for (dr = TAILQ_FIRST(&nd_defrouter); dr; 615 for (dr = TAILQ_FIRST(&nd_defrouter); dr;
606 dr = TAILQ_NEXT(dr, dr_entry)) 616 dr = TAILQ_NEXT(dr, dr_entry))
607 defrouter_delreq(dr); 617 defrouter_delreq(dr);
@@ -662,44 +672,44 @@ defrouter_select(void) @@ -662,44 +672,44 @@ defrouter_select(void)
662 */ 672 */
663 if (!TAILQ_FIRST(&nd_defrouter)) { 673 if (!TAILQ_FIRST(&nd_defrouter)) {
664 splx(s); 674 splx(s);
665 return; 675 return;
666 } 676 }
667 677
668 /* 678 /*
669 * Search for a (probably) reachable router from the list. 679 * Search for a (probably) reachable router from the list.
670 * We just pick up the first reachable one (if any), assuming that 680 * We just pick up the first reachable one (if any), assuming that
671 * the ordering rule of the list described in defrtrlist_update(). 681 * the ordering rule of the list described in defrtrlist_update().
672 */ 682 */
673 for (dr = TAILQ_FIRST(&nd_defrouter); dr; 683 for (dr = TAILQ_FIRST(&nd_defrouter); dr;
674 dr = TAILQ_NEXT(dr, dr_entry)) { 684 dr = TAILQ_NEXT(dr, dr_entry)) {
 685 if (dr->installed && !installed_dr)
 686 installed_dr = dr;
 687 else if (dr->installed && installed_dr) {
 688 /* this should not happen. warn for diagnosis. */
 689 log(LOG_ERR, "defrouter_select: more than one router"
 690 " is installed\n");
 691 }
 692
675 ndi = ND_IFINFO(dr->ifp); 693 ndi = ND_IFINFO(dr->ifp);
676 if (nd6_accepts_rtadv(ndi)) 694 if (!nd6_accepts_rtadv(ndi))
677 continue; 695 continue;
678 696
679 if (selected_dr == NULL && 697 if (selected_dr == NULL &&
680 (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) != NULL && 698 (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) != NULL &&
681 (ln = (struct llinfo_nd6 *)rt->rt_llinfo) != NULL && 699 (ln = (struct llinfo_nd6 *)rt->rt_llinfo) != NULL &&
682 ND6_IS_LLINFO_PROBREACH(ln)) { 700 ND6_IS_LLINFO_PROBREACH(ln)) {
683 selected_dr = dr; 701 selected_dr = dr;
684 } 702 }
685 
686 if (dr->installed && !installed_dr) 
687 installed_dr = dr; 
688 else if (dr->installed && installed_dr) { 
689 /* this should not happen. warn for diagnosis. */ 
690 log(LOG_ERR, "defrouter_select: more than one router" 
691 " is installed\n"); 
692 } 
693 } 703 }
694 /* 704 /*
695 * If none of the default routers was found to be reachable, 705 * If none of the default routers was found to be reachable,
696 * round-robin the list regardless of preference. 706 * round-robin the list regardless of preference.
697 * Otherwise, if we have an installed router, check if the selected 707 * Otherwise, if we have an installed router, check if the selected
698 * (reachable) router should really be preferred to the installed one. 708 * (reachable) router should really be preferred to the installed one.
699 * We only prefer the new router when the old one is not reachable 709 * We only prefer the new router when the old one is not reachable
700 * or when the new one has a really higher preference value. 710 * or when the new one has a really higher preference value.
701 */ 711 */
702 if (selected_dr == NULL) { 712 if (selected_dr == NULL) {
703 if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry)) 713 if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry))
704 selected_dr = TAILQ_FIRST(&nd_defrouter); 714 selected_dr = TAILQ_FIRST(&nd_defrouter);
705 else 715 else