對MPTCP協議理論部分的學習進行了整理,文中數據包結構的圖來自於RFC6824。詳見http://www.rfcreader.com/#rfc6824
MPTCP協議學習
MPTCP目的:隨着技術的發展許多設備具有了多個網絡接口,而TCP依然是一個單線路的協議,在TCP的通信過程中發端和收端都不能隨意變換地址。我們可以利用多個網絡接口的這一特性來改善性能和有效冗余。
例如:手中的 iPhone 同時開啟了 4G 和 WiFi 連接(大多數情況也是這樣),這個時候我通過 App Store 更新一個 100M 的軟件。按照以往的情況,App Store 的軟件更新是會優先通過 WiFi 進行的,44G 在此刻是閑置狀態。但是在 Multipath TCP 的支援下,盡管只通過 App Store 更新一個軟件,建立起了一個網絡連接,但是它卻可以同時利用 3G 和 WiFi 建立 Mutlpath 連接,通過多點優化網絡下載,且互為備份。假如這個時候 WiFi 斷了,以前的情況是,App Store 更新中斷,需要人工干預恢復或重新下載。而在 Mutlipath TCP 的優化下,只要 3G 沒斷,App Store 就能繼續更新下載。除非 3G 也斷了,才宣告此次連接失敗。
而Multipath TCP可以在一條TCP鏈接中包含多條路徑,避免上述問題出現。
簡單來說:MPTCP允許在一條TCP鏈路中建立多個子通道。當一條通道按照三次握手的方式建立起來后,可以按照三次握手的方式建立其他的子通道,這些通道以三次握手建立連接和四次握手解除連接。這些通道都會綁定於MPTCP session,發送端的數據可以選擇其中一條通道進行傳輸。
MPTCP的設計遵守以下兩個原則:1. 應用程序的兼容性,應用程序只要可以運行在TCP環境下,就可以在沒有任何修改的情況下,運行於MPTCP環境。2. 網絡的兼容性,MPTCP兼容其他協議。協議棧中的位置:同TCP一樣處於傳輸層。
頭部選項在TCP頭部和數據包內容之間,一個TCP包可能沒有頭部選項,也可能同時有好幾個頭部選項。TCP頭部選項的格式如下,通過kind字段區分不同的頭部選項。
TCP數據包格式:
源端口(16) |
目的端口(16) |
||
TCP序號(32) |
|||
捎帶的確認(32) |
|||
首部長度(4) |
保留(6) |
FLAG(6) |
窗口尺寸(16) |
TCP校驗和(16) |
緊急指針(16) |
||
選項和填充 |
|||
數據 |
TCP選項格式:
在做包解析的時候,根據TCP頭部選項的kind值就可以判斷該包是否為MPTCP包了。
MPTCP選項的典型結構為
其中,kind字段表示該頭部選項為MPTCP頭部選項,kind=30。Length字段表示該頭部選項的長度,subtype選項表示該MPTCP選項的子類型,剩下的字節則為該子類選項的具體數據。根據subtype值的不同,MPTCP選項的子類型有以下幾種:
MPTCP建立連接過程:如圖,MPTCP的第一個子通道的建立遵守TCP的三次握手,唯一的區別是每次發送的報文段需要添加MP_CAPABLE的的TCP選項和一個安全用途的key。而子通道的建立依需要四次握手,而TCP選項換成了MP_JOIN。而token是基於key的一個hash值,rand為一個隨機數,而HMAC是基於rand的一個has
數據的發送和接收:MPTCP可以選擇多條子通道中任意一條來發送數據。MPTCP在發送數據方面和TCP的區別是可以從多條路徑中選擇一條路徑來發送數據,MPTCP在接收數據方面與TCP的區別是子路徑對無序包進行重排后。
由於所有的數據會通過不同的子路徑發送,在接收端MPTCP需要對數據進行重新排序。因此我們需要數據序號映射。數據序號映射定義從子路徑序列空間到數據序列空間的映射。子路徑的序列空間是子路徑自身的序列號,而數據序列空間維護着所有需發送的數據。如下圖
紅色子路徑上的子路徑序號分別是1、2,其數據序號是1000、1002。而下面的藍色的子路徑上的子路徑序號和數據序號分別是200,1001。這說明從下面的藍色子路徑已經發送了199個報文,而上面的紅色子路徑才開始發送。在MPTCP協議定義如下:
MPTCP的接收包過程分為兩個階段:第一、每個子通道依據自身序號來重組報文段;第二、MPTCP的控制模塊依據DSN對所有子通道的報文段進行重組。
擁塞控制:
MPTCP的擁塞控制對TCP的擁塞控制的線性增加階段進行了修改,而慢啟動,快速重傳、快速恢復都沒有改變。每條子路徑擁有自己的cwnd,MPTCP的擁塞算法主要關心cwnd的改變。
擁塞算法設計原則:
MPTCP的Throughput 要達到MPTCP中所有子路徑中最好的一條路徑
MPTCP應該和普通TCP一樣從共享資源中獲得相同資源
MPTCP中的流量將從擁塞的子路徑轉移到不擁塞的路徑
關於傳統TCP協議中的擁塞控制:
幾種擁塞控制的方法:慢開始( slow-start )、擁塞避免( congestion avoidance )、快重傳( fast retransmit )和快恢復( fast recovery )、選擇性應答( selective acknowledgement,SACK)算法。
慢開始算法:當主機開始發送數據時,如果立即所大量數據字節注入到網絡,那么就有可能引起網絡擁塞,因為現在並不清楚網絡的負荷情況。因此,較好的方法是先探測一下,即由小到大逐漸增大發送窗口,也就是說,由小到大逐漸增大擁塞窗口數值。
為了防止擁塞窗口cwnd增長過大引起網絡擁塞,還需要設置一個慢開始門限ssthresh狀態變量(如何設置ssthresh)。慢開始門限ssthresh的用法如下:
當 cwnd < ssthresh 時,使用上述的慢開始算法。
當 cwnd > ssthresh 時,停止使用慢開始算法而改用擁塞避免算法。
當 cwnd = ssthresh 時,既可使用慢開始算法,也可使用擁塞控制避免算法。
擁塞避免算法:讓擁塞窗口cwnd緩慢地增大,即每經過一個往返時間RTT就把發送方的擁塞窗口cwnd加1,而不是加倍。這樣擁塞窗口cwnd按線性規律緩慢增長,比慢開始算法的擁塞窗口增長速率緩慢得多。
快重傳算法:快重傳算法首先要求接收方每收到一個失序的報文段后就立即發出重復確認(為的是使發送方及早知道有報文段沒有到達對方)而不要等到自己發送數據時才進行捎帶確認。
快重傳算法還規定,發送方只要一連收到三個重復確認就應當立即重傳對方尚未收到的報文段M3,而不必繼續等待M3設置的重傳計時器到期。
與快重傳配合使用的還有快恢復算法,其過程有以下兩個要點:
<1>. 當發送方連續收到三個重復確認,就執行“乘法減小”算法,把慢開始門限ssthresh減半。這是為了預防網絡發生擁塞。請注意:接下去不執行慢開始算法。
<2>. 由於發送方現在認為網絡很可能沒有發生擁塞,因此與慢開始不同之處是現在不執行慢開始算法(即擁塞窗口cwnd現在不設置為1),而是把cwnd值設置為慢開始門限ssthresh減半后的數值,然后開始執行擁塞避免算法(“加法增大”),使擁塞窗口緩慢地線性增大。
選擇性應答:改變TCP的確認機制,最初的TCP只確認當前已連續收到的數據,SACK則把亂序等信息會全部告訴對方,從而減少數據發送方重傳的盲目性。比如說序號1,2,3,5,7的數據收到了,那么普通的ACK只會確認序列號4,而SACK會把當前的5,7已經收到的信息在SACK選項里面告知對端,從而提高性能,當使用SACK的時候,NewReno算法可以不使用,因為SACK本身攜帶的信息就可以使得發送方有足夠的信息來知道需要重傳哪些包,而不需要重傳哪些包。
另外還有Limited transmit(RFC3042)。這個算法是在擁塞窗口比較小的時候如果在一個傳輸窗口內有多個包丟失時比較有效率的恢復算法。之前已經講過,TCP有一個快速恢復的機制,而快速恢復的前提是收到3個重復ACK。然而,接收方發送重復ACK卻又需要亂序包的到達才可以觸發,TCP在每收到一個亂序包就會立即發送一個重復的ACK給發送端。如果擁塞窗口比較小的時候會發生情況呢?發送方和接收方進入一段互相等待的狀況,接收方等待再收到一個包於是發生重復ACK,而發送方卻等待第3個重復ACK,如果窗口較小,例如為3,如果此時第一個包丟失了,接收方對第二個和第三個包分別發送了重復ACK,總共兩個重復ACK,此時發送端由於窗口的關系不能再發送數據,此時雙方進入互等,直到發送方的重傳超時計時器到,才能打破該僵局,顯然如果是這樣的話效率就明顯降低,因為重傳超時的時間設置為RTT+4×RTTVar,一般該值都比較大。
Limited Transmit就是為了解決這種情況的,它的方法很簡單,那就是當收到兩個重復ACK時,檢測兩個條件:
1)接收方的通告窗口rwnd是否允許傳輸新的數據包,即是否滿足rwnd>cwnd?
2)停留在網絡中的數據包個數是否小於或等於cwnd+2?
如果這兩個條件都滿足的話,那么TCP再發送新的數據包,其實第二個條件換個意思理解就是說在這種情況下可以超出擁塞窗口最多再發送兩個數據包。假設新的數據包和相應的ACK不被丟失的話,那么有了這兩個新的數據包,從而雙方可以立即從僵局中恢復出來,發送方接着進入標准的快速恢復。注意的是盡管可以發送兩個新的數據包,但是cwnd的值要保持不變,而不能把它增加2。顯然Limited Transmit算法比利用超時重傳在包亂序時具有更好的魯棒性
協議學習過程中遇到的一些名詞:
head-of-line blocking:
輸入排隊最主要的缺點是存在對頭阻塞(HOL Blocking)現象。這是比較容易理解的。在一條入線上輸入隊列中緩存的輸入信元,其目的出現通常情況下各不相同。如果對頭的信元因為競爭失敗而暫時無法得到服務,那么對頭信元的等待將使整個隊列中所有信元被迫等待。例如,假定某入線I1的對頭信元的目的出線為O1,恰巧另一條入線I2的對頭信元的目的出線也是O1。仲裁邏輯判定入線I2首先獲得服務,入線I1上的信元則必須等待。這將導致整個入線I1的輸入隊列中的后續信元進入等待。即使I1隊列中的后續的第2個信元的目的是另外某個出線Ox,且Ox當時正處於空閑狀態,該信元也不能被服務,因為該信元牽頭的對頭信元阻擋着它的傳送
DoS/DDoS:
DoS:最常見的DoS攻擊有對計算機網絡的帶寬攻擊和連通性攻擊。帶寬攻擊指以極大的通信量沖擊網絡,使得所有可用網絡資源都被消耗殆盡,最后導致合法的用戶請求無法通過。連通性攻擊指用大量的連接請求沖擊計算機,使得所有可用的操作系統資源都被消耗殆盡,最終計算機無法再處理合法用戶的請求
DDoS:傳統上,攻擊者所面臨的主要問題是網絡帶寬,由於較小的網絡規模和較慢的網絡速度的限制,攻擊者無法發出過多的請求。雖然類似“the ping of death”的攻擊類型只需要較少量的包就可以摧毀一個沒有打過補丁的UNIX系統,但大多數的DoS攻擊還是需要相當大的帶寬的,而以個人為單位的黑客們很難使用高帶寬的資源。為了克服這個缺點,DoS攻擊者開發了分布式的攻擊。攻擊者簡單利用工具集合許多的網絡帶寬來同時對同一個目標發動大量的攻擊請求,這就是DDoS(Distributed Denial of Service)攻擊。
SYN attack:
SYN Flood是一種廣為人知的DoS(拒絕服務攻擊)是DDoS(分布式拒絕服務攻擊)的方式之一,這是一種利用TCP協議缺陷,發送大量偽造的TCP連接請求,從而使得被攻擊方資源耗盡(CPU滿負荷或內存不足)的攻擊方式
half-open:
TCP的半開連接(half-open)是指TCP連接的一端崩潰,或者在未通知對端的情況下移除socket,不可以正常收發數據,否則會產生RST。
TCP的半關閉是指TCP連接的一端調用shutdown操作使數據只能往一個方向流動,只有一方發送了FIN,仍然可以正常收(或發)數據