Skip to content

Commit fff755e

Browse files
committed
Merge branch 'TCP_INFO-RTO'
Aananth V says: ==================== tcp: new TCP_INFO stats for RTO events The 2023 SIGCOMM paper "Improving Network Availability with Protective ReRoute" has indicated Linux TCP's RTO-triggered txhash rehashing can effectively reduce application disruption during outages. To better measure the efficacy of this feature, this patch set adds three more detailed stats during RTO recovery and exports via TCP_INFO. Applications and monitoring systems can leverage this data to measure the network path diversity and end-to-end repair latency during network outages to improve their network infrastructure. Patch 1 fixes a bug in TFO SYNACK that we encountered while testing these new metrics. Patch 2 adds the new metrics to tcp_sock and tcp_info. v2: Addressed feedback from a check bot in patch 2 by removing the inline keyword from the tcp_update_rto_time and tcp_update_rto_stats functions. Changed a comment in include/net/tcp.h to fit under 80 words. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 50675d8 + 3868ab0 commit fff755e

File tree

6 files changed

+68
-6
lines changed

6 files changed

+68
-6
lines changed

include/linux/tcp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,14 @@ struct tcp_sock {
377377
* Total data bytes retransmitted
378378
*/
379379
u32 total_retrans; /* Total retransmits for entire connection */
380+
u32 rto_stamp; /* Start time (ms) of last CA_Loss recovery */
381+
u16 total_rto; /* Total number of RTO timeouts, including
382+
* SYN/SYN-ACK and recurring timeouts.
383+
*/
384+
u16 total_rto_recoveries; /* Total number of RTO recoveries,
385+
* including any unfinished recovery.
386+
*/
387+
u32 total_rto_time; /* ms spent in (completed) RTO recoveries. */
380388

381389
u32 urg_seq; /* Seq of received urgent pointer */
382390
unsigned int keepalive_time; /* time before keep alive takes place */

include/uapi/linux/tcp.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,18 @@ struct tcp_info {
289289
*/
290290

291291
__u32 tcpi_rehash; /* PLB or timeout triggered rehash attempts */
292+
293+
__u16 tcpi_total_rto; /* Total number of RTO timeouts, including
294+
* SYN/SYN-ACK and recurring timeouts.
295+
*/
296+
__u16 tcpi_total_rto_recoveries; /* Total number of RTO
297+
* recoveries, including any
298+
* unfinished recovery.
299+
*/
300+
__u32 tcpi_total_rto_time; /* Total time spent in RTO recoveries
301+
* in milliseconds, including any
302+
* unfinished recovery.
303+
*/
292304
};
293305

294306
/* netlink attributes types for SCM_TIMESTAMPING_OPT_STATS */

net/ipv4/tcp.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,6 +3818,15 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
38183818
info->tcpi_rcv_wnd = tp->rcv_wnd;
38193819
info->tcpi_rehash = tp->plb_rehash + tp->timeout_rehash;
38203820
info->tcpi_fastopen_client_fail = tp->fastopen_client_fail;
3821+
3822+
info->tcpi_total_rto = tp->total_rto;
3823+
info->tcpi_total_rto_recoveries = tp->total_rto_recoveries;
3824+
info->tcpi_total_rto_time = tp->total_rto_time;
3825+
if (tp->rto_stamp) {
3826+
info->tcpi_total_rto_time += tcp_time_stamp_raw() -
3827+
tp->rto_stamp;
3828+
}
3829+
38213830
unlock_sock_fast(sk, slow);
38223831
}
38233832
EXPORT_SYMBOL_GPL(tcp_get_info);

net/ipv4/tcp_input.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2088,6 +2088,10 @@ void tcp_clear_retrans(struct tcp_sock *tp)
20882088
tp->undo_marker = 0;
20892089
tp->undo_retrans = -1;
20902090
tp->sacked_out = 0;
2091+
tp->rto_stamp = 0;
2092+
tp->total_rto = 0;
2093+
tp->total_rto_recoveries = 0;
2094+
tp->total_rto_time = 0;
20912095
}
20922096

20932097
static inline void tcp_init_undo(struct tcp_sock *tp)
@@ -2825,6 +2829,14 @@ void tcp_enter_recovery(struct sock *sk, bool ece_ack)
28252829
tcp_set_ca_state(sk, TCP_CA_Recovery);
28262830
}
28272831

