diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2015-08-31 09:58:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-31 15:34:00 -0400 |
commit | c3a8d9474684d391b0afc3970d9b249add15ec07 (patch) | |
tree | f12130b61955f4471ebd61474244ecf9ebdc0858 /net/ipv4/tcp_input.c | |
parent | b8d3e4163a3562d7cba486687904383e78e7dd6a (diff) |
tcp: use dctcp if enabled on the route to the initiator
Currently, the following case doesn't use DCTCP, even if it should:
A responder has f.e. Cubic as system wide default, but for a specific
route to the initiating host, DCTCP is being set in RTAX_CC_ALGO. The
initiating host then uses DCTCP as congestion control, but since the
initiator sets ECT(0), tcp_ecn_create_request() doesn't set ecn_ok,
and we have to fall back to Reno after 3WHS completes.
We were thinking on how to solve this in a minimal, non-intrusive
way without bloating tcp_ecn_create_request() needlessly: lets cache
the CA ecn option flag in RTAX_FEATURES. In other words, when ECT(0)
is set on the SYN packet, set ecn_ok=1 iff route RTAX_FEATURES
contains the unexposed (internal-only) DST_FEATURE_ECN_CA. This allows
to only do a single metric feature lookup inside tcp_ecn_create_request().
Joint work with Florian Westphal.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index dc08e2352665..a8f515bb19c4 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -6003,14 +6003,17 @@ static void tcp_ecn_create_request(struct request_sock *req, | |||
6003 | const struct net *net = sock_net(listen_sk); | 6003 | const struct net *net = sock_net(listen_sk); |
6004 | bool th_ecn = th->ece && th->cwr; | 6004 | bool th_ecn = th->ece && th->cwr; |
6005 | bool ect, ecn_ok; | 6005 | bool ect, ecn_ok; |
6006 | u32 ecn_ok_dst; | ||
6006 | 6007 | ||
6007 | if (!th_ecn) | 6008 | if (!th_ecn) |
6008 | return; | 6009 | return; |
6009 | 6010 | ||
6010 | ect = !INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield); | 6011 | ect = !INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield); |
6011 | ecn_ok = net->ipv4.sysctl_tcp_ecn || dst_feature(dst, RTAX_FEATURE_ECN); | 6012 | ecn_ok_dst = dst_feature(dst, DST_FEATURE_ECN_MASK); |
6013 | ecn_ok = net->ipv4.sysctl_tcp_ecn || ecn_ok_dst; | ||
6012 | 6014 | ||
6013 | if ((!ect && ecn_ok) || tcp_ca_needs_ecn(listen_sk)) | 6015 | if ((!ect && ecn_ok) || tcp_ca_needs_ecn(listen_sk) || |
6016 | (ecn_ok_dst & DST_FEATURE_ECN_CA)) | ||
6014 | inet_rsk(req)->ecn_ok = 1; | 6017 | inet_rsk(req)->ecn_ok = 1; |
6015 | } | 6018 | } |
6016 | 6019 | ||