#endif
};
-static bool inited;
-
+static int gre_ports;
static int gre_init(void)
{
int err;
- if (inited)
+ gre_ports++;
+ if (gre_ports > 1)
return 0;
- inited = true;
err = inet_add_protocol(&gre_protocol_handlers, IPPROTO_GRE);
if (err)
pr_warn("cannot register gre protocol handler\n");
static void gre_exit(void)
{
- if (!inited)
+ gre_ports--;
+ if (gre_ports > 0)
return;
- inited = false;
-
inet_del_protocol(&gre_protocol_handlers, IPPROTO_GRE);
}
struct net *net = ovs_dp_get_net(parms->dp);
struct ovs_net *ovs_net;
struct vport *vport;
+ int err;
+
+ err = gre_init();
+ if (err)
+ return ERR_PTR(err);
ovs_net = net_generic(net, ovs_net_id);
- if (ovsl_dereference(ovs_net->vport_net.gre_vport))
- return ERR_PTR(-EEXIST);
+ if (ovsl_dereference(ovs_net->vport_net.gre_vport)) {
+ vport = ERR_PTR(-EEXIST);
+ goto error;
+ }
vport = ovs_vport_alloc(IFNAMSIZ, &ovs_gre_vport_ops, parms);
if (IS_ERR(vport))
- return vport;
+ goto error;
strncpy(vport_priv(vport), parms->name, IFNAMSIZ);
rcu_assign_pointer(ovs_net->vport_net.gre_vport, vport);
return vport;
+
+error:
+ gre_exit();
+ return vport;
}
static void gre_tnl_destroy(struct vport *vport)
rcu_assign_pointer(ovs_net->vport_net.gre_vport, NULL);
ovs_vport_deferred_free(vport);
+ gre_exit();
}
static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
const struct vport_ops ovs_gre_vport_ops = {
.type = OVS_VPORT_TYPE_GRE,
.flags = VPORT_F_TUN_ID,
- .init = gre_init,
- .exit = gre_exit,
.create = gre_create,
.destroy = gre_tnl_destroy,
.get_name = gre_get_name,
struct net *net = ovs_dp_get_net(parms->dp);
struct ovs_net *ovs_net;
struct vport *vport;
+ int err;
+
+ err = gre_init();
+ if (err)
+ return ERR_PTR(err);
ovs_net = net_generic(net, ovs_net_id);
- if (ovsl_dereference(ovs_net->vport_net.gre64_vport))
- return ERR_PTR(-EEXIST);
+ if (ovsl_dereference(ovs_net->vport_net.gre64_vport)) {
+ vport = ERR_PTR(-EEXIST);
+ goto error;
+ }
vport = ovs_vport_alloc(IFNAMSIZ, &ovs_gre64_vport_ops, parms);
if (IS_ERR(vport))
- return vport;
+ goto error;
strncpy(vport_priv(vport), parms->name, IFNAMSIZ);
rcu_assign_pointer(ovs_net->vport_net.gre64_vport, vport);
return vport;
+error:
+ gre_exit();
+ return vport;
}
static void gre64_tnl_destroy(struct vport *vport)
rcu_assign_pointer(ovs_net->vport_net.gre64_vport, NULL);
ovs_vport_deferred_free(vport);
+ gre_exit();
}
static int gre64_tnl_send(struct vport *vport, struct sk_buff *skb)
const struct vport_ops ovs_gre64_vport_ops = {
.type = OVS_VPORT_TYPE_GRE64,
.flags = VPORT_F_TUN_ID,
- .init = gre_init,
- .exit = gre_exit,
.create = gre64_create,
.destroy = gre64_tnl_destroy,
.get_name = gre_get_name,
const struct vport_ops ovs_internal_vport_ops = {
.type = OVS_VPORT_TYPE_INTERNAL,
- .flags = VPORT_F_REQUIRED,
.create = internal_dev_create,
.destroy = internal_dev_destroy,
.get_name = ovs_netdev_get_name,
static int netdev_init(void) { return 0; }
static void netdev_exit(void) { }
#else
-static int netdev_init(void)
+static int port_count;
+
+static void netdev_init(void)
{
+ port_count++;
+ if (port_count > 1)
+ return;
+
/* Hook into callback used by the bridge to intercept packets.
* Parasites we are. */
br_handle_frame_hook = netdev_frame_hook;
- return 0;
+ return;
}
static void netdev_exit(void)
{
+ port_count--;
+ if (port_count > 0)
+ return;
+
br_handle_frame_hook = NULL;
}
#endif
netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH;
rtnl_unlock();
+ netdev_init();
return vport;
#ifndef HAVE_RHEL_OVS_HOOK
{
struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
+ netdev_exit();
rtnl_lock();
netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH;
netdev_rx_handler_unregister(netdev_vport->dev);
const struct vport_ops ovs_netdev_vport_ops = {
.type = OVS_VPORT_TYPE_NETDEV,
- .flags = VPORT_F_REQUIRED,
- .init = netdev_init,
- .exit = netdev_exit,
.create = netdev_create,
.destroy = netdev_destroy,
.get_name = ovs_netdev_get_name,
/* List of statically compiled vport implementations. Don't forget to also
* add yours to the list at the bottom of vport.h. */
-static const struct vport_ops *base_vport_ops_list[] = {
+static const struct vport_ops *vport_ops_list[] = {
&ovs_netdev_vport_ops,
&ovs_internal_vport_ops,
&ovs_gre_vport_ops,
#endif
};
-static const struct vport_ops **vport_ops_list;
-static int n_vport_types;
-
/* Protected by RCU read lock for reading, ovs_mutex for writing. */
static struct hlist_head *dev_table;
#define VPORT_HASH_BUCKETS 1024
/**
* ovs_vport_init - initialize vport subsystem
*
- * Called at module load time to initialize the vport subsystem and any
- * compiled in vport types.
+ * Called at module load time to initialize the vport subsystem.
*/
int ovs_vport_init(void)
{
- int err;
- int i;
-
dev_table = kzalloc(VPORT_HASH_BUCKETS * sizeof(struct hlist_head),
GFP_KERNEL);
- if (!dev_table) {
- err = -ENOMEM;
- goto error;
- }
-
- vport_ops_list = kmalloc(ARRAY_SIZE(base_vport_ops_list) *
- sizeof(struct vport_ops *), GFP_KERNEL);
- if (!vport_ops_list) {
- err = -ENOMEM;
- goto error_dev_table;
- }
-
- for (i = 0; i < ARRAY_SIZE(base_vport_ops_list); i++) {
- const struct vport_ops *new_ops = base_vport_ops_list[i];
-
- if (new_ops->init)
- err = new_ops->init();
- else
- err = 0;
-
- if (!err)
- vport_ops_list[n_vport_types++] = new_ops;
- else if (new_ops->flags & VPORT_F_REQUIRED) {
- ovs_vport_exit();
- goto error;
- }
- }
+ if (!dev_table)
+ return -ENOMEM;
return 0;
-
-error_dev_table:
- kfree(dev_table);
-error:
- return err;
}
/**
* ovs_vport_exit - shutdown vport subsystem
*
- * Called at module exit time to shutdown the vport subsystem and any
- * initialized vport types.
+ * Called at module exit time to shutdown the vport subsystem.
*/
void ovs_vport_exit(void)
{
- int i;
-
- for (i = 0; i < n_vport_types; i++) {
- if (vport_ops_list[i]->exit)
- vport_ops_list[i]->exit();
- }
-
- kfree(vport_ops_list);
kfree(dev_table);
}
int err = 0;
int i;
- for (i = 0; i < n_vport_types; i++) {
+ for (i = 0; i < ARRAY_SIZE(vport_ops_list); i++) {
if (vport_ops_list[i]->type == parms->type) {
struct hlist_head *bucket;
struct ovs_vport_stats offset_stats;
};
-#define VPORT_F_REQUIRED (1 << 0) /* If init fails, module loading fails. */
-#define VPORT_F_TUN_ID (1 << 1) /* Sets OVS_CB(skb)->tun_id. */
+#define VPORT_F_TUN_ID (1 << 0) /* Sets OVS_CB(skb)->tun_id. */
/**
* struct vport_parms - parameters for creating a new vport
* @type: %OVS_VPORT_TYPE_* value for this type of virtual port.
* @flags: Flags of type VPORT_F_* that influence how the generic vport layer
* handles this vport.
- * @init: Called at module initialization. If VPORT_F_REQUIRED is set then the
- * failure of this function will cause the module to not load. If the flag is
- * not set and initialzation fails then no vports of this type can be created.
- * @exit: Called at module unload.
* @create: Create a new vport configured as specified. On success returns
* a new vport allocated with ovs_vport_alloc(), otherwise an ERR_PTR() value.
* @destroy: Destroys a vport. Must call vport_free() on the vport but not
enum ovs_vport_type type;
u32 flags;
- /* Called at module init and exit respectively. */
- int (*init)(void);
- void (*exit)(void);
-
/* Called with ovs_mutex. */
struct vport *(*create)(const struct vport_parms *);
void (*destroy)(struct vport *);