From af5333e0a02b2295304d4e029b15ee15a4fe2b3a Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 4 Nov 2013 11:33:00 +0100 Subject: Update to FreeBSD 8.4 --- freebsd/sys/netinet6/nd6_rtr.c | 274 +++++++++++++++++++++++------------------ 1 file changed, 157 insertions(+), 117 deletions(-) (limited to 'freebsd/sys/netinet6/nd6_rtr.c') diff --git a/freebsd/sys/netinet6/nd6_rtr.c b/freebsd/sys/netinet6/nd6_rtr.c index f2a07d96..4da54fa6 100644 --- a/freebsd/sys/netinet6/nd6_rtr.c +++ b/freebsd/sys/netinet6/nd6_rtr.c @@ -86,6 +86,9 @@ static int in6_init_prefix_ltimes(struct nd_prefix *); static void in6_init_address_ltimes __P((struct nd_prefix *, struct in6_addrlifetime *)); +static int nd6_prefix_onlink(struct nd_prefix *); +static int nd6_prefix_offlink(struct nd_prefix *); + static int rt6_deleteroute(struct radix_node *, void *); VNET_DECLARE(int, nd6_recalc_reachtm_interval); @@ -443,21 +446,21 @@ nd6_rtmsg(int cmd, struct rtentry *rt) info.rti_info[RTAX_NETMASK] = rt_mask(rt); ifp = rt->rt_ifp; if (ifp != NULL) { - IF_ADDR_LOCK(ifp); + IF_ADDR_RLOCK(ifp); ifa = TAILQ_FIRST(&ifp->if_addrhead); info.rti_info[RTAX_IFP] = ifa->ifa_addr; ifa_ref(ifa); - IF_ADDR_UNLOCK(ifp); + IF_ADDR_RUNLOCK(ifp); info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; } else ifa = NULL; - rt_missmsg(cmd, &info, rt->rt_flags, 0); + rt_missmsg_fib(cmd, &info, rt->rt_flags, 0, rt->rt_fibnum); if (ifa != NULL) ifa_free(ifa); } -void +static void defrouter_addreq(struct nd_defrouter *new) { struct sockaddr_in6 def, mask, gate; @@ -475,9 +478,9 @@ defrouter_addreq(struct nd_defrouter *new) gate.sin6_addr = new->rtaddr; s = splnet(); - error = rtrequest(RTM_ADD, (struct sockaddr *)&def, + error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def, (struct sockaddr *)&gate, (struct sockaddr *)&mask, - RTF_GATEWAY, &newrt); + RTF_GATEWAY, &newrt, RT_DEFAULT_FIB); if (newrt) { nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ RTFREE(newrt); @@ -493,8 +496,7 @@ defrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) { struct nd_defrouter *dr; - for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; - dr = TAILQ_NEXT(dr, dr_entry)) { + TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) return (dr); } @@ -522,9 +524,9 @@ defrouter_delreq(struct nd_defrouter *dr) def.sin6_family = gate.sin6_family = AF_INET6; gate.sin6_addr = dr->rtaddr; - rtrequest(RTM_DELETE, (struct sockaddr *)&def, + in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def, (struct sockaddr *)&gate, - (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); + (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, RT_DEFAULT_FIB); if (oldrt) { nd6_rtmsg(RTM_DELETE, oldrt); RTFREE(oldrt); @@ -541,8 +543,7 @@ defrouter_reset(void) { struct nd_defrouter *dr; - for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; - dr = TAILQ_NEXT(dr, dr_entry)) + TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) defrouter_delreq(dr); /* @@ -573,7 +574,7 @@ defrtrlist_del(struct nd_defrouter *dr) /* * Also delete all the pointers to the router in each prefix lists. */ - for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { struct nd_pfxrouter *pfxrtr; if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) pfxrtr_del(pfxrtr); @@ -637,7 +638,7 @@ defrouter_select(void) * Let's handle easy case (3) first: * If default router list is empty, there's nothing to be done. */ - if (!TAILQ_FIRST(&V_nd_defrouter)) { + if (TAILQ_EMPTY(&V_nd_defrouter)) { splx(s); return; } @@ -647,15 +648,14 @@ defrouter_select(void) * We just pick up the first reachable one (if any), assuming that * the ordering rule of the list described in defrtrlist_update(). */ - for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; - dr = TAILQ_NEXT(dr, dr_entry)) { - IF_AFDATA_LOCK(dr->ifp); + 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; } - IF_AFDATA_UNLOCK(dr->ifp); + IF_AFDATA_RUNLOCK(dr->ifp); if (ln != NULL) { LLE_RUNLOCK(ln); ln = NULL; @@ -683,13 +683,13 @@ defrouter_select(void) else selected_dr = TAILQ_NEXT(installed_dr, dr_entry); } else if (installed_dr) { - IF_AFDATA_LOCK(installed_dr->ifp); + 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)) { selected_dr = installed_dr; } - IF_AFDATA_UNLOCK(installed_dr->ifp); + IF_AFDATA_RUNLOCK(installed_dr->ifp); if (ln != NULL) LLE_RUNLOCK(ln); } @@ -757,9 +757,10 @@ defrtrlist_update(struct nd_defrouter *new) /* * If the preference does not change, there's no need - * to sort the entries. + * to sort the entries. Also make sure the selected + * router is still installed in the kernel. */ - if (rtpref(new) == oldpref) { + if (dr->installed && rtpref(new) == oldpref) { splx(s); return (dr); } @@ -804,8 +805,7 @@ insert: */ /* insert at the end of the group */ - for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; - dr = TAILQ_NEXT(dr, dr_entry)) { + TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { if (rtpref(n) > rtpref(dr)) break; } @@ -826,7 +826,7 @@ pfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) { struct nd_pfxrouter *search; - for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { + LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) { if (search->router == dr) break; } @@ -862,8 +862,7 @@ nd6_prefix_lookup(struct nd_prefixctl *key) { struct nd_prefix *search; - for (search = V_nd_prefix.lh_first; - search; search = search->ndpr_next) { + LIST_FOREACH(search, &V_nd_prefix, ndpr_entry) { if (key->ndpr_ifp == search->ndpr_ifp && key->ndpr_plen == search->ndpr_plen && in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr, @@ -969,9 +968,7 @@ prelist_remove(struct nd_prefix *pr) LIST_REMOVE(pr, ndpr_entry); /* free list of routers that adversed the prefix */ - for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { - next = pfr->pfr_next; - + LIST_FOREACH_SAFE(pfr, &pr->ndpr_advrtrs, pfr_entry, next) { free(pfr, M_IP6NDP); } splx(s); @@ -1119,7 +1116,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, * consider autoconfigured addresses while RFC2462 simply said * "address". */ - IF_ADDR_LOCK(ifp); + IF_ADDR_RLOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct in6_ifaddr *ifa6; u_int32_t remaininglifetime; @@ -1242,7 +1239,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, ifa6->ia6_lifetime = lt6_tmp; ifa6->ia6_updatetime = time_second; } - IF_ADDR_UNLOCK(ifp); + IF_ADDR_RUNLOCK(ifp); if (ia6_match == NULL && new->ndpr_vltime) { int ifidlen; @@ -1334,11 +1331,10 @@ find_pfxlist_reachable_router(struct nd_prefix *pr) struct llentry *ln; int canreach; - for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr != NULL; - pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { - IF_AFDATA_LOCK(pfxrtr->router->ifp); + LIST_FOREACH(pfxrtr, &pr->ndpr_advrtrs, pfr_entry) { + IF_AFDATA_RLOCK(pfxrtr->router->ifp); ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp); - IF_AFDATA_UNLOCK(pfxrtr->router->ifp); + IF_AFDATA_RUNLOCK(pfxrtr->router->ifp); if (ln == NULL) continue; canreach = ND6_IS_LLINFO_PROBREACH(ln); @@ -1374,7 +1370,7 @@ pfxlist_onlink_check() * Check if there is a prefix that has a reachable advertising * router. */ - for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) break; } @@ -1384,12 +1380,10 @@ pfxlist_onlink_check() * that does not advertise any prefixes. */ if (pr == NULL) { - for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; - dr = TAILQ_NEXT(dr, dr_entry)) { + TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { struct nd_prefix *pr0; - for (pr0 = V_nd_prefix.lh_first; pr0; - pr0 = pr0->ndpr_next) { + LIST_FOREACH(pr0, &V_nd_prefix, ndpr_entry) { if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) break; } @@ -1397,7 +1391,7 @@ pfxlist_onlink_check() break; } } - if (pr != NULL || (TAILQ_FIRST(&V_nd_defrouter) && pfxrtr == NULL)) { + if (pr != NULL || (!TAILQ_EMPTY(&V_nd_defrouter) && pfxrtr == NULL)) { /* * There is at least one prefix that has a reachable router, * or at least a router which probably does not advertise @@ -1407,7 +1401,7 @@ pfxlist_onlink_check() * Detach prefixes which have no reachable advertising * router, and attach other prefixes. */ - for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { /* XXX: a link-local prefix should never be detached */ if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) continue; @@ -1431,7 +1425,7 @@ pfxlist_onlink_check() } } else { /* there is no prefix that has a reachable router */ - for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) continue; @@ -1454,7 +1448,7 @@ pfxlist_onlink_check() * interfaces. Such cases will be handled in nd6_prefix_onlink, * so we don't have to care about them. */ - for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { int e; char ip6buf[INET6_ADDRSTRLEN]; @@ -1552,19 +1546,92 @@ pfxlist_onlink_check() } } -int +static int +nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) +{ + static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; + struct radix_node_head *rnh; + struct rtentry *rt; + struct sockaddr_in6 mask6; + u_long rtflags; + int error, a_failure, fibnum; + + /* + * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. + * ifa->ifa_rtrequest = nd6_rtrequest; + */ + bzero(&mask6, sizeof(mask6)); + mask6.sin6_len = sizeof(mask6); + mask6.sin6_addr = pr->ndpr_mask; + rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP; + + a_failure = 0; + for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { + + rt = NULL; + error = in6_rtrequest(RTM_ADD, + (struct sockaddr *)&pr->ndpr_prefix, ifa->ifa_addr, + (struct sockaddr *)&mask6, rtflags, &rt, fibnum); + if (error == 0) { + KASSERT(rt != NULL, ("%s: in6_rtrequest return no " + "error(%d) but rt is NULL, pr=%p, ifa=%p", __func__, + error, pr, ifa)); + + rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6); + /* XXX what if rhn == NULL? */ + RADIX_NODE_HEAD_LOCK(rnh); + RT_LOCK(rt); + if (rt_setgate(rt, rt_key(rt), + (struct sockaddr *)&null_sdl) == 0) { + struct sockaddr_dl *dl; + + dl = (struct sockaddr_dl *)rt->rt_gateway; + dl->sdl_type = rt->rt_ifp->if_type; + dl->sdl_index = rt->rt_ifp->if_index; + } + RADIX_NODE_HEAD_UNLOCK(rnh); + nd6_rtmsg(RTM_ADD, rt); + RT_UNLOCK(rt); + pr->ndpr_stateflags |= NDPRF_ONLINK; + } else { + char ip6buf[INET6_ADDRSTRLEN]; + char ip6bufg[INET6_ADDRSTRLEN]; + char ip6bufm[INET6_ADDRSTRLEN]; + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add " + "route for a prefix (%s/%d) on %s, gw=%s, mask=%s, " + "flags=%lx errno = %d\n", + ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(pr->ndpr_ifp), + ip6_sprintf(ip6bufg, &sin6->sin6_addr), + ip6_sprintf(ip6bufm, &mask6.sin6_addr), + rtflags, error)); + + /* Save last error to return, see rtinit(). */ + a_failure = error; + } + + if (rt != NULL) { + RT_LOCK(rt); + RT_REMREF(rt); + RT_UNLOCK(rt); + } + } + + /* Return the last error we got. */ + return (a_failure); +} + +static int nd6_prefix_onlink(struct nd_prefix *pr) { struct ifaddr *ifa; struct ifnet *ifp = pr->ndpr_ifp; - struct sockaddr_in6 mask6; struct nd_prefix *opr; - u_long rtflags; int error = 0; - struct radix_node_head *rnh; - struct rtentry *rt = NULL; char ip6buf[INET6_ADDRSTRLEN]; - struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; /* sanity check */ if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { @@ -1582,7 +1649,7 @@ nd6_prefix_onlink(struct nd_prefix *pr) * Although such a configuration is expected to be rare, we explicitly * allow it. */ - for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) { + LIST_FOREACH(opr, &V_nd_prefix, ndpr_entry) { if (opr == pr) continue; @@ -1603,14 +1670,14 @@ nd6_prefix_onlink(struct nd_prefix *pr) IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); if (ifa == NULL) { /* XXX: freebsd does not have ifa_ifwithaf */ - IF_ADDR_LOCK(ifp); + IF_ADDR_RLOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET6) break; } if (ifa != NULL) ifa_ref(ifa); - IF_ADDR_UNLOCK(ifp); + IF_ADDR_RUNLOCK(ifp); /* should we care about ia6_flags? */ } if (ifa == NULL) { @@ -1628,64 +1695,24 @@ nd6_prefix_onlink(struct nd_prefix *pr) return (0); } - /* - * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. - * ifa->ifa_rtrequest = nd6_rtrequest; - */ - bzero(&mask6, sizeof(mask6)); - mask6.sin6_len = sizeof(mask6); - mask6.sin6_addr = pr->ndpr_mask; - rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP; - error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, - ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt); - if (error == 0) { - if (rt != NULL) /* this should be non NULL, though */ { - rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6); - /* XXX what if rhn == NULL? */ - RADIX_NODE_HEAD_LOCK(rnh); - RT_LOCK(rt); - if (!rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl)) { - ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = - rt->rt_ifp->if_type; - ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = - rt->rt_ifp->if_index; - } - RADIX_NODE_HEAD_UNLOCK(rnh); - nd6_rtmsg(RTM_ADD, rt); - RT_UNLOCK(rt); - } - pr->ndpr_stateflags |= NDPRF_ONLINK; - } else { - char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN]; - nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" - " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " - "errno = %d\n", - ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen, if_name(ifp), - ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), - ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error)); - } + error = nd6_prefix_onlink_rtrequest(pr, ifa); - if (rt != NULL) { - RT_LOCK(rt); - RT_REMREF(rt); - RT_UNLOCK(rt); - } if (ifa != NULL) ifa_free(ifa); return (error); } -int +static int nd6_prefix_offlink(struct nd_prefix *pr) { int error = 0; struct ifnet *ifp = pr->ndpr_ifp; struct nd_prefix *opr; struct sockaddr_in6 sa6, mask6; - struct rtentry *rt = NULL; + struct rtentry *rt; char ip6buf[INET6_ADDRSTRLEN]; + int fibnum, a_failure; /* sanity check */ if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { @@ -1705,15 +1732,28 @@ nd6_prefix_offlink(struct nd_prefix *pr) mask6.sin6_family = AF_INET6; mask6.sin6_len = sizeof(sa6); bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); - error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, - (struct sockaddr *)&mask6, 0, &rt); + + a_failure = 0; + for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { + rt = NULL; + error = in6_rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, + (struct sockaddr *)&mask6, 0, &rt, fibnum); + if (error == 0) { + /* report the route deletion to the routing socket. */ + if (rt != NULL) + nd6_rtmsg(RTM_DELETE, rt); + } else { + /* Save last error to return, see rtinit(). */ + a_failure = error; + } + if (rt != NULL) { + RTFREE(rt); + } + } + error = a_failure; if (error == 0) { pr->ndpr_stateflags &= ~NDPRF_ONLINK; - /* report the route deletion to the routing socket. */ - if (rt != NULL) - nd6_rtmsg(RTM_DELETE, rt); - /* * There might be the same prefix on another interface, * the prefix which could not be on-link just because we have @@ -1721,7 +1761,7 @@ nd6_prefix_offlink(struct nd_prefix *pr) * If there's one, try to make the prefix on-link on the * interface. */ - for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) { + LIST_FOREACH(opr, &V_nd_prefix, ndpr_entry) { if (opr == pr) continue; @@ -1761,10 +1801,6 @@ nd6_prefix_offlink(struct nd_prefix *pr) if_name(ifp), error)); } - if (rt != NULL) { - RTFREE(rt); - } - return (error); } @@ -2081,6 +2117,7 @@ void rt6_flush(struct in6_addr *gateway, struct ifnet *ifp) { struct radix_node_head *rnh; + u_int fibnum; int s = splnet(); /* We'll care only link-local addresses */ @@ -2089,13 +2126,16 @@ rt6_flush(struct in6_addr *gateway, struct ifnet *ifp) return; } - rnh = rt_tables_get_rnh(0, AF_INET6); - if (rnh == NULL) - return; + /* XXX Do we really need to walk any but the default FIB? */ + for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { + rnh = rt_tables_get_rnh(fibnum, AF_INET6); + if (rnh == NULL) + continue; - RADIX_NODE_HEAD_LOCK(rnh); - rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); - RADIX_NODE_HEAD_UNLOCK(rnh); + RADIX_NODE_HEAD_LOCK(rnh); + rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); + RADIX_NODE_HEAD_UNLOCK(rnh); + } splx(s); } @@ -2128,8 +2168,8 @@ rt6_deleteroute(struct radix_node *rn, void *arg) if ((rt->rt_flags & RTF_HOST) == 0) return (0); - return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, - rt_mask(rt), rt->rt_flags, 0)); + return (in6_rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, + rt_mask(rt), rt->rt_flags, NULL, rt->rt_fibnum)); #undef SIN6 } -- cgit v1.2.3