STT协议全称是Stateless Transport Tunneling Protocol,是nicira.com给ietf提交的一个隧道协议的draft
http://tools.ietf.org/html/draft-davie-stt-01
STT是一种mac over ip的协议,和vxlan, nvgre类似,都是把二层的帧封装在一个ip报文的payload中,在ip报文的payload中,除了虚拟网络的二层包以外,还要把构造的一个tcp头,和一个stt头加在最前面,可以参考上面文档第9页的图
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Version | Flags | L4 Offset | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Max. Segment Size | PCP |V| VLAN ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Context ID (64 bits) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Padding | data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
| |
Figure 3: STT Frame Format
上图是STT的头结构
Version 为0
Flags一共有8位,bit0表示csum已经被验证,bit1表示csum只是在tcp/ip为包头的情况下才会被计算,由于STT必然会利用TSO/LRO的特性来提高性能,所以这两位基本都是01。bit2表示IP协议版本,1表示ipv4,0表示ipv6,那么如果是arp呢?我个人认为应该是0,表示一种non-ip protocol,bit3表示L4版本,1表示TCP,0表示其他,说实话我觉得这两位没啥用。剩下bit4-bit7保留,全部设备0
L4 Offset 表示STT头+TCP头的长度
MSS,STT frame(即STT包头+payload)是要按照这个MSS的大小分段的,分段之后每个段会加上TCP包头,利用TSO机制交给网卡
PCP表示优先级,可以不设
V|VLAN是VLAN相关的设置,略过了
Context ID表示tenant ID,每个租户不同
STT依赖于TSO和LRO(GRO)的特性,所以STT协议很聪明的在STT头前面增加了TCP头,把自己伪装成一个TCP包,但和TCP协议不同的是,这只是一个伪装的TCP包,既没有3次握手的流程,也没有用到TCP那些拥塞控制,丢包重传,因此这个TCP头是精心构造出来的,目的是利用网卡的TSO/LRO功能,把分段/合并功能和TCP校检转移到网卡上去做
STT构造的TCP头和一般的TCP结构上没有区别,但填的数据不同
Source Port和Dst Port都是随机选的,注意Dst Port 的范围在1024 - 49151之间,Src Port的范围建议在49152 - 65535之间,对于tunnel两个固定的endpoint而言,两者之间的通信应该用固定的Source/Destination Port
SEQ/ACK 也不会用做窗口重传或者拥塞控制,而是用作一个STT frame的分段/合并,所以被分段的同一STT frame,其TCP头的ACK字段都是相同的,不同STT frame的ACK字段不同。SEQ的高16位,用于记录STT frame的长度(byte为单位),低16位用于记录当前STT frame 分段的偏移量(byte为单位)
其他的位基本没用,都可以置0,除了最后一个STT frame分段对ACK,PSH两个bit置位
这里抛出个问题,如果被分段的ip包在传输中间丢了几个段怎么办?STT endpoint是不会去要求重传的,实际上,STT endpoint只是利用了LRO来接收tcp payload,经过解包之后,得到虚拟网络的二层包交给vm处理,一定记住tunnel里是个不可靠通信信道,如果需要可靠通信需要vm的tcp stack去保证
还有一点,STT endpoint 需要给STT预留TCP port,所有发往这个port的tcp包会被认为是STT包,从而不会走正常的tcp stack路径