📄 ip_mroute.c
字号:
if ( (pIp == NULL) ||(pMbuf == NULL) ||(pRt == NULL) ||(pIfnet == NULL) ) { return (ERROR); } GET_TIME(now); MRTDEBUG ( (mrtdebug), "MROUTE: pimNotify calling overlying routing protocol.\n", 1,2,3,4,5,6 ); pMbufCopy = m_copy(pMbuf, 0, M_COPYALL); if (pMbufCopy == NULL) { return ENOBUFS; } hlen = pIp->ip_hl << 2; if (pMbufCopy && (M_HASCL(pMbufCopy) || pMbufCopy->m_len < hlen)) pMbufCopy = m_pullup(pMbufCopy, hlen); pRt->mfc_last_assert = now;/* It looks like they're overlaying the igmpmsg structure on top of the ip structure. This will allow us to access the im_src member (which in IP corresponds to the ip_src member of struct ip. Note that both members are offset by 12 bytes. struct igmpmsg { u_long unused1; u_long unused2; u_char im_msgtype;#define IGMPMSG_NOCACHE 1#define IGMPMSG_WRONGVIF 2 u_char im_mbz; u_char im_vif; u_char unused3; struct in_addr im_src, im_dst;}; struct ip {#if _BYTE_ORDER == _LITTLE_ENDIAN u_int ip_hl:4, ip_v:4, #endif#if _BYTE_ORDER == _BIG_ENDIAN u_int ip_v:4, ip_hl:4, #endif ip_tos:8, ip_len:16; u_short ip_id; short ip_off; #define IP_DF 0x4000 #define IP_MF 0x2000 #define IP_OFFMASK 0x1fff u_char ip_ttl; u_char ip_p; u_short ip_sum; struct in_addr ip_src,ip_dst; };*/ pIGMPMessage = mtod(pMbufCopy, struct igmpmsg *); if (pIGMPMessage == NULL) { return (ERROR); } k_igmpsrc.sin_addr = pIGMPMessage->im_src; /* The kernel stores these values in host order, pim requires net order*/ pIpNew = mtod (pMbufCopy, struct ip*); if (pIpNew == NULL) { return (ERROR); } pIpNew->ip_len = htons(pIpNew->ip_len); pIpNew->ip_off = htons(pIpNew->ip_off); /* these values are in the wrong order for PIM*/ MRTDEBUG ( (mrtdebug), "MROUTE: pimNotify calling pim=%p.\n", (int)_pimCacheMissSendHook,2,3,4,5,6 ); if ( _pimCacheMissSendHook != 0) { _pimCacheMissSendHook (pMbufCopy, pIfnet, &k_igmpsrc); } return (OK);}/* * IP multicast forwarding function. This function assumes that the packet * pointed to by "ip" has arrived on (or is about to be sent to) the interface * pointed to by "ifp", and the packet is to be relayed to other networks * that have members of the packet's destination IP multicast group. * * The packet is returned unscathed to the caller, unless it is * erroneous, in which case a non-zero return value tells the caller to * discard it. */#define IP_HDR_LEN 20 /* # bytes of fixed IP header (excluding options) */#define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */static intX_ip_mforward(m, ifp, ip, imo ) struct mbuf *m; struct ifnet *ifp; struct ip *ip; struct ip_moptions *imo;{ struct mfc *rt; struct mfc *root_rt; u_char *ipoptions; static struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; static int srctun = 0; int s; BOOL null_list; vifi_t vifi = -1; MRTDEBUG ( (mrtdebug & DEBUG_FORWARD), "ip_mforward: src %lx, dst %lx, if=%p, %s%i\n", (u_long)ntohl(ip->ip_src.s_addr), (u_long)ntohl(ip->ip_dst.s_addr), (int)ifp, (int)ifp->if_name, ifp->if_unit, 6 ); if ( (mrtdebug & DEBUG_TABLE) != 0) mRouteDumpMfctable(); if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 || (ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) { /* * Packet arrived via a physical interface or * an encapsulated tunnel. */ } else { MRTDEBUG ( (mrtdebug & DEBUG_FORWARD), "MROUTE: Packet arrived through a source-route tunnel. \ Source-route tunnels are no longer supported.\n", 1,2,3,4,5,6 ); /* * Packet arrived through a source-route tunnel. * Source-route tunnels are no longer supported. */ if ((srctun++ % 1000) == 0) { MRTDEBUG ( (mrtdebug), "MROUTE: ip_mforward: received source-routed packet from %lx\n", (u_long)ntohl(ip->ip_src.s_addr), 2,3,4,5,6 ); } return 1; } if ( (imo) && (vifi < numvifs) ) { if (ip->ip_ttl < 255) ip->ip_ttl++; /* compensate for -1 in *_send routines */ vifi = -1; return (ip_mdq(m, ifp, NULL, vifi));/* this is for a specific forwarding scenario... explicitly chosen vif. we no longer support this */ } /* * Don't forward a packet with time-to-live of zero or one, * or a packet destined to a local-only group. */ if (ip->ip_ttl <= 1 || (ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP) ) { return 0; } /* * Determine forwarding vifs from the forwarding cache table */ s = splnet(); MFCFIND(ip->ip_src.s_addr, ip->ip_dst.s_addr, rt); /* Entry exists, so forward if necessary */ if (rt != NULL) { null_list = oifListIsEmpty(rt); splx(s); if ( ( (null_list) && (pim_assert ) && (ifp->if_flags & IFF_BROADCAST) ) || ( rt->mfc_notify != 0 ) ) { rt->mfc_notify = 1; pimNotify(ip, m, rt, vifi, ifp); /* tell pim about new packet for old group. * Pim will be responsible for forwarding*/ if (null_list ) { return (OK); } } return (ip_mdq(m, ifp, rt, -1)); } else { /* * If we don't have a route for packet's origin, * Make a copy of the packet & * send message to routing daemon */ struct mbuf *mb0; struct rtdetq *rte; u_long hash; int hlen = ip->ip_hl << 2; mrtstat.mrts_no_route++; MRTDEBUG ( (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC)), "MROUTE: ip_mforward: origin unknown no rte s %lx g %lx\n", (u_long)ntohl(ip->ip_src.s_addr), (u_long)ntohl(ip->ip_dst.s_addr), 3,4,5,6 ); /* * Allocate mbufs early so that we don't do extra work if we are * just going to fail anyway. Make sure to pullup the header so * that other people can't step on it. */ rte = MRT_ALLOC (sizeof (struct rtdetq ) ); if (rte == NULL) { splx(s); return ENOBUFS; } rte->m = 0; mb0 = m_copy(m, 0, M_COPYALL); if (mb0 && (M_HASCL(mb0) || mb0->m_len < hlen)) mb0 = m_pullup(mb0, hlen); if (mb0 == NULL) { MRT_FREE((char*) rte); splx(s); return ENOBUFS; } /* is there an upcall waiting for this packet? */ hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr); for (rt = mfctable[hash]; rt; rt = rt->mfc_next) { if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) && (ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) && (rt->mfc_stall != NULL) ) break; } if (rt == NULL) { int i; /* no upcall, so make a new entry */ rt = MRT_ALLOC(sizeof(struct mfc)); if (rt == NULL) { MRT_FREE((char*) rte); m_freem(mb0); splx(s); return ENOBUFS; } /* Make a copy of the header to send to the user level process */ rt->mfc_notify = 0; /* * Send message to routing daemon to install * a route into the kernel table */ k_igmpsrc.sin_addr = ip->ip_src; mrtstat.mrts_upcalls++; rt->mfc_origin.s_addr = ip->ip_src.s_addr; rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr; rt->mfc_expire = UPCALL_EXPIRE; nexpire[hash]++; /* find the root route */ MFCFIND(0, rt->mfc_mcastgrp.s_addr, root_rt); if (root_rt != NULL) {/* it exists, do nothing */ } else if (root_rt == NULL) {/* create one */ root_rt = MRT_ALLOC(sizeof(struct mfc)); if (root_rt == NULL) { MRT_FREE((char*) rt); splx(s); return ENOBUFS; } root_rt->mfc_notify = 0; /* inset NULL entry at head of hash chain */ root_rt->mfc_origin.s_addr = 0; root_rt->mfc_mcastgrp = rt->mfc_mcastgrp; root_rt->mfc_parent = 0; for (i = 0; i < numvifs; i++) root_rt->mfc_ttls[i] = 0; /* initialize pkt counters per src-grp */ root_rt->mfc_pkt_cnt = 0; root_rt->mfc_byte_cnt = 0; root_rt->mfc_wrong_if = 0; rt->mfc_last_assert = 0; root_rt->mfc_last_assert = 0; root_rt->mfc_expire = 0; root_rt->mfc_stall = NULL; /* link into table */ root_rt->mfc_next = mfctable[MFCHASH(root_rt->mfc_origin.s_addr, root_rt->mfc_mcastgrp.s_addr) ]; mfctable[MFCHASH(root_rt->mfc_origin.s_addr, root_rt->mfc_mcastgrp.s_addr) ]= root_rt; root_rt->mfc_next_g = root_rt; /* next group in same chain */ root_rt->mfc_root_rt = root_rt; /* 0,g entry in hash table, itself in this case*/ } rt->mfc_parent = mRouteNameToPort(ifp->if_name, ifp->if_unit); rt->mfc_root_rt = root_rt;/* set root_rt*/ rt->mfc_next_g = root_rt->mfc_next_g; /* insert into from of group chain*/ for (i = 0; i < numvifs; i++) rt->mfc_ttls[i] = root_rt->mfc_ttls[i]; root_rt->mfc_next_g = rt; /* insert new entry at head of hash chain */ /* link into table */ rt->mfc_next = mfctable[hash]; mfctable[hash] = rt; rt->mfc_stall = rte; if (rte->m == 0) { rte->m = mb0; rte->ifp = ifp; rte->next = NULL; } if (pim_assert == 0) {/* new route automatically inherits *,g entries */ if (mRouteGroupAdd( ifp, ip->ip_src, ip->ip_dst ) < 0) { MRTDEBUG ( (mrtdebug), "MROUTE: ip_mforward: ip_mrouter socket queue full, mRouteGroupAdd failed\n", 1,2,3,4,5,6 ); ++mrtstat.mrts_upq_sockfull; MRT_FREE((char*) rte); m_freem(mb0); MRT_FREE((char*) rt); splx(s); return ENOBUFS; } } else if (pim_assert && (ifp->if_flags & IFF_BROADCAST) ) { pimNotify(ip, m, rt, vifi, ifp);/* tell pim about new group */ } } else { /* determine if q has overflowed */ int npkts = 0; struct rtdetq **p; for (p = &rt->mfc_stall; *p != NULL; p = &(*p)->next) npkts++; if (npkts > MAX_UPQ) { mrtstat.mrts_upq_ovflw++; MRT_FREE((char*) rte); m_freem(mb0); splx(s); return 0; } /* Add this entry to the end of the queue */ *p = rte; } if (rte->m == 0) { rte->m = mb0; rte->ifp = ifp; rte->next = NULL; } splx(s); return 0; } }int ip_mforward (struct mbuf * m, struct ifnet * ifp, struct ip *ip, struct ip_moptions *imo){ return(X_ip_mforward(m, ifp, ip, imo));};/* * Clean up the cache entry if upcall is not serviced */static voidexpire_upcalls(void *unused){ struct rtdetq *rte; struct mfc *mfc, **nptr; int i; int s; s = splnet(); for (i = 0; i < MFCTBLSIZ; i++) { if (nexpire[i] == 0) continue; nptr = &mfctable[i]; for (mfc = *nptr; mfc != NULL; mfc = *nptr) { /* * Skip real cache entries * Make sure it wasn't marked to not expire (shouldn't happen) * If it expires now */ if (mfc->mfc_stall != NULL && mfc->mfc_expire != 0 && --mfc->mfc_expire == 0) { MRTDEBUG ( (mrtdebug & DEBUG_EXPIRE), "MROUTE: expire_upcalls: expiring (%lx %lx)\n", (u_long)ntohl(mfc->mfc_origin.s_addr), (u_long)ntohl(mfc->mfc_mcastgrp.s_addr), 3,4,5,6 ); /* * drop all the packets * free the mbuf with the pkt, if, timing info */ for (rte = mfc->mfc_stall; rte; ) { struct rtdetq *n = rte->next; m_freem(rte->m); MRT_FREE((char*) rte); rte = n; } ++mrtstat.mrts_cache_cleanups; nexpire[i]--; *nptr = mfc->mfc_next; MRT_FREE((char*) mfc); } else { nptr = &mfc->mfc_next; } } } splx(s); expire_upcalls_ch = timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); }/* * Packet forwarding routine once entry in the cache is made */static intip_mdq(m, ifp, rt, xmt_vif) struct mbuf *m; struct ifnet *ifp; struct mfc *rt; vifi_t xmt_vif;{ struct ip *ip = mtod(m, struct ip *); vifi_t vifi; vifi_t vifi_original; struct vif *vifp; USHORT old_len; int port; int plen = ip->ip_len; int forwarded = 0;/* * Macro to send packet on vif. Since RSVP packets don't get counted on * input, they shouldn't get counted on output, so statistics keeping is * seperate. */#define MC_SEND(ip,vifp,m) { \ if ((vifp)->v_flags & VIFF_TUNNEL) \ encap_send((ip), (vifp), (m)); \ else \ phyint_send((ip), (vifp), (m)); \} /* * If xmt_vif is not -1, send on only the requested vif. * * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.) */ port = mRouteNameToPort(ifp->if_name, ifp->if_unit); MRTDEBUG ( (mrtdebug), "MROUTE: MDQ found VIF=%i, parent=%i.\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -