summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2026-03-05 11:48:29 +0000
committerJakub Kicinski <kuba@kernel.org>2026-03-06 16:32:26 -0800
commitc698f5cc940de5871ea3c65c94f5fd7fbc6844e3 (patch)
treef844b064d588b0e9d0b204fc3aeec9ed55f919dd
parentdb29970799e499b88fea048d8a3ad81bd95672c9 (diff)
downloadlwn-c698f5cc940de5871ea3c65c94f5fd7fbc6844e3.tar.gz
lwn-c698f5cc940de5871ea3c65c94f5fd7fbc6844e3.zip
inet_diag: report delayed ack timer information
inet_sk_diag_fill() populates r->idiag_timer with the following precedence order: 1 - Retransmit timer. 4 - Probe0 timer. 2 - Keepalive timer. This patch adds a new value, last in the list, if other timers are not active. 5 - Delayed ACK timer. A corresponding iproute2 patch will follow to replace "unknown" with "delack": ESTAB 10 0 [2002:a05:6830:1f86::]:12875 [2002:a05:6830:1f85::]:50438 timer:(unknown,003ms,0) ino:152178 sk:3004 cgroup:unreachable:189 <-> skmem:(r1344,rb12780520,t0,tb262144,f2752,w0,o250,bl0,d0) ts usec_ts ... Also add the following enum in uapi/linux/inet_diag.h as suggested by David Ahern. enum { IDIAG_TIMER_OFF, IDIAG_TIMER_ON, IDIAG_TIMER_KEEPALIVE, IDIAG_TIMER_TIMEWAIT, IDIAG_TIMER_PROBE0, IDIAG_TIMER_DELACK, }; Neal Cardwell suggested to test for ICSK_ACK_TIMER: inet_csk_clear_xmit_timer() does not call sk_stop_timer() because INET_CSK_CLEAR_TIMERS is unset. Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: David Ahern <dsahern@kernel.org> Reviewed-by: Neal Cardwell <ncardwell@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260305114829.2163276-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--include/uapi/linux/inet_diag.h9
-rw-r--r--net/ipv4/inet_diag.c13
-rw-r--r--net/ipv4/tcp_diag.c4
3 files changed, 20 insertions, 6 deletions
diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h
index 86bb2e8b17c9..21f0d735fbae 100644
--- a/include/uapi/linux/inet_diag.h
+++ b/include/uapi/linux/inet_diag.h
@@ -129,6 +129,15 @@ struct inet_diag_msg {
__u32 idiag_inode;
};
+enum {
+ IDIAG_TIMER_OFF,
+ IDIAG_TIMER_ON,
+ IDIAG_TIMER_KEEPALIVE,
+ IDIAG_TIMER_TIMEWAIT,
+ IDIAG_TIMER_PROBE0,
+ IDIAG_TIMER_DELACK,
+};
+
/* Extensions */
enum {
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 9d215485b5c7..34b77aa87d0a 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -241,7 +241,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
inet_diag_msg_common_fill(r, sk);
r->idiag_state = sk->sk_state;
- r->idiag_timer = 0;
+ r->idiag_timer = IDIAG_TIMER_OFF;
r->idiag_retrans = 0;
r->idiag_expires = 0;
@@ -284,20 +284,25 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
if (icsk_pending == ICSK_TIME_RETRANS ||
icsk_pending == ICSK_TIME_REO_TIMEOUT ||
icsk_pending == ICSK_TIME_LOSS_PROBE) {
- r->idiag_timer = 1;
+ r->idiag_timer = IDIAG_TIMER_ON;
r->idiag_retrans = READ_ONCE(icsk->icsk_retransmits);
r->idiag_expires =
jiffies_delta_to_msecs(tcp_timeout_expires(sk) - jiffies);
} else if (icsk_pending == ICSK_TIME_PROBE0) {
- r->idiag_timer = 4;
+ r->idiag_timer = IDIAG_TIMER_PROBE0;
r->idiag_retrans = READ_ONCE(icsk->icsk_probes_out);
r->idiag_expires =
jiffies_delta_to_msecs(tcp_timeout_expires(sk) - jiffies);
} else if (timer_pending(&icsk->icsk_keepalive_timer)) {
- r->idiag_timer = 2;
+ r->idiag_timer = IDIAG_TIMER_KEEPALIVE;
r->idiag_retrans = READ_ONCE(icsk->icsk_probes_out);
r->idiag_expires =
jiffies_delta_to_msecs(icsk->icsk_keepalive_timer.expires - jiffies);
+ } else if ((READ_ONCE(icsk->icsk_ack.pending) & ICSK_ACK_TIMER) &&
+ timer_pending(&icsk->icsk_delack_timer)) {
+ r->idiag_timer = IDIAG_TIMER_DELACK;
+ r->idiag_expires =
+ jiffies_delta_to_msecs(icsk_delack_timeout(icsk) - jiffies);
}
if ((ext & (1 << (INET_DIAG_INFO - 1))) && handler->idiag_info_size) {
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 7935702e394b..ba1fdbe9807f 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -212,7 +212,7 @@ static int tcp_twsk_diag_fill(struct sock *sk,
r->idiag_retrans = 0;
r->idiag_state = READ_ONCE(tw->tw_substate);
- r->idiag_timer = 3;
+ r->idiag_timer = IDIAG_TIMER_TIMEWAIT;
tmo = tw->tw_timer.expires - jiffies;
r->idiag_expires = jiffies_delta_to_msecs(tmo);
r->idiag_rqueue = 0;
@@ -247,7 +247,7 @@ static int tcp_req_diag_fill(struct sock *sk, struct sk_buff *skb,
r = nlmsg_data(nlh);
inet_diag_msg_common_fill(r, sk);
r->idiag_state = TCP_SYN_RECV;
- r->idiag_timer = 1;
+ r->idiag_timer = IDIAG_TIMER_ON;
r->idiag_retrans = READ_ONCE(reqsk->num_retrans);
BUILD_BUG_ON(offsetof(struct inet_request_sock, ir_cookie) !=