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

Merge branch 'IP-listification-follow-ups'

Edward Cree says:

====================
IP listification follow-ups

While working on IPv6 list processing, I found another bug in the IPv4
version. So this patch series has that fix, and the IPv6 version with
both fixes incorporated.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+133 -24
+2
include/net/ipv6.h
··· 922 922 923 923 int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, 924 924 struct packet_type *pt, struct net_device *orig_dev); 925 + void ipv6_list_rcv(struct list_head *head, struct packet_type *pt, 926 + struct net_device *orig_dev); 925 927 926 928 int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb); 927 929
+15 -8
net/ipv4/ip_input.c
··· 316 316 struct rtable *rt; 317 317 int err; 318 318 319 - /* if ingress device is enslaved to an L3 master device pass the 320 - * skb to its handler for processing 321 - */ 322 - skb = l3mdev_ip_rcv(skb); 323 - if (!skb) 324 - return NET_RX_SUCCESS; 325 - 326 319 if (net->ipv4.sysctl_ip_early_demux && 327 320 !skb_dst(skb) && 328 321 !skb->sk && ··· 401 408 402 409 static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 403 410 { 404 - int ret = ip_rcv_finish_core(net, sk, skb); 411 + int ret; 405 412 413 + /* if ingress device is enslaved to an L3 master device pass the 414 + * skb to its handler for processing 415 + */ 416 + skb = l3mdev_ip_rcv(skb); 417 + if (!skb) 418 + return NET_RX_SUCCESS; 419 + 420 + ret = ip_rcv_finish_core(net, sk, skb); 406 421 if (ret != NET_RX_DROP) 407 422 ret = dst_input(skb); 408 423 return ret; ··· 546 545 struct dst_entry *dst; 547 546 548 547 list_del(&skb->list); 548 + /* if ingress device is enslaved to an L3 master device pass the 549 + * skb to its handler for processing 550 + */ 551 + skb = l3mdev_ip_rcv(skb); 552 + if (!skb) 553 + continue; 549 554 if (ip_rcv_finish_core(net, sk, skb) == NET_RX_DROP) 550 555 continue; 551 556
+1
net/ipv6/af_inet6.c
··· 764 764 static struct packet_type ipv6_packet_type __read_mostly = { 765 765 .type = cpu_to_be16(ETH_P_IPV6), 766 766 .func = ipv6_rcv, 767 + .list_func = ipv6_list_rcv, 767 768 }; 768 769 769 770 static int __init ipv6_packet_init(void)
+115 -16
net/ipv6/ip6_input.c
··· 47 47 #include <net/inet_ecn.h> 48 48 #include <net/dst_metadata.h> 49 49 50 - int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 50 + static void ip6_rcv_finish_core(struct net *net, struct sock *sk, 51 + struct sk_buff *skb) 51 52 { 52 53 void (*edemux)(struct sk_buff *skb); 53 - 54 - /* if ingress device is enslaved to an L3 master device pass the 55 - * skb to its handler for processing 56 - */ 57 - skb = l3mdev_ip6_rcv(skb); 58 - if (!skb) 59 - return NET_RX_SUCCESS; 60 54 61 55 if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) { 62 56 const struct inet6_protocol *ipprot; ··· 61 67 } 62 68 if (!skb_valid_dst(skb)) 63 69 ip6_route_input(skb); 70 + } 71 + 72 + int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 73 + { 74 + /* if ingress device is enslaved to an L3 master device pass the 75 + * skb to its handler for processing 76 + */ 77 + skb = l3mdev_ip6_rcv(skb); 78 + if (!skb) 79 + return NET_RX_SUCCESS; 80 + ip6_rcv_finish_core(net, sk, skb); 64 81 65 82 return dst_input(skb); 66 83 } 67 84 68 - int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) 85 + static void ip6_sublist_rcv_finish(struct list_head *head) 86 + { 87 + struct sk_buff *skb, *next; 88 + 89 + list_for_each_entry_safe(skb, next, head, list) 90 + dst_input(skb); 91 + } 92 + 93 + static void ip6_list_rcv_finish(struct net *net, struct sock *sk, 94 + struct list_head *head) 95 + { 96 + struct dst_entry *curr_dst = NULL; 97 + struct sk_buff *skb, *next; 98 + struct list_head sublist; 99 + 100 + INIT_LIST_HEAD(&sublist); 101 + list_for_each_entry_safe(skb, next, head, list) { 102 + struct dst_entry *dst; 103 + 104 + list_del(&skb->list); 105 + /* if ingress device is enslaved to an L3 master device pass the 106 + * skb to its handler for processing 107 + */ 108 + skb = l3mdev_ip6_rcv(skb); 109 + if (!skb) 110 + continue; 111 + ip6_rcv_finish_core(net, sk, skb); 112 + dst = skb_dst(skb); 113 + if (curr_dst != dst) { 114 + /* dispatch old sublist */ 115 + if (!list_empty(&sublist)) 116 + ip6_sublist_rcv_finish(&sublist); 117 + /* start new sublist */ 118 + INIT_LIST_HEAD(&sublist); 119 + curr_dst = dst; 120 + } 121 + list_add_tail(&skb->list, &sublist); 122 + } 123 + /* dispatch final sublist */ 124 + ip6_sublist_rcv_finish(&sublist); 125 + } 126 + 127 + static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, 128 + struct net *net) 69 129 { 70 130 const struct ipv6hdr *hdr; 71 131 u32 pkt_len; 72 132 struct inet6_dev *idev; 73 - struct net *net = dev_net(skb->dev); 74 133 75 134 if (skb->pkt_type == PACKET_OTHERHOST) { 76 135 kfree_skb(skb); 77 - return NET_RX_DROP; 136 + return NULL; 78 137 } 79 138 80 139 rcu_read_lock(); ··· 243 196 if (ipv6_parse_hopopts(skb) < 0) { 244 197 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 245 198 rcu_read_unlock(); 246 - return NET_RX_DROP; 199 + return NULL; 247 200 } 248 201 } 249 202 ··· 252 205 /* Must drop socket now because of tproxy. */ 253 206 skb_orphan(skb); 254 207 255 - return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, 256 - net, NULL, skb, dev, NULL, 257 - ip6_rcv_finish); 208 + return skb; 258 209 err: 259 210 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 260 211 drop: 261 212 rcu_read_unlock(); 262 213 kfree_skb(skb); 263 - return NET_RX_DROP; 214 + return NULL; 215 + } 216 + 217 + int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) 218 + { 219 + struct net *net = dev_net(skb->dev); 220 + 221 + skb = ip6_rcv_core(skb, dev, net); 222 + if (skb == NULL) 223 + return NET_RX_DROP; 224 + return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, 225 + net, NULL, skb, dev, NULL, 226 + ip6_rcv_finish); 227 + } 228 + 229 + static void ip6_sublist_rcv(struct list_head *head, struct net_device *dev, 230 + struct net *net) 231 + { 232 + NF_HOOK_LIST(NFPROTO_IPV6, NF_INET_PRE_ROUTING, net, NULL, 233 + head, dev, NULL, ip6_rcv_finish); 234 + ip6_list_rcv_finish(net, NULL, head); 235 + } 236 + 237 + /* Receive a list of IPv6 packets */ 238 + void ipv6_list_rcv(struct list_head *head, struct packet_type *pt, 239 + struct net_device *orig_dev) 240 + { 241 + struct net_device *curr_dev = NULL; 242 + struct net *curr_net = NULL; 243 + struct sk_buff *skb, *next; 244 + struct list_head sublist; 245 + 246 + INIT_LIST_HEAD(&sublist); 247 + list_for_each_entry_safe(skb, next, head, list) { 248 + struct net_device *dev = skb->dev; 249 + struct net *net = dev_net(dev); 250 + 251 + list_del(&skb->list); 252 + skb = ip6_rcv_core(skb, dev, net); 253 + if (skb == NULL) 254 + continue; 255 + 256 + if (curr_dev != dev || curr_net != net) { 257 + /* dispatch old sublist */ 258 + if (!list_empty(&sublist)) 259 + ip6_sublist_rcv(&sublist, curr_dev, curr_net); 260 + /* start new sublist */ 261 + INIT_LIST_HEAD(&sublist); 262 + curr_dev = dev; 263 + curr_net = net; 264 + } 265 + list_add_tail(&skb->list, &sublist); 266 + } 267 + /* dispatch final sublist */ 268 + ip6_sublist_rcv(&sublist, curr_dev, curr_net); 264 269 } 265 270 266 271 /*