TCP重传机制 1

TCP重传机制是保障TCP传输正确的重要机制,也是在网络传输中容易发生错误的地方。因此对于Linux如何实现TCP重传,需要仔细来分析其代码实现与工作机制。

1 TCP重传分类

TCP重传可以分为两大类:超时重传(RTO)和快速重传(Fast Recovery),快速重传也可以分为两类:不启用sack的reno式重传和sack重传。因此我们可以将重传分为三类:1) Reno重传,2) Sack重传和3) RTO重传

本文主要介绍重传类型1,2.

2 TCP的函数调用流程

重传是发生在丢包的情况下,在进入重传前需要先判断接收到的ACK是否符合预期。在表面丢包的ACK(dup ACK)接收到时,TCP仍是按照其函数调用流程来工作。因此,首先来回顾一下TCP函数的整体调用关系,如下图所示:

图中没有体现出来拥塞控制算法的工作流程,这里简单说一下。

在tcp_ack( )中,会利用tcp_may_raise_cwnd( )来判断是否执行tcp_cong_avoid( )来增长窗口。

进入判断执行后,会利用register的tcp_cong_avoid函数来设置窗口增长。

在快要退出tcp_ack( )时,会执行tcp_update_pacing_rate( ),更新报文发送速率。

3 快速恢复

对于重传类型1,2,其会在tcp_ack( )函数中,调用tcp_fastretrans_alert( )来处理可疑的ack报文(包括dup ack),而是否进入fast recovery,需要tcp_fastretrans_alert( )调用time_tcp_time_to_recover( )来判断。

在原始的TCP协议栈中,分为以下6种情况来判断是否快速进入重传( recovery )阶段。

扫描二维码关注公众号,回复: 195923 查看本文章
  1. 确认为丢包的情况( tp->lost_out )
  2. Duplicate ACK的数量大于阀值( tcp_dupack_heuristics( tp ) > tp->reordering )
  3. 如果使用RFC2988,判断队列头部是否超时
  4. 如果以上条件不能满足,但是sacked_out比较多,同时还没有可以发送的报文
  5. 假如是thin stream, 那么只要有duplicate ack就重传(只针对sack)
  6. 基于RFC5827的early retransmission判断

修改后的协议栈做了新的安排,具体如下:

  1. 删除条件3的判定,原代码为
  2. 增加对early retransmission的判断条件,代码如下:


    增加的代码对packet_out大于阀值的情况进行处理:在推迟period_rtt时间后,判断是否进行early retransmission。

以上是在tcp_fastretrans_alert中进入recovery阶段的判断条件。

当判定满足后,执行tcp_enter_recovery( )函数, 其首先会初始化窗口减小( tcp_init_cwnd_reduction ), 然后设置tcp_ca_state ( open:0, disorder:1, cwr:2, recovery:3, loss:4) 为TCP_CA_Recovery。最后退出该函数,回到tcp_ack( )。

在tcp_ack( )中,会执行下一个函数tcp_xmit_recovery( ), 该函数调用tcp_xmit_retransmit_queue( ) 来重传丢失的报文。

搜索到丢失的报文保存在sk_buff skb里,如果需重传的skb是tcp_send_head,那么直接在tcp_write_xmit( )函数就发送报文;假如不在,那么调用tcp_retransmit_skb( ) -> __tcp_retransmit_skb( ) -> tcp_transmit_skb( ) 来发送重传的报文。

以上就是如何进入快速恢复并重传丢包的过程,涉及到重传类型1,2。将以上内容总结,可以得到如下的函数调用关系:

通过代码比较,在进入fast recovery的处理上,sack和reno ack没有太大的区别,除了在识别出thin stream后,sack能更快的执行恢复。下面补充几点工作机制:

1 除了重传报文,TCP还需要重新设置窗口值。执行完tcp_fastretrans_alert( ), 会执行tcp_cong_control,其会根据tcp_ca_state来执行tcp_cwnd_reduction( ),减小发送窗口(本段基于kernel4.0以上的流程,适用于BBR的分析)。

  1. 除了重传报文,TCP还需要重新设置窗口值。在执行tcp_fastretrans_alert( )前,tcp会先执行tcp_cong_avoid( )来设置窗口,假如进入重传,会执行tcp_init_cwnd_reduction( ),减小ssthresh。
  2. 在进入fast recovery后,发送窗口的设置是依据函数tcp_cwnd_reduction( )来计算,其会按照接受的dup ack和减小后的ssthresh来设置窗口大小。
  3. 退出快速恢复,还是在tcp_fastretrans_alert( )中进行判断退出,并执行tcp_end_cwnd_reduction( ),设置tcp_ca_event(传递给拥塞控制接口)为CA_EVENT_COMPLETE_CWR

猜你喜欢

转载自blog.csdn.net/eipi1/article/details/80237693