Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf, netns: Keep a list of attached bpf_link's

To support multi-prog link-based attachments for new netns attach types, we
need to keep track of more than one bpf_link per attach type. Hence,
convert net->bpf.links into a list, that currently can be either empty or
have just one item.

Instead of reusing bpf_prog_list from bpf-cgroup, we link together
bpf_netns_link's themselves. This makes list management simpler as we don't
have to allocate, initialize, and later release list elements. We can do
this because multi-prog attachment will be available only for bpf_link, and
we don't need to build a list of programs attached directly and indirectly
via links.

No functional changes intended.

Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/bpf/20200625141357.910330-4-jakub@cloudflare.com

authored by

Jakub Sitnicki and committed by
Alexei Starovoitov
ab53cad9 695c1214

+24 -20
+1 -1
include/net/netns/bpf.h
··· 15 15 /* Array of programs to run compiled from progs or links */ 16 16 struct bpf_prog_array __rcu *run_array[MAX_NETNS_BPF_ATTACH_TYPE]; 17 17 struct bpf_prog *progs[MAX_NETNS_BPF_ATTACH_TYPE]; 18 - struct bpf_link *links[MAX_NETNS_BPF_ATTACH_TYPE]; 18 + struct list_head links[MAX_NETNS_BPF_ATTACH_TYPE]; 19 19 }; 20 20 21 21 #endif /* __NETNS_BPF_H__ */
+23 -19
kernel/bpf/net_namespace.c
··· 19 19 * with netns_bpf_mutex held. 20 20 */ 21 21 struct net *net; 22 + struct list_head node; /* node in list of links attached to net */ 22 23 }; 23 24 24 25 /* Protects updates to netns_bpf */ 25 26 DEFINE_MUTEX(netns_bpf_mutex); 26 - 27 - /* Must be called with netns_bpf_mutex held. */ 28 - static void __net_exit bpf_netns_link_auto_detach(struct bpf_link *link) 29 - { 30 - struct bpf_netns_link *net_link = 31 - container_of(link, struct bpf_netns_link, link); 32 - 33 - net_link->net = NULL; 34 - } 35 27 36 28 /* Must be called with netns_bpf_mutex held. */ 37 29 static void netns_bpf_run_array_detach(struct net *net, ··· 58 66 goto out_unlock; 59 67 60 68 netns_bpf_run_array_detach(net, type); 61 - net->bpf.links[type] = NULL; 69 + list_del(&net_link->node); 62 70 63 71 out_unlock: 64 72 mutex_unlock(&netns_bpf_mutex); ··· 217 225 mutex_lock(&netns_bpf_mutex); 218 226 219 227 /* Attaching prog directly is not compatible with links */ 220 - if (net->bpf.links[type]) { 228 + if (!list_empty(&net->bpf.links[type])) { 221 229 ret = -EEXIST; 222 230 goto out_unlock; 223 231 } ··· 271 279 struct bpf_prog *attached; 272 280 273 281 /* Progs attached via links cannot be detached */ 274 - if (net->bpf.links[type]) 282 + if (!list_empty(&net->bpf.links[type])) 275 283 return -EINVAL; 276 284 277 285 attached = net->bpf.progs[type]; ··· 302 310 static int netns_bpf_link_attach(struct net *net, struct bpf_link *link, 303 311 enum netns_bpf_attach_type type) 304 312 { 313 + struct bpf_netns_link *net_link = 314 + container_of(link, struct bpf_netns_link, link); 305 315 struct bpf_prog_array *run_array; 306 316 int err; 307 317 308 318 mutex_lock(&netns_bpf_mutex); 309 319 310 320 /* Allow attaching only one prog or link for now */ 311 - if (net->bpf.links[type]) { 321 + if (!list_empty(&net->bpf.links[type])) { 312 322 err = -E2BIG; 313 323 goto out_unlock; 314 324 } ··· 339 345 run_array->items[0].prog = link->prog; 340 346 rcu_assign_pointer(net->bpf.run_array[type], run_array); 341 347 342 - net->bpf.links[type] = link; 348 + list_add_tail(&net_link->node, &net->bpf.links[type]); 343 349 344 350 out_unlock: 345 351 mutex_unlock(&netns_bpf_mutex); ··· 398 404 return err; 399 405 } 400 406 407 + static int __net_init netns_bpf_pernet_init(struct net *net) 408 + { 409 + int type; 410 + 411 + for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) 412 + INIT_LIST_HEAD(&net->bpf.links[type]); 413 + 414 + return 0; 415 + } 416 + 401 417 static void __net_exit netns_bpf_pernet_pre_exit(struct net *net) 402 418 { 403 419 enum netns_bpf_attach_type type; 404 - struct bpf_link *link; 420 + struct bpf_netns_link *net_link; 405 421 406 422 mutex_lock(&netns_bpf_mutex); 407 423 for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) { 408 424 netns_bpf_run_array_detach(net, type); 409 - link = net->bpf.links[type]; 410 - if (link) 411 - bpf_netns_link_auto_detach(link); 412 - else if (net->bpf.progs[type]) 425 + list_for_each_entry(net_link, &net->bpf.links[type], node) 426 + net_link->net = NULL; /* auto-detach link */ 427 + if (net->bpf.progs[type]) 413 428 bpf_prog_put(net->bpf.progs[type]); 414 429 } 415 430 mutex_unlock(&netns_bpf_mutex); 416 431 } 417 432 418 433 static struct pernet_operations netns_bpf_pernet_ops __net_initdata = { 434 + .init = netns_bpf_pernet_init, 419 435 .pre_exit = netns_bpf_pernet_pre_exit, 420 436 }; 421 437