📄 route.c
字号:
now = tickGet(); if ( (pRoute->rt_flags & RTF_DELETE) && !(pRoute->rt_flags & RTF_STATIC)) { pCount->found++; if (pCount->draining || pRoute->rt_rmx.rmx_expire <= now) { if (pRoute->rt_refcnt > 0) panic ("routeKill removing route in use?"); error = rtrequest (RTM_DELETE, (struct sockaddr *)rt_key (pRoute), pRoute->rt_gateway, rt_mask (pRoute), pRoute->rt_flags, 0); if (!error) pCount->killed++; } else { if (pCount->updating && (pRoute->rt_rmx.rmx_expire - now > routePendInterval)) pRoute->rt_rmx.rmx_expire = now + routePendInterval; if (pRoute->rt_rmx.rmx_expire < pCount->nextstop) pCount->nextstop = pRoute->rt_rmx.rmx_expire; } } return (0); } /* * Remove all unused routes cloned from entries to remote destinations, * regardless of expiration time. */void routeDrain (void) { struct radix_node_head *pHead; struct rtqk_arg count; int s; pHead = rt_tables [AF_INET]; if (pHead == NULL) /* Missing routing table. */ return; count.found = count.killed = 0; count.rnh = pHead; count.nextstop = 0; count.draining = 1; count.updating = 0; s = splnet (); rn_walktree (pHead, routeUpdate, &count); splx (s); }/* * Packet routing routines. */voidrtalloc(ro) register struct route *ro;{ if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) return; /* XXX */ ro->ro_rt = rtalloc1(&ro->ro_dst, 1, 1);} /* * This version of the route search routine is modified to avoid route * cloning when forwarding packets to remote destinations. Cloned routes * to local (directly connected) destinations store the associated * hardware address obtained with ARP, if any, as well as the path MTU * information. Cloned routes to remote destinations are only necessary * for path MTU discovery, and should only exist when the Internet host * originates the traffic, not when it forwards it as a router. * * The routine also permits the caller to ignore matching route entries * associated with an interface which is disabled. */struct rtentry *rtalloc1(dst, report, skipFlag) register struct sockaddr *dst; int report; BOOL skipFlag; /* ignore routes if interface is down? */{ register struct radix_node_head *rnh = rt_tables[dst->sa_family]; register struct rtentry *rt; register struct radix_node *rn; struct rtentry *newrt = 0; struct rt_addrinfo info; u_long tosRtMask; /* TOS route mask */ u_long newRtMask; /* TOS 0 route mask */ int s = splnet(), err = 0, msgtype = RTM_MISS; struct rtentry * tosRt = NULL; u_char savedTos; /* * save original tos since we overwrite it temporarily in the * dst socketaddr */ savedTos = TOS_GET (dst); /* * The Type of Service octet consists of three fields: * * 0 1 2 3 4 5 6 7 * +-----+-----+-----+-----+-----+-----+-----+-----+ * | | | | * | PRECEDENCE | TOS | MBZ | * | | | | * +-----+-----+-----+-----+-----+-----+-----+-----+ * * Precedence bits should not be considered when searching * the table. An existing matching route would not be found * and if a new route were created, since dst is copied to * generate the key, precedence bits would be part * of the new route's TOS field which is wrong. This * would create a leak if this wrong route were created * for a local address. ARP would hold on to a packet, * while it resolves the local address. When the reply * comes back, since ARP does not look for routes with * TOS set, the packet would never be sent. * */ TOS_SET(dst, savedTos & 0x1f);match: if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh, skipFlag)) && ((rn->rn_flags & RNF_ROOT) == 0)) { newrt = rt = (struct rtentry *)rn; if ( (dst->sa_family == AF_INET) && (rt->rt_refcnt == 0) && (rt->rt_flags & RTF_DELETE) && !(rt->rt_flags & RTF_STATIC)) { /* * Reusing a (cloned) route to a remote destination. * Remove deletion tag and reset timer. * * NOTE: All manually added proxy ARP entries include * the RTF_ANNOUNCE flag which uses the same value as * the RTF_DELETE flag. The preceding test for RTF_STATIC * preserves the flag settings for those ARP entries, * even though the removal of RTF_ANNOUNCE should be * harmless since its only purpose is to trigger the * gratuitous ARP request when the entry is created. */ rt->rt_flags &= ~RTF_DELETE; rt->rt_rmx.rmx_expire = 0; } /* * Ignore the cloning flag when forwarding data * (report == 2) to a remote destination. If the * destination of the forwarded packet is directly * reachable, this search will still create a cloned * entry to hold the ARP information for the target host. */ if ( (rt->rt_flags & RTF_CLONING) && (report == 1 || (report == 2 && !(rt->rt_flags & RTF_GATEWAY)))) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 17, 9, WV_NETEVENT_RTALLOC_CLONE, ((struct sockaddr_in *)rt_key (rt))->sin_addr.s_addr, ((struct sockaddr_in *)dst)->sin_addr.s_addr)#endif /* INCLUDE_WVNET */#endif err = rtrequest(RTM_RESOLVE, dst, SA(0), SA(0), 0, &newrt); if (err) { newrt = rt; rt->rt_refcnt++; goto miss; } if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { msgtype = RTM_RESOLVE; goto miss; } } else {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_DSTADDROUT_MARKER_1 (NET_AUX_EVENT, WV_NET_INFO, 18, 10, ((struct sockaddr_in *)dst)->sin_addr.s_addr, WV_NETEVENT_RTALLOC_SEARCHGOOD, ((struct sockaddr_in *)dst)->sin_addr.s_addr)#endif /* INCLUDE_WVNET */#endif rt->rt_refcnt++; } } else { rtstat.rts_unreach++; miss:#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_CRITICAL, 26, 5, WV_NETEVENT_RTALLOC_SEARCHFAIL, ((struct sockaddr_in *)dst)->sin_addr.s_addr)#endif /* INCLUDE_WVNET */#endif if (report) { bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = dst; if (rtMissMsgHook) (*rtMissMsgHook) (msgtype, &info, 0, err); } } /* * RFC 1583 Section 11.1: * * "Select the routing table entry whose value matches the TOS found * in the packet header. If there is no routing table entry for * this TOS, select the routing table entry for TOS 0. In other * words, packets requesting TOS X are routed along the TOS 0 * path if a TOS X path does not exist." * See also RFC 1349, Appendix B.4. */ if (TOS_GET (dst) != 0) { TOS_SET (dst, 0); tosRt = newrt; newrt = NULL; goto match; } /* * tosRt is the TOS route match, if any. If none exists, tosRt is the * default route ("0.0.0.0"), if any. Otherwise, tosRt is NULL. * newrt is the TOS 0 route. */ if (tosRt != NULL) { if (newrt != NULL) { /* * Host route entries created by ARP have null masks with * implied mask = 0xffffffff */ tosRtMask = (rt_mask (tosRt) == NULL) ? 0xffffffff : ((struct sockaddr_in *) rt_mask (tosRt))->sin_addr.s_addr;#ifdef RTALLOC_DEBUG printf("\nBEST MATCHING TOS ROUTE:\n"); routeEntryDebugShow ((struct radix_node *)tosRt); printf("\nTOS 0 ROUTE:\n"); routeEntryDebugShow ((struct radix_node *)newrt);#endif /* RTALLOC_DEBUG */ newRtMask = (rt_mask (newrt) == NULL) ? 0xffffffff : ((struct sockaddr_in *) rt_mask (newrt))->sin_addr.s_addr; /* * select the route with longest netmask. we assume * contiguous masks starting at the same bit position. * The default route has a mask = 0x00000000 */ if (tosRtMask >= newRtMask) { RTFREE (newrt); newrt = tosRt; } else { /* newrt is more specific: keep it */ RTFREE (tosRt); } } else /* newrt is NULL */ { /* * Restore previously found TOS route. Can happen if there is a * route entered with TOS set, but no default route exists nor * route match with 0 TOS. */ newrt = tosRt; } }#ifdef RTALLOC_DEBUG if (savedTos && newrt != NULL) { printf ("\nSELECTED ROUTE:\n"); routeEntryDebugShow ((struct radix_node *)newrt); }#endif /* RTALLOC_DEBUG */ /* Restore the saved TOS. */ TOS_SET (dst, savedTos); splx(s); return (newrt);}voidrtfree(rt) register struct rtentry *rt;{ register struct ifaddr *ifa;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ if (rt) { WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 19, 11, WV_NETEVENT_RTFREE_START, ((struct sockaddr_in *)rt_key (rt))->sin_addr.s_addr, rt->rt_refcnt) } else { WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 19, 11, WV_NETEVENT_RTFREE_START, 0, 0) }#endif /* INCLUDE_WVNET */#endif if (rt == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_EMERGENCY event */ WV_NET_MARKER_0 (NET_AUX_EVENT, WV_NET_EMERGENCY, 21, 1, WV_NETEVENT_RTFREE_PANIC)#endif /* INCLUDE_WVNET */#endif panic("rtfree"); } rt->rt_refcnt--; if (rt_key(rt)->sa_family == AF_INET) { /* * If route was cloned for path MTU results, mark for later * removal (if not reused) instead of deleting immediately. */ if ( (rt->rt_refcnt == 0) && (rt->rt_flags & RTF_UP) && (rt->rt_flags & RTF_HOST) && !(rt->rt_flags & RTF_LLINFO) && (rt->rt_flags & RTF_CLONED)) { rt->rt_flags |= RTF_DELETE; if (rt->rt_rmx.rmx_expire == 0) /* Not yet assigned. */ rt->rt_rmx.rmx_expire = tickGet() + routePendInterval; } } if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_EMERGENCY event */ WV_NET_MARKER_0 (NET_AUX_EVENT, WV_NET_EMERGENCY, 21, 1, WV_NETEVENT_RTFREE_PANIC)#endif /* INCLUDE_WVNET */#endif panic ("rtfree 2"); } rttrash--; if (rt->rt_refcnt < 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ALERT event */ WV_NET_MARKER_0 (NET_AUX_EVENT, WV_NET_ALERT, 8, 4, WV_NETEVENT_RTFREE_BADREFCNT)#endif /* INCLUDE_WVNET */#endif logMsg ("rtfree: %x not freed (neg refs)\n", (int)rt, 0, 0, 0, 0, 0); return; } ifa = rt->rt_ifa; IFAFREE(ifa); if (rt->rt_parent) { RTFREE (rt->rt_parent) } Free(rt_key(rt));#ifdef ROUTER_STACK /* * Entries which are not directly attached to the * tree use a different free routine since the netmask * information is stored in a uniquely allocated buffer, * not shared among multiple route entries. */ if ( ((ROUTE_ENTRY*)rt)->primaryRouteFlag == FALSE) routeEntryFree ((ROUTE_ENTRY*)rt, FALSE); else Free ((ROUTE_ENTRY*)rt);#else Free (rt);#endif /* ROUTER_STACK */ }}/* * Force a routing table entry to the specified * destination to go through the given gateway. * Normally called as a result of a routing redirect * message from the network layer. * * N.B.: must be called at splnet * */intrtredirect(dst, gateway, netmask, flags, src, rtp) struct sockaddr *dst, *gateway, *netmask, *src; int flags; struct rtentry **rtp;{ register struct rtentry *rt; int error = 0; short *stat = 0; struct rt_addrinfo info; struct ifaddr *ifa; /* verify the gateway is directly reachable */ if ((ifa = ifa_ifwithnet(gateway)) == 0) { error = ENETUNREACH; goto out; } rt = rtalloc1(dst, 0, 0); /* * If the redirect isn't from our current router for this dst, * it's either old or wrong. If it redirects us to ourselves, * we have a routing loop, perhaps as a result of an interface * going down recently. */#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) if (!(flags & RTF_DONE) && rt && (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) error = EINVAL; else if (ifa_ifwithaddr(gateway)) error = EHOSTUNREACH; if (error) goto done; /* * Create a new entry if we just got back a wildcard entry * or the the lookup failed. This is necessary for hosts * which use routing redirects generated by smart gateways * to dynamically build the routing tables. */ if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) goto create; /* * Don't listen to the redirect if it's * for a route to an interface. */ if (rt->rt_flags & RTF_GATEWAY) { if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { /* * Changing from route to net => route to host. * Create new route, rather than smashing route to net. */ create: flags |= RTF_GATEWAY | RTF_DYNAMIC; /* * Create the new route entry using the default * weight. Do not report the change since the * later hook generates both types of messages.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -