Commit fb4a020e authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji Committed by David S. Miller

[IPV4/IPV6]: More fragment handling improvements.

Here's the optimization: if we know the remaining data exceeds the
mtu, we do not need to fill up full of it.

skb_prev:
                mtu
+----------+--+-+
|          |  | |
+----------+--+-+
           ^  ^
skb_prev->len |
              maxfraglen

appending data:
           +--------+
           |        |
           +--------+
           --------->
                  length

In this case, we know we need more fragment(s).
So, let's fill up to maxfraglen (instead of mtu) 
to avoid needless copy in the next loop.
Signed-off-by: default avatarHideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8749b1cd
...@@ -811,26 +811,33 @@ int ip_append_data(struct sock *sk, ...@@ -811,26 +811,33 @@ int ip_append_data(struct sock *sk,
goto alloc_new_skb; goto alloc_new_skb;
while (length > 0) { while (length > 0) {
if ((copy = mtu - skb->len) <= 0) { /* Check if the remaining data fits into current packet. */
copy = mtu - skb->len;
if (copy < length)
copy = maxfraglen - skb->len;
if (copy <= 0) {
char *data; char *data;
unsigned int datalen; unsigned int datalen;
unsigned int fraglen; unsigned int fraglen;
unsigned int fraggap; unsigned int fraggap;
unsigned int alloclen; unsigned int alloclen;
struct sk_buff *skb_prev; struct sk_buff *skb_prev;
BUG_TRAP(copy == 0);
alloc_new_skb: alloc_new_skb:
skb_prev = skb; skb_prev = skb;
fraggap = 0;
if (skb_prev) if (skb_prev)
fraggap = mtu - maxfraglen; fraggap = skb_prev->len - maxfraglen;
else
fraggap = 0;
datalen = mtu - fragheaderlen; /*
if (datalen > length + fraggap) * If remaining data exceeds the mtu,
* we know we need more fragment(s).
*/
datalen = length + fraggap; datalen = length + fraggap;
if (datalen > mtu - fragheaderlen)
datalen = maxfraglen - fragheaderlen;
fraglen = datalen + fragheaderlen; fraglen = datalen + fragheaderlen;
if ((flags & MSG_MORE) && if ((flags & MSG_MORE) &&
!(rt->u.dst.dev->features&NETIF_F_SG)) !(rt->u.dst.dev->features&NETIF_F_SG))
alloclen = mtu; alloclen = mtu;
...@@ -1026,18 +1033,22 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, ...@@ -1026,18 +1033,22 @@ ssize_t ip_append_page(struct sock *sk, struct page *page,
while (size > 0) { while (size > 0) {
int i; int i;
if ((len = mtu - skb->len) <= 0) {
/* Check if the remaining data fits into current packet. */
len = mtu - skb->len;
if (len < size)
len = maxfraglen - skb->len;
if (len <= 0) {
struct sk_buff *skb_prev; struct sk_buff *skb_prev;
char *data; char *data;
struct iphdr *iph; struct iphdr *iph;
int alloclen; int alloclen;
BUG_TRAP(len == 0);
skb_prev = skb; skb_prev = skb;
fraggap = 0;
if (skb_prev) if (skb_prev)
fraggap = mtu - maxfraglen; fraggap = skb_prev->len - maxfraglen;
else
fraggap = 0;
alloclen = fragheaderlen + hh_len + fraggap + 15; alloclen = fragheaderlen + hh_len + fraggap + 15;
skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation); skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation);
......
...@@ -898,26 +898,34 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offse ...@@ -898,26 +898,34 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offse
goto alloc_new_skb; goto alloc_new_skb;
while (length > 0) { while (length > 0) {
if ((copy = mtu - skb->len) <= 0) { /* Check if the remaining data fits into current packet. */
copy = mtu - skb->len;
if (copy < length)
copy = maxfraglen - skb->len;
if (copy <= 0) {
char *data; char *data;
unsigned int datalen; unsigned int datalen;
unsigned int fraglen; unsigned int fraglen;
unsigned int fraggap; unsigned int fraggap;
unsigned int alloclen; unsigned int alloclen;
struct sk_buff *skb_prev; struct sk_buff *skb_prev;
BUG_TRAP(copy == 0);
alloc_new_skb: alloc_new_skb:
skb_prev = skb; skb_prev = skb;
/* There's no room in the current skb */ /* There's no room in the current skb */
fraggap = 0;
if (skb_prev) if (skb_prev)
fraggap = mtu - maxfraglen; fraggap = skb_prev->len - maxfraglen;
else
datalen = mtu - fragheaderlen; fraggap = 0;
if (datalen > length + fraggap) /*
* If remaining data exceeds the mtu,
* we know we need more fragment(s).
*/
datalen = length + fraggap; datalen = length + fraggap;
if (datalen > mtu - fragheaderlen)
datalen = maxfraglen - fragheaderlen;
fraglen = datalen + fragheaderlen; fraglen = datalen + fragheaderlen;
if ((flags & MSG_MORE) && if ((flags & MSG_MORE) &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment