CUBIC擁塞擁塞控制算法

背景和意義

隨着Internet的發展,網絡中出現了愈來愈多的高速和長距離鏈路,這些鏈路的特色是時延帶寬積(BDP=bandwith*RTT)很大,也就是說,這些鏈路所能容納的總數據量很大。linux

傳統TCP協議,例如TCP-Reno、TCP-NewReno、TCP-SACK中,每過一個RTT(Round Trip Times),窗口增長一個單位,這使得TCP的數據傳輸速度緩慢,遠不能充分利用網絡帶寬。當碰上高帶寬環境時,可能須要經歷不少個RTT,擁塞窗口才能接近於一個BDP。若是數據流很短,可能擁塞窗口還沒增加到一個BDP,數據流就已經結束了,這種狀況的帶寬利用率就會很是低。c++

假設網絡帶寬是10Gbps,RTT是100ms,數據包是固定的1250字節,則此網絡所能容納的數據包總量是:\(\dfrac{10\times 10^9\times 0.1}{1250\times 8}=10^5\)個數據包。假設窗口從50000開始增加,也須要50000個RTT(1.4個小時)才能達到網路的滿負荷,若是一個TCP流在此以前結束(顯然每每如此),則未充分利用帶寬。算法

BIC-TCP

BIC-TCP採用二分搜索的方式來決定擁塞窗口的增加尺度,首先它會記錄擁塞窗口的一個最大值點,這個最大值就是TCP最近一次出現丟包時擁塞窗口的值;還會記錄一個最小值點,即在一個RTT週期內沒有出現丟包事件時窗口的大小。二分搜索就是取最小值和最大值的中間點,當擁塞窗口增加到這個中間值且沒有出現丟包的話,就說明網絡還能夠容納更多的數據包。那麼將這個中值設爲新的最小值,在新的最小值和最大值間搜索中間值。當前擁塞窗口的值還遠沒有達到通道的容量時,其增加速度很快;相反,當擁塞窗口的值接近於通道的容量時,其擁塞窗口增加函數是一個簡化的對數凸函數。這個凸函數使擁塞窗口在飽和點或平衡點比凹函數或線性函數保持更長的時間,在飽和點處,凸函數和線性函數具備最大的窗口增量,所以在丟包發生時會出現大量的數據包被丟失。網絡

image-20200702113942824

BIC-TCP的主要特徵是在前面說過的其獨特的窗口增加函數,圖1給出了BIC-TCP的窗口增加函數。當出現丟包事件時,BIC-TCP經過乘以因子 \(\beta\) 來縮小窗口,縮小以前的窗口大小被設置爲最大值\(W_{\max}\) ,而且縮小以後的窗口大小被設置爲最小值\(W_{\min}\) 。 而後,BIC-TCP使用這兩個參數執行二分搜索,擁塞窗口的下一個取值會是\(W_{\max}\)\(W_{\min}\) 之間的「中點」 \(W_{mid}\)app

爲了防止擁塞窗口從\(W_{\min}\) 增加到 \(W_{\max}\) 的步長step太大,BIC-TCP還設置了一個常數\(S_{\max}\) ,當step>\(S_{\max}\) 時,BIC-TCP會取下一個增加點爲 \(W_{\min}\)+\(S_{\max}\) 而不是 \(W_{mid}\) (加法增長階段),若是沒有出現丟包的話,再更新\(W_{\min}\) ,直到step< \(S_{\max}\) 爲止。與此同時BIC-TCP還設置一個另外一個控制參數\(S_{\min}\) ,當窗口增量小於 \(S_{\min}\) 時,BIC-TCP會將當前擁塞窗口值設爲最大值。異步

若是窗口增加超過最大值,則說明當前窗口最大值還不是一個飽和點,網絡還能夠容納更多的數據包,窗口還有增加的空間,一個新的窗口最大值須要被探索。因而BIC-TCP會進入一個新的階段,叫作最大值探索階段。最大探測使用一個與在加法增加和二分搜索階段徹底對稱的窗口增加函數。圖1中給出了在最大探索階段期間的窗口增加函數。在最大探測期間,窗口最初緩慢地增加以發現附近新的最大值,通過一段時間的緩慢增加,若是沒有找到新的最大值(即沒出現包丟失),則它猜想新的最大值離得很遠,因此它給窗口大小增長一個大的固定增量,使用加法增長切換到更快的增長速度。BIC-TCP的良好性能來自 \(W_{\max}\) 附近的緩慢增長以及在加法增長和最大探測期間的線性增長。tcp

BIC-TCP在高速網絡中具備良好的可擴展性、多個流競爭的公平性和低窗口振盪的穩定性。然而,BIC-TCP的增加功能對於TCP來講仍然過於激進,特別是在短RTT或低速網絡下。此外,窗口控制的幾個不一樣階段(二進制搜索增長、最大探測、\(S_{\max}\)\(S_{\min}\) )增長了協議實現和性能分析的複雜性。ide

算法與推導

算法簡述

CUBIC是BIC-TCP的下一代版本。 它經過用三次函數(包含凹和凸部分)代替BIC-TCP的凹凸窗口生長部分,大大簡化了BIC-TCP的窗口調整算法, 該函數在保留BIC-TCP的優勢(特別是其穩定性和可擴展性)的同時,簡化了窗口控制,加強了其TCP友好性。實際上,任何奇數階多項式函數都具備這種形狀。三次函數的選擇是偶然的,可是也是出於方便。CUBIC的關鍵特徵是其窗口增加僅取決於兩個連續擁塞事件之間的時間。一個擁塞事件是指出現TCP快速恢復的時間。所以,窗口增加與RTT無關。 這個特性容許CUBIC流在同一個瓶頸中競爭,有相同的窗口大小,而不依賴於它們的RTT,從而得到良好的RTT公平性。並且,當RTT較短時,因爲窗口增加率是固定的,其增加速度可能比TCP標準慢。 因爲TCP標準(例如,TCP-SACK)在短RTT下工做良好,所以該特徵加強了協議的TCP友好性。函數

CUBIC窗口增加函數

image-20200702115622954

CUBIC的窗口增加函數是一個三次函數,很是相似於BIC-TCP的窗口增加函數,CUBIC的函數圖像如圖2所示。CUBIC的詳細運行過程以下,當出現丟包事件時,CUBIC同BIC-TCP同樣,會記錄這時的擁塞窗口大小做爲\(W_{\max}\),接着經過常數因子\(\beta\) 執行擁塞窗口的乘法減少,這裏 \(\beta\) 是一個窗口下降常數,並進行正常的TCP快速恢復和重傳。從快速恢復階段進入擁塞避免後,使用三次函數的凸函數增長窗口。三次函數設置在 \(W_{\max}\) 處達到穩定點,若是存在新的最大窗口(網絡帶寬發生變化), 而後使用三次函數的凹函數開始探索新的最大窗口。源碼分析

CUBIC的窗口增加函數公式以下所示:

image-20200702120040814

\(C\)是一個CUBIC的參數, \(t\)是從窗口上次下降開始到如今的時間,是一個彈性值,而 \(K\) 是上述函數在沒有進一步丟包的狀況下將當前的擁塞窗口 \(W\) 增長到 \(W_{\max}\) 經歷的時間。

\(K\)計算公式以下:

image-20200702120636183

在擁塞避免階段每收到一個ACK,CUBIC都會使用方程(1)計算在下個RTT的窗口增加速率。CUBIC使用$W\left( t+RTT \right) $做爲擁塞窗口的候選值,假設當前擁塞窗口大小爲 \(cwnd\)。根據 \(cwnd\)的值,CUBIC有三種運行模式。在linux內核實現中,\(K\)值立方根求取使用得是牛頓迭代法,這是由於牛頓迭代法的性能優於二分法。

