How Linux Handles ECN in TCP Traffic
Explicit Congestion Notification (ECN) allows the Linux operating
system to detect and respond to network congestion without relying on
dropped packets. In TCP traffic, the Linux kernel implements ECN by
negotiating capabilities during the three-way handshake, interpreting
Congestion Experienced (CE) marks placed by intermediate routers in the
IP header, signaling back via TCP flags, and adjusting the congestion
window accordingly. Through fine-grained kernel sysctl
configurations, Linux provides a reliable mechanism to reduce latency,
prevent packet retransmissions, and sustain high throughput under heavy
network load.
ECN Negotiation via the TCP Handshake
Before ECN can be utilized, both endpoints must agree to use it during the initial TCP three-way handshake:
- SYN Packet: The Linux client advertises ECN support by setting both the ECN-Echo (ECE) and Congestion Window Reduced (CWR) flags in the TCP header of the initial SYN packet.
- SYN-ACK Packet: If the responding Linux server supports ECN, it replies with a SYN-ACK packet with only the ECE flag set.
- ACK Packet: The client completes the handshake with a standard ACK packet, establishing an ECN-capable TCP session.
If either endpoint does not support ECN or if an intermediate middlebox clears these flags, the Linux kernel automatically falls back to standard, non-ECN TCP operation.
IP-Level Packet Marking
Once negotiated, the Linux networking stack sets the ECN field in the IP header of outgoing data packets. The IP header uses the two least-significant bits of the Differentiated Services (DiffServ) field:
- 00 (Non-ECT): Non-ECN-Capable Transport.
- 10 (ECT(0)) or 01 (ECT(1)): ECN-Capable Transport. Linux typically marks data packets as ECT(0).
- 11 (CE): Congestion Experienced.
When an intermediate router encounters buffer buildup, instead of
dropping an ECT-marked packet (tail drop or active queue management like
RED/CoDel), it rewrites the IP bits to 11 (CE) and forwards
the packet to its destination.
Handling Congestion Signals in the Linux Stack
When the receiving Linux host accepts a packet marked with CE in the IP header, it acknowledges the congestion event back to the sender through the TCP header:
- ECE Generation: The receiver sets the ECE flag on subsequent TCP ACK packets sent back to the sender. It continues setting ECE on ACKs until the sender acknowledges the notification.
- Sender Reaction: When the transmitting Linux host
receives an ACK with the ECE bit set, it invokes its active congestion
control algorithm (such as CUBIC, BBR, or DCTCP). The kernel reduces the
Congestion Window (
cwnd) and the Slow Start Threshold (ssthresh) in a manner similar to handling a single packet loss event. - CWR Acknowledgment: The sender then sets the CWR flag on the next outgoing data packet. This informs the receiver that the sender has responded to the congestion event, allowing the receiver to stop setting the ECE flag on subsequent ACKs.
Because the window reduction happens without an actual packet drop, the connection avoids costly packet retransmissions and prevents TCP fast recovery timeouts.
Linux Kernel Configuration
Linux manages ECN behavior through sysctl settings
located in /proc/sys/net/ipv4/:
net.ipv4.tcp_ecn:0: Completely disables ECN. The kernel will neither request nor accept ECN negotiation.1: Fully enables ECN. The kernel requests ECN on outgoing connections and accepts incoming requests.2(Default in many distributions): Enables ECN only when requested by incoming connections (server mode), but does not request ECN when initiating outbound connections.
net.ipv4.tcp_ecn_fallback:- When set to
1(default), the Linux kernel automatically retries connection attempts without ECN flags if an initial ECN-enabled SYN packet drops or fails to receive an acknowledgment, mitigating issues caused by outdated middleboxes that drop ECN packets.
- When set to