aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@medozas.de>2010-04-13 09:28:11 -0400
committerPatrick McHardy <kaber@trash.net>2010-04-13 09:28:11 -0400
commit9e50849054a4824f06c66d2b449de21b98e03770 (patch)
treec5b48b8786af6111373d8646c5920c67a7002b97 /net/ipv6/ip6_output.c
parent9f93ff5be54108066372d1c4100c515d9d9acc1b (diff)
netfilter: ipv6: move POSTROUTING invocation before fragmentation
Patrick McHardy notes: "We used to invoke IPv4 POST_ROUTING after fragmentation as well just to defragment the packets in conntrack immediately afterwards, but that got changed during the netfilter-ipsec integration. Ideally IPv6 would behave like IPv4." This patch makes it so. Sending an oversized frame (e.g. `ping6 -s64000 -c1 ::1`) will now show up in POSTROUTING as a single skb rather than multiple ones. Signed-off-by: Jan Engelhardt <jengelh@medozas.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c49
1 files changed, 23 insertions, 26 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 4535b7a0169b..236ac7813744 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -82,22 +82,6 @@ int ip6_local_out(struct sk_buff *skb)
82} 82}
83EXPORT_SYMBOL_GPL(ip6_local_out); 83EXPORT_SYMBOL_GPL(ip6_local_out);
84 84
85static int ip6_output_finish(struct sk_buff *skb)
86{
87 struct dst_entry *dst = skb_dst(skb);
88
89 if (dst->hh)
90 return neigh_hh_output(dst->hh, skb);
91 else if (dst->neighbour)
92 return dst->neighbour->output(skb);
93
94 IP6_INC_STATS_BH(dev_net(dst->dev),
95 ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
96 kfree_skb(skb);
97 return -EINVAL;
98
99}
100
101/* dev_loopback_xmit for use with netfilter. */ 85/* dev_loopback_xmit for use with netfilter. */
102static int ip6_dev_loopback_xmit(struct sk_buff *newskb) 86static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
103{ 87{
@@ -111,8 +95,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
111 return 0; 95 return 0;
112} 96}
113 97
114 98static int ip6_finish_output2(struct sk_buff *skb)
115static int ip6_output2(struct sk_buff *skb)
116{ 99{
117 struct dst_entry *dst = skb_dst(skb); 100 struct dst_entry *dst = skb_dst(skb);
118 struct net_device *dev = dst->dev; 101 struct net_device *dev = dst->dev;
@@ -150,8 +133,15 @@ static int ip6_output2(struct sk_buff *skb)
150 skb->len); 133 skb->len);
151 } 134 }
152 135
153 return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, skb->dev, 136 if (dst->hh)
154 ip6_output_finish); 137 return neigh_hh_output(dst->hh, skb);
138 else if (dst->neighbour)
139 return dst->neighbour->output(skb);
140
141 IP6_INC_STATS_BH(dev_net(dst->dev),
142 ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
143 kfree_skb(skb);
144 return -EINVAL;
155} 145}
156 146
157static inline int ip6_skb_dst_mtu(struct sk_buff *skb) 147static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
@@ -162,21 +152,28 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
162 skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); 152 skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
163} 153}
164 154
155static int ip6_finish_output(struct sk_buff *skb)
156{
157 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
158 dst_allfrag(skb_dst(skb)))
159 return ip6_fragment(skb, ip6_finish_output2);
160 else
161 return ip6_finish_output2(skb);
162}
163
165int ip6_output(struct sk_buff *skb) 164int ip6_output(struct sk_buff *skb)
166{ 165{
166 struct net_device *dev = skb_dst(skb)->dev;
167 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); 167 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
168 if (unlikely(idev->cnf.disable_ipv6)) { 168 if (unlikely(idev->cnf.disable_ipv6)) {
169 IP6_INC_STATS(dev_net(skb_dst(skb)->dev), idev, 169 IP6_INC_STATS(dev_net(dev), idev,
170 IPSTATS_MIB_OUTDISCARDS); 170 IPSTATS_MIB_OUTDISCARDS);
171 kfree_skb(skb); 171 kfree_skb(skb);
172 return 0; 172 return 0;
173 } 173 }
174 174
175 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || 175 return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev,
176 dst_allfrag(skb_dst(skb))) 176 ip6_finish_output);
177 return ip6_fragment(skb, ip6_output2);
178 else
179 return ip6_output2(skb);
180} 177}
181 178
182/* 179/*