++++++++++转载请标明出处++++++++++++
RACK即recent ack,表示根据最新的(s)ack来做丢包判断,是google去年新提出的一个丢包检测算法,目前主要用于解决尾部丢包和二次重传的问题,但是它应该可以FACK,dupACK并驾齐驱,理解起来也比较直观。
以下分析是基于linux-4.5内核版本
基本思想
如果数据包p1在p2之前发送,没有收到p1的确认,当收到p2的SACK后,推断p1丢了。
算法
每一个skb记录发送时间xmit_time,传输控制块维护全局变量:rack.xmit_time,rack.reo_wnd。Rack.xmit_time是接收方已经收到的最新的那个skb的发送时间;rack.reo_wnd是乱序的时间窗口大小。
a. 每当收到一个ACK或者SACK的时候,更新rack.xmit_time.再去遍历发送队列上已经发送但还没有收到确认的skb,如果满足如下条件:
rack.xmit_time - skb.xmit_time > reo_wnd, 那么标记这个skb丢了。
b. 如果没有收到确认,那么就用定时器每个一段时间看看有哪些包丢了,如果满足如下条件:
currentTime > skb.xmit_time + min_rtt + rack.reo_wnd + 1ms, 那么把这个skb标记为已经丢了
注:目前linux内核中只实现了第一种判断方法,定时器还没有实现,这样的话就还没有解决对于尾部包丢失的问题。
实现
1. 数据结构
在tcp_sock中加入数据结构rack和rtt_min:
struct tcp_rack {
struct skb_mstamp mstamp; /* (Re)sent time of the skb 接收方已经收到的最新的那个skb的发送时间*/
u8 advanced; /* mstamp advanced since last lost marking 用于标记mstamp是否有更新*/
u8 reord; /* reordering detected 是否检测到乱序*/
} rack;
Rtt_min是一个数组,里面放了3个rtt_meas,用来记录最小的3个rtt测试量值,rtt_min[3]分别。rtt一开始初始化为~0U
struct rtt_meas {
u32 rtt, ts; /* RTT in usec and sampling time in jiffies. ts是设置这个rtt的时刻,即这个rtt_min[i]最近被更新的时间 */
} rtt_min[3];