顯式擁塞通知

顯式擁塞通知（Explicit Congestion Notification，簡稱ECN）是一個對網際協議和傳輸控制協議（TCP）的擴展，定義於RFC 3168（2001）。ECN允許擁塞控制的端對端通知而避免丟包。ECN為一項可選功能，如果底層網路設施支持，則可能被啟用ECN的兩個端點使用。

通常來說，TCP/IP網路通過丟棄數據包來表明信道阻塞。在ECN成功協商的情況下，ECN感知路由器可以在IP頭中設置一個標記來代替丟棄數據包，以標明阻塞即將發生。數據包的接收端回應發送端的表示，降低其傳輸速率，就如同在往常中檢測到包丟失那樣。

相較於正確響應或者忽略位標記，一些過時或有故障的網路設備會丟棄或篡改數據包的ECN位。測量顯示，公共網際網路上會因ECN設置阻斷網絡連接的網頁伺服器減少到不足1%。

2015年5月，蘋果公司宣布將在受支持的及未來的產品中默認啟用ECN，以推進ECN信令在全行業的應用。

## 操作

由於下列原因，ECN需要網際網路層和傳輸層提供特定支持：

- 在TCP/IP中，路由器在網際網路層操作，而傳輸速率由傳輸層處的端點處理。
- 擁塞可能僅由發送端處理，但由於它是在數據包發送後發生，所以接收端必須向發送端回傳擁塞指示。

在無ECN時，擁塞指示回傳是通過檢測分組丟失來間接實現。在有ECN時，擁塞通過設置IP分組內的ECN欄位為CE並由接收端通過在傳輸協議的報頭中設置適當的位來回傳給發送端。例如，當使用TCP時，擁塞指示通過設置ECE位來回傳。

### IP 中的 ECN 操作

ECN 使用 IPv4 首部或 IPv6 首部中 ToS (Type of Service，位於首部第 9 到 16 比特位) 欄位的兩個最低有效位（最右側的位編碼）來表示四個狀態碼：

- `00` – 不支持 ECN 的傳輸，非 ECT(Non ECN-Capable Transport)
- `10` – 支持 ECN 的傳輸，ECT(0)
- `01` – 支持 ECN 的傳輸，ECT(1)
- `11` – 發生擁塞，CE(Congestion Experienced)。

當兩端支持 ECN 時，它將數據包標為 ECT(0) 或 ECT(1)。如果分組穿過一個遇到阻塞並且相應路由器支持 ECN 的活動隊列管理（AQM）隊列（例如一個使用隨機早期檢測，即 RED 的隊列），它可以將代碼點更改為`CE`而非丟包。這種行為就是「標記」，其目的是通知接收端即將發生擁塞。在接收端，該擁塞指示由上層協議（傳輸層協議）處理，並且需要將信號回傳給發送端，以通知其降低傳輸速率。

因為 CE 指示只能由支持它的上層協議有效處理，ECN 只能配合上層協議使用。例如 TCP 協議，它支持阻塞控制並且有方法將 CE 指示回傳給發送端。

### TCP中的ECN

TCP支持使用TCP頭中的三個標記（flag）來支持ECN。第一個標記是隨機和（Nonce Sum，簡稱NS），用於防止TCP發送者的數據包標記被意外或惡意改動。另兩位用於回傳擁塞指示（即指示發送者應減少資訊發送量）和確認接收到了擁塞指示回應。這即是ECN-Echo（ECE）和Congestion Window Reduced（CWR）位。

在TCP連接上使用ECN是可選的；當ECN被使用時，它必須在連接建立時通過SYN和SYN-ACK段中包含適當選項來協商。

當在一個TCP連接上協商ECN後，發送方指示連接上的TCP段攜帶IP分組傳輸流量，將支持ECN的傳輸用ECT碼點標記。這使支持ECN的中間路由器可以標記具有CE碼點的IP分組而不是丟棄它們，以指示即將發生的阻塞。

當接收到具有遇到阻塞碼點時，TCP接收者使用TCP頭中的ECE標記回傳這個阻塞指示。當一個端點收到TCP帶有ECE位的段時，它減少其擁塞窗口來代替丟包。然後，它設置段的CWR位來確認阻塞指示。

節點保持傳輸設置有ECE位的TCP段，直到它接收到設置有CWR的段。

要使用tcpdump查看受影響的數據包，使用過濾方法 `(tcp[13] & 0xc0 != 0)`。

#### ECN與TCP控制包

由於傳輸控制協議（TCP）不對控制分組（純ACKs、SYN、FIN段）進行擁塞控制，控制分組通常不被標記為可進行ECN。

一份2009年的提議建議將SYN-ACK標記為支持ECN。這種改進被稱為ECN+，已經顯示出對短壽命TCP連接的性能提供了顯著改善。

ECN也在其他執行擁塞控制的傳輸層協議中被定義，尤其是數據擁塞控制協議（DCCP）和流控制傳輸協議（SCTP）。其一般原理類似於TCP，儘管編碼細節有所不同。

在原則上可以在使用者數據報協議（UDP）之上的協議層實行ECN。但是，UDP需要應用程式實行擁塞控制，並且當前的網路API未提供訪問ECN位的方法。

## 對性能的影響

由於ECN僅在配合活動隊列管理（AQM）策略時有效，因此ECN的益處依賴於所用的AQM的精確度。

