Skip to content

Commit efc6b6f

Browse files
q2vendavem330
authored andcommitted
udp: Improve load balancing for SO_REUSEPORT.
Currently, SO_REUSEPORT does not work well if connected sockets are in a UDP reuseport group. Then reuseport_has_conns() returns true and the result of reuseport_select_sock() is discarded. Also, unconnected sockets have the same score, hence only does the first unconnected socket in udp_hslot always receive all packets sent to unconnected sockets. So, the result of reuseport_select_sock() should be used for load balancing. The noteworthy point is that the unconnected sockets placed after connected sockets in sock_reuseport.socks will receive more packets than others because of the algorithm in reuseport_select_sock(). index | connected | reciprocal_scale | result --------------------------------------------- 0 | no | 20% | 40% 1 | no | 20% | 20% 2 | yes | 20% | 0% 3 | no | 20% | 40% 4 | yes | 20% | 0% If most of the sockets are connected, this can be a problem, but it still works better than now. Fixes: acdcecc ("udp: correct reuseport selection with connected sockets") CC: Willem de Bruijn <[email protected]> Reviewed-by: Benjamin Herrenschmidt <[email protected]> Signed-off-by: Kuniyuki Iwashima <[email protected]> Acked-by: Willem de Bruijn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f2b2c55 commit efc6b6f

File tree

2 files changed

+18
-12
lines changed

2 files changed

+18
-12
lines changed

net/ipv4/udp.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
416416
struct udp_hslot *hslot2,
417417
struct sk_buff *skb)
418418
{
419-
struct sock *sk, *result;
419+
struct sock *sk, *result, *reuseport_result;
420420
int score, badness;
421421
u32 hash = 0;
422422

@@ -426,17 +426,20 @@ static struct sock *udp4_lib_lookup2(struct net *net,
426426
score = compute_score(sk, net, saddr, sport,
427427
daddr, hnum, dif, sdif);
428428
if (score > badness) {
429+
reuseport_result = NULL;
430+
429431
if (sk->sk_reuseport &&
430432
sk->sk_state != TCP_ESTABLISHED) {
431433
hash = udp_ehashfn(net, daddr, hnum,
432434
saddr, sport);
433-
result = reuseport_select_sock(sk, hash, skb,
434-
sizeof(struct udphdr));
435-
if (result && !reuseport_has_conns(sk, false))
436-
return result;
435+
reuseport_result = reuseport_select_sock(sk, hash, skb,
436+
sizeof(struct udphdr));
437+
if (reuseport_result && !reuseport_has_conns(sk, false))
438+
return reuseport_result;
437439
}
440+
441+
result = reuseport_result ? : sk;
438442
badness = score;
439-
result = sk;
440443
}
441444
}
442445
return result;

net/ipv6/udp.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ static struct sock *udp6_lib_lookup2(struct net *net,
148148
int dif, int sdif, struct udp_hslot *hslot2,
149149
struct sk_buff *skb)
150150
{
151-
struct sock *sk, *result;
151+
struct sock *sk, *result, *reuseport_result;
152152
int score, badness;
153153
u32 hash = 0;
154154

@@ -158,17 +158,20 @@ static struct sock *udp6_lib_lookup2(struct net *net,
158158
score = compute_score(sk, net, saddr, sport,
159159
daddr, hnum, dif, sdif);
160160
if (score > badness) {
161+
reuseport_result = NULL;
162+
161163
if (sk->sk_reuseport &&
162164
sk->sk_state != TCP_ESTABLISHED) {
163165
hash = udp6_ehashfn(net, daddr, hnum,
164166
saddr, sport);
165167

166-
result = reuseport_select_sock(sk, hash, skb,
167-
sizeof(struct udphdr));
168-
if (result && !reuseport_has_conns(sk, false))
169-
return result;
168+
reuseport_result = reuseport_select_sock(sk, hash, skb,
169+
sizeof(struct udphdr));
170+
if (reuseport_result && !reuseport_has_conns(sk, false))
171+
return reuseport_result;
170172
}
171-
result = sk;
173+
174+
result = reuseport_result ? : sk;
172175
badness = score;
173176
}
174177
}

0 commit comments

Comments
 (0)