[ovs-dev] [PATCH v2 2/2] datapath lisp: Use ovs offload compat functionality.

Pravin B Shelar pshelar at nicira.com
Fri Sep 6 18:16:23 UTC 2013


OVS already has compat functions to handle GSO packets.
Following patch get rid of GSO packet handling in lisp
and use ovs iptunnel_xmit() function for same.

CC: Lori Jakab <lojakab at cisco.com>
Signed-off-by: Pravin B Shelar <pshelar at nicira.com>
---
 datapath/vport-lisp.c |  221 +++++++++++--------------------------------------
 1 files changed, 48 insertions(+), 173 deletions(-)

diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
index 2cec115..b1581ef 100644
--- a/datapath/vport-lisp.c
+++ b/datapath/vport-lisp.c
@@ -34,6 +34,7 @@
 #include <net/xfrm.h>
 
 #include "datapath.h"
+#include "gso.h"
 #include "vport.h"
 
 /*
@@ -162,7 +163,7 @@ static __be64 instance_id_to_tunnel_id(__u8 *iid)
 /* Compute source UDP port for outgoing packet.
  * Currently we use the flow hash.
  */
-static u16 ovs_tnl_get_src_port(struct sk_buff *skb)
+static u16 get_src_port(struct sk_buff *skb)
 {
 	int low;
 	int high;
@@ -177,8 +178,7 @@ static u16 ovs_tnl_get_src_port(struct sk_buff *skb)
 }
 
 static void lisp_build_header(const struct vport *vport,
-			      struct sk_buff *skb,
-			      int tunnel_hlen)
+			      struct sk_buff *skb)
 {
 	struct lisp_port *lisp_port = lisp_vport(vport);
 	struct udphdr *udph = udp_hdr(skb);
@@ -186,7 +186,7 @@ static void lisp_build_header(const struct vport *vport,
 	const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
 
 	udph->dest = lisp_port->dst_port;
-	udph->source = htons(ovs_tnl_get_src_port(skb));
+	udph->source = htons(get_src_port(skb));
 	udph->check = 0;
 	udph->len = htons(skb->len - skb_transport_offset(skb));
 
@@ -376,90 +376,47 @@ error:
 	return ERR_PTR(err);
 }
 
-static bool need_linearize(const struct sk_buff *skb)
+static void lisp_fix_segment(struct sk_buff *skb)
 {
-	int i;
-
-	if (unlikely(skb_shinfo(skb)->frag_list))
-		return true;
-
-	/*
-	 * Generally speaking we should linearize if there are paged frags.
-	 * However, if all of the refcounts are 1 we know nobody else can
-	 * change them from underneath us and we can skip the linearization.
-	 */
-	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-		if (unlikely(page_count(skb_frag_page(&skb_shinfo(skb)->frags[i])) > 1))
-			return true;
+	struct udphdr *udph = udp_hdr(skb);
 
-	return false;
+	udph->len = htons(skb->len - skb_transport_offset(skb));
 }
 
-static struct sk_buff *handle_offloads(struct sk_buff *skb)
+static void handle_offloads(struct sk_buff *skb)
 {
-	int err;
-
-	if (skb_is_gso(skb)) {
-		struct sk_buff *nskb;
-		char cb[sizeof(skb->cb)];
-
-		memcpy(cb, skb->cb, sizeof(cb));
-
-		nskb = __skb_gso_segment(skb, 0, false);
-		if (IS_ERR(nskb)) {
-			err = PTR_ERR(nskb);
-			goto error;
-		}
-
-		consume_skb(skb);
-		skb = nskb;
-		while (nskb) {
-			memcpy(nskb->cb, cb, sizeof(cb));
-			nskb = nskb->next;
-		}
-	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		/* Pages aren't locked and could change at any time.
-		 * If this happens after we compute the checksum, the
-		 * checksum will be wrong.  We linearize now to avoid
-		 * this problem.
-		 */
-		if (unlikely(need_linearize(skb))) {
-			err = __skb_linearize(skb);
-			if (unlikely(err))
-				goto error;
-		}
-
-		err = skb_checksum_help(skb);
-		if (unlikely(err))
-			goto error;
-	}
-
-	skb->ip_summed = CHECKSUM_NONE;
-	return skb;
-
-error:
-	return ERR_PTR(err);
+	if (skb_is_gso(skb))
+		OVS_GSO_CB(skb)->fix_segment = lisp_fix_segment;
+	else if (skb->ip_summed != CHECKSUM_PARTIAL)
+		skb->ip_summed = CHECKSUM_NONE;
 }
 
-static 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))
+static int lisp_send(struct vport *vport, struct sk_buff *skb)
 {
-	int min_headroom;
+	struct net *net = ovs_dp_get_net(vport->dp);
+	int network_offset = skb_network_offset(skb);
 	struct rtable *rt;
+	int min_headroom;
 	__be32 saddr;
-	int sent_len = 0;
+	__be16 df;
+	int sent_len;
 	int err;
-	struct sk_buff *nskb;
+
+	if (unlikely(!OVS_CB(skb)->tun_key))
+		return -EINVAL;
+
+	if (skb->protocol != htons(ETH_P_IP) &&
+	    skb->protocol != htons(ETH_P_IPV6)) {
+		kfree_skb(skb);
+		return 0;
+	}
 
 	/* 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,
-			ipproto,
+			IPPROTO_UDP,
 			OVS_CB(skb)->tun_key->ipv4_tos,
 			skb->mark);
 	if (IS_ERR(rt)) {
@@ -467,11 +424,8 @@ static int ovs_tnl_send(struct vport *vport, struct sk_buff *skb,
 		goto error;
 	}
 
-	tunnel_hlen += sizeof(struct iphdr);
-
 	min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
-			+ tunnel_hlen
-			+ (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
+			+ sizeof(struct iphdr) + LISP_HLEN;
 
 	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
 		int head_delta = SKB_DATA_ALIGN(min_headroom -
@@ -484,83 +438,27 @@ static int ovs_tnl_send(struct vport *vport, struct sk_buff *skb,
 			goto err_free_rt;
 	}
 
+	skb_pull(skb, network_offset);
+	skb_reset_mac_header(skb);
+	skb_reset_inner_headers(skb);
+
+	__skb_push(skb, LISP_HLEN);
+	skb_reset_transport_header(skb);
+
+	lisp_build_header(vport, skb);
+
 	/* Offloading */
-	nskb = handle_offloads(skb);
-	if (IS_ERR(nskb)) {
-		err = PTR_ERR(nskb);
-		goto err_free_rt;
-	}
-	skb = nskb;
-
-	/* Reset SKB */
-	nf_reset(skb);
-	secpath_reset(skb);
-	skb_dst_drop(skb);
-	skb_clear_rxhash(skb);
-
-	while (skb) {
-		struct sk_buff *next_skb = skb->next;
-		struct iphdr *iph;
-		int frag_len;
-
-		skb->next = NULL;
-
-		if (vlan_tx_tag_present(skb)) {
-			if (unlikely(!__vlan_put_tag(skb,
-							skb->vlan_proto,
-							vlan_tx_tag_get(skb))))
-				goto next;
-
-			vlan_set_tci(skb, 0);
-		}
-
-		frag_len = skb->len;
-		skb_push(skb, tunnel_hlen);
-		skb_reset_network_header(skb);
-		skb_set_transport_header(skb, sizeof(struct iphdr));
-
-		if (next_skb)
-			skb_dst_set(skb, dst_clone(&rt_dst(rt)));
-		else
-			skb_dst_set(skb, &rt_dst(rt));
-
-		/* Push Tunnel header. */
-		build_header(vport, skb, tunnel_hlen);
-
-		/* Push IP header. */
-		iph = ip_hdr(skb);
-		iph->version	= 4;
-		iph->ihl	= sizeof(struct iphdr) >> 2;
-		iph->protocol	= ipproto;
-		iph->daddr	= OVS_CB(skb)->tun_key->ipv4_dst;
-		iph->saddr	= saddr;
-		iph->tos	= OVS_CB(skb)->tun_key->ipv4_tos;
-		iph->ttl	= OVS_CB(skb)->tun_key->ipv4_ttl;
-		iph->frag_off	= OVS_CB(skb)->tun_key->tun_flags &
+	handle_offloads(skb);
+	skb->local_df = 1;
+
+	df = OVS_CB(skb)->tun_key->tun_flags &
 				  TUNNEL_DONT_FRAGMENT ?  htons(IP_DF) : 0;
-		/*
-		 * Allow our local IP stack to fragment the outer packet even
-		 * if the DF bit is set as a last resort.  We also need to
-		 * force selection of an IP ID here with __ip_select_ident(),
-		 * as ip_select_ident() assumes a proper ID is not needed when
-		 * when the DF bit is set.
-		 */
-		skb->local_df = 1;
-		__ip_select_ident(iph, skb_dst(skb), 0);
-
-		memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-
-		err = ip_local_out(skb);
-		if (unlikely(net_xmit_eval(err)))
-			goto next;
-
-		sent_len += frag_len;
-
-next:
-		skb = next_skb;
-	}
+	sent_len = iptunnel_xmit(net, rt, skb,
+			     saddr, OVS_CB(skb)->tun_key->ipv4_dst,
+			     IPPROTO_UDP, OVS_CB(skb)->tun_key->ipv4_tos,
+			     OVS_CB(skb)->tun_key->ipv4_ttl, df);
 
-	return sent_len;
+	return sent_len > 0 ? sent_len + network_offset : sent_len;
 
 err_free_rt:
 	ip_rt_put(rt);
@@ -568,29 +466,6 @@ error:
 	return err;
 }
 
-static int lisp_tnl_send(struct vport *vport, struct sk_buff *skb)
-{
-	int tnl_len;
-	int network_offset = skb_network_offset(skb);
-
-	if (unlikely(!OVS_CB(skb)->tun_key))
-		return -EINVAL;
-
-	/* 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:
-		kfree_skb(skb);
-		return 0;
-	}
-}
-
 static const char *lisp_get_name(const struct vport *vport)
 {
 	struct lisp_port *lisp_port = lisp_vport(vport);
@@ -603,5 +478,5 @@ const struct vport_ops ovs_lisp_vport_ops = {
 	.destroy	= lisp_tnl_destroy,
 	.get_name	= lisp_get_name,
 	.get_options	= lisp_get_options,
-	.send		= lisp_tnl_send,
+	.send		= lisp_send,
 };
-- 
1.7.1




More information about the dev mailing list