Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81aded24 authored by David S. Miller's avatar David S. Miller
Browse files

ipv6: Handle PMTU in ICMP error handlers.



One tricky issue on the ipv6 side vs. ipv4 is that the ICMP callouts
to handle the error pass the 32-bit info cookie in network byte order
whereas ipv4 passes it around in host byte order.

Like the ipv4 side, we have two helper functions.  One for when we
have a socket context and one for when we do not.

ip6ip6 tunnels are not handled here, because they handle PMTU events
by essentially relaying another ICMP packet-too-big message back to
the original sender.

This patch allows us to get rid of rt6_do_pmtu_disc().  It handles all
kinds of situations that simply cannot happen when we do the PMTU
update directly using a fully resolved route.

In fact, the "plen == 128" check in ip6_rt_update_pmtu() can very
likely be removed or changed into a BUG_ON() check.  We should never
have a prefixed ipv6 route when we get there.

Another piece of strange history here is that TCP and DCCP, unlike in
ipv4, never invoke the update_pmtu() method from their ICMP error
handlers.  This is incredibly astonishing since this is the context
where we have the most accurate context in which to make a PMTU
update, namely we have a fully connected socket and associated cached
socket route.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 36393395
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -140,10 +140,10 @@ extern void rt6_redirect(const struct in6_addr *dest,
					     u8 *lladdr,
					     int on_link);

extern void			rt6_pmtu_discovery(const struct in6_addr *daddr,
						   const struct in6_addr *saddr,
						   struct net_device *dev,
						   u32 pmtu);
extern void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
			    int oif, u32 mark);
extern void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk,
			       __be32 mtu);

struct netlink_callback;

+2 −0
Original line number Diff line number Diff line
@@ -165,6 +165,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
		} else
			dst_hold(dst);

		dst->ops->update_pmtu(dst, ntohl(info));

		if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
			dccp_sync_mss(sk, dst_mtu(dst));
		} /* else let the usual retransmit timer handle it */
+2 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <linux/pfkeyv2.h>
#include <linux/string.h>
#include <linux/scatterlist.h>
#include <net/ip6_route.h>
#include <net/icmp.h>
#include <net/ipv6.h>
#include <net/protocol.h>
@@ -621,7 +622,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,

	NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/%pI6\n",
		 ntohl(ah->spi), &iph->daddr);

	ip6_update_pmtu(skb, net, info, 0, 0);
	xfrm_state_put(x);
}

+2 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <net/ip6_route.h>
#include <net/icmp.h>
#include <net/ipv6.h>
#include <net/protocol.h>
@@ -442,6 +443,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
		return;
	pr_debug("pmtu discovery on SA ESP/%08x/%pI6\n",
		 ntohl(esph->spi), &iph->daddr);
	ip6_update_pmtu(skb, net, info, 0, 0);
	xfrm_state_put(x);
}

+1 −5
Original line number Diff line number Diff line
@@ -649,7 +649,6 @@ static int icmpv6_rcv(struct sk_buff *skb)
	struct net_device *dev = skb->dev;
	struct inet6_dev *idev = __in6_dev_get(dev);
	const struct in6_addr *saddr, *daddr;
	const struct ipv6hdr *orig_hdr;
	struct icmp6hdr *hdr;
	u8 type;

@@ -661,7 +660,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
				 XFRM_STATE_ICMP))
			goto drop_no_count;

		if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(*orig_hdr)))
		if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr)))
			goto drop_no_count;

		nh = skb_network_offset(skb);
@@ -722,9 +721,6 @@ static int icmpv6_rcv(struct sk_buff *skb)
		if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
			goto discard_it;
		hdr = icmp6_hdr(skb);
		orig_hdr = (struct ipv6hdr *) (hdr + 1);
		rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
				   ntohl(hdr->icmp6_mtu));

		/*
		 *	Drop through to notify
Loading