net: ipv4 only populate IP_PKTINFO when needed
authorShawn Bohrer <sbohrer@rgmadvisors.com>
Mon, 7 Oct 2013 16:01:40 +0000 (11:01 -0500)
committerDavid S. Miller <davem@davemloft.net>
Tue, 8 Oct 2013 20:27:33 +0000 (16:27 -0400)
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>
include/net/ip.h
net/ipv4/ip_sockglue.c
net/ipv4/raw.c
net/ipv4/udp.c

index 16078f422397841a5c532ee4afb0343563d6ef2c..b39ebe5339ac63269c76ebc9c15df7bfa55b55d1 100644 (file)
@@ -459,7 +459,7 @@ int ip_options_rcv_srr(struct sk_buff *skb);
  *     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);
 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,
index 56e34457ac070922ba7467f8c4fcba94d22827d7..0626f2cb192e69ecb3fdbcf6d4d12884c7bc5c6d 100644 (file)
@@ -1052,11 +1052,12 @@ e_inval:
  * destination in skb->cb[] before dst drop.
  * 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);
 
-       if (skb_rtable(skb)) {
+       if ((inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) &&
+           skb_rtable(skb)) {
                pktinfo->ipi_ifindex = inet_iif(skb);
                pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
        } else {
index b2fa14c1a6f135ee58f1ef96ee018bcb4becf1ed..41e1d2845c8f6690b5588888134bd80e49fc5dcf 100644 (file)
@@ -299,7 +299,7 @@ static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        /* Charge it to the socket. */
 
-       ipv4_pktinfo_prepare(skb);
+       ipv4_pktinfo_prepare(sk, skb);
        if (sock_queue_rcv_skb(sk, skb) < 0) {
                kfree_skb(skb);
                return NET_RX_DROP;
index 262ea3929da65a7963c2b3bbbb53ef6dc5eb4e6d..4226c53daaed123b06f4f4b8c486253f887a0733 100644 (file)
@@ -1544,7 +1544,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
        rc = 0;
 
-       ipv4_pktinfo_prepare(skb);
+       ipv4_pktinfo_prepare(sk, skb);
        bh_lock_sock(sk);
        if (!sock_owned_by_user(sk))
                rc = __udp_queue_rcv_skb(sk, skb);