mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	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
This commit is contained in:
		
							parent
							
								
									695c12147a
								
							
						
					
					
						commit
						ab53cad90e
					
				
					 2 changed files with 24 additions and 20 deletions
				
			
		|  | @ -15,7 +15,7 @@ struct netns_bpf { | |||
| 	/* Array of programs to run compiled from progs or links */ | ||||
| 	struct bpf_prog_array __rcu *run_array[MAX_NETNS_BPF_ATTACH_TYPE]; | ||||
| 	struct bpf_prog *progs[MAX_NETNS_BPF_ATTACH_TYPE]; | ||||
| 	struct bpf_link *links[MAX_NETNS_BPF_ATTACH_TYPE]; | ||||
| 	struct list_head links[MAX_NETNS_BPF_ATTACH_TYPE]; | ||||
| }; | ||||
| 
 | ||||
| #endif /* __NETNS_BPF_H__ */ | ||||
|  |  | |||
|  | @ -19,20 +19,12 @@ struct bpf_netns_link { | |||
| 	 * with netns_bpf_mutex held. | ||||
| 	 */ | ||||
| 	struct net *net; | ||||
| 	struct list_head node; /* node in list of links attached to net */ | ||||
| }; | ||||
| 
 | ||||
| /* Protects updates to netns_bpf */ | ||||
| DEFINE_MUTEX(netns_bpf_mutex); | ||||
| 
 | ||||
| /* Must be called with netns_bpf_mutex held. */ | ||||
| static void __net_exit bpf_netns_link_auto_detach(struct bpf_link *link) | ||||
| { | ||||
| 	struct bpf_netns_link *net_link = | ||||
| 		container_of(link, struct bpf_netns_link, link); | ||||
| 
 | ||||
| 	net_link->net = NULL; | ||||
| } | ||||
| 
 | ||||
| /* Must be called with netns_bpf_mutex held. */ | ||||
| static void netns_bpf_run_array_detach(struct net *net, | ||||
| 				       enum netns_bpf_attach_type type) | ||||
|  | @ -66,7 +58,7 @@ static void bpf_netns_link_release(struct bpf_link *link) | |||
| 		goto out_unlock; | ||||
| 
 | ||||
| 	netns_bpf_run_array_detach(net, type); | ||||
| 	net->bpf.links[type] = NULL; | ||||
| 	list_del(&net_link->node); | ||||
| 
 | ||||
| out_unlock: | ||||
| 	mutex_unlock(&netns_bpf_mutex); | ||||
|  | @ -225,7 +217,7 @@ int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog) | |||
| 	mutex_lock(&netns_bpf_mutex); | ||||
| 
 | ||||
| 	/* Attaching prog directly is not compatible with links */ | ||||
| 	if (net->bpf.links[type]) { | ||||
| 	if (!list_empty(&net->bpf.links[type])) { | ||||
| 		ret = -EEXIST; | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
|  | @ -279,7 +271,7 @@ static int __netns_bpf_prog_detach(struct net *net, | |||
| 	struct bpf_prog *attached; | ||||
| 
 | ||||
| 	/* Progs attached via links cannot be detached */ | ||||
| 	if (net->bpf.links[type]) | ||||
| 	if (!list_empty(&net->bpf.links[type])) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	attached = net->bpf.progs[type]; | ||||
|  | @ -310,13 +302,15 @@ int netns_bpf_prog_detach(const union bpf_attr *attr) | |||
| static int netns_bpf_link_attach(struct net *net, struct bpf_link *link, | ||||
| 				 enum netns_bpf_attach_type type) | ||||
| { | ||||
| 	struct bpf_netns_link *net_link = | ||||
| 		container_of(link, struct bpf_netns_link, link); | ||||
| 	struct bpf_prog_array *run_array; | ||||
| 	int err; | ||||
| 
 | ||||
| 	mutex_lock(&netns_bpf_mutex); | ||||
| 
 | ||||
| 	/* Allow attaching only one prog or link for now */ | ||||
| 	if (net->bpf.links[type]) { | ||||
| 	if (!list_empty(&net->bpf.links[type])) { | ||||
| 		err = -E2BIG; | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
|  | @ -345,7 +339,7 @@ static int netns_bpf_link_attach(struct net *net, struct bpf_link *link, | |||
| 	run_array->items[0].prog = link->prog; | ||||
| 	rcu_assign_pointer(net->bpf.run_array[type], run_array); | ||||
| 
 | ||||
| 	net->bpf.links[type] = link; | ||||
| 	list_add_tail(&net_link->node, &net->bpf.links[type]); | ||||
| 
 | ||||
| out_unlock: | ||||
| 	mutex_unlock(&netns_bpf_mutex); | ||||
|  | @ -404,24 +398,34 @@ int netns_bpf_link_create(const union bpf_attr *attr, struct bpf_prog *prog) | |||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int __net_init netns_bpf_pernet_init(struct net *net) | ||||
| { | ||||
| 	int type; | ||||
| 
 | ||||
| 	for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) | ||||
| 		INIT_LIST_HEAD(&net->bpf.links[type]); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void __net_exit netns_bpf_pernet_pre_exit(struct net *net) | ||||
| { | ||||
| 	enum netns_bpf_attach_type type; | ||||
| 	struct bpf_link *link; | ||||
| 	struct bpf_netns_link *net_link; | ||||
| 
 | ||||
| 	mutex_lock(&netns_bpf_mutex); | ||||
| 	for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) { | ||||
| 		netns_bpf_run_array_detach(net, type); | ||||
| 		link = net->bpf.links[type]; | ||||
| 		if (link) | ||||
| 			bpf_netns_link_auto_detach(link); | ||||
| 		else if (net->bpf.progs[type]) | ||||
| 		list_for_each_entry(net_link, &net->bpf.links[type], node) | ||||
| 			net_link->net = NULL; /* auto-detach link */ | ||||
| 		if (net->bpf.progs[type]) | ||||
| 			bpf_prog_put(net->bpf.progs[type]); | ||||
| 	} | ||||
| 	mutex_unlock(&netns_bpf_mutex); | ||||
| } | ||||
| 
 | ||||
| static struct pernet_operations netns_bpf_pernet_ops __net_initdata = { | ||||
| 	.init = netns_bpf_pernet_init, | ||||
| 	.pre_exit = netns_bpf_pernet_pre_exit, | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Jakub Sitnicki
						Jakub Sitnicki