提交 d6bebca9 编写于 作者: C Changli Gao 提交者: David S. Miller

fragment: add fast path for in-order fragments

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: NChangli Gao <xiaosuo@gmail.com>
----
 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: NDavid S. Miller <davem@davemloft.net>
上级 4ce3c183
...@@ -20,6 +20,7 @@ struct inet_frag_queue { ...@@ -20,6 +20,7 @@ struct inet_frag_queue {
atomic_t refcnt; atomic_t refcnt;
struct timer_list timer; /* when will this queue expire? */ struct timer_list timer; /* when will this queue expire? */
struct sk_buff *fragments; /* list of received fragments */ struct sk_buff *fragments; /* list of received fragments */
struct sk_buff *fragments_tail;
ktime_t stamp; ktime_t stamp;
int len; /* total length of orig datagram */ int len; /* total length of orig datagram */
int meat; int meat;
......
...@@ -314,6 +314,7 @@ static int ip_frag_reinit(struct ipq *qp) ...@@ -314,6 +314,7 @@ static int ip_frag_reinit(struct ipq *qp)
qp->q.len = 0; qp->q.len = 0;
qp->q.meat = 0; qp->q.meat = 0;
qp->q.fragments = NULL; qp->q.fragments = NULL;
qp->q.fragments_tail = NULL;
qp->iif = 0; qp->iif = 0;
return 0; return 0;
...@@ -386,6 +387,11 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) ...@@ -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 * in the chain of fragments so far. We must know where to put
* this fragment, right? * this fragment, right?
*/ */
prev = qp->q.fragments_tail;
if (!prev || FRAG_CB(prev)->offset < offset) {
next = NULL;
goto found;
}
prev = NULL; prev = NULL;
for (next = qp->q.fragments; next != NULL; next = next->next) { for (next = qp->q.fragments; next != NULL; next = next->next) {
if (FRAG_CB(next)->offset >= offset) if (FRAG_CB(next)->offset >= offset)
...@@ -393,6 +399,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) ...@@ -393,6 +399,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
prev = next; prev = next;
} }
found:
/* We found where to put this one. Check for overlap with /* We found where to put this one. Check for overlap with
* preceding fragment, and, if needed, align things so that * preceding fragment, and, if needed, align things so that
* any overlaps are eliminated. * any overlaps are eliminated.
...@@ -451,6 +458,8 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) ...@@ -451,6 +458,8 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
/* Insert this fragment in the chain of fragments. */ /* Insert this fragment in the chain of fragments. */
skb->next = next; skb->next = next;
if (!next)
qp->q.fragments_tail = skb;
if (prev) if (prev)
prev->next = skb; prev->next = skb;
else else
...@@ -504,6 +513,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, ...@@ -504,6 +513,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
goto out_nomem; goto out_nomem;
fp->next = head->next; fp->next = head->next;
if (!fp->next)
qp->q.fragments_tail = fp;
prev->next = fp; prev->next = fp;
skb_morph(head, qp->q.fragments); skb_morph(head, qp->q.fragments);
...@@ -574,6 +585,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, ...@@ -574,6 +585,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
iph->tot_len = htons(len); iph->tot_len = htons(len);
IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
qp->q.fragments = NULL; qp->q.fragments = NULL;
qp->q.fragments_tail = NULL;
return 0; return 0;
out_nomem: out_nomem:
......
...@@ -333,6 +333,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, ...@@ -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 * in the chain of fragments so far. We must know where to put
* this fragment, right? * this fragment, right?
*/ */
prev = fq->q.fragments_tail;
if (!prev || FRAG6_CB(prev)->offset < offset) {
next = NULL;
goto found;
}
prev = NULL; prev = NULL;
for(next = fq->q.fragments; next != NULL; next = next->next) { for(next = fq->q.fragments; next != NULL; next = next->next) {
if (FRAG6_CB(next)->offset >= offset) if (FRAG6_CB(next)->offset >= offset)
...@@ -340,6 +345,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, ...@@ -340,6 +345,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
prev = next; prev = next;
} }
found:
/* We found where to put this one. Check for overlap with /* We found where to put this one. Check for overlap with
* preceding fragment, and, if needed, align things so that * preceding fragment, and, if needed, align things so that
* any overlaps are eliminated. * any overlaps are eliminated.
...@@ -397,6 +403,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, ...@@ -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. */ /* Insert this fragment in the chain of fragments. */
skb->next = next; skb->next = next;
if (!next)
fq->q.fragments_tail = skb;
if (prev) if (prev)
prev->next = skb; prev->next = skb;
else else
...@@ -463,6 +471,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, ...@@ -463,6 +471,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
goto out_oom; goto out_oom;
fp->next = head->next; fp->next = head->next;
if (!fp->next)
fq->q.fragments_tail = fp;
prev->next = fp; prev->next = fp;
skb_morph(head, fq->q.fragments); skb_morph(head, fq->q.fragments);
...@@ -549,6 +559,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, ...@@ -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); IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
rcu_read_unlock(); rcu_read_unlock();
fq->q.fragments = NULL; fq->q.fragments = NULL;
fq->q.fragments_tail = NULL;
return 1; return 1;
out_oversize: out_oversize:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册