iph = ip_hdr(skb);
tnl_flags = gre_flags_to_tunnel_flags(gre_flags, is_gre64);
tnl_tun_key_init(&tun_key, iph, key, tnl_flags);
- OVS_CB(skb)->tun_key = &tun_key;
__skb_pull(skb, hdr_len);
skb_postpull_rcsum(skb, skb_transport_header(skb), hdr_len + ETH_HLEN);
- ovs_tnl_rcv(vport, skb);
+ ovs_tnl_rcv(vport, skb, &tun_key);
return 0;
error:
#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)
{
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);
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)
{
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);
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,