ipv4: tcp: fix ACK/RST sent with a transmit delay
authorEric Dumazet <edumazet@google.com>
Fri, 14 Jun 2019 04:22:35 +0000 (21:22 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sat, 15 Jun 2019 02:51:12 +0000 (19:51 -0700)
If we want to set a EDT time for the skb we want to send
via ip_send_unicast_reply(), we have to pass a new parameter
and initialize ipc.sockc.transmit_time with it.

This fixes the EDT time for ACK/RST packets sent on behalf of
a TIME_WAIT socket.

Fixes: a842fe1425cb ("tcp: add optional per socket transmit delay")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip.h
include/net/tcp.h
net/ipv4/ip_output.c
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c

index 6dbf88e..29d89de 100644 (file)
@@ -279,7 +279,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
                           const struct ip_options *sopt,
                           __be32 daddr, __be32 saddr,
                           const struct ip_reply_arg *arg,
-                          unsigned int len);
+                          unsigned int len, u64 transmit_time);
 
 #define IP_INC_STATS(net, field)       SNMP_INC_STATS64((net)->mib.ip_statistics, field)
 #define __IP_INC_STATS(net, field)     __SNMP_INC_STATS64((net)->mib.ip_statistics, field)
index 49a178b..96e0e53 100644 (file)
@@ -2240,15 +2240,18 @@ static inline void tcp_add_tx_delay(struct sk_buff *skb,
                skb->skb_mstamp_ns += (u64)tp->tcp_tx_delay * NSEC_PER_USEC;
 }
 
-static inline void tcp_set_tx_time(struct sk_buff *skb,
-                                  const struct sock *sk)
+/* Compute Earliest Departure Time for some control packets
+ * like ACK or RST for TIME_WAIT or non ESTABLISHED sockets.
+ */
+static inline u64 tcp_transmit_time(const struct sock *sk)
 {
        if (static_branch_unlikely(&tcp_tx_delay_enabled)) {
                u32 delay = (sk->sk_state == TCP_TIME_WAIT) ?
                        tcp_twsk(sk)->tw_tx_delay : tcp_sk(sk)->tcp_tx_delay;
 
-               skb->skb_mstamp_ns = tcp_clock_ns() + (u64)delay * NSEC_PER_USEC;
+               return tcp_clock_ns() + (u64)delay * NSEC_PER_USEC;
        }
+       return 0;
 }
 
 #endif /* _TCP_H */
index f5636ab..e0ac390 100644 (file)
@@ -1632,7 +1632,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
                           const struct ip_options *sopt,
                           __be32 daddr, __be32 saddr,
                           const struct ip_reply_arg *arg,
-                          unsigned int len)
+                          unsigned int len, u64 transmit_time)
 {
        struct ip_options_data replyopts;
        struct ipcm_cookie ipc;
@@ -1648,6 +1648,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
 
        ipcm_init(&ipc);
        ipc.addr = daddr;
+       ipc.sockc.transmit_time = transmit_time;
 
        if (replyopts.opt.opt.optlen) {
                ipc.opt = &replyopts.opt;
index 1b7e9e1..633e824 100644 (file)
@@ -662,8 +662,9 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
        int genhash;
        struct sock *sk1 = NULL;
 #endif
-       struct net *net;
+       u64 transmit_time = 0;
        struct sock *ctl_sk;
+       struct net *net;
 
        /* Never send a reset in response to a reset. */
        if (th->rst)
@@ -770,12 +771,13 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
        if (sk) {
                ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ?
                                   inet_twsk(sk)->tw_mark : sk->sk_mark;
-               tcp_set_tx_time(skb, sk);
+               transmit_time = tcp_transmit_time(sk);
        }
        ip_send_unicast_reply(ctl_sk,
                              skb, &TCP_SKB_CB(skb)->header.h4.opt,
                              ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
-                             &arg, arg.iov[0].iov_len);
+                             &arg, arg.iov[0].iov_len,
+                             transmit_time);
 
        ctl_sk->sk_mark = 0;
        __TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
@@ -810,6 +812,7 @@ static void tcp_v4_send_ack(const struct sock *sk,
        struct net *net = sock_net(sk);
        struct ip_reply_arg arg;
        struct sock *ctl_sk;
+       u64 transmit_time;
 
        memset(&rep.th, 0, sizeof(struct tcphdr));
        memset(&arg, 0, sizeof(arg));
@@ -863,11 +866,12 @@ static void tcp_v4_send_ack(const struct sock *sk,
        ctl_sk = this_cpu_read(*net->ipv4.tcp_sk);
        ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ?
                           inet_twsk(sk)->tw_mark : sk->sk_mark;
-       tcp_set_tx_time(skb, sk);
+       transmit_time = tcp_transmit_time(sk);
        ip_send_unicast_reply(ctl_sk,
                              skb, &TCP_SKB_CB(skb)->header.h4.opt,
                              ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
-                             &arg, arg.iov[0].iov_len);
+                             &arg, arg.iov[0].iov_len,
+                             transmit_time);
 
        ctl_sk->sk_mark = 0;
        __TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
index 5606b21..408d9ec 100644 (file)
@@ -892,7 +892,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
                } else {
                        mark = sk->sk_mark;
                }
-               tcp_set_tx_time(buff, sk);
+               buff->tstamp = tcp_transmit_time(sk);
        }
        fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark) ?: mark;
        fl6.fl6_dport = t1->dest;