如預期那樣，ECN減少TCP連接中被丟棄的數據包數量，以避免重傳、減少等待時間，尤其是網路抖動。當TCP連接有單個未完成段時，這種效果最為明顯，它可以避免傳輸控制協議（RTO）超時；這通常發生在交互式連接時，例如遠程登錄，以及事務協議，例如HTTP請求、SMTP的會話階段、SQL請求。

ECN對批量吞吐的效果不太明確，因為現代的TCP實現在發送方的窗口足夠大時對於及時處理段丟失相當友好。

ECN的使用已被發現在高度擁塞的網路上是有害的，AQM演算法使數據包不會被丟棄。現代的AQM實現在極高負載下會丟包而非標記包來避免這個陷阱。

## 實現

許多現代產品中的TCP/IP協議已部分支持ECN；但是，大多數產品默認禁用ECN。

### 主機支持的TCP中的ECN

#### Microsoft Windows

Windows自Windows Server 2008和Windows Vista開始支持TCP中的ECN。因為數據中心傳輸控制協議（DCTCP）被使用，從Windows Server 2012開始在Windows Server版本中默認啟用。在更早的Windows版本以及非Server版本中，它被默認禁用。

ECN支持可以用命令啟用，例如netsh interface tcp set global ecncapability=enabled。

#### 類Unix

##### BSD

FreeBSD 8.0和NetBSD 4.0為TCP實現了ECN支持，可以通過sysctl接口將net.inet.tcp.ecn.enable參數設為1來激活。與此相同，OpenBSD中可以設置sysctl net.inet.tcp.ecn。

##### Linux

從發布於2002年11月的Linux內核2.4.20版本開始，Linux支持TCP中的ECN的三種工作模式，以及通過sysctl接口設置/proc/sys/net/ipv4/tcp_ecn參數為下列值：

- 0 – 禁用ECN，不發起也不接受
- 1 – 啟用ECN，當傳入連接請求時，並也在傳出連接時嘗試請求ECN
- 2 – （默認）傳入連接請求時啟用ECN，但不在傳出連接上請求ECN

從2015年6月發布的Linux內核4.1開始，tcp_ecn_fallback機制按RFC 3168中的規定，在ECN被啟用（值為1）時默認啟用。該回退機制在傳出連接的初始設置時嘗試ECN連接，對沒有ECN能力的傳輸實行良好回退，緩解不支持ECN的主機或防火牆問題。

##### Mac OS X

Mac OS X 10.5和10.6為TCP實現了ECN支持。它採用sysctl的布爾變量net.inet.tcp.ecn_negotiate_in和net.inet.tcp.ecn_initiate_out控制。第一個變量在已經設置ECN標記的傳入連接上使用ECN；第二個則嘗試在傳出連接上啟用ECN。兩個變量均默認為0，但可以設置為1以實現相應的行為。

2015年6月，蘋果公司宣布將在年內發布的OS X 10.11將默認啟用ECN。

##### iOS

2015年6月，蘋果公司宣布iOS的下一版本——iOS 9，將支持ECN並默認啟用。

##### Solaris

Solaris內核支持對TCP支持ECN的三種狀態：

- never – 無ECN
- active – 使用ECN
- passive – 僅在被詢問時宣告ECN支持。

默認行為是passive。從Solaris 11開始，可以通過激活完整的ECN功能。

### 路由器支持的IP中的ECN

由於在路由器中標記ECN依賴於某些形式的活動隊列管理，路由器必須配置合適的隊列規則才能實行ECN標記。

Cisco IOS路由器從12.2(8)T版本開始，如果已配置加權隨機早期檢測排隊規則，則實行ECN標記。

Linux路由器實行ECN標記，如果隨機早期檢測或GRED隊列顯式配置了ecn參數，通過使用sfb規則，或使用CoDel公平排隊（fq_codel）規則。

現代的BSD實現，例如FreeBSD、NetBSD和OpenBSD支持ECN標記，在許多排隊規則的ALTQ隊列實現，尤其是隨機早期檢測和Blue (隊列管理演算法)。FreeBSD 11在具有ECN標記能力的ipfw/dummynet框架中包括CoDel、PIE、FQ-CoDel和FQ-PIE 排隊規則的實現。

### 數據中心TCP

數據中心傳輸控制協議（也稱數據中心TCP或DCTCP）是利用ECN來增強傳輸控制協議的擁塞控制演算法，其用於數據中心網路。標準的TCP擁塞控制演算法只能檢測擁塞的存在，而使用ECN的DCTCP可以測量擁塞的程度。

DCTCP修改了TCP的接收端以始終中繼傳入連接的精確ECN標記，代價是忽略一個保持信令可靠性的功能。這使DCTCP的發送端易受到接受ACK丟失的影響，因為它沒有檢測或應對的機制。以更可靠的方法提供等效或更好的接收器反饋的演算法是一個活躍的研究課題，並有一個被稱為「More accurate ECN feedback in TCP」（「TCP中更準確的ECN反饋」）（Accurate ECN，精準ECN）的實驗建議。

## 外部連結

- ECN web page by Sally Floyd
- RFC 4774 (BCP), Specifying Alternate Semantics for the Explicit Congestion Notification (ECN) Field, S. Floyd, (November 2006)
- Linux kernel support for defining a per-route/destination congestion control algorithm (merged in Linux kernel 4.0)