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, |
