OSDN Git Service

tcp: Retain ECT bits for tos reflection
authorWei Wang <weiwan@google.com>
Tue, 8 Dec 2020 17:55:08 +0000 (09:55 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 10 Dec 2020 00:08:23 +0000 (16:08 -0800)
For DCTCP, we have to retain the ECT bits set by the congestion control
algorithm on the socket when reflecting syn TOS in syn-ack, in order to
make ECN work properly.

Fixes: ac8f1710c12b ("tcp: reflect tos value received in SYN to the socket")
Reported-by: Alexander Duyck <alexanderduyck@fb.com>
Signed-off-by: Wei Wang <weiwan@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c

index 8391aa2..595dcc3 100644 (file)
@@ -984,7 +984,8 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
                __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);
 
                tos = sock_net(sk)->ipv4.sysctl_tcp_reflect_tos ?
-                               tcp_rsk(req)->syn_tos & ~INET_ECN_MASK :
+                               (tcp_rsk(req)->syn_tos & ~INET_ECN_MASK) |
+                               (inet_sk(sk)->tos & INET_ECN_MASK) :
                                inet_sk(sk)->tos;
 
                if (!INET_ECN_is_capable(tos) &&
@@ -1541,7 +1542,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
                inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
        newinet->inet_id = prandom_u32();
 
-       /* Set ToS of the new socket based upon the value of incoming SYN. */
+       /* Set ToS of the new socket based upon the value of incoming SYN.
+        * ECT bits are set later in tcp_init_transfer().
+        */
        if (sock_net(sk)->ipv4.sysctl_tcp_reflect_tos)
                newinet->tos = tcp_rsk(req)->syn_tos & ~INET_ECN_MASK;
 
index 992cbf3..991dc36 100644 (file)
@@ -528,7 +528,8 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
                        fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
 
                tclass = sock_net(sk)->ipv4.sysctl_tcp_reflect_tos ?
-                               tcp_rsk(req)->syn_tos & ~INET_ECN_MASK :
+                               (tcp_rsk(req)->syn_tos & ~INET_ECN_MASK) |
+                               (np->tclass & INET_ECN_MASK) :
                                np->tclass;
 
                if (!INET_ECN_is_capable(tclass) &&
@@ -1320,7 +1321,9 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
        if (np->repflow)
                newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb));
 
-       /* Set ToS of the new socket based upon the value of incoming SYN. */
+       /* Set ToS of the new socket based upon the value of incoming SYN.
+        * ECT bits are set later in tcp_init_transfer().
+        */
        if (sock_net(sk)->ipv4.sysctl_tcp_reflect_tos)
                newnp->tclass = tcp_rsk(req)->syn_tos & ~INET_ECN_MASK;