Chinaunix

标题: 关于一块网卡收包,另一块网卡转发数据包的问题 [打印本页]

作者: Arm_Linux_boy    时间: 2011-03-07 16:48
标题: 关于一块网卡收包,另一块网卡转发数据包的问题
本帖最后由 dreamice 于 2011-03-08 17:24 编辑

各位大牛,帮帮我,帮我看一个问题。
用的操作系统是suse9,内核是2.6.5
我在做一个网卡转发包的功能模块,是直接在网卡驱动中修改的,修改的网卡驱动是e1000,主要是实现一块网卡接收数据包,然后由另一块网卡转发走。我将网卡的接收模式置成了混杂模式。
首先将A网卡收到的数据包存放到缓存区中,然后将缓存区中的数据包构造成sk_buff结构,sk_buff的设置如下:
   skb_reserve(skb, 18);
    skb->mac.raw = skb->data;//指向mac域
    skb->nh.raw = skb->mac.raw + 14;
    memcpy(skb->data, skb_blk, snd_length);//skb_blk是缓存区中保存原先数据包的内容,数据包内容里有完整的mac,ip等各个头信息       
    skb_put(skb, snd_length);
    skb->pkt_type = PACKET_OTHERHOST;
    skb->protocol = *(unsigned short *)(skb_blk + 12);
    skb->ip_summed = CHECKSUM_NONE;
    skb->priority = 0;
    skb->len = snd_length;
    skb->data_len = 0;
(1)然后直接调用发送函数dev_queue_xmit(skb)会出现死机现象。
(2)如果此时设置atomic_set(&skb->users, 0);再调用dev_queue_xmit(skb)不会死机,但是经过网卡的数据包过多时就是死机。
(3)如果调用skb->dev->hard_start_xmit(skb, skb->dev)这个函数的时候不会死机,但是数据包过多时就会死机,而且此时发现发送成功后的skb没有释放掉,于是我怀疑是内存泄漏,但是再释放skb,但是此时出现的现象是机器假死了,能ping通这台主机,但是不能对主机进行操作了
(4)如果设置atomic_set(&skb->users, 0);再调用skb->dev->hard_start_xmit(skb, skb->dev);然后再释放skb,此时不会死机,但是经过网卡的数据包过多时就会死机
请问根据上面的现象大概是哪里有可能有问题,谢谢了,这几天被这个问题困扰很久了,望大牛们帮帮忙
作者: Arm_Linux_boy    时间: 2011-03-07 16:50
图中那个发出来是一个表情的,其实是数字8
作者: shank941    时间: 2011-03-07 17:15
本帖最后由 shank941 于 2011-03-07 17:19 编辑
各位大牛,帮帮我,帮我看一个问题。
用的操作系统是suse9,内核是2.6.5
我在做一个网卡转发包的功能模块 ...
Arm_Linux_boy 发表于 2011-03-07 16:48


1.死机是什么现象?crash了?还是只是驱动不转发了?如果只是网卡不转发,可以把网卡的BD状态打印出来看看bd状态。
2.是直接在驱动层就调用skb->dev->hard_start_xmit转发了么,还是会经过上层协议栈的?
3.另外看到你直接设置引用计数和内存泄漏问题,我猜没释放可能是哪里的引用计数出问题了(kfree_skb只有引用计数为1时才释放),直接set 0 肯定不行,人家还用着呢,你直接set 0给强行free 了。。。
4.方便的话,最好是把代码都放上来。
作者: Godbach    时间: 2011-03-07 17:20
回复 1# Arm_Linux_boy


   
主要是实现一块网卡接收数据包,然后由另一块网卡转发走

你的代码中体现了 有另一块网卡发出的设置了吗?
作者: Arm_Linux_boy    时间: 2011-03-07 18:50
回复 3# shank941
(1)系统是直接crash掉的
(2)直接通过skb->dev->hard_start_xmit转发和通过dev_queue_xmit转发的我都有做过,出现的现象我也列在上面了。
(3)对于引用计数,如果不设置为0的话,dev_queue_xmit的调用就会直接死机,如果不设置的话,只能使用skb->dev->hard_start_xmit
不会死机,但是内存泄漏问题就出现了,数据包多了电脑又死机了。如果在skb->dev->hard_start_xmit发生完数据包之后调用kfree_skb将skb释放掉的话就会造成假死问题,能ping主机,但是不能进行操作。
作者: Arm_Linux_boy    时间: 2011-03-07 18:53
回复 4# Godbach
skb->dev = e_dev;e_dev里面就是用来发送的网卡指针。
作者: Godbach    时间: 2011-03-07 18:59
你是在什么下测试的,有 Oops 信息吗。还是一发包就死了,什么都没有
作者: Arm_Linux_boy    时间: 2011-03-07 19:15
当我不设置引用计数为0的时候,直接调用skb->dev->hard_start_xmit(skb, skb->dev)来发送数据包的时候
出现以下的oops信息:
linux kernel: invalid operand: 0000 [1] SMP

