Skip to content

Commit

Permalink
fragment: add fast path for in-order fragments
Browse files Browse the repository at this point in the history
add fast path for in-order fragments

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 <[email protected]>
----
 include/net/inet_frag.h |    1 +
 net/ipv4/ip_fragment.c  |   12 ++++++++++++
 net/ipv6/reassembly.c   |   11 +++++++++++
 3 files changed, 24 insertions(+)
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
xiaosuo authored and davem330 committed Jun 30, 2010
1 parent 4ce3c18 commit d6bebca
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/net/inet_frag.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions net/ipv4/ip_fragment.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -386,13 +387,19 @@ 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)
break; /* bingo! */
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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
11 changes: 11 additions & 0 deletions net/ipv6/reassembly.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,13 +333,19 @@ 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)
break; /* bingo! */
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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit d6bebca

Please sign in to comment.