[ovs-dev] [PATCH] stt: linearize for CONFIG_SLUB case

Pravin B Shelar pshelar at ovn.org
Thu Mar 31 21:30:08 UTC 2016


STT implementation we saw performance improvements with linearizing
skb for SLUB case.  So following patch skips zero copy operation
for such a case.

Tested-By: Vasmi Abidi <vabidi at vmware.com>
Signed-off-by: Pravin B Shelar <pshelar at ovn.org>
---
 datapath/linux/compat/stt.c | 77 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 71 insertions(+), 6 deletions(-)

diff --git a/datapath/linux/compat/stt.c b/datapath/linux/compat/stt.c
index eb397e8..ae33d5e 100644
--- a/datapath/linux/compat/stt.c
+++ b/datapath/linux/compat/stt.c
@@ -49,6 +49,15 @@
 #define STT_DST_PORT 7471
 
 #ifdef OVS_STT
+#ifdef CONFIG_SLUB
+/*
+ * We saw better performance with skipping zero copy in case of SLUB.
+ * So skip zero copy for SLUB case.
+ */
+#define SKIP_ZERO_COPY
+#endif
+
+
 #define STT_VER 0
 
 /* @list: Per-net list of STT ports.
@@ -286,6 +295,7 @@ static int straighten_frag_list(struct sk_buff **skbp)
 	return 0;
 }
 
+#ifndef SKIP_ZERO_COPY
 static void copy_skb_metadata(struct sk_buff *to, struct sk_buff *from)
 {
 	to->protocol = from->protocol;
@@ -464,10 +474,14 @@ static int skb_list_segment(struct sk_buff *head, bool ipv4, int l4_offset)
 	update_headers(head, true, l4_offset, hdr_len, ipv4, 0);
 	return 0;
 }
+#endif
 
 static int coalesce_skb(struct sk_buff **headp)
 {
-	struct sk_buff *frag, *head, *prev;
+	struct sk_buff *frag, *head;
+#ifndef SKIP_ZERO_COPY
+	struct sk_buff *prev;
+#endif
 	int err;
 
 	err = straighten_frag_list(headp);
@@ -475,6 +489,7 @@ static int coalesce_skb(struct sk_buff **headp)
 		return err;
 	head = *headp;
 
+#ifndef SKIP_ZERO_COPY
 	/* Coalesce frag list. */
 	prev = head;
 	for (frag = head->next; frag; frag = frag->next) {
@@ -500,6 +515,7 @@ static int coalesce_skb(struct sk_buff **headp)
 	if (!head->next)
 		return 0;
 
+#endif
 	for (frag = head->next; frag; frag = frag->next) {
 		head->len += frag->len;
 		head->data_len += frag->len;
@@ -508,9 +524,16 @@ static int coalesce_skb(struct sk_buff **headp)
 
 	skb_shinfo(head)->frag_list = head->next;
 	head->next = NULL;
+#ifdef SKIP_ZERO_COPY
+	if (skb_shinfo(head)->frag_list) {
+		err = __skb_linearize(head);
+		return err;
+	}
+#endif
 	return 0;
 }
 
+#ifndef SKIP_ZERO_COPY
 static int __try_to_segment(struct sk_buff *skb, bool csum_partial,
 			    bool ipv4, bool tcp, int l4_offset)
 {
@@ -519,9 +542,16 @@ static int __try_to_segment(struct sk_buff *skb, bool csum_partial,
 	else
 		return skb_linearize(skb);
 }
+#endif
 
 static int try_to_segment(struct sk_buff *skb)
 {
+#ifdef SKIP_ZERO_COPY
+	/* coalesce_skb() since does not generate frag-list no need to
+	 * linearize it here.
+	 */
+	return 0;
+#else
 	struct stthdr *stth = stt_hdr(skb);
 	bool csum_partial = !!(stth->flags & STT_CSUM_PARTIAL);
 	bool ipv4 = !!(stth->flags & STT_PROTO_IPV4);
@@ -529,11 +559,13 @@ static int try_to_segment(struct sk_buff *skb)
 	int l4_offset = stth->l4_offset;
 
 	return __try_to_segment(skb, csum_partial, ipv4, tcp, l4_offset);
+#endif
 }
 
 static int segment_skb(struct sk_buff **headp, bool csum_partial,
 		       bool ipv4, bool tcp, int l4_offset)
 {
+#ifndef SKIP_ZERO_COPY
 	int err;
 
 	err = coalesce_skb(headp);
@@ -543,6 +575,7 @@ static int segment_skb(struct sk_buff **headp, bool csum_partial,
 	if (skb_shinfo(*headp)->frag_list)
 		return __try_to_segment(*headp, csum_partial,
 					ipv4, tcp, l4_offset);
+#endif
 	return 0;
 }
 
@@ -1054,13 +1087,28 @@ static struct pkt_frag *lookup_frag(struct net *net,
 	return victim_frag;
 }
 
+#ifdef SKIP_ZERO_COPY
+static int __copy_skb(struct sk_buff *to, struct sk_buff *from)
+{
+	if (to->next)
+		return -EINVAL;
+
+	if (unlikely(to->data_len || (from->len > skb_tailroom(to))))
+		return -EINVAL;
+	skb_copy_bits(from, 0, skb_put(to, from->len), from->len);
+	return 0;
+}
+#else
+#define __copy_skb(a, b)	-EINVAL;
+#endif
+
 static struct sk_buff *reassemble(struct sk_buff *skb)
 {
 	struct iphdr *iph = ip_hdr(skb);
 	struct tcphdr *tcph = tcp_hdr(skb);
 	u32 seq = ntohl(tcph->seq);
 	struct stt_percpu *stt_percpu;
-	struct sk_buff *last_skb;
+	struct sk_buff *last_skb, *copied_skb = NULL;
 	struct pkt_frag *frag;
 	struct pkt_key key;
 	int tot_len;
@@ -1093,6 +1141,15 @@ static struct sk_buff *reassemble(struct sk_buff *skb)
 
 	frag = lookup_frag(dev_net(skb->dev), stt_percpu, &key, hash);
 	if (!frag->skbs) {
+		int err;
+
+		err = pskb_expand_head(skb, skb_headroom(skb),
+				       skb->data_len + tot_len, GFP_ATOMIC);
+		if (likely(!err)) {
+			if (unlikely(!__pskb_pull_tail(skb, skb->data_len)))
+				BUG();
+		}
+
 		frag->skbs = skb;
 		frag->key = key;
 		frag->timestamp = jiffies;
@@ -1114,8 +1171,13 @@ static struct sk_buff *reassemble(struct sk_buff *skb)
 	last_skb = FRAG_CB(frag->skbs)->first.last_skb;
 	if (likely(FRAG_CB(last_skb)->offset + last_skb->len ==
 		   FRAG_CB(skb)->offset)) {
-		last_skb->next = skb;
-		FRAG_CB(frag->skbs)->first.last_skb = skb;
+
+		if (!__copy_skb(frag->skbs, skb)) {
+			copied_skb = skb;
+		} else {
+			last_skb->next = skb;
+			FRAG_CB(frag->skbs)->first.last_skb = skb;
+		}
 	} else {
 		struct sk_buff *prev = NULL, *next;
 
@@ -1154,8 +1216,10 @@ static struct sk_buff *reassemble(struct sk_buff *skb)
 
 	FRAG_CB(frag->skbs)->first.set_ecn_ce |= INET_ECN_is_ce(iph->tos);
 	FRAG_CB(frag->skbs)->first.rcvd_len += skb->len;
-	FRAG_CB(frag->skbs)->first.mem_used += skb->truesize;
-	stt_percpu->frag_mem_used += skb->truesize;
+	if (!copied_skb) {
+		FRAG_CB(frag->skbs)->first.mem_used += skb->truesize;
+		stt_percpu->frag_mem_used += skb->truesize;
+	}
 
 	if (FRAG_CB(frag->skbs)->first.tot_len ==
 	    FRAG_CB(frag->skbs)->first.rcvd_len) {
@@ -1174,6 +1238,7 @@ static struct sk_buff *reassemble(struct sk_buff *skb)
 		skb = NULL;
 	}
 
+	kfree_skb(copied_skb);
 	goto unlock;
 
 unlock_free:
-- 
1.8.3.1




More information about the dev mailing list