tcp: add TCP_RFC7323_TW_PAWS drop reason
authorJiayuan Chen <jiayuan.chen@linux.dev>
Wed, 9 Apr 2025 11:26:04 +0000 (19:26 +0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 11 Apr 2025 01:29:26 +0000 (18:29 -0700)
Devices in the networking path, such as firewalls, NATs, or routers, which
can perform SNAT or DNAT, use addresses from their own limited address
pools to masquerade the source address during forwarding, causing PAWS
verification to fail more easily.

Currently, packet loss statistics for PAWS can only be viewed through MIB,
which is a global metric and cannot be precisely obtained through tracing
to get the specific 4-tuple of the dropped packet. In the past, we had to
use kprobe ret to retrieve relevant skb information from
tcp_timewait_state_process().

We add a drop_reason pointer, similar to what previous commit does:
commit e34100c2ecbb ("tcp: add a drop_reason pointer to tcp_check_req()")

This commit addresses the PAWSESTABREJECTED case and also sets the
corresponding drop reason.

We use 'pwru' to test.

Before this commit:
''''
./pwru 'port 9999'
2025/04/07 13:40:19 Listening for events..
TUPLE                                        FUNC
172.31.75.115:12345->172.31.75.114:9999(tcp) sk_skb_reason_drop(SKB_DROP_REASON_NOT_SPECIFIED)
'''

After this commit:
'''
./pwru 'port 9999'
2025/04/07 13:51:34 Listening for events..
TUPLE                                        FUNC
172.31.75.115:12345->172.31.75.114:9999(tcp) sk_skb_reason_drop(SKB_DROP_REASON_TCP_RFC7323_TW_PAWS)
'''

Suggested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250409112614.16153-2-jiayuan.chen@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/dropreason-core.h
include/net/tcp.h
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv6/tcp_ipv6.c

index e4fdc6b54ceffe9b225e613f739c089f3077d3ab..9701d7f936f6894772369e0a881d5361f68e4aa2 100644 (file)
@@ -40,6 +40,7 @@
        FN(TCP_OFOMERGE)                \
        FN(TCP_RFC7323_PAWS)            \
        FN(TCP_RFC7323_PAWS_ACK)        \
+       FN(TCP_RFC7323_TW_PAWS)         \
        FN(TCP_RFC7323_TSECR)           \
        FN(TCP_LISTEN_OVERFLOW)         \
        FN(TCP_OLD_SEQUENCE)            \
@@ -283,6 +284,11 @@ enum skb_drop_reason {
         * Corresponds to LINUX_MIB_PAWS_OLD_ACK.
         */
        SKB_DROP_REASON_TCP_RFC7323_PAWS_ACK,
+       /**
+        * @SKB_DROP_REASON_TCP_RFC7323_TW_PAWS: PAWS check, socket is in
+        * TIME_WAIT state.
+        */
+       SKB_DROP_REASON_TCP_RFC7323_TW_PAWS,
        /**
         * @SKB_DROP_REASON_TCP_RFC7323_TSECR: PAWS check, invalid TSEcr.
         * Corresponds to LINUX_MIB_TSECRREJECTED.
index 4450c384ef178e860bd76c23653e9ce9d7a7289b..5078ad868feef8fd8f210f8c3c54cdf575742ff2 100644 (file)
@@ -427,7 +427,8 @@ enum tcp_tw_status {
 enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
                                              struct sk_buff *skb,
                                              const struct tcphdr *th,
-                                             u32 *tw_isn);
+                                             u32 *tw_isn,
+                                             enum skb_drop_reason *drop_reason);
 struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
                           struct request_sock *req, bool fastopen,
                           bool *lost_race, enum skb_drop_reason *drop_reason);
index 8cce0d5489daeb21c3384e44752acd84ec0eb3e9..d5b5c32115d2ef84b0c91d43f584e571f342d9fb 100644 (file)
@@ -2417,7 +2417,8 @@ do_time_wait:
                goto csum_error;
        }
 
-       tw_status = tcp_timewait_state_process(inet_twsk(sk), skb, th, &isn);
+       tw_status = tcp_timewait_state_process(inet_twsk(sk), skb, th, &isn,
+                                              &drop_reason);
        switch (tw_status) {
        case TCP_TW_SYN: {
                struct sock *sk2 = inet_lookup_listener(net,
index fb9349be36b80c0dbaa434aa5bd292614fa8b7e7..27511bf58c0f58119e6d378f6c7a0209523af2ed 100644 (file)
@@ -97,7 +97,8 @@ static void twsk_rcv_nxt_update(struct tcp_timewait_sock *tcptw, u32 seq,
  */
 enum tcp_tw_status
 tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
-                          const struct tcphdr *th, u32 *tw_isn)
+                          const struct tcphdr *th, u32 *tw_isn,
+                          enum skb_drop_reason *drop_reason)
 {
        struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
        u32 rcv_nxt = READ_ONCE(tcptw->tw_rcv_nxt);
@@ -245,8 +246,10 @@ kill:
                return TCP_TW_SYN;
        }
 
-       if (paws_reject)
+       if (paws_reject) {
+               *drop_reason = SKB_DROP_REASON_TCP_RFC7323_TW_PAWS;
                __NET_INC_STATS(twsk_net(tw), LINUX_MIB_PAWSESTABREJECTED);
+       }
 
        if (!th->rst) {
                /* In this case we must reset the TIMEWAIT timer.
index b03c223eda4fa3f4ad47a84224a24c32f02571fc..7dcb33f879ee17b2377f1f0c41f68e4d67798c76 100644 (file)
@@ -1970,7 +1970,8 @@ do_time_wait:
                goto csum_error;
        }
 
-       tw_status = tcp_timewait_state_process(inet_twsk(sk), skb, th, &isn);
+       tw_status = tcp_timewait_state_process(inet_twsk(sk), skb, th, &isn,
+                                              &drop_reason);
        switch (tw_status) {
        case TCP_TW_SYN:
        {