[ovs-dev] [PATCH v3 1/4] tunneling: Remove struct tnl_vport and tnl_ops.

Pravin B Shelar pshelar at nicira.com
Wed May 1 23:02:24 UTC 2013


After flow based tunneling, kernel tunneling is greatly simplified.
There is no need to have extra tunning layer between vport and
perticular protocol.
Following patch removes tunneling struct which make code easy to read.

Signed-off-by: Pravin B Shelar <pshelar at nicira.com>
---
v2-v3:
 - Fixed error handling in ovs_tnl_send.
v1-v2:
 - Updated comments for vxlan-port.
 - merge together vxlan_tnl_create() and vxlan_tunnel_setup().
---
 datapath/tunnel.c      |  104 +++++++--------------------
 datapath/tunnel.h      |   39 ++---------
 datapath/vport-gre.c   |   67 ++++++++++++------
 datapath/vport-lisp.c  |  183 ++++++++++++++++++++----------------------------
 datapath/vport-vxlan.c |  151 ++++++++++++++++------------------------
 datapath/vport.c       |   15 ++++
 datapath/vport.h       |    1 +
 7 files changed, 230 insertions(+), 330 deletions(-)

diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 057aaed..0cc0607 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -141,27 +141,10 @@ static bool need_linearize(const struct sk_buff *skb)
 	return false;
 }
 