然后紧接着就死机了,也ping不同主机
作者: Arm_Linux_boy    时间: 2011-03-07 19:50
回复 3# shank941
如果引用计数是1,然后skb发送结束后又没有被释放,这时候我来主动用kfree_skb来释放skb,此时就会出现那种假死印象。
应该在什么情况下可以较安全地释放skb?
作者: Godbach    时间: 2011-03-07 20:16
你的 oops 信息不够全啊。建议你找个虚拟机测试,这样便于保存 oops 信息
作者: shank941    时间: 2011-03-07 21:34
回复 9# Arm_Linux_boy


    看你描述的现象,个人猜测应该原因可能是这样:

   1.由于引用计数不对,有增加引用计数,但没减少的地方,因此出现内存泄漏。
   2.由于你强制将skb的引用计数清0,并直接kfree了skb,而其他模块本来对这个skb有引用计数的,因此这部分内存可能会重入,小流量时不一定冲突,
大流量时就产生冲突了,导致这里同步访问的内存可能异常。


正常报文发送后skb的释放,应该是通过网卡发送完成的中断来触发的,此时会去释放skb,正常时候skb的引用计数应该是1,此时正好释放掉了这个buffer。
建议先看看不改引用计数,引用计数为什么没减成0,为什么内存没释放掉,不用大流量,加个打印看看就行了,应该引用计数是有增有减的,没有你这样直接set 0这么玩的。。。
作者: Arm_Linux_boy    时间: 2011-03-08 09:03
回复 10# Godbach
还有一个现象就是当调用dev_queue_xmit来发送skb的时候,如果把网线拔掉也就是现在的网卡状态是down的时候,电脑不死机,然后插上也不会死机程序继续正常工作。但是插上网线即网卡up就会死掉
作者: Godbach    时间: 2011-03-08 09:50
down 的估计就没有触发发包的程序,当然不会死机了。
应该就是你的 skb 处理的有问题,导致调用 dev_queue_xmit 出问题。
作者: Godbach    时间: 2011-03-08 09:51
对了,你可以这样测试一下:
用个 Netfilter 的 hook 函数,在这个里面拦截数据包,然后修改一下数据包,从另外一个网口转发出去。这样可以做成模块的方式,便于调试。

BTW,你的实际需求是什么
作者: Arm_Linux_boy    时间: 2011-03-08 14:10
回复 14# Godbach
我是网卡的驱动层直接抓的包,在网卡驱动准备调用netif_receive_skb(old_skb);
将数据包发送到协议栈之前被我截下,然后我使用
skb_push(old_skb, SIZE_ETHERNET);       
struct sk_buff *skb = skb_copy(old_skb, GFP_ATOMIC);
然后我再调用dev_queue_xmit发送也是会死机的

我的需求就是现在将A网卡收到的数据包直接从B网卡发走
作者: Arm_Linux_boy    时间: 2011-03-08 14:13
回复 13# Godbach
那么SKB怎么处理?我之前收到数据包的时候,会将数据包交给应用程序检测下,然后再交给驱动程序由B网卡发走,这时候是没有问题的,不会死机
作者: Godbach    时间: 2011-03-08 15:00
感觉你说的不清楚。
你的数据包不是到了网卡驱动需要直接转发给另外一个网口吗。怎么还有交给应用层程序检测啊
作者: Godbach    时间: 2011-03-08 15:01
回复 16# Arm_Linux_boy


    NF 收到 skb,修改一下 skb,调用 dev_queue_xmit 发出去,并且给 NF  返回一个 NF_STOLEN 即可
作者: Arm_Linux_boy    时间: 2011-03-08 16:15
Netfilter我没有使用过,我们现在在做一个检测数据包协议的东西。数据数据包收到后需要交给应用程序检测,但有时候应用程序还没有开启的情况下就需要直接将数据包从另外一块网卡转发走。所以整个过程都是驱动程序里面添加模块来实现这些功能的
作者: dreamice    时间: 2011-03-08 17:25
图中那个发出来是一个表情的,其实是数字8
Arm_Linux_boy 发表于 2011-03-07 16:50



    发帖的时候,左边选择“禁用 Smilies”就可以解决这个问题了




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2