| From foo@baz Fri Nov  7 11:36:50 PST 2014 | 
 | From: Sathya Perla <sathya.perla@emulex.com> | 
 | Date: Wed, 22 Oct 2014 21:42:01 +0530 | 
 | Subject: net: fix saving TX flow hash in sock for outgoing connections | 
 |  | 
 | From: Sathya Perla <sathya.perla@emulex.com> | 
 |  | 
 | [ Upstream commit 9e7ceb060754f134231f68cb29d5db31419fe1ed ] | 
 |  | 
 | The commit "net: Save TX flow hash in sock and set in skbuf on xmit" | 
 | introduced the inet_set_txhash() and ip6_set_txhash() routines to calculate | 
 | and record flow hash(sk_txhash) in the socket structure. sk_txhash is used | 
 | to set skb->hash which is used to spread flows across multiple TXQs. | 
 |  | 
 | But, the above routines are invoked before the source port of the connection | 
 | is created. Because of this all outgoing connections that just differ in the | 
 | source port get hashed into the same TXQ. | 
 |  | 
 | This patch fixes this problem for IPv4/6 by invoking the the above routines | 
 | after the source port is available for the socket. | 
 |  | 
 | Fixes: b73c3d0e4("net: Save TX flow hash in sock and set in skbuf on xmit") | 
 |  | 
 | Signed-off-by: Sathya Perla <sathya.perla@emulex.com> | 
 | Acked-by: Eric Dumazet <edumazet@google.com> | 
 | Signed-off-by: David S. Miller <davem@davemloft.net> | 
 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 
 | --- | 
 |  net/ipv4/tcp_ipv4.c |    4 ++-- | 
 |  net/ipv6/tcp_ipv6.c |    4 ++-- | 
 |  2 files changed, 4 insertions(+), 4 deletions(-) | 
 |  | 
 | --- a/net/ipv4/tcp_ipv4.c | 
 | +++ b/net/ipv4/tcp_ipv4.c | 
 | @@ -208,8 +208,6 @@ int tcp_v4_connect(struct sock *sk, stru | 
 |  	inet->inet_dport = usin->sin_port; | 
 |  	inet->inet_daddr = daddr; | 
 |   | 
 | -	inet_set_txhash(sk); | 
 | - | 
 |  	inet_csk(sk)->icsk_ext_hdr_len = 0; | 
 |  	if (inet_opt) | 
 |  		inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen; | 
 | @@ -226,6 +224,8 @@ int tcp_v4_connect(struct sock *sk, stru | 
 |  	if (err) | 
 |  		goto failure; | 
 |   | 
 | +	inet_set_txhash(sk); | 
 | + | 
 |  	rt = ip_route_newports(fl4, rt, orig_sport, orig_dport, | 
 |  			       inet->inet_sport, inet->inet_dport, sk); | 
 |  	if (IS_ERR(rt)) { | 
 | --- a/net/ipv6/tcp_ipv6.c | 
 | +++ b/net/ipv6/tcp_ipv6.c | 
 | @@ -198,8 +198,6 @@ static int tcp_v6_connect(struct sock *s | 
 |  	sk->sk_v6_daddr = usin->sin6_addr; | 
 |  	np->flow_label = fl6.flowlabel; | 
 |   | 
 | -	ip6_set_txhash(sk); | 
 | - | 
 |  	/* | 
 |  	 *	TCP over IPv4 | 
 |  	 */ | 
 | @@ -295,6 +293,8 @@ static int tcp_v6_connect(struct sock *s | 
 |  	if (err) | 
 |  		goto late_failure; | 
 |   | 
 | +	ip6_set_txhash(sk); | 
 | + | 
 |  	if (!tp->write_seq && likely(!tp->repair)) | 
 |  		tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, | 
 |  							     sk->sk_v6_daddr.s6_addr32, |