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