2832+
static void tcp_update_rto_time(struct tcp_sock *tp)
2833+
{
2834+
if (tp->rto_stamp) {
2835+
tp->total_rto_time += tcp_time_stamp(tp) - tp->rto_stamp;
2836+
tp->rto_stamp = 0;
2837+
}
2838+
}
2839+
28282840
/* Process an ACK in CA_Loss state. Move to CA_Open if lost data are
28292841
* recovered or spurious. Otherwise retransmits more on partial ACKs.
28302842
*/
@@ -3029,6 +3041,8 @@ static void tcp_fastretrans_alert(struct sock *sk, const u32 prior_snd_una,
30293041
break;
30303042
case TCP_CA_Loss:
30313043
tcp_process_loss(sk, flag, num_dupack, rexmit);
3044+
if (icsk->icsk_ca_state != TCP_CA_Loss)
3045+
tcp_update_rto_time(tp);
30323046
tcp_identify_packet_loss(sk, ack_flag);
30333047
if (!(icsk->icsk_ca_state == TCP_CA_Open ||
30343048
(*ack_flag & FLAG_LOST_RETRANS)))
@@ -6444,22 +6458,24 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
64446458

64456459
static void tcp_rcv_synrecv_state_fastopen(struct sock *sk)
64466460
{
6461+
struct tcp_sock *tp = tcp_sk(sk);
64476462
struct request_sock *req;
64486463

64496464
/* If we are still handling the SYNACK RTO, see if timestamp ECR allows
64506465
* undo. If peer SACKs triggered fast recovery, we can't undo here.
64516466
*/
6452-
if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss)
6453-
tcp_try_undo_loss(sk, false);
6467+
if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss && !tp->packets_out)
6468+
tcp_try_undo_recovery(sk);
64546469

64556470
/* Reset rtx states to prevent spurious retransmits_timed_out() */
6456-
tcp_sk(sk)->retrans_stamp = 0;
6471+
tcp_update_rto_time(tp);
6472+
tp->retrans_stamp = 0;
64576473
inet_csk(sk)->icsk_retransmits = 0;
64586474

64596475
/* Once we leave TCP_SYN_RECV or TCP_FIN_WAIT_1,
64606476
* we no longer need req so release it.
64616477
*/
6462-
req = rcu_dereference_protected(tcp_sk(sk)->fastopen_rsk,
6478+
req = rcu_dereference_protected(tp->fastopen_rsk,
64636479
lockdep_sock_is_held(sk));
64646480
reqsk_fastopen_remove(sk, req, false);
64656481

net/ipv4/tcp_minisocks.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,10 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
565565
newtp->undo_marker = treq->snt_isn;
566566
newtp->retrans_stamp = div_u64(treq->snt_synack,
567567
USEC_PER_SEC / TCP_TS_HZ);
568+
newtp->total_rto = req->num_timeout;
569+
newtp->total_rto_recoveries = 1;
570+
newtp->total_rto_time = tcp_time_stamp_raw() -
571+
newtp->retrans_stamp;
568572
}
569573
newtp->tsoffset = treq->ts_off;
570574
#ifdef CONFIG_TCP_MD5SIG

net/ipv4/tcp_timer.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,19 @@ abort: tcp_write_err(sk);
415415
}
416416
}
417417

418+
static void tcp_update_rto_stats(struct sock *sk)
419+
{
420+
struct inet_connection_sock *icsk = inet_csk(sk);
421+
struct tcp_sock *tp = tcp_sk(sk);
422+
423+
if (!icsk->icsk_retransmits) {
424+
tp->total_rto_recoveries++;
425+
tp->rto_stamp = tcp_time_stamp(tp);
426+
}
427+
icsk->icsk_retransmits++;
428+
tp->total_rto++;
429+
}
430+
418431
/*
419432
* Timer for Fast Open socket to retransmit SYNACK. Note that the
420433
* sk here is the child socket, not the parent (listener) socket.
@@ -447,7 +460,7 @@ static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req)
447460
*/
448461
inet_rtx_syn_ack(sk, req);
449462
req->num_timeout++;
450-
icsk->icsk_retransmits++;
463+
tcp_update_rto_stats(sk);
451464
if (!tp->retrans_stamp)
452465
tp->retrans_stamp = tcp_time_stamp(tp);
453466
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
@@ -575,7 +588,7 @@ void tcp_retransmit_timer(struct sock *sk)
575588

576589
tcp_enter_loss(sk);
577590

578-
icsk->icsk_retransmits++;
591+
tcp_update_rto_stats(sk);
579592
if (tcp_retransmit_skb(sk, tcp_rtx_queue_head(sk), 1) > 0) {
580593
/* Retransmission failed because of local congestion,
581594
* Let senders fight for local resources conservatively.

0 commit comments

Comments
 (0)