不要乱用 TCP ECN flag

前段时间处理了一个 case,现象很简单,同网络环境下的机器,绝大多数的机器都无法 curl 访问 example.com,仅有少部分的可以 curl 访问,并且他们的 mtr 的路径一模一样,机器的配置应该也有一样。
对比一下,可以访问的:
$ curl -IL "http://example.com:80/rest"
-v
* About to connect() to example.com port 80 (#0)
*   Trying example.com… connected
* Connected to example.com (example.com) port 80 (#0)
> HEAD /rest HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3
> zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: example.com
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: nginx
Server: nginx
< Date: Fri, 24 Oct 2014 07:13:23 GMT
Date: Fri, 24 Oct 2014 07:13:23 GMT
< Content-Type: application/json;charset=UTF-8
Content-Type: application/json;charset=UTF-8
< Content-Length: 0
Content-Length: 0
< Connection: keep-alive
Connection: keep-alive
< s-rt: 2
s-rt: 2

<
* Connection #0 to host example.com left intact
* Closing connection #0

访问超时的:
curl -IL "http://example.com:80/rest" -v
* About to connect() to example.com port 80 (#0)
*   Trying example.com… Connection timed out
* couldn't connect to host
* Closing connection #0
curl: (7) couldn't connect to host

最初以为是 example.com(泛指) 的问题,后来联系了下我们的服务方,确认没有问题。当时想到一种可能是否是由于 SNAT 出口的 timestamps, tcp recycle 的时间戳问题引起的,后来确认了下,并不存在这个问题。BTW,要确认是不是 ts 的问题很简单,把客户端的 ts 给关闭再测试就知道是不是这个问题了。
直接抓包,惊奇的发现,根据经验,第一次的 TCP 连接,9bit 的 Flags 区域只应该有 SYN 标识位是被设置的,但是连不上的机器的 flags 竟然是 SYN, ECN, CWR 三个 bit 都被设置了。

看了下 wiki 对 ECN 的解释,以及 stackexchange 的实践,原因就很明显了,这条经过的 routing 上肯定有不支持 ECN 的 router,收到带有 ECN flag 的包之后就直接丢弃了,
可以访问的那部分机器由于 /proc/sys/net/ipv4/tcp_ecn 的默认值 2,可以接受带有 ECN 的包,但是不会主动发送,其余的机器由于明确的设置为了 1,这些包到从目的地返回源的过程中被中间 router 丢弃了。
2000 的统计显示,全球有 8% 的网络不可达跟 ECN 有关系。十多年过去了,理论上讲,应该有所改善。