From patchwork Fri Jun 25 02:54:32 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changli Gao X-Patchwork-Id: 56883 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 9F829B6F19 for ; Fri, 25 Jun 2010 12:55:58 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753896Ab0FYCzq (ORCPT ); Thu, 24 Jun 2010 22:55:46 -0400 Received: from mail-pw0-f46.google.com ([209.85.160.46]:50040 "EHLO mail-pw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751083Ab0FYCzp (ORCPT ); Thu, 24 Jun 2010 22:55:45 -0400 Received: by pwj8 with SMTP id 8so2137895pwj.19 for ; Thu, 24 Jun 2010 19:55:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer; bh=AmBb4LYIWokop1NegJ1bC2ZEuaPRdsepXNPknZOuXus=; b=lT9ezhsm1/vqC28WZp76c0LJv0OQiSQ2skDg8rShTOkuyDZMFEbso6PfvpwIw5fa27 fbgjr8aYaGHQXdwqR2ZvqTCJ4h6YHwA2RV8Ot/h/Z2GRexOpEdHICk9isTlrZqTS3NjA +q0RsFJiQNCgTy5S/HkmGLNe3RFMoi19ou4rY= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=azxI1ZPpdRg9FVXWIxrGYhMxrDbwIaTUqHwWd9GsYqqWQIewSuoTVPaBJ4xtXF3Q49 UQysMnnr3Wwlr5/N7WBQ6GMU1PJMEQpoZfj3oSmrdSAJhVBogZ4L59/Xp/gzvxJvQOEY FxrP4cqPRc70alo6pRGI3LRL0WbEEY1fx25p4= Received: by 10.114.10.14 with SMTP id 14mr4849waj.72.1277434545345; Thu, 24 Jun 2010 19:55:45 -0700 (PDT) Received: from localhost.localdomain ([221.238.105.180]) by mx.google.com with ESMTPS id h4sm793798wae.23.2010.06.24.19.55.36 (version=TLSv1/SSLv3 cipher=RC4-MD5); Thu, 24 Jun 2010 19:55:44 -0700 (PDT) From: Changli Gao To: David Miller Cc: Alexey Kuznetsov , "Pekka Savola (ipv6)" , James Morris , Hideaki YOSHIFUJI , Patrick McHardy , Eric Dumazet , netdev@vger.kernel.org, Mitchell Erblich , Changli Gao Subject: [PATCH v2] fragment: add fast path Date: Fri, 25 Jun 2010 10:54:32 +0800 Message-Id: <1277434472-2845-1-git-send-email-xiaosuo@gmail.com> X-Mailer: git-send-email 1.7.1 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org add fast path As the fragments are sent in order in most of OSes, such as Windows, Darwin and FreeBSD, it is likely the new fragments are at the end of the inet_frag_queue. In the fast path, we check if the skb at the end of the inet_frag_queue is the prev we expect. Signed-off-by: Changli Gao ---- include/net/inet_frag.h | 1 + net/ipv4/ip_fragment.c | 12 ++++++++++++ net/ipv6/reassembly.c | 11 +++++++++++ 3 files changed, 24 insertions(+) --- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 39f2dc9..16ff29a 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -20,6 +20,7 @@ struct inet_frag_queue { atomic_t refcnt; struct timer_list timer; /* when will this queue expire? */ struct sk_buff *fragments; /* list of received fragments */ + struct sk_buff *fragments_tail; ktime_t stamp; int len; /* total length of orig datagram */ int meat; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 858d346..dbe8999 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -314,6 +314,7 @@ static int ip_frag_reinit(struct ipq *qp) qp->q.len = 0; qp->q.meat = 0; qp->q.fragments = NULL; + qp->q.fragments_tail = NULL; qp->iif = 0; return 0; @@ -386,6 +387,11 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) * in the chain of fragments so far. We must know where to put * this fragment, right? */ + prev = qp->q.fragments_tail; + if (!prev || FRAG_CB(prev)->offset < offset) { + next = NULL; + goto found; + } prev = NULL; for (next = qp->q.fragments; next != NULL; next = next->next) { if (FRAG_CB(next)->offset >= offset) @@ -393,6 +399,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) prev = next; } +found: /* We found where to put this one. Check for overlap with * preceding fragment, and, if needed, align things so that * any overlaps are eliminated. @@ -451,6 +458,8 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) /* Insert this fragment in the chain of fragments. */ skb->next = next; + if (!next) + qp->q.fragments_tail = skb; if (prev) prev->next = skb; else @@ -504,6 +513,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, goto out_nomem; fp->next = head->next; + if (!fp->next) + qp->q.fragments_tail = fp; prev->next = fp; skb_morph(head, qp->q.fragments); @@ -574,6 +585,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, iph->tot_len = htons(len); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); qp->q.fragments = NULL; + qp->q.fragments_tail = NULL; return 0; out_nomem: diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 0b97230..b832f7b 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -333,6 +333,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, * in the chain of fragments so far. We must know where to put * this fragment, right? */ + prev = fq->q.fragments_tail; + if (!prev || FRAG6_CB(prev)->offset < offset) { + next = NULL; + goto found; + } prev = NULL; for(next = fq->q.fragments; next != NULL; next = next->next) { if (FRAG6_CB(next)->offset >= offset) @@ -340,6 +345,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, prev = next; } +found: /* We found where to put this one. Check for overlap with * preceding fragment, and, if needed, align things so that * any overlaps are eliminated. @@ -397,6 +403,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, /* Insert this fragment in the chain of fragments. */ skb->next = next; + if (!next) + fq->q.fragments_tail = skb; if (prev) prev->next = skb; else @@ -463,6 +471,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, goto out_oom; fp->next = head->next; + if (!fp->next) + fq->q.fragments_tail = fp; prev->next = fp; skb_morph(head, fq->q.fragments); @@ -549,6 +559,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); rcu_read_unlock(); fq->q.fragments = NULL; + fq->q.fragments_tail = NULL; return 1; out_oversize: