diff options
| author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2014-02-26 01:20:43 +0100 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-02-26 15:51:01 -0500 | 
| commit | 0b95227a7ba7e69f795757cd7c839eff0615f2d1 (patch) | |
| tree | c7e343f11b05e29cf4d9ccc4b2026f0002fd78f7 | |
| parent | 1b346576359c72bee34b1476b4fc63d77d37b314 (diff) | |
ipv6: yet another new IPV6_MTU_DISCOVER option IPV6_PMTUDISC_OMIT
This option has the same semantic as IP_PMTUDISC_OMIT for IPv4 which
got recently introduced. It doesn't honor the path mtu discovered by the
host but in contrary to IPV6_PMTUDISC_INTERFACE allows the generation of
fragments if the packet size exceeds the MTU of the outgoing interface
MTU.
Fixes: 93b36cf3425b9b ("ipv6: support IPV6_PMTU_INTERFACE on sockets")
Cc: Florian Weimer <fweimer@redhat.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/ip6_route.h | 9 | ||||
| -rw-r--r-- | include/uapi/linux/in6.h | 4 | ||||
| -rw-r--r-- | net/ipv6/ip6_output.c | 9 | ||||
| -rw-r--r-- | net/ipv6/ipv6_sockglue.c | 2 | 
4 files changed, 18 insertions, 6 deletions
| diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 017badb1aec7..00e3f12cb2f9 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -171,7 +171,14 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)  static inline bool ip6_sk_accept_pmtu(const struct sock *sk)  { -	return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE; +	return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE && +	       inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_OMIT; +} + +static inline bool ip6_sk_local_df(const struct sock *sk) +{ +	return inet6_sk(sk)->pmtudisc < IPV6_PMTUDISC_DO || +	       inet6_sk(sk)->pmtudisc == IPV6_PMTUDISC_OMIT;  }  static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt) diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h index e9a1d2d973b6..0d8e0f0342dc 100644 --- a/include/uapi/linux/in6.h +++ b/include/uapi/linux/in6.h @@ -185,6 +185,10 @@ struct in6_flowlabel_req {   * also see comments on IP_PMTUDISC_INTERFACE   */  #define IPV6_PMTUDISC_INTERFACE		4 +/* weaker version of IPV6_PMTUDISC_INTERFACE, which allows packets to + * get fragmented if they exceed the interface mtu + */ +#define IPV6_PMTUDISC_OMIT		5  /* Flowlabel */  #define IPV6_FLOWLABEL_MGR	32 diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 070a2fae2375..be1b7f5a3a54 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1234,8 +1234,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,  			      sizeof(struct frag_hdr) : 0) +  			     rt->rt6i_nfheader_len; -		maxnonfragsize = (np->pmtudisc >= IPV6_PMTUDISC_DO) ? -				 mtu : sizeof(struct ipv6hdr) + IPV6_MAXPLEN; +		if (ip6_sk_local_df(sk)) +			maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN; +		else +			maxnonfragsize = mtu;  		/* dontfrag active */  		if ((cork->length + length > mtu - headersize) && dontfrag && @@ -1543,8 +1545,7 @@ int ip6_push_pending_frames(struct sock *sk)  	}  	/* Allow local fragmentation. */ -	if (np->pmtudisc < IPV6_PMTUDISC_DO) -		skb->local_df = 1; +	skb->local_df = ip6_sk_local_df(sk);  	*final_dst = fl6->daddr;  	__skb_pull(skb, skb_network_header_len(skb)); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 0a00f449de5e..edb58aff4ae7 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -722,7 +722,7 @@ done:  	case IPV6_MTU_DISCOVER:  		if (optlen < sizeof(int))  			goto e_inval; -		if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_INTERFACE) +		if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT)  			goto e_inval;  		np->pmtudisc = val;  		retv = 0; | 