若是\(cwnd\) 小於(標準)TCP在上次丟包事件以後 \(t\) 時刻到達的窗口大小,那麼CUBIC處於TCP模式(咱們將在下面描述如何根據時間肯定標準TCP的窗口大小)。

若是\(cwnd\) 小於\(W_{\max}\) ,那麼CUBIC在三次函數的凸函數區域。

若是\(cwnd\) 大於\(W_{\max}\) ,那麼CUBIC處於三次函數的凹區域。

TCP友好型區域

標準TCP協議在網絡時延帶寬積小或者RTT小的狀況下表現仍不錯,CUBIC被設計爲在這兩種狀況下能夠很好的兼容標準TCP協議。算法執行過程當中,每收到一個ACK後都會判斷當前是否處於標準TCP階段,即TCP友好域,以此來更好的兼容TCP。所以須要經過TCP的AIMD(加法增、乘法減)特性並使用加法因子 $\alpha $ 和乘法因子 \(\beta\) 去估算在TCP傳統擁塞算法下的擁塞窗口大小。

image-20200702121524418

\(W_{\max}\left( 1-\beta \right)\)是當發生擁塞事件時減小後的初始 \(cwnd\)\(3\frac{\beta}{2-\beta}\)爲線性增加的大小(斜率), \(\frac{t}{RTT}\)爲從發生擁塞窗口到至今須要經歷RTT的個數。若是當前的 \(cwnd\) 小於\(W_{tcp\left( t \right)}\) ,則處於TCP模式,所以每次接受ACK時,都會將 \(cwnd\)設置爲\(W_{tcp\left( t \right)}\)

凸區域

當在擁塞避免階段收到一個ACK,若是協議不處於TCP模式,且\(cwnd\)小於\(W_{\max}\),那麼協議就處於凸區域,在這個區域,\(cwnd\) 的增量爲:

凹區域

當前的\(cwnd\) 大於\(W_{\max}\) 時,協議就會進入凹區域。因爲 \(cwnd\)大於先前的飽和點\(W_{\max}\) ,這代表自上次擁塞事件以來,網絡條件可能受到干擾,這可能意味着在一些競爭流離開後,可用帶寬會增長。因爲網絡是高度異步的,可用帶寬的波動老是存在的。凹區域使得窗口在開始時增加很是緩慢,並逐漸增長其增加率。因爲CUBIC正在搜索一個新的\(W_{\max}\) ,咱們也將此階段稱爲最大探測階段。因爲沒有修改凹區域的窗口增加函數,所以兩個區域的窗口增加函數保持不變。所以 \(cwnd\)的增量一樣爲:

乘法下降

當出現數據包丟失時,CUBIC會經過乘法因子 $\beta $ 來下降擁塞窗口,這裏取\(\beta =0.2\) 。雖然自適應性的設置 $\beta $ 會致使更快的收斂,可是會使協議的分析變得更加困難,並影響協議的穩定性。

快速收斂機制

新的流量加入網絡時,網絡中的現有流量須要放棄其部分帶寬份額,以使新流量有必定的增加空間。在發生丟包前,CUBIC會記錄一個最大窗口值\(W_{\max}\) 。當發生丟包後,在下降窗口前,CUBIC又會記錄當前的窗口值做爲新的\(W_{\max}\) ,爲了避免至於混淆,能夠將以前記錄的\(W_{\max}\) 記爲\(W_{last\_max}\)。當發生丟包時,CUBIC會比較$ W_{last_max}$ 和\(W_{\max}\) 的大小,若是\(W_{\max}\) 小於$ W_{last_max}$ ,這代表因爲可用帶寬的變化,該流的窗口飽和點正在下降。這種狀況下,CUBIC的作法是經過進一步的減少\(W_{\max}\) 來釋放更多的可用帶寬,使得新加入的流量有必定的增加空間。

僞碼示例

image-20200702150009714

