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

udp: enable busy polling for all sockets

UDP busy polling is restricted to connected UDP sockets.

This is because sk_busy_loop() only takes care of one NAPI context.

There are cases where it could be extended.

1) Some hosts receive traffic on a single NIC, with one RX queue.

2) Some applications use SO_REUSEPORT and associated BPF filter
to split the incoming traffic on one UDP socket per RX
queue/thread/cpu

3) Some UDP sockets are used to send/receive traffic for one flow, but
they do not bother with connect()

This patch records the napi_id of first received skb, giving more
reach to busy polling.

Tested:

lpaa23:~# echo 70 >/proc/sys/net/core/busy_read
lpaa24:~# echo 70 >/proc/sys/net/core/busy_read

lpaa23:~# for f in `seq 1 10`; do ./super_netperf 1 -H lpaa24 -t UDP_RR -l 5; done

Before patch :
27867 28870 37324 41060 41215
36764 36838 44455 41282 43843
After patch :
73920 73213 70147 74845 71697
68315 68028 75219 70082 73707

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
e68b6e50 fcd2b0da

+23 -9
+19 -9
include/net/busy_poll.h
··· 80 80 skb->napi_id = napi->napi_id; 81 81 } 82 82 83 - /* used in the protocol hanlder to propagate the napi_id to the socket */ 84 - static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb) 85 - { 86 - sk->sk_napi_id = skb->napi_id; 87 - } 88 83 89 84 #else /* CONFIG_NET_RX_BUSY_POLL */ 90 85 static inline unsigned long net_busy_loop_on(void) ··· 102 107 { 103 108 } 104 109 105 - static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb) 106 - { 107 - } 108 - 109 110 static inline bool busy_loop_timeout(unsigned long end_time) 110 111 { 111 112 return true; ··· 113 122 } 114 123 115 124 #endif /* CONFIG_NET_RX_BUSY_POLL */ 125 + 126 + /* used in the protocol hanlder to propagate the napi_id to the socket */ 127 + static inline void sk_mark_napi_id(struct sock *sk, const struct sk_buff *skb) 128 + { 129 + #ifdef CONFIG_NET_RX_BUSY_POLL 130 + sk->sk_napi_id = skb->napi_id; 131 + #endif 132 + } 133 + 134 + /* variant used for unconnected sockets */ 135 + static inline void sk_mark_napi_id_once(struct sock *sk, 136 + const struct sk_buff *skb) 137 + { 138 + #ifdef CONFIG_NET_RX_BUSY_POLL 139 + if (!sk->sk_napi_id) 140 + sk->sk_napi_id = skb->napi_id; 141 + #endif 142 + } 143 + 116 144 #endif /* _LINUX_NET_BUSY_POLL_H */
+2
net/ipv4/udp.c
··· 1569 1569 sock_rps_save_rxhash(sk, skb); 1570 1570 sk_mark_napi_id(sk, skb); 1571 1571 sk_incoming_cpu_update(sk); 1572 + } else { 1573 + sk_mark_napi_id_once(sk, skb); 1572 1574 } 1573 1575 1574 1576 rc = __udp_enqueue_schedule_skb(sk, skb);
+2
net/ipv6/udp.c
··· 519 519 sock_rps_save_rxhash(sk, skb); 520 520 sk_mark_napi_id(sk, skb); 521 521 sk_incoming_cpu_update(sk); 522 + } else { 523 + sk_mark_napi_id_once(sk, skb); 522 524 } 523 525 524 526 rc = __udp_enqueue_schedule_skb(sk, skb);