net: ipv4 only populate IP_PKTINFO when needed
The since the removal of the routing cache computing fib_compute_spec_dst() does a fib_table lookup for each UDP multicast packet received. This has introduced a performance regression for some UDP workloads. This change skips populating the packet info for sockets that do not have IP_PKTINFO set. Benchmark results from a netperf UDP_RR test: Before 89789.68 transactions/s After 90587.62 transactions/s Benchmark results from a fio 1 byte UDP multicast pingpong test (Multicast one way unicast response): Before 12.63us RTT After 12.48us RTT Signed-off-by: Shawn Bohrer <sbohrer@rgmadvisors.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
421b3885bf
commit
fbf8866d65
@@ -459,7 +459,7 @@ int ip_options_rcv_srr(struct sk_buff *skb);
|
|||||||
* Functions provided by ip_sockglue.c
|
* Functions provided by ip_sockglue.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ipv4_pktinfo_prepare(struct sk_buff *skb);
|
void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb);
|
||||||
void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
|
void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
|
||||||
int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc);
|
int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc);
|
||||||
int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
|
int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
|
||||||
|
@@ -1052,11 +1052,12 @@ e_inval:
|
|||||||
* destination in skb->cb[] before dst drop.
|
* destination in skb->cb[] before dst drop.
|
||||||
* This way, receiver doesnt make cache line misses to read rtable.
|
* This way, receiver doesnt make cache line misses to read rtable.
|
||||||
*/
|
*/
|
||||||
void ipv4_pktinfo_prepare(struct sk_buff *skb)
|
void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
|
struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
|
||||||
|
|
||||||
if (skb_rtable(skb)) {
|
if ((inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) &&
|
||||||
|
skb_rtable(skb)) {
|
||||||
pktinfo->ipi_ifindex = inet_iif(skb);
|
pktinfo->ipi_ifindex = inet_iif(skb);
|
||||||
pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
|
pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -299,7 +299,7 @@ static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||||||
{
|
{
|
||||||
/* Charge it to the socket. */
|
/* Charge it to the socket. */
|
||||||
|
|
||||||
ipv4_pktinfo_prepare(skb);
|
ipv4_pktinfo_prepare(sk, skb);
|
||||||
if (sock_queue_rcv_skb(sk, skb) < 0) {
|
if (sock_queue_rcv_skb(sk, skb) < 0) {
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return NET_RX_DROP;
|
return NET_RX_DROP;
|
||||||
|
@@ -1544,7 +1544,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
ipv4_pktinfo_prepare(skb);
|
ipv4_pktinfo_prepare(sk, skb);
|
||||||
bh_lock_sock(sk);
|
bh_lock_sock(sk);
|
||||||
if (!sock_owned_by_user(sk))
|
if (!sock_owned_by_user(sk))
|
||||||
rc = __udp_queue_rcv_skb(sk, skb);
|
rc = __udp_queue_rcv_skb(sk, skb);
|
||||||
|
Reference in New Issue
Block a user