mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-01 00:58:39 +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 */ | 	/* 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_array __rcu *run_array[MAX_NETNS_BPF_ATTACH_TYPE]; | ||||||
| 	struct bpf_prog *progs[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__ */ | #endif /* __NETNS_BPF_H__ */ | ||||||
|  |  | ||||||
|  | @ -19,20 +19,12 @@ struct bpf_netns_link { | ||||||
| 	 * with netns_bpf_mutex held. | 	 * with netns_bpf_mutex held. | ||||||
| 	 */ | 	 */ | ||||||
| 	struct net *net; | 	struct net *net; | ||||||
|  | 	struct list_head node; /* node in list of links attached to net */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* Protects updates to netns_bpf */ | /* Protects updates to netns_bpf */ | ||||||
| DEFINE_MUTEX(netns_bpf_mutex); | 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. */ | /* Must be called with netns_bpf_mutex held. */ | ||||||
| static void netns_bpf_run_array_detach(struct net *net, | static void netns_bpf_run_array_detach(struct net *net, | ||||||
| 				       enum netns_bpf_attach_type type) | 				       enum netns_bpf_attach_type type) | ||||||
|  | @ -66,7 +58,7 @@ static void bpf_netns_link_release(struct bpf_link *link) | ||||||
| 		goto out_unlock; | 		goto out_unlock; | ||||||
| 
 | 
 | ||||||
| 	netns_bpf_run_array_detach(net, type); | 	netns_bpf_run_array_detach(net, type); | ||||||
| 	net->bpf.links[type] = NULL; | 	list_del(&net_link->node); | ||||||
| 
 | 
 | ||||||
| out_unlock: | out_unlock: | ||||||
| 	mutex_unlock(&netns_bpf_mutex); | 	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); | 	mutex_lock(&netns_bpf_mutex); | ||||||
| 
 | 
 | ||||||
| 	/* Attaching prog directly is not compatible with links */ | 	/* Attaching prog directly is not compatible with links */ | ||||||
| 	if (net->bpf.links[type]) { | 	if (!list_empty(&net->bpf.links[type])) { | ||||||
| 		ret = -EEXIST; | 		ret = -EEXIST; | ||||||
| 		goto out_unlock; | 		goto out_unlock; | ||||||
| 	} | 	} | ||||||
|  | @ -279,7 +271,7 @@ static int __netns_bpf_prog_detach(struct net *net, | ||||||
| 	struct bpf_prog *attached; | 	struct bpf_prog *attached; | ||||||
| 
 | 
 | ||||||
| 	/* Progs attached via links cannot be detached */ | 	/* Progs attached via links cannot be detached */ | ||||||
| 	if (net->bpf.links[type]) | 	if (!list_empty(&net->bpf.links[type])) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	attached = net->bpf.progs[type]; | 	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, | static int netns_bpf_link_attach(struct net *net, struct bpf_link *link, | ||||||
| 				 enum netns_bpf_attach_type type) | 				 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; | 	struct bpf_prog_array *run_array; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&netns_bpf_mutex); | 	mutex_lock(&netns_bpf_mutex); | ||||||
| 
 | 
 | ||||||
| 	/* Allow attaching only one prog or link for now */ | 	/* Allow attaching only one prog or link for now */ | ||||||
| 	if (net->bpf.links[type]) { | 	if (!list_empty(&net->bpf.links[type])) { | ||||||
| 		err = -E2BIG; | 		err = -E2BIG; | ||||||
| 		goto out_unlock; | 		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; | 	run_array->items[0].prog = link->prog; | ||||||
| 	rcu_assign_pointer(net->bpf.run_array[type], run_array); | 	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: | out_unlock: | ||||||
| 	mutex_unlock(&netns_bpf_mutex); | 	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; | 	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) | static void __net_exit netns_bpf_pernet_pre_exit(struct net *net) | ||||||
| { | { | ||||||
| 	enum netns_bpf_attach_type type; | 	enum netns_bpf_attach_type type; | ||||||
| 	struct bpf_link *link; | 	struct bpf_netns_link *net_link; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&netns_bpf_mutex); | 	mutex_lock(&netns_bpf_mutex); | ||||||
| 	for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) { | 	for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) { | ||||||
| 		netns_bpf_run_array_detach(net, type); | 		netns_bpf_run_array_detach(net, type); | ||||||
| 		link = net->bpf.links[type]; | 		list_for_each_entry(net_link, &net->bpf.links[type], node) | ||||||
| 		if (link) | 			net_link->net = NULL; /* auto-detach link */ | ||||||
| 			bpf_netns_link_auto_detach(link); | 		if (net->bpf.progs[type]) | ||||||
| 		else if (net->bpf.progs[type]) |  | ||||||
| 			bpf_prog_put(net->bpf.progs[type]); | 			bpf_prog_put(net->bpf.progs[type]); | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&netns_bpf_mutex); | 	mutex_unlock(&netns_bpf_mutex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct pernet_operations netns_bpf_pernet_ops __net_initdata = { | static struct pernet_operations netns_bpf_pernet_ops __net_initdata = { | ||||||
|  | 	.init = netns_bpf_pernet_init, | ||||||
| 	.pre_exit = netns_bpf_pernet_pre_exit, | 	.pre_exit = netns_bpf_pernet_pre_exit, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Jakub Sitnicki
						Jakub Sitnicki