Skip to content

Commit a3fd7ce

Browse files
jsitnickiAlexei Starovoitov
authored andcommitted
net: Introduce netns_bpf for BPF programs attached to netns
In order to: (1) attach more than one BPF program type to netns, or (2) support attaching BPF programs to netns with bpf_link, or (3) support multi-prog attach points for netns we will need to keep more state per netns than a single pointer like we have now for BPF flow dissector program. Prepare for the above by extracting netns_bpf that is part of struct net, for storing all state related to BPF programs attached to netns. Turn flow dissector callbacks for querying/attaching/detaching a program into generic ones that operate on netns_bpf. Next patch will move the generic callbacks into their own module. This is similar to how it is organized for cgroup with cgroup_bpf. Signed-off-by: Jakub Sitnicki <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Cc: Stanislav Fomichev <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 171526f commit a3fd7ce

File tree

6 files changed

+149
-66
lines changed

6 files changed

+149
-66
lines changed

include/linux/bpf-netns.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _BPF_NETNS_H
3+
#define _BPF_NETNS_H
4+
5+
#include <linux/mutex.h>
6+
#include <uapi/linux/bpf.h>
7+
8+
enum netns_bpf_attach_type {
9+
NETNS_BPF_INVALID = -1,
10+
NETNS_BPF_FLOW_DISSECTOR = 0,
11+
MAX_NETNS_BPF_ATTACH_TYPE
12+
};
13+
14+
static inline enum netns_bpf_attach_type
15+
to_netns_bpf_attach_type(enum bpf_attach_type attach_type)
16+
{
17+
switch (attach_type) {
18+
case BPF_FLOW_DISSECTOR:
19+
return NETNS_BPF_FLOW_DISSECTOR;
20+
default:
21+
return NETNS_BPF_INVALID;
22+
}
23+
}
24+
25+
/* Protects updates to netns_bpf */
26+
extern struct mutex netns_bpf_mutex;
27+
28+
union bpf_attr;
29+
struct bpf_prog;
30+
31+
#ifdef CONFIG_NET
32+
int netns_bpf_prog_query(const union bpf_attr *attr,
33+
union bpf_attr __user *uattr);
34+
int netns_bpf_prog_attach(const union bpf_attr *attr,
35+
struct bpf_prog *prog);
36+
int netns_bpf_prog_detach(const union bpf_attr *attr);
37+
#else
38+
static inline int netns_bpf_prog_query(const union bpf_attr *attr,
39+
union bpf_attr __user *uattr)
40+
{
41+
return -EOPNOTSUPP;
42+
}
43+
44+
static inline int netns_bpf_prog_attach(const union bpf_attr *attr,
45+
struct bpf_prog *prog)
46+
{
47+
return -EOPNOTSUPP;
48+
}
49+
50+
static inline int netns_bpf_prog_detach(const union bpf_attr *attr)
51+
{
52+
return -EOPNOTSUPP;
53+
}
54+
#endif
55+
56+
#endif /* _BPF_NETNS_H */

include/linux/skbuff.h

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,32 +1283,6 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
12831283
const struct flow_dissector_key *key,
12841284
unsigned int key_count);
12851285

1286-
#ifdef CONFIG_NET
1287-
int skb_flow_dissector_prog_query(const union bpf_attr *attr,
1288-
union bpf_attr __user *uattr);
1289-
int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr,
1290-
struct bpf_prog *prog);
1291-
1292-
int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr);
1293-
#else
1294-
static inline int skb_flow_dissector_prog_query(const union bpf_attr *attr,
1295-
union bpf_attr __user *uattr)
1296-
{
1297-
return -EOPNOTSUPP;
1298-
}
1299-
1300-
static inline int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr,
1301-
struct bpf_prog *prog)
1302-
{
1303-
return -EOPNOTSUPP;
1304-
}
1305-
1306-
static inline int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr)
1307-
{
1308-
return -EOPNOTSUPP;
1309-
}
1310-
#endif
1311-
13121286
struct bpf_flow_dissector;
13131287
bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,
13141288
__be16 proto, int nhoff, int hlen, unsigned int flags);

