staticbool init_net_initialized; /* * pernet_ops_rwsem: protects: pernet_list, net_generic_ids, * init_net_initialized and first_device pointer. * This is internal net namespace object. Please, don't use it * outside.
*/
DECLARE_RWSEM(pernet_ops_rwsem);
ng = net_alloc_generic(); if (!ng) return -ENOMEM;
/* * Some synchronisation notes: * * The net_generic explores the net->gen array inside rcu * read section. Besides once set the net->gen->ptr[x] * pointer never changes (see rules in netns/generic.h). * * That said, we simply duplicate this array and schedule * the old copy for kfree after a grace period.
*/
/* Another CPU might be rcu-iterating the list, wait for it. * This needs to be before calling the exit() notifiers, so the * rcu_barrier() after ops_undo_list() isn't sufficient alone. * Also the pre_exit() and exit() methods need this barrier.
*/ if (expedite_rcu)
synchronize_rcu_expedited(); else
synchronize_rcu();
if (hold_rtnl)
ops_exit_rtnl_list(ops_list, saved_ops, net_exit_list);
/* This function is used by idr_for_each(). If net is equal to peer, the * function returns the id so that idr_for_each() stops. Because we cannot * returns the id 0 (idr_for_each() will not stop), we return the magic value * NET_ID_ZERO (-1) for it.
*/ #define NET_ID_ZERO -1 staticint net_eq_idr(int id, void *net, void *peer)
{ if (net_eq(net, peer)) return id ? : NET_ID_ZERO; return 0;
}
/* Must be called from RCU-critical section or with nsid_lock held */ staticint __peernet2id(conststruct net *net, struct net *peer)
{ int id = idr_for_each(&net->netns_ids, net_eq_idr, peer);
/* Magic value for id 0. */ if (id == NET_ID_ZERO) return 0; if (id > 0) return id;
return NETNSA_NSID_NOT_ASSIGNED;
}
staticvoid rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, struct nlmsghdr *nlh, gfp_t gfp); /* This function returns the id of a peer netns. If no id is assigned, one will * be allocated and returned.
*/ int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp)
{ int id;
if (refcount_read(&net->ns.count) == 0) return NETNSA_NSID_NOT_ASSIGNED;
spin_lock(&net->nsid_lock);
id = __peernet2id(net, peer); if (id >= 0) {
spin_unlock(&net->nsid_lock); return id;
}
/* When peer is obtained from RCU lists, we may race with * its cleanup. Check whether it's alive, and this guarantees * we never hash a peer back to net->netns_ids, after it has * just been idr_remove()'d from there in cleanup_net().
*/ if (!maybe_get_net(peer)) {
spin_unlock(&net->nsid_lock); return NETNSA_NSID_NOT_ASSIGNED;
}
id = alloc_netid(net, peer, -1);
spin_unlock(&net->nsid_lock);
put_net(peer); if (id < 0) return NETNSA_NSID_NOT_ASSIGNED;
/* This function returns, if assigned, the id of a peer netns. */ int peernet2id(conststruct net *net, struct net *peer)
{ int id;
rcu_read_lock();
id = __peernet2id(net, peer);
rcu_read_unlock();
return id;
}
EXPORT_SYMBOL(peernet2id);
/* This function returns true is the peer netns has an id assigned into the * current netns.
*/ bool peernet_has_id(conststruct net *net, struct net *peer)
{ return peernet2id(net, peer) >= 0;
}
struct net *get_net_ns_by_id(conststruct net *net, int id)
{ struct net *peer;
/* init code that must occur even if setup_net() is not called. */ static __net_init void preinit_net(struct net *net, struct user_namespace *user_ns)
{
refcount_set(&net->passive, 1);
refcount_set(&net->ns.count, 1);
ref_tracker_dir_init(&net->refcnt_tracker, 128, "net_refcnt");
ref_tracker_dir_init(&net->notrefcnt_tracker, 128, "net_notrefcnt");
/* * setup_net runs the initializers for the network namespace object.
*/ static __net_init int setup_net(struct net *net)
{ /* Must be called with pernet_ops_rwsem held */ conststruct pernet_operations *ops;
LIST_HEAD(net_exit_list); int error = 0;
out_undo: /* Walk through the list backwards calling the exit functions * for the pernet modules whose init functions did not fail.
*/
list_add(&net->exit_list, &net_exit_list);
ops_undo_list(&pernet_list, ops, &net_exit_list, false);
rcu_barrier(); goto out;
}
/** * net_ns_get_ownership - get sysfs ownership data for @net * @net: network namespace in question (can be NULL) * @uid: kernel user ID for sysfs objects * @gid: kernel group ID for sysfs objects * * Returns the uid/gid pair of root in the user namespace associated with the * given network namespace.
*/ void net_ns_get_ownership(conststruct net *net, kuid_t *uid, kgid_t *gid)
{ if (net) {
kuid_t ns_root_uid = make_kuid(net->user_ns, 0);
kgid_t ns_root_gid = make_kgid(net->user_ns, 0);
staticvoid unhash_nsid(struct net *net, struct net *last)
{ struct net *tmp; /* This function is only called from cleanup_net() work, * and this work is the only process, that may delete * a net from net_namespace_list. So, when the below * is executing, the list may only grow. Thus, we do not * use for_each_net_rcu() or net_rwsem.
*/
for_each_net(tmp) { int id;
spin_lock(&tmp->nsid_lock);
id = __peernet2id(tmp, net); if (id >= 0)
idr_remove(&tmp->netns_ids, id);
spin_unlock(&tmp->nsid_lock); if (id >= 0)
rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL,
GFP_KERNEL); if (tmp == last) break;
}
spin_lock(&net->nsid_lock);
idr_destroy(&net->netns_ids);
spin_unlock(&net->nsid_lock);
}
/* Atomically snapshot the list of namespaces to cleanup */
net_kill_list = llist_del_all(&cleanup_list);
down_read(&pernet_ops_rwsem);
/* Don't let anyone else find us. */
down_write(&net_rwsem);
llist_for_each_entry(net, net_kill_list, cleanup_list)
list_del_rcu(&net->list); /* Cache last net. After we unlock rtnl, no one new net * added to net_namespace_list can assign nsid pointer * to a net from net_kill_list (see peernet2id_alloc()). * So, we skip them in unhash_nsid(). * * Note, that unhash_nsid() does not delete nsid links * between net_kill_list's nets, as they've already * deleted from net_namespace_list. But, this would be * useless anyway, as netns_ids are destroyed there.
*/
last = list_last_entry(&net_namespace_list, struct net, list);
up_write(&net_rwsem);
/* Ensure there are no outstanding rcu callbacks using this * network namespace.
*/
rcu_barrier();
net_complete_free();
/* Finally it is safe to free my network namespace structure */
list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
list_del_init(&net->exit_list);
dec_net_namespaces(net->ucounts); #ifdef CONFIG_KEYS
key_remove_domain(net->key_domain); #endif
put_user_ns(net->user_ns);
net_passive_dec(net);
}
WRITE_ONCE(cleanup_net_task, NULL);
}
/** * net_ns_barrier - wait until concurrent net_cleanup_work is done * * cleanup_net runs from work queue and will first remove namespaces * from the global list, then run net exit functions. * * Call this in module exit path to make sure that all netns * ->exit ops have been invoked before the function is removed.
*/ void net_ns_barrier(void)
{
down_write(&pernet_ops_rwsem);
up_write(&pernet_ops_rwsem);
}
EXPORT_SYMBOL(net_ns_barrier);
void __put_net(struct net *net)
{
ref_tracker_dir_exit(&net->refcnt_tracker); /* Cleanup the network namespace in process context */ if (llist_add(&net->cleanup_list, &cleanup_list))
queue_work(netns_wq, &net_cleanup_work);
}
EXPORT_SYMBOL_GPL(__put_net);
/** * get_net_ns - increment the refcount of the network namespace * @ns: common namespace (net) * * Returns the net's common namespace or ERR_PTR() if ref is zero.
*/ struct ns_common *get_net_ns(struct ns_common *ns)
{ struct net *net;
net = maybe_get_net(container_of(ns, struct net, ns)); if (net) return &net->ns; return ERR_PTR(-EINVAL);
}
EXPORT_SYMBOL_GPL(get_net_ns);
struct net *get_net_ns_by_fd(int fd)
{ CLASS(fd, f)(fd);
if (fd_empty(f)) return ERR_PTR(-EBADF);
if (proc_ns_file(fd_file(f))) { struct ns_common *ns = get_proc_ns(file_inode(fd_file(f))); if (ns->ops == &netns_operations) return get_net(container_of(ns, struct net, ns));
}
static __net_init int net_ns_net_init(struct net *net)
{ #ifdef CONFIG_NET_NS
net->ns.ops = &netns_operations; #endif
net->ns.inum = PROC_NET_INIT_INO; if (net != &init_net) { int ret = ns_alloc_inum(&net->ns); if (ret) return ret;
}
net_ns_net_debugfs(net); return 0;
}
static __net_exit void net_ns_net_exit(struct net *net)
{ /* * Initial network namespace doesn't exit so we don't need any * special checks here.
*/
ns_free_inum(&net->ns);
}
for (i = 0; i <= NETNSA_MAX; i++) { if (!tb[i]) continue;
switch (i) { case NETNSA_PID: case NETNSA_FD: case NETNSA_NSID: case NETNSA_TARGET_NSID: break; default:
NL_SET_ERR_MSG(extack, "Unsupported attribute in peer netns getid request"); return -EINVAL;
}
}
if (register_pernet_subsys(&net_ns_ops))
panic("Could not register network namespace subsystems");
rtnl_register_many(net_ns_rtnl_msg_handlers);
}
#ifdef CONFIG_NET_NS staticint __register_pernet_operations(struct list_head *list, struct pernet_operations *ops)
{
LIST_HEAD(net_exit_list); struct net *net; int error;
list_add_tail(&ops->list, list); if (ops->init || ops->id) { /* We held write locked pernet_ops_rwsem, and parallel * setup_net() and cleanup_net() are not possible.
*/
for_each_net(net) {
error = ops_init(ops, net); if (error) goto out_undo;
list_add_tail(&net->exit_list, &net_exit_list);
}
} return 0;
out_undo: /* If I have an error cleanup all namespaces I initialized */
list_del(&ops->list);
ops_undo_single(ops, &net_exit_list); return error;
}
staticvoid __unregister_pernet_operations(struct pernet_operations *ops)
{
LIST_HEAD(net_exit_list); struct net *net;
/* See comment in __register_pernet_operations() */
for_each_net(net)
list_add_tail(&net->exit_list, &net_exit_list);
staticint register_pernet_operations(struct list_head *list, struct pernet_operations *ops)
{ int error;
if (WARN_ON(!!ops->id ^ !!ops->size)) return -EINVAL;
if (ops->id) {
error = ida_alloc_min(&net_generic_ids, MIN_PERNET_OPS_ID,
GFP_KERNEL); if (error < 0) return error;
*ops->id = error; /* This does not require READ_ONCE as writers already hold * pernet_ops_rwsem. But WRITE_ONCE is needed to protect * net_alloc_generic.
*/
WRITE_ONCE(max_gen_ptrs, max(max_gen_ptrs, *ops->id + 1));
}
error = __register_pernet_operations(list, ops); if (error) {
rcu_barrier(); if (ops->id)
ida_free(&net_generic_ids, *ops->id);
}
/** * register_pernet_subsys - register a network namespace subsystem * @ops: pernet operations structure for the subsystem * * Register a subsystem which has init and exit functions * that are called when network namespaces are created and * destroyed respectively. * * When registered all network namespace init functions are * called for every existing network namespace. Allowing kernel * modules to have a race free view of the set of network namespaces. * * When a new network namespace is created all of the init * methods are called in the order in which they were registered. * * When a network namespace is destroyed all of the exit methods * are called in the reverse of the order with which they were * registered.
*/ int register_pernet_subsys(struct pernet_operations *ops)
{ int error;
down_write(&pernet_ops_rwsem);
error = register_pernet_operations(first_device, ops);
up_write(&pernet_ops_rwsem); return error;
}
EXPORT_SYMBOL_GPL(register_pernet_subsys);
/** * unregister_pernet_subsys - unregister a network namespace subsystem * @ops: pernet operations structure to manipulate * * Remove the pernet operations structure from the list to be * used when network namespaces are created or destroyed. In * addition run the exit method for all existing network * namespaces.
*/ void unregister_pernet_subsys(struct pernet_operations *ops)
{
down_write(&pernet_ops_rwsem);
unregister_pernet_operations(ops);
up_write(&pernet_ops_rwsem);
}
EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
/** * register_pernet_device - register a network namespace device * @ops: pernet operations structure for the subsystem * * Register a device which has init and exit functions * that are called when network namespaces are created and * destroyed respectively. * * When registered all network namespace init functions are * called for every existing network namespace. Allowing kernel * modules to have a race free view of the set of network namespaces. * * When a new network namespace is created all of the init * methods are called in the order in which they were registered. * * When a network namespace is destroyed all of the exit methods * are called in the reverse of the order with which they were * registered.
*/ int register_pernet_device(struct pernet_operations *ops)
{ int error;
down_write(&pernet_ops_rwsem);
error = register_pernet_operations(&pernet_list, ops); if (!error && (first_device == &pernet_list))
first_device = &ops->list;
up_write(&pernet_ops_rwsem); return error;
}
EXPORT_SYMBOL_GPL(register_pernet_device);
/** * unregister_pernet_device - unregister a network namespace netdevice * @ops: pernet operations structure to manipulate * * Remove the pernet operations structure from the list to be * used when network namespaces are created or destroyed. In * addition run the exit method for all existing network * namespaces.
*/ void unregister_pernet_device(struct pernet_operations *ops)
{
down_write(&pernet_ops_rwsem); if (&ops->list == first_device)
first_device = first_device->next;
unregister_pernet_operations(ops);
up_write(&pernet_ops_rwsem);
}
EXPORT_SYMBOL_GPL(unregister_pernet_device);
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.