显式拥塞通知

显式拥塞通知（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)