diff options
author | Eric Dumazet <edumazet@google.com> | 2019-06-14 00:22:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-06-14 22:51:12 -0400 |
commit | d6fb396cfaa71afc9f38d573b8ec6409fe3716de (patch) | |
tree | 81f13c19c7e214129cb08ef7301b4941f435b52f | |
parent | 3e18943333404b03d17fc4a008da7c3676523f05 (diff) |
ipv4: tcp: fix ACK/RST sent with a transmit delay
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>
-rw-r--r-- | include/net/ip.h | 2 | ||||
-rw-r--r-- | include/net/tcp.h | 9 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 3 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 14 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 2 |
5 files changed, 19 insertions, 11 deletions
diff --git a/include/net/ip.h b/include/net/ip.h index 6dbf88ea07f1..29d89de39822 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -279,7 +279,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, | |||
279 | const struct ip_options *sopt, | 279 | const struct ip_options *sopt, |
280 | __be32 daddr, __be32 saddr, | 280 | __be32 daddr, __be32 saddr, |
281 | const struct ip_reply_arg *arg, | 281 | const struct ip_reply_arg *arg, |
282 | unsigned int len); | 282 | unsigned int len, u64 transmit_time); |
283 | 283 | ||
284 | #define IP_INC_STATS(net, field) SNMP_INC_STATS64((net)->mib.ip_statistics, field) | 284 | #define IP_INC_STATS(net, field) SNMP_INC_STATS64((net)->mib.ip_statistics, field) |
285 | #define __IP_INC_STATS(net, field) __SNMP_INC_STATS64((net)->mib.ip_statistics, field) | 285 | #define __IP_INC_STATS(net, field) __SNMP_INC_STATS64((net)->mib.ip_statistics, field) |
diff --git a/include/net/tcp.h b/include/net/tcp.h index 49a178b8d5b2..96e0e53ff440 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -2240,15 +2240,18 @@ static inline void tcp_add_tx_delay(struct sk_buff *skb, | |||
2240 | skb->skb_mstamp_ns += (u64)tp->tcp_tx_delay * NSEC_PER_USEC; | 2240 | skb->skb_mstamp_ns += (u64)tp->tcp_tx_delay * NSEC_PER_USEC; |
2241 | } | 2241 | } |
2242 | 2242 | ||
2243 | static inline void tcp_set_tx_time(struct sk_buff *skb, | 2243 | /* Compute Earliest Departure Time for some control packets |
2244 | const struct sock *sk) | 2244 | * like ACK or RST for TIME_WAIT or non ESTABLISHED sockets. |
2245 | */ | ||
2246 | static inline u64 tcp_transmit_time(const struct sock *sk) | ||
2245 | { | 2247 | { |
2246 | if (static_branch_unlikely(&tcp_tx_delay_enabled)) { | 2248 | if (static_branch_unlikely(&tcp_tx_delay_enabled)) { |
2247 | u32 delay = (sk->sk_state == TCP_TIME_WAIT) ? | 2249 | u32 delay = (sk->sk_state == TCP_TIME_WAIT) ? |
2248 | tcp_twsk(sk)->tw_tx_delay : tcp_sk(sk)->tcp_tx_delay; | 2250 | tcp_twsk(sk)->tw_tx_delay : tcp_sk(sk)->tcp_tx_delay; |
2249 | 2251 | ||
2250 | skb->skb_mstamp_ns = tcp_clock_ns() + (u64)delay * NSEC_PER_USEC; | 2252 | return tcp_clock_ns() + (u64)delay * NSEC_PER_USEC; |
2251 | } | 2253 | } |
2254 | return 0; | ||
2252 | } | 2255 | } |
2253 | 2256 | ||
2254 | #endif /* _TCP_H */ | 2257 | #endif /* _TCP_H */ |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index f5636ab0b9c3..e0ac39072a9c 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -1632,7 +1632,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, | |||
1632 | const struct ip_options *sopt, | 1632 | const struct ip_options *sopt, |
1633 | __be32 daddr, __be32 saddr, | 1633 | __be32 daddr, __be32 saddr, |
1634 | const struct ip_reply_arg *arg, | 1634 | const struct ip_reply_arg *arg, |
1635 | unsigned int len) | 1635 | unsigned int len, u64 transmit_time) |
1636 | { | 1636 | { |
1637 | struct ip_options_data replyopts; | 1637 | struct ip_options_data replyopts; |
1638 | struct ipcm_cookie ipc; | 1638 | struct ipcm_cookie ipc; |
@@ -1648,6 +1648,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, | |||
1648 | 1648 | ||
1649 | ipcm_init(&ipc); | 1649 | ipcm_init(&ipc); |
1650 | ipc.addr = daddr; | 1650 | ipc.addr = daddr; |
1651 | ipc.sockc.transmit_time = transmit_time; | ||
1651 | 1652 | ||
1652 | if (replyopts.opt.opt.optlen) { | 1653 | if (replyopts.opt.opt.optlen) { |
1653 | ipc.opt = &replyopts.opt; | 1654 | ipc.opt = &replyopts.opt; |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1b7e9e1fbd3b..633e8244ed5b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -662,8 +662,9 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) | |||
662 | int genhash; | 662 | int genhash; |
663 | struct sock *sk1 = NULL; | 663 | struct sock *sk1 = NULL; |
664 | #endif | 664 | #endif |
665 | struct net *net; | 665 | u64 transmit_time = 0; |
666 | struct sock *ctl_sk; | 666 | struct sock *ctl_sk; |
667 | struct net *net; | ||
667 | 668 | ||
668 | /* Never send a reset in response to a reset. */ | 669 | /* Never send a reset in response to a reset. */ |
669 | if (th->rst) | 670 | if (th->rst) |
@@ -770,12 +771,13 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) | |||
770 | if (sk) { | 771 | if (sk) { |
771 | ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ? | 772 | ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ? |
772 | inet_twsk(sk)->tw_mark : sk->sk_mark; | 773 | inet_twsk(sk)->tw_mark : sk->sk_mark; |
773 | tcp_set_tx_time(skb, sk); | 774 | transmit_time = tcp_transmit_time(sk); |
774 | } | 775 | } |
775 | ip_send_unicast_reply(ctl_sk, | 776 | ip_send_unicast_reply(ctl_sk, |
776 | skb, &TCP_SKB_CB(skb)->header.h4.opt, | 777 | skb, &TCP_SKB_CB(skb)->header.h4.opt, |
777 | ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, | 778 | ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, |
778 | &arg, arg.iov[0].iov_len); | 779 | &arg, arg.iov[0].iov_len, |
780 | transmit_time); | ||
779 | 781 | ||
780 | ctl_sk->sk_mark = 0; | 782 | ctl_sk->sk_mark = 0; |
781 | __TCP_INC_STATS(net, TCP_MIB_OUTSEGS); | 783 | __TCP_INC_STATS(net, TCP_MIB_OUTSEGS); |
@@ -810,6 +812,7 @@ static void tcp_v4_send_ack(const struct sock *sk, | |||
810 | struct net *net = sock_net(sk); | 812 | struct net *net = sock_net(sk); |
811 | struct ip_reply_arg arg; | 813 | struct ip_reply_arg arg; |
812 | struct sock *ctl_sk; | 814 | struct sock *ctl_sk; |
815 | u64 transmit_time; | ||
813 | 816 | ||
814 | memset(&rep.th, 0, sizeof(struct tcphdr)); | 817 | memset(&rep.th, 0, sizeof(struct tcphdr)); |
815 | memset(&arg, 0, sizeof(arg)); | 818 | memset(&arg, 0, sizeof(arg)); |
@@ -863,11 +866,12 @@ static void tcp_v4_send_ack(const struct sock *sk, | |||
863 | ctl_sk = this_cpu_read(*net->ipv4.tcp_sk); | 866 | ctl_sk = this_cpu_read(*net->ipv4.tcp_sk); |
864 | ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ? | 867 | ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ? |
865 | inet_twsk(sk)->tw_mark : sk->sk_mark; | 868 | inet_twsk(sk)->tw_mark : sk->sk_mark; |
866 | tcp_set_tx_time(skb, sk); | 869 | transmit_time = tcp_transmit_time(sk); |
867 | ip_send_unicast_reply(ctl_sk, | 870 | ip_send_unicast_reply(ctl_sk, |
868 | skb, &TCP_SKB_CB(skb)->header.h4.opt, | 871 | skb, &TCP_SKB_CB(skb)->header.h4.opt, |
869 | ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, | 872 | ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, |
870 | &arg, arg.iov[0].iov_len); | 873 | &arg, arg.iov[0].iov_len, |
874 | transmit_time); | ||
871 | 875 | ||
872 | ctl_sk->sk_mark = 0; | 876 | ctl_sk->sk_mark = 0; |
873 | __TCP_INC_STATS(net, TCP_MIB_OUTSEGS); | 877 | __TCP_INC_STATS(net, TCP_MIB_OUTSEGS); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5606b2131b65..408d9ec26971 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -892,7 +892,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 | |||
892 | } else { | 892 | } else { |
893 | mark = sk->sk_mark; | 893 | mark = sk->sk_mark; |
894 | } | 894 | } |
895 | tcp_set_tx_time(buff, sk); | 895 | buff->tstamp = tcp_transmit_time(sk); |
896 | } | 896 | } |
897 | fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark) ?: mark; | 897 | fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark) ?: mark; |
898 | fl6.fl6_dport = t1->dest; | 898 | fl6.fl6_dport = t1->dest; |