aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2014-01-09 04:01:16 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-13 14:22:54 -0500
commit0954cf9c6141d597929a292b93a2dca2c1f29159 (patch)
treeacdc5ca06a9eda83c5094254fd6bfd67cbe9bdc5
parentf87c10a8aa1e82498c42d0335524d6ae7cf5a52b (diff)
ipv6: introduce ip6_dst_mtu_forward and protect forwarding path with it
In the IPv6 forwarding path we are only concerend about the outgoing interface MTU, but also respect locked MTUs on routes. Tunnel provider or IPSEC already have to recheck and if needed send PtB notifications to the sending host in case the data does not fit into the packet with added headers (we only know the final header sizes there, while also using path MTU information). The reason for this change is, that path MTU information can be injected into the kernel via e.g. icmp_err protocol handler without verification of local sockets. As such, this could cause the IPv6 forwarding path to wrongfully emit Packet-too-Big errors and drop IPv6 packets. Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: David Miller <davem@davemloft.net> Cc: John Heffner <johnwheffner@gmail.com> Cc: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/ip6_output.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index d1de9560c421..ef02b26ccf81 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -321,6 +321,27 @@ static inline int ip6_forward_finish(struct sk_buff *skb)
321 return dst_output(skb); 321 return dst_output(skb);
322} 322}
323 323
324static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
325{
326 unsigned int mtu;
327 struct inet6_dev *idev;
328
329 if (dst_metric_locked(dst, RTAX_MTU)) {
330 mtu = dst_metric_raw(dst, RTAX_MTU);
331 if (mtu)
332 return mtu;
333 }
334
335 mtu = IPV6_MIN_MTU;
336 rcu_read_lock();
337 idev = __in6_dev_get(dst->dev);
338 if (idev)
339 mtu = idev->cnf.mtu6;
340 rcu_read_unlock();
341
342 return mtu;
343}
344
324int ip6_forward(struct sk_buff *skb) 345int ip6_forward(struct sk_buff *skb)
325{ 346{
326 struct dst_entry *dst = skb_dst(skb); 347 struct dst_entry *dst = skb_dst(skb);
@@ -441,7 +462,7 @@ int ip6_forward(struct sk_buff *skb)
441 } 462 }
442 } 463 }
443 464
444 mtu = dst_mtu(dst); 465 mtu = ip6_dst_mtu_forward(dst);
445 if (mtu < IPV6_MIN_MTU) 466 if (mtu < IPV6_MIN_MTU)
446 mtu = IPV6_MIN_MTU; 467 mtu = IPV6_MIN_MTU;
447 468