mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-08 15:04:45 +00:00
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: a842fe1425
("tcp: add optional per socket transmit delay")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3e18943333
commit
d6fb396cfa
@ -279,7 +279,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
|
|||||||
const struct ip_options *sopt,
|
const struct ip_options *sopt,
|
||||||
__be32 daddr, __be32 saddr,
|
__be32 daddr, __be32 saddr,
|
||||||
const struct ip_reply_arg *arg,
|
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)
|
||||||
#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)
|
||||||
|
@ -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;
|
skb->skb_mstamp_ns += (u64)tp->tcp_tx_delay * NSEC_PER_USEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void tcp_set_tx_time(struct sk_buff *skb,
|
/* Compute Earliest Departure Time for some control packets
|
||||||
const struct sock *sk)
|
* 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)) {
|
if (static_branch_unlikely(&tcp_tx_delay_enabled)) {
|
||||||
u32 delay = (sk->sk_state == TCP_TIME_WAIT) ?
|
u32 delay = (sk->sk_state == TCP_TIME_WAIT) ?
|
||||||
tcp_twsk(sk)->tw_tx_delay : tcp_sk(sk)->tcp_tx_delay;
|
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 */
|
#endif /* _TCP_H */
|
||||||
|
@ -1632,7 +1632,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
|
|||||||
const struct ip_options *sopt,
|
const struct ip_options *sopt,
|
||||||
__be32 daddr, __be32 saddr,
|
__be32 daddr, __be32 saddr,
|
||||||
const struct ip_reply_arg *arg,
|
const struct ip_reply_arg *arg,
|
||||||
unsigned int len)
|
unsigned int len, u64 transmit_time)
|
||||||
{
|
{
|
||||||
struct ip_options_data replyopts;
|
struct ip_options_data replyopts;
|
||||||
struct ipcm_cookie ipc;
|
struct ipcm_cookie ipc;
|
||||||
@ -1648,6 +1648,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
|
|||||||
|
|
||||||
ipcm_init(&ipc);
|
ipcm_init(&ipc);
|
||||||
ipc.addr = daddr;
|
ipc.addr = daddr;
|
||||||
|
ipc.sockc.transmit_time = transmit_time;
|
||||||
|
|
||||||
if (replyopts.opt.opt.optlen) {
|
if (replyopts.opt.opt.optlen) {
|
||||||
ipc.opt = &replyopts.opt;
|
ipc.opt = &replyopts.opt;
|
||||||
|
@ -662,8 +662,9 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
|
|||||||
int genhash;
|
int genhash;
|
||||||
struct sock *sk1 = NULL;
|
struct sock *sk1 = NULL;
|
||||||
#endif
|
#endif
|
||||||
struct net *net;
|
u64 transmit_time = 0;
|
||||||
struct sock *ctl_sk;
|
struct sock *ctl_sk;
|
||||||
|
struct net *net;
|
||||||
|
|
||||||
/* Never send a reset in response to a reset. */
|
/* Never send a reset in response to a reset. */
|
||||||
if (th->rst)
|
if (th->rst)
|
||||||
@ -770,12 +771,13 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
|
|||||||
if (sk) {
|
if (sk) {
|
||||||
ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ?
|
ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ?
|
||||||
inet_twsk(sk)->tw_mark : sk->sk_mark;
|
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,
|
ip_send_unicast_reply(ctl_sk,
|
||||||
skb, &TCP_SKB_CB(skb)->header.h4.opt,
|
skb, &TCP_SKB_CB(skb)->header.h4.opt,
|
||||||
ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
|
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;
|
ctl_sk->sk_mark = 0;
|
||||||
__TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
|
__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 net *net = sock_net(sk);
|
||||||
struct ip_reply_arg arg;
|
struct ip_reply_arg arg;
|
||||||
struct sock *ctl_sk;
|
struct sock *ctl_sk;
|
||||||
|
u64 transmit_time;
|
||||||
|
|
||||||
memset(&rep.th, 0, sizeof(struct tcphdr));
|
memset(&rep.th, 0, sizeof(struct tcphdr));
|
||||||
memset(&arg, 0, sizeof(arg));
|
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 = this_cpu_read(*net->ipv4.tcp_sk);
|
||||||
ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ?
|
ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ?
|
||||||
inet_twsk(sk)->tw_mark : sk->sk_mark;
|
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,
|
ip_send_unicast_reply(ctl_sk,
|
||||||
skb, &TCP_SKB_CB(skb)->header.h4.opt,
|
skb, &TCP_SKB_CB(skb)->header.h4.opt,
|
||||||
ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
|
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;
|
ctl_sk->sk_mark = 0;
|
||||||
__TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
|
__TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
|
||||||
|
@ -892,7 +892,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
|
|||||||
} else {
|
} else {
|
||||||
mark = sk->sk_mark;
|
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.flowi6_mark = IP6_REPLY_MARK(net, skb->mark) ?: mark;
|
||||||
fl6.fl6_dport = t1->dest;
|
fl6.fl6_dport = t1->dest;
|
||||||
|
Loading…
Reference in New Issue
Block a user