Skip to content

Commit 4dec641

Browse files
LPhghNipaLocal
authored andcommitted
ipv6/udp: Add 4-tuple hash for connected socket
Implement ipv6 udp hash4 like that in ipv4. The major difference is that the hash value should be calculated with udp6_ehashfn(). Besides, ipv4-mapped ipv6 address is handled before hash() and rehash(). Export udp_ehashfn because now we use it in udpv6 rehash. Core procedures of hash/unhash/rehash are same as ipv4, and udpv4 and udpv6 share the same udptable, so some functions in ipv4 hash4 can also be shared. Signed-off-by: Philo Lu <[email protected]> Signed-off-by: Cambda Zhu <[email protected]> Signed-off-by: Fred Chen <[email protected]> Signed-off-by: Yubing Qiu <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent e8aeca8 commit 4dec641

File tree

3 files changed

+103
-3
lines changed

3 files changed

+103
-3
lines changed

include/net/udp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ static inline int udp_lib_hash(struct sock *sk)
303303

304304
void udp_lib_unhash(struct sock *sk);
305305
void udp_lib_rehash(struct sock *sk, u16 new_hash, u16 new_hash4);
306+
u32 udp_ehashfn(const struct net *net, const __be32 laddr, const __u16 lport,
307+
const __be32 faddr, const __be16 fport);
306308

307309
static inline void udp_lib_close(struct sock *sk, long timeout)
308310
{

net/ipv4/udp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,6 @@ static int compute_score(struct sock *sk, const struct net *net,
410410
return score;
411411
}
412412

413-
INDIRECT_CALLABLE_SCOPE
414413
u32 udp_ehashfn(const struct net *net, const __be32 laddr, const __u16 lport,
415414
const __be32 faddr, const __be16 fport)
416415
{
@@ -419,6 +418,7 @@ u32 udp_ehashfn(const struct net *net, const __be32 laddr, const __u16 lport,
419418
return __inet_ehashfn(laddr, lport, faddr, fport,
420419
udp_ehash_secret + net_hash_mix(net));
421420
}
421+
EXPORT_SYMBOL(udp_ehashfn);
422422

423423
/* called with rcu_read_lock() */
424424
static struct sock *udp4_lib_lookup2(const struct net *net,

net/ipv6/udp.c

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,19 @@ void udp_v6_rehash(struct sock *sk)
110110
u16 new_hash = ipv6_portaddr_hash(sock_net(sk),
111111
&sk->sk_v6_rcv_saddr,
112112
inet_sk(sk)->inet_num);
113+
u16 new_hash4;
113114

114-
udp_lib_rehash(sk, new_hash, 0); /* 4-tuple hash not implemented */
115+
if (ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr)) {
116+
new_hash4 = udp_ehashfn(sock_net(sk),
117+
sk->sk_rcv_saddr, sk->sk_num,
118+
sk->sk_daddr, sk->sk_dport);
119+
} else {
120+
new_hash4 = udp6_ehashfn(sock_net(sk),
121+
&sk->sk_v6_rcv_saddr, sk->sk_num,
122+
&sk->sk_v6_daddr, sk->sk_dport);
123+
}
124+
125+
udp_lib_rehash(sk, new_hash, new_hash4);
115126
}
116127

117128
static int compute_score(struct sock *sk, const struct net *net,
@@ -216,6 +227,74 @@ static struct sock *udp6_lib_lookup2(const struct net *net,
216227
return result;
217228
}
218229

230+
#if IS_ENABLED(CONFIG_BASE_SMALL)
231+
static struct sock *udp6_lib_lookup4(const struct net *net,
232+
const struct in6_addr *saddr, __be16 sport,
233+
const struct in6_addr *daddr,
234+
unsigned int hnum, int dif, int sdif,
235+
struct udp_table *udptable)
236+
{
237+
return NULL;
238+
}
239+
240+
static void udp6_hash4(struct sock *sk)
241+
{
242+
}
243+
#else /* !CONFIG_BASE_SMALL */
244+
static struct sock *udp6_lib_lookup4(const struct net *net,
245+
const struct in6_addr *saddr, __be16 sport,
246+
const struct in6_addr *daddr,
247+
unsigned int hnum, int dif, int sdif,
248+
struct udp_table *udptable)
249+
{
250+
const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
251+
const struct hlist_nulls_node *node;
252+
struct udp_hslot *hslot4;
253+
unsigned int hash4, slot;
254+
struct udp_sock *up;
255+
struct sock *sk;
256+
257+
hash4 = udp6_ehashfn(net, daddr, hnum, saddr, sport);
258+
slot = hash4 & udptable->mask;
259+
hslot4 = &udptable->hash4[slot];
260+
261+
begin:
262+
udp_lrpa_for_each_entry_rcu(up, node, &hslot4->nulls_head) {
263+
sk = (struct sock *)up;
264+
if (inet6_match(net, sk, saddr, daddr, ports, dif, sdif))
265+
return sk;
266+
}
267+
268+
/* if the nulls value we got at the end of this lookup is not the
269+
* expected one, we must restart lookup. We probably met an item that
270+
* was moved to another chain due to rehash.
271+
*/
272+
if (get_nulls_value(node) != slot)
273+
goto begin;
274+
275+
return NULL;
276+
}
277+
278+
static void udp6_hash4(struct sock *sk)
279+
{
280+
struct net *net = sock_net(sk);
281+
unsigned int hash;
282+
283+
if (ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr)) {
284+
udp4_hash4(sk);
285+
return;
286+
}
287+
288+
if (sk_unhashed(sk) || ipv6_addr_any(&sk->sk_v6_rcv_saddr))
289+
return;
290+
291+
hash = udp6_ehashfn(net, &sk->sk_v6_rcv_saddr, sk->sk_num,
292+
&sk->sk_v6_daddr, sk->sk_dport);
293+
294+
udp_lib_hash4(sk, hash);
295+
}
296+
#endif /* CONFIG_BASE_SMALL */
297+
219298
/* rcu_read_lock() must be held */
220299
struct sock *__udp6_lib_lookup(const struct net *net,
221300
const struct in6_addr *saddr, __be16 sport,
@@ -231,6 +310,13 @@ struct sock *__udp6_lib_lookup(const struct net *net,
231310
hash2 = ipv6_portaddr_hash(net, daddr, hnum);
232311
hslot2 = udp_hashslot2(udptable, hash2);
233312

313+
if (udp_has_hash4(hslot2)) {
314+
result = udp6_lib_lookup4(net, saddr, sport, daddr, hnum,
315+
dif, sdif, udptable);
316+
if (result) /* udp6_lib_lookup4 return sk or NULL */
317+
return result;
318+
}
319+
234320
/* Lookup connected or non-wildcard sockets */
235321
result = udp6_lib_lookup2(net, saddr, sport,
236322
daddr, hnum, dif, sdif,
@@ -1166,6 +1252,18 @@ static int udpv6_pre_connect(struct sock *sk, struct sockaddr *uaddr,
11661252
return BPF_CGROUP_RUN_PROG_INET6_CONNECT_LOCK(sk, uaddr, &addr_len);
11671253
}
11681254

1255+
static int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
1256+
{
1257+
int res;
1258+
1259+
lock_sock(sk);
1260+
res = __ip6_datagram_connect(sk, uaddr, addr_len);
1261+
if (!res)
1262+
udp6_hash4(sk);
1263+
release_sock(sk);
1264+
return res;
1265+
}
1266+
11691267
/**
11701268
* udp6_hwcsum_outgoing - handle outgoing HW checksumming
11711269
* @sk: socket we are sending on
@@ -1761,7 +1859,7 @@ struct proto udpv6_prot = {
17611859
.owner = THIS_MODULE,
17621860
.close = udp_lib_close,
17631861
.pre_connect = udpv6_pre_connect,
1764-
.connect = ip6_datagram_connect,
1862+
.connect = udpv6_connect,
17651863
.disconnect = udp_disconnect,
17661864
.ioctl = udp_ioctl,
17671865
.init = udpv6_init_sock,

0 commit comments

Comments
 (0)