Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rxrpc: Allow a delay to be injected into packet reception

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

+91 -2
+9
net/rxrpc/Kconfig
··· 36 36 Say Y here to inject packet loss by discarding some received and some 37 37 transmitted packets. 38 38 39 + config AF_RXRPC_INJECT_RX_DELAY 40 + bool "Inject delay into packet reception" 41 + depends on SYSCTL 42 + help 43 + Say Y here to inject a delay into packet reception, allowing an 44 + extended RTT time to be modelled. The delay can be configured using 45 + /proc/sys/net/rxrpc/rxrpc_inject_rx_delay, setting a number of 46 + milliseconds up to 0.5s (note that the granularity is actually in 47 + jiffies). 39 48 40 49 config AF_RXRPC_DEBUG 41 50 bool "RxRPC dynamic debugging"
+6
net/rxrpc/ar-internal.h
··· 285 285 struct completion io_thread_ready; /* Indication that the I/O thread started */ 286 286 struct rxrpc_sock *service; /* Service(s) listening on this endpoint */ 287 287 struct rw_semaphore defrag_sem; /* control re-enablement of IP DF bit */ 288 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 289 + struct sk_buff_head rx_delay_queue; /* Delay injection queue */ 290 + #endif 288 291 struct sk_buff_head rx_queue; /* Received packets */ 289 292 struct list_head conn_attend_q; /* Conns requiring immediate attention */ 290 293 struct list_head call_attend_q; /* Calls requiring immediate attention */ ··· 1112 1109 extern unsigned int rxrpc_rx_window_size; 1113 1110 extern unsigned int rxrpc_rx_mtu; 1114 1111 extern unsigned int rxrpc_rx_jumbo_max; 1112 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 1113 + extern unsigned long rxrpc_inject_rx_delay; 1114 + #endif 1115 1115 1116 1116 /* 1117 1117 * net_ns.c
+47 -1
net/rxrpc/io_thread.c
··· 25 25 */ 26 26 int rxrpc_encap_rcv(struct sock *udp_sk, struct sk_buff *skb) 27 27 { 28 + struct sk_buff_head *rx_queue; 28 29 struct rxrpc_local *local = rcu_dereference_sk_user_data(udp_sk); 29 30 30 31 if (unlikely(!local)) { ··· 37 36 38 37 skb->mark = RXRPC_SKB_MARK_PACKET; 39 38 rxrpc_new_skb(skb, rxrpc_skb_new_encap_rcv); 40 - skb_queue_tail(&local->rx_queue, skb); 39 + rx_queue = &local->rx_queue; 40 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 41 + if (rxrpc_inject_rx_delay || 42 + !skb_queue_empty(&local->rx_delay_queue)) { 43 + skb->tstamp = ktime_add_ms(skb->tstamp, rxrpc_inject_rx_delay); 44 + rx_queue = &local->rx_delay_queue; 45 + } 46 + #endif 47 + 48 + skb_queue_tail(rx_queue, skb); 41 49 rxrpc_wake_up_io_thread(local); 42 50 return 0; 43 51 } ··· 417 407 struct rxrpc_local *local = data; 418 408 struct rxrpc_call *call; 419 409 struct sk_buff *skb; 410 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 411 + ktime_t now; 412 + #endif 420 413 bool should_stop; 421 414 422 415 complete(&local->io_thread_ready); ··· 494 481 continue; 495 482 } 496 483 484 + /* Inject a delay into packets if requested. */ 485 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 486 + now = ktime_get_real(); 487 + while ((skb = skb_peek(&local->rx_delay_queue))) { 488 + if (ktime_before(now, skb->tstamp)) 489 + break; 490 + skb = skb_dequeue(&local->rx_delay_queue); 491 + skb_queue_tail(&local->rx_queue, skb); 492 + } 493 + #endif 494 + 497 495 if (!skb_queue_empty(&local->rx_queue)) { 498 496 spin_lock_irq(&local->rx_queue.lock); 499 497 skb_queue_splice_tail_init(&local->rx_queue, &rx_queue); ··· 526 502 527 503 if (should_stop) 528 504 break; 505 + 506 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 507 + skb = skb_peek(&local->rx_delay_queue); 508 + if (skb) { 509 + unsigned long timeout; 510 + ktime_t tstamp = skb->tstamp; 511 + ktime_t now = ktime_get_real(); 512 + s64 delay_ns = ktime_to_ns(ktime_sub(tstamp, now)); 513 + 514 + if (delay_ns <= 0) { 515 + __set_current_state(TASK_RUNNING); 516 + continue; 517 + } 518 + 519 + timeout = nsecs_to_jiffies(delay_ns); 520 + timeout = max(timeout, 1UL); 521 + schedule_timeout(timeout); 522 + __set_current_state(TASK_RUNNING); 523 + continue; 524 + } 525 + #endif 526 + 529 527 schedule(); 530 528 } 531 529
+6
net/rxrpc/local_object.c
··· 110 110 INIT_HLIST_NODE(&local->link); 111 111 init_rwsem(&local->defrag_sem); 112 112 init_completion(&local->io_thread_ready); 113 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 114 + skb_queue_head_init(&local->rx_delay_queue); 115 + #endif 113 116 skb_queue_head_init(&local->rx_queue); 114 117 INIT_LIST_HEAD(&local->conn_attend_q); 115 118 INIT_LIST_HEAD(&local->call_attend_q); ··· 437 434 /* At this point, there should be no more packets coming in to the 438 435 * local endpoint. 439 436 */ 437 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 438 + rxrpc_purge_queue(&local->rx_delay_queue); 439 + #endif 440 440 rxrpc_purge_queue(&local->rx_queue); 441 441 rxrpc_purge_client_connections(local); 442 442 }
+7
net/rxrpc/misc.c
··· 53 53 * sender that we're willing to handle. 54 54 */ 55 55 unsigned int rxrpc_rx_jumbo_max = 4; 56 + 57 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 58 + /* 59 + * The delay to inject into packet reception. 60 + */ 61 + unsigned long rxrpc_inject_rx_delay; 62 + #endif
+16 -1
net/rxrpc/sysctl.c
··· 17 17 static const unsigned int n_max_acks = 255; 18 18 static const unsigned long one_jiffy = 1; 19 19 static const unsigned long max_jiffies = MAX_JIFFY_OFFSET; 20 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 21 + static const unsigned long max_500 = 500; 22 + #endif 20 23 21 24 /* 22 25 * RxRPC operating parameters. ··· 65 62 .extra1 = (void *)&one_jiffy, 66 63 .extra2 = (void *)&max_jiffies, 67 64 }, 65 + 66 + /* Values used in milliseconds */ 67 + #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 68 + { 69 + .procname = "inject_rx_delay", 70 + .data = &rxrpc_inject_rx_delay, 71 + .maxlen = sizeof(unsigned long), 72 + .mode = 0644, 73 + .proc_handler = proc_doulongvec_minmax, 74 + .extra1 = (void *)SYSCTL_LONG_ZERO, 75 + .extra2 = (void *)&max_500, 76 + }, 77 + #endif 68 78 69 79 /* Non-time values */ 70 80 { ··· 125 109 .extra1 = (void *)SYSCTL_ONE, 126 110 .extra2 = (void *)&four, 127 111 }, 128 - 129 112 { } 130 113 }; 131 114