📄 route.c
字号:
/* * Copyright (c) 1980, 1986, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)route.c 8.2 (Berkeley) 11/15/93 * $Id: route.c,v 1.3 2002/01/31 21:40:47 joel Exp $ */#include "opt_mrouting.h"#include <sys/param.h>#include <sys/queue.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/proc.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/domain.h>#include <sys/protosw.h>#include <sys/ioctl.h>#include <net/if.h>#include <net/route.h>#include <net/raw_cb.h>#include <netinet/in.h>#include <netinet/in_var.h>#include <netinet/ip_mroute.h>#define SA(p) ((struct sockaddr *)(p))struct route_cb route_cb;static struct rtstat rtstat;struct radix_node_head *rt_tables[AF_MAX+1];static int rttrash; /* routes not in table but not freed */static void rt_maskedcopy __P((struct sockaddr *, struct sockaddr *, struct sockaddr *));static void rtable_init __P((void **));static voidrtable_init(table) void **table;{ struct domain *dom; for (dom = domains; dom; dom = dom->dom_next) if (dom->dom_rtattach) dom->dom_rtattach(&table[dom->dom_family], dom->dom_rtoffset);}voidroute_init(){ rn_init(); /* initialize all zeroes, all ones, mask table */ rtable_init((void **)rt_tables);}/* * 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, 0UL);}voidrtalloc_ign(ro, ignore) register struct route *ro; u_long ignore;{ 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, ignore);}/* * Look up the route that matches the address given * Or, at least try.. Create a cloned route if needed. */struct rtentry *rtalloc1(dst, report, ignflags) register struct sockaddr *dst; int report; u_long ignflags;{ 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 nflags; int s = splnet(), err = 0, msgtype = RTM_MISS; /* * Look up the address in the table for that Address Family */ if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && ((rn->rn_flags & RNF_ROOT) == 0)) { /* * If we find it and it's not the root node, then * get a refernce on the rtentry associated. */ newrt = rt = (struct rtentry *)rn; nflags = rt->rt_flags & ~ignflags; if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) { /* * We are apparently adding (report = 0 in delete). * If it requires that it be cloned, do so. * (This implies it wasn't a HOST route.) */ err = rtrequest(RTM_RESOLVE, dst, SA(0), SA(0), 0, &newrt); if (err) { /* * If the cloning didn't succeed, maybe * what we have will do. Return that. */ newrt = rt; rt->rt_refcnt++; goto miss; } if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { /* * If the new route specifies it be * externally resolved, then go do that. */ msgtype = RTM_RESOLVE; goto miss; } } else rt->rt_refcnt++; } else { /* * Either we hit the root or couldn't find any match, * Which basically means * "caint get there frm here" */ rtstat.rts_unreach++; miss: if (report) { /* * If required, report the failure to the supervising * Authorities. * For a delete, this is not an error. (report == 0) */ bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = dst; rt_missmsg(msgtype, &info, 0, err); } } splx(s); return (newrt);}voidrtfree(rt) register struct rtentry *rt;{ register struct radix_node_head *rnh = rt_tables[rt_key(rt)->sa_family]; register struct ifaddr *ifa; if (rt == 0 || rnh == 0) panic("rtfree"); rt->rt_refcnt--; if(rnh->rnh_close && rt->rt_refcnt == 0) { rnh->rnh_close((struct radix_node *)rt, rnh); } if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) panic ("rtfree 2"); rttrash--; if (rt->rt_refcnt < 0) { printf("rtfree: %p not freed (neg refs)\n", rt); return; } ifa = rt->rt_ifa; IFAFREE(ifa); if (rt->rt_parent) { RTFREE(rt->rt_parent); } Free(rt_key(rt)); Free(rt); }}voidifafree(ifa) register struct ifaddr *ifa;{ if (ifa == NULL) panic("ifafree"); if (ifa->ifa_refcnt == 0) free(ifa, M_IFADDR); else ifa->ifa_refcnt--;}/* * 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 * */voidrtredirect(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, 0UL); /* * 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; error = rtrequest((int)RTM_ADD, dst, gateway, netmask, flags, (struct rtentry **)0); stat = &rtstat.rts_dynamic; } else { /* * Smash the current notion of the gateway to * this destination. Should check about netmask!!! */ rt->rt_flags |= RTF_MODIFIED; flags |= RTF_MODIFIED; stat = &rtstat.rts_newgateway; rt_setgate(rt, rt_key(rt), gateway); } } else error = EHOSTUNREACH;done: if (rt) { if (rtp && !error) *rtp = rt; else rtfree(rt); }out: if (error) rtstat.rts_badredirect++; else if (stat != NULL) (*stat)++; bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = dst; info.rti_info[RTAX_GATEWAY] = gateway; info.rti_info[RTAX_NETMASK] = netmask; info.rti_info[RTAX_AUTHOR] = src; rt_missmsg(RTM_REDIRECT, &info, flags, error);}/** Routing table ioctl interface.*/intrtioctl(req, data, p) int req; caddr_t data; struct proc *p;{#ifdef INET /* Multicast goop, grrr... */#ifdef MROUTING return mrt_ioctl(req, data);#else return mrt_ioctl(req, data, p);#endif#else /* INET */ return ENXIO;#endif /* INET */}struct ifaddr *ifa_ifwithroute(flags, dst, gateway) int flags; struct sockaddr *dst, *gateway;{ register struct ifaddr *ifa; if ((flags & RTF_GATEWAY) == 0) { /* * If we are adding a route to an interface, * and the interface is a pt to pt link * we should search for the destination * as our clue to the interface. Otherwise * we can use the local address. */ ifa = 0; if (flags & RTF_HOST) { ifa = ifa_ifwithdstaddr(dst); } if (ifa == 0) ifa = ifa_ifwithaddr(gateway); } else { /* * If we are adding a route to a remote net * or host, the gateway may still be on the * other end of a pt to pt link. */ ifa = ifa_ifwithdstaddr(gateway); } if (ifa == 0) ifa = ifa_ifwithnet(gateway); if (ifa == 0) { struct rtentry *rt = rtalloc1(dst, 0, 0UL); if (rt == 0) return (0); rt->rt_refcnt--; if ((ifa = rt->rt_ifa) == 0) return (0); } if (ifa->ifa_addr->sa_family != dst->sa_family) { struct ifaddr *oifa = ifa; ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); if (ifa == 0) ifa = oifa; } return (ifa);}#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))static int rt_fixdelete(struct radix_node *, void *);static int rt_fixchange(struct radix_node *, void *);struct rtfc_arg { struct rtentry *rt0; struct radix_node_head *rnh;};/* * Do appropriate manipulations of a routing tree given * all the bits of info needed */intrtrequest(req, dst, gateway, netmask, flags, ret_nrt) int req, flags; struct sockaddr *dst, *gateway, *netmask; struct rtentry **ret_nrt;{ int s = splnet(); int error = 0; register struct rtentry *rt; register struct radix_node *rn; register struct radix_node_head *rnh; struct ifaddr *ifa; struct sockaddr *ndst;#define senderr(x) { error = x ; goto bad; } /* * Find the correct routing tree to use for this Address Family */ if ((rnh = rt_tables[dst->sa_family]) == 0) senderr(ESRCH); /* * If we are adding a host route then we don't want to put * a netmask in the tree */ if (flags & RTF_HOST) netmask = 0; switch (req) { case RTM_DELETE: /* * Remove the item from the tree and return it. * Complain if it is not there and do no more processing. */ if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0) senderr(ESRCH); if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) panic ("rtrequest delete"); rt = (struct rtentry *)rn; /* * Now search what's left of the subtree for any cloned * routes which might have been formed from this node. */ if ((rt->rt_flags & RTF_PRCLONING) && netmask) { rnh->rnh_walktree_from(rnh, dst, netmask, rt_fixdelete, rt); } /* * Remove any external references we may have. * This might result in another rtentry being freed if * we held it's last reference. */ if (rt->rt_gwroute) { rt = rt->rt_gwroute; RTFREE(rt); (rt = (struct rtentry *)rn)->rt_gwroute = 0; } /* * NB: RTF_UP must be set during the search above, * because we might delete the last ref, causing * rt to get freed prematurely. */ rt->rt_flags &= ~RTF_UP; /* * If there is llinfo or similar associated with the * route, give the interface a chance to deal with it.. */ if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -