前言
RFC6298讨论重传定时器相关的算法。因为首次涉足内核协议栈实现时,注释里总是提到各种RFC,因此需要过一遍。对于文中提到的MUST,或者SHOULD,将会用颜色标注;其它仅强调的语气(MAY)会加粗处理
背景介绍
RFC1122指出,RTO的计算方式应当遵循Jac88
[Jac88] Jacobson, V., “Congestion Avoidance and Control”, Computer Communication Review, vol. 18, no. 4, pp. 314-329, Aug. 1988.
而RFC6298要求发送端使用这些算法可以相对保守点,但是绝对不能更加激进
基本算法
求出RTO的算法需要维护两个变量:
SRTT
: smoothed RTTRTTVAR
: RTT variation
还有两个常量:
G
: clock granularity (<= 100 msec)K
: 4
初始阶段
在初始阶段,RTO的初值被设为1s。注意在RFC2988中提到RTO初值是3s,而在RFC6298中改为了1s,但是如果发生SYN丢失或者ACK of SYN丢失的话,将会回退到3s,直到开始传输数据
首次RTT计算
当首次测量到RTT数值(设为R
)的时候,必须使用如下算法:
SRTT = R
RTTVAR = R / 2
RTO = SRTT + max(G, K * RTTVAR)
后续RTT计算
当后续测量到RTT数值(设为R'
)的时候,必须使用如下算法:
RTTVAR = (1-β) * RTTVAR + β * (SRTT - R')
SRTT = (1-α) * SRTT + α * R'
RTO = SRTT + max(G, K * RTTVAR)
作者认为公式中列出的两个因子应当取\(\alpha = \frac{1}{8}, \beta = \frac{1}{4}\)
另外,如果RTO小于1s,那么应当上取整到1s
作者提到以前是用粗粒度时钟G
使得最小RTO值足够大来避免过度重传,事实上G
的取值没有硬性要求,只是文中给出了一个参考的数
RTT样本的选择
TCP必须使用Karn算法进行RTT采样:
- 采样对象:RTT不得根据已重传的数据段进行采样,除非使用了timestamp option
- 采样时机:当使用了timestamp时,可以每次ACK都进行RTT采样;而TCP实现必须在每一次RTT范围内进行至少一次RTT采样
我顺手贴一下以前上学时做的计网笔记,脑子不够用笔记来凑数
Karn算法的提出是基于这样的背景:
- 对于一个分组p,它曾被重传过,也就是说,对端(接收端B)能收到至少2份相同的分组(p1、p2……)
- 那么当原来的发送端A现在收到B发来的报文确认时,该如何判定是对哪一份的重复分组的确认(p1还是p2?)
- 这种歧义影响到了RTT的测量
而Karn算法的核心很简单:就是当发生报文重传时,不对它进行RTT采样(既不参与运算)
RTO定时器的维护
状态转移的感性认知还是比较简单的:
- 启动:含数据的包首次发出,就启动重传定时器,达到RTO时间后超时
- 重设:如果有ACK,重传定时器重新设为当前RTO
- 关闭:如果全部发出的数据都ACK,关闭定时器
- 更新:下次重传时更新
RTO = RTO * 2
,最大阈值可能是60s- 这种做法称为RTO backoff
- 当发生backoff时,前面维护的2个变量可能清零,此后的计算仍需区分首次和后续两个阶段
- 采样:如果有采样到RTT,用前面的计算方式覆盖当前RTO
- 这种情况只发生在发出新的数据包和ACK
安全性
作者好像说了什么,但好像也没说什么,总之当作没看到吧
完
文章太短,就不需要总结了