TCP_ECN_OK 是来自 linuxkernel 内部struct tcp_sock as(字段ecn_flags)的位标志。其中有几个位标志(include/net/tcp.h file 来自 linux 内核源代码):
398 #define TCP_ECN_OK 1
399 #define TCP_ECN_QUEUE_CWR 2
400 #define TCP_ECN_DEMAND_CWR 4
401 #define TCP_ECN_SEEN 8
表达式tp->ecn_flags & TCP_ECN_OK是逻辑测试,TCP_ECN_OK是否仍然设置。
更新:我认为TCP_ECN_OK位在tcp套接字打开时设置(如果sysctl的当前设置在Linux中启用ECN支持),如果套接字的另一端也支持ECN,它将保持设置。
正如维基百科中所说的http://en.wikipedia.org/wiki/Explicit_Congestion_Notification
ECN 是可选功能,仅在两个端点都支持并愿意使用时使用。
...跳到 Linux 部分
Linux 内核支持 TCP 的 ECN 的三种工作模式,由 /proc/sys/net/ipv4/tcp_ecn 变量的值配置,通过 sysctl 接口:[11 - tcp_ecn in Documentation/networking/ip-sysctl.txt]
- 0 – 禁用 ECN,既不启动也不接受它
- 1 – 在传入连接请求时启用 ECN,并在传出连接尝试时请求 ECN
- 2 – 在传入连接请求时启用 ECN,但在传出连接上不请求 ECN。 // 3.14 中的默认设置 //
默认值为 2,表示默认情况下,ECN 在传入连接请求时启用,但在传出连接上不请求。无论如何,只有在 TCP 连接的两端都表示支持 ECN 时,Linux 内核才会使用 ECN。[11]
例如,当我们在传出套接字连接开始时发送 SYN,并且为传出连接启用 sysctl tcp_ecn(“sysctl_tcp_ecn”标志为1),我们在 tcp 头中设置 ECE 位并设置 TCP_ECN_OK。 net/ipv4/tcp_output.c315号线
315 /* Packet ECN state for a SYN. */
316 static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
....
320 tp->ecn_flags = 0;
321 if (sock_net(sk)->ipv4.sysctl_tcp_ecn == 1) {
322 TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR;
323 tp->ecn_flags = TCP_ECN_OK;
324 }
稍后,如果连接的另一端不支持 ECN 或者它被禁用,我们将取消设置 TCP_ECN_OK 标志。
net/ipv4/tcp_input.c246号线
246 static inline void TCP_ECN_rcv_synack(struct tcp_sock *tp, const struct tcphdr *th)
247 {
248 if ((tp->ecn_flags & TCP_ECN_OK) && (!th->ece || th->cwr))
249 tp->ecn_flags &= ~TCP_ECN_OK;
250 }
对于传入连接,我们取消设置 TCP_ECN_OK,如果传入 SYN 中没有 ECE tcp 标头标志(在RFC3168 "The Addition of Explicit Congestion Notification (ECN) to IP" 中阅读有关标志和 ECN 的更多信息)
252 static inline void TCP_ECN_rcv_syn(struct tcp_sock *tp, const struct tcphdr *th)
253 {
254 if ((tp->ecn_flags & TCP_ECN_OK) && (!th->ece || !th->cwr))
255 tp->ecn_flags &= ~TCP_ECN_OK;
256 }