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 + -
显示快捷键?