]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
tcp: new TCP_INFO stats for RTO events
authorAananth V <aananthv@google.com>
Thu, 14 Sep 2023 14:36:21 +0000 (14:36 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 16 Sep 2023 12:42:34 +0000 (13:42 +0100)
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 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.

The following counters are added to tcp_sock in order to track RTO
events over the lifetime of a TCP socket.

1. u16 total_rto - Counts the total number of RTO timeouts.
2. u16 total_rto_recoveries - Counts the total number of RTO recoveries.
3. u32 total_rto_time - Counts the total time spent (ms) in RTO
                        recoveries. (time spent in CA_Loss and
                        CA_Recovery states)

To compute total_rto_time, we add a new u32 rto_stamp field to
tcp_sock. rto_stamp records the start timestamp (ms) of the last RTO
recovery (CA_Loss).

Corresponding fields are also added to the tcp_info struct.

Signed-off-by: Aananth V <aananthv@google.com>
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/tcp.h
include/uapi/linux/tcp.h
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_timer.c

index 44d946161d4a7e52b05c196a1e1d37db25329650..e15452df9804f6d5badddaed3445c5586b1fcea3 100644 (file)
@@ -377,6 +377,14 @@ struct tcp_sock {
                                 * Total data bytes retransmitted
                                 */
        u32     total_retrans;  /* Total retransmits for entire connection */
+       u32     rto_stamp;      /* Start time (ms) of last CA_Loss recovery */
+       u16     total_rto;      /* Total number of RTO timeouts, including
+                                * SYN/SYN-ACK and recurring timeouts.
+                                */
+       u16     total_rto_recoveries;   /* Total number of RTO recoveries,
+                                        * including any unfinished recovery.
+                                        */
+       u32     total_rto_time; /* ms spent in (completed) RTO recoveries. */
 
        u32     urg_seq;        /* Seq of received urgent pointer */
        unsigned int            keepalive_time;   /* time before keep alive takes place */
index 879eeb0a084b4da77a2a73c422cf65c9f8d9f4fb..d1d08da6331ab5e1f07baacd7057c7a2207229e6 100644 (file)
@@ -289,6 +289,18 @@ struct tcp_info {
                                      */
 
        __u32   tcpi_rehash;         /* PLB or timeout triggered rehash attempts */
+
+       __u16   tcpi_total_rto; /* Total number of RTO timeouts, including
+                                * SYN/SYN-ACK and recurring timeouts.
+                                */
+       __u16   tcpi_total_rto_recoveries;      /* Total number of RTO
+                                                * recoveries, including any
+                                                * unfinished recovery.
+                                                */
+       __u32   tcpi_total_rto_time;    /* Total time spent in RTO recoveries
+                                        * in milliseconds, including any
+                                        * unfinished recovery.
+                                        */
 };
 
 /* netlink attributes types for SCM_TIMESTAMPING_OPT_STATS */
index 0c3040a63ebdb15be2c60532e2bdfc3d0fc51a9c..69b8d707370844020770438cc4f31aeda4830b3d 100644 (file)
@@ -3818,6 +3818,15 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
        info->tcpi_rcv_wnd = tp->rcv_wnd;
        info->tcpi_rehash = tp->plb_rehash + tp->timeout_rehash;
        info->tcpi_fastopen_client_fail = tp->fastopen_client_fail;
+
+       info->tcpi_total_rto = tp->total_rto;
+       info->tcpi_total_rto_recoveries = tp->total_rto_recoveries;
+       info->tcpi_total_rto_time = tp->total_rto_time;
+       if (tp->rto_stamp) {
+               info->tcpi_total_rto_time += tcp_time_stamp_raw() -
+                                               tp->rto_stamp;
+       }
+
        unlock_sock_fast(sk, slow);
 }
 EXPORT_SYMBOL_GPL(tcp_get_info);
index 8d2c9170315872b5aa2e9cd30841520f49ef336d..584825ddd0a09a2037aea7869b137c3ac64a1534 100644 (file)
@@ -2088,6 +2088,10 @@ void tcp_clear_retrans(struct tcp_sock *tp)
        tp->undo_marker = 0;
        tp->undo_retrans = -1;
        tp->sacked_out = 0;
+       tp->rto_stamp = 0;
+       tp->total_rto = 0;
+       tp->total_rto_recoveries = 0;
+       tp->total_rto_time = 0;
 }
 
 static inline void tcp_init_undo(struct tcp_sock *tp)
