ip_mroute.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,320 行 · 第 1/4 页
C
2,320 行
ip_mrouter = so; bzero((caddr_t)mfctable, sizeof(mfctable)); bzero((caddr_t)nexpire, sizeof(nexpire)); pim_assert = 0; expire_upcalls_ch = timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); if (mrtdebug) log(LOG_DEBUG, "ip_mrouter_init\n"); return 0;}/* * Disable multicast routing */static intX_ip_mrouter_done(){ vifi_t vifi; int i; struct ifnet *ifp; struct ifreq ifr; struct mfc *rt; struct rtdetq *rte; int s; s = splnet(); /* * For each phyint in use, disable promiscuous reception of all IP * multicasts. */ for (vifi = 0; vifi < numvifs; vifi++) { if (viftable[vifi].v_lcl_addr.s_addr != 0 && !(viftable[vifi].v_flags & VIFF_TUNNEL)) { ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY; ifp = viftable[vifi].v_ifp; if_allmulti(ifp, 0); } } bzero((caddr_t)tbftable, sizeof(tbftable)); bzero((caddr_t)viftable, sizeof(viftable)); numvifs = 0; pim_assert = 0; untimeout(expire_upcalls, (caddr_t)NULL, expire_upcalls_ch); /* * Free all multicast forwarding cache entries. */ for (i = 0; i < MFCTBLSIZ; i++) { for (rt = mfctable[i]; rt != NULL; ) { struct mfc *nr = rt->mfc_next; for (rte = rt->mfc_stall; rte != NULL; ) { struct rtdetq *n = rte->next; m_freem(rte->m); free(rte, M_MRTABLE); rte = n; } free(rt, M_MRTABLE); rt = nr; } } bzero((caddr_t)mfctable, sizeof(mfctable)); /* * Reset de-encapsulation cache */ last_encap_src = 0; last_encap_vif = NULL; have_encap_tunnel = 0; ip_mrouter = NULL; splx(s); if (mrtdebug) log(LOG_DEBUG, "ip_mrouter_done\n"); return 0;}#ifndef MROUTE_LKMint (*ip_mrouter_done)(void) = X_ip_mrouter_done;#endif/* * Set PIM assert processing global */static intset_assert(i) int i;{ if ((i != 1) && (i != 0)) return EINVAL; pim_assert = i; return 0;}/* * Add a vif to the vif table */static intadd_vif(vifcp) register struct vifctl *vifcp;{ register struct vif *vifp = viftable + vifcp->vifc_vifi; static struct sockaddr_in sin = {sizeof sin, AF_INET}; struct ifaddr *ifa; struct ifnet *ifp; int error, s; struct tbf *v_tbf = tbftable + vifcp->vifc_vifi; if (vifcp->vifc_vifi >= MAXVIFS) return EINVAL; if (vifp->v_lcl_addr.s_addr != 0) return EADDRINUSE; /* Find the interface with an address in AF_INET family */ sin.sin_addr = vifcp->vifc_lcl_addr; ifa = ifa_ifwithaddr((struct sockaddr *)&sin); if (ifa == 0) return EADDRNOTAVAIL; ifp = ifa->ifa_ifp; if (vifcp->vifc_flags & VIFF_TUNNEL) { if ((vifcp->vifc_flags & VIFF_SRCRT) == 0) { /* * An encapsulating tunnel is wanted. Tell ipip_input() to * start paying attention to encapsulated packets. */ if (have_encap_tunnel == 0) { have_encap_tunnel = 1; for (s = 0; s < MAXVIFS; ++s) { multicast_decap_if[s].if_name = "mdecap"; multicast_decap_if[s].if_unit = s; } } /* * Set interface to fake encapsulator interface */ ifp = &multicast_decap_if[vifcp->vifc_vifi]; /* * Prepare cached route entry */ bzero(&vifp->v_route, sizeof(vifp->v_route)); } else { log(LOG_ERR, "source routed tunnels not supported\n"); return EOPNOTSUPP; } } else { /* Make sure the interface supports multicast */ if ((ifp->if_flags & IFF_MULTICAST) == 0) return EOPNOTSUPP; /* Enable promiscuous reception of all IP multicasts from the if */ s = splnet(); error = if_allmulti(ifp, 1); splx(s); if (error) return error; } s = splnet(); /* define parameters for the tbf structure */ vifp->v_tbf = v_tbf; GET_TIME(vifp->v_tbf->tbf_last_pkt_t); vifp->v_tbf->tbf_n_tok = 0; vifp->v_tbf->tbf_q_len = 0; vifp->v_tbf->tbf_max_q_len = MAXQSIZE; vifp->v_tbf->tbf_q = vifp->v_tbf->tbf_t = NULL; vifp->v_flags = vifcp->vifc_flags; vifp->v_threshold = vifcp->vifc_threshold; vifp->v_lcl_addr = vifcp->vifc_lcl_addr; vifp->v_rmt_addr = vifcp->vifc_rmt_addr; vifp->v_ifp = ifp; /* scaling up here allows division by 1024 in critical code */ vifp->v_rate_limit= vifcp->vifc_rate_limit * 1024 / 1000; vifp->v_rsvp_on = 0; vifp->v_rsvpd = NULL; /* initialize per vif pkt counters */ vifp->v_pkt_in = 0; vifp->v_pkt_out = 0; vifp->v_bytes_in = 0; vifp->v_bytes_out = 0; splx(s); /* Adjust numvifs up if the vifi is higher than numvifs */ if (numvifs <= vifcp->vifc_vifi) numvifs = vifcp->vifc_vifi + 1; if (mrtdebug) log(LOG_DEBUG, "add_vif #%d, lcladdr %lx, %s %lx, thresh %x, rate %d\n", vifcp->vifc_vifi, (u_long)ntohl(vifcp->vifc_lcl_addr.s_addr), (vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask", (u_long)ntohl(vifcp->vifc_rmt_addr.s_addr), vifcp->vifc_threshold, vifcp->vifc_rate_limit); return 0;}/* * Delete a vif from the vif table */static intdel_vif(vifi) vifi_t vifi;{ register struct vif *vifp = &viftable[vifi]; register struct mbuf *m; struct ifnet *ifp; struct ifreq ifr; int s; if (vifi >= numvifs) return EINVAL; if (vifp->v_lcl_addr.s_addr == 0) return EADDRNOTAVAIL; s = splnet(); if (!(vifp->v_flags & VIFF_TUNNEL)) { ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY; ifp = vifp->v_ifp; if_allmulti(ifp, 0); } if (vifp == last_encap_vif) { last_encap_vif = 0; last_encap_src = 0; } /* * Free packets queued at the interface */ while (vifp->v_tbf->tbf_q) { m = vifp->v_tbf->tbf_q; vifp->v_tbf->tbf_q = m->m_act; m_freem(m); } bzero((caddr_t)vifp->v_tbf, sizeof(*(vifp->v_tbf))); bzero((caddr_t)vifp, sizeof (*vifp)); if (mrtdebug) log(LOG_DEBUG, "del_vif %d, numvifs %d\n", vifi, numvifs); /* Adjust numvifs down */ for (vifi = numvifs; vifi > 0; vifi--) if (viftable[vifi-1].v_lcl_addr.s_addr != 0) break; numvifs = vifi; splx(s); return 0;}/* * Add an mfc entry */static intadd_mfc(mfccp) struct mfcctl *mfccp;{ struct mfc *rt; u_long hash; struct rtdetq *rte; register u_short nstl; int s; int i; MFCFIND(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr, rt); /* If an entry already exists, just update the fields */ if (rt) { if (mrtdebug & DEBUG_MFC) log(LOG_DEBUG,"add_mfc update o %lx g %lx p %x\n", (u_long)ntohl(mfccp->mfcc_origin.s_addr), (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), mfccp->mfcc_parent); s = splnet(); rt->mfc_parent = mfccp->mfcc_parent; for (i = 0; i < numvifs; i++) rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; splx(s); return 0; } /* * Find the entry for which the upcall was made and update */ s = splnet(); hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr); for (rt = mfctable[hash], nstl = 0; rt; rt = rt->mfc_next) { if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) && (rt->mfc_stall != NULL)) { if (nstl++) log(LOG_ERR, "add_mfc %s o %lx g %lx p %x dbx %p\n", "multiple kernel entries", (u_long)ntohl(mfccp->mfcc_origin.s_addr), (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), mfccp->mfcc_parent, (void *)rt->mfc_stall); if (mrtdebug & DEBUG_MFC) log(LOG_DEBUG,"add_mfc o %lx g %lx p %x dbg %p\n", (u_long)ntohl(mfccp->mfcc_origin.s_addr), (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), mfccp->mfcc_parent, (void *)rt->mfc_stall); rt->mfc_origin = mfccp->mfcc_origin; rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; rt->mfc_parent = mfccp->mfcc_parent; for (i = 0; i < numvifs; i++) rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; /* initialize pkt counters per src-grp */ rt->mfc_pkt_cnt = 0; rt->mfc_byte_cnt = 0; rt->mfc_wrong_if = 0; rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; rt->mfc_expire = 0; /* Don't clean this guy up */ nexpire[hash]--; /* free packets Qed at the end of this entry */ for (rte = rt->mfc_stall; rte != NULL; ) { struct rtdetq *n = rte->next; ip_mdq(rte->m, rte->ifp, rt, -1); m_freem(rte->m);#ifdef UPCALL_TIMING collate(&(rte->t));#endif /* UPCALL_TIMING */ free(rte, M_MRTABLE); rte = n; } rt->mfc_stall = NULL; } } /* * It is possible that an entry is being inserted without an upcall */ if (nstl == 0) { if (mrtdebug & DEBUG_MFC) log(LOG_DEBUG,"add_mfc no upcall h %lu o %lx g %lx p %x\n", hash, (u_long)ntohl(mfccp->mfcc_origin.s_addr), (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), mfccp->mfcc_parent); for (rt = mfctable[hash]; rt != NULL; rt = rt->mfc_next) { if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) { rt->mfc_origin = mfccp->mfcc_origin; rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; rt->mfc_parent = mfccp->mfcc_parent; for (i = 0; i < numvifs; i++) rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; /* initialize pkt counters per src-grp */ rt->mfc_pkt_cnt = 0; rt->mfc_byte_cnt = 0; rt->mfc_wrong_if = 0; rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; if (rt->mfc_expire) nexpire[hash]--; rt->mfc_expire = 0; } } if (rt == NULL) { /* no upcall, so make a new entry */ rt = (struct mfc *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT); if (rt == NULL) { splx(s); return ENOBUFS; } /* insert new entry at head of hash chain */ rt->mfc_origin = mfccp->mfcc_origin; rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; rt->mfc_parent = mfccp->mfcc_parent; for (i = 0; i < numvifs; i++) rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; /* initialize pkt counters per src-grp */ rt->mfc_pkt_cnt = 0; rt->mfc_byte_cnt = 0; rt->mfc_wrong_if = 0; rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; rt->mfc_expire = 0; rt->mfc_stall = NULL; /* link into table */ rt->mfc_next = mfctable[hash]; mfctable[hash] = rt; } } splx(s); return 0;}#ifdef UPCALL_TIMING/* * collect delay statistics on the upcalls */static void collate(t)register struct timeval *t;{ register u_long d; register struct timeval tp; register u_long delta; GET_TIME(tp); if (TV_LT(*t, tp)) { TV_DELTA(tp, *t, delta); d = delta >> 10; if (d > 50) d = 50; ++upcall_data[d]; }}#endif /* UPCALL_TIMING *//* * Delete an mfc entry */static intdel_mfc(mfccp) struct mfcctl *mfccp;{ struct in_addr origin; struct in_addr mcastgrp; struct mfc *rt; struct mfc **nptr; u_long hash; int s; origin = mfccp->mfcc_origin; mcastgrp = mfccp->mfcc_mcastgrp; hash = MFCHASH(origin.s_addr, mcastgrp.s_addr); if (mrtdebug & DEBUG_MFC) log(LOG_DEBUG,"del_mfc orig %lx mcastgrp %lx\n", (u_long)ntohl(origin.s_addr), (u_long)ntohl(mcastgrp.s_addr)); s = splnet(); nptr = &mfctable[hash]; while ((rt = *nptr) != NULL) { if (origin.s_addr == rt->mfc_origin.s_addr && mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr && rt->mfc_stall == NULL) break; nptr = &rt->mfc_next; } if (rt == NULL) { splx(s); return EADDRNOTAVAIL; } *nptr = rt->mfc_next; free(rt, M_MRTABLE); splx(s); return 0;}/* * Send a message to mrouted on the multicast routing socket */static intsocket_send(s, mm, src) struct socket *s; struct mbuf *mm; struct sockaddr_in *src;{ if (s) { if (sbappendaddr(&s->so_rcv, (struct sockaddr *)src, mm, (struct mbuf *)0) != 0) { sorwakeup(s); return 0; } } m_freem(mm); return -1;}/* * 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(ip, ifp, m, imo) register struct ip *ip; struct ifnet *ifp; struct mbuf *m; struct ip_moptions *imo;{ register struct mfc *rt; register u_char *ipoptions; static struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; static int srctun = 0; register struct mbuf *mm; int s; vifi_t vifi; struct vif *vifp; if (mrtdebug & DEBUG_FORWARD) log(LOG_DEBUG, "ip_mforward: src %lx, dst %lx, ifp %p\n", (u_long)ntohl(ip->ip_src.s_addr), (u_long)ntohl(ip->ip_dst.s_addr), (void *)ifp); 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 { /* * Packet arrived through a source-route tunnel. * Source-route tunnels are no longer supported. */ if ((srctun++ % 1000) == 0) log(LOG_ERR, "ip_mforward: received source-routed packet from %lx\n", (u_long)ntohl(ip->ip_src.s_addr)); return 1; } if ((imo) && ((vifi = imo->imo_multicast_vif) < numvifs)) { if (ip->ip_ttl < 255) ip->ip_ttl++; /* compensate for -1 in *_send routines */ if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { vifp = viftable + vifi; printf("Sending IPPROTO_RSVP from %lx to %lx on vif %d (%s%s%d)\n", ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), vifi, (vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "", vifp->v_ifp->if_name, vifp->v_ifp->if_unit); } return (ip_mdq(m, ifp, NULL, vifi)); } if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { printf("Warning: IPPROTO_RSVP from %lx to %lx without vif option\n", ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr)); if(!imo) printf("In fact, no options were specified at all\n"); } /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?