datapath: Move vport init to first port create.
[sliver-openvswitch.git] / datapath / vport-gre.c
index 0c7ae57..1f046ae 100644 (file)
@@ -290,16 +290,15 @@ static const struct net_protocol gre_protocol_handlers = {
 #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");
@@ -309,11 +308,10 @@ static int gre_init(void)
 
 static void gre_exit(void)
 {
-       if (!inited)
+       gre_ports--;
+       if (gre_ports > 0)
                return;
 
-       inited = false;
-
        inet_del_protocol(&gre_protocol_handlers, IPPROTO_GRE);
 }
 
@@ -327,18 +325,29 @@ static struct vport *gre_create(const struct vport_parms *parms)
        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)
@@ -350,17 +359,15 @@ 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)
 {
        int hlen;
 
-       if (unlikely(!OVS_CB(skb)->tun_key)) {
-               kfree_skb(skb);
-               ovs_vport_record_error(vport, VPORT_E_TX_ERROR);
-               return 0;
-       }
+       if (unlikely(!OVS_CB(skb)->tun_key))
+               return -EINVAL;
 
        hlen = gre_hdr_len(OVS_CB(skb)->tun_key);
        return ovs_tnl_send(vport, skb, IPPROTO_GRE, hlen, gre_build_header);
@@ -369,8 +376,6 @@ 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,
@@ -383,18 +388,28 @@ static struct vport *gre64_create(const struct vport_parms *parms)
        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)
@@ -406,17 +421,15 @@ 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)
 {
        int hlen;
 
-       if (unlikely(!OVS_CB(skb)->tun_key)) {
-               ovs_vport_record_error(vport, VPORT_E_TX_ERROR);
-               kfree_skb(skb);
-               return 0;
-       }
+       if (unlikely(!OVS_CB(skb)->tun_key))
+               return -EINVAL;
 
        hlen = gre64_hdr_len(OVS_CB(skb)->tun_key);
        return ovs_tnl_send(vport, skb, IPPROTO_GRE, hlen, gre64_build_header);
@@ -425,8 +438,6 @@ 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,