diff options
| author | Wang Zhan <wang.zhan@smartx.com> | 2026-10-08 18:06:48 +0800 |
|---|---|---|
| committer | Paolo Abeni <pabeni@redhat.com> | 2026-10-13 15:32:47 +0200 |
| commit | c4076626ba520ecf710755046bf5ae6f2fd5b965 (patch) | |
| tree | cd5a3151cc0ed1e5d920da9d1ac10c7f319a95d3 /include | |
| parent | 0bba48256b0aa86e84a08d69b4410018bd8ffc67 (diff) | |
| download | linux-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.h | 7 | ||||
| -rw-r--r-- | include/net/udp.h | 2 |
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; |
