F-RTO的基本思路是判断RTO是否正常,从而决定是否需要触发丢失恢复过程。方法是观察RTO之后的两个ACK。如果ACK不是重复ACK,并且确认的包不是重传的,会认为RTO是Spurious的。F-RTO可以只在TCP的发送端实现,不需要对端TCP协议栈的任何参与。
RTO后能否使用F-RTO:
sysctl 变量 sysctl_tcp_frto 激活F-RTO
F-RTO 只能在发生RTO之后,有新数据可以发送时。因此需要检查有新数据,并且可以发送 (处在发送窗口之内)
如果满足以上两个条件,初始化F-RTO。
如果连接正在丢包状态中恢复,减半snd_ssthresh,但不能小于2。
初始化跟踪F-RTO状态的相关变量:
重传包的计数器 retrans_out 复位为0.
做标记:将进入F-RTO时最新确认的字节序号(snd_una),保存于 undo_marker。
复位在“undo_marker标记”之后重传的计数器:undo_retrans。
所有在队列中没有确认的数据包,都标识为没有重传过。
设置拥塞避免状态ca_state为 TCP_CA_OPEN
做标记:将frto_highmark设置为,进入F-RTO后要发送的新segment的起始字节序号(发送窗口左边沿,snd_nxt)。
在RTO后,得到处理的ACK数量 frto_counter ,设为1
在进入F-RTO之后,使用接收到的ACK,按以下方法判断RTO合理与否:
进入F-RTO并且重传RTO的数据之后,接收到的ACK可能是:
重复ACK:接收到重复ACK说明包确实丢失了。
不是重复ACK,但确认了直到(或者其后) frto_highmark 的数据。这说明重传的数据很可能是填充了“空隙”,即其后数据包已经接收到了。也就是说,第一次发送的数据(被重传)确实是丢失了。
(以下两段原文似有笔误,我纠正过来了)
在认为RTO是 spurious的情况下,如果第一个ACK并没有指明重传确实是需要的,就再允许再发送两个未发送的数据包出去。注意,正常的恢复方法也会如此处理,因此即使之后到达的ACK指明确实是丢失了数据包,我们也能按正常的恢复方法继续处理。此时,frto_counter加一。在第二个ACK时,也作类似的检查。
如果确实丢失了数据,就说明发生了阻塞,进入拥塞避免状态。在处理完第二个ACK之后,frto_counter被复位为0,这意味着之后的ACK不再由F-RTO算法处理了
如果没有相应的SACK记录,就把 frto_highmark 之前数据包标记为丢失。
根据RTO之后接收后的ACK数量,设置拥塞窗口为2或者3:这与通常丢失恢复算法的行为符合。
ca_state设置为 TCP_CA_Loss。
原文地址:
维护:
翻译: raise.sail@gmail.com