forked from mirrors/linux
		
	ipv6: tcp: enable flowlabel reflection in some RST packets
When RST packets are sent because no socket could be found,
it makes sense to use flowlabel_reflect sysctl to decide
if a reflection of the flowlabel is requested.
This extends commit 22b6722bfa ("ipv6: Add sysctl for per
namespace flow label reflection"), for some TCP RST packets.
In order to provide full control of this new feature,
flowlabel_reflect becomes a bitmask.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									e736bf72af
								
							
						
					
					
						commit
						323a53c412
					
				
					 4 changed files with 29 additions and 9 deletions
				
			
		|  | @ -1429,14 +1429,24 @@ flowlabel_state_ranges - BOOLEAN | ||||||
| 	FALSE: disabled | 	FALSE: disabled | ||||||
| 	Default: true | 	Default: true | ||||||
| 
 | 
 | ||||||
| flowlabel_reflect - BOOLEAN | flowlabel_reflect - INTEGER | ||||||
| 	Automatically reflect the flow label. Needed for Path MTU | 	Control flow label reflection. Needed for Path MTU | ||||||
| 	Discovery to work with Equal Cost Multipath Routing in anycast | 	Discovery to work with Equal Cost Multipath Routing in anycast | ||||||
| 	environments. See RFC 7690 and: | 	environments. See RFC 7690 and: | ||||||
| 	https://tools.ietf.org/html/draft-wang-6man-flow-label-reflection-01 | 	https://tools.ietf.org/html/draft-wang-6man-flow-label-reflection-01 | ||||||
| 	TRUE: enabled | 
 | ||||||
| 	FALSE: disabled | 	This is a mask of two bits. | ||||||
| 	Default: FALSE | 	1: enabled for established flows | ||||||
|  | 
 | ||||||
|  | 	Note that this prevents automatic flowlabel changes, as done | ||||||
|  | 	in "tcp: change IPv6 flow-label upon receiving spurious retransmission" | ||||||
|  | 	and "tcp: Change txhash on every SYN and RTO retransmit" | ||||||
|  | 
 | ||||||
|  | 	2: enabled for TCP RESET packets (no active listener) | ||||||
|  | 	If set, a RST packet sent in response to a SYN packet on a closed | ||||||
|  | 	port will reflect the incoming flow label. | ||||||
|  | 
 | ||||||
|  | 	Default: 0 | ||||||
| 
 | 
 | ||||||
| fib_multipath_hash_policy - INTEGER | fib_multipath_hash_policy - INTEGER | ||||||
| 	Controls which hash policy to use for multipath routes. | 	Controls which hash policy to use for multipath routes. | ||||||
|  |  | ||||||
|  | @ -212,7 +212,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, | ||||||
| 	np->mc_loop	= 1; | 	np->mc_loop	= 1; | ||||||
| 	np->mc_all	= 1; | 	np->mc_all	= 1; | ||||||
| 	np->pmtudisc	= IPV6_PMTUDISC_WANT; | 	np->pmtudisc	= IPV6_PMTUDISC_WANT; | ||||||
| 	np->repflow	= net->ipv6.sysctl.flowlabel_reflect; | 	np->repflow	= net->ipv6.sysctl.flowlabel_reflect & 1; | ||||||
| 	sk->sk_ipv6only	= net->ipv6.sysctl.bindv6only; | 	sk->sk_ipv6only	= net->ipv6.sysctl.bindv6only; | ||||||
| 
 | 
 | ||||||
| 	/* Init the ipv4 part of the socket since we can have sockets
 | 	/* Init the ipv4 part of the socket since we can have sockets
 | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ | ||||||
| 
 | 
 | ||||||
| static int zero; | static int zero; | ||||||
| static int one = 1; | static int one = 1; | ||||||
|  | static int three = 3; | ||||||
| static int auto_flowlabels_min; | static int auto_flowlabels_min; | ||||||
| static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX; | static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX; | ||||||
| 
 | 
 | ||||||
|  | @ -114,6 +115,8 @@ static struct ctl_table ipv6_table_template[] = { | ||||||
| 		.maxlen		= sizeof(int), | 		.maxlen		= sizeof(int), | ||||||
| 		.mode		= 0644, | 		.mode		= 0644, | ||||||
| 		.proc_handler	= proc_dointvec, | 		.proc_handler	= proc_dointvec, | ||||||
|  | 		.extra1		= &zero, | ||||||
|  | 		.extra2		= &three, | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		.procname	= "max_dst_opts_number", | 		.procname	= "max_dst_opts_number", | ||||||
|  |  | ||||||
|  | @ -916,15 +916,17 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 | ||||||
| static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) | static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	const struct tcphdr *th = tcp_hdr(skb); | 	const struct tcphdr *th = tcp_hdr(skb); | ||||||
|  | 	struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||||||
| 	u32 seq = 0, ack_seq = 0; | 	u32 seq = 0, ack_seq = 0; | ||||||
| 	struct tcp_md5sig_key *key = NULL; | 	struct tcp_md5sig_key *key = NULL; | ||||||
| #ifdef CONFIG_TCP_MD5SIG | #ifdef CONFIG_TCP_MD5SIG | ||||||
| 	const __u8 *hash_location = NULL; | 	const __u8 *hash_location = NULL; | ||||||
| 	struct ipv6hdr *ipv6h = ipv6_hdr(skb); |  | ||||||
| 	unsigned char newhash[16]; | 	unsigned char newhash[16]; | ||||||
| 	int genhash; | 	int genhash; | ||||||
| 	struct sock *sk1 = NULL; | 	struct sock *sk1 = NULL; | ||||||
| #endif | #endif | ||||||
|  | 	__be32 label = 0; | ||||||
|  | 	struct net *net; | ||||||
| 	int oif = 0; | 	int oif = 0; | ||||||
| 
 | 
 | ||||||
| 	if (th->rst) | 	if (th->rst) | ||||||
|  | @ -936,6 +938,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) | ||||||
| 	if (!sk && !ipv6_unicast_destination(skb)) | 	if (!sk && !ipv6_unicast_destination(skb)) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	net = dev_net(skb_dst(skb)->dev); | ||||||
| #ifdef CONFIG_TCP_MD5SIG | #ifdef CONFIG_TCP_MD5SIG | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 	hash_location = tcp_parse_md5sig_option(th); | 	hash_location = tcp_parse_md5sig_option(th); | ||||||
|  | @ -949,7 +952,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) | ||||||
| 		 * Incoming packet is checked with md5 hash with finding key, | 		 * Incoming packet is checked with md5 hash with finding key, | ||||||
| 		 * no RST generated if md5 hash doesn't match. | 		 * no RST generated if md5 hash doesn't match. | ||||||
| 		 */ | 		 */ | ||||||
| 		sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), | 		sk1 = inet6_lookup_listener(net, | ||||||
| 					   &tcp_hashinfo, NULL, 0, | 					   &tcp_hashinfo, NULL, 0, | ||||||
| 					   &ipv6h->saddr, | 					   &ipv6h->saddr, | ||||||
| 					   th->source, &ipv6h->daddr, | 					   th->source, &ipv6h->daddr, | ||||||
|  | @ -979,9 +982,13 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) | ||||||
| 		oif = sk->sk_bound_dev_if; | 		oif = sk->sk_bound_dev_if; | ||||||
| 		if (sk_fullsock(sk)) | 		if (sk_fullsock(sk)) | ||||||
| 			trace_tcp_send_reset(sk, skb); | 			trace_tcp_send_reset(sk, skb); | ||||||
|  | 	} else { | ||||||
|  | 		if (net->ipv6.sysctl.flowlabel_reflect & 2) | ||||||
|  | 			label = ip6_flowlabel(ipv6h); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0); | 	tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, | ||||||
|  | 			     label); | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_TCP_MD5SIG | #ifdef CONFIG_TCP_MD5SIG | ||||||
| out: | out: | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Eric Dumazet
						Eric Dumazet