對所須要的參數進行初始化,其中tcp_friendliness決定TCP友好型區域是否開啓,默認爲開啓狀態;fast_convergence決定快速收斂機制是否開啓,默認爲開啓狀態;其他的參數值須要放入cubic_reset()函數中,由於這些參數在每次發生擁塞時間後,都須要進行重置。其中 \(W_{last\_max}\) 爲上一次發生擁塞窗口時所記錄的窗口值;epoch_start會記錄每次發生擁塞的時間;origin_point則記錄\(W_{last\_max}\) 和當前的 \(cwnd\) 之間的最大值;dMin記錄最小的RTT(往返傳輸時間); \(W_{tcp}\)爲TCP模式時的計算得出的窗口值; \(K\)是在沒有進一步丟包的狀況下將當前的擁塞窗口 \(W\)增長到\(W_{\max}\) 經歷的時間;ack_cnt 記錄接收到ACK的數量。

image-20200702151640761

每當接受到一個ACK時,dMin會去記錄自身與當前RTT的最小值,保證dMin記錄着最小的RTT,這樣作的緣由是因爲網絡的不肯定性因素,致使每一個ACK對應的RTT可能也會有增長,所以須要找到最接近實際的RTTssthresh判斷當前狀態爲慢啓動仍是擁塞避免階段的閾值,若是當前的cwnd小於或等於ssthresh,那麼進入慢啓動階段,每接收到一個ACK,cwnd相應自加一,直到cwnd大於ssthresh,則須要進入擁塞避免階段,cubic_update()函數會計算得出一個cnt值,與cwnd_cnt進行比較,以此判斷cwnd是否須要增加。

image-20200702151759627

當包丟失(擁塞事件)時,經過快速恢復階段,接下來就會從新進入擁塞避免。所以epoch_start須要置爲0。若是發生擁塞事件時的cwnd小於上一次發生擁塞事件的\(W_{last\_max}\) ,而且快速收斂機制爲開啓狀態,即意味着是因爲新流的加入,致使cwnd小於\(W_{last\_max}\) ,所以須要將當前的cwnd須要讓出一部分帶寬給新流;不然就是因爲網絡的波動(帶寬減小或增長)致使cwnd小於或大於\(W_{last\_max}\) ,那麼只須要將當前的cwnd記錄到\(W_{last\_max}\) 便可。當cwndssthresh進行乘法減小後,從新開始擁塞避免階段(即凸函數區域)

image-20200702152312413

Cubic_update()函數爲核心算法的實現。當epoch_start爲零時,意味着從新進入擁塞避免後階段,若是cwnd小於\(W_{last\_max}\),須要計算cwnd到達\(W_{last\_max}\) 的時間K;反之若是cwnd大於\(W_{last\_max}\) ,意味着網絡的帶寬增長了,須要進行窗口最大值探索(凹函數區域)。時間\(t\)記錄的是以擁塞避免階段爲起點時間到當前的時間之差,然後與dMin之和,於是去計算出下一個dMin所須要到達的目標窗口值target。若是target大於當前窗口值cwnd,須要增長窗口的增加率;反之,意味着當前窗口值已經到達平穩期,須要去下降窗口的增加率。

image-20200702171632218

同時,也須要計算若是是在傳統的TCP擁塞控制算法下的窗口值\(W_{tcp}\) ,而後\(W_{tcp}\) 與在CUBIC擁塞控制算法下的cwnd進行比較,以此判斷是否進入tcp友好型區域。這樣經過與TCP傳統擁塞控制算法的組合,可以獲得更高的網絡質量。

整體流程

FireShot Capture 076 - CUBIC小結 - 百度文庫 - wenku.baidu.com

原理推導

CUBIC窗口增加函數的推導

從做者的角度來看,是如何從經過改進BIC算法獲得CUBIC算法,最主要的仍是窗口增加函數的變化。

image-20200702172045501

從上圖,能夠看出該函數的斜率是從高到低,然後又慢慢增大。所以,能夠直觀假設其導數爲二次曲線函數,以\(g\left( x \right) =3x^2-2x\)爲例,它的圖像以下圖所示。

