最近遇到一个QinQ的问题,总结一下。
对QinQ协议的交换机做Span,tcpdump抓包后发现,有一些包大小为1522字节,这些包都被网卡丢掉了。仔细排查后发现,网卡对于>1518的包,统一丢掉处理了。
简单的解决办法,就是将网卡的mtu增大,设置为1508或者直接1600,就OK了。
事情虽小,但还是有不少知识点的,归纳一下:
QinQ
简介
IEEE 802.1ad或称为QinQ、vlan stacking。是一种以802.1Q为基础衍生出来的通讯协定。
QinQ报文有固定的格式,就是在802.1Q的标签之上再打一层802.1Q标签,QinQ报文比正常的802.1Q报文多4个字节。这4个字节用作外层标签,即运营商网络的公网VLAN Tag。原802.1Q的Tag用作内层标签,即私网VLAN Tag。
可以参考这张图:
https://zh.wikipedia.org/wiki/IEEE802.1ad#/media/File:TCPIP802.1ad_DoubleTag.svg
QinQ的出现,扩充了原始的vlan个数,由4094 -> 4094*4094。
QinQ的作用,在大规模组网时,或者建立Paas云时,可以允许不同的租户设置相同的vlan id。
并不是所有的交换机都支持QinQ的,QinQ只是一个草案,需要交换机厂商的支持。
下面从wiki上摘抄一个典型例子:
Acme及XYZ分别在Seattle及Tacoma有一间分公司,并借由SP的L2 VPN网络连线,而他们的子公司都使用相同的LAN。 换句话说,我们可以假设,Acme使用VLAN 100-200并透过SP连结两间子公司的网络;XYZ也使用VLAN 100-200并使用SP的网络连结子公司。
而对SP而言,则必须想办法区隔Acme及XYZ的资料,使其有办法通过SP的网络并分别送至各自的子公司。
解决办法就是,使用VLAN STACKING来区隔Acme及XYZ的资料。
当Acme送出资料时,SP使用QinQ并给予该资料一个独特的SPVID 1001,使其能通过SP的网络并流向另外一间子公司,当到达子公司则移除该SPVID,该资料便能依照原始的VLAN ID进行传送。而XYZ送出资料时,SP则使用SPVID 1002来区隔。
包长
QinQ比正常的报文多了4个字节,所以QinQ报文,在链路层,最大包长到了1522个字节。
标准的Ethernet V2中,IP报文最大不超过1500字节,加上DA+SA+TYPE+DATA+PAD, 链路层的以太网帧最小为60字节,最大为1514字节,如果是802.1q,带有vlan tag,会有1518字节。
QinQ的最大包长明显超出了,在大多数网卡驱动中,默认配置下,这种包是会被丢弃掉的。好在交换机会自动处理这种情况,确保包最终到我们的网卡时,是符合Ethernet V2的。
但是直接对交换机端口做Span,网卡便傻掉了。
阅读linux tg3驱动源码发现,丢弃此类包的判断是很简单的:
10188 /* MTU + ethernet header + FCS + optional VLAN tag */
10189 tw32(MAC_RX_MTU_SIZE,
10190 tp->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
10191
http://lxr.free-electrons.com/source/drivers/net/ethernet/broadcom/tg3.c#L88
所以只要把网卡的mtu改改大就可以了:
ifconfig ethx mtu 1600 up
再说说以太网帧的大小
根据rfc894的说明,以太网封装IP数据包的最大长度是1500字节,也就是说以太网最大帧长应该是以太网首部加上1500,再加上7字节的前导同步码和1字节的帧开始定界符,具体就是:7字节前导同步码 + 1字节帧开始定界符 + 6字节的目的MAC + 6字节的源MAC + 2字节的帧类型 + 1500 + 4字节的FCS。
按照上述,最大帧应该是1526字节,但是实际上我们抓包得到的最大帧是1514字节,为什么不是1526字节呢?
原因是当数据帧到达网卡时,在物理层上网卡要先去掉前导同步码和帧开始定界符,然后对帧进行CRC检验,如果帧校验和出错,就丢弃此帧。如果校验和正确,就判断帧的目的硬件地址是否符合自己的接收条件(目的地址是自己的物理硬件地址、广播地址、可接收的多播硬件地址等),如果符合,就将帧交给“设备驱动程序”做进一步处理。这时我们抓包的软件才能抓到数据,因此,抓包软件抓到的是去掉前导同步码、帧开始分界符、FCS之外的数据,其最大值是6 + 6 + 2 + 1500 = 1514。
以太网规定,以太网帧数据域部分最小为46字节,也就是以太网帧最小是 6 + 6 + 2 + 46 + 4 = 64。除去4个字节的FCS,因此,抓包时就是60字节。当数据字段的长度小于46字节时,MAC子层就会在数据字段的后面填充以满足数据帧长不小于64 字节。由于填充数据是由MAC子层负责,也就是设备驱动程序。不同的抓包程序和设备驱动程序所处的优先层次可能不同,抓包程序的优先级可能比设备驱动程序更高,也就是说,我们的抓包程序可能在设备驱动程序还没有填充不到64字节帧的时候,已经捕获了数据。因此不同的抓包工具抓到的数据帧的大小可能不同。(比如,wireshark抓到的可能没有填充数据段,而sniffer抓到的就有填充数据段)
那么以太网帧格式一共有多少种呢
历史上以太网帧格式有五种:
1 Ethernet V1
这是最原始的一种格式,是由Xerox PARC提出的3Mbps CSMA/CD以太网标准的封装格式,后来在1980年由DEC,Intel和Xerox标准化形成Ethernet V1标准
2 Ethernet II即DIX 2.0
Xerox与DEC、Intel在1982年制定的以太网标准帧格式。Cisco名称为:ARPA。
这是最常见的一种以太网帧格式,也是今天以太网的事实标准,由DEC,Intel和Xerox在1982年公布其标准,主要更改了Ethernet V1的电气特性和物理接口,在帧格式上并无变化;
Ethernet V2出现后迅速取代Ethernet V1成为以太网事实标准; Ethernet V2帧头结构为6bytes的源地址+6bytes的目标地址+2Bytes的协议类型字段+数据。 常见协议类型如下:
- 0800 IP
- 0806 ARP
- 0835 RARP
- 8137 Novell IPX
- 809b Apple Talk
如果协议类型字段取值为0000-05dc(十进制的0-1500),则该帧就不是Ethernet V2(ARPA)类型了,而是下面讲到的三种802.3帧类型之一;Ethernet可以支持TCP/IP,Novell IPX/SPX,Apple Talk Phase I等协议;RFC 894定义了IP报文在Ethernet V2上的封装格式;
下面给一张图,就对这种帧格式一目了然了:
+-----+-----+------+-----+-------+------+------+-------+
|PR |SD |DA |SA |TYPE |DATA |PAD |FCS |
+-----+-----+------+-----+-------+------+------+-------+
|56b |8b |48b |48b |16b |<=1500|不够 | 32b |
| | | | | | |填充 | |
+-----+-----+------+-----+-------+------+------+-------+
在每种格式的以太网帧的开始处都有64比特(8字节)的前导字符,如图所示。其中,前7个字节称为前同步码(Preamble),内容是16进制数0xAA,最后1字节为帧起始标志符0xAB,它标识着以太网帧的开始。前导字符的作用是使接收节点进行同步并做好接收数据帧的准备。
-
PR:同步位,用于收发双方的时钟同步,同时也指明了传输的速率(10M和100M的时钟频率不一样,所以100M网卡可以兼容10M网卡),是56位的二进制数101010101010…..
-
SD: 分隔位,表示下面跟着的是真正的数据,而不是同步时钟,为8位的10101011,跟同步位不同的是最后2位是11而不是10.
-
DA:目的地址,以太网的地址为48位(6个字节)二进制地址,表明该帧传输给哪个网卡.如果为FFFFFFFFFFFF,则是广播地址,广播地址的数据可以被任何网卡接收到.
-
SA:源地址,48位,表明该帧的数据是哪个网卡发的,即发送端的网卡地址,同样是6个字节.
-
TYPE:类型字段,表明该帧的数据是什么类型的数据,不同的协议的类型字段不同。如:0800H 表示数据为IP包,0806H 表示数据为ARP包,814CH是SNMP包,8137H为IPX/SPX包,(小于0600H的值是用于IEEE802的,表示数据包的长度。)
-
DATA:数据段 ,该段数据不能超过1500字节。因为以太网规定整个传输包的最大长度不能超过1514字节。(14字节为DA,SA,TYPE)
-
PAD:填充位。由于以太网帧传输的数据包最小不能小于60字节, 除去(DA,SA,TYPE 14字节),还必须传输46字节的数据,当数据段的数据不足46字节时,后面补000000…..(当然也可以补其它值)
-
FCS:32位数据校验位.为32位的CRC校验,该校验由网卡自动计算,自动生成,自动校验,自动在数据段后面填入.对于数据的校验算法,我们无需了解.
事实上,PR,SD,PAD,FCS这几个数据段我们不用理它 ,它是由网卡自动产生的,我们要理的是DA,SA,TYPE,DATA四个段的内容.
所有数据位的传输由低位开始(但传输的位流是用曼彻斯特编码的)
以太网的冲突退避算法就不介绍了,它是由硬件自动执行的.
DA+SA+TYPE+DATA+PAD最小为60字节,最大为1514字节.
以太网卡可以接收三种地址的数据,一个是广播地位,一个是多播地址(我们用不上),一个是它自已的地址.但网卡也可以设置为接收任何数据包(用于网络分析和监控).
任何两个网卡的物理地址都是不一样的,是世界上唯一的,网卡地址由专门机构分配.不同厂家使用不同地址段,同一厂家的任何两个网卡的地址也是唯一的.根据网卡的地址段(网卡地址的前三个字节),可以知道网卡的生产厂家.有些网卡的地址也可以由用户去设定,但一般不需要.
3 Ethernet 802.3 raw帧格式
在Ethernet 802.3 raw类型以太网帧中,原来Ethernet II类型以太网帧中的类型字段被”总长度”字段所取代,它指明其后数据域的长度,其取值范围为:46-1500。
接下来的2个字节是固定不变的16进制数0xFFFF,它标识此帧为Novell以太类型数据帧。
这种格式的来源历史非常晦涩,这是1983年Novell发布其划时代的Netware/86网络套件时采用的私有以太网帧格式,该格式以当时尚未正式发布的802.3标准为基础;但是当两年以后IEEE正式发布802.3标准时情况发生了变化—IEEE在802.3帧头中又加入了802.2 LLC(Logical Link Control)头,这使得Novell的RAW 802.3格式跟正式的IEEE 802.3标准互不兼容;可以看到在Novell的RAW 802.3帧结构中并没有标志协议类型的字段,而只有Length 字段(2bytes,取值为0000-05dc,即十进制的0-1500),因为RAW 802.3帧只支持IPX/SPX一种协议;
4 Ethernet 802.3 SAP帧格式
这种帧格式属于 IEEE 802.3/802.2 LLC 标准。
在Ethernet 802.3 SAP帧中,将原Ethernet 802.3 raw帧中2个字节的0xFFFF变为各1个字节的DSAP和SSAP,同时增加了1个字节的”控制”字段,构成了802.2逻辑链路控制(LLC)的首部。LLC提供了无连接(LLC类型1)和面向连接(LLC类型2)的网络服务。LLC1是应用于以太网中,而LLC2应用在IBM SNA网络环境中。
新增的802.2 LLC首部包括两个服务访问点:源服务访问点(SSAP)和目标服务访问点(DSAP)。它们用于标识以太网帧所携带的上层数据类型,如16进制数0x06代表IP协议数据,16进制数0xE0代表Novell类型协议数据,16进制数0xF0代表IBM NetBIOS类型协议数据等。
常见SAP值:
-
0 Null LSAP
-
4 SNA Path Control
-
6 DOD IP
-
AA: SNAP
-
FE: ISO DIS
-
FF: Global DSAP
……
SAP值用以标志上层应用,但是每个SAP字段只有8bits长,而且其中仅保留了6比特用于标识上层协议,因此所能标识的协议数有限(不超过32种);并且IEEE拒绝为某些重要的协议比如ARP协议定义SAP值(奇怪的是同时他们却定义了IP的SAP值);因此802.3/802.2 LLC的使用有很大局限性;
至于1个字节的”控制”字段,则基本不使用(一般被设为0x03,指明采用无连接服务的802.2无编号数据格式)。
5 Ethernet 802.3 SNAP帧格式
Ethernet 802.3 SNAP类型以太网帧格式和Ethernet 802.3 SAP类型以太网帧格式的主要区别在于:
-
2个字节的DSAP和SSAP字段内容被固定下来,其值为16进制数0xAA。
-
1个字节的”控制”字段内容被固定下来,其值为16进制数0x03。
-
增加了SNAP字段,由下面两项组成
-
新增了3个字节的组织唯一标识符(Organizationally Unique Identifier,OUI ID)字段,其值通常等于MAC地址的前3字节
-
增加了表示上层协议的类型
-
这是IEEE为保证在802.2 LLC上支持更多的上层协议同时更好的支持IP协议而发布的标准,与802.3/802.2 LLC一样,802.3/802.2 SNAP也带有LLC头,但是扩展了LLC属性,新添加了一个2Bytes的协议类型域(同时将SAP的值置为AA),从而使其可以标识更多的上层协议类型;另外添加了一个3Bytes的OUI字段用于代表不同的组织,RFC 1042定义了IP报文在802.2网络中的封装方法和ARP协议在802.2 SANP中的实现;
一点资料
关于802.3 的标准,历史真是晦暗不明,看wiki都看不出个所以然来,我只能简单列举一下资料:
https://en.wikipedia.org/wiki/Ethernet_frame#Novell_raw_IEEE_802.3
http://lostintransit.se/2012/06/06/the-history-of-ethernet-dix-vs-802-3/
一点小tip
Q: MTU最大可以设置为多大?
A: 9000,这是由CRC校验的能力决定的。参考:
https://en.wikipedia.org/wiki/Jumbo_frame
PS:早期的一些网络,比如超通道,可以支持65535的mtu,但是已经湮没于历史风尘中了。
参考:
https://zh.wikipedia.org/wiki/IEEE_802.1ad
https://en.wikipedia.org/wiki/Ethernet_frame