一、介绍

FACK的全称是forward acknowledgement,FACK通过记录SACK块中系列号最大(forward-most)的SACK块来推测丢包信息,在linux中使用fackets_out这个状态变量来记录FACK信息。我们之前介绍SACK重传时候说过在SACK下需要3个dup ACK来触发快速重传(3个为默认值),而SACK下的dup ACK的定义与传统的非SACK下定义又略有不同(详细请参考前面的文章和示例)。当使能FACK的时候,实际上我们可以通过一个SACK块信息来推测丢包情况进而触发快速重传。比如server端依次发出P1(0-9)、P2(10-19)、P3(20-29)、P4(30-39)、P5(40-49),假设client端正常收到了P1包并回复了ACK确认包,P2、P3、P4则由于网络拥塞等原因丢失,client在收到P5时候回复一个Ack=10的确认包,并携带P5有SACK块信息(40-50),这样server在收到P1的确认包和P5的dup ACK时候,就可以根据dup ACK中的SACK信息得知client端收到了P1报文和P5报文,计算出P1和P5两个数据包中间间隔了3个数据包,达到了dup ACK门限(默认为3),进而推测出P2报文丢失。

SACK reneging我们在前面SACK中已经介绍了,下面我们通过示例来一起看一下FACK和SACK reneging下的重传。

二、wireshark示例

1、tcp_early_retrans=0,tcp_retrans_collapse=0,tcp_discard_on_port =9877,tcp_sack=1,tcp_fack=1;场景下的重传如下图所示:

  • server端依次发送No6-No10五个数据包

  • client收到No6后回复一个不带有SACK选项的ACK确认包(No11),server端正常接收到这个ACK确认包

  • 接着client模拟No7-No9数据包丢包,在收到No10乱序包的时候,回复一个dup ACK,其中包含SACK信息(33-41),

  • server端收到这个dup ACK后推测处client端已经收到No6和No10报文,中间间隔的报文个数为3个,达到dup ACK门限,进而触发快速重传。

  • client继续模拟丢包,接着server端RTO超时,进行指数回退过程。

  • 直到No16重传后,client开始回复不带有SACK选项的ACK(partial ACK),但是因为ack number并没有落在33-40之间,此时linux并不会确认发生了SACK reneging。这个ACK触发快速重传(No18)。受限与拥塞控制,这个时候只能发送一个重传包,发送完这个重传报文后根据收到的ACK更新拥塞窗口,拥塞窗口自增1,因此此时可以发送一个新的数据包,但是因为缓存中没有新的待发送数据因此并没有新数据包传出。

  • 接收client回复No19的ACK确认包(partial ACK),这个ACK报文虽然不带有SACK选项,但是linux同样不会确认发生了SACK reneging,server端根据这个partial ACK触发快速重传,在上一步中拥塞窗口已经自增了1,因此实际上快速重传可以重传两个TCP报文但是因为重传完No20后,只剩下一个报文待重传,而这个报文之前又被SACK过,因此快速重传不会重传这个报文

  • 接着client回复不带有SACK选项的No21确认包,Ack=33,注意之前触发FACK快速重传的时候反馈的SACK块信息是(33-41)告诉server端收到了No10数据包,而这个新回复的No21确认包又告诉server没有收到No10确认包。此时就是发生了SACK reneging。在这个ACK确认包触发快速重传时候,就会检测是否发生了SACK seneging,如果发生SACK reneging,linux会初始化一个RTO定时器,定时器的定时时间为RTT/2。快速重传时候检测到了SACK seneging就会直接退出。

  • 接着上一步的RTO定时器超时,触发了No22的RTO超时重传,client回复对应的ACK确认包,整个传输过程结束。

TCP系列18—重传—8、FACK及SACK reneging下的重传-LMLPHP

2、tcp_early_retrans=0,tcp_retrans_collapse=0,tcp_discard_on_port =9877,tcp_sack=1,tcp_fack=0;这里我们关闭FACK功能,其他设置不变重新进行类似上面的测试

可以看到这个示例与上面示例的主要差异就是No12的dup ACK虽然同样反馈了No10的SACK信息,但是并没有触发快速重传。其他内容与上面示例基本一致不再重复介绍。

TCP系列18—重传—8、FACK及SACK reneging下的重传-LMLPHP

3、tcp_early_retrans=0,tcp_retrans_collapse=0,tcp_discard_on_port =9877,tcp_sack=1,tcp_fack=1;低于dup ACK门限

这个示例和示例1不同的地方在于No12的dup ACK确认包携带的SACK信息为(25-33),也就是通过SACK确认了No9报文,No9与No6报文之间间隔了2个报文没有达到dup ACK的门限,因此并不会触发快速重传。注意server端在收到No19确认包时候触发了快速重传流程,但是快速重传前检测到SACK seneging,重启了RTO定时器并退出快速重传。

TCP系列18—重传—8、FACK及SACK reneging下的重传-LMLPHP

补充说明:

1、SACK seneging的检测和RTO定时器的设置参考linux内核tcp_check_sack_reneging函数

05-11 17:56