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 | ||||
| 	Default: true | ||||
| 
 | ||||
| flowlabel_reflect - BOOLEAN | ||||
| 	Automatically reflect the flow label. Needed for Path MTU | ||||
| flowlabel_reflect - INTEGER | ||||
| 	Control flow label reflection. Needed for Path MTU | ||||
| 	Discovery to work with Equal Cost Multipath Routing in anycast | ||||
| 	environments. See RFC 7690 and: | ||||
| 	https://tools.ietf.org/html/draft-wang-6man-flow-label-reflection-01 | ||||
| 	TRUE: enabled | ||||
| 	FALSE: disabled | ||||
| 	Default: FALSE | ||||
| 
 | ||||
| 	This is a mask of two bits. | ||||
| 	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 | ||||
| 	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_all	= 1; | ||||
| 	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; | ||||
| 
 | ||||
| 	/* Init the ipv4 part of the socket since we can have sockets
 | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ | |||
| 
 | ||||
| static int zero; | ||||
| static int one = 1; | ||||
| static int three = 3; | ||||
| static int auto_flowlabels_min; | ||||
| static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX; | ||||
| 
 | ||||
|  | @ -114,6 +115,8 @@ static struct ctl_table ipv6_table_template[] = { | |||
| 		.maxlen		= sizeof(int), | ||||
| 		.mode		= 0644, | ||||
| 		.proc_handler	= proc_dointvec, | ||||
| 		.extra1		= &zero, | ||||
| 		.extra2		= &three, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.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) | ||||
| { | ||||
| 	const struct tcphdr *th = tcp_hdr(skb); | ||||
| 	struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||||
| 	u32 seq = 0, ack_seq = 0; | ||||
| 	struct tcp_md5sig_key *key = NULL; | ||||
| #ifdef CONFIG_TCP_MD5SIG | ||||
| 	const __u8 *hash_location = NULL; | ||||
| 	struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||||
| 	unsigned char newhash[16]; | ||||
| 	int genhash; | ||||
| 	struct sock *sk1 = NULL; | ||||
| #endif | ||||
| 	__be32 label = 0; | ||||
| 	struct net *net; | ||||
| 	int oif = 0; | ||||
| 
 | ||||
| 	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)) | ||||
| 		return; | ||||
| 
 | ||||
| 	net = dev_net(skb_dst(skb)->dev); | ||||
| #ifdef CONFIG_TCP_MD5SIG | ||||
| 	rcu_read_lock(); | ||||
| 	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, | ||||
| 		 * 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, | ||||
| 					   &ipv6h->saddr, | ||||
| 					   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; | ||||
| 		if (sk_fullsock(sk)) | ||||
| 			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 | ||||
| out: | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Eric Dumazet
						Eric Dumazet