datapath: Add support for namespace.
[sliver-openvswitch.git] / datapath / linux / compat / net_namespace.c
1 #include <linux/if_vlan.h>
2 #include <linux/netdevice.h>
3 #include <net/net_namespace.h>
4 #include <net/netns/generic.h>
5
6 #undef pernet_operations
7
8 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,32)
9 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
10 static int net_assign_generic(struct net *net, int id, void *data);
11 #endif
12
13 static int __net_init compat_init_net(struct net *net, struct rpl_pernet_operations *pnet)
14 {
15         int err;
16         void *ovs_net = kzalloc(pnet->size, GFP_KERNEL);
17
18         if (!ovs_net)
19                 return -ENOMEM;
20
21         err = net_assign_generic(net, *pnet->id, ovs_net);
22         if (err)
23                 goto err;
24
25         if (pnet->init) {
26                 err = pnet->init(net);
27                 if (err)
28                         goto err;
29         }
30
31         return 0;
32 err:
33         kfree(ovs_net);
34         return err;
35 }
36
37 static void __net_exit compat_exit_net(struct net *net, struct rpl_pernet_operations *pnet)
38 {
39         void *ovs_net = net_generic(net, *pnet->id);
40
41         if (pnet->exit)
42                 pnet->exit(net);
43         kfree(ovs_net);
44 }
45 #endif
46
47 #if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,32)
48 #define DEFINE_PNET_REG_FUNC(PNET_TYPE)                                 \
49         static struct rpl_pernet_operations *pnet_##PNET_TYPE;          \
50 static int __net_init compat_init_net_##PNET_TYPE(struct net *net)      \
51 {                                                                       \
52         return compat_init_net(net, pnet_##PNET_TYPE);                  \
53 }                                                                       \
54                                                                         \
55 static void __net_exit compat_exit_net_##PNET_TYPE(struct net *net)     \
56 {                                                                       \
57         compat_exit_net(net, pnet_##PNET_TYPE);                         \
58 }                                                                       \
59                                                                         \
60 static struct pernet_operations pnet_compat_##PNET_TYPE = {             \
61         .init = compat_init_net_##PNET_TYPE,                            \
62         .exit = compat_exit_net_##PNET_TYPE,                            \
63 };                                                                      \
64                                                                         \
65 int rpl_register_pernet_##PNET_TYPE(struct rpl_pernet_operations *rpl_pnet)     \
66 {                                                                               \
67         pnet_##PNET_TYPE = rpl_pnet;                                            \
68         return register_pernet_##PNET_TYPE(pnet_##PNET_TYPE->id, &pnet_compat_##PNET_TYPE); \
69 }                                                                                       \
70                                                                                         \
71 void rpl_unregister_pernet_##PNET_TYPE(struct rpl_pernet_operations *pnet)              \
72 {                                                                                       \
73         unregister_pernet_##PNET_TYPE(*pnet->id, &pnet_compat_##PNET_TYPE);             \
74 }
75
76 DEFINE_PNET_REG_FUNC(gen_device);
77
78 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
79 #define MAX_DATA_COUNT 1
80 static struct net *net;
81
82 static void *__ovs_net_data[MAX_DATA_COUNT];
83 static int count;
84
85 static int net_assign_generic(struct net *net, int id, void *data)
86 {
87         BUG_ON(id >= MAX_DATA_COUNT);
88         __ovs_net_data[id] = data;
89         return 0;
90 }
91
92 void *net_generic(const struct net *net, int id)
93 {
94         return __ovs_net_data[id];
95 }
96
97 int rpl_register_pernet_gen_device(struct rpl_pernet_operations *rpl_pnet)
98 {
99         *rpl_pnet->id = count++;
100         return compat_init_net(net, rpl_pnet);
101 }
102
103 void rpl_unregister_pernet_gen_device(struct rpl_pernet_operations *rpl_pnet)
104 {
105         compat_exit_net(net, rpl_pnet);
106 }
107
108 #endif