[NETFILTER]: Call POST_ROUTING hook before fragmentation
Call POST_ROUTING hook before fragmentation to get rid of the okfn use in ip_refrag and save the useless fragmentation/defragmentation step when NAT is used. The patch introduces one user-visible change, the POSTROUTING chain in the mangle table gets entire packets, not fragments, which should simplify use of the MARK and CLASSIFY targets for queueing as a nice side-effect. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
abbcc73982
commit
1bd9bef6f9
5 changed files with 16 additions and 84 deletions
|
@ -317,7 +317,6 @@ enum ip_defrag_users
|
||||||
IP_DEFRAG_CALL_RA_CHAIN,
|
IP_DEFRAG_CALL_RA_CHAIN,
|
||||||
IP_DEFRAG_CONNTRACK_IN,
|
IP_DEFRAG_CONNTRACK_IN,
|
||||||
IP_DEFRAG_CONNTRACK_OUT,
|
IP_DEFRAG_CONNTRACK_OUT,
|
||||||
IP_DEFRAG_NAT_OUT,
|
|
||||||
IP_DEFRAG_VS_IN,
|
IP_DEFRAG_VS_IN,
|
||||||
IP_DEFRAG_VS_OUT,
|
IP_DEFRAG_VS_OUT,
|
||||||
IP_DEFRAG_VS_FWD
|
IP_DEFRAG_VS_FWD
|
||||||
|
|
|
@ -202,13 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)
|
||||||
|
|
||||||
static inline int ip_finish_output(struct sk_buff *skb)
|
static inline int ip_finish_output(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct net_device *dev = skb->dst->dev;
|
if (skb->len > dst_mtu(skb->dst) &&
|
||||||
|
!(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
|
||||||
skb->dev = dev;
|
return ip_fragment(skb, ip_finish_output2);
|
||||||
skb->protocol = htons(ETH_P_IP);
|
else
|
||||||
|
return ip_finish_output2(skb);
|
||||||
return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
|
|
||||||
ip_finish_output2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ip_mc_output(struct sk_buff *skb)
|
int ip_mc_output(struct sk_buff *skb)
|
||||||
|
@ -265,21 +263,21 @@ int ip_mc_output(struct sk_buff *skb)
|
||||||
newskb->dev, ip_dev_loopback_xmit);
|
newskb->dev, ip_dev_loopback_xmit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skb->len > dst_mtu(&rt->u.dst))
|
return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dev,
|
||||||
return ip_fragment(skb, ip_finish_output);
|
ip_finish_output);
|
||||||
else
|
|
||||||
return ip_finish_output(skb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ip_output(struct sk_buff *skb)
|
int ip_output(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
struct net_device *dev = skb->dst->dev;
|
||||||
|
|
||||||
IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
|
IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
|
||||||
|
|
||||||
if (skb->len > dst_mtu(skb->dst) &&
|
skb->dev = dev;
|
||||||
!(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
|
skb->protocol = htons(ETH_P_IP);
|
||||||
return ip_fragment(skb, ip_finish_output);
|
|
||||||
else
|
return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
|
||||||
return ip_finish_output(skb);
|
ip_finish_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
|
int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
|
||||||
|
|
|
@ -451,30 +451,6 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum,
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int ip_refrag(unsigned int hooknum,
|
|
||||||
struct sk_buff **pskb,
|
|
||||||
const struct net_device *in,
|
|
||||||
const struct net_device *out,
|
|
||||||
int (*okfn)(struct sk_buff *))
|
|
||||||
{
|
|
||||||
struct rtable *rt = (struct rtable *)(*pskb)->dst;
|
|
||||||
|
|
||||||
/* We've seen it coming out the other side: confirm */
|
|
||||||
if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
|
|
||||||
return NF_DROP;
|
|
||||||
|
|
||||||
/* Local packets are never produced too large for their
|
|
||||||
interface. We degfragment them at LOCAL_OUT, however,
|
|
||||||
so we have to refragment them here. */
|
|
||||||
if ((*pskb)->len > dst_mtu(&rt->u.dst) &&
|
|
||||||
!skb_shinfo(*pskb)->tso_size) {
|
|
||||||
/* No hook can be after us, so this should be OK. */
|
|
||||||
ip_fragment(*pskb, okfn);
|
|
||||||
return NF_STOLEN;
|
|
||||||
}
|
|
||||||
return NF_ACCEPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int ip_conntrack_local(unsigned int hooknum,
|
static unsigned int ip_conntrack_local(unsigned int hooknum,
|
||||||
struct sk_buff **pskb,
|
struct sk_buff **pskb,
|
||||||
const struct net_device *in,
|
const struct net_device *in,
|
||||||
|
@ -544,7 +520,7 @@ static struct nf_hook_ops ip_conntrack_helper_in_ops = {
|
||||||
|
|
||||||
/* Refragmenter; last chance. */
|
/* Refragmenter; last chance. */
|
||||||
static struct nf_hook_ops ip_conntrack_out_ops = {
|
static struct nf_hook_ops ip_conntrack_out_ops = {
|
||||||
.hook = ip_refrag,
|
.hook = ip_confirm,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.pf = PF_INET,
|
.pf = PF_INET,
|
||||||
.hooknum = NF_IP_POST_ROUTING,
|
.hooknum = NF_IP_POST_ROUTING,
|
||||||
|
|
|
@ -190,23 +190,6 @@ ip_nat_out(unsigned int hooknum,
|
||||||
|| (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
|
|| (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
|
||||||
/* We can hit fragment here; forwarded packets get
|
|
||||||
defragmented by connection tracking coming in, then
|
|
||||||
fragmented (grr) by the forward code.
|
|
||||||
|
|
||||||
In future: If we have nfct != NULL, AND we have NAT
|
|
||||||
initialized, AND there is no helper, then we can do full
|
|
||||||
NAPT on the head, and IP-address-only NAT on the rest.
|
|
||||||
|
|
||||||
I'm starting to have nightmares about fragments. */
|
|
||||||
|
|
||||||
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
|
|
||||||
*pskb = ip_ct_gather_frags(*pskb, IP_DEFRAG_NAT_OUT);
|
|
||||||
|
|
||||||
if (!*pskb)
|
|
||||||
return NF_STOLEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ip_nat_fn(hooknum, pskb, in, out, okfn);
|
return ip_nat_fn(hooknum, pskb, in, out, okfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,30 +180,6 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int ipv4_refrag(unsigned int hooknum,
|
|
||||||
struct sk_buff **pskb,
|
|
||||||
const struct net_device *in,
|
|
||||||
const struct net_device *out,
|
|
||||||
int (*okfn)(struct sk_buff *))
|
|
||||||
{
|
|
||||||
struct rtable *rt = (struct rtable *)(*pskb)->dst;
|
|
||||||
|
|
||||||
/* We've seen it coming out the other side: confirm */
|
|
||||||
if (ipv4_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
|
|
||||||
return NF_DROP;
|
|
||||||
|
|
||||||
/* Local packets are never produced too large for their
|
|
||||||
interface. We degfragment them at LOCAL_OUT, however,
|
|
||||||
so we have to refragment them here. */
|
|
||||||
if ((*pskb)->len > dst_mtu(&rt->u.dst) &&
|
|
||||||
!skb_shinfo(*pskb)->tso_size) {
|
|
||||||
/* No hook can be after us, so this should be OK. */
|
|
||||||
ip_fragment(*pskb, okfn);
|
|
||||||
return NF_STOLEN;
|
|
||||||
}
|
|
||||||
return NF_ACCEPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int ipv4_conntrack_in(unsigned int hooknum,
|
static unsigned int ipv4_conntrack_in(unsigned int hooknum,
|
||||||
struct sk_buff **pskb,
|
struct sk_buff **pskb,
|
||||||
const struct net_device *in,
|
const struct net_device *in,
|
||||||
|
@ -283,7 +259,7 @@ static struct nf_hook_ops ipv4_conntrack_helper_in_ops = {
|
||||||
|
|
||||||
/* Refragmenter; last chance. */
|
/* Refragmenter; last chance. */
|
||||||
static struct nf_hook_ops ipv4_conntrack_out_ops = {
|
static struct nf_hook_ops ipv4_conntrack_out_ops = {
|
||||||
.hook = ipv4_refrag,
|
.hook = ipv4_confirm,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.pf = PF_INET,
|
.pf = PF_INET,
|
||||||
.hooknum = NF_IP_POST_ROUTING,
|
.hooknum = NF_IP_POST_ROUTING,
|
||||||
|
|
Loading…
Reference in a new issue