/* * Functions to manage BPF programs attached to netns
*/
struct bpf_netns_link { struct bpf_link link;
/* We don't hold a ref to net in order to auto-detach the link * when netns is going away. Instead we rely on pernet * pre_exit callback to clear this pointer. Must be accessed * with netns_bpf_mutex held.
*/ struct net *net; struct list_head node; /* node in list of links attached to net */ enum netns_bpf_attach_type netns_type;
};
/* Protects updates to netns_bpf */
DEFINE_MUTEX(netns_bpf_mutex);
/* Must be called with netns_bpf_mutex held. */ staticvoid netns_bpf_run_array_detach(struct net *net, enum netns_bpf_attach_type type)
{ struct bpf_prog_array *run_array;
staticvoid bpf_netns_link_release(struct bpf_link *link)
{ struct bpf_netns_link *net_link =
container_of(link, struct bpf_netns_link, link); enum netns_bpf_attach_type type = net_link->netns_type; struct bpf_prog_array *old_array, *new_array; struct net *net; int cnt, idx;
mutex_lock(&netns_bpf_mutex);
/* We can race with cleanup_net, but if we see a non-NULL * struct net pointer, pre_exit has not run yet and wait for * netns_bpf_mutex.
*/
net = net_link->net; if (!net) goto out_unlock;
/* Mark attach point as unused */
netns_bpf_attach_type_unneed(type);
/* Remember link position in case of safe delete */
idx = link_index(net, type, net_link);
list_del(&net_link->node);
int netns_bpf_prog_query(constunion bpf_attr *attr, union bpf_attr __user *uattr)
{ enum netns_bpf_attach_type type; struct net *net; int ret;
if (attr->query.query_flags) return -EINVAL;
type = to_netns_bpf_attach_type(attr->query.attach_type); if (type < 0) return -EINVAL;
net = get_net_ns_by_fd(attr->query.target_fd); if (IS_ERR(net)) return PTR_ERR(net);
mutex_lock(&netns_bpf_mutex);
ret = __netns_bpf_prog_query(attr, uattr, net, type);
mutex_unlock(&netns_bpf_mutex);
put_net(net); return ret;
}
int netns_bpf_prog_attach(constunion bpf_attr *attr, struct bpf_prog *prog)
{ struct bpf_prog_array *run_array; enum netns_bpf_attach_type type; struct bpf_prog *attached; struct net *net; int ret;
if (attr->target_fd || attr->attach_flags || attr->replace_bpf_fd) return -EINVAL;
type = to_netns_bpf_attach_type(attr->attach_type); if (type < 0) return -EINVAL;
net = current->nsproxy->net_ns;
mutex_lock(&netns_bpf_mutex);
/* Attaching prog directly is not compatible with links */ if (!list_empty(&net->bpf.links[type])) {
ret = -EEXIST; goto out_unlock;
}
switch (type) { case NETNS_BPF_FLOW_DISSECTOR:
ret = flow_dissector_bpf_prog_attach_check(net, prog); break; default:
ret = -EINVAL; break;
} if (ret) goto out_unlock;
attached = net->bpf.progs[type]; if (attached == prog) { /* The same program cannot be attached twice */
ret = -EINVAL; goto out_unlock;
}
net->bpf.progs[type] = prog; if (attached)
bpf_prog_put(attached);
out_unlock:
mutex_unlock(&netns_bpf_mutex);
return ret;
}
/* Must be called with netns_bpf_mutex held. */ staticint __netns_bpf_prog_detach(struct net *net, enum netns_bpf_attach_type type, struct bpf_prog *old)
{ struct bpf_prog *attached;
/* Progs attached via links cannot be detached */ if (!list_empty(&net->bpf.links[type])) return -EINVAL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.