TCP快速恢復演算法PRR

2021-10-06 07:56:31 字數 3473 閱讀 6253

prr演算法(proportional rate reduction)決定在丟包恢復(loss recovery)期間,對應於每個ack報文,可傳送的報文數量。目的是:1)快速平穩的從loss中恢復;2)恢復之後擁塞視窗收斂與ssthresh。主要是為了解決linux核心之前採用的恢復演算法rate-halving存在的一些弊端:

prr由兩個部分組成。一是當網路中報文數量(pipe)大於ssthresh時,通常是丟失較少報文時的恢復開始階段的情況,根據ack報文的到達成比例的降低擁塞視窗。例如對於cubic演算法,此部分通過每接收到10個ack確認報文(10報文被對端所接收),傳送7個報文的方式,將擁塞視窗降低30%(等於cubic設定的ssthresh值)。

第二個部分是,如果網路中報文數量(pipe)小於ssthresh,通常是丟失多個報文或者應用程式在恢復階段沒有資料可傳送的情況,阻止擁塞視窗的降低。rfc6937中定義了兩種reduction bound演算法:conservative reduction bound (crb)和slow start reduction bound (ssrb),前者嚴格遵守報文守恆機制;而後者類似slowstart,比crb更具侵略性,對於每個接收到的ack報文,ssrb允許額外多傳送乙個資料報文。

在進入tcp_ca_recovery或者tcp_ca_cwr擁塞狀態時,呼叫函式tcp_init_cwnd_reduction初始化prr相關引數。prr_delivered記錄在進入recovery/cwr狀態後接收端收到的報文數量,而變數prr_out用於統計進入recovery之後,傳送的報文數量。

snd_ssthresh為擁塞演算法(預設cubic,參見函式bictcp_recalc_ssthresh)計算的ssthresh值,最終,擁塞視窗將收斂與此值。

static void tcp_init_cwnd_reduction(struct sock *sk)

核心中使用進入recovery時的擁塞視窗prior_cwnd表示演算法中的recoverfs的值,變數dividend首先增加了prior_cwnd-1的值,在除去prior_cwnd,達到了演算法中ceil的效果。此階段需要等比例的減小擁塞視窗,比例為:snd_ssthresh/prior_cwnd。

void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked, int flag)

else if ((flag & (flag_retrans_data_acked | flag_lost_retrans)) ==

flag_retrans_data_acked) else

/* force a fast retransmit upon entering fast recovery */

/* 在進入快速恢復階段時,強制傳送至少乙個報文(此時prr_out為零)。 */

sndcnt = max(sndcnt, (tp->prr_out ? 0 : 1));

tp->snd_cwnd = tcp_packets_in_flight(tp) + sndcnt;

如果當前ack報文確認了之前重傳的資料,並且沒有進一步標記新的重傳資料的丟失,使用prr演算法的第二部分計算傳送數量。

rfc6937中定義的prr演算法的第二部分如下(else部分,linux使用prr-ssrb部分)。如果由於應用程式缺少報文傳送將導致prr_delivered的值大於prr_out的值,核心取其與新確認報文數量newly_acked_sacked值,兩者之間的最大值,另外再加上1(mss),最後,取以上結果和delta之間的較小值。此階段增加擁塞視窗,趨近於ssthresh。

相比於prr-crb,ssrb的加1操作,並非嚴格遵守報文守恆原則,

if (pipe > ssthresh)  else  else 

// attempt to catch up, as permitted by limit

sndcnt = min(ssthresh - pipe, limit)

}

最後,如果當前ack報文沒有確認重傳資料,確認的為正常資料,或者確認了新的重傳資料的丟失,傳送數量設定類似於prr-crb,不同點在於核心使用delta與newly_acked_sacked之間的最小值。而prr-crb使用的是delta與prr_delivered - tp->prr_out的差值之間的最小值。此種情況下,報文傳送數量不像prr-ssrb激進,原因是一方面丟失報文較少;或者另一方面,丟失報文較多,網路擁塞嚴重。

sndcnt = min(delta, newly_acked_sacked);
以上函式tcp_cwnd_reduction在tcp_ack處理完成ack報文之後,在函式tcp_cong_control中呼叫。注意bbr擁塞演算法(實現了自身的cong_control控制)不使用prr。

static void tcp_cong_control(struct sock *sk, u32 ack, u32 acked_sacked,

int flag, const struct rate_sample *rs)

if (tcp_in_cwnd_reduction(sk))

如下tcp報文傳送函式tcp_write_xmit,如果套介面處於cwr/recovery擁塞狀態,增加prr_out的值。

static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,

int push_one, gfp_t gfp)

{ ...

if (likely(sent_pkts)) {

if (tcp_in_cwnd_reduction(sk))

tp->prr_out += sent_pkts;

如下tcp報文重傳函式tcp_xmit_retransmit_queue,如果套介面處於cwr/recovery擁塞狀態,增加prr_out的值。

void tcp_xmit_retransmit_queue(struct sock *sk)

{ ...

rtx_head = tcp_rtx_queue_head(sk);

skb = tp->retransmit_skb_hint ?: rtx_head;

max_segs = tcp_tso_segs(sk, tcp_current_mss(sk));

skb_rbtree_walk_from(skb) {

if (tcp_retransmit_skb(sk, skb, segs))

return;

net_add_stats(sock_net(sk), mib_idx, tcp_skb_pcount(skb));

if (tcp_in_cwnd_reduction(sk))

tp->prr_out += tcp_skb_pcount(skb);

核心版本 5.0

快速重傳與快速恢復演算法

擁塞避免演算法的修改建議1 9 9 0年提出 jacobson 1990b 在介紹修改之前,我們認識到在收到乙個失序的報文段時,tcp立即需要產生乙個ack 乙個重複的ack 這個重複的ack不應該被遲延。該重複的ack的目的在於讓對方知道收到乙個失序的報文段,並告訴對方自己希望收到的序號。由於我們...

相位恢復演算法(Phase Retrieval)

相位恢復演算法的分類 1 光學測量 就測量方法而言,可以建立乙個光學系統來實現它,如建立乙個hilbert變換系統,或建立乙個gerchberg saxton反饋迴路等。也可以避開數字演算法的思想,直接設計乙個試驗系統來測量相位因子,如利用高階光學相關,或者利用四波混頻技術產生乙個映象光場等,2 數...

TCP快速恢復

tcp快速恢復演算法在接收到3個 重複 ack後會產生會執行 演算法流程如下 收到第3個重複的ack時,將ssthresh設定為當前cwnd的一半。設定cwnd ssthresh 3 重傳丟失的報文段 每收到乙個重複的ack,cwnd 1 確認新資料的ack到達時,設定cwnd ssthresh。思...