datapath: Move vport init to first port create.
[sliver-openvswitch.git] / datapath / vport-gre.c
index 40b96cf..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,35 +308,46 @@ 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);
 }
 
-/* GRE vport. */
-static const struct tnl_ops gre_tnl_ops = {
-       .ipproto        = IPPROTO_GRE,
-       .hdr_len        = gre_hdr_len,
-       .build_header   = gre_build_header,
-};
+static const char *gre_get_name(const struct vport *vport)
+{
+       return vport_priv(vport);
+}
 
 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 (rtnl_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_tnl_create(parms, &ovs_gre_vport_ops, &gre_tnl_ops);
+       vport = ovs_vport_alloc(IFNAMSIZ, &ovs_gre_vport_ops, parms);
+       if (IS_ERR(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)
@@ -348,44 +358,60 @@ static void gre_tnl_destroy(struct vport *vport)
        ovs_net = net_generic(net, ovs_net_id);
 
        rcu_assign_pointer(ovs_net->vport_net.gre_vport, NULL);
-       ovs_tnl_destroy(vport);
+       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))
+               return -EINVAL;
+
+       hlen = gre_hdr_len(OVS_CB(skb)->tun_key);
+       return ovs_tnl_send(vport, skb, IPPROTO_GRE, hlen, gre_build_header);
 }
 
 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       = ovs_tnl_get_name,
-       .send           = ovs_tnl_send,
+       .get_name       = gre_get_name,
+       .send           = gre_tnl_send,
 };
 
 /* GRE64 vport. */
-static const struct tnl_ops gre64_tnl_ops = {
-       .ipproto        = IPPROTO_GRE,
-       .hdr_len        = gre64_hdr_len,
-       .build_header   = gre64_build_header,
-};
-
 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 (rtnl_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_tnl_create(parms, &ovs_gre64_vport_ops, &gre64_tnl_ops);
+       vport = ovs_vport_alloc(IFNAMSIZ, &ovs_gre64_vport_ops, parms);
+       if (IS_ERR(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)
 {
        struct net *net = ovs_dp_get_net(vport->dp);
@@ -394,16 +420,26 @@ static void gre64_tnl_destroy(struct vport *vport)
        ovs_net = net_generic(net, ovs_net_id);
 
        rcu_assign_pointer(ovs_net->vport_net.gre64_vport, NULL);
-       ovs_tnl_destroy(vport);
+       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))
+               return -EINVAL;
+
+       hlen = gre64_hdr_len(OVS_CB(skb)->tun_key);
+       return ovs_tnl_send(vport, skb, IPPROTO_GRE, hlen, gre64_build_header);
 }
 
 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       = ovs_tnl_get_name,
-       .send           = ovs_tnl_send,
+       .get_name       = gre_get_name,
+       .send           = gre64_tnl_send,
 };