FreeBSD/sys/netinet6/nd6_rtr.c
/*
 * Default Router Selection according to Section 6.3.6 of RFC 2461 and
 * draft-ietf-ipngwg-router-selection:
 * 1) Routers that are reachable or probably reachable should be preferred.
 *    If we have more than one (probably) reachable router, prefer ones
 *    with the highest router preference.
 * 2) When no routers on the list are known to be reachable or
 *    probably reachable, routers SHOULD be selected in a round-robin
 *    fashion, regardless of router preference values.
 * 3) If the Default Router List is empty, assume that all
 *    destinations are on-link.
 *
 * We assume nd_defrouter is sorted by router preference value.
 * Since the code below covers both with and without router preference cases,
 * we do not need to classify the cases by ifdef.
 *
 * At this moment, we do not try to install more than one default router,
 * even when the multipath routing is available, because we're not sure about
 * the benefits for stub hosts comparing to the risk of making the code
 * complicated and the possibility of introducing bugs.
 */
Default Router Selection according to Section 6.3.6 of RFC 2461 and
draft-ietf-ipngwg-router-selection:
1) Routers that are reachable or probably reachable should be preferred.
If we have more than one (probably) reachable router, prefer ones
with the highest router preference.
2) When no routers on the list are known to be reachable or
probably reachable, routers SHOULD be selected in a round-robin
fashion, regardless of router preference values.
3) If the Default Router List is empty, assume that all
destinations are on-link.

We assume nd_defrouter is sorted by router preference value.
Since the code below covers both with and without router preference cases,
we do not need to classify the cases by ifdef.