include/net/net_namespace.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <net/netns/mpls.h>
3434
#include <net/netns/can.h>
3535
#include <net/netns/xdp.h>
36+
#include <net/netns/bpf.h>
3637
#include <linux/ns_common.h>
3738
#include <linux/idr.h>
3839
#include <linux/skbuff.h>
@@ -162,7 +163,8 @@ struct net {
162163
#endif
163164
struct net_generic __rcu *gen;
164165

165-
struct bpf_prog __rcu *flow_dissector_prog;
166+
/* Used to store attached BPF programs */
167+
struct netns_bpf bpf;
166168

167169
/* Note : following structs are cache line aligned */
168170
#ifdef CONFIG_XFRM

include/net/netns/bpf.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* BPF programs attached to network namespace
4+
*/
5+
6+
#ifndef __NETNS_BPF_H__
7+
#define __NETNS_BPF_H__
8+
9+
#include <linux/bpf-netns.h>
10+
11+
struct bpf_prog;
12+
13+
struct netns_bpf {
14+
struct bpf_prog __rcu *progs[MAX_NETNS_BPF_ATTACH_TYPE];
15+
};
16+
17+
#endif /* __NETNS_BPF_H__ */

kernel/bpf/syscall.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <uapi/linux/btf.h>
2828
#include <linux/bpf_lsm.h>
2929
#include <linux/poll.h>
30+
#include <linux/bpf-netns.h>
3031

3132
#define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
3233
(map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
@@ -2868,7 +2869,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
28682869
ret = lirc_prog_attach(attr, prog);
28692870
break;
28702871
case BPF_PROG_TYPE_FLOW_DISSECTOR:
2871-
ret = skb_flow_dissector_bpf_prog_attach(attr, prog);
2872+
ret = netns_bpf_prog_attach(attr, prog);
28722873
break;
28732874
case BPF_PROG_TYPE_CGROUP_DEVICE:
28742875
case BPF_PROG_TYPE_CGROUP_SKB:
@@ -2908,7 +2909,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
29082909
case BPF_PROG_TYPE_FLOW_DISSECTOR:
29092910
if (!capable(CAP_NET_ADMIN))
29102911
return -EPERM;
2911-
return skb_flow_dissector_bpf_prog_detach(attr);
2912+
return netns_bpf_prog_detach(attr);
29122913
case BPF_PROG_TYPE_CGROUP_DEVICE:
29132914
case BPF_PROG_TYPE_CGROUP_SKB:
29142915
case BPF_PROG_TYPE_CGROUP_SOCK:
@@ -2961,7 +2962,7 @@ static int bpf_prog_query(const union bpf_attr *attr,
29612962
case BPF_LIRC_MODE2:
29622963
return lirc_prog_query(attr, uattr);
29632964
case BPF_FLOW_DISSECTOR:
2964-
return skb_flow_dissector_prog_query(attr, uattr);
2965+
return netns_bpf_prog_query(attr, uattr);
29652966
default:
29662967
return -EINVAL;
29672968
}

net/core/flow_dissector.c

Lines changed: 69 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131
#include <net/netfilter/nf_conntrack_core.h>
3232
#include <net/netfilter/nf_conntrack_labels.h>
3333
#endif
34+
#include <linux/bpf-netns.h>
3435

35-
static DEFINE_MUTEX(flow_dissector_mutex);
36+
/* Protects updates to netns_bpf */
37+
DEFINE_MUTEX(netns_bpf_mutex);
3638

3739
static void dissector_set_key(struct flow_dissector *flow_dissector,
3840
enum flow_dissector_key_id key_id)
@@ -70,23 +72,28 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
7072
}
7173
EXPORT_SYMBOL(skb_flow_dissector_init);
7274

73-
int skb_flow_dissector_prog_query(const union bpf_attr *attr,
74-
union bpf_attr __user *uattr)
75+
int netns_bpf_prog_query(const union bpf_attr *attr,
76+
union bpf_attr __user *uattr)
7577
{
7678
__u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids);
7779
u32 prog_id, prog_cnt = 0, flags = 0;
80+
enum netns_bpf_attach_type type;
7881
struct bpf_prog *attached;
7982
struct net *net;
8083

8184
if (attr->query.query_flags)
8285
return -EINVAL;
8386

87+
type = to_netns_bpf_attach_type(attr->query.attach_type);
88+
if (type < 0)
89+
return -EINVAL;
90+
8491
net = get_net_ns_by_fd(attr->query.target_fd);
8592
if (IS_ERR(net))
8693
return PTR_ERR(net);
8794

8895
rcu_read_lock();
89-
attached = rcu_dereference(net->flow_dissector_prog);
96+
attached = rcu_dereference(net->bpf.progs[type]);
9097
if (attached) {
9198
prog_cnt = 1;
9299
prog_id = attached->aux->id;
@@ -112,6 +119,7 @@ int skb_flow_dissector_prog_query(const union bpf_attr *attr,
112119
static int flow_dissector_bpf_prog_attach(struct net *net,
113120
struct bpf_prog *prog)
114121
{
122+
enum netns_bpf_attach_type type = NETNS_BPF_FLOW_DISSECTOR;
115123
struct bpf_prog *attached;
116124

117125
if (net == &init_net) {
@@ -125,74 +133,97 @@ static int flow_dissector_bpf_prog_attach(struct net *net,
125133
for_each_net(ns) {
126134
if (ns == &init_net)
127135
continue;
128-
if (rcu_access_pointer(ns->flow_dissector_prog))
136+
if (rcu_access_pointer(ns->bpf.progs[type]))
129137
return -EEXIST;
130138
}
131139
} else {
132140
/* Make sure root flow dissector is not attached
133141
* when attaching to the non-root namespace.
134142
*/
135-
if (rcu_access_pointer(init_net.flow_dissector_prog))
143+
if (rcu_access_pointer(init_net.bpf.progs[type]))
136144
return -EEXIST;
137145
}
138146

139-
attached = rcu_dereference_protected(net->flow_dissector_prog,
140-
lockdep_is_held(&flow_dissector_mutex));
147+
attached = rcu_dereference_protected(net->bpf.progs[type],
148+
lockdep_is_held(&netns_bpf_mutex));
141149
if (attached == prog)
142150
/* The same program cannot be attached twice */
143151
return -EINVAL;
144152

145-
rcu_assign_pointer(net->flow_dissector_prog, prog);
153+
rcu_assign_pointer(net->bpf.progs[type], prog);
146154
if (attached)
147155
bpf_prog_put(attached);
148156
return 0;
149157
}
150158

151-
int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr,
152-
struct bpf_prog *prog)
159+
int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog)
153160
{
161+
enum netns_bpf_attach_type type;
162+
struct net *net;
154163
int ret;
155164

156-
mutex_lock(&flow_dissector_mutex);
157-
ret = flow_dissector_bpf_prog_attach(current->nsproxy->net_ns, prog);
158-
mutex_unlock(&flow_dissector_mutex);
165+
type = to_netns_bpf_attach_type(attr->attach_type);
166+
if (type < 0)
167+
return -EINVAL;
168+
169+
net = current->nsproxy->net_ns;
170+
mutex_lock(&netns_bpf_mutex);
171+
switch (type) {
172+
case NETNS_BPF_FLOW_DISSECTOR:
173+
ret = flow_dissector_bpf_prog_attach(net, prog);
174+
break;
175+
default:
176+
ret = -EINVAL;
177+
break;
178+
}
179+
mutex_unlock(&netns_bpf_mutex);
159180

160181
return ret;
161182
}
162183

163-
static int flow_dissector_bpf_prog_detach(struct net *net)
184+
/* Must be called with netns_bpf_mutex held. */
185+
static int __netns_bpf_prog_detach(struct net *net,
186+
enum netns_bpf_attach_type type)
164187
{
165188
struct bpf_prog *attached;
166189

167-
mutex_lock(&flow_dissector_mutex);
168-
attached = rcu_dereference_protected(net->flow_dissector_prog,
169-
lockdep_is_held(&flow_dissector_mutex));
170-
if (!attached) {
171-
mutex_unlock(&flow_dissector_mutex);
190+
attached = rcu_dereference_protected(net->bpf.progs[type],
191+
lockdep_is_held(&netns_bpf_mutex));
192+
if (!attached)
172193
return -ENOENT;
173-
}
174-
RCU_INIT_POINTER(net->flow_dissector_prog, NULL);
194+
RCU_INIT_POINTER(net->bpf.progs[type], NULL);
175195
bpf_prog_put(attached);
176-
mutex_unlock(&flow_dissector_mutex);
177196
return 0;
178197
}
179198

180-
int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr)
199+
int netns_bpf_prog_detach(const union bpf_attr *attr)
181200
{
182-
return flow_dissector_bpf_prog_detach(current->nsproxy->net_ns);
201+
enum netns_bpf_attach_type type;
202+
int ret;
203+
204+
type = to_netns_bpf_attach_type(attr->attach_type);
205+
if (type < 0)
206+
return -EINVAL;
207+
208+
mutex_lock(&netns_bpf_mutex);
209+
ret = __netns_bpf_prog_detach(current->nsproxy->net_ns, type);
210+
mutex_unlock(&netns_bpf_mutex);
211+
212+
return ret;
183213
}
184214

185-
static void __net_exit flow_dissector_pernet_pre_exit(struct net *net)
215+
static void __net_exit netns_bpf_pernet_pre_exit(struct net *net)
186216
{
187-
/* We're not racing with attach/detach because there are no
188-
* references to netns left when pre_exit gets called.
189-
*/
190-
if (rcu_access_pointer(net->flow_dissector_prog))
191-
flow_dissector_bpf_prog_detach(net);
217+
enum netns_bpf_attach_type type;
218+
219+
mutex_lock(&netns_bpf_mutex);
220+
for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++)
221+
__netns_bpf_prog_detach(net, type);
222+
mutex_unlock(&netns_bpf_mutex);
192223
}
193224

