Skip to content

Commit 736b460

Browse files
iamkafaiborkmann
authored andcommitted
net: Add ID (if needed) to sock_reuseport and expose reuseport_lock
A later patch will introduce a BPF_MAP_TYPE_REUSEPORT_ARRAY which allows a SO_REUSEPORT sk to be added to a bpf map. When a sk is removed from reuse->socks[], it also needs to be removed from the bpf map. Also, when adding a sk to a bpf map, the bpf map needs to ensure it is indeed in a reuse->socks[]. Hence, reuseport_lock is needed by the bpf map to ensure its map_update_elem() and map_delete_elem() operations are in-sync with the reuse->socks[]. The BPF_MAP_TYPE_REUSEPORT_ARRAY map will only acquire the reuseport_lock after ensuring the adding sk is already in a reuseport group (i.e. reuse->socks[]). The map_lookup_elem() will be lockless. This patch also adds an ID to sock_reuseport. A later patch will introduce BPF_PROG_TYPE_SK_REUSEPORT which allows a bpf prog to select a sk from a bpf map. It is inflexible to statically enforce a bpf map can only contain the sk belonging to a particular reuse->socks[] (i.e. same IP:PORT) during the bpf verification time. For example, think about the the map-in-map situation where the inner map can be dynamically changed in runtime and the outer map may have inner maps belonging to different reuseport groups. Hence, when the bpf prog (in the new BPF_PROG_TYPE_SK_REUSEPORT type) selects a sk, this selected sk has to be checked to ensure it belongs to the requesting reuseport group (i.e. the group serving that IP:PORT). The "sk->sk_reuseport_cb" pointer cannot be used for this checking purpose because the pointer value will change after reuseport_grow(). Instead of saving all checking conditions like the ones preced calling "reuseport_add_sock()" and compare them everytime a bpf_prog is run, a 32bits ID is introduced to survive the reuseport_grow(). The ID is only acquired if any of the reuse->socks[] is added to the newly introduced "BPF_MAP_TYPE_REUSEPORT_ARRAY" map. If "BPF_MAP_TYPE_REUSEPORT_ARRAY" is not used, the changes in this patch is a no-op. Signed-off-by: Martin KaFai Lau <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent 40a1227 commit 736b460

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

include/net/sock_reuseport.h

+6
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
#include <linux/filter.h>
66
#include <linux/skbuff.h>
77
#include <linux/types.h>
8+
#include <linux/spinlock.h>
89
#include <net/sock.h>
910

11+
extern spinlock_t reuseport_lock;
12+
1013
struct sock_reuseport {
1114
struct rcu_head rcu;
1215

@@ -16,6 +19,8 @@ struct sock_reuseport {
1619
* reuse->socks[] group.
1720
*/
1821
unsigned int synq_overflow_ts;
22+
/* ID stays the same even after the size of socks[] grows. */
23+
unsigned int reuseport_id;
1924
struct bpf_prog __rcu *prog; /* optional BPF sock selector */
2025
struct sock *socks[0]; /* array of sock pointers */
2126
};
@@ -29,5 +34,6 @@ extern struct sock *reuseport_select_sock(struct sock *sk,
2934
int hdr_len);
3035
extern struct bpf_prog *reuseport_attach_prog(struct sock *sk,
3136
struct bpf_prog *prog);
37+
int reuseport_get_id(struct sock_reuseport *reuse);
3238

3339
#endif /* _SOCK_REUSEPORT_H */

net/core/sock_reuseport.c

+26-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,33 @@
88

99
#include <net/sock_reuseport.h>
1010
#include <linux/bpf.h>
11+
#include <linux/idr.h>
1112
#include <linux/rcupdate.h>
1213

1314
#define INIT_SOCKS 128
1415

15-
static DEFINE_SPINLOCK(reuseport_lock);
16+
DEFINE_SPINLOCK(reuseport_lock);
17+
18+
#define REUSEPORT_MIN_ID 1
19+
static DEFINE_IDA(reuseport_ida);
20+
21+
int reuseport_get_id(struct sock_reuseport *reuse)
22+
{
23+
int id;
24+
25+
if (reuse->reuseport_id)
26+
return reuse->reuseport_id;
27+
28+
id = ida_simple_get(&reuseport_ida, REUSEPORT_MIN_ID, 0,
29+
/* Called under reuseport_lock */
30+
GFP_ATOMIC);
31+
if (id < 0)
32+
return id;
33+
34+
reuse->reuseport_id = id;
35+
36+
return reuse->reuseport_id;
37+
}
1638

1739
static struct sock_reuseport *__reuseport_alloc(unsigned int max_socks)
1840
{
@@ -78,6 +100,7 @@ static struct sock_reuseport *reuseport_grow(struct sock_reuseport *reuse)
78100
more_reuse->max_socks = more_socks_size;
79101
more_reuse->num_socks = reuse->num_socks;
80102
more_reuse->prog = reuse->prog;
103+
more_reuse->reuseport_id = reuse->reuseport_id;
81104

82105
memcpy(more_reuse->socks, reuse->socks,
83106
reuse->num_socks * sizeof(struct sock *));
@@ -102,6 +125,8 @@ static void reuseport_free_rcu(struct rcu_head *head)
102125
reuse = container_of(head, struct sock_reuseport, rcu);
103126
if (reuse->prog)
104127
bpf_prog_destroy(reuse->prog);
128+
if (reuse->reuseport_id)
129+
ida_simple_remove(&reuseport_ida, reuse->reuseport_id);
105130
kfree(reuse);
106131
}
107132

0 commit comments

Comments
 (0)