rxrpc: Allow a delay to be injected into packet reception
authorDavid Howells <dhowells@redhat.com>
Mon, 17 Oct 2022 07:54:57 +0000 (08:54 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 31 Jan 2023 16:38:09 +0000 (16:38 +0000)
If CONFIG_AF_RXRPC_DEBUG_RX_DELAY=y, then a delay is injected between
packets and errors being received and them being made available to the
processing code, thereby allowing the RTT to be artificially increased.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org

net/rxrpc/Kconfig
net/rxrpc/ar-internal.h
net/rxrpc/io_thread.c
net/rxrpc/local_object.c
net/rxrpc/misc.c
net/rxrpc/sysctl.c

index 7ae023b37a83a5450035d006efc23dc5ec83f9f5..a20986806fea966033124654c6162c7ffe794b59 100644 (file)
@@ -36,6 +36,15 @@ config AF_RXRPC_INJECT_LOSS
          Say Y here to inject packet loss by discarding some received and some
          transmitted packets.
 
+config AF_RXRPC_INJECT_RX_DELAY
+       bool "Inject delay into packet reception"
+       depends on SYSCTL
+       help
+         Say Y here to inject a delay into packet reception, allowing an
+         extended RTT time to be modelled.  The delay can be configured using
+         /proc/sys/net/rxrpc/rxrpc_inject_rx_delay, setting a number of
+         milliseconds up to 0.5s (note that the granularity is actually in
+         jiffies).
 
 config AF_RXRPC_DEBUG
        bool "RxRPC dynamic debugging"
index 808c08cb2ae5637b7a4ecc7e134892c0c10e7865..bfae4a87626f3b3d2ce595728803b0f4e835a251 100644 (file)
@@ -285,6 +285,9 @@ struct rxrpc_local {
        struct completion       io_thread_ready; /* Indication that the I/O thread started */
        struct rxrpc_sock       *service;       /* Service(s) listening on this endpoint */
        struct rw_semaphore     defrag_sem;     /* control re-enablement of IP DF bit */
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+       struct sk_buff_head     rx_delay_queue; /* Delay injection queue */
+#endif
        struct sk_buff_head     rx_queue;       /* Received packets */
        struct list_head        conn_attend_q;  /* Conns requiring immediate attention */
        struct list_head        call_attend_q;  /* Calls requiring immediate attention */
@@ -1109,6 +1112,9 @@ extern unsigned long rxrpc_idle_ack_delay;
 extern unsigned int rxrpc_rx_window_size;
 extern unsigned int rxrpc_rx_mtu;
 extern unsigned int rxrpc_rx_jumbo_max;
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+extern unsigned long rxrpc_inject_rx_delay;
+#endif
 
 /*
  * net_ns.c
index 9e9dfb2fc559be6c2615ecaf2e675f9e3c73d752..4a3a08a0e2cd041856f8a5d8a302f50b0064e8be 100644 (file)
@@ -25,6 +25,7 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
  */
 int rxrpc_encap_rcv(struct sock *udp_sk, struct sk_buff *skb)
 {
+       struct sk_buff_head *rx_queue;
        struct rxrpc_local *local = rcu_dereference_sk_user_data(udp_sk);
 
        if (unlikely(!local)) {
@@ -36,7 +37,16 @@ int rxrpc_encap_rcv(struct sock *udp_sk, struct sk_buff *skb)
 
        skb->mark = RXRPC_SKB_MARK_PACKET;
        rxrpc_new_skb(skb, rxrpc_skb_new_encap_rcv);
-       skb_queue_tail(&local->rx_queue, skb);
+       rx_queue = &local->rx_queue;
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+       if (rxrpc_inject_rx_delay ||
+           !skb_queue_empty(&local->rx_delay_queue)) {
+               skb->tstamp = ktime_add_ms(skb->tstamp, rxrpc_inject_rx_delay);
+               rx_queue = &local->rx_delay_queue;
+       }
+#endif
+
+       skb_queue_tail(rx_queue, skb);
        rxrpc_wake_up_io_thread(local);
        return 0;
 }
@@ -407,6 +417,9 @@ int rxrpc_io_thread(void *data)
        struct rxrpc_local *local = data;
        struct rxrpc_call *call;
        struct sk_buff *skb;
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+       ktime_t now;
+#endif
        bool should_stop;
 
        complete(&local->io_thread_ready);
@@ -481,6 +494,17 @@ int rxrpc_io_thread(void *data)
                        continue;
                }
 
+               /* Inject a delay into packets if requested. */
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+               now = ktime_get_real();
+               while ((skb = skb_peek(&local->rx_delay_queue))) {
+                       if (ktime_before(now, skb->tstamp))
+                               break;
+                       skb = skb_dequeue(&local->rx_delay_queue);
+                       skb_queue_tail(&local->rx_queue, skb);
+               }
+#endif
+
                if (!skb_queue_empty(&local->rx_queue)) {
                        spin_lock_irq(&local->rx_queue.lock);
                        skb_queue_splice_tail_init(&local->rx_queue, &rx_queue);
@@ -502,6 +526,28 @@ int rxrpc_io_thread(void *data)
 
                if (should_stop)
                        break;
+
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+               skb = skb_peek(&local->rx_delay_queue);
+               if (skb) {
+                       unsigned long timeout;
+                       ktime_t tstamp = skb->tstamp;
+                       ktime_t now = ktime_get_real();
+                       s64 delay_ns = ktime_to_ns(ktime_sub(tstamp, now));
+
+                       if (delay_ns <= 0) {
+                               __set_current_state(TASK_RUNNING);
+                               continue;
+                       }
+
+                       timeout = nsecs_to_jiffies(delay_ns);
+                       timeout = max(timeout, 1UL);
+                       schedule_timeout(timeout);
+                       __set_current_state(TASK_RUNNING);
+                       continue;
+               }
+#endif
+
                schedule();
        }
 
index b8eaca5d9f221362517b26aeeea91739c18bba24..07d83a4e58411b2793e7b90fe79415cdae2d034d 100644 (file)
@@ -110,6 +110,9 @@ static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
                INIT_HLIST_NODE(&local->link);
                init_rwsem(&local->defrag_sem);
                init_completion(&local->io_thread_ready);
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+               skb_queue_head_init(&local->rx_delay_queue);
+#endif
                skb_queue_head_init(&local->rx_queue);
                INIT_LIST_HEAD(&local->conn_attend_q);
                INIT_LIST_HEAD(&local->call_attend_q);
@@ -434,6 +437,9 @@ void rxrpc_destroy_local(struct rxrpc_local *local)
        /* At this point, there should be no more packets coming in to the
         * local endpoint.
         */
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+       rxrpc_purge_queue(&local->rx_delay_queue);
+#endif
        rxrpc_purge_queue(&local->rx_queue);
        rxrpc_purge_client_connections(local);
 }
index 056c428d8bf38dd56e3e37b683273c3f82883058..825b81183046eca8c0acddd0594189fe6c0e4608 100644 (file)
@@ -53,3 +53,10 @@ unsigned int rxrpc_rx_mtu = 5692;
  * sender that we're willing to handle.
  */
 unsigned int rxrpc_rx_jumbo_max = 4;
+
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+/*
+ * The delay to inject into packet reception.
+ */
+unsigned long rxrpc_inject_rx_delay;
+#endif
index cde3224a5cd277100467c81c2fd2e44ca5bc6c6b..ecaeb4ecfb58a94b9ee83676d66c5fe500fe3f58 100644 (file)
@@ -17,6 +17,9 @@ static const unsigned int n_65535 = 65535;
 static const unsigned int n_max_acks = 255;
 static const unsigned long one_jiffy = 1;
 static const unsigned long max_jiffies = MAX_JIFFY_OFFSET;
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+static const unsigned long max_500 = 500;
+#endif
 
 /*
  * RxRPC operating parameters.
@@ -63,6 +66,19 @@ static struct ctl_table rxrpc_sysctl_table[] = {
                .extra2         = (void *)&max_jiffies,
        },
 
+       /* Values used in milliseconds */
+#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY
+       {
+               .procname       = "inject_rx_delay",
+               .data           = &rxrpc_inject_rx_delay,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = proc_doulongvec_minmax,
+               .extra1         = (void *)SYSCTL_LONG_ZERO,
+               .extra2         = (void *)&max_500,
+       },
+#endif
+
        /* Non-time values */
        {
                .procname       = "reap_client_conns",
@@ -109,7 +125,6 @@ static struct ctl_table rxrpc_sysctl_table[] = {
                .extra1         = (void *)SYSCTL_ONE,
                .extra2         = (void *)&four,
        },
-
        { }
 };