diff options
-rw-r--r-- | include/net/ip.h | 2 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 35 | ||||
-rw-r--r-- | net/ipv4/raw.c | 3 | ||||
-rw-r--r-- | net/ipv4/udp.c | 3 | ||||
-rw-r--r-- | net/ipv6/raw.c | 3 | ||||
-rw-r--r-- | net/ipv6/udp.c | 4 |
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 | ||
453 | extern int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); | 453 | extern void ipv4_pktinfo_prepare(struct sk_buff *skb); |
454 | extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb); | 454 | extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb); |
455 | extern int ip_cmsg_send(struct net *net, | 455 | extern 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 | ||
59 | static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) | 60 | static 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 | */ |
1002 | int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | 996 | void 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 | } |
1008 | EXPORT_SYMBOL(ip_queue_rcv_skb); | ||
1009 | 1010 | ||
1010 | int ip_setsockopt(struct sock *sk, int level, | 1011 | int 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), |