netfilter: ipv6: move POSTROUTING invocation before fragmentation
Patrick McHardy notes: "We used to invoke IPv4 POST_ROUTING after fragmentation as well just to defragment the packets in conntrack immediately afterwards, but that got changed during the netfilter-ipsec integration. Ideally IPv6 would behave like IPv4." This patch makes it so. Sending an oversized frame (e.g. `ping6 -s64000 -c1 ::1`) will now show up in POSTROUTING as a single skb rather than multiple ones. Signed-off-by: Jan Engelhardt <jengelh@medozas.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
parent
9f93ff5be5
commit
9e50849054
1 changed files with 23 additions and 26 deletions
|
@ -82,22 +82,6 @@ int ip6_local_out(struct sk_buff *skb)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ip6_local_out);
|
||||
|
||||
static int ip6_output_finish(struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
|
||||
if (dst->hh)
|
||||
return neigh_hh_output(dst->hh, skb);
|
||||
else if (dst->neighbour)
|
||||
return dst->neighbour->output(skb);
|
||||
|
||||
IP6_INC_STATS_BH(dev_net(dst->dev),
|
||||
ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
/* dev_loopback_xmit for use with netfilter. */
|
||||
static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
|
||||
{
|
||||
|
@ -111,8 +95,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ip6_output2(struct sk_buff *skb)
|
||||
static int ip6_finish_output2(struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct net_device *dev = dst->dev;
|
||||
|
@ -150,8 +133,15 @@ static int ip6_output2(struct sk_buff *skb)
|
|||
skb->len);
|
||||
}
|
||||
|
||||
return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, skb->dev,
|
||||
ip6_output_finish);
|
||||
if (dst->hh)
|
||||
return neigh_hh_output(dst->hh, skb);
|
||||
else if (dst->neighbour)
|
||||
return dst->neighbour->output(skb);
|
||||
|
||||
IP6_INC_STATS_BH(dev_net(dst->dev),
|
||||
ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
|
||||
|
@ -162,21 +152,28 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
|
|||
skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
|
||||
}
|
||||
|
||||
static int ip6_finish_output(struct sk_buff *skb)
|
||||
{
|
||||
if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
|
||||
dst_allfrag(skb_dst(skb)))
|
||||
return ip6_fragment(skb, ip6_finish_output2);
|
||||
else
|
||||
return ip6_finish_output2(skb);
|
||||
}
|
||||
|
||||
int ip6_output(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb_dst(skb)->dev;
|
||||
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
|
||||
if (unlikely(idev->cnf.disable_ipv6)) {
|
||||
IP6_INC_STATS(dev_net(skb_dst(skb)->dev), idev,
|
||||
IP6_INC_STATS(dev_net(dev), idev,
|
||||
IPSTATS_MIB_OUTDISCARDS);
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
|
||||
dst_allfrag(skb_dst(skb)))
|
||||
return ip6_fragment(skb, ip6_output2);
|
||||
else
|
||||
return ip6_output2(skb);
|
||||
return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev,
|
||||
ip6_finish_output);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue