aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip.h2
-rw-r--r--net/ipv4/ip_sockglue.c35
-rw-r--r--net/ipv4/raw.c3
-rw-r--r--net/ipv4/udp.c3
-rw-r--r--net/ipv6/raw.c3
-rw-r--r--net/ipv6/udp.c4
6 files changed, 28 insertions, 22 deletions
diff --git a/include/net/ip.h b/include/net/ip.h
index eca0ef7a495e..fd1561e88a1a 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -450,7 +450,7 @@ extern int ip_options_rcv_srr(struct sk_buff *skb);
450 * Functions provided by ip_sockglue.c 450 * Functions provided by ip_sockglue.c
451 */ 451 */
452 452
453extern int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); 453extern void ipv4_pktinfo_prepare(struct sk_buff *skb);
454extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb); 454extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
455extern int ip_cmsg_send(struct net *net, 455extern int ip_cmsg_send(struct net *net,
456 struct msghdr *msg, struct ipcm_cookie *ipc); 456 struct msghdr *msg, struct ipcm_cookie *ipc);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 09ff51bf16a4..80d5fa450210 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -55,20 +55,13 @@
55/* 55/*
56 * SOL_IP control messages. 56 * SOL_IP control messages.
57 */ 57 */
58#define PKTINFO_SKB_CB(__skb) ((struct in_pktinfo *)((__skb)->cb))
58 59
59static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) 60static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
60{ 61{
61 struct in_pktinfo info; 62 struct in_pktinfo info = *PKTINFO_SKB_CB(skb);
62 struct rtable *rt = skb_rtable(skb);
63 63
64 info.ipi_addr.s_addr = ip_hdr(skb)->daddr; 64 info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
65 if (rt) {
66 info.ipi_ifindex = rt->rt_iif;
67 info.ipi_spec_dst.s_addr = rt->rt_spec_dst;
68 } else {
69 info.ipi_ifindex = 0;
70 info.ipi_spec_dst.s_addr = 0;
71 }
72 65
73 put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info); 66 put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
74} 67}
@@ -992,20 +985,28 @@ e_inval:
992} 985}
993 986
994/** 987/**
995 * ip_queue_rcv_skb - Queue an skb into sock receive queue 988 * ipv4_pktinfo_prepare - transfert some info from rtable to skb
996 * @sk: socket 989 * @sk: socket
997 * @skb: buffer 990 * @skb: buffer
998 * 991 *
999 * Queues an skb into socket receive queue. If IP_CMSG_PKTINFO option 992 * To support IP_CMSG_PKTINFO option, we store rt_iif and rt_spec_dst
1000 * is not set, we drop skb dst entry now, while dst cache line is hot. 993 * in skb->cb[] before dst drop.
994 * This way, receiver doesnt make cache line misses to read rtable.
1001 */ 995 */
1002int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) 996void ipv4_pktinfo_prepare(struct sk_buff *skb)
1003{ 997{
1004 if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO)) 998 struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
1005 skb_dst_drop(skb); 999 const struct rtable *rt = skb_rtable(skb);
1006 return sock_queue_rcv_skb(sk, skb); 1000
1001 if (rt) {
1002 pktinfo->ipi_ifindex = rt->rt_iif;
1003 pktinfo->ipi_spec_dst.s_addr = rt->rt_spec_dst;
1004 } else {
1005 pktinfo->ipi_ifindex = 0;
1006 pktinfo->ipi_spec_dst.s_addr = 0;
1007 }
1008 skb_dst_drop(skb);
1007} 1009}
1008EXPORT_SYMBOL(ip_queue_rcv_skb);
1009 1010
1010int ip_setsockopt(struct sock *sk, int level, 1011int ip_setsockopt(struct sock *sk, int level,
1011 int optname, char __user *optval, unsigned int optlen) 1012 int optname, char __user *optval, unsigned int optlen)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 007e2eb769d3..7a8410d1b4b1 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -292,7 +292,8 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
292{ 292{
293 /* Charge it to the socket. */ 293 /* Charge it to the socket. */
294 294
295 if (ip_queue_rcv_skb(sk, skb) < 0) { 295 ipv4_pktinfo_prepare(skb);
296 if (sock_queue_rcv_skb(sk, skb) < 0) {
296 kfree_skb(skb); 297 kfree_skb(skb);
297 return NET_RX_DROP; 298 return NET_RX_DROP;
298 } 299 }
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index ab0966df1e2a..6854f581313f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1357,7 +1357,7 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
1357 if (inet_sk(sk)->inet_daddr) 1357 if (inet_sk(sk)->inet_daddr)
1358 sock_rps_save_rxhash(sk, skb); 1358 sock_rps_save_rxhash(sk, skb);
1359 1359
1360 rc = ip_queue_rcv_skb(sk, skb); 1360 rc = sock_queue_rcv_skb(sk, skb);
1361 if (rc < 0) { 1361 if (rc < 0) {
1362 int is_udplite = IS_UDPLITE(sk); 1362 int is_udplite = IS_UDPLITE(sk);
1363 1363
@@ -1473,6 +1473,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
1473 1473
1474 rc = 0; 1474 rc = 0;
1475 1475
1476 ipv4_pktinfo_prepare(skb);
1476 bh_lock_sock(sk); 1477 bh_lock_sock(sk);
1477 if (!sock_owned_by_user(sk)) 1478 if (!sock_owned_by_user(sk))
1478 rc = __udp_queue_rcv_skb(sk, skb); 1479 rc = __udp_queue_rcv_skb(sk, skb);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 331af3b882ac..204f2e833f04 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -383,7 +383,8 @@ static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb)
383 } 383 }
384 384
385 /* Charge it to the socket. */ 385 /* Charge it to the socket. */
386 if (ip_queue_rcv_skb(sk, skb) < 0) { 386 skb_dst_drop(skb);
387 if (sock_queue_rcv_skb(sk, skb) < 0) {
387 kfree_skb(skb); 388 kfree_skb(skb);
388 return NET_RX_DROP; 389 return NET_RX_DROP;
389 } 390 }
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 846f4757eb8d..b4a4a15fa96f 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -538,7 +538,9 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
538 goto drop; 538 goto drop;
539 } 539 }
540 540
541 if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) { 541 skb_dst_drop(skb);
542 rc = sock_queue_rcv_skb(sk, skb);
543 if (rc < 0) {
542 /* Note that an ENOMEM error is charged twice */ 544 /* Note that an ENOMEM error is charged twice */
543 if (rc == -ENOMEM) 545 if (rc == -ENOMEM)
544 UDP6_INC_STATS_BH(sock_net(sk), 546 UDP6_INC_STATS_BH(sock_net(sk),