From fb4a020e6ef676c284e8b30d898d2c6b96453712 Mon Sep 17 00:00:00 2001 From: Hideaki Yoshifuji Date: Tue, 7 Sep 2004 23:23:00 -0700 Subject: [PATCH] [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: Hideaki YOSHIFUJI Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 39 +++++++++++++++++++++++++-------------- net/ipv6/ip6_output.c | 24 ++++++++++++++++-------- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 983b50d9dc6ca..5282f53f551ce 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -811,26 +811,33 @@ int ip_append_data(struct sock *sk, goto alloc_new_skb; 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; unsigned int datalen; unsigned int fraglen; unsigned int fraggap; unsigned int alloclen; struct sk_buff *skb_prev; - BUG_TRAP(copy == 0); - alloc_new_skb: skb_prev = skb; - fraggap = 0; if (skb_prev) - fraggap = mtu - maxfraglen; - - datalen = mtu - fragheaderlen; - if (datalen > length + fraggap) - datalen = length + fraggap; + fraggap = skb_prev->len - maxfraglen; + else + fraggap = 0; + /* + * If remaining data exceeds the mtu, + * we know we need more fragment(s). + */ + datalen = length + fraggap; + if (datalen > mtu - fragheaderlen) + datalen = maxfraglen - fragheaderlen; fraglen = datalen + fragheaderlen; + if ((flags & MSG_MORE) && !(rt->u.dst.dev->features&NETIF_F_SG)) alloclen = mtu; @@ -1026,18 +1033,22 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, while (size > 0) { 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; char *data; struct iphdr *iph; int alloclen; - BUG_TRAP(len == 0); - skb_prev = skb; - fraggap = 0; if (skb_prev) - fraggap = mtu - maxfraglen; + fraggap = skb_prev->len - maxfraglen; + else + fraggap = 0; alloclen = fragheaderlen + hh_len + fraggap + 15; skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index f7d462f0cd05b..63d1dabdad88d 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -898,26 +898,34 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offse goto alloc_new_skb; 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; unsigned int datalen; unsigned int fraglen; unsigned int fraggap; unsigned int alloclen; struct sk_buff *skb_prev; - BUG_TRAP(copy == 0); alloc_new_skb: skb_prev = skb; /* There's no room in the current skb */ - fraggap = 0; if (skb_prev) - fraggap = mtu - maxfraglen; - - datalen = mtu - fragheaderlen; + fraggap = skb_prev->len - maxfraglen; + else + fraggap = 0; - if (datalen > length + fraggap) - datalen = length + fraggap; + /* + * If remaining data exceeds the mtu, + * we know we need more fragment(s). + */ + datalen = length + fraggap; + if (datalen > mtu - fragheaderlen) + datalen = maxfraglen - fragheaderlen; fraglen = datalen + fragheaderlen; if ((flags & MSG_MORE) && -- 2.53.0