| From 74ff364e6f25bd036fbc1693a86d1179f06e1322 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 5 Oct 2021 14:03:42 +0100 |
| Subject: net: prefer socket bound to interface when not in VRF |
| |
| From: Mike Manning <mvrmanning@gmail.com> |
| |
| [ Upstream commit 8d6c414cd2fb74aa6812e9bfec6178f8246c4f3a ] |
| |
| The commit 6da5b0f027a8 ("net: ensure unbound datagram socket to be |
| chosen when not in a VRF") modified compute_score() so that a device |
| match is always made, not just in the case of an l3mdev skb, then |
| increments the score also for unbound sockets. This ensures that |
| sockets bound to an l3mdev are never selected when not in a VRF. |
| But as unbound and bound sockets are now scored equally, this results |
| in the last opened socket being selected if there are matches in the |
| default VRF for an unbound socket and a socket bound to a dev that is |
| not an l3mdev. However, handling prior to this commit was to always |
| select the bound socket in this case. Reinstate this handling by |
| incrementing the score only for bound sockets. The required isolation |
| due to choosing between an unbound socket and a socket bound to an |
| l3mdev remains in place due to the device match always being made. |
| The same approach is taken for compute_score() for stream sockets. |
| |
| Fixes: 6da5b0f027a8 ("net: ensure unbound datagram socket to be chosen when not in a VRF") |
| Fixes: e78190581aff ("net: ensure unbound stream socket to be chosen when not in a VRF") |
| Signed-off-by: Mike Manning <mmanning@vyatta.att-mail.com> |
| Reviewed-by: David Ahern <dsahern@kernel.org> |
| Link: https://lore.kernel.org/r/cf0a8523-b362-1edf-ee78-eef63cbbb428@gmail.com |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/ipv4/inet_hashtables.c | 4 +++- |
| net/ipv4/udp.c | 3 ++- |
| net/ipv6/inet6_hashtables.c | 2 +- |
| net/ipv6/udp.c | 3 ++- |
| 4 files changed, 8 insertions(+), 4 deletions(-) |
| |
| diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c |
| index 45fb450b4522..f3fd5c911ed0 100644 |
| --- a/net/ipv4/inet_hashtables.c |
| +++ b/net/ipv4/inet_hashtables.c |
| @@ -242,8 +242,10 @@ static inline int compute_score(struct sock *sk, struct net *net, |
| |
| if (!inet_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif)) |
| return -1; |
| + score = sk->sk_bound_dev_if ? 2 : 1; |
| |
| - score = sk->sk_family == PF_INET ? 2 : 1; |
| + if (sk->sk_family == PF_INET) |
| + score++; |
| if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) |
| score++; |
| } |
| diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c |
| index bd7fd9b1f24c..655f0d8a13d3 100644 |
| --- a/net/ipv4/udp.c |
| +++ b/net/ipv4/udp.c |
| @@ -390,7 +390,8 @@ static int compute_score(struct sock *sk, struct net *net, |
| dif, sdif); |
| if (!dev_match) |
| return -1; |
| - score += 4; |
| + if (sk->sk_bound_dev_if) |
| + score += 4; |
| |
| if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) |
| score++; |
| diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c |
| index 55c290d55605..67c9114835c8 100644 |
| --- a/net/ipv6/inet6_hashtables.c |
| +++ b/net/ipv6/inet6_hashtables.c |
| @@ -106,7 +106,7 @@ static inline int compute_score(struct sock *sk, struct net *net, |
| if (!inet_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif)) |
| return -1; |
| |
| - score = 1; |
| + score = sk->sk_bound_dev_if ? 2 : 1; |
| if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) |
| score++; |
| } |
| diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c |
| index 1943ae5103eb..bae6b51a9bd4 100644 |
| --- a/net/ipv6/udp.c |
| +++ b/net/ipv6/udp.c |
| @@ -133,7 +133,8 @@ static int compute_score(struct sock *sk, struct net *net, |
| dev_match = udp_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif); |
| if (!dev_match) |
| return -1; |
| - score++; |
| + if (sk->sk_bound_dev_if) |
| + score++; |
| |
| if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) |
| score++; |
| -- |
| 2.33.0 |
| |