Chinaunix首页 | 论坛 | 博客
  • 博客访问: 29949
  • 博文数量: 6
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 70
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-13 13:23
文章分类

全部博文(6)

文章存档

2013年(6)

我的朋友

分类: LINUX

2013-11-07 16:30:58

前几天设备突然出现问题,害的我搞到凌晨3点多。当时虽然问题搞定,但对深层次的原因不是很清楚,所以写篇blog记录下,希望帮到遇到类似问题的朋友。

问题描述,系统中用的packet socket抓包,但是同样的包,发送的时候却失败了,按道理不应该的。查看日志,是大于1514(MTU 1500 + 以太头 14)的包发送失败了,现实错误时"message too long"。查看抓包的地方,居然抓到了大于1514的包,。其实,对于抓到大于MTU的包,这点我也很疑惑。

关于这个问题我想以两个问题的形式把问题及原因引出来.

问题1:
    下面这段代码的,rcvbuf 跟 sendbuf 分贝设置设置多大合适?
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        read = recv(sockfd ,rcvbuf,sizeof(rcvbuf), 0);
        write = send(sockfd ,sendbuf,sizeof(sendbuf), 0);
解答:
    上面的代码是一个正常的tcp socket,两个buf的大小应该是没有大小限制,但是网上说有64k的限制,这一点我没有查阅相关资料,不敢确定。但是,至少有一点是确定的,可以接收或者发送送大于MTU的数据包。
    ps:MTU是链路层的概念,在tcp层是mss,但是为了这里讨论方便,将他俩视为"一个概念",就是socket(packet 、raw socket)所能发送的最大字节数,二者的区别,可以去google.


问题2:
    下面二者的区别
    raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    packet_socket = socket(PF_PACKET, SOCK_RAW, IPPROTO_TCP);

解答:
     第一个是基于AF_INET协议族的raw socket,第二个是基于PF_PACKET的raw socket,都可以用于抓包,但是二者抓包的位置不一样,方式1抓包是在tcp/ip协议层之上,方式2是在
链路层抓到的包,所以造成的结果是方式1抓到的包是经过ip层的分片重组的,所以在没有网卡的一些特性的支持下(嘿嘿,下面会说到网卡的一些特性对抓包的影响),方式1抓到的其实是数据流,方式2抓到的是单个的数据包。所以用方式1抓包的话,接收buf的大小应该是任意的,但是这点没有验证过,理论上是这样。现在用方式1抓包的少了,也懒得去验证了,下面见证奇葩,谈下一个问题。
问题3:
       下面这段代码的,rcvbuf 跟 sendbuf 分贝设置设置多大合适?
    
    read = recv(packet_socket,rcvbuf,sizeof(rcvbuf), 0);
    write = send(packet_socket ,sendbuf,sizeof(sendbuf), 0);
    因为packet socket是在链路层抓包的,所以抓到的包不会经过协议栈,也就不会被分片重组,所以理论上在普通的以太环境中,rcvbuf的大小不能小于1514(MTU + 14的链路层长度),因为如果rcvbuf太小的话,比如rcvbuf大小是1400 ,接收到1500的一个包,多余的100字节会被丢弃掉,就会出问题。
     但是,,
     用packet socket确实抓到了大于MTU的包,如何解释?这跟在wireshark中抓包抓到大于MTU的包是一回事,linux wireshark 用的应该也是packet socket。
    难道无解???NO!!!!且看下面分解。。

先看下关于网卡的一些特性,秘密就在这:

网卡TSO、UFO、GSO、LRO、GRO和RSS介绍 

见链接: http://coolhappy.blog.163.com/blog/static/19285610820121119112017797/

这里只说TSO,GSO,GRO
简单点说TSO是用于发送的时候对数据包进行分片的,如果协议栈检测到网卡支持TSO就不会再协议栈层分片,而将整个数据包发送到网卡,由网卡分片后发送出去。
GSO跟TSO差不多,通用性好点。。
GRO是用于对接收的数据包进行分片重组的,这样就免去了协议层对数据包进行重组,节省系统资源,提高效率。

所以,问题就出在这里,如果开启了GRO,但是没有开TSO的话,就会出现收到大包,却发送失败的问题。但是,单纯打开TSO,用PACKET SOCKET 发包还是会失败,要设置一个socket选项,这个选项的含义没有完全搞明白,内核源码里没有注释,希望知道的朋友不吝赐教。


相关的网卡设置的命令,及socket选项设置,

ethtool -K eth0 tso off/on
ethtool -K eth0 gso off/on
ethtool -K eth0 gro off/on

int flag = 1;
setsockopt(packet_socket,SOL_PACKET,PACKET_VNET_HDR,&flag,sizeof(int));



阅读(3360) | 评论(0) | 转发(0) |
0

上一篇:一个python小爬虫(详细注释)

下一篇:没有了

给主人留下些什么吧!~~