image-20200702172141008

由此,能夠獲得它的原函數爲\(f\left( x \right) =x^3-x^2+1\) ,即它的圖像爲

image-20200702172208227

以上僅僅是個例子,目的在於肯定CUBIC的曲線形狀,上面的圖像和BIC的窗口探測曲線很像,在肯定了曲線的形狀以後,最終要肯定曲線的參數,而曲線的通用方程應該是:

\[f\left( x \right) =ax^3+bx^2+cx+d \]

對於參數的肯定,須要聯繫CUBIC擁塞控制算法的過程,\(W_{\min}\)實際上就是上次擁塞事件發生後最大窗口( \(W_{\max}\) 記錄着擁塞事件發生時所測量出的對應的最大窗口值,即爲已知)乘法減小後的值,所以 \(W_{\min}=W_{\max}\times beta\),再者因爲函數的對稱特性,可以計算得出最高點值爲$W_{\max}+W_{\max}\left( 1-beta \right) $ 。

image-20200702172408563

所以,能夠得出如下的圖像,因爲這個函數增加圖像對應着一次擁塞避免狀態的從新開始,所以P1點處的時間爲零,而由P1到P0的時間假設爲r已知,根據對稱的特性,於是P2處的時間也爲2r。

image-20200702172505644

因爲曲線自己是關於P0(x=r, y=\(W_{\max}\) )這個點對稱的,所以能夠肯定曲線方程的常數因子爲\(W_{\max}\) ,因此可以將曲線方程寫成以下的形式:

\[f\left( x \right) =h\left( x \right) +W_{\max}\ \ \ \ \ \ \left( 0 \right) \]

如今的目標就是求h(x),再因爲P1和P2點已知:

\[f\left( 0 \right) =\beta W_{\max}\ \ \ \ \left( 1 \right) \]

\[f\left( 2r \right) =2W_{\max}-\beta W_{\max}\ \ \ \ \ \left( 2 \right) \]

\[f\left( r \right) =W_{\max}\ \ \ \ \ \left( 3 \right) \]

由0、一、3式可得:

\[h\left( r \right) =0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \left( 4 \right) \]

\[h\left( 0 \right) =\left( \beta -1 \right) W_{\max}\ \ \ \ \ \ \ \left( 5 \right) \ \ \]

根據4式以及f(x) ,即h(x)爲三次函數的特性,能夠假設:

\[h\left( x \right) =C\left( x-K \right) ^3\ \ \ \ \ \ \left( 6 \right) \]

其中C爲一常量,所以咱們須要將5式代入6式中,可得:

\[K=\sqrt[3]{\frac{\left( 1-\beta \right) W_{\max}}{C}}\ \ \ \ \ \ \ \left( 7 \right) \]

綜上可得:

\[f\left( x \right) =h\left( x \right) +W_{\max}=C\left( x-K \right) ^3+W_{\max}=C\left( x-\sqrt[3]{\frac{\left( 1-\beta \right) W_{\max}}{C}} \right) ^3+W_{\max} \]

TCP友好型區域\(W_{\max}\)窗口值公式的推導

image-20200702173047237

上圖爲在TCP傳統擁塞控制算法(New-Reno)下,窗口值隨時間的變化過程,其中W對應着發生擁塞事件時的窗口值(最大窗口值),因爲上圖具備週期性,所以只需對第一個週期的圖像進行分析便可,在發生擁塞事件後,須要對\(W\)進行乘法減小,即\(\left( 1-b \right) W\)(起點),然後經過TCP的累計確認機制以固定的速率a去進行窗口值的增加,直到到達W。

顯然,經過等差數列公式,能夠得出:

\[\left( 1-b \right) W+na=W\ \ \ \ \ \ \ \left( 1 \right) \]

\[n=\frac{bW}{a}\ \ \ \ \ \ \ \ \ \ \ \ \ \left( 2 \right) \]