194-
static struct pernet_operations flow_dissector_pernet_ops __net_initdata = {
195-
.pre_exit = flow_dissector_pernet_pre_exit,
225+
static struct pernet_operations netns_bpf_pernet_ops __net_initdata = {
226+
.pre_exit = netns_bpf_pernet_pre_exit,
196227
};
197228

198229
/**
@@ -1044,11 +1075,13 @@ bool __skb_flow_dissect(const struct net *net,
10441075

10451076
WARN_ON_ONCE(!net);
10461077
if (net) {
1078+
enum netns_bpf_attach_type type = NETNS_BPF_FLOW_DISSECTOR;
1079+
10471080
rcu_read_lock();
1048-
attached = rcu_dereference(init_net.flow_dissector_prog);
1081+
attached = rcu_dereference(init_net.bpf.progs[type]);
10491082

10501083
if (!attached)
1051-
attached = rcu_dereference(net->flow_dissector_prog);
1084+
attached = rcu_dereference(net->bpf.progs[type]);
10521085

10531086
if (attached) {
10541087
struct bpf_flow_keys flow_keys;
@@ -1870,6 +1903,6 @@ static int __init init_default_flow_dissectors(void)
18701903
flow_keys_basic_dissector_keys,
18711904
ARRAY_SIZE(flow_keys_basic_dissector_keys));
18721905

1873-
return register_pernet_subsys(&flow_dissector_pernet_ops);
1906+
return register_pernet_subsys(&netns_bpf_pernet_ops);
18741907
}
18751908
core_initcall(init_default_flow_dissectors);

0 commit comments

Comments
 (0)