diff options
author | Patrick McHardy <kaber@trash.net> | 2006-01-05 15:20:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-01-05 15:20:59 -0500 |
commit | 1bd9bef6f9fe06dd0c628ac877c85b6b36aca062 (patch) | |
tree | 60b4bfdd06efc0ab5cf297c470a273f470b7c1f5 | |
parent | abbcc73982445c1457901c7fc1d0d110e7a587e3 (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>
-rw-r--r-- | include/net/ip.h | 1 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 30 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_conntrack_standalone.c | 26 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_nat_standalone.c | 17 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 26 |
5 files changed, 16 insertions, 84 deletions
diff --git a/include/net/ip.h b/include/net/ip.h index f7e7fd728b67..7bb5804847f2 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -317,7 +317,6 @@ enum ip_defrag_users | |||
317 | IP_DEFRAG_CALL_RA_CHAIN, | 317 | IP_DEFRAG_CALL_RA_CHAIN, |
318 | IP_DEFRAG_CONNTRACK_IN, | 318 | IP_DEFRAG_CONNTRACK_IN, |
319 | IP_DEFRAG_CONNTRACK_OUT, | 319 | IP_DEFRAG_CONNTRACK_OUT, |
320 | IP_DEFRAG_NAT_OUT, | ||
321 | IP_DEFRAG_VS_IN, | 320 | IP_DEFRAG_VS_IN, |
322 | IP_DEFRAG_VS_OUT, | 321 | IP_DEFRAG_VS_OUT, |
323 | IP_DEFRAG_VS_FWD | 322 | IP_DEFRAG_VS_FWD |
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 | ||
203 | static inline int ip_finish_output(struct sk_buff *skb) | 203 | static 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 | ||
214 | int ip_mc_output(struct sk_buff *skb) | 212 | int 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 | ||
274 | int ip_output(struct sk_buff *skb) | 270 | int 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 | ||
285 | int ip_queue_xmit(struct sk_buff *skb, int ipfragok) | 283 | int 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 | ||
454 | static 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 | |||
478 | static unsigned int ip_conntrack_local(unsigned int hooknum, | 454 | static 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. */ |
546 | static struct nf_hook_ops ip_conntrack_out_ops = { | 522 | static 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 | ||
183 | static 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 | |||
207 | static unsigned int ipv4_conntrack_in(unsigned int hooknum, | 183 | static 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. */ |
285 | static struct nf_hook_ops ipv4_conntrack_out_ops = { | 261 | static 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, |