mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 23:54:04 +08:00
net: ipv6: listify ipv6_rcv() and ip6_rcv_finish()
Essentially the same as the ipv4 equivalents. Signed-off-by: Edward Cree <ecree@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
efe6aaca67
commit
d8269e2cbf
@ -922,6 +922,8 @@ static inline __be32 flowi6_get_flowlabel(const struct flowi6 *fl6)
|
|||||||
|
|
||||||
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev,
|
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||||
struct packet_type *pt, struct net_device *orig_dev);
|
struct packet_type *pt, struct net_device *orig_dev);
|
||||||
|
void ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
|
||||||
|
struct net_device *orig_dev);
|
||||||
|
|
||||||
int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
|
int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||||
|
|
||||||
|
@ -764,6 +764,7 @@ EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
|
|||||||
static struct packet_type ipv6_packet_type __read_mostly = {
|
static struct packet_type ipv6_packet_type __read_mostly = {
|
||||||
.type = cpu_to_be16(ETH_P_IPV6),
|
.type = cpu_to_be16(ETH_P_IPV6),
|
||||||
.func = ipv6_rcv,
|
.func = ipv6_rcv,
|
||||||
|
.list_func = ipv6_list_rcv,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init ipv6_packet_init(void)
|
static int __init ipv6_packet_init(void)
|
||||||
|
@ -47,17 +47,11 @@
|
|||||||
#include <net/inet_ecn.h>
|
#include <net/inet_ecn.h>
|
||||||
#include <net/dst_metadata.h>
|
#include <net/dst_metadata.h>
|
||||||
|
|
||||||
int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
static void ip6_rcv_finish_core(struct net *net, struct sock *sk,
|
||||||
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
void (*edemux)(struct sk_buff *skb);
|
void (*edemux)(struct sk_buff *skb);
|
||||||
|
|
||||||
/* if ingress device is enslaved to an L3 master device pass the
|
|
||||||
* skb to its handler for processing
|
|
||||||
*/
|
|
||||||
skb = l3mdev_ip6_rcv(skb);
|
|
||||||
if (!skb)
|
|
||||||
return NET_RX_SUCCESS;
|
|
||||||
|
|
||||||
if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) {
|
if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) {
|
||||||
const struct inet6_protocol *ipprot;
|
const struct inet6_protocol *ipprot;
|
||||||
|
|
||||||
@ -67,20 +61,73 @@ int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|||||||
}
|
}
|
||||||
if (!skb_valid_dst(skb))
|
if (!skb_valid_dst(skb))
|
||||||
ip6_route_input(skb);
|
ip6_route_input(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
/* if ingress device is enslaved to an L3 master device pass the
|
||||||
|
* skb to its handler for processing
|
||||||
|
*/
|
||||||
|
skb = l3mdev_ip6_rcv(skb);
|
||||||
|
if (!skb)
|
||||||
|
return NET_RX_SUCCESS;
|
||||||
|
ip6_rcv_finish_core(net, sk, skb);
|
||||||
|
|
||||||
return dst_input(skb);
|
return dst_input(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
|
static void ip6_sublist_rcv_finish(struct list_head *head)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb, *next;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(skb, next, head, list)
|
||||||
|
dst_input(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ip6_list_rcv_finish(struct net *net, struct sock *sk,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
struct dst_entry *curr_dst = NULL;
|
||||||
|
struct sk_buff *skb, *next;
|
||||||
|
struct list_head sublist;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&sublist);
|
||||||
|
list_for_each_entry_safe(skb, next, head, list) {
|
||||||
|
struct dst_entry *dst;
|
||||||
|
|
||||||
|
list_del(&skb->list);
|
||||||
|
/* if ingress device is enslaved to an L3 master device pass the
|
||||||
|
* skb to its handler for processing
|
||||||
|
*/
|
||||||
|
skb = l3mdev_ip6_rcv(skb);
|
||||||
|
if (!skb)
|
||||||
|
continue;
|
||||||
|
ip6_rcv_finish_core(net, sk, skb);
|
||||||
|
dst = skb_dst(skb);
|
||||||
|
if (curr_dst != dst) {
|
||||||
|
/* dispatch old sublist */
|
||||||
|
if (!list_empty(&sublist))
|
||||||
|
ip6_sublist_rcv_finish(&sublist);
|
||||||
|
/* start new sublist */
|
||||||
|
INIT_LIST_HEAD(&sublist);
|
||||||
|
curr_dst = dst;
|
||||||
|
}
|
||||||
|
list_add_tail(&skb->list, &sublist);
|
||||||
|
}
|
||||||
|
/* dispatch final sublist */
|
||||||
|
ip6_sublist_rcv_finish(&sublist);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
|
||||||
|
struct net *net)
|
||||||
{
|
{
|
||||||
const struct ipv6hdr *hdr;
|
const struct ipv6hdr *hdr;
|
||||||
u32 pkt_len;
|
u32 pkt_len;
|
||||||
struct inet6_dev *idev;
|
struct inet6_dev *idev;
|
||||||
struct net *net = dev_net(skb->dev);
|
|
||||||
|
|
||||||
if (skb->pkt_type == PACKET_OTHERHOST) {
|
if (skb->pkt_type == PACKET_OTHERHOST) {
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return NET_RX_DROP;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
@ -196,7 +243,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
|
|||||||
if (ipv6_parse_hopopts(skb) < 0) {
|
if (ipv6_parse_hopopts(skb) < 0) {
|
||||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return NET_RX_DROP;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,15 +252,67 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
|
|||||||
/* Must drop socket now because of tproxy. */
|
/* Must drop socket now because of tproxy. */
|
||||||
skb_orphan(skb);
|
skb_orphan(skb);
|
||||||
|
|
||||||
return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
|
return skb;
|
||||||
net, NULL, skb, dev, NULL,
|
|
||||||
ip6_rcv_finish);
|
|
||||||
err:
|
err:
|
||||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||||
drop:
|
drop:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return NET_RX_DROP;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
|
||||||
|
{
|
||||||
|
struct net *net = dev_net(skb->dev);
|
||||||
|
|
||||||
|
skb = ip6_rcv_core(skb, dev, net);
|
||||||
|
if (skb == NULL)
|
||||||
|
return NET_RX_DROP;
|
||||||
|
return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
|
||||||
|
net, NULL, skb, dev, NULL,
|
||||||
|
ip6_rcv_finish);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ip6_sublist_rcv(struct list_head *head, struct net_device *dev,
|
||||||
|
struct net *net)
|
||||||
|
{
|
||||||
|
NF_HOOK_LIST(NFPROTO_IPV6, NF_INET_PRE_ROUTING, net, NULL,
|
||||||
|
head, dev, NULL, ip6_rcv_finish);
|
||||||
|
ip6_list_rcv_finish(net, NULL, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive a list of IPv6 packets */
|
||||||
|
void ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
|
||||||
|
struct net_device *orig_dev)
|
||||||
|
{
|
||||||
|
struct net_device *curr_dev = NULL;
|
||||||
|
struct net *curr_net = NULL;
|
||||||
|
struct sk_buff *skb, *next;
|
||||||
|
struct list_head sublist;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&sublist);
|
||||||
|
list_for_each_entry_safe(skb, next, head, list) {
|
||||||
|
struct net_device *dev = skb->dev;
|
||||||
|
struct net *net = dev_net(dev);
|
||||||
|
|
||||||
|
list_del(&skb->list);
|
||||||
|
skb = ip6_rcv_core(skb, dev, net);
|
||||||
|
if (skb == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (curr_dev != dev || curr_net != net) {
|
||||||
|
/* dispatch old sublist */
|
||||||
|
if (!list_empty(&sublist))
|
||||||
|
ip6_sublist_rcv(&sublist, curr_dev, curr_net);
|
||||||
|
/* start new sublist */
|
||||||
|
INIT_LIST_HEAD(&sublist);
|
||||||
|
curr_dev = dev;
|
||||||
|
curr_net = net;
|
||||||
|
}
|
||||||
|
list_add_tail(&skb->list, &sublist);
|
||||||
|
}
|
||||||
|
/* dispatch final sublist */
|
||||||
|
ip6_sublist_rcv(&sublist, curr_dev, curr_net);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user