⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipmr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local){	int psend = -1;	int vif, ct;	vif = cache->mfc_parent;	cache->mfc_un.res.pkt++;	cache->mfc_un.res.bytes += skb->len;	/*	 * Wrong interface: drop packet and (maybe) send PIM assert.	 */	if (vif_table[vif].dev != skb->dev) {		int true_vifi;		if (((struct rtable*)skb->dst)->fl.iif == 0) {			/* It is our own packet, looped back.			   Very complicated situation...			   The best workaround until routing daemons will be			   fixed is not to redistribute packet, if it was			   send through wrong interface. It means, that			   multicast applications WILL NOT work for			   (S,G), which have default multicast route pointing			   to wrong oif. In any case, it is not a good			   idea to use multicasting applications on router.			 */			goto dont_forward;		}		cache->mfc_un.res.wrong_if++;		true_vifi = ipmr_find_vif(skb->dev);		if (true_vifi >= 0 && mroute_do_assert &&		    /* pimsm uses asserts, when switching from RPT to SPT,		       so that we cannot check that packet arrived on an oif.		       It is bad, but otherwise we would need to move pretty		       large chunk of pimd to kernel. Ough... --ANK		     */		    (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) &&		    time_after(jiffies,			       cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {			cache->mfc_un.res.last_assert = jiffies;			ipmr_cache_report(skb, true_vifi, IGMPMSG_WRONGVIF);		}		goto dont_forward;	}	vif_table[vif].pkt_in++;	vif_table[vif].bytes_in+=skb->len;	/*	 *	Forward the frame	 */	for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {		if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {			if (psend != -1) {				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);				if (skb2)					ipmr_queue_xmit(skb2, cache, psend);			}			psend=ct;		}	}	if (psend != -1) {		if (local) {			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);			if (skb2)				ipmr_queue_xmit(skb2, cache, psend);		} else {			ipmr_queue_xmit(skb, cache, psend);			return 0;		}	}dont_forward:	if (!local)		kfree_skb(skb);	return 0;}/* *	Multicast packets for forwarding arrive here */int ip_mr_input(struct sk_buff *skb){	struct mfc_cache *cache;	int local = ((struct rtable*)skb->dst)->rt_flags&RTCF_LOCAL;	/* Packet is looped back after forward, it should not be	   forwarded second time, but still can be delivered locally.	 */	if (IPCB(skb)->flags&IPSKB_FORWARDED)		goto dont_forward;	if (!local) {		    if (IPCB(skb)->opt.router_alert) {			    if (ip_call_ra_chain(skb))				    return 0;		    } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP){			    /* IGMPv1 (and broken IGMPv2 implementations sort of			       Cisco IOS <= 11.2(8)) do not put router alert			       option to IGMP packets destined to routable			       groups. It is very bad, because it means			       that we can forward NO IGMP messages.			     */			    read_lock(&mrt_lock);			    if (mroute_socket) {				    nf_reset(skb);				    raw_rcv(mroute_socket, skb);				    read_unlock(&mrt_lock);				    return 0;			    }			    read_unlock(&mrt_lock);		    }	}	read_lock(&mrt_lock);	cache = ipmr_cache_find(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);	/*	 *	No usable cache entry	 */	if (cache==NULL) {		int vif;		if (local) {			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);			ip_local_deliver(skb);			if (skb2 == NULL) {				read_unlock(&mrt_lock);				return -ENOBUFS;			}			skb = skb2;		}		vif = ipmr_find_vif(skb->dev);		if (vif >= 0) {			int err = ipmr_cache_unresolved(vif, skb);			read_unlock(&mrt_lock);			return err;		}		read_unlock(&mrt_lock);		kfree_skb(skb);		return -ENODEV;	}	ip_mr_forward(skb, cache, local);	read_unlock(&mrt_lock);	if (local)		return ip_local_deliver(skb);	return 0;dont_forward:	if (local)		return ip_local_deliver(skb);	kfree_skb(skb);	return 0;}#ifdef CONFIG_IP_PIMSM_V1/* * Handle IGMP messages of PIMv1 */int pim_rcv_v1(struct sk_buff * skb){	struct igmphdr *pim;	struct iphdr   *encap;	struct net_device  *reg_dev = NULL;	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))		goto drop;	pim = igmp_hdr(skb);	if (!mroute_do_pim ||	    skb->len < sizeof(*pim) + sizeof(*encap) ||	    pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)		goto drop;	encap = (struct iphdr *)(skb_transport_header(skb) +				 sizeof(struct igmphdr));	/*	   Check that:	   a. packet is really destinted to a multicast group	   b. packet is not a NULL-REGISTER	   c. packet is not truncated	 */	if (!MULTICAST(encap->daddr) ||	    encap->tot_len == 0 ||	    ntohs(encap->tot_len) + sizeof(*pim) > skb->len)		goto drop;	read_lock(&mrt_lock);	if (reg_vif_num >= 0)		reg_dev = vif_table[reg_vif_num].dev;	if (reg_dev)		dev_hold(reg_dev);	read_unlock(&mrt_lock);	if (reg_dev == NULL)		goto drop;	skb->mac_header = skb->network_header;	skb_pull(skb, (u8*)encap - skb->data);	skb_reset_network_header(skb);	skb->dev = reg_dev;	skb->protocol = htons(ETH_P_IP);	skb->ip_summed = 0;	skb->pkt_type = PACKET_HOST;	dst_release(skb->dst);	skb->dst = NULL;	((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len;	((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++;	nf_reset(skb);	netif_rx(skb);	dev_put(reg_dev);	return 0; drop:	kfree_skb(skb);	return 0;}#endif#ifdef CONFIG_IP_PIMSM_V2static int pim_rcv(struct sk_buff * skb){	struct pimreghdr *pim;	struct iphdr   *encap;	struct net_device  *reg_dev = NULL;	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))		goto drop;	pim = (struct pimreghdr *)skb_transport_header(skb);	if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||	    (pim->flags&PIM_NULL_REGISTER) ||	    (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&	     csum_fold(skb_checksum(skb, 0, skb->len, 0))))		goto drop;	/* check if the inner packet is destined to mcast group */	encap = (struct iphdr *)(skb_transport_header(skb) +				 sizeof(struct pimreghdr));	if (!MULTICAST(encap->daddr) ||	    encap->tot_len == 0 ||	    ntohs(encap->tot_len) + sizeof(*pim) > skb->len)		goto drop;	read_lock(&mrt_lock);	if (reg_vif_num >= 0)		reg_dev = vif_table[reg_vif_num].dev;	if (reg_dev)		dev_hold(reg_dev);	read_unlock(&mrt_lock);	if (reg_dev == NULL)		goto drop;	skb->mac_header = skb->network_header;	skb_pull(skb, (u8*)encap - skb->data);	skb_reset_network_header(skb);	skb->dev = reg_dev;	skb->protocol = htons(ETH_P_IP);	skb->ip_summed = 0;	skb->pkt_type = PACKET_HOST;	dst_release(skb->dst);	((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len;	((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++;	skb->dst = NULL;	nf_reset(skb);	netif_rx(skb);	dev_put(reg_dev);	return 0; drop:	kfree_skb(skb);	return 0;}#endifstatic intipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm){	int ct;	struct rtnexthop *nhp;	struct net_device *dev = vif_table[c->mfc_parent].dev;	u8 *b = skb_tail_pointer(skb);	struct rtattr *mp_head;	if (dev)		RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex);	mp_head = (struct rtattr*)skb_put(skb, RTA_LENGTH(0));	for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {		if (c->mfc_un.res.ttls[ct] < 255) {			if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))				goto rtattr_failure;			nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));			nhp->rtnh_flags = 0;			nhp->rtnh_hops = c->mfc_un.res.ttls[ct];			nhp->rtnh_ifindex = vif_table[ct].dev->ifindex;			nhp->rtnh_len = sizeof(*nhp);		}	}	mp_head->rta_type = RTA_MULTIPATH;	mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;	rtm->rtm_type = RTN_MULTICAST;	return 1;rtattr_failure:	nlmsg_trim(skb, b);	return -EMSGSIZE;}int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait){	int err;	struct mfc_cache *cache;	struct rtable *rt = (struct rtable*)skb->dst;	read_lock(&mrt_lock);	cache = ipmr_cache_find(rt->rt_src, rt->rt_dst);	if (cache==NULL) {		struct sk_buff *skb2;		struct iphdr *iph;		struct net_device *dev;		int vif;		if (nowait) {			read_unlock(&mrt_lock);			return -EAGAIN;		}		dev = skb->dev;		if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) {			read_unlock(&mrt_lock);			return -ENODEV;		}		skb2 = skb_clone(skb, GFP_ATOMIC);		if (!skb2) {			read_unlock(&mrt_lock);			return -ENOMEM;		}		skb_push(skb2, sizeof(struct iphdr));		skb_reset_network_header(skb2);		iph = ip_hdr(skb2);		iph->ihl = sizeof(struct iphdr) >> 2;		iph->saddr = rt->rt_src;		iph->daddr = rt->rt_dst;		iph->version = 0;		err = ipmr_cache_unresolved(vif, skb2);		read_unlock(&mrt_lock);		return err;	}	if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))		cache->mfc_flags |= MFC_NOTIFY;	err = ipmr_fill_mroute(skb, cache, rtm);	read_unlock(&mrt_lock);	return err;}#ifdef CONFIG_PROC_FS/* *	The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif */struct ipmr_vif_iter {	int ct;};static struct vif_device *ipmr_vif_seq_idx(struct ipmr_vif_iter *iter,					   loff_t pos){	for (iter->ct = 0; iter->ct < maxvif; ++iter->ct) {		if (!VIF_EXISTS(iter->ct))			continue;		if (pos-- == 0)			return &vif_table[iter->ct];	}	return NULL;}static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos){	read_lock(&mrt_lock);	return *pos ? ipmr_vif_seq_idx(seq->private, *pos - 1)		: SEQ_START_TOKEN;}static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct ipmr_vif_iter *iter = seq->private;	++*pos;	if (v == SEQ_START_TOKEN)		return ipmr_vif_seq_idx(iter, 0);	while (++iter->ct < maxvif) {		if (!VIF_EXISTS(iter->ct))			continue;		return &vif_table[iter->ct];	}	return NULL;}static void ipmr_vif_seq_stop(struct seq_file *seq, void *v){	read_unlock(&mrt_lock);}static int ipmr_vif_seq_show(struct seq_file *seq, void *v){	if (v == SEQ_START_TOKEN) {		seq_puts(seq,			 "Interface      BytesIn  PktsIn  BytesOut PktsOut Flags Local    Remote\n");	} else {		const struct vif_device *vif = v;		const char *name =  vif->dev ? vif->dev->name : "none";		seq_printf(seq,			   "%2Zd %-10s %8ld %7ld  %8ld %7ld %05X %08X %08X\n",			   vif - vif_table,			   name, vif->bytes_in, vif->pkt_in,			   vif->bytes_out, vif->pkt_out,			   vif->flags, vif->local, vif->remote);	}	return 0;}static const struct seq_operations ipmr_vif_seq_ops = {	.start = ipmr_vif_seq_start,	.next  = ipmr_vif_seq_next,	.stop  = ipmr_vif_seq_stop,	.show  = ipmr_vif_seq_show,};static int ipmr_vif_open(struct inode *inode, struct file *file){	return seq_open_private(file, &ipmr_vif_seq_ops,			sizeof(struct ipmr_vif_iter));}static const struct file_operations ipmr_vif_fops = {	.owner	 = THIS_MODULE,	.open    = ipmr_vif_open,	.read    = seq_read,	.llseek  = seq_lseek,	.release = seq_release_private,};struct ipmr_mfc_iter {	struct mfc_cache **cache;	int ct;};static struct mfc_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos){	struct mfc_cache *mfc;	it->cache = mfc_cache_array;	read_lock(&mrt_lock);	for (it->ct = 0; it->ct < MFC_LINES; it->ct++)		for (mfc = mfc_cache_array[it->ct]; mfc; mfc = mfc->next)			if (pos-- == 0)				return mfc;	read_unlock(&mrt_lock);	it->cache = &mfc_unres_queue;	spin_lock_bh(&mfc_unres_lock);	for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)		if (pos-- == 0)			return mfc;	spin_unlock_bh(&mfc_unres_lock);	it->cache = NULL;	return NULL;}static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos){	struct ipmr_mfc_iter *it = seq->private;	it->cache = NULL;	it->ct = 0;	return *pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1)		: SEQ_START_TOKEN;}static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct mfc_cache *mfc = v;	struct ipmr_mfc_iter *it = seq->private;	++*pos;	if (v == SEQ_START_TOKEN)		return ipmr_mfc_seq_idx(seq->private, 0);	if (mfc->next)		return mfc->next;	if (it->cache == &mfc_unres_queue)		goto end_of_list;	BUG_ON(it->cache != mfc_cache_array);	while (++it->ct < MFC_LINES) {		mfc = mfc_cache_array[it->ct];		if (mfc)			return mfc;	}	/* exhausted cache_array, show unresolved */	read_unlock(&mrt_lock);	it->cache = &mfc_unres_queue;	it->ct = 0;	spin_lock_bh(&mfc_unres_lock);	mfc = mfc_unres_queue;	if (mfc)		return mfc; end_of_list:	spin_unlock_bh(&mfc_unres_lock);	it->cache = NULL;	return NULL;}static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v){	struct ipmr_mfc_iter *it = seq->private;	if (it->cache == &mfc_unres_queue)		spin_unlock_bh(&mfc_unres_lock);	else if (it->cache == mfc_cache_array)		read_unlock(&mrt_lock);}static int ipmr_mfc_seq_show(struct seq_file *seq, void *v){	int n;	if (v == SEQ_START_TOKEN) {		seq_puts(seq,		 "Group    Origin   Iif     Pkts    Bytes    Wrong Oifs\n");	} else {		const struct mfc_cache *mfc = v;		const struct ipmr_mfc_iter *it = seq->private;		seq_printf(seq, "%08lX %08lX %-3d %8ld %8ld %8ld",			   (unsigned long) mfc->mfc_mcastgrp,			   (unsigned long) mfc->mfc_origin,			   mfc->mfc_parent,			   mfc->mfc_un.res.pkt,			   mfc->mfc_un.res.bytes,			   mfc->mfc_un.res.wrong_if);		if (it->cache != &mfc_unres_queue) {			for (n = mfc->mfc_un.res.minvif;			     n < mfc->mfc_un.res.maxvif; n++ ) {				if (VIF_EXISTS(n)				   && mfc->mfc_un.res.ttls[n] < 255)				seq_printf(seq,					   " %2d:%-3d",					   n, mfc->mfc_un.res.ttls[n]);			}		}		seq_putc(seq, '\n');	}	return 0;}static const struct seq_operations ipmr_mfc_seq_ops = {	.start = ipmr_mfc_seq_start,	.next  = ipmr_mfc_seq_next,	.stop  = ipmr_mfc_seq_stop,	.show  = ipmr_mfc_seq_show,};static int ipmr_mfc_open(struct inode *inode, struct file *file){	return seq_open_private(file, &ipmr_mfc_seq_ops,			sizeof(struct ipmr_mfc_iter));}static const struct file_operations ipmr_mfc_fops = {	.owner	 = THIS_MODULE,	.open    = ipmr_mfc_open,	.read    = seq_read,	.llseek  = seq_lseek,	.release = seq_release_private,};#endif#ifdef CONFIG_IP_PIMSM_V2static struct net_protocol pim_protocol = {	.handler	=	pim_rcv,};#endif/* *	Setup for IP multicast routing */void __init ip_mr_init(void){	mrt_cachep = kmem_cache_create("ip_mrt_cache",				       sizeof(struct mfc_cache),				       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,				       NULL);	init_timer(&ipmr_expire_timer);	ipmr_expire_timer.function=ipmr_expire_process;	register_netdevice_notifier(&ip_mr_notifier);#ifdef CONFIG_PROC_FS	proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops);	proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops);#endif}

⌨️ 快捷键说明

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