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 <vab...@vmware.com> Signed-off-by: Pravin B Shelar <pshe...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev