[NETFILTER]: Call POST_ROUTING hook before fragmentation
authorPatrick McHardy <kaber@trash.net>
Thu, 5 Jan 2006 20:20:59 +0000 (12:20 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 5 Jan 2006 20:20:59 +0000 (12:20 -0800)
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>
include/net/ip.h
net/ipv4/ip_output.c
net/ipv4/netfilter/ip_conntrack_standalone.c
net/ipv4/netfilter/ip_nat_standalone.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c

index f7e7fd728b67049a42f6e6f8a2b82bd4dd7b7c2e..7bb5804847f29d2ea457383cdce7b0929e16a65a 100644 (file)
@@ -317,7 +317,6 @@ enum ip_defrag_users
        IP_DEFRAG_CALL_RA_CHAIN,
        IP_DEFRAG_CONNTRACK_IN,
        IP_DEFRAG_CONNTRACK_OUT,
-       IP_DEFRAG_NAT_OUT,
        IP_DEFRAG_VS_IN,
        IP_DEFRAG_VS_OUT,
        IP_DEFRAG_VS_FWD
index 2a830de3a6993cf47bf42d60c8ea409f3baaab7d..71da31818cfc434473678fe149c1c9b9c692cdf8 100644 (file)
@@ -202,13 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)
 
 static inline int ip_finish_output(struct sk_buff *skb)
 {
-       struct net_device *dev = skb->dst->dev;
-
-       skb->dev = dev;
-       skb->protocol = htons(ETH_P_IP);
-
-       return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
-                      ip_finish_output2);
+       if (skb->len > dst_mtu(skb->dst) &&
+           !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
+               return ip_fragment(skb, ip_finish_output2);
+       else
+               return ip_finish_output2(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);
        }
 
-       if (skb->len > dst_mtu(&rt->u.dst))
-               return ip_fragment(skb, ip_finish_output);
-       else
-               return ip_finish_output(skb);
+       return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dev,
+                      ip_finish_output);
 }
 
 int ip_output(struct sk_buff *skb)
 {
+       struct net_device *dev = skb->dst->dev;
+
        IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
 
-       if (skb->len > dst_mtu(skb->dst) &&
-               !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
-               return ip_fragment(skb, ip_finish_output);
-       else
-               return ip_finish_output(skb);
+       skb->dev = dev;
+       skb->protocol = htons(ETH_P_IP);
+
+       return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
+                      ip_finish_output);
 }
 
 int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
index a88bcc551244129ae5df46681374c47f9d07b106..7ba97783e741408edc194ea3f571475c3d5e88de 100644 (file)
@@ -451,30 +451,6 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum,
        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,
                                       struct sk_buff **pskb,
                                       const struct net_device *in,
@@ -544,7 +520,7 @@ static struct nf_hook_ops ip_conntrack_helper_in_ops = {
 
 /* Refragmenter; last chance. */
 static struct nf_hook_ops ip_conntrack_out_ops = {
-       .hook           = ip_refrag,
+       .hook           = ip_confirm,
        .owner          = THIS_MODULE,
        .pf             = PF_INET,
        .hooknum        = NF_IP_POST_ROUTING,
index 30cd4e18c129e8904acbcedd8b1233762e0196c0..f04111f74e090dcde7e9b481277c28e6f05d9e0e 100644 (file)
@@ -190,23 +190,6 @@ ip_nat_out(unsigned int hooknum,
            || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
                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);
 }
 
index 385867efd4812f8633bc05cd51774a1e3fc2d892..1d36e8effe4fa73c32066afeab685d0780cc39b3 100644 (file)
@@ -180,30 +180,6 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
        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,
                                      struct sk_buff **pskb,
                                      const struct net_device *in,
@@ -283,7 +259,7 @@ static struct nf_hook_ops ipv4_conntrack_helper_in_ops = {
 
 /* Refragmenter; last chance. */
 static struct nf_hook_ops ipv4_conntrack_out_ops = {
-       .hook           = ipv4_refrag,
+       .hook           = ipv4_confirm,
        .owner          = THIS_MODULE,
        .pf             = PF_INET,
        .hooknum        = NF_IP_POST_ROUTING,