Skip to content

Commit 21f827b

Browse files
LPhghopsiff
authored andcommitted
udp: Make rehash4 independent in udp_lib_rehash()
[ Upstream commit 644f910 ] As discussed in [0], rehash4 could be missed in udp_lib_rehash() when udp hash4 changes while hash2 doesn't change. This patch fixes this by moving rehash4 codes out of rehash2 checking, and then rehash2 and rehash4 are done separately. By doing this, we no longer need to call rehash4 explicitly in udp_lib_hash4(), as the rehash callback in __ip4_datagram_connect takes it. Thus, now udp_lib_hash4() returns directly if the sk is already hashed. Note that uhash4 may fail to work under consecutive connect(<dst address>) calls because rehash() is not called with every connect(). To overcome this, connect(<AF_UNSPEC>) needs to be called after the next connect to a new destination. [0] https://lore.kernel.org/all/4761e466ab9f7542c68cdc95f248987d127044d2.1733499715.git.pabeni@redhat.com/ Fixes: 78c91ae ("ipv4/udp: Add 4-tuple hash for connected socket") Suggested-by: Paolo Abeni <[email protected]> Signed-off-by: Philo Lu <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]> [ Backport from v6.13 ] Suggested-by: Wentao Guan <[email protected]> Signed-off-by: WangYuli <[email protected]>
1 parent affbc21 commit 21f827b

File tree

1 file changed

+27
-19
lines changed

1 file changed

+27
-19
lines changed

net/ipv4/udp.c

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ static struct sock *udp4_lib_lookup4(struct net *net,
534534
return NULL;
535535
}
536536

537-
/* In hash4, rehash can happen in connect(), where hash4_cnt keeps unchanged. */
537+
/* udp_rehash4() only checks hslot4, and hash4_cnt is not processed. */
538538
static void udp_rehash4(struct udp_table *udptable, struct sock *sk,
539539
u16 newhash4)
540540
{
@@ -583,15 +583,13 @@ void udp_lib_hash4(struct sock *sk, u16 hash)
583583
struct net *net = sock_net(sk);
584584
struct udp_table *udptable;
585585

586-
/* Connected udp socket can re-connect to another remote address,
587-
* so rehash4 is needed.
586+
/* Connected udp socket can re-connect to another remote address, which
587+
* will be handled by rehash. Thus no need to redo hash4 here.
588588
*/
589-
udptable = net->ipv4.udp_table;
590-
if (udp_hashed4(sk)) {
591-
udp_rehash4(udptable, sk, hash);
589+
if (udp_hashed4(sk))
592590
return;
593-
}
594591

592+
udptable = net->ipv4.udp_table;
595593
hslot = udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash);
596594
hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
597595
hslot4 = udp_hashslot4(udptable, hash);
@@ -2177,14 +2175,14 @@ void udp_lib_rehash(struct sock *sk, u16 newhash, u16 newhash4)
21772175
struct udp_table *udptable = udp_get_table_prot(sk);
21782176
struct udp_hslot *hslot, *hslot2, *nhslot2;
21792177

2178+
hslot = udp_hashslot(udptable, sock_net(sk),
2179+
udp_sk(sk)->udp_port_hash);
21802180
hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
21812181
nhslot2 = udp_hashslot2(udptable, newhash);
21822182
udp_sk(sk)->udp_portaddr_hash = newhash;
21832183

21842184
if (hslot2 != nhslot2 ||
21852185
rcu_access_pointer(sk->sk_reuseport_cb)) {
2186-
hslot = udp_hashslot(udptable, sock_net(sk),
2187-
udp_sk(sk)->udp_port_hash);
21882186
/* we must lock primary chain too */
21892187
spin_lock_bh(&hslot->lock);
21902188
if (rcu_access_pointer(sk->sk_reuseport_cb))
@@ -2203,19 +2201,29 @@ void udp_lib_rehash(struct sock *sk, u16 newhash, u16 newhash4)
22032201
spin_unlock(&nhslot2->lock);
22042202
}
22052203

2206-
if (udp_hashed4(sk)) {
2207-
udp_rehash4(udptable, sk, newhash4);
2204+
spin_unlock_bh(&hslot->lock);
2205+
}
2206+
2207+
/* Now process hash4 if necessary:
2208+
* (1) update hslot4;
2209+
* (2) update hslot2->hash4_cnt.
2210+
* Note that hslot2/hslot4 should be checked separately, as
2211+
* either of them may change with the other unchanged.
2212+
*/
2213+
if (udp_hashed4(sk)) {
2214+
spin_lock_bh(&hslot->lock);
22082215

2209-
if (hslot2 != nhslot2) {
2210-
spin_lock(&hslot2->lock);
2211-
udp_hash4_dec(hslot2);
2212-
spin_unlock(&hslot2->lock);
2216+
udp_rehash4(udptable, sk, newhash4);
2217+
if (hslot2 != nhslot2) {
2218+
spin_lock(&hslot2->lock);
2219+
udp_hash4_dec(hslot2);
2220+
spin_unlock(&hslot2->lock);
22132221

2214-
spin_lock(&nhslot2->lock);
2215-
udp_hash4_inc(nhslot2);
2216-
spin_unlock(&nhslot2->lock);
2217-
}
2222+
spin_lock(&nhslot2->lock);
2223+
udp_hash4_inc(nhslot2);
2224+
spin_unlock(&nhslot2->lock);
22182225
}
2226+
22192227
spin_unlock_bh(&hslot->lock);
22202228
}
22212229
}

0 commit comments

Comments
 (0)