-static struct sk_buff *handle_offloads(struct sk_buff *skb,
-				       const struct rtable *rt,
-				       int tunnel_hlen)
+static struct sk_buff *handle_offloads(struct sk_buff *skb)
 {
-	int min_headroom;
 	int err;
 
-	min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
-			+ tunnel_hlen
-			+ (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
-
-	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
-		int head_delta = SKB_DATA_ALIGN(min_headroom -
-						skb_headroom(skb) +
-						16);
-		err = pskb_expand_head(skb, max_t(int, head_delta, 0),
-					0, GFP_ATOMIC);
-		if (unlikely(err))
-			goto error_free;
-	}
-
 	forward_ip_summed(skb, true);
 
 	if (skb_is_gso(skb)) {
@@ -218,33 +201,48 @@ u16 ovs_tnl_get_src_port(struct sk_buff *skb)
 	return (((u64) hash * range) >> 32) + low;
 }
 
-int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
+int ovs_tnl_send(struct vport *vport, struct sk_buff *skb,
+		 u8 ipproto, int tunnel_hlen,
+		 void (*build_header)(const struct vport *,
+				      struct sk_buff *,
+				      int tunnel_hlen))
 {
-	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+	int min_headroom;
 	struct rtable *rt;
 	__be32 saddr;
 	int sent_len = 0;
-	int tunnel_hlen;
-
-	if (unlikely(!OVS_CB(skb)->tun_key))
-		goto error_free;
 
 	/* Route lookup */
 	saddr = OVS_CB(skb)->tun_key->ipv4_src;
 	rt = find_route(ovs_dp_get_net(vport->dp),
 			&saddr,
 			OVS_CB(skb)->tun_key->ipv4_dst,
-			tnl_vport->tnl_ops->ipproto,
+			ipproto,
 			OVS_CB(skb)->tun_key->ipv4_tos,
 			skb_get_mark(skb));
 	if (IS_ERR(rt))
 		goto error_free;
 
-	/* Offloading */
-	tunnel_hlen = tnl_vport->tnl_ops->hdr_len(OVS_CB(skb)->tun_key);
 	tunnel_hlen += sizeof(struct iphdr);
 
-	skb = handle_offloads(skb, rt, tunnel_hlen);
+	min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
+			+ tunnel_hlen
+			+ (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
+
+	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
+		int err;
+		int head_delta = SKB_DATA_ALIGN(min_headroom -
+						skb_headroom(skb) +
+						16);
+
+		err = pskb_expand_head(skb, max_t(int, head_delta, 0),
+					0, GFP_ATOMIC);
+		if (unlikely(err))
+			goto err_free_rt;
+	}
+
+	/* Offloading */
+	skb = handle_offloads(skb);
 	if (IS_ERR(skb)) {
 		skb = NULL;
 		goto err_free_rt;
@@ -278,13 +276,13 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
 			skb_dst_set(skb, &rt_dst(rt));
 
 		/* Push Tunnel header. */
-		tnl_vport->tnl_ops->build_header(vport, skb, tunnel_hlen);
+		build_header(vport, skb, tunnel_hlen);
 
 		/* Push IP header. */
 		iph = ip_hdr(skb);
 		iph->version	= 4;
 		iph->ihl	= sizeof(struct iphdr) >> 2;
-		iph->protocol	= tnl_vport->tnl_ops->ipproto;
+		iph->protocol	= ipproto;
 		iph->daddr	= OVS_CB(skb)->tun_key->ipv4_dst;
 		iph->saddr	= saddr;
 		iph->tos	= OVS_CB(skb)->tun_key->ipv4_tos;
@@ -325,49 +323,3 @@ error_free:
 	ovs_vport_record_error(vport, VPORT_E_TX_ERROR);
 	return sent_len;
 }
-
-struct vport *ovs_tnl_create(const struct vport_parms *parms,
-			     const struct vport_ops *vport_ops,
-			     const struct tnl_ops *tnl_ops)
-{
-	struct vport *vport;
-	struct tnl_vport *tnl_vport;
-	int err;
-
-	vport = ovs_vport_alloc(sizeof(struct tnl_vport), vport_ops, parms);
-	if (IS_ERR(vport)) {
-		err = PTR_ERR(vport);
-		goto error;
-	}
-
-	tnl_vport = tnl_vport_priv(vport);
-
-	strcpy(tnl_vport->name, parms->name);
-	tnl_vport->tnl_ops = tnl_ops;
-
-	return vport;
-
-error:
-	return ERR_PTR(err);
-}
-
-static void free_port_rcu(struct rcu_head *rcu)
-{
-	struct tnl_vport *tnl_vport = container_of(rcu,
-						   struct tnl_vport, rcu);
-
-	ovs_vport_free(vport_from_priv(tnl_vport));
-}
-
-void ovs_tnl_destroy(struct vport *vport)
-{
-	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-
-	call_rcu(&tnl_vport->rcu, free_port_rcu);
-}
-
-const char *ovs_tnl_get_name(const struct vport *vport)
-{
-	const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-	return tnl_vport->name;
-}
diff --git a/datapath/tunnel.h b/datapath/tunnel.h
index e853146..75a84d1 100644
--- a/datapath/tunnel.h
+++ b/datapath/tunnel.h
@@ -26,45 +26,16 @@
 #include "flow.h"
 #include "vport.h"
 
-struct tnl_ops {
-	u8 ipproto;		/* The IP protocol for the tunnel. */
 
-	/*
-	 * Returns the length of the tunnel header that will be added in
-	 * build_header() (i.e. excludes the IP header).
-	 */
-	int (*hdr_len)(const struct ovs_key_ipv4_tunnel *);
-	/*
-	* Builds header for given SKB.  Space will have already been
-	* allocated at the start of the packet equal
-	* to sizeof(struct iphdr) + value returned by hdr_len().
-	*/
-	void (*build_header)(const struct vport *, struct sk_buff *,
-			     int tunnel_hlen);
-};
+int ovs_tnl_send(struct vport *vport, struct sk_buff *skb,
+		 u8 ipproto, int tunnel_hlen,
+		 void (*build_header)(const struct vport *,
+				      struct sk_buff *,
+				      int tunnel_hlen));
 
-struct tnl_vport {
-	struct rcu_head rcu;
-
-	__be16 dst_port;
-	char name[IFNAMSIZ];
-	const struct tnl_ops *tnl_ops;
-};
-
-struct vport *ovs_tnl_create(const struct vport_parms *, const struct vport_ops *,
-			     const struct tnl_ops *);
-void ovs_tnl_destroy(struct vport *);
-
-const char *ovs_tnl_get_name(const struct vport *vport);
-int ovs_tnl_send(struct vport *vport, struct sk_buff *skb);
 void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb);
 u16 ovs_tnl_get_src_port(struct sk_buff *skb);
 
-static inline struct tnl_vport *tnl_vport_priv(const struct vport *vport)
-{
-	return vport_priv(vport);
-}
-
 static inline void tnl_tun_key_init(struct ovs_key_ipv4_tunnel *tun_key,
 				    const struct iphdr *iph, __be64 tun_id, u32 tun_flags)
 {
diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c
index a29d2e8..0c7ae57 100644
--- a/datapath/vport-gre.c
+++ b/datapath/vport-gre.c
@@ -317,12 +317,10 @@ static void gre_exit(void)
 	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)
 {
@@ -334,8 +332,11 @@ static struct vport *gre_create(const struct vport_parms *parms)
 	if (ovsl_dereference(ovs_net->vport_net.gre_vport))
 		return ERR_PTR(-EEXIST);
 
-	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))
+		return vport;
 
