📄 rt_table.c
字号:
/* * Copyright (C) 1998 WIDE Project. * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. */#include "include.h"#include "bgp.h"#include "router.h"#include "task.h"#include "aspath.h"#include "rt_table.h"#include "bgp_var.h"#include "in6.h"#include "ripng.h"struct rt_entry static_rte_head = {&static_rte_head, &static_rte_head};/* alignment constraint for routing socket messages */#define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))voidkrt_init(){ int mib[6]; size_t msize; char *buf, *p, *lim; struct rt_msghdr *rtm; extern int rtsock; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET6; /* Address family */ mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ mib[5] = 0; /* No flags */ if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) fatal("<krt_init>: sysctl estimate"); if ((buf = (char *)malloc(msize)) == NULL) fatalx("<krt_init>: malloc"); if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) fatal("<krt_init>: sysctl NET_RT_DUMP"); if ((rtsock = socket(PF_ROUTE, SOCK_RAW, AF_INET6)) < 0) fatal("<krt_init>: routing socket"); /* force Routing socket write-only */ if (shutdown(rtsock, 0) < 0) fatal("<krt_init>: shutdown"); lim = buf + msize; for (p = buf; p < lim; p += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)p; krt_entry(rtm); } free(buf);}/* * krt_entry() * Flush dinamic-network-routes. * Construct the initial "rt_entry" list. */voidkrt_entry(rtm) struct rt_msghdr *rtm;{ struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; struct sockaddr_in6 *sin6_genmask, *sin6_ifp; char *rtmp, *ifname; char buf[BUFSIZ]; struct rt_entry *rrt; struct ripinfo6 *np; struct ifinfo *ife; int s; extern int rtsock; /* Interface */ if ((s = rtm->rtm_index)) ifname = if_indextoname(s, buf); else fatalx("<krt_entry>: Unkown interface"); sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; if ((rtm->rtm_flags & RTF_UP) == 0 ||#ifdef __FreeBSD__ (rtm->rtm_flags & (RTF_XRESOLVE|RTF_WASCLONED))#endif /* __FreeBSD__ */#ifdef __bsdi__ (rtm->rtm_flags & (RTF_XRESOLVE|RTF_CLONED))#endif /*__bsdi__*/#if defined(__NetBSD__) || defined(__OpenBSD__) (rtm->rtm_flags & (RTF_XRESOLVE))#endif /* __NetBSD__ || __OpenBSD__ */ ) return; /* not interested in the link route */ rtmp = (char *)(rtm + 1); /* Destination */ if ((rtm->rtm_addrs & RTA_DST) == 0) /* ignore routes without destination */ return; /* address */ sin6_dst = (struct sockaddr_in6 *)rtmp; if (!IN6_IS_ADDR_ROUTABLE(&sin6_dst->sin6_addr)) return; rtmp += sin6_dst->sin6_len; /* char pointer */ if (rtm->rtm_addrs & RTA_GATEWAY) { sin6_gw = (struct sockaddr_in6 *)rtmp; rtmp += ROUNDUP(sin6_gw->sin6_len); } if (rtm->rtm_addrs & RTA_NETMASK) { sin6_mask = (struct sockaddr_in6 *)rtmp; rtmp += ROUNDUP(sin6_mask->sin6_len); } if (rtm->rtm_addrs & RTA_GENMASK) { sin6_genmask = (struct sockaddr_in6 *)rtmp; rtmp += ROUNDUP(sin6_genmask->sin6_len); } if (rtm->rtm_addrs & RTA_IFP) { sin6_ifp = (struct sockaddr_in6 *)rtmp; rtmp += ROUNDUP(sin6_ifp->sin6_len); }#if 0 /* checking previously added P-to-P self route (1998/04/24) */ if (IN6_IS_ADDR_LOOPBACK(&sin6_gw->sin6_addr)) return;#endif /* flush */ if (!(rtm->rtm_flags & RTF_STATIC) && (rtm->rtm_flags & RTF_GATEWAY)) { int len; rtm->rtm_type = RTM_DELETE; rtm->rtm_seq = 0; /* ??? */ len = write(rtsock, (char *)rtm, rtm->rtm_msglen); if (len < (int)rtm->rtm_msglen) { fatalx("<krt_entry>: write failed routing socket"); } return; } MALLOC(rrt, struct rt_entry); /* a new space */ np = &rrt->rt_ripinfo; rrt->rt_aspath = NULL; /* because I/F direct RTE */ rrt->rt_riptime = NULL; np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; /* direct RTE metric = 0 */ rrt->rt_flags = rtm->rtm_flags; np->rip6_dest = sin6_dst->sin6_addr; /* Prefix length (from routing socket) */ if (rtm->rtm_flags & RTF_HOST) /* host route */ np->rip6_plen = 128; else if (sin6_mask) /* other */ np->rip6_plen = mask2len(sin6_mask); else np->rip6_plen = 0; /* Gateway (i.e. next hop) */ if (sin6_gw == NULL) memset(&rrt->rt_gw, 0, sizeof(struct in6_addr)); else rrt->rt_gw = sin6_gw->sin6_addr; /* Check gateway */ if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rt_gw)) { rrt->rt_flags |= RTF_NH_NOT_LLADDR; } if ((ife = find_if_by_index(s)) == NULL) fatalx("<krt_entry>: I/F not found"); if (find_rte(rrt, ife->ifi_rte)) { /* Already found ? */ free(rrt); return; } rrt->rt_proto.rtp_type = RTPROTO_IF; rrt->rt_proto.rtp_if = ife; /* Put "rrt" into the I/F's RTE-list */ if (ife->ifi_rte != NULL) { insque(rrt, ife->ifi_rte); } else { rrt->rt_next = rrt; rrt->rt_prev = rrt; ife->ifi_rte = rrt; };#if 0 /* KAME kernel automatically install such routes */ /* * Add a route for our own address on a point-to-point interface. */ if ((sin6_gw->sin6_family == AF_INET6) && IN6_IS_ADDR_ROUTABLE(&sin6_gw->sin6_addr) && ife->ifi_flags & IFF_POINTOPOINT) { struct rt_entry *rte; MALLOC(rte, struct rt_entry); /* a new space */ np = &rte->rt_ripinfo; np->rip6_dest = sin6_gw->sin6_addr; /* in6_addr */ np->rip6_plen = 128; np->rip6_metric = 0; /* direct RTE metric = 0 */ rte->rt_gw = in6addr_loopback; rte->rt_flags = RTF_UP|RTF_GATEWAY|RTF_HOST; /* UGH */ rte->rt_proto.rtp_type = RTPROTO_IF; rte->rt_proto.rtp_if = ife; addroute(rte, &rte->rt_gw, ife); /* Put "rte" into the I/F's RTE-list */ insque(rte, ife->ifi_rte); return; }#endif /* End of krt_entry() */}/* * find_rte() */struct rt_entry *find_rte(key, base) struct rt_entry *key; struct rt_entry *base;{ struct rt_entry *rte; if ((key == NULL) || ((rte = base) == NULL)) return NULL; while(rte) { if (key->rt_ripinfo.rip6_plen == rte->rt_ripinfo.rip6_plen && IN6_ARE_PRFX_EQUAL(&rte->rt_ripinfo.rip6_dest, &key->rt_ripinfo.rip6_dest, key->rt_ripinfo.rip6_plen)) break; if ((rte = rte->rt_next) == base) return NULL; if (rte == rte->rt_next) fatalx("<find_rte>: BUG"); } return rte;}intset_nexthop(dst, ret_rte) struct in6_addr *dst; struct rt_entry *ret_rte;{ struct ifinfo *ife, *bestife = NULL; struct rt_entry *rte, *bestrte = NULL; struct ripif *ripif; extern byte ripyes; extern struct ifinfo *ifentry; extern struct ripif *ripifs; /* flush old nexthop */ memset(&ret_rte->rt_gw, 0, sizeof(struct in6_addr)); ret_rte->rt_gwif = NULL; ret_rte->rt_gwsrc_type = RTPROTO_NONE; ret_rte->rt_gwsrc_entry = NULL; ife = ifentry; /* global */ while(ife) { rte = ife->ifi_rte; while(rte) { if (IN6_ARE_PRFX_EQUAL(dst, &rte->rt_ripinfo.rip6_dest, rte->rt_ripinfo.rip6_plen) && (rte->rt_flags & RTF_UP)) { if (bestrte == NULL || bestrte->rt_ripinfo.rip6_plen < rte->rt_ripinfo.rip6_plen) { /* keep the route if its the 1st one or has a longer prefix */ bestrte = rte; bestife = ife; } } if ((rte = rte->rt_next) == ife->ifi_rte) break; } if ((ife = ife->ifi_next) == ifentry) break; } if (ripyes) { ripif = ripifs; /* global */ while(ripif) { rte = ripif->rip_adj_ribs_in; while(rte) { if (IN6_ARE_PRFX_EQUAL(dst, &rte->rt_ripinfo.rip6_dest, rte->rt_ripinfo.rip6_plen) && (rte->rt_flags & RTF_UP) && rte->rt_ripinfo.rip6_metric != RIPNG_METRIC_UNREACHABLE) { if (bestrte == NULL || bestrte->rt_ripinfo.rip6_plen < rte->rt_ripinfo.rip6_plen) { /* keep the route if its the 1st one or has a longer prefix */ bestrte = rte; bestife = ripif->rip_ife; } } if ((rte = rte->rt_next) == ripif->rip_adj_ribs_in) break; } if ((ripif = ripif->rip_next) == ripifs) break; } } if (bestrte) { ret_rte->rt_gwif = bestife; ret_rte->rt_gwsrc_type = bestrte->rt_proto.rtp_type; ret_rte->rt_gwsrc_entry = bestrte; switch(bestrte->rt_proto.rtp_type) { case RTPROTO_IF: /* * If the destination resides in a local network, just use the * destination as gateway. * XXX: this might cause non-link-local gateway to be installed * in the kernel. Should we look up the neighbor cache?? */ memcpy(&ret_rte->rt_gw, dst, sizeof(struct in6_addr)); break; case RTPROTO_RIP: memcpy(&ret_rte->rt_gw, &bestrte->rt_gw, sizeof(struct in6_addr)); break; default: fatalx("<set_nexthop>: BUG(bogus gwsrc protocol"); /* NOTREACHED */ } return 1; /* success */ } return 0; /* not found */}/* * find_filter() * RETURN VALUES: 1: found * 0: not found */intfind_filter(head, filter) struct filtinfo *head, *filter;{ struct filtinfo *search = head; while (search) { if (IN6_ARE_ADDR_EQUAL(&head->filtinfo_addr, &filter->filtinfo_addr) && head->filtinfo_plen == filter->filtinfo_plen) return(1); if ((search = search->filtinfo_next) == head) break; } return(0);}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -