Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions net/ipv6/tcp_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,28 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,

sk_set_txhash(sk);

/* The route was resolved before fl6 was complete: the source address
* was unselected (::) and the source port unbound (0). Both are now
* final -- the earlier lookup selected the source (written back to
* fl6.saddr) and inet6_hash_connect() just bound the port. The IPv6
* multipath hash uses the source port (policy=1) or the source
* address (policy=0), so the next hop picked from the incomplete
* tuple may differ from the connection's real one, and the flow would
* migrate on dst invalidation. Re-resolve with the bound port -- as
* tcp_v4_connect() does via ip_route_newports() -- to pin the flow to
* the correct path. Only repeat the lookup if the port changed.
*/
if (fl6.fl6_sport != inet->inet_sport) {
fl6.fl6_sport = inet->inet_sport;
security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
dst = ip6_dst_lookup_flow(net, sk, &fl6, final_p);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
goto late_failure;
}
ip6_dst_store(sk, dst, NULL, NULL);
}

if (likely(!tp->repair)) {
union tcp_seq_and_ts_off st;

Expand Down