[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20241231055207.9208-1-laoar.shao@gmail.com>
Date: Tue, 31 Dec 2024 13:52:07 +0800
From: Yafang Shao <laoar.shao@...il.com>
To: edumazet@...gle.com,
davem@...emloft.net,
dsahern@...nel.org,
kuba@...nel.org,
pabeni@...hat.com,
horms@...nel.org
Cc: netdev@...r.kernel.org,
Yafang Shao <laoar.shao@...il.com>
Subject: [PATCH net-next] net: tcp: Define tcp_listendrop() as noinline
The LINUX_MIB_LISTENDROPS counter can be incremented for several reasons,
such as:
- A full SYN backlog queue
- SYN flood attacks
- Memory exhaustion
- Other resource constraints
Recently, one of our services experienced frequent ListenDrops. While
attempting to trace the root cause, we discovered that tracing the function
tcp_listendrop() was not straightforward because it is currently inlined.
To overcome this, we had to create a livepatch that defined a non-inlined
version of the function, which we then traced using BPF programs.
$ grep tcp_listendrop /proc/kallsyms
ffffffffc093fba0 t tcp_listendrop_x [livepatch_tmp]
Through this process, we eventually determined that the ListenDrops were
caused by SYN attacks.
Since tcp_listendrop() is not part of the critical path, defining it as
noinline would make it significantly easier to trace and diagnose issues
without requiring workarounds such as livepatching. This function can be
used by kernel modules like smc, so export it with EXPORT_SYMBOL_GPL().
After that change, the result is as follows,
$ grep tcp_listendrop /proc/kallsyms
ffffffffb718eaa0 T __pfx_tcp_listendrop
ffffffffb718eab0 T tcp_listendrop
ffffffffb7e636b8 r __ksymtab_tcp_listendrop
Signed-off-by: Yafang Shao <laoar.shao@...il.com>
---
include/net/tcp.h | 13 +------------
net/ipv4/tcp_input.c | 14 ++++++++++++++
2 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index e9b37b76e894..65e6357e893b 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2537,18 +2537,7 @@ static inline void tcp_segs_in(struct tcp_sock *tp, const struct sk_buff *skb)
WRITE_ONCE(tp->data_segs_in, tp->data_segs_in + segs_in);
}
-/*
- * TCP listen path runs lockless.
- * We forced "struct sock" to be const qualified to make sure
- * we don't modify one of its field by mistake.
- * Here, we increment sk_drops which is an atomic_t, so we can safely
- * make sock writable again.
- */
-static inline void tcp_listendrop(const struct sock *sk)
-{
- atomic_inc(&((struct sock *)sk)->sk_drops);
- __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
-}
+void tcp_listendrop(const struct sock *sk);
enum hrtimer_restart tcp_pace_kick(struct hrtimer *timer);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 5bdf13ac26ef..0fcea815860b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -7174,6 +7174,20 @@ u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops,
}
EXPORT_SYMBOL_GPL(tcp_get_syncookie_mss);
+/*
+ * TCP listen path runs lockless.
+ * We forced "struct sock" to be const qualified to make sure
+ * we don't modify one of its field by mistake.
+ * Here, we increment sk_drops which is an atomic_t, so we can safely
+ * make sock writable again.
+ */
+void tcp_listendrop(const struct sock *sk)
+{
+ atomic_inc(&((struct sock *)sk)->sk_drops);
+ __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
+}
+EXPORT_SYMBOL_GPL(tcp_listendrop);
+
int tcp_conn_request(struct request_sock_ops *rsk_ops,
const struct tcp_request_sock_ops *af_ops,
struct sock *sk, struct sk_buff *skb)
--
2.43.5
Powered by blists - more mailing lists