+	strncpy(vport_priv(vport), parms->name, IFNAMSIZ);
 	rcu_assign_pointer(ovs_net->vport_net.gre_vport, vport);
 	return vport;
 }
@@ -348,7 +349,21 @@ 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);
+}
+
+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;
+	}
+
+	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 = {
@@ -358,17 +373,11 @@ const struct vport_ops ovs_gre_vport_ops = {
 	.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);
@@ -379,13 +388,15 @@ static struct vport *gre64_create(const struct vport_parms *parms)
 	if (ovsl_dereference(ovs_net->vport_net.gre64_vport))
 		return ERR_PTR(-EEXIST);
 
-	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))
+		return vport;
 
+	strncpy(vport_priv(vport), parms->name, IFNAMSIZ);
 	rcu_assign_pointer(ovs_net->vport_net.gre64_vport, vport);
 	return vport;
 }
 
-
 static void gre64_tnl_destroy(struct vport *vport)
 {
 	struct net *net = ovs_dp_get_net(vport->dp);
@@ -394,7 +405,21 @@ 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);
+}
+
+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;
+	}
+
+	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 = {
@@ -404,6 +429,6 @@ const struct vport_ops ovs_gre64_vport_ops = {
 	.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,
 };
diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
index 1fff5ae..d45a4cc 100644
--- a/datapath/vport-lisp.c
+++ b/datapath/vport-lisp.c
@@ -94,34 +94,33 @@ struct lisphdr {
 
 #define LISP_HLEN (sizeof(struct udphdr) + sizeof(struct lisphdr))
 
-static inline int lisp_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key)
-{
-	return LISP_HLEN;
-}
-
 /**
  * struct lisp_port - Keeps track of open UDP ports
- * @list: list element.
- * @vport: vport for the tunnel.
- * @socket: The socket created for this port number.
+ * @dst_port: lisp UDP port no.
+ * @list: list element in @lisp_ports.
+ * @lisp_rcv_socket: The socket created for this port number.
+ * @name: vport name.
  */
 struct lisp_port {
+	__be16 dst_port;
 	struct list_head list;
-	struct vport *vport;
 	struct socket *lisp_rcv_socket;
-	struct rcu_head rcu;
+	char name[IFNAMSIZ];
 };
 
 static LIST_HEAD(lisp_ports);
 
+static inline struct lisp_port *lisp_vport(const struct vport *vport)
+{
+	return vport_priv(vport);
+}
+
 static struct lisp_port *lisp_find_port(struct net *net, __be16 port)
 {
 	struct lisp_port *lisp_port;
 
 	list_for_each_entry_rcu(lisp_port, &lisp_ports, list) {
-		struct tnl_vport *tnl_vport = tnl_vport_priv(lisp_port->vport);
-
-		if (tnl_vport->dst_port == port &&
+		if (lisp_port->dst_port == port &&
 			net_eq(sock_net(lisp_port->lisp_rcv_socket->sk), net))
 			return lisp_port;
 	}
@@ -134,25 +133,6 @@ static inline struct lisphdr *lisp_hdr(const struct sk_buff *skb)
 	return (struct lisphdr *)(udp_hdr(skb) + 1);
 }
 
-static int lisp_tnl_send(struct vport *vport, struct sk_buff *skb)
-{
-	int tnl_len;
-	int network_offset = skb_network_offset(skb);
-
-	/* We only encapsulate IPv4 and IPv6 packets */
-	switch (skb->protocol) {
-	case htons(ETH_P_IP):
-	case htons(ETH_P_IPV6):
-		/* Pop off "inner" Ethernet header */
-		skb_pull(skb, network_offset);
-		tnl_len = ovs_tnl_send(vport, skb);
-		return tnl_len > 0 ? tnl_len + network_offset : tnl_len;
-	default:
-		kfree_skb(skb);
-		return 0;
-	}
-}
-
 /* Convert 64 bit tunnel ID to 24 bit Instance ID. */
 static void tunnel_id_to_instance_id(__be64 tun_id, __u8 *iid)
 {
@@ -184,12 +164,12 @@ static void lisp_build_header(const struct vport *vport,
 			      struct sk_buff *skb,
 			      int tunnel_hlen)
 {
-	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+	struct lisp_port *lisp_port = lisp_vport(vport);
 	struct udphdr *udph = udp_hdr(skb);
 	struct lisphdr *lisph = (struct lisphdr *)(udph + 1);
 	const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
 
-	udph->dest = tnl_vport->dst_port;
+	udph->dest = lisp_port->dst_port;
 	udph->source = htons(ovs_tnl_get_src_port(skb));
 	udph->check = 0;
 	udph->len = htons(skb->len - skb_transport_offset(skb));
@@ -261,7 +241,7 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
 	ethh->h_source[0] = 0x02;
 	ethh->h_proto = protocol;
 
-	ovs_tnl_rcv(lisp_port->vport, skb);
+	ovs_tnl_rcv(vport_from_priv(lisp_port), skb);
 	goto out;
 
 error:
@@ -274,9 +254,8 @@ out:
 #define UDP_ENCAP_LISP 1
 static int lisp_socket_init(struct lisp_port *lisp_port, struct net *net)
 {
-	int err;
 	struct sockaddr_in sin;
-	struct tnl_vport *tnl_vport = tnl_vport_priv(lisp_port->vport);
+	int err;
 
 	err = sock_create_kern(AF_INET, SOCK_DGRAM, 0,
 			       &lisp_port->lisp_rcv_socket);
@@ -288,7 +267,7 @@ static int lisp_socket_init(struct lisp_port *lisp_port, struct net *net)
 
 	sin.sin_family = AF_INET;
 	sin.sin_addr.s_addr = htonl(INADDR_ANY);
-	sin.sin_port = tnl_vport->dst_port;
+	sin.sin_port = lisp_port->dst_port;
 
 	err = kernel_bind(lisp_port->lisp_rcv_socket, (struct sockaddr *)&sin,
 			  sizeof(struct sockaddr_in));
@@ -309,37 +288,39 @@ error:
 	return err;
 }
 
-
-static void free_port_rcu(struct rcu_head *rcu)
+static int lisp_get_options(const struct vport *vport, struct sk_buff *skb)
 {
-	struct lisp_port *lisp_port = container_of(rcu,
-			struct lisp_port, rcu);
+	struct lisp_port *lisp_port = lisp_vport(vport);
 
-	kfree(lisp_port);
+	if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(lisp_port->dst_port)))
+		return -EMSGSIZE;
+	return 0;
 }
 
-static void lisp_tunnel_release(struct lisp_port *lisp_port)
+static void lisp_tnl_destroy(struct vport *vport)
 {
-	if (!lisp_port)
-		return;
+	struct lisp_port *lisp_port = lisp_vport(vport);
+
 	list_del_rcu(&lisp_port->list);
 	/* Release socket */
 	sk_release_kernel(lisp_port->lisp_rcv_socket->sk);
-	call_rcu(&lisp_port->rcu, free_port_rcu);
+
+	ovs_vport_deferred_free(vport);
 }
 
-static int lisp_tunnel_setup(struct net *net, struct vport *vport,
-			     struct nlattr *options)
+static struct vport *lisp_tnl_create(const struct vport_parms *parms)
 {
-	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+	struct net *net = ovs_dp_get_net(parms->dp);
+	struct nlattr *options = parms->options;
 	struct lisp_port *lisp_port;
+	struct vport *vport;
 	struct nlattr *a;
 	int err;
 	u16 dst_port;
 
 	if (!options) {
 		err = -EINVAL;
-		goto out;
+		goto error;
 	}
 
 	a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
@@ -348,84 +329,70 @@ static int lisp_tunnel_setup(struct net *net, struct vport *vport,
 	} else {
 		/* Require destination port from userspace. */
 		err = -EINVAL;
-		goto out;
+		goto error;
 	}
 
 	/* Verify if we already have a socket created for this port */
-	lisp_port = lisp_find_port(net, htons(dst_port));
-	if (lisp_port) {
+	if (lisp_find_port(net, htons(dst_port))) {
 		err = -EEXIST;
-		goto out;
+		goto error;
 	}
 
-	/* Add a new socket for this port */
-	lisp_port = kzalloc(sizeof(struct lisp_port), GFP_KERNEL);
-	if (!lisp_port) {
-		err = -ENOMEM;
-		goto out;
-	}
+	vport = ovs_vport_alloc(sizeof(struct lisp_port),
+				&ovs_lisp_vport_ops, parms);
+	if (IS_ERR(vport))
+		return vport;
 
-	tnl_vport->dst_port = htons(dst_port);
-	lisp_port->vport = vport;
-	list_add_tail_rcu(&lisp_port->list, &lisp_ports);
+	lisp_port = lisp_vport(vport);
+	lisp_port->dst_port = htons(dst_port);
+	strncpy(lisp_port->name, parms->name, IFNAMSIZ);
 
 	err = lisp_socket_init(lisp_port, net);
 	if (err)
-		goto error;
+		goto error_free;
 
-	return 0;
+	list_add_tail_rcu(&lisp_port->list, &lisp_ports);
+	return vport;
 
+error_free:
+	ovs_vport_free(vport);
 error:
-	list_del_rcu(&lisp_port->list);
-	kfree(lisp_port);
-out:
-	return err;
+	return ERR_PTR(err);
 }
 
-static int lisp_get_options(const struct vport *vport, struct sk_buff *skb)
+static int lisp_tnl_send(struct vport *vport, struct sk_buff *skb)
 {
-	const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-
-	if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(tnl_vport->dst_port)))
-		return -EMSGSIZE;
-	return 0;
-}
-
-static const struct tnl_ops ovs_lisp_tnl_ops = {
-	.ipproto	= IPPROTO_UDP,
-	.hdr_len	= lisp_hdr_len,
-	.build_header	= lisp_build_header,
-};
+	int tnl_len;
+	int network_offset = skb_network_offset(skb);
 
-static void lisp_tnl_destroy(struct vport *vport)
-{
-	struct lisp_port *lisp_port;
-	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+	if (unlikely(!OVS_CB(skb)->tun_key)) {
+		ovs_vport_record_error(vport, VPORT_E_TX_ERROR);
+		goto free;
+	}
 
-	lisp_port = lisp_find_port(ovs_dp_get_net(vport->dp),
-				   tnl_vport->dst_port);
+	/* We only encapsulate IPv4 and IPv6 packets */
+	switch (skb->protocol) {
+	case htons(ETH_P_IP):
+	case htons(ETH_P_IPV6):
+		/* Pop off "inner" Ethernet header */
+		skb_pull(skb, network_offset);
+		tnl_len = ovs_tnl_send(vport, skb, IPPROTO_UDP,
+				LISP_HLEN, lisp_build_header);
+		return tnl_len > 0 ? tnl_len + network_offset : tnl_len;
+	default:
+		ovs_vport_record_error(vport, VPORT_E_TX_DROPPED);
+		goto free;
+	}
 
-	lisp_tunnel_release(lisp_port);
-	ovs_tnl_destroy(vport);
+free:
+	kfree_skb(skb);
+	return 0;
 }
 
-static struct vport *lisp_tnl_create(const struct vport_parms *parms)
+static const char *lisp_get_name(const struct vport *vport)
 {
-	struct vport *vport;
-	int err;
-
-	vport = ovs_tnl_create(parms, &ovs_lisp_vport_ops, &ovs_lisp_tnl_ops);
-	if (IS_ERR(vport))
-		return vport;
-
-	err = lisp_tunnel_setup(ovs_dp_get_net(parms->dp), vport,
-				parms->options);
-	if (err) {
-		ovs_tnl_destroy(vport);
-		return ERR_PTR(err);
-	}
-
-	return vport;
+	struct lisp_port *lisp_port = lisp_vport(vport);
+	return lisp_port->name;
 }
 
 const struct vport_ops ovs_lisp_vport_ops = {
@@ -433,7 +400,7 @@ const struct vport_ops ovs_lisp_vport_ops = {
 	.flags		= VPORT_F_TUN_ID,
 	.create		= lisp_tnl_create,
 	.destroy	= lisp_tnl_destroy,
-	.get_name	= ovs_tnl_get_name,
+	.get_name	= lisp_get_name,
 	.get_options	= lisp_get_options,
 	.send		= lisp_tnl_send,
 };
diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
index 1850fc2..3558b0e 100644
--- a/datapath/vport-vxlan.c
+++ b/datapath/vport-vxlan.c
@@ -50,34 +50,34 @@ struct vxlanhdr {
 
 #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
 
-static inline int vxlan_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key)
-{
-	return VXLAN_HLEN;
-}
-
 /**
  * struct vxlan_port - Keeps track of open UDP ports
- * @list: list element.
- * @vport: vport for the tunnel.
- * @socket: The socket created for this port number.
+ * @dst_port: vxlan UDP port no.
+ * @list: list element in @vxlan_ports.
+ * @vxlan_rcv_socket: The socket created for this port number.
+ * @name: vport name.
  */
 struct vxlan_port {
+	__be16 dst_port;
 	struct list_head list;
-	struct vport *vport;
 	struct socket *vxlan_rcv_socket;
-	struct rcu_head rcu;
+	char name[IFNAMSIZ];
 };
 
 static LIST_HEAD(vxlan_ports);
 
+static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
+{
+	return vport_priv(vport);
+}
+
 static struct vxlan_port *vxlan_find_port(struct net *net, __be16 port)
 {
 	struct vxlan_port *vxlan_port;
 
 	list_for_each_entry_rcu(vxlan_port, &vxlan_ports, list) {
-		struct tnl_vport *tnl_vport = tnl_vport_priv(vxlan_port->vport);
 
-		if (tnl_vport->dst_port == port &&
+		if (vxlan_port->dst_port == port &&
 			net_eq(sock_net(vxlan_port->vxlan_rcv_socket->sk), net))
 			return vxlan_port;
 	}
@@ -94,12 +94,12 @@ static void vxlan_build_header(const struct vport *vport,
 			       struct sk_buff *skb,
 			       int tunnel_hlen)
 {
-	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+	struct vxlan_port *vxlan_port = vxlan_vport(vport);
 	struct udphdr *udph = udp_hdr(skb);
 	struct vxlanhdr *vxh = (struct vxlanhdr *)(udph + 1);
 	const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
 
-	udph->dest = tnl_vport->dst_port;
+	udph->dest = vxlan_port->dst_port;
 	udph->source = htons(ovs_tnl_get_src_port(skb));
 	udph->check = 0;
 	udph->len = htons(skb->len - skb_transport_offset(skb));
@@ -139,7 +139,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 	tnl_tun_key_init(&tun_key, iph, key, OVS_TNL_F_KEY);
 	OVS_CB(skb)->tun_key = &tun_key;
 
-	ovs_tnl_rcv(vxlan_vport->vport, skb);
+	ovs_tnl_rcv(vport_from_priv(vxlan_vport), skb);
 	goto out;
 
 error:
@@ -152,9 +152,8 @@ out:
 #define UDP_ENCAP_VXLAN 1
 static int vxlan_socket_init(struct vxlan_port *vxlan_port, struct net *net)
 {
-	int err;
 	struct sockaddr_in sin;
-	struct tnl_vport *tnl_vport = tnl_vport_priv(vxlan_port->vport);
+	int err;
 
 	err = sock_create_kern(AF_INET, SOCK_DGRAM, 0,
 			       &vxlan_port->vxlan_rcv_socket);
@@ -166,7 +165,7 @@ static int vxlan_socket_init(struct vxlan_port *vxlan_port, struct net *net)
 
 	sin.sin_family = AF_INET;
 	sin.sin_addr.s_addr = htonl(INADDR_ANY);
-	sin.sin_port = tnl_vport->dst_port;
+	sin.sin_port = vxlan_port->dst_port;
 
 	err = kernel_bind(vxlan_port->vxlan_rcv_socket, (struct sockaddr *)&sin,
 			  sizeof(struct sockaddr_in));
@@ -187,123 +186,93 @@ error:
 	return err;
 }
 
-static void free_port_rcu(struct rcu_head *rcu)
+static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
 {
-	struct vxlan_port *vxlan_port = container_of(rcu,
-			struct vxlan_port, rcu);
+	struct vxlan_port *vxlan_port = vxlan_vport(vport);
 
-	kfree(vxlan_port);
+	if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(vxlan_port->dst_port)))
+		return -EMSGSIZE;
+	return 0;
 }
 
-static void vxlan_tunnel_release(struct vxlan_port *vxlan_port)
+static void vxlan_tnl_destroy(struct vport *vport)
 {
-	if (!vxlan_port)
-		return;
+	struct vxlan_port *vxlan_port = vxlan_vport(vport);
 
 	list_del_rcu(&vxlan_port->list);
 	/* Release socket */
 	sk_release_kernel(vxlan_port->vxlan_rcv_socket->sk);
-	call_rcu(&vxlan_port->rcu, free_port_rcu);
+
+	ovs_vport_deferred_free(vport);
 }
 
-static int vxlan_tunnel_setup(struct net *net, struct vport *vport,
-			      struct nlattr *options)
+static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
 {
+	struct net *net = ovs_dp_get_net(parms->dp);
+	struct nlattr *options = parms->options;
 	struct vxlan_port *vxlan_port;
-	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+	struct vport *vport;
 	struct nlattr *a;
 	int err;
 	u16 dst_port;
 
 	if (!options) {
 		err = -EINVAL;
-		goto out;
+		goto error;
 	}
-
 	a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
 	if (a && nla_len(a) == sizeof(u16)) {
 		dst_port = nla_get_u16(a);
 	} else {
 		/* Require destination port from userspace. */
 		err = -EINVAL;
-		goto out;
+		goto error;
 	}
 
 	/* Verify if we already have a socket created for this port */
-	vxlan_port = vxlan_find_port(net, htons(dst_port));
-	if (vxlan_port) {
+	if (vxlan_find_port(net, htons(dst_port))) {
 		err = -EEXIST;
-		goto out;
+		goto error;
 	}
 
-	/* Add a new socket for this port */
-	vxlan_port = kzalloc(sizeof(struct vxlan_port), GFP_KERNEL);
-	if (!vxlan_port) {
-		err = -ENOMEM;
-		goto out;
-	}
+	vport = ovs_vport_alloc(sizeof(struct vxlan_port),
+				&ovs_vxlan_vport_ops, parms);
+	if (IS_ERR(vport))
+		return vport;
 
-	tnl_vport->dst_port = htons(dst_port);
-	vxlan_port->vport = vport;
-	list_add_tail_rcu(&vxlan_port->list, &vxlan_ports);
+	vxlan_port = vxlan_vport(vport);
+	vxlan_port->dst_port = htons(dst_port);
+	strncpy(vxlan_port->name, parms->name, IFNAMSIZ);
 
 	err = vxlan_socket_init(vxlan_port, net);
 	if (err)
-		goto error;
+		goto error_free;
 
-	return 0;
+	list_add_tail_rcu(&vxlan_port->list, &vxlan_ports);
+	return vport;
 
+error_free:
+	ovs_vport_free(vport);
 error:
-	list_del_rcu(&vxlan_port->list);
-	kfree(vxlan_port);
-out:
-	return err;
-}
-
-static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
-{
-	const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-
-	if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(tnl_vport->dst_port)))
-		return -EMSGSIZE;
-	return 0;
+	return ERR_PTR(err);
 }
 
-static const struct tnl_ops ovs_vxlan_tnl_ops = {
-	.ipproto	= IPPROTO_UDP,
-	.hdr_len	= vxlan_hdr_len,
-	.build_header	= vxlan_build_header,
-};
-
-static void vxlan_tnl_destroy(struct vport *vport)
+static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
 {
-	struct vxlan_port *vxlan_port;
-	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-
-	vxlan_port = vxlan_find_port(ovs_dp_get_net(vport->dp),
-					 tnl_vport->dst_port);
+	if (unlikely(!OVS_CB(skb)->tun_key)) {
+		ovs_vport_record_error(vport, VPORT_E_TX_ERROR);
+		kfree_skb(skb);
+		return 0;
+	}
 
-	vxlan_tunnel_release(vxlan_port);
-	ovs_tnl_destroy(vport);
+	return ovs_tnl_send(vport, skb, IPPROTO_UDP,
+			VXLAN_HLEN, vxlan_build_header);
 }
 
-static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
+static const char *vxlan_get_name(const struct vport *vport)
 {
-	int err;
-	struct vport *vport;
-
-	vport = ovs_tnl_create(parms, &ovs_vxlan_vport_ops, &ovs_vxlan_tnl_ops);
-	if (IS_ERR(vport))
-		return vport;
-
-	err = vxlan_tunnel_setup(ovs_dp_get_net(parms->dp), vport,
-				 parms->options);
-	if (err) {
-		ovs_tnl_destroy(vport);
-		return ERR_PTR(err);
-	}
-
-	return vport;
+	struct vxlan_port *vxlan_port = vxlan_vport(vport);
+	return vxlan_port->name;
 }
 
 const struct vport_ops ovs_vxlan_vport_ops = {
@@ -311,9 +280,9 @@ const struct vport_ops ovs_vxlan_vport_ops = {
 	.flags		= VPORT_F_TUN_ID,
 	.create		= vxlan_tnl_create,
 	.destroy	= vxlan_tnl_destroy,
-	.get_name	= ovs_tnl_get_name,
+	.get_name	= vxlan_get_name,
 	.get_options	= vxlan_get_options,
-	.send		= ovs_tnl_send,
+	.send		= vxlan_tnl_send,
 };
 #else
 #warning VXLAN tunneling will not be available on kernels before 2.6.26
diff --git a/datapath/vport.c b/datapath/vport.c
index 03446da..b63ed59 100644
--- a/datapath/vport.c
+++ b/datapath/vport.c
@@ -475,3 +475,18 @@ void ovs_vport_record_error(struct vport *vport, enum vport_err_type err_type)
 
 	spin_unlock(&vport->stats_lock);
 }
+
+static void free_vport_rcu(struct rcu_head *rcu)
+{
+	struct vport *vport = container_of(rcu, struct vport, rcu);
+
+	ovs_vport_free(vport);
+}
+
+void ovs_vport_deferred_free(struct vport *vport)
+{
+	if (!vport)
+		return;
+
+	call_rcu(&vport->rcu, free_vport_rcu);
+}
diff --git a/datapath/vport.h b/datapath/vport.h
index 7233e4f..cba578c 100644
--- a/datapath/vport.h
+++ b/datapath/vport.h
@@ -174,6 +174,7 @@ enum vport_err_type {
 struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *,
 			      const struct vport_parms *);
 void ovs_vport_free(struct vport *);
+void ovs_vport_deferred_free(struct vport *vport);
 
 #define VPORT_ALIGN 8
 
-- 
1.7.1




More information about the dev mailing list