又該等差數列應該從零開始,因此

\[n=\frac{bW}{a}+1\ \ \ \ \ \ \ \ \left( 3 \right) \]

\(\left( 1-b \right) W\)須要n次RTT才能到達\(W\) ,所以在這一個週期內的平均窗口值\(S\),應該拿窗口值總和,除以迭代增加的次數\(n\)

\[S=\frac{n\left[ \left( 1-b \right) W+W \right]}{2n}=\frac{2-b}{2}W\ \ \ \ \ \ \ \left( 4 \right) \]

假設RTT爲R時間(second),所以每秒的發包速率爲:

\[T=\frac{2-b}{2R}W\ \ \ \ \ \ \ \ \ \left( 5 \right) \]

假設在這個一個週期內,發送窗口的總和爲P,則

\[P=nS=\left( \frac{b}{a}W+1 \right) \left( \frac{2-b}{2}W \right) \approx \frac{b\left( 2-b \right)}{2a}W^2\ \ \ \ \left( 6 \right) \]

所以丟包率(丟一個包時)p爲

\[p=\frac{1}{P}=\frac{2a}{b\left( 2-b \right) W^2+a\left( 2-b \right) W}\approx \frac{2a}{b\left( 2-b \right) W^2}\ \ \ \ \left( 7 \right) \]

由此可得

\[W\approx \sqrt{\frac{2a}{b\left( 2-b \right) p}}\ \ \ \ \ \ \ \ \ \left( 8 \right) \]

而後,再將8式代入5式獲得每秒的平均發包速率爲

\[\hat{T}=\frac{1}{R}\sqrt{\frac{a\left( 2-b \right)}{2bp}}\,\,\,\,\,\,\,\,\,\,\,\,\,\,\text{符號替換} \]

\[\hat{T}=\frac{1}{R}\sqrt{\frac{\alpha \left( 2-\beta \right)}{2\beta p}}\,\,\,\,\,\,\,\,\,\,\,\,\ \ \,\,\,\,\left( 9 \right) \ \]

又在TCP傳統得擁塞控制算法中,\(\alpha =1\) \(\beta =0.5\)\(\hat{T}=\frac{1}{R}\sqrt{\frac{3}{2}\frac{1}{p}}\) 。所以在CUBIC算法中保持這種關係,只有當\(\alpha =\frac{3\beta}{2-\beta}\) 時知足,且\(\alpha\) 爲TCP擁塞控制算法窗口增長的加法因子,因此在CUBIC中計算 \(W_{tcp}\)的公式爲:

\[W_{tcp}=W_{\max}\left( 1-\beta \right) +\alpha \frac{t}{R}=W_{\max}\left( 1-\beta \right) +3\frac{\beta}{2-\beta}\frac{t}{R} \]

源碼分析

/*
 * Compute congestion window to use.
 */  //從快速恢復退出並進入擁塞避免狀態以後,更新cnt
