Thread (2 messages) 2 messages, 2 authors, 2016-09-09

Re: [PATCH net-next v5] gso: Support partial splitting at the frag_list pointer

flat view

From: Alexander Duyck <hidden>
Date: 2016-09-09 15:20:57

On Fri, Sep 9, 2016 at 12:25 AM, Steffen Klassert
[off-list ref] wrote:
quoted hunk ↗ jump to hunk
Since commit 8a29111c7 ("net: gro: allow to build full sized skb")
gro may build buffers with a frag_list. This can hurt forwarding
because most NICs can't offload such packets, they need to be
segmented in software. This patch splits buffers with a frag_list
at the frag_list pointer into buffers that can be TSO offloaded.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---

Changes since v1:

- Use the assumption that all buffers in the chain excluding the last
  containing the same amount of data.

- Simplify some checks against gso partial.

- Fix the generation of IP IDs.

Changes since v2:

- Merge common code of gso partial and frag_list pointer splitting.

Changes since v3:

- Fix the checks for doing frag_list pointer splitting.

Changes since v4:

- Whitespace fix.
- Fix size calculations of the tail packet.

 net/core/skbuff.c      | 51 +++++++++++++++++++++++++++++++++++++++-----------
 net/ipv4/af_inet.c     | 14 ++++++++++----
 net/ipv4/gre_offload.c |  6 ++++--
 net/ipv4/tcp_offload.c | 13 +++++++------
 net/ipv4/udp_offload.c |  6 ++++--
 net/ipv6/ip6_offload.c |  5 ++++-
 6 files changed, 69 insertions(+), 26 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 3864b4b6..51e761a 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3078,11 +3078,31 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
<...>
quoted hunk ↗ jump to hunk
@@ -3090,6 +3110,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
                        partial_segs = 0;
        }

+normal:
        headroom = skb_headroom(head_skb);
        pos = skb_headlen(head_skb);
@@ -3281,21 +3302,29 @@ perform_csum_check:
         */
        segs->prev = tail;

-       /* Update GSO info on first skb in partial sequence. */
        if (partial_segs) {
+               struct sk_buff *iter;
                int type = skb_shinfo(head_skb)->gso_type;
+               unsigned short gso_size = skb_shinfo(head_skb)->gso_size;

                /* Update type to add partial and then remove dodgy if set */
-               type |= SKB_GSO_PARTIAL;
+               type |= (features & NETIF_F_GSO_PARTIAL) / NETIF_F_GSO_PARTIAL * SKB_GSO_PARTIAL;
                type &= ~SKB_GSO_DODGY;

                /* Update GSO info and prepare to start updating headers on
                 * our way back down the stack of protocols.
                 */
-               skb_shinfo(segs)->gso_size = skb_shinfo(head_skb)->gso_size;
-               skb_shinfo(segs)->gso_segs = partial_segs;
-               skb_shinfo(segs)->gso_type = type;
-               SKB_GSO_CB(segs)->data_offset = skb_headroom(segs) + doffset;
+               for (iter = segs; iter; iter = iter->next) {
+                       skb_shinfo(iter)->gso_size = gso_size;
+                       skb_shinfo(iter)->gso_segs = partial_segs;
+                       skb_shinfo(iter)->gso_type = type;
+                       SKB_GSO_CB(iter)->data_offset = skb_headroom(iter) + doffset;
+               }
+
+               if (tail->len <= gso_size)
+                       skb_shinfo(tail)->gso_size = 0;
Actually we need to do tail->len - doffset up here as well.  The
gso_size value reflects the size of the data segment, and tail->len is
the size of the entire frame so we have to remove the size of the
headers to make the comparison accurate.
quoted hunk ↗ jump to hunk
+               else if (tail != segs)
+                       skb_shinfo(tail)->gso_segs = DIV_ROUND_UP(tail->len - doffset, gso_size);
        }

        /* Following permits correct backpressure, for protocols
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help