summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorWang Zhan <wang.zhan@smartx.com>2026-10-08 18:06:48 +0800
committerPaolo Abeni <pabeni@redhat.com>2026-10-13 15:32:47 +0200
commitc4076626ba520ecf710755046bf5ae6f2fd5b965 (patch)
treecd5a3151cc0ed1e5d920da9d1ac10c7f319a95d3 /include
parent0bba48256b0aa86e84a08d69b4410018bd8ffc67 (diff)
downloadlinux-c4076626ba520ecf710755046bf5ae6f2fd5b965.tar.gz
linux-c4076626ba520ecf710755046bf5ae6f2fd5b965.zip
net: gso: support re-segmentation of TCP GSO skbs
A caller which re-segments an oversized TCP GSO skb needs the engine to group several MSS into one output skb, so let it pass how many MSS segments each output skb may carry through __skb_gso_segment(). max_segs is a per-call u8 in the skb_gso_cb scratch context, and only an unencapsulated TCP skb without a frag_list sets it; every other caller passes zero. Without max_segs, skb_segment() groups several MSS into one output skb only for a device which advertises NETIF_F_GSO_PARTIAL, or for a frag_list which splits into uniform pieces. max_segs skips that test. The output stays a GSO skb: gso_size keeps the original MSS and gso_segs the number of MSS it holds, so a downstream device can still perform TSO. The caller keeps the output within the 64 KiB its L3 length field can express. Reviewed-by: Willem de Bruijn <willemb@google.com> Assisted-by: LLM Signed-off-by: Wang Zhan <wang.zhan@smartx.com> Link: https://patch.msgid.link/20261008100651.2534957-4-wang.zhan@smartx.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'include')
-rw-r--r--include/net/gso.h7
-rw-r--r--include/net/udp.h2
2 files changed, 6 insertions, 3 deletions
diff --git a/include/net/gso.h b/include/net/gso.h
index 0749230d414e..fe3260b381d4 100644
--- a/include/net/gso.h
+++ b/include/net/gso.h
@@ -21,6 +21,8 @@ struct skb_gso_cb {
__u16 csum_start;
/* Number of IPv4/IPv6 GSO handler entries for this packet. */
u8 recursion_counter;
+ /* Max MSS segs per output skb, 0 = no limit */
+ u8 max_segs;
};
#define SKB_GSO_CB_OFFSET 32
#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)((skb)->cb + SKB_GSO_CB_OFFSET))
@@ -83,12 +85,13 @@ static inline __sum16 gso_make_checksum(struct sk_buff *skb, __wsum res)
}
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
- netdev_features_t features, bool tx_path);
+ netdev_features_t features, bool tx_path,
+ unsigned int max_segs);
static inline struct sk_buff *skb_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
- return __skb_gso_segment(skb, features, true);
+ return __skb_gso_segment(skb, features, true, 0);
}
struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
diff --git a/include/net/udp.h b/include/net/udp.h
index 1fee17274745..5bc25dcf25fb 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -613,7 +613,7 @@ static inline struct sk_buff *udp_rcv_segment(struct sock *sk,
/* the GSO CB lays after the UDP one, no need to save and restore any
* CB fragment
*/
- segs = __skb_gso_segment(skb, features, false);
+ segs = __skb_gso_segment(skb, features, false, 0);
if (IS_ERR_OR_NULL(segs)) {
drop_count = skb_shinfo(skb)->gso_segs;
goto drop;