At this moment, we do not try to install more than one default router,
even when the multipath routing is available, because we're not sure about
the benefits for stub hosts comparing to the risk of making the code
complicated and the possibility of introducing bugs.
Default Router Selection according to Section 6 . 3 . 6 of RFC 2461 and draft - ietf - ipngwg - router - selection : 1 ) Routers that are reachable or probably reachable should be preferred . If we have more than one ( probably ) reachable router prefer ones with the highest router preference . 2 ) When no routers on the list are known to be reachable or probably reachable routers SHOULD be selected in a round - robin fashion regardless of router preference values . 3 ) If the Default Router List is empty assume that all destinations are on - link . We assume nd_defrouter is sorted by router preference value . Since the code below covers both with and without router preference cases we do not need to classify the cases by ifdef . At this moment we do not try to install more than one default router even when the multipath routing is available because we ' re not sure about the benefits for stub hosts comparing to the risk of making the code complicated and the possibility of introducing bugs .
void
defrouter_select(void)
{
	struct nd_defrouter *dr, *selected_dr, *installed_dr;
	struct llentry *ln = NULL;
	ND6_RLOCK();
	if (TAILQ_EMPTY(&V_nd_defrouter)) {
		ND6_RUNLOCK();
		return;
	}
	selected_dr = installed_dr = NULL;
	TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) {
		IF_AFDATA_RLOCK(dr->ifp);
		if (selected_dr == NULL &&
		    (ln = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
		    ND6_IS_LLINFO_PROBREACH(ln)) {
			selected_dr = dr;
			defrouter_ref(selected_dr);
		}
		IF_AFDATA_RUNLOCK(dr->ifp);
		if (ln != NULL) {
			LLE_RUNLOCK(ln);
			ln = NULL;
		}
		if (dr->installed) {
			if (installed_dr == NULL) {
				installed_dr = dr;
				defrouter_ref(installed_dr);
			} else {
				log(LOG_ERR,
		    "defrouter_select: more than one router is installed\n");
			}
		}
	}
	if (selected_dr == NULL) {
		if (installed_dr == NULL ||
		    TAILQ_NEXT(installed_dr, dr_entry) == NULL)
			selected_dr = TAILQ_FIRST(&V_nd_defrouter);
		else
			selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
		defrouter_ref(selected_dr);
	} else if (installed_dr != NULL) {
		IF_AFDATA_RLOCK(installed_dr->ifp);
		if ((ln = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) &&
		    ND6_IS_LLINFO_PROBREACH(ln) &&
		    rtpref(selected_dr) <= rtpref(installed_dr)) {
			defrouter_rele(selected_dr);
			selected_dr = installed_dr;
		}
		IF_AFDATA_RUNLOCK(installed_dr->ifp);
		if (ln != NULL)
			LLE_RUNLOCK(ln);
	}
	ND6_RUNLOCK();
	if (installed_dr != selected_dr) {
		if (installed_dr != NULL) {
			defrouter_delreq(installed_dr);
			defrouter_rele(installed_dr);
		}
		defrouter_addreq(selected_dr);
	}
	defrouter_rele(selected_dr);
}
void defrouter_select ( void ) { struct nd_defrouter * dr , * selected_dr , * installed_dr ; struct llentry * ln = NULL ; ND6_RLOCK ( ) ; if ( TAILQ_EMPTY ( & V_nd_defrouter ) ) { ND6_RUNLOCK ( ) ; return ; } selected_dr = installed_dr = NULL ; TAILQ_FOREACH ( dr , & V_nd_defrouter , dr_entry ) { IF_AFDATA_RLOCK ( dr -> ifp ) ; if ( selected_dr == NULL && ( ln = nd6_lookup ( & dr -> rtaddr , 0 , dr -> ifp ) ) && ND6_IS_LLINFO_PROBREACH ( ln ) ) { selected_dr = dr ; defrouter_ref ( selected_dr ) ; } IF_AFDATA_RUNLOCK ( dr -> ifp ) ; if ( ln != NULL ) { LLE_RUNLOCK ( ln ) ; ln = NULL ; } if ( dr -> installed ) { if ( installed_dr == NULL ) { installed_dr = dr ; defrouter_ref ( installed_dr ) ; } else { log ( LOG_ERR , " \n " ) ; } } } if ( selected_dr == NULL ) { if ( installed_dr == NULL || TAILQ_NEXT ( installed_dr , dr_entry ) == NULL ) selected_dr = TAILQ_FIRST ( & V_nd_defrouter ) ; else selected_dr = TAILQ_NEXT ( installed_dr , dr_entry ) ; defrouter_ref ( selected_dr ) ; } else if ( installed_dr != NULL ) { IF_AFDATA_RLOCK ( installed_dr -> ifp ) ; if ( ( ln = nd6_lookup ( & installed_dr -> rtaddr , 0 , installed_dr -> ifp ) ) && ND6_IS_LLINFO_PROBREACH ( ln ) && rtpref ( selected_dr ) <= rtpref ( installed_dr ) ) { defrouter_rele ( selected_dr ) ; selected_dr = installed_dr ; } IF_AFDATA_RUNLOCK ( installed_dr -> ifp ) ; if ( ln != NULL ) LLE_RUNLOCK ( ln ) ; } ND6_RUNLOCK ( ) ; if ( installed_dr != selected_dr ) { if ( installed_dr != NULL ) { defrouter_delreq ( installed_dr ) ; defrouter_rele ( installed_dr ) ; } defrouter_addreq ( selected_dr ) ; } defrouter_rele ( selected_dr ) ; }
Default Router Selection according to Section 6.3.6 of RFC 2461 and
 draft-ietf-ipngwg-router-selection:
 1) Routers that are reachable or probably reachable should be preferred.
Default Router Selection according to Section 6 . 3 . 6 of RFC 2461 and draft - ietf - ipngwg - router - selection : 1 ) Routers that are reachable or probably reachable should be preferred .
/*
	 * Let's handle easy case (3) first:
	 * If default router list is empty, there's nothing to be done.
	 */ /*
	 * Search for a (probably) reachable router from the list.
	 * We just pick up the first reachable one (if any), assuming that
	 * the ordering rule of the list described in defrtrlist_update().
	 */ /* this should not happen.  warn for diagnosis. */ /*
	 * If none of the default routers was found to be reachable,
	 * round-robin the list regardless of preference.
	 * Otherwise, if we have an installed router, check if the selected
	 * (reachable) router should really be preferred to the installed one.
	 * We only prefer the new router when the old one is not reachable
	 * or when the new one has a really higher preference value.
	 */ /*
	 * If the selected router is different than the installed one,
	 * remove the installed router and install the selected one.
	 * Note that the selected router is never NULL here.
	 */