mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-12 17:26:47 -04:00
Merge branch 'tcp-add-a-new-paws_ack-drop-reason'
Eric Dumazet says: ==================== tcp: add a new PAWS_ACK drop reason Current TCP_RFC7323_PAWS drop reason is too generic and can cause confusion. One common source for these drops are ACK packets coming too late. A prior packet with payload already changed tp->rcv_nxt. Add TCP_RFC7323_PAWS_ACK new drop reason, and do not generate a DUPACK for such old ACK. ==================== Link: https://patch.msgid.link/20250113135558.3180360-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
FN(TCP_OVERWINDOW) \
|
||||
FN(TCP_OFOMERGE) \
|
||||
FN(TCP_RFC7323_PAWS) \
|
||||
FN(TCP_RFC7323_PAWS_ACK) \
|
||||
FN(TCP_OLD_SEQUENCE) \
|
||||
FN(TCP_INVALID_SEQUENCE) \
|
||||
FN(TCP_INVALID_ACK_SEQUENCE) \
|
||||
@@ -259,6 +260,11 @@ enum skb_drop_reason {
|
||||
* LINUX_MIB_PAWSESTABREJECTED, LINUX_MIB_PAWSACTIVEREJECTED
|
||||
*/
|
||||
SKB_DROP_REASON_TCP_RFC7323_PAWS,
|
||||
/**
|
||||
* @SKB_DROP_REASON_TCP_RFC7323_PAWS_ACK: PAWS check, old ACK packet.
|
||||
* Corresponds to LINUX_MIB_PAWS_OLD_ACK.
|
||||
*/
|
||||
SKB_DROP_REASON_TCP_RFC7323_PAWS_ACK,
|
||||
/** @SKB_DROP_REASON_TCP_OLD_SEQUENCE: Old SEQ field (duplicate packet) */
|
||||
SKB_DROP_REASON_TCP_OLD_SEQUENCE,
|
||||
/** @SKB_DROP_REASON_TCP_INVALID_SEQUENCE: Not acceptable SEQ field */
|
||||
|
||||
@@ -186,6 +186,7 @@ enum
|
||||
LINUX_MIB_TIMEWAITKILLED, /* TimeWaitKilled */
|
||||
LINUX_MIB_PAWSACTIVEREJECTED, /* PAWSActiveRejected */
|
||||
LINUX_MIB_PAWSESTABREJECTED, /* PAWSEstabRejected */
|
||||
LINUX_MIB_PAWS_OLD_ACK, /* PAWSOldAck */
|
||||
LINUX_MIB_DELAYEDACKS, /* DelayedACKs */
|
||||
LINUX_MIB_DELAYEDACKLOCKED, /* DelayedACKLocked */
|
||||
LINUX_MIB_DELAYEDACKLOST, /* DelayedACKLost */
|
||||
|
||||
@@ -189,6 +189,7 @@ static const struct snmp_mib snmp4_net_list[] = {
|
||||
SNMP_MIB_ITEM("TWKilled", LINUX_MIB_TIMEWAITKILLED),
|
||||
SNMP_MIB_ITEM("PAWSActive", LINUX_MIB_PAWSACTIVEREJECTED),
|
||||
SNMP_MIB_ITEM("PAWSEstab", LINUX_MIB_PAWSESTABREJECTED),
|
||||
SNMP_MIB_ITEM("PAWSOldAck", LINUX_MIB_PAWS_OLD_ACK),
|
||||
SNMP_MIB_ITEM("DelayedACKs", LINUX_MIB_DELAYEDACKS),
|
||||
SNMP_MIB_ITEM("DelayedACKLocked", LINUX_MIB_DELAYEDACKLOCKED),
|
||||
SNMP_MIB_ITEM("DelayedACKLost", LINUX_MIB_DELAYEDACKLOST),
|
||||
|
||||
@@ -4450,34 +4450,40 @@ static u32 tcp_tsval_replay(const struct sock *sk)
|
||||
return inet_csk(sk)->icsk_rto * 1200 / HZ;
|
||||
}
|
||||
|
||||
static int tcp_disordered_ack(const struct sock *sk, const struct sk_buff *skb)
|
||||
static enum skb_drop_reason tcp_disordered_ack_check(const struct sock *sk,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
const struct tcp_sock *tp = tcp_sk(sk);
|
||||
const struct tcphdr *th = tcp_hdr(skb);
|
||||
u32 seq = TCP_SKB_CB(skb)->seq;
|
||||
SKB_DR_INIT(reason, TCP_RFC7323_PAWS);
|
||||
u32 ack = TCP_SKB_CB(skb)->ack_seq;
|
||||
u32 seq = TCP_SKB_CB(skb)->seq;
|
||||
|
||||
return /* 1. Pure ACK with correct sequence number. */
|
||||
(th->ack && seq == TCP_SKB_CB(skb)->end_seq && seq == tp->rcv_nxt) &&
|
||||
/* 1. Is this not a pure ACK ? */
|
||||
if (!th->ack || seq != TCP_SKB_CB(skb)->end_seq)
|
||||
return reason;
|
||||
|
||||
/* 2. ... and duplicate ACK. */
|
||||
ack == tp->snd_una &&
|
||||
/* 2. Is its sequence not the expected one ? */
|
||||
if (seq != tp->rcv_nxt)
|
||||
return before(seq, tp->rcv_nxt) ?
|
||||
SKB_DROP_REASON_TCP_RFC7323_PAWS_ACK :
|
||||
reason;
|
||||
|
||||
/* 3. ... and does not update window. */
|
||||
!tcp_may_update_window(tp, ack, seq, ntohs(th->window) << tp->rx_opt.snd_wscale) &&
|
||||
/* 3. Is this not a duplicate ACK ? */
|
||||
if (ack != tp->snd_una)
|
||||
return reason;
|
||||
|
||||
/* 4. ... and sits in replay window. */
|
||||
(s32)(tp->rx_opt.ts_recent - tp->rx_opt.rcv_tsval) <=
|
||||
tcp_tsval_replay(sk);
|
||||
}
|
||||
/* 4. Is this updating the window ? */
|
||||
if (tcp_may_update_window(tp, ack, seq, ntohs(th->window) <<
|
||||
tp->rx_opt.snd_wscale))
|
||||
return reason;
|
||||
|
||||
static inline bool tcp_paws_discard(const struct sock *sk,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
const struct tcp_sock *tp = tcp_sk(sk);
|
||||
/* 5. Is this not in the replay window ? */
|
||||
if ((s32)(tp->rx_opt.ts_recent - tp->rx_opt.rcv_tsval) >
|
||||
tcp_tsval_replay(sk))
|
||||
return reason;
|
||||
|
||||
return !tcp_paws_check(&tp->rx_opt, TCP_PAWS_WINDOW) &&
|
||||
!tcp_disordered_ack(sk, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check segment sequence number for validity.
|
||||
@@ -5949,23 +5955,35 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
|
||||
SKB_DR(reason);
|
||||
|
||||
/* RFC1323: H1. Apply PAWS check first. */
|
||||
if (tcp_fast_parse_options(sock_net(sk), skb, th, tp) &&
|
||||
tp->rx_opt.saw_tstamp &&
|
||||
tcp_paws_discard(sk, skb)) {
|
||||
if (!th->rst) {
|
||||
if (unlikely(th->syn))
|
||||
goto syn_challenge;
|
||||
NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
||||
if (!tcp_oow_rate_limited(sock_net(sk), skb,
|
||||
LINUX_MIB_TCPACKSKIPPEDPAWS,
|
||||
&tp->last_oow_ack_time))
|
||||
tcp_send_dupack(sk, skb);
|
||||
SKB_DR_SET(reason, TCP_RFC7323_PAWS);
|
||||
goto discard;
|
||||
}
|
||||
/* Reset is accepted even if it did not pass PAWS. */
|
||||
}
|
||||
if (!tcp_fast_parse_options(sock_net(sk), skb, th, tp) ||
|
||||
!tp->rx_opt.saw_tstamp ||
|
||||
tcp_paws_check(&tp->rx_opt, TCP_PAWS_WINDOW))
|
||||
goto step1;
|
||||
|
||||
reason = tcp_disordered_ack_check(sk, skb);
|
||||
if (!reason)
|
||||
goto step1;
|
||||
/* Reset is accepted even if it did not pass PAWS. */
|
||||
if (th->rst)
|
||||
goto step1;
|
||||
if (unlikely(th->syn))
|
||||
goto syn_challenge;
|
||||
|
||||
/* Old ACK are common, increment PAWS_OLD_ACK
|
||||
* and do not send a dupack.
|
||||
*/
|
||||
if (reason == SKB_DROP_REASON_TCP_RFC7323_PAWS_ACK) {
|
||||
NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWS_OLD_ACK);
|
||||
goto discard;
|
||||
}
|
||||
NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
||||
if (!tcp_oow_rate_limited(sock_net(sk), skb,
|
||||
LINUX_MIB_TCPACKSKIPPEDPAWS,
|
||||
&tp->last_oow_ack_time))
|
||||
tcp_send_dupack(sk, skb);
|
||||
goto discard;
|
||||
|
||||
step1:
|
||||
/* Step 1: check sequence number */
|
||||
reason = tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
|
||||
if (reason) {
|
||||
|
||||
Reference in New Issue
Block a user