Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/nd6_rtr.c
Show First 20 Lines • Show All 862 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* We maintain a single list of routers for multiple FIBs, only considering one | * We maintain a single list of routers for multiple FIBs, only considering one | ||||
* at a time based on the receiving interface's FIB. If @fibnum is RT_ALL_FIBS, | * at a time based on the receiving interface's FIB. If @fibnum is RT_ALL_FIBS, | ||||
* we do the whole thing multiple times. | * we do the whole thing multiple times. | ||||
*/ | */ | ||||
void | void | ||||
defrouter_select_fib(int fibnum) | defrouter_select_fib(int fibnum) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct nd_defrouter *dr, *selected_dr, *installed_dr; | struct nd_defrouter *dr, *selected_dr, *installed_dr; | ||||
struct llentry *ln = NULL; | struct llentry *ln = NULL; | ||||
NET_EPOCH_ASSERT(); | |||||
if (fibnum == RT_ALL_FIBS) { | if (fibnum == RT_ALL_FIBS) { | ||||
for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { | for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { | ||||
defrouter_select_fib(fibnum); | defrouter_select_fib(fibnum); | ||||
} | } | ||||
} | } | ||||
ND6_RLOCK(); | ND6_RLOCK(); | ||||
/* | /* | ||||
* Let's handle easy case (3) first: | * Let's handle easy case (3) first: | ||||
* If default router list is empty, there's nothing to be done. | * If default router list is empty, there's nothing to be done. | ||||
*/ | */ | ||||
if (TAILQ_EMPTY(&V_nd_defrouter)) { | if (TAILQ_EMPTY(&V_nd_defrouter)) { | ||||
ND6_RUNLOCK(); | ND6_RUNLOCK(); | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Search for a (probably) reachable router from the list. | * Search for a (probably) reachable router from the list. | ||||
* We just pick up the first reachable one (if any), assuming that | * We just pick up the first reachable one (if any), assuming that | ||||
* the ordering rule of the list described in defrtrlist_update(). | * the ordering rule of the list described in defrtrlist_update(). | ||||
*/ | */ | ||||
selected_dr = installed_dr = NULL; | selected_dr = installed_dr = NULL; | ||||
TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { | TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { | ||||
NET_EPOCH_ENTER(et); | |||||
if (selected_dr == NULL && dr->ifp->if_fib == fibnum && | if (selected_dr == NULL && dr->ifp->if_fib == fibnum && | ||||
(ln = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && | (ln = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && | ||||
ND6_IS_LLINFO_PROBREACH(ln)) { | ND6_IS_LLINFO_PROBREACH(ln)) { | ||||
selected_dr = dr; | selected_dr = dr; | ||||
defrouter_ref(selected_dr); | defrouter_ref(selected_dr); | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
if (ln != NULL) { | if (ln != NULL) { | ||||
LLE_RUNLOCK(ln); | LLE_RUNLOCK(ln); | ||||
ln = NULL; | ln = NULL; | ||||
} | } | ||||
if (dr->installed && dr->ifp->if_fib == fibnum) { | if (dr->installed && dr->ifp->if_fib == fibnum) { | ||||
if (installed_dr == NULL) { | if (installed_dr == NULL) { | ||||
installed_dr = dr; | installed_dr = dr; | ||||
Show All 27 Lines | if (selected_dr == NULL) { | ||||
TAILQ_FOREACH_FROM(dr, &V_nd_defrouter, dr_entry) { | TAILQ_FOREACH_FROM(dr, &V_nd_defrouter, dr_entry) { | ||||
if (dr->ifp->if_fib == fibnum) { | if (dr->ifp->if_fib == fibnum) { | ||||
selected_dr = dr; | selected_dr = dr; | ||||
defrouter_ref(selected_dr); | defrouter_ref(selected_dr); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} else if (installed_dr != NULL) { | } else if (installed_dr != NULL) { | ||||
NET_EPOCH_ENTER(et); | |||||
if ((ln = nd6_lookup(&installed_dr->rtaddr, 0, | if ((ln = nd6_lookup(&installed_dr->rtaddr, 0, | ||||
installed_dr->ifp)) && | installed_dr->ifp)) && | ||||
ND6_IS_LLINFO_PROBREACH(ln) && | ND6_IS_LLINFO_PROBREACH(ln) && | ||||
installed_dr->ifp->if_fib == fibnum && | installed_dr->ifp->if_fib == fibnum && | ||||
rtpref(selected_dr) <= rtpref(installed_dr)) { | rtpref(selected_dr) <= rtpref(installed_dr)) { | ||||
defrouter_rele(selected_dr); | defrouter_rele(selected_dr); | ||||
selected_dr = installed_dr; | selected_dr = installed_dr; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
if (ln != NULL) | if (ln != NULL) | ||||
LLE_RUNLOCK(ln); | LLE_RUNLOCK(ln); | ||||
} | } | ||||
ND6_RUNLOCK(); | ND6_RUNLOCK(); | ||||
/* | /* | ||||
* If we selected a router for this FIB and it's different | * If we selected a router for this FIB and it's different | ||||
* than the installed one, remove the installed router and | * than the installed one, remove the installed router and | ||||
▲ Show 20 Lines • Show All 288 Lines • ▼ Show 20 Lines | nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr, | ||||
ND6_WLOCK(); | ND6_WLOCK(); | ||||
LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry); | LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry); | ||||
V_nd6_list_genid++; | V_nd6_list_genid++; | ||||
ND6_WUNLOCK(); | ND6_WUNLOCK(); | ||||
/* ND_OPT_PI_FLAG_ONLINK processing */ | /* ND_OPT_PI_FLAG_ONLINK processing */ | ||||
if (new->ndpr_raf_onlink) { | if (new->ndpr_raf_onlink) { | ||||
struct epoch_tracker et; | |||||
ND6_ONLINK_LOCK(); | ND6_ONLINK_LOCK(); | ||||
NET_EPOCH_ENTER(et); | |||||
if ((error = nd6_prefix_onlink(new)) != 0) { | if ((error = nd6_prefix_onlink(new)) != 0) { | ||||
nd6log((LOG_ERR, "nd6_prelist_add: failed to make " | nd6log((LOG_ERR, "nd6_prelist_add: failed to make " | ||||
"the prefix %s/%d on-link on %s (errno=%d)\n", | "the prefix %s/%d on-link on %s (errno=%d)\n", | ||||
ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), | ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), | ||||
pr->ndpr_plen, if_name(pr->ndpr_ifp), error)); | pr->ndpr_plen, if_name(pr->ndpr_ifp), error)); | ||||
/* proceed anyway. XXX: is it correct? */ | /* proceed anyway. XXX: is it correct? */ | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
ND6_ONLINK_UNLOCK(); | ND6_ONLINK_UNLOCK(); | ||||
} | } | ||||
if (dr != NULL) | if (dr != NULL) | ||||
pfxrtr_add(new, dr); | pfxrtr_add(new, dr); | ||||
if (newp != NULL) | if (newp != NULL) | ||||
*newp = new; | *newp = new; | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, | ||||
struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; | struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct ifnet *ifp = new->ndpr_ifp; | struct ifnet *ifp = new->ndpr_ifp; | ||||
struct nd_prefix *pr; | struct nd_prefix *pr; | ||||
int error = 0; | int error = 0; | ||||
int auth; | int auth; | ||||
struct in6_addrlifetime lt6_tmp; | struct in6_addrlifetime lt6_tmp; | ||||
char ip6buf[INET6_ADDRSTRLEN]; | char ip6buf[INET6_ADDRSTRLEN]; | ||||
struct epoch_tracker et; | |||||
NET_EPOCH_ASSERT(); | |||||
auth = 0; | auth = 0; | ||||
if (m) { | if (m) { | ||||
/* | /* | ||||
* Authenticity for NA consists authentication for | * Authenticity for NA consists authentication for | ||||
* both IP header and IP datagrams, doesn't it ? | * both IP header and IP datagrams, doesn't it ? | ||||
*/ | */ | ||||
#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) | #if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) | ||||
auth = ((m->m_flags & M_AUTHIPHDR) && | auth = ((m->m_flags & M_AUTHIPHDR) && | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | #endif | ||||
* an address configured by stateless autoconfiguration already in the | * an address configured by stateless autoconfiguration already in the | ||||
* list of addresses associated with the interface, and the Valid | * list of addresses associated with the interface, and the Valid | ||||
* Lifetime is not 0, form an address. We first check if we have | * Lifetime is not 0, form an address. We first check if we have | ||||
* a matching prefix. | * a matching prefix. | ||||
* Note: we apply a clarification in rfc2462bis-02 here. We only | * Note: we apply a clarification in rfc2462bis-02 here. We only | ||||
* consider autoconfigured addresses while RFC2462 simply said | * consider autoconfigured addresses while RFC2462 simply said | ||||
* "address". | * "address". | ||||
*/ | */ | ||||
NET_EPOCH_ENTER(et); | |||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
struct in6_ifaddr *ifa6; | struct in6_ifaddr *ifa6; | ||||
u_int32_t remaininglifetime; | u_int32_t remaininglifetime; | ||||
if (ifa->ifa_addr->sa_family != AF_INET6) | if (ifa->ifa_addr->sa_family != AF_INET6) | ||||
continue; | continue; | ||||
ifa6 = (struct in6_ifaddr *)ifa; | ifa6 = (struct in6_ifaddr *)ifa; | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { | ||||
if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || | if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || | ||||
lt6_tmp.ia6t_pltime > maxpltime) { | lt6_tmp.ia6t_pltime > maxpltime) { | ||||
lt6_tmp.ia6t_pltime = maxpltime; | lt6_tmp.ia6t_pltime = maxpltime; | ||||
} | } | ||||
} | } | ||||
ifa6->ia6_lifetime = lt6_tmp; | ifa6->ia6_lifetime = lt6_tmp; | ||||
ifa6->ia6_updatetime = time_uptime; | ifa6->ia6_updatetime = time_uptime; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
if (ia6_match == NULL && new->ndpr_vltime) { | if (ia6_match == NULL && new->ndpr_vltime) { | ||||
int ifidlen; | int ifidlen; | ||||
/* | /* | ||||
* 5.5.3 (d) (continued) | * 5.5.3 (d) (continued) | ||||
* No address matched and the valid lifetime is non-zero. | * No address matched and the valid lifetime is non-zero. | ||||
* Create a new address. | * Create a new address. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct nd_pfxrouter *pfxrtr; | struct nd_pfxrouter *pfxrtr; | ||||
struct llentry *ln; | struct llentry *ln; | ||||
int canreach; | int canreach; | ||||
ND6_LOCK_ASSERT(); | ND6_LOCK_ASSERT(); | ||||
LIST_FOREACH(pfxrtr, &pr->ndpr_advrtrs, pfr_entry) { | |||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
LIST_FOREACH(pfxrtr, &pr->ndpr_advrtrs, pfr_entry) { | |||||
ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp); | ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp); | ||||
NET_EPOCH_EXIT(et); | |||||
if (ln == NULL) | if (ln == NULL) | ||||
continue; | continue; | ||||
canreach = ND6_IS_LLINFO_PROBREACH(ln); | canreach = ND6_IS_LLINFO_PROBREACH(ln); | ||||
LLE_RUNLOCK(ln); | LLE_RUNLOCK(ln); | ||||
if (canreach) | if (canreach) | ||||
break; | break; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
return (pfxrtr); | return (pfxrtr); | ||||
} | } | ||||
/* | /* | ||||
* Check if each prefix in the prefix list has at least one available router | * Check if each prefix in the prefix list has at least one available router | ||||
* that advertised the prefix (a router is "available" if its neighbor cache | * that advertised the prefix (a router is "available" if its neighbor cache | ||||
* entry is reachable or probably reachable). | * entry is reachable or probably reachable). | ||||
* If the check fails, the prefix may be off-link, because, for example, | * If the check fails, the prefix may be off-link, because, for example, | ||||
▲ Show 20 Lines • Show All 825 Lines • Show Last 20 Lines |