static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
{
    u64 offs;//時間差|t - K|
    //delta是cwnd差,bic_target是預測值,t爲預測時間
    u32 delta, t, bic_target, max_cnt;

    ca->ack_cnt++;    /*ack包計數器加1   count the number of ACKs */

    if (ca->last_cwnd == cwnd && //當前窗口與歷史窗口相同
        (s32)(tcp_time_stamp - ca->last_time) <= HZ / 32)//時間差小於1000/32ms
        return; //直接結束

    ca->last_cwnd = cwnd;//記錄進入擁塞避免時的窗口值
    ca->last_time = tcp_time_stamp;//記錄進入擁塞避免時的時刻

    if (ca->epoch_start == 0) {//丟包後,開啓一個新的時段
        ca->epoch_start = tcp_time_stamp;    /*新時段的開始 record the beginning of an epoch */
        ca->ack_cnt = 1;            /*ack包計數器初始化  start counting */
        ca->tcp_cwnd = cwnd;            /*同步更新 syn with cubic */

        //取max(last_max_cwnd , cwnd)做爲當前Wmax飽和點
        if (ca->last_max_cwnd <= cwnd) {
            ca->bic_K = 0;
            ca->bic_origin_point = cwnd;
        } else {
            /* Compute new K based on
             * (wmax-cwnd) * (srtt>>3 / HZ) / c * 2^(3*bictcp_HZ)
             */
            ca->bic_K = cubic_root(cube_factor
                           * (ca->last_max_cwnd - cwnd));
            ca->bic_origin_point = ca->last_max_cwnd;
        }
    }

    /* cubic function - calc*/
    /* calculate c * time^3 / rtt,
     *  while considering overflow in calculation of time^3
     * (so time^3 is done by using 64 bit)
     * and without the support of division of 64bit numbers
     * (so all divisions are done by using 32 bit)
     *  also NOTE the unit of those veriables
     *      time  = (t - K) / 2^bictcp_HZ
     *      c = bic_scale >> 10 == 0.04
     * rtt  = (srtt >> 3) / HZ
     * !!! The following code does not have overflow problems,
     * if the cwnd < 1 million packets !!!
     */

    /* change the unit from HZ to bictcp_HZ */
    t = ((tcp_time_stamp + (ca->delay_min>>3) - ca->epoch_start)
         << BICTCP_HZ) / HZ;

     //求| t - bic_K |
    if (t < ca->bic_K)        // 還未達到Wmax
        offs = ca->bic_K - t;
    else
        offs = t - ca->bic_K;//已經超過Wmax

    /* c/rtt * (t-K)^3 */     //計算立方,delta =| W(t) - W(bic_K) |
    delta = (cube_rtt_scale * offs * offs * offs) >> (10+3*BICTCP_HZ);



     //t爲預測時間,bic_K爲新Wmax所對應的時間,
     //bic_target爲cwnd預測值,bic_origin_point爲當前Wmax飽和點
    if (t < ca->bic_K)                                    /* below origin*/
        bic_target = ca->bic_origin_point - delta;
    else                                                    /* above origin*/
        bic_target = ca->bic_origin_point + delta;

    /* cubic function - calc bictcp_cnt*/
    if (bic_target > cwnd) {// 相差越多,增加越快,這就是函數形狀由來
        ca->cnt = cwnd / (bic_target - cwnd);//
    } else {//目前cwnd已經超出預期了,應該降速
        ca->cnt = 100 * cwnd;              /* very small increment*/
    }



    /* TCP Friendly —若是bic比RENO慢,則提高cwnd增加速度,即減少cnt
     * 以上次丟包之後的時間t算起,每次RTT增加 3B / ( 2 - B),那麼能夠獲得
      * 採用RENO算法的cwnd。
      * cwnd (RENO) = cwnd + 3B / (2 - B) * ack_cnt / cwnd
     * B爲乘性減小因子,在此算法中爲0.3
     */
    if (tcp_friendliness) {
        u32 scale = beta_scale;
        delta = (cwnd * scale) >> 3; //delta表明多少ACK可以使tcp_cwnd++
        while (ca->ack_cnt > delta) {        /* update tcp cwnd */
            ca->ack_cnt -= delta;
            ca->tcp_cwnd++;
        }

        if (ca->tcp_cwnd > cwnd){    /* if bic is slower than tcp */
            delta = ca->tcp_cwnd - cwnd;
            max_cnt = cwnd / delta;
            if (ca->cnt > max_cnt)
                ca->cnt = max_cnt;
        }
    }

    ca->cnt = (ca->cnt << ACK_RATIO_SHIFT) / ca->delayed_ack;
    if (ca->cnt == 0)            /* cannot be zero */
        ca->cnt = 1; //此時表明cwnd遠小於bic_target,增加速度最大
}

巨人的肩膀

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.153.3152&rep=rep1&type=pdf

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.37.7442&rep=rep1&type=pdf

http://www.javashuo.com/article/p-agoyrwtf-kg.html

相關文章
相關標籤/搜索