ip_mroute.c

来自「eCos操作系统源码」· C语言 代码 · 共 2,320 行 · 第 1/4 页

C
2,320
字号
//==========================================================================////      src/sys/netinet/ip_mroute.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/* * IP multicast forwarding procedures * * Written by David Waitzman, BBN Labs, August 1988. * Modified by Steve Deering, Stanford, February 1989. * Modified by Mark J. Steiglitz, Stanford, May, 1991 * Modified by Van Jacobson, LBL, January 1993 * Modified by Ajit Thyagarajan, PARC, August 1993 * Modified by Bill Fenner, PARC, April 1995 * * MROUTING Revision: 3.5 * $FreeBSD: src/sys/netinet/ip_mroute.c,v 1.56.2.2 2001/07/19 06:37:26 kris Exp $ */#include <sys/param.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/protosw.h>#include <sys/sockio.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_pcb.h>#include <netinet/ip.h>#include <netinet/ip_var.h>#include <netinet/in_var.h>#include <netinet/igmp.h>#include <netinet/ip_mroute.h>#include <netinet/udp.h>#ifndef NTOHL#if BYTE_ORDER != BIG_ENDIAN#define NTOHL(d) ((d) = ntohl((d)))#define NTOHS(d) ((d) = ntohs((u_short)(d)))#define HTONL(d) ((d) = htonl((d)))#define HTONS(d) ((d) = htons((u_short)(d)))#else#define NTOHL(d)#define NTOHS(d)#define HTONL(d)#define HTONS(d)#endif#endif#ifndef MROUTINGextern u_long	_ip_mcast_src __P((int vifi));extern int	_ip_mforward __P((struct ip *ip, struct ifnet *ifp,				  struct mbuf *m, struct ip_moptions *imo));extern int	_ip_mrouter_done __P((void));extern int	_ip_mrouter_get __P((struct socket *so, struct sockopt *sopt));extern int	_ip_mrouter_set __P((struct socket *so, struct sockopt *sopt));extern int	_mrt_ioctl __P((int req, caddr_t data, struct proc *p));/* * Dummy routines and globals used when multicast routing is not compiled in. */struct socket  *ip_mrouter  = NULL;u_int		rsvpdebug = 0;int_ip_mrouter_set(so, sopt)	struct socket *so;	struct sockopt *sopt;{	return(EOPNOTSUPP);}int (*ip_mrouter_set)(struct socket *, struct sockopt *) = _ip_mrouter_set;int_ip_mrouter_get(so, sopt)	struct socket *so;	struct sockopt *sopt;{	return(EOPNOTSUPP);}int (*ip_mrouter_get)(struct socket *, struct sockopt *) = _ip_mrouter_get;int_ip_mrouter_done(){	return(0);}int (*ip_mrouter_done)(void) = _ip_mrouter_done;int_ip_mforward(ip, ifp, m, imo)	struct ip *ip;	struct ifnet *ifp;	struct mbuf *m;	struct ip_moptions *imo;{	return(0);}int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,		   struct ip_moptions *) = _ip_mforward;int_mrt_ioctl(int req, caddr_t data, struct proc *p){	return EOPNOTSUPP;}int (*mrt_ioctl)(int, caddr_t, struct proc *) = _mrt_ioctl;voidrsvp_input(m, off)		/* XXX must fixup manually */	struct mbuf *m;	int off;{    /* Can still get packets with rsvp_on = 0 if there is a local member     * of the group to which the RSVP packet is addressed.  But in this     * case we want to throw the packet away.     */    if (!rsvp_on) {	m_freem(m);	return;    }     if (ip_rsvpd != NULL) {	if (rsvpdebug)	    printf("rsvp_input: Sending packet up old-style socket\n");	rip_input(m, off);	return;    }    /* Drop the packet */    m_freem(m);}void ipip_input(struct mbuf *m, int off) { /* XXX must fixup manually */	rip_input(m, off);}int (*legal_vif_num)(int) = 0;/* * This should never be called, since IP_MULTICAST_VIF should fail, but * just in case it does get called, the code a little lower in ip_output * will assign the packet a local address. */u_long_ip_mcast_src(int vifi) { return INADDR_ANY; }u_long (*ip_mcast_src)(int) = _ip_mcast_src;intip_rsvp_vif_init(so, sopt)    struct socket *so;    struct sockopt *sopt;{    return(EINVAL);}intip_rsvp_vif_done(so, sopt)    struct socket *so;    struct sockopt *sopt;{    return(EINVAL);}voidip_rsvp_force_done(so)    struct socket *so;{    return;}#else /* MROUTING */#define M_HASCL(m)	((m)->m_flags & M_EXT)#define INSIZ		sizeof(struct in_addr)#define	same(a1, a2) \	(bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0)/* * Globals.  All but ip_mrouter and ip_mrtproto could be static, * except for netstat or debugging purposes. */#ifndef MROUTE_LKMstruct socket  *ip_mrouter  = NULL;static struct mrtstat	mrtstat;#else /* MROUTE_LKM */extern void	X_ipip_input __P((struct mbuf *m, int iphlen));extern struct mrtstat mrtstat;static int ip_mrtproto;#endif#define NO_RTE_FOUND 	0x1#define RTE_FOUND	0x2static struct mfc	*mfctable[MFCTBLSIZ];static u_char		nexpire[MFCTBLSIZ];static struct vif	viftable[MAXVIFS];static u_int	mrtdebug = 0;	  /* debug level 	*/#define		DEBUG_MFC	0x02#define		DEBUG_FORWARD	0x04#define		DEBUG_EXPIRE	0x08#define		DEBUG_XMIT	0x10static u_int  	tbfdebug = 0;     /* tbf debug level 	*/static u_int	rsvpdebug = 0;	  /* rsvp debug level   */static struct callout_handle expire_upcalls_ch;#define		EXPIRE_TIMEOUT	(hz / 4)	/* 4x / second		*/#define		UPCALL_EXPIRE	6		/* number of timeouts	*//* * Define the token bucket filter structures * tbftable -> each vif has one of these for storing info  */static struct tbf tbftable[MAXVIFS];#define		TBF_REPROCESS	(hz / 100)	/* 100x / second *//* * 'Interfaces' associated with decapsulator (so we can tell * packets that went through it from ones that get reflected * by a broken gateway).  These interfaces are never linked into * the system ifnet list & no routes point to them.  I.e., packets * can't be sent this way.  They only exist as a placeholder for * multicast source verification. */static struct ifnet multicast_decap_if[MAXVIFS];#define ENCAP_TTL 64#define ENCAP_PROTO IPPROTO_IPIP	/* 4 *//* prototype IP hdr for encapsulated packets */static struct ip multicast_encap_iphdr = {#if BYTE_ORDER == LITTLE_ENDIAN	sizeof(struct ip) >> 2, IPVERSION,#else	IPVERSION, sizeof(struct ip) >> 2,#endif	0,				/* tos */	sizeof(struct ip),		/* total length */	0,				/* id */	0,				/* frag offset */	ENCAP_TTL, ENCAP_PROTO,		0,				/* checksum */};/* * Private variables. */static vifi_t	   numvifs = 0;static int have_encap_tunnel = 0;/* * one-back cache used by ipip_input to locate a tunnel's vif * given a datagram's src ip address. */static u_long last_encap_src;static struct vif *last_encap_vif;static u_long	X_ip_mcast_src __P((int vifi));static int	X_ip_mforward __P((struct ip *ip, struct ifnet *ifp, struct mbuf *m, struct ip_moptions *imo));static int	X_ip_mrouter_done __P((void));static int	X_ip_mrouter_get __P((struct socket *so, struct sockopt *m));static int	X_ip_mrouter_set __P((struct socket *so, struct sockopt *m));static int	X_legal_vif_num __P((int vif));static int	X_mrt_ioctl __P((int cmd, caddr_t data));static int get_sg_cnt(struct sioc_sg_req *);static int get_vif_cnt(struct sioc_vif_req *);static int ip_mrouter_init(struct socket *, int);static int add_vif(struct vifctl *);static int del_vif(vifi_t);static int add_mfc(struct mfcctl *);static int del_mfc(struct mfcctl *);static int socket_send(struct socket *, struct mbuf *, struct sockaddr_in *);static int set_assert(int);static void expire_upcalls(void *);static int ip_mdq(struct mbuf *, struct ifnet *, struct mfc *,		  vifi_t);static void phyint_send(struct ip *, struct vif *, struct mbuf *);static void encap_send(struct ip *, struct vif *, struct mbuf *);static void tbf_control(struct vif *, struct mbuf *, struct ip *, u_long);static void tbf_queue(struct vif *, struct mbuf *);static void tbf_process_q(struct vif *);static void tbf_reprocess_q(void *);static int tbf_dq_sel(struct vif *, struct ip *);static void tbf_send_packet(struct vif *, struct mbuf *);static void tbf_update_tokens(struct vif *);static int priority(struct vif *, struct ip *);void multiencap_decap(struct mbuf *);/* * whether or not special PIM assert processing is enabled. */static int pim_assert;/* * Rate limit for assert notification messages, in usec */#define ASSERT_MSG_TIME		3000000/* * Hash function for a source, group entry */#define MFCHASH(a, g) MFCHASHMOD(((a) >> 20) ^ ((a) >> 10) ^ (a) ^ \			((g) >> 20) ^ ((g) >> 10) ^ (g))/* * Find a route for a given origin IP address and Multicast group address * Type of service parameter to be added in the future!!! */#define MFCFIND(o, g, rt) { \	register struct mfc *_rt = mfctable[MFCHASH(o,g)]; \	rt = NULL; \	++mrtstat.mrts_mfc_lookups; \	while (_rt) { \		if ((_rt->mfc_origin.s_addr == o) && \		    (_rt->mfc_mcastgrp.s_addr == g) && \		    (_rt->mfc_stall == NULL)) { \			rt = _rt; \			break; \		} \		_rt = _rt->mfc_next; \	} \	if (rt == NULL) { \		++mrtstat.mrts_mfc_misses; \	} \}/* * Macros to compute elapsed time efficiently * Borrowed from Van Jacobson's scheduling code */#define TV_DELTA(a, b, delta) { \	    register int xxs; \		\	    delta = (a).tv_usec - (b).tv_usec; \	    if ((xxs = (a).tv_sec - (b).tv_sec)) { \	       switch (xxs) { \		      case 2: \			  delta += 1000000; \			      /* fall through */ \		      case 1: \			  delta += 1000000; \			  break; \		      default: \			  delta += (1000000 * xxs); \	       } \	    } \}#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \	      (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)#ifdef UPCALL_TIMINGu_long upcall_data[51];static void collate(struct timeval *);#endif /* UPCALL_TIMING *//* * Handle MRT setsockopt commands to modify the multicast routing tables. */static intX_ip_mrouter_set(so, sopt)	struct socket *so;	struct sockopt *sopt;{	int	error, optval;	vifi_t	vifi;	struct	vifctl vifc;	struct	mfcctl mfc;	if (so != ip_mrouter && sopt->sopt_name != MRT_INIT)		return (EPERM);	error = 0;	switch (sopt->sopt_name) {	case MRT_INIT:		error = sooptcopyin(sopt, &optval, sizeof optval, 				    sizeof optval);		if (error)			break;		error = ip_mrouter_init(so, optval);		break;	case MRT_DONE:		error = ip_mrouter_done();		break;	case MRT_ADD_VIF:		error = sooptcopyin(sopt, &vifc, sizeof vifc, sizeof vifc);		if (error)			break;		error = add_vif(&vifc);		break;	case MRT_DEL_VIF:		error = sooptcopyin(sopt, &vifi, sizeof vifi, sizeof vifi);		if (error)			break;		error = del_vif(vifi);		break;	case MRT_ADD_MFC:	case MRT_DEL_MFC:		error = sooptcopyin(sopt, &mfc, sizeof mfc, sizeof mfc);		if (error)			break;		if (sopt->sopt_name == MRT_ADD_MFC)			error = add_mfc(&mfc);		else			error = del_mfc(&mfc);		break;	case MRT_ASSERT:		error = sooptcopyin(sopt, &optval, sizeof optval, 				    sizeof optval);		if (error)			break;		set_assert(optval);		break;	default:		error = EOPNOTSUPP;		break;	}	return (error);}#ifndef MROUTE_LKMint (*ip_mrouter_set)(struct socket *, struct sockopt *) = X_ip_mrouter_set;#endif/* * Handle MRT getsockopt commands */static intX_ip_mrouter_get(so, sopt)	struct socket *so;	struct sockopt *sopt;{	int error;	static int version = 0x0305; /* !!! why is this here? XXX */	switch (sopt->sopt_name) {	case MRT_VERSION:		error = sooptcopyout(sopt, &version, sizeof version);		break;	case MRT_ASSERT:		error = sooptcopyout(sopt, &pim_assert, sizeof pim_assert);		break;	default:		error = EOPNOTSUPP;		break;	}	return (error);}#ifndef MROUTE_LKMint (*ip_mrouter_get)(struct socket *, struct sockopt *) = X_ip_mrouter_get;#endif/* * Handle ioctl commands to obtain information from the cache */static intX_mrt_ioctl(cmd, data)    int cmd;    caddr_t data;{    int error = 0;    switch (cmd) {	case (SIOCGETVIFCNT):	    return (get_vif_cnt((struct sioc_vif_req *)data));	    break;	case (SIOCGETSGCNT):	    return (get_sg_cnt((struct sioc_sg_req *)data));	    break;	default:	    return (EINVAL);	    break;    }    return error;}#ifndef MROUTE_LKMint (*mrt_ioctl)(int, caddr_t) = X_mrt_ioctl;#endif/* * returns the packet, byte, rpf-failure count for the source group provided */static intget_sg_cnt(req)    register struct sioc_sg_req *req;{    register struct mfc *rt;    int s;    s = splnet();    MFCFIND(req->src.s_addr, req->grp.s_addr, rt);    splx(s);    if (rt != NULL) {	req->pktcnt = rt->mfc_pkt_cnt;	req->bytecnt = rt->mfc_byte_cnt;	req->wrong_if = rt->mfc_wrong_if;    } else	req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;    return 0;}/* * returns the input and output packet and byte counts on the vif provided */static intget_vif_cnt(req)    register struct sioc_vif_req *req;{    register vifi_t vifi = req->vifi;    if (vifi >= numvifs) return EINVAL;    req->icount = viftable[vifi].v_pkt_in;    req->ocount = viftable[vifi].v_pkt_out;    req->ibytes = viftable[vifi].v_bytes_in;    req->obytes = viftable[vifi].v_bytes_out;    return 0;}/* * Enable multicast routing */static intip_mrouter_init(so, version)	struct socket *so;	int version;{    if (mrtdebug)	log(LOG_DEBUG,"ip_mrouter_init: so_type = %d, pr_protocol = %d\n",		so->so_type, so->so_proto->pr_protocol);    if (so->so_type != SOCK_RAW ||	so->so_proto->pr_protocol != IPPROTO_IGMP) return EOPNOTSUPP;    if (version != 1)	return ENOPROTOOPT;    if (ip_mrouter != NULL) return EADDRINUSE;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?