aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-01-05 15:20:59 -0500
committerDavid S. Miller <davem@davemloft.net>2006-01-05 15:20:59 -0500
commit1bd9bef6f9fe06dd0c628ac877c85b6b36aca062 (patch)
tree60b4bfdd06efc0ab5cf297c470a273f470b7c1f5 /net
parentabbcc73982445c1457901c7fc1d0d110e7a587e3 (diff)
[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>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ip_output.c30
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c26
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c17
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c26
4 files changed, 16 insertions, 83 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 2a830de3a699..71da31818cfc 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -202,13 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)
202 202
203static inline int ip_finish_output(struct sk_buff *skb) 203static inline int ip_finish_output(struct sk_buff *skb)
204{ 204{
205 struct net_device *dev = skb->dst->dev; 205 if (skb->len > dst_mtu(skb->dst) &&
206 206 !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
207 skb->dev = dev; 207 return ip_fragment(skb, ip_finish_output2);
208 skb->protocol = htons(ETH_P_IP); 208 else
209 209 return ip_finish_output2(skb);
210 return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
211 ip_finish_output2);
212} 210}
213 211
214int ip_mc_output(struct sk_buff *skb) 212int ip_mc_output(struct sk_buff *skb)
@@ -265,21 +263,21 @@ int ip_mc_output(struct sk_buff *skb)
265 newskb->dev, ip_dev_loopback_xmit); 263 newskb->dev, ip_dev_loopback_xmit);
266 } 264 }
267 265
268 if (skb->len > dst_mtu(&rt->u.dst)) 266 return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dev,
269 return ip_fragment(skb, ip_finish_output); 267 ip_finish_output);
270 else
271 return ip_finish_output(skb);
272} 268}
273 269
274int ip_output(struct sk_buff *skb) 270int ip_output(struct sk_buff *skb)
275{ 271{
272 struct net_device *dev = skb->dst->dev;
273
276 IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); 274 IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
277 275
278 if (skb->len > dst_mtu(skb->dst) && 276 skb->dev = dev;
279 !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) 277 skb->protocol = htons(ETH_P_IP);
280 return ip_fragment(skb, ip_finish_output); 278
281 else 279 return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
282 return ip_finish_output(skb); 280 ip_finish_output);
283} 281}
284 282
285int ip_queue_xmit(struct sk_buff *skb, int ipfragok) 283int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index a88bcc551244..7ba97783e741 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -451,30 +451,6 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum,
451 return NF_ACCEPT; 451 return NF_ACCEPT;
452} 452}
453 453
454static unsigned int ip_refrag(unsigned int hooknum,
455 struct sk_buff **pskb,
456 const struct net_device *in,
457 const struct net_device *out,
458 int (*okfn)(struct sk_buff *))
459{
460 struct rtable *rt = (struct rtable *)(*pskb)->dst;
461
462 /* We've seen it coming out the other side: confirm */
463 if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
464 return NF_DROP;
465
466 /* Local packets are never produced too large for their
467 interface. We degfragment them at LOCAL_OUT, however,
468 so we have to refragment them here. */
469 if ((*pskb)->len > dst_mtu(&rt->u.dst) &&
470 !skb_shinfo(*pskb)->tso_size) {
471 /* No hook can be after us, so this should be OK. */
472 ip_fragment(*pskb, okfn);
473 return NF_STOLEN;
474 }
475 return NF_ACCEPT;
476}
477
478static unsigned int ip_conntrack_local(unsigned int hooknum, 454static unsigned int ip_conntrack_local(unsigned int hooknum,
479 struct sk_buff **pskb, 455 struct sk_buff **pskb,
480 const struct net_device *in, 456 const struct net_device *in,
@@ -544,7 +520,7 @@ static struct nf_hook_ops ip_conntrack_helper_in_ops = {
544 520
545/* Refragmenter; last chance. */ 521/* Refragmenter; last chance. */
546static struct nf_hook_ops ip_conntrack_out_ops = { 522static struct nf_hook_ops ip_conntrack_out_ops = {
547 .hook = ip_refrag, 523 .hook = ip_confirm,
548 .owner = THIS_MODULE, 524 .owner = THIS_MODULE,
549 .pf = PF_INET, 525 .pf = PF_INET,
550 .hooknum = NF_IP_POST_ROUTING, 526 .hooknum = NF_IP_POST_ROUTING,
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 30cd4e18c129..f04111f74e09 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -190,23 +190,6 @@ ip_nat_out(unsigned int hooknum,
190 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) 190 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
191 return NF_ACCEPT; 191 return NF_ACCEPT;
192 192
193 /* We can hit fragment here; forwarded packets get
194 defragmented by connection tracking coming in, then
195 fragmented (grr) by the forward code.
196
197 In future: If we have nfct != NULL, AND we have NAT
198 initialized, AND there is no helper, then we can do full
199 NAPT on the head, and IP-address-only NAT on the rest.
200
201 I'm starting to have nightmares about fragments. */
202
203 if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
204 *pskb = ip_ct_gather_frags(*pskb, IP_DEFRAG_NAT_OUT);
205
206 if (!*pskb)
207 return NF_STOLEN;
208 }
209
210 return ip_nat_fn(hooknum, pskb, in, out, okfn); 193 return ip_nat_fn(hooknum, pskb, in, out, okfn);
211} 194}
212 195
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 385867efd481..1d36e8effe4f 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -180,30 +180,6 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
180 return NF_ACCEPT; 180 return NF_ACCEPT;
181} 181}
182 182
183static unsigned int ipv4_refrag(unsigned int hooknum,
184 struct sk_buff **pskb,
185 const struct net_device *in,
186 const struct net_device *out,
187 int (*okfn)(struct sk_buff *))
188{
189 struct rtable *rt = (struct rtable *)(*pskb)->dst;
190
191 /* We've seen it coming out the other side: confirm */
192 if (ipv4_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
193 return NF_DROP;
194
195 /* Local packets are never produced too large for their
196 interface. We degfragment them at LOCAL_OUT, however,
197 so we have to refragment them here. */
198 if ((*pskb)->len > dst_mtu(&rt->u.dst) &&
199 !skb_shinfo(*pskb)->tso_size) {
200 /* No hook can be after us, so this should be OK. */
201 ip_fragment(*pskb, okfn);
202 return NF_STOLEN;
203 }
204 return NF_ACCEPT;
205}
206
207static unsigned int ipv4_conntrack_in(unsigned int hooknum, 183static unsigned int ipv4_conntrack_in(unsigned int hooknum,
208 struct sk_buff **pskb, 184 struct sk_buff **pskb,
209 const struct net_device *in, 185 const struct net_device *in,
@@ -283,7 +259,7 @@ static struct nf_hook_ops ipv4_conntrack_helper_in_ops = {
283 259
284/* Refragmenter; last chance. */ 260/* Refragmenter; last chance. */
285static struct nf_hook_ops ipv4_conntrack_out_ops = { 261static struct nf_hook_ops ipv4_conntrack_out_ops = {
286 .hook = ipv4_refrag, 262 .hook = ipv4_confirm,
287 .owner = THIS_MODULE, 263 .owner = THIS_MODULE,
288 .pf = PF_INET, 264 .pf = PF_INET,
289 .hooknum = NF_IP_POST_ROUTING, 265 .hooknum = NF_IP_POST_ROUTING,