134e63756d
This makes generic netlink network namespace aware. No generic netlink families except for the controller family are made namespace aware, they need to be checked one by one and then set the family->netnsok member to true. A new function genlmsg_multicast_netns() is introduced to allow sending a multicast message in a given namespace, for example when it applies to an object that lives in that namespace, a new function genlmsg_multicast_allns() to send a message to all network namespaces (for objects that do not have an associated netns). The function genlmsg_multicast() is changed to multicast the message in just init_net, which is currently correct for all generic netlink families since they only work in init_net right now. Some will later want to work in all net namespaces because they do not care about the netns at all -- those will have to be converted to use one of the new functions genlmsg_multicast_allns() or genlmsg_multicast_netns() whenever they are made netns aware in some way. After this patch families can easily decide whether or not they should be available in all net namespaces. Many genl families us it for objects not related to networking and should therefore be available in all namespaces, but that will have to be done on a per family basis. Note that this doesn't touch on the checkpoint/restart problem where network namespaces could be used, genl families and multicast groups are numbered globally and I see no easy way of changing that, especially since it must be possible to multicast to all network namespaces for those families that do not care about netns. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: David S. Miller <davem@davemloft.net>
268 lines
6.4 KiB
C
268 lines
6.4 KiB
C
/*
|
|
* Operations on the network namespace
|
|
*/
|
|
#ifndef __NET_NET_NAMESPACE_H
|
|
#define __NET_NET_NAMESPACE_H
|
|
|
|
#include <asm/atomic.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/list.h>
|
|
|
|
#include <net/netns/core.h>
|
|
#include <net/netns/mib.h>
|
|
#include <net/netns/unix.h>
|
|
#include <net/netns/packet.h>
|
|
#include <net/netns/ipv4.h>
|
|
#include <net/netns/ipv6.h>
|
|
#include <net/netns/dccp.h>
|
|
#include <net/netns/x_tables.h>
|
|
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
|
|
#include <net/netns/conntrack.h>
|
|
#endif
|
|
#include <net/netns/xfrm.h>
|
|
|
|
struct proc_dir_entry;
|
|
struct net_device;
|
|
struct sock;
|
|
struct ctl_table_header;
|
|
struct net_generic;
|
|
struct sock;
|
|
|
|
struct net {
|
|
atomic_t count; /* To decided when the network
|
|
* namespace should be freed.
|
|
*/
|
|
#ifdef NETNS_REFCNT_DEBUG
|
|
atomic_t use_count; /* To track references we
|
|
* destroy on demand
|
|
*/
|
|
#endif
|
|
struct list_head list; /* list of network namespaces */
|
|
struct work_struct work; /* work struct for freeing */
|
|
|
|
struct proc_dir_entry *proc_net;
|
|
struct proc_dir_entry *proc_net_stat;
|
|
|
|
#ifdef CONFIG_SYSCTL
|
|
struct ctl_table_set sysctls;
|
|
#endif
|
|
|
|
struct net_device *loopback_dev; /* The loopback */
|
|
|
|
struct list_head dev_base_head;
|
|
struct hlist_head *dev_name_head;
|
|
struct hlist_head *dev_index_head;
|
|
|
|
/* core fib_rules */
|
|
struct list_head rules_ops;
|
|
spinlock_t rules_mod_lock;
|
|
|
|
struct sock *rtnl; /* rtnetlink socket */
|
|
struct sock *genl_sock;
|
|
|
|
struct netns_core core;
|
|
struct netns_mib mib;
|
|
struct netns_packet packet;
|
|
struct netns_unix unx;
|
|
struct netns_ipv4 ipv4;
|
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
struct netns_ipv6 ipv6;
|
|
#endif
|
|
#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
|
|
struct netns_dccp dccp;
|
|
#endif
|
|
#ifdef CONFIG_NETFILTER
|
|
struct netns_xt xt;
|
|
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
|
|
struct netns_ct ct;
|
|
#endif
|
|
#endif
|
|
#ifdef CONFIG_XFRM
|
|
struct netns_xfrm xfrm;
|
|
#endif
|
|
struct net_generic *gen;
|
|
};
|
|
|
|
|
|
#include <linux/seq_file_net.h>
|
|
|
|
/* Init's network namespace */
|
|
extern struct net init_net;
|
|
|
|
#ifdef CONFIG_NET
|
|
#define INIT_NET_NS(net_ns) .net_ns = &init_net,
|
|
|
|
extern struct net *copy_net_ns(unsigned long flags, struct net *net_ns);
|
|
|
|
#else /* CONFIG_NET */
|
|
|
|
#define INIT_NET_NS(net_ns)
|
|
|
|
static inline struct net *copy_net_ns(unsigned long flags, struct net *net_ns)
|
|
{
|
|
/* There is nothing to copy so this is a noop */
|
|
return net_ns;
|
|
}
|
|
#endif /* CONFIG_NET */
|
|
|
|
|
|
extern struct list_head net_namespace_list;
|
|
|
|
#ifdef CONFIG_NET_NS
|
|
extern void __put_net(struct net *net);
|
|
|
|
static inline struct net *get_net(struct net *net)
|
|
{
|
|
atomic_inc(&net->count);
|
|
return net;
|
|
}
|
|
|
|
static inline struct net *maybe_get_net(struct net *net)
|
|
{
|
|
/* Used when we know struct net exists but we
|
|
* aren't guaranteed a previous reference count
|
|
* exists. If the reference count is zero this
|
|
* function fails and returns NULL.
|
|
*/
|
|
if (!atomic_inc_not_zero(&net->count))
|
|
net = NULL;
|
|
return net;
|
|
}
|
|
|
|
static inline void put_net(struct net *net)
|
|
{
|
|
if (atomic_dec_and_test(&net->count))
|
|
__put_net(net);
|
|
}
|
|
|
|
static inline
|
|
int net_eq(const struct net *net1, const struct net *net2)
|
|
{
|
|
return net1 == net2;
|
|
}
|
|
#else
|
|
|
|
static inline struct net *get_net(struct net *net)
|
|
{
|
|
return net;
|
|
}
|
|
|
|
static inline void put_net(struct net *net)
|
|
{
|
|
}
|
|
|
|
static inline struct net *maybe_get_net(struct net *net)
|
|
{
|
|
return net;
|
|
}
|
|
|
|
static inline
|
|
int net_eq(const struct net *net1, const struct net *net2)
|
|
{
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef NETNS_REFCNT_DEBUG
|
|
static inline struct net *hold_net(struct net *net)
|
|
{
|
|
if (net)
|
|
atomic_inc(&net->use_count);
|
|
return net;
|
|
}
|
|
|
|
static inline void release_net(struct net *net)
|
|
{
|
|
if (net)
|
|
atomic_dec(&net->use_count);
|
|
}
|
|
#else
|
|
static inline struct net *hold_net(struct net *net)
|
|
{
|
|
return net;
|
|
}
|
|
|
|
static inline void release_net(struct net *net)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_NET_NS
|
|
|
|
static inline void write_pnet(struct net **pnet, struct net *net)
|
|
{
|
|
*pnet = net;
|
|
}
|
|
|
|
static inline struct net *read_pnet(struct net * const *pnet)
|
|
{
|
|
return *pnet;
|
|
}
|
|
|
|
#else
|
|
|
|
#define write_pnet(pnet, net) do { (void)(net);} while (0)
|
|
#define read_pnet(pnet) (&init_net)
|
|
|
|
#endif
|
|
|
|
#define for_each_net(VAR) \
|
|
list_for_each_entry(VAR, &net_namespace_list, list)
|
|
|
|
#define for_each_net_rcu(VAR) \
|
|
list_for_each_entry_rcu(VAR, &net_namespace_list, list)
|
|
|
|
#ifdef CONFIG_NET_NS
|
|
#define __net_init
|
|
#define __net_exit
|
|
#define __net_initdata
|
|
#else
|
|
#define __net_init __init
|
|
#define __net_exit __exit_refok
|
|
#define __net_initdata __initdata
|
|
#endif
|
|
|
|
struct pernet_operations {
|
|
struct list_head list;
|
|
int (*init)(struct net *net);
|
|
void (*exit)(struct net *net);
|
|
};
|
|
|
|
/*
|
|
* Use these carefully. If you implement a network device and it
|
|
* needs per network namespace operations use device pernet operations,
|
|
* otherwise use pernet subsys operations.
|
|
*
|
|
* This is critically important. Most of the network code cleanup
|
|
* runs with the assumption that dev_remove_pack has been called so no
|
|
* new packets will arrive during and after the cleanup functions have
|
|
* been called. dev_remove_pack is not per namespace so instead the
|
|
* guarantee of no more packets arriving in a network namespace is
|
|
* provided by ensuring that all network devices and all sockets have
|
|
* left the network namespace before the cleanup methods are called.
|
|
*
|
|
* For the longest time the ipv4 icmp code was registered as a pernet
|
|
* device which caused kernel oops, and panics during network
|
|
* namespace cleanup. So please don't get this wrong.
|
|
*/
|
|
extern int register_pernet_subsys(struct pernet_operations *);
|
|
extern void unregister_pernet_subsys(struct pernet_operations *);
|
|
extern int register_pernet_gen_subsys(int *id, struct pernet_operations *);
|
|
extern void unregister_pernet_gen_subsys(int id, struct pernet_operations *);
|
|
extern int register_pernet_device(struct pernet_operations *);
|
|
extern void unregister_pernet_device(struct pernet_operations *);
|
|
extern int register_pernet_gen_device(int *id, struct pernet_operations *);
|
|
extern void unregister_pernet_gen_device(int id, struct pernet_operations *);
|
|
|
|
struct ctl_path;
|
|
struct ctl_table;
|
|
struct ctl_table_header;
|
|
|
|
extern struct ctl_table_header *register_net_sysctl_table(struct net *net,
|
|
const struct ctl_path *path, struct ctl_table *table);
|
|
extern struct ctl_table_header *register_net_sysctl_rotable(
|
|
const struct ctl_path *path, struct ctl_table *table);
|
|
extern void unregister_net_sysctl_table(struct ctl_table_header *header);
|
|
|
|
#endif /* __NET_NET_NAMESPACE_H */
|