aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2014-10-22 11:29:06 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-28 14:43:18 -0400
commit62b9c8d0372d11a5e048c6b56997374901e0445b (patch)
treee75c8fdf723466e9aa98997b6555fb5baa9c55d7 /net/openvswitch
parentcf7b2003866ca5afc91dcddf9d91b627101f9654 (diff)
ovs: Turn vports with dependencies into separate modules
The internal and netdev vport remain part of openvswitch.ko. Encap vports including vxlan, gre, and geneve can be built as separate modules and are loaded on demand. Modules can be unloaded after use. Datapath ports keep a reference to the vport module during their lifetime. Allows to remove the error prone maintenance of the global list vport_ops_list. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/Kconfig18
-rw-r--r--net/openvswitch/Makefile14
-rw-r--r--net/openvswitch/datapath.c16
-rw-r--r--net/openvswitch/vport-geneve.c23
-rw-r--r--net/openvswitch/vport-gre.c23
-rw-r--r--net/openvswitch/vport-internal_dev.c17
-rw-r--r--net/openvswitch/vport-netdev.c14
-rw-r--r--net/openvswitch/vport-netdev.h3
-rw-r--r--net/openvswitch/vport-vxlan.c23
-rw-r--r--net/openvswitch/vport.c102
-rw-r--r--net/openvswitch/vport.h14
11 files changed, 199 insertions, 68 deletions
diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig
index ba3bb8203b99..2a9673e39ca1 100644
--- a/net/openvswitch/Kconfig
+++ b/net/openvswitch/Kconfig
@@ -29,11 +29,11 @@ config OPENVSWITCH
29 If unsure, say N. 29 If unsure, say N.
30 30
31config OPENVSWITCH_GRE 31config OPENVSWITCH_GRE
32 bool "Open vSwitch GRE tunneling support" 32 tristate "Open vSwitch GRE tunneling support"
33 depends on INET 33 depends on INET
34 depends on OPENVSWITCH 34 depends on OPENVSWITCH
35 depends on NET_IPGRE_DEMUX && !(OPENVSWITCH=y && NET_IPGRE_DEMUX=m) 35 depends on NET_IPGRE_DEMUX
36 default y 36 default OPENVSWITCH
37 ---help--- 37 ---help---
38 If you say Y here, then the Open vSwitch will be able create GRE 38 If you say Y here, then the Open vSwitch will be able create GRE
39 vport. 39 vport.
@@ -43,11 +43,11 @@ config OPENVSWITCH_GRE
43 If unsure, say Y. 43 If unsure, say Y.
44 44
45config OPENVSWITCH_VXLAN 45config OPENVSWITCH_VXLAN
46 bool "Open vSwitch VXLAN tunneling support" 46 tristate "Open vSwitch VXLAN tunneling support"
47 depends on INET 47 depends on INET
48 depends on OPENVSWITCH 48 depends on OPENVSWITCH
49 depends on VXLAN && !(OPENVSWITCH=y && VXLAN=m) 49 depends on VXLAN
50 default y 50 default OPENVSWITCH
51 ---help--- 51 ---help---
52 If you say Y here, then the Open vSwitch will be able create vxlan vport. 52 If you say Y here, then the Open vSwitch will be able create vxlan vport.
53 53
@@ -56,11 +56,11 @@ config OPENVSWITCH_VXLAN
56 If unsure, say Y. 56 If unsure, say Y.
57 57
58config OPENVSWITCH_GENEVE 58config OPENVSWITCH_GENEVE
59 bool "Open vSwitch Geneve tunneling support" 59 tristate "Open vSwitch Geneve tunneling support"
60 depends on INET 60 depends on INET
61 depends on OPENVSWITCH 61 depends on OPENVSWITCH
62 depends on GENEVE && !(OPENVSWITCH=y && GENEVE=m) 62 depends on GENEVE
63 default y 63 default OPENVSWITCH
64 ---help--- 64 ---help---
65 If you say Y here, then the Open vSwitch will be able create geneve vport. 65 If you say Y here, then the Open vSwitch will be able create geneve vport.
66 66
diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile
index 9a33a273c375..91b9478413ef 100644
--- a/net/openvswitch/Makefile
+++ b/net/openvswitch/Makefile
@@ -15,14 +15,6 @@ openvswitch-y := \
15 vport-internal_dev.o \ 15 vport-internal_dev.o \
16 vport-netdev.o 16 vport-netdev.o
17 17
18ifneq ($(CONFIG_OPENVSWITCH_GENEVE),) 18obj-$(CONFIG_OPENVSWITCH_GENEVE)+= vport-geneve.o
19openvswitch-y += vport-geneve.o 19obj-$(CONFIG_OPENVSWITCH_VXLAN) += vport-vxlan.o
20endif 20obj-$(CONFIG_OPENVSWITCH_GRE) += vport-gre.o
21
22ifneq ($(CONFIG_OPENVSWITCH_VXLAN),)
23openvswitch-y += vport-vxlan.o
24endif
25
26ifneq ($(CONFIG_OPENVSWITCH_GRE),)
27openvswitch-y += vport-gre.o
28endif
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index e6d7255183eb..aecddb9bb80a 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -59,6 +59,7 @@
59#include "vport-netdev.h" 59#include "vport-netdev.h"
60 60
61int ovs_net_id __read_mostly; 61int ovs_net_id __read_mostly;
62EXPORT_SYMBOL(ovs_net_id);
62 63
63static struct genl_family dp_packet_genl_family; 64static struct genl_family dp_packet_genl_family;
64static struct genl_family dp_flow_genl_family; 65static struct genl_family dp_flow_genl_family;
@@ -1764,6 +1765,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
1764 return -ENOMEM; 1765 return -ENOMEM;
1765 1766
1766 ovs_lock(); 1767 ovs_lock();
1768restart:
1767 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 1769 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
1768 err = -ENODEV; 1770 err = -ENODEV;
1769 if (!dp) 1771 if (!dp)
@@ -1795,8 +1797,11 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
1795 1797
1796 vport = new_vport(&parms); 1798 vport = new_vport(&parms);
1797 err = PTR_ERR(vport); 1799 err = PTR_ERR(vport);
1798 if (IS_ERR(vport)) 1800 if (IS_ERR(vport)) {
1801 if (err == -EAGAIN)
1802 goto restart;
1799 goto exit_unlock_free; 1803 goto exit_unlock_free;
1804 }
1800 1805
1801 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, 1806 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
1802 info->snd_seq, 0, OVS_VPORT_CMD_NEW); 1807 info->snd_seq, 0, OVS_VPORT_CMD_NEW);
@@ -2112,12 +2117,18 @@ static int __init dp_init(void)
2112 if (err) 2117 if (err)
2113 goto error_netns_exit; 2118 goto error_netns_exit;
2114 2119
2120 err = ovs_netdev_init();
2121 if (err)
2122 goto error_unreg_notifier;
2123
2115 err = dp_register_genl(); 2124 err = dp_register_genl();
2116 if (err < 0) 2125 if (err < 0)
2117 goto error_unreg_notifier; 2126 goto error_unreg_netdev;
2118 2127
2119 return 0; 2128 return 0;
2120 2129
2130error_unreg_netdev:
2131 ovs_netdev_exit();
2121error_unreg_notifier: 2132error_unreg_notifier:
2122 unregister_netdevice_notifier(&ovs_dp_device_notifier); 2133 unregister_netdevice_notifier(&ovs_dp_device_notifier);
2123error_netns_exit: 2134error_netns_exit:
@@ -2137,6 +2148,7 @@ error:
2137static void dp_cleanup(void) 2148static void dp_cleanup(void)
2138{ 2149{
2139 dp_unregister_genl(ARRAY_SIZE(dp_genl_families)); 2150 dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
2151 ovs_netdev_exit();
2140 unregister_netdevice_notifier(&ovs_dp_device_notifier); 2152 unregister_netdevice_notifier(&ovs_dp_device_notifier);
2141 unregister_pernet_device(&ovs_net_ops); 2153 unregister_pernet_device(&ovs_net_ops);
2142 rcu_barrier(); 2154 rcu_barrier();
diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c
index 106a9d80b663..70c9765011f4 100644
--- a/net/openvswitch/vport-geneve.c
+++ b/net/openvswitch/vport-geneve.c
@@ -17,6 +17,7 @@
17#include <linux/rculist.h> 17#include <linux/rculist.h>
18#include <linux/udp.h> 18#include <linux/udp.h>
19#include <linux/if_vlan.h> 19#include <linux/if_vlan.h>
20#include <linux/module.h>
20 21
21#include <net/geneve.h> 22#include <net/geneve.h>
22#include <net/icmp.h> 23#include <net/icmp.h>
@@ -28,6 +29,8 @@
28#include "datapath.h" 29#include "datapath.h"
29#include "vport.h" 30#include "vport.h"
30 31
32static struct vport_ops ovs_geneve_vport_ops;
33
31/** 34/**
32 * struct geneve_port - Keeps track of open UDP ports 35 * struct geneve_port - Keeps track of open UDP ports
33 * @gs: The socket created for this port number. 36 * @gs: The socket created for this port number.
@@ -225,11 +228,29 @@ static const char *geneve_get_name(const struct vport *vport)
225 return geneve_port->name; 228 return geneve_port->name;
226} 229}
227 230
228const struct vport_ops ovs_geneve_vport_ops = { 231static struct vport_ops ovs_geneve_vport_ops = {
229 .type = OVS_VPORT_TYPE_GENEVE, 232 .type = OVS_VPORT_TYPE_GENEVE,
230 .create = geneve_tnl_create, 233 .create = geneve_tnl_create,
231 .destroy = geneve_tnl_destroy, 234 .destroy = geneve_tnl_destroy,
232 .get_name = geneve_get_name, 235 .get_name = geneve_get_name,
233 .get_options = geneve_get_options, 236 .get_options = geneve_get_options,
234 .send = geneve_tnl_send, 237 .send = geneve_tnl_send,
238 .owner = THIS_MODULE,
235}; 239};
240
241static int __init ovs_geneve_tnl_init(void)
242{
243 return ovs_vport_ops_register(&ovs_geneve_vport_ops);
244}
245
246static void __exit ovs_geneve_tnl_exit(void)
247{
248 ovs_vport_ops_unregister(&ovs_geneve_vport_ops);
249}
250
251module_init(ovs_geneve_tnl_init);
252module_exit(ovs_geneve_tnl_exit);
253
254MODULE_DESCRIPTION("OVS: Geneve swiching port");
255MODULE_LICENSE("GPL");
256MODULE_ALIAS("vport-type-5");
diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c
index 108b82da2fd9..00270b608844 100644
--- a/net/openvswitch/vport-gre.c
+++ b/net/openvswitch/vport-gre.c
@@ -29,6 +29,7 @@
29#include <linux/jhash.h> 29#include <linux/jhash.h>
30#include <linux/list.h> 30#include <linux/list.h>
31#include <linux/kernel.h> 31#include <linux/kernel.h>
32#include <linux/module.h>
32#include <linux/workqueue.h> 33#include <linux/workqueue.h>
33#include <linux/rculist.h> 34#include <linux/rculist.h>
34#include <net/route.h> 35#include <net/route.h>
@@ -45,6 +46,8 @@
45#include "datapath.h" 46#include "datapath.h"
46#include "vport.h" 47#include "vport.h"
47 48
49static struct vport_ops ovs_gre_vport_ops;
50
48/* Returns the least-significant 32 bits of a __be64. */ 51/* Returns the least-significant 32 bits of a __be64. */
49static __be32 be64_get_low32(__be64 x) 52static __be32 be64_get_low32(__be64 x)
50{ 53{
@@ -281,10 +284,28 @@ static void gre_tnl_destroy(struct vport *vport)
281 gre_exit(); 284 gre_exit();
282} 285}
283 286
284const struct vport_ops ovs_gre_vport_ops = { 287static struct vport_ops ovs_gre_vport_ops = {
285 .type = OVS_VPORT_TYPE_GRE, 288 .type = OVS_VPORT_TYPE_GRE,
286 .create = gre_create, 289 .create = gre_create,
287 .destroy = gre_tnl_destroy, 290 .destroy = gre_tnl_destroy,
288 .get_name = gre_get_name, 291 .get_name = gre_get_name,
289 .send = gre_tnl_send, 292 .send = gre_tnl_send,
293 .owner = THIS_MODULE,
290}; 294};
295
296static int __init ovs_gre_tnl_init(void)
297{
298 return ovs_vport_ops_register(&ovs_gre_vport_ops);
299}
300
301static void __exit ovs_gre_tnl_exit(void)
302{
303 ovs_vport_ops_unregister(&ovs_gre_vport_ops);
304}
305
306module_init(ovs_gre_tnl_init);
307module_exit(ovs_gre_tnl_exit);
308
309MODULE_DESCRIPTION("OVS: GRE switching port");
310MODULE_LICENSE("GPL");
311MODULE_ALIAS("vport-type-3");
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c
index 84516126e5f3..10dc07e1678b 100644
--- a/net/openvswitch/vport-internal_dev.c
+++ b/net/openvswitch/vport-internal_dev.c
@@ -36,6 +36,8 @@ struct internal_dev {
36 struct vport *vport; 36 struct vport *vport;
37}; 37};
38 38
39static struct vport_ops ovs_internal_vport_ops;
40
39static struct internal_dev *internal_dev_priv(struct net_device *netdev) 41static struct internal_dev *internal_dev_priv(struct net_device *netdev)
40{ 42{
41 return netdev_priv(netdev); 43 return netdev_priv(netdev);
@@ -238,7 +240,7 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb)
238 return len; 240 return len;
239} 241}
240 242
241const struct vport_ops ovs_internal_vport_ops = { 243static struct vport_ops ovs_internal_vport_ops = {
242 .type = OVS_VPORT_TYPE_INTERNAL, 244 .type = OVS_VPORT_TYPE_INTERNAL,
243 .create = internal_dev_create, 245 .create = internal_dev_create,
244 .destroy = internal_dev_destroy, 246 .destroy = internal_dev_destroy,
@@ -261,10 +263,21 @@ struct vport *ovs_internal_dev_get_vport(struct net_device *netdev)
261 263
262int ovs_internal_dev_rtnl_link_register(void) 264int ovs_internal_dev_rtnl_link_register(void)
263{ 265{
264 return rtnl_link_register(&internal_dev_link_ops); 266 int err;
267
268 err = rtnl_link_register(&internal_dev_link_ops);
269 if (err < 0)
270 return err;
271
272 err = ovs_vport_ops_register(&ovs_internal_vport_ops);
273 if (err < 0)
274 rtnl_link_unregister(&internal_dev_link_ops);
275
276 return err;
265} 277}
266 278
267void ovs_internal_dev_rtnl_link_unregister(void) 279void ovs_internal_dev_rtnl_link_unregister(void)
268{ 280{
281 ovs_vport_ops_unregister(&ovs_internal_vport_ops);
269 rtnl_link_unregister(&internal_dev_link_ops); 282 rtnl_link_unregister(&internal_dev_link_ops);
270} 283}
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c
index d21f77d875ba..877ee74b4f08 100644
--- a/net/openvswitch/vport-netdev.c
+++ b/net/openvswitch/vport-netdev.c
@@ -33,6 +33,8 @@
33#include "vport-internal_dev.h" 33#include "vport-internal_dev.h"
34#include "vport-netdev.h" 34#include "vport-netdev.h"
35 35
36static struct vport_ops ovs_netdev_vport_ops;
37
36/* Must be called with rcu_read_lock. */ 38/* Must be called with rcu_read_lock. */
37static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) 39static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
38{ 40{
@@ -224,10 +226,20 @@ struct vport *ovs_netdev_get_vport(struct net_device *dev)
224 return NULL; 226 return NULL;
225} 227}
226 228
227const struct vport_ops ovs_netdev_vport_ops = { 229static struct vport_ops ovs_netdev_vport_ops = {
228 .type = OVS_VPORT_TYPE_NETDEV, 230 .type = OVS_VPORT_TYPE_NETDEV,
229 .create = netdev_create, 231 .create = netdev_create,
230 .destroy = netdev_destroy, 232 .destroy = netdev_destroy,
231 .get_name = ovs_netdev_get_name, 233 .get_name = ovs_netdev_get_name,
232 .send = netdev_send, 234 .send = netdev_send,
233}; 235};
236
237int __init ovs_netdev_init(void)
238{
239 return ovs_vport_ops_register(&ovs_netdev_vport_ops);
240}
241
242void ovs_netdev_exit(void)
243{
244 ovs_vport_ops_unregister(&ovs_netdev_vport_ops);
245}
diff --git a/net/openvswitch/vport-netdev.h b/net/openvswitch/vport-netdev.h
index 8df01c1127e5..6f7038e79c52 100644
--- a/net/openvswitch/vport-netdev.h
+++ b/net/openvswitch/vport-netdev.h
@@ -41,4 +41,7 @@ netdev_vport_priv(const struct vport *vport)
41const char *ovs_netdev_get_name(const struct vport *); 41const char *ovs_netdev_get_name(const struct vport *);
42void ovs_netdev_detach_dev(struct vport *); 42void ovs_netdev_detach_dev(struct vport *);
43 43
44int __init ovs_netdev_init(void);
45void ovs_netdev_exit(void);
46
44#endif /* vport_netdev.h */ 47#endif /* vport_netdev.h */
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c
index 2735e01dca73..965e7500c5a6 100644
--- a/net/openvswitch/vport-vxlan.c
+++ b/net/openvswitch/vport-vxlan.c
@@ -24,6 +24,7 @@
24#include <linux/net.h> 24#include <linux/net.h>
25#include <linux/rculist.h> 25#include <linux/rculist.h>
26#include <linux/udp.h> 26#include <linux/udp.h>
27#include <linux/module.h>
27 28
28#include <net/icmp.h> 29#include <net/icmp.h>
29#include <net/ip.h> 30#include <net/ip.h>
@@ -50,6 +51,8 @@ struct vxlan_port {
50 char name[IFNAMSIZ]; 51 char name[IFNAMSIZ];
51}; 52};
52 53
54static struct vport_ops ovs_vxlan_vport_ops;
55
53static inline struct vxlan_port *vxlan_vport(const struct vport *vport) 56static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
54{ 57{
55 return vport_priv(vport); 58 return vport_priv(vport);
@@ -192,11 +195,29 @@ static const char *vxlan_get_name(const struct vport *vport)
192 return vxlan_port->name; 195 return vxlan_port->name;
193} 196}
194 197
195const struct vport_ops ovs_vxlan_vport_ops = { 198static struct vport_ops ovs_vxlan_vport_ops = {
196 .type = OVS_VPORT_TYPE_VXLAN, 199 .type = OVS_VPORT_TYPE_VXLAN,
197 .create = vxlan_tnl_create, 200 .create = vxlan_tnl_create,
198 .destroy = vxlan_tnl_destroy, 201 .destroy = vxlan_tnl_destroy,
199 .get_name = vxlan_get_name, 202 .get_name = vxlan_get_name,
200 .get_options = vxlan_get_options, 203 .get_options = vxlan_get_options,
201 .send = vxlan_tnl_send, 204 .send = vxlan_tnl_send,
205 .owner = THIS_MODULE,
202}; 206};
207
208static int __init ovs_vxlan_tnl_init(void)
209{
210 return ovs_vport_ops_register(&ovs_vxlan_vport_ops);
211}
212
213static void __exit ovs_vxlan_tnl_exit(void)
214{
215 ovs_vport_ops_unregister(&ovs_vxlan_vport_ops);
216}
217
218module_init(ovs_vxlan_tnl_init);
219module_exit(ovs_vxlan_tnl_exit);
220
221MODULE_DESCRIPTION("OVS: VXLAN switching port");
222MODULE_LICENSE("GPL");
223MODULE_ALIAS("vport-type-4");
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 6015802ebe6f..8168ef021337 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -28,6 +28,7 @@
28#include <linux/rtnetlink.h> 28#include <linux/rtnetlink.h>
29#include <linux/compat.h> 29#include <linux/compat.h>
30#include <net/net_namespace.h> 30#include <net/net_namespace.h>
31#include <linux/module.h>
31 32
32#include "datapath.h" 33#include "datapath.h"
33#include "vport.h" 34#include "vport.h"
@@ -36,22 +37,7 @@
36static void ovs_vport_record_error(struct vport *, 37static void ovs_vport_record_error(struct vport *,
37 enum vport_err_type err_type); 38 enum vport_err_type err_type);
38 39
39/* List of statically compiled vport implementations. Don't forget to also 40static LIST_HEAD(vport_ops_list);
40 * add yours to the list at the bottom of vport.h. */
41static const struct vport_ops *vport_ops_list[] = {
42 &ovs_netdev_vport_ops,
43 &ovs_internal_vport_ops,
44
45#ifdef CONFIG_OPENVSWITCH_GRE
46 &ovs_gre_vport_ops,
47#endif
48#ifdef CONFIG_OPENVSWITCH_VXLAN
49 &ovs_vxlan_vport_ops,
50#endif
51#ifdef CONFIG_OPENVSWITCH_GENEVE
52 &ovs_geneve_vport_ops,
53#endif
54};
55 41
56/* Protected by RCU read lock for reading, ovs_mutex for writing. */ 42/* Protected by RCU read lock for reading, ovs_mutex for writing. */
57static struct hlist_head *dev_table; 43static struct hlist_head *dev_table;
@@ -88,6 +74,32 @@ static struct hlist_head *hash_bucket(struct net *net, const char *name)
88 return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)]; 74 return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)];
89} 75}
90 76
77int ovs_vport_ops_register(struct vport_ops *ops)
78{
79 int err = -EEXIST;
80 struct vport_ops *o;
81
82 ovs_lock();
83 list_for_each_entry(o, &vport_ops_list, list)
84 if (ops->type == o->type)
85 goto errout;
86
87 list_add_tail(&ops->list, &vport_ops_list);
88 err = 0;
89errout:
90 ovs_unlock();
91 return err;
92}
93EXPORT_SYMBOL(ovs_vport_ops_register);
94
95void ovs_vport_ops_unregister(struct vport_ops *ops)
96{
97 ovs_lock();
98 list_del(&ops->list);
99 ovs_unlock();
100}
101EXPORT_SYMBOL(ovs_vport_ops_unregister);
102
91/** 103/**
92 * ovs_vport_locate - find a port that has already been created 104 * ovs_vport_locate - find a port that has already been created
93 * 105 *
@@ -153,6 +165,7 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
153 165
154 return vport; 166 return vport;
155} 167}
168EXPORT_SYMBOL(ovs_vport_alloc);
156 169
157/** 170/**
158 * ovs_vport_free - uninitialize and free vport 171 * ovs_vport_free - uninitialize and free vport
@@ -173,6 +186,18 @@ void ovs_vport_free(struct vport *vport)
173 free_percpu(vport->percpu_stats); 186 free_percpu(vport->percpu_stats);
174 kfree(vport); 187 kfree(vport);
175} 188}
189EXPORT_SYMBOL(ovs_vport_free);
190
191static struct vport_ops *ovs_vport_lookup(const struct vport_parms *parms)
192{
193 struct vport_ops *ops;
194
195 list_for_each_entry(ops, &vport_ops_list, list)
196 if (ops->type == parms->type)
197 return ops;
198
199 return NULL;
200}
176 201
177/** 202/**
178 * ovs_vport_add - add vport device (for kernel callers) 203 * ovs_vport_add - add vport device (for kernel callers)
@@ -184,31 +209,40 @@ void ovs_vport_free(struct vport *vport)
184 */ 209 */
185struct vport *ovs_vport_add(const struct vport_parms *parms) 210struct vport *ovs_vport_add(const struct vport_parms *parms)
186{ 211{
212 struct vport_ops *ops;
187 struct vport *vport; 213 struct vport *vport;
188 int err = 0;
189 int i;
190 214
191 for (i = 0; i < ARRAY_SIZE(vport_ops_list); i++) { 215 ops = ovs_vport_lookup(parms);
192 if (vport_ops_list[i]->type == parms->type) { 216 if (ops) {
193 struct hlist_head *bucket; 217 struct hlist_head *bucket;
194 218
195 vport = vport_ops_list[i]->create(parms); 219 if (!try_module_get(ops->owner))
196 if (IS_ERR(vport)) { 220 return ERR_PTR(-EAFNOSUPPORT);
197 err = PTR_ERR(vport);
198 goto out;
199 }
200 221
201 bucket = hash_bucket(ovs_dp_get_net(vport->dp), 222 vport = ops->create(parms);
202 vport->ops->get_name(vport)); 223 if (IS_ERR(vport)) {
203 hlist_add_head_rcu(&vport->hash_node, bucket); 224 module_put(ops->owner);
204 return vport; 225 return vport;
205 } 226 }
227
228 bucket = hash_bucket(ovs_dp_get_net(vport->dp),
229 vport->ops->get_name(vport));
230 hlist_add_head_rcu(&vport->hash_node, bucket);
231 return vport;
206 } 232 }
207 233
208 err = -EAFNOSUPPORT; 234 /* Unlock to attempt module load and return -EAGAIN if load
235 * was successful as we need to restart the port addition
236 * workflow.
237 */
238 ovs_unlock();
239 request_module("vport-type-%d", parms->type);
240 ovs_lock();
209 241
210out: 242 if (!ovs_vport_lookup(parms))
211 return ERR_PTR(err); 243 return ERR_PTR(-EAFNOSUPPORT);
244 else
245 return ERR_PTR(-EAGAIN);
212} 246}
213 247
214/** 248/**
@@ -242,6 +276,8 @@ void ovs_vport_del(struct vport *vport)
242 hlist_del_rcu(&vport->hash_node); 276 hlist_del_rcu(&vport->hash_node);
243 277
244 vport->ops->destroy(vport); 278 vport->ops->destroy(vport);
279
280 module_put(vport->ops->owner);
245} 281}
246 282
247/** 283/**
@@ -457,6 +493,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
457 } 493 }
458 ovs_dp_process_packet(skb, &key); 494 ovs_dp_process_packet(skb, &key);
459} 495}
496EXPORT_SYMBOL(ovs_vport_receive);
460 497
461/** 498/**
462 * ovs_vport_send - send a packet on a device 499 * ovs_vport_send - send a packet on a device
@@ -535,3 +572,4 @@ void ovs_vport_deferred_free(struct vport *vport)
535 572
536 call_rcu(&vport->rcu, free_vport_rcu); 573 call_rcu(&vport->rcu, free_vport_rcu);
537} 574}
575EXPORT_SYMBOL(ovs_vport_deferred_free);
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
index 8942125de3a6..e41c3facf799 100644
--- a/net/openvswitch/vport.h
+++ b/net/openvswitch/vport.h
@@ -161,6 +161,9 @@ struct vport_ops {
161 const char *(*get_name)(const struct vport *); 161 const char *(*get_name)(const struct vport *);
162 162
163 int (*send)(struct vport *, struct sk_buff *); 163 int (*send)(struct vport *, struct sk_buff *);
164
165 struct module *owner;
166 struct list_head list;
164}; 167};
165 168
166enum vport_err_type { 169enum vport_err_type {
@@ -209,14 +212,6 @@ static inline struct vport *vport_from_priv(void *priv)
209void ovs_vport_receive(struct vport *, struct sk_buff *, 212void ovs_vport_receive(struct vport *, struct sk_buff *,
210 struct ovs_tunnel_info *); 213 struct ovs_tunnel_info *);
211 214
212/* List of statically compiled vport implementations. Don't forget to also
213 * add yours to the list at the top of vport.c. */
214extern const struct vport_ops ovs_netdev_vport_ops;
215extern const struct vport_ops ovs_internal_vport_ops;
216extern const struct vport_ops ovs_gre_vport_ops;
217extern const struct vport_ops ovs_vxlan_vport_ops;
218extern const struct vport_ops ovs_geneve_vport_ops;
219
220static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, 215static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb,
221 const void *start, unsigned int len) 216 const void *start, unsigned int len)
222{ 217{
@@ -224,4 +219,7 @@ static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb,
224 skb->csum = csum_add(skb->csum, csum_partial(start, len, 0)); 219 skb->csum = csum_add(skb->csum, csum_partial(start, len, 0));
225} 220}
226 221
222int ovs_vport_ops_register(struct vport_ops *ops);
223void ovs_vport_ops_unregister(struct vport_ops *ops);
224
227#endif /* vport.h */ 225#endif /* vport.h */