nd6_rtr.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,371 行 · 第 1/5 页
C
2,371 行
nd6log((LOG_INFO, "nd6_ra_input: mtu option " "mtu=%d sent from %s; maxmtu unknown, " "ignoring\n", mtu, ip6_sprintf(&ip6->ip6_src))); } } skip: /* * Source link layer address */ { char *lladdr = NULL; int lladdrlen = 0; if (ndopts.nd_opts_src_lladdr) { lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { nd6log((LOG_INFO, "nd6_ra_input: lladdrlen mismatch for %s " "(if %d, RA packet %d)\n", ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2)); goto bad; } nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0); /* * Installing a link-layer address might change the state of the * router's neighbor cache, which might also affect our on-link * detection of adveritsed prefixes. */ pfxlist_onlink_check(); } freeit: m_freem(m); return; bad: icmp6stat.icp6s_badra++; m_freem(m);}/* * default router list proccessing sub routines *//* tell the change to user processes watching the routing socket. */static voidnd6_rtmsg(cmd, rt) int cmd; struct rtentry *rt;{ struct rt_addrinfo info; bzero((caddr_t)&info, sizeof(info));#if (defined(__bsdi__) && _BSDI_VERSION >= 199802) /* BSDI4 */ /* maybe this is unnecessary */ info.rti_flags = rt->rt_flags;#endif info.rti_info[RTAX_DST] = rt_key(rt); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_NETMASK] = rt_mask(rt);#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addrlist->ifa_addr;#else info.rti_info[RTAX_IFP] = (struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist);#endif info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; rt_missmsg(cmd, &info, rt->rt_flags, 0);}voiddefrouter_addreq(new) struct nd_defrouter *new;{ struct sockaddr_in6 def, mask, gate; struct rtentry *newrt = NULL; int s; int error; Bzero(&def, sizeof(def)); Bzero(&mask, sizeof(mask)); Bzero(&gate, sizeof(gate)); def.sin6_len = mask.sin6_len = gate.sin6_len = sizeof(struct sockaddr_in6); def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6; gate.sin6_addr = new->rtaddr;#ifdef __NetBSD__ s = splsoftnet();#else s = splnet();#endif error = rtrequest(RTM_ADD, (struct sockaddr *)&def, (struct sockaddr *)&gate, (struct sockaddr *)&mask, RTF_GATEWAY, &newrt); if (newrt) { nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ newrt->rt_refcnt--; } if (error == 0) new->installed = 1; splx(s); return;}/* Add a route to a given interface as default */static voiddefrouter_addifreq(ifp) struct ifnet *ifp;{ struct sockaddr_in6 def, mask; struct ifaddr *ifa; struct rtentry *newrt = NULL; int error, flags;#if (defined(__bsdi__) && _BSDI_VERSION >= 199802) struct rt_addrinfo info;#endif /* remove one if we have already installed one */ if (nd6_defif_installed) defrouter_delifreq(); bzero(&def, sizeof(def)); bzero(&mask, sizeof(mask)); def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6); def.sin6_family = mask.sin6_family = AF_INET6; /* * Search for an ifaddr beloging to the specified interface. * XXX: An IPv6 address are required to be assigned on the interface. */ if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) { nd6log((LOG_ERR, /* better error? */ "defrouter_addifreq: failed to find an ifaddr " "to install a route to interface %s\n", if_name(ifp))); return; } flags = ifa->ifa_flags;#if (defined(__bsdi__) && _BSDI_VERSION >= 199802) bzero(&info, sizeof(info)); info.rti_info[RTAX_DST] = (struct sockaddr *)&def; info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)ifa->ifa_addr; info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; info.rti_info[RTAX_IFA] = (struct sockaddr *)ifa->ifa_addr; info.rti_flags = flags; error = rtrequest1(RTM_ADD, &info, &newrt);#else error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr, (struct sockaddr *)&mask, flags, &newrt);#endif if (error != 0) { nd6log((LOG_ERR, "defrouter_addifreq: failed to install a route to " "interface %s (errno = %d)\n", if_name(ifp), error)); if (newrt) /* maybe unnecessary, but do it for safety */ newrt->rt_refcnt--; } else { if (newrt) { nd6_rtmsg(RTM_ADD, newrt); newrt->rt_refcnt--; } } nd6_defif_installed = ifa; IFAREF(ifa);}/* Remove a default route points to interface */static voiddefrouter_delifreq(){ struct sockaddr_in6 def, mask; struct rtentry *oldrt = NULL; if (!nd6_defif_installed) return; Bzero(&def, sizeof(def)); Bzero(&mask, sizeof(mask)); def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6); def.sin6_family = mask.sin6_family = AF_INET6; rtrequest(RTM_DELETE, (struct sockaddr *)&def, (struct sockaddr *)nd6_defif_installed->ifa_addr, (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); if (oldrt) { nd6_rtmsg(RTM_DELETE, oldrt); if (oldrt->rt_refcnt <= 0) { /* * XXX: borrowed from the RTM_DELETE case of * rtrequest(). */ oldrt->rt_refcnt++; rtfree(oldrt); } } IFAFREE(nd6_defif_installed); nd6_defif_installed = NULL;}struct nd_defrouter *defrouter_lookup(addr, ifp) struct in6_addr *addr; struct ifnet *ifp;{ struct nd_defrouter *dr; for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)) { if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) return(dr); } return(NULL); /* search failed */}voiddefrtrlist_del(dr) struct nd_defrouter *dr;{ struct nd_defrouter *deldr = NULL; struct nd_prefix *pr; /* * Flush all the routing table entries that use the router * as a next hop. */ if (!ip6_forwarding && ip6_accept_rtadv) { /* above is a good condition? */ rt6_flush(&dr->rtaddr, dr->ifp); } if (dr->installed) { deldr = dr; defrouter_delreq(dr); } TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); /* * Also delete all the pointers to the router in each prefix lists. */ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { struct nd_pfxrouter *pfxrtr; if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) pfxrtr_del(pfxrtr); } pfxlist_onlink_check(); /* * If the router is the primary one, choose a new one. * Note that defrouter_select() will remove the current gateway * from the routing table. */ if (deldr) defrouter_select(); free(dr, M_IP6NDP);}/* * Remove the default route for a given router. * This is just a subroutine function for defrouter_select(), and should * not be called from anywhere else. */static voiddefrouter_delreq(dr) struct nd_defrouter *dr;{ struct sockaddr_in6 def, mask, gw; struct rtentry *oldrt = NULL; Bzero(&def, sizeof(def)); Bzero(&mask, sizeof(mask)); Bzero(&gw, sizeof(gw)); def.sin6_len = mask.sin6_len = gw.sin6_len = sizeof(struct sockaddr_in6); def.sin6_family = mask.sin6_family = gw.sin6_family = AF_INET6; if (dr) gw.sin6_addr = dr->rtaddr; rtrequest(RTM_DELETE, (struct sockaddr *)&def, dr ? (struct sockaddr *)&gw : NULL, (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); if (oldrt) { nd6_rtmsg(RTM_DELETE, oldrt); if (oldrt->rt_refcnt <= 0) { /* * XXX: borrowed from the RTM_DELETE case of * rtrequest(). */ oldrt->rt_refcnt++; rtfree(oldrt); } } if (dr) dr->installed = 0;}/* * remove all default routes from default router list */voiddefrouter_reset(){ struct nd_defrouter *dr; for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)) defrouter_delreq(dr); defrouter_delifreq(); /* * XXX should we also nuke any default routers in the kernel, by * going through them by rtalloc1()? */}/* * 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. */voiddefrouter_select(){#ifdef __NetBSD__ int s = splsoftnet();#else int s = splnet();#endif struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; struct rtentry *rt = NULL; struct llinfo_nd6 *ln = NULL; /* * This function should be called only when acting as an autoconfigured * host. Although the remaining part of this function is not effective * if the node is not an autoconfigured host, we explicitly exclude * such cases here for safety. */ if (ip6_forwarding || !ip6_accept_rtadv) { nd6log((LOG_WARNING, "defrouter_select: called unexpectedly (forwarding=%d, " "accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv)); splx(s); return; } /* * Let's handle easy case (3) first: * If default router list is empty, we should probably install * an interface route and assume that all destinations are on-link. */ if (!TAILQ_FIRST(&nd_defrouter)) { /* * XXX: The specification does not say this mechanism should * be restricted to hosts, but this would be not useful * (even harmful) for routers. * This test is meaningless due to a test at the beginning of * the function, but we intentionally keep it to make the note * clear. */ if (!ip6_forwarding) { if (nd6_defifp) { /* * Install a route to the default interface * as default route. */ defrouter_addifreq(nd6_defifp); } else { /* * purge the existing route. * XXX: is this really correct? */ defrouter_delifreq(); nd6log((LOG_INFO, "defrouter_select: " "there's no default router and no default" " interface\n")); } } splx(s); return; } /* * If we have a default route for the default interface, delete it. * Note that the existence of the route is checked in the delete * function. */ defrouter_delifreq(); /* * 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(). */ for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)) { if (!selected_dr && (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && ND6_IS_LLINFO_PROBREACH(ln)) { selected_dr = dr; } if (dr->installed && !installed_dr) installed_dr = dr; else if (dr->installed && installed_dr) { /* this should not happen. warn for diagnosis. */ log(LOG_ERR, "defrouter_select: more than one router" " is installed\n"); } } /* * 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 (!selected_dr) { if (!installed_dr || !TAILQ_NEXT(installed_dr, dr_entry)) selected_dr = TAILQ_FIRST(&nd_defrouter); else selected_dr = TAILQ_NEXT(installed_dr, dr_entry); } else if (installed_dr && (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && ND6_IS_LLINFO_PROBREACH(ln) && rtpref(selected_dr) <= rtpref(installed_dr)) { selected_dr = installed_dr; } /* * 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. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?