@@ -2825,6 +2829,14 @@ void tcp_enter_recovery(struct sock *sk, bool ece_ack)
        tcp_set_ca_state(sk, TCP_CA_Recovery);
 }
 
+static void tcp_update_rto_time(struct tcp_sock *tp)
+{
+       if (tp->rto_stamp) {
+               tp->total_rto_time += tcp_time_stamp(tp) - tp->rto_stamp;
+               tp->rto_stamp = 0;
+       }
+}
+
 /* Process an ACK in CA_Loss state. Move to CA_Open if lost data are
  * recovered or spurious. Otherwise retransmits more on partial ACKs.
  */
@@ -3029,6 +3041,8 @@ static void tcp_fastretrans_alert(struct sock *sk, const u32 prior_snd_una,
                break;
        case TCP_CA_Loss:
                tcp_process_loss(sk, flag, num_dupack, rexmit);
+               if (icsk->icsk_ca_state != TCP_CA_Loss)
+                       tcp_update_rto_time(tp);
                tcp_identify_packet_loss(sk, ack_flag);
                if (!(icsk->icsk_ca_state == TCP_CA_Open ||
                      (*ack_flag & FLAG_LOST_RETRANS)))
@@ -6454,6 +6468,7 @@ static void tcp_rcv_synrecv_state_fastopen(struct sock *sk)
                tcp_try_undo_recovery(sk);
 
        /* Reset rtx states to prevent spurious retransmits_timed_out() */
+       tcp_update_rto_time(tp);
        tp->retrans_stamp = 0;
        inet_csk(sk)->icsk_retransmits = 0;
 
index b98d476f1594bd8f9a70e6ff53d7f868a15997c5..eee8ab1bfa0e4fecde0cd1ff5d480d11c6741049 100644 (file)
@@ -565,6 +565,10 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
                newtp->undo_marker = treq->snt_isn;
                newtp->retrans_stamp = div_u64(treq->snt_synack,
                                               USEC_PER_SEC / TCP_TS_HZ);
+               newtp->total_rto = req->num_timeout;
+               newtp->total_rto_recoveries = 1;
+               newtp->total_rto_time = tcp_time_stamp_raw() -
+                                               newtp->retrans_stamp;
        }
        newtp->tsoffset = treq->ts_off;
 #ifdef CONFIG_TCP_MD5SIG
index d7d64682b068527c24e6d8bd4256dd0d8ef79948..3f61c6a70a1ff9b8f310aea30a91306e963216f5 100644 (file)
@@ -415,6 +415,19 @@ abort:             tcp_write_err(sk);
        }
 }
 
+static void tcp_update_rto_stats(struct sock *sk)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct tcp_sock *tp = tcp_sk(sk);
+
+       if (!icsk->icsk_retransmits) {
+               tp->total_rto_recoveries++;
+               tp->rto_stamp = tcp_time_stamp(tp);
+       }
+       icsk->icsk_retransmits++;
+       tp->total_rto++;
+}
+
 /*
  *     Timer for Fast Open socket to retransmit SYNACK. Note that the
  *     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)
         */
        inet_rtx_syn_ack(sk, req);
        req->num_timeout++;
-       icsk->icsk_retransmits++;
+       tcp_update_rto_stats(sk);
        if (!tp->retrans_stamp)
                tp->retrans_stamp = tcp_time_stamp(tp);
        inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
@@ -575,7 +588,7 @@ void tcp_retransmit_timer(struct sock *sk)
 
        tcp_enter_loss(sk);
 
-       icsk->icsk_retransmits++;
+       tcp_update_rto_stats(sk);
        if (tcp_retransmit_skb(sk, tcp_rtx_queue_head(sk), 1) > 0) {
                /* Retransmission failed because of local congestion,
                 * Let senders fight for local resources conservatively.