net: move gso declarations and functions to their own files

Move declarations into include/net/gso.h and code into net/core/gso.c

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Stanislav Fomichev <sdf@google.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20230608191738.3947077-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Eric Dumazet 2023-06-08 19:17:37 +00:00 committed by Jakub Kicinski
parent cabb8b48e5
commit d457a0e329
46 changed files with 425 additions and 365 deletions

View File

@ -57,6 +57,7 @@
#include <linux/crc32poly.h> #include <linux/crc32poly.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/gso.h>
#include <net/ip.h> #include <net/ip.h>
#include <linux/io.h> #include <linux/io.h>

View File

@ -66,6 +66,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/prefetch.h> #include <linux/prefetch.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/gso.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>

View File

@ -12,6 +12,7 @@
#include "efx.h" #include "efx.h"
#include "nic_common.h" #include "nic_common.h"
#include "tx_common.h" #include "tx_common.h"
#include <net/gso.h>
static unsigned int efx_tx_cb_page_count(struct efx_tx_queue *tx_queue) static unsigned int efx_tx_cb_page_count(struct efx_tx_queue *tx_queue)
{ {

View File

@ -12,6 +12,7 @@
#include "efx.h" #include "efx.h"
#include "nic_common.h" #include "nic_common.h"
#include "tx_common.h" #include "tx_common.h"
#include <net/gso.h>
static unsigned int efx_tx_cb_page_count(struct efx_tx_queue *tx_queue) static unsigned int efx_tx_cb_page_count(struct efx_tx_queue *tx_queue)
{ {

View File

@ -18,6 +18,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <net/gso.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include <net/sock.h> #include <net/sock.h>

View File

@ -27,6 +27,7 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include <linux/usb/r8152.h> #include <linux/usb/r8152.h>
#include <net/gso.h>
/* Information for net-next */ /* Information for net-next */
#define NETNEXT_VERSION "12" #define NETNEXT_VERSION "12"

View File

@ -20,6 +20,7 @@
#include <linux/icmp.h> #include <linux/icmp.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <net/dst_metadata.h> #include <net/dst_metadata.h>
#include <net/gso.h>
#include <net/icmp.h> #include <net/icmp.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include <net/ip_tunnels.h> #include <net/ip_tunnels.h>

View File

@ -7,6 +7,7 @@
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/tcp.h> #include <linux/tcp.h>
#include <net/gso.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>

View File

@ -4827,13 +4827,6 @@ int skb_crc32c_csum_help(struct sk_buff *skb);
int skb_csum_hwoffload_help(struct sk_buff *skb, int skb_csum_hwoffload_help(struct sk_buff *skb,
const netdev_features_t features); const netdev_features_t features);
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
netdev_features_t features, bool tx_path);
struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
netdev_features_t features, __be16 type);
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
netdev_features_t features);
struct netdev_bonding_info { struct netdev_bonding_info {
ifslave slave; ifslave slave;
ifbond master; ifbond master;
@ -4856,11 +4849,6 @@ static inline void ethtool_notify(struct net_device *dev, unsigned int cmd,
} }
#endif #endif
static inline
struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features)
{
return __skb_gso_segment(skb, features, true);
}
__be16 skb_network_protocol(struct sk_buff *skb, int *depth); __be16 skb_network_protocol(struct sk_buff *skb, int *depth);
static inline bool can_checksum_protocol(netdev_features_t features, static inline bool can_checksum_protocol(netdev_features_t features,
@ -4987,6 +4975,7 @@ netdev_features_t passthru_features_check(struct sk_buff *skb,
struct net_device *dev, struct net_device *dev,
netdev_features_t features); netdev_features_t features);
netdev_features_t netif_skb_features(struct sk_buff *skb); netdev_features_t netif_skb_features(struct sk_buff *skb);
void skb_warn_bad_offload(const struct sk_buff *skb);
static inline bool net_gso_ok(netdev_features_t features, int gso_type) static inline bool net_gso_ok(netdev_features_t features, int gso_type)
{ {
@ -5035,19 +5024,6 @@ void netif_set_tso_max_segs(struct net_device *dev, unsigned int segs);
void netif_inherit_tso_max(struct net_device *to, void netif_inherit_tso_max(struct net_device *to,
const struct net_device *from); const struct net_device *from);
static inline void skb_gso_error_unwind(struct sk_buff *skb, __be16 protocol,
int pulled_hlen, u16 mac_offset,
int mac_len)
{
skb->protocol = protocol;
skb->encapsulation = 1;
skb_push(skb, pulled_hlen);
skb_reset_transport_header(skb);
skb->mac_header = mac_offset;
skb->network_header = skb->mac_header + mac_len;
skb->mac_len = mac_len;
}
static inline bool netif_is_macsec(const struct net_device *dev) static inline bool netif_is_macsec(const struct net_device *dev)
{ {
return dev->priv_flags & IFF_MACSEC; return dev->priv_flags & IFF_MACSEC;

View File

@ -3974,8 +3974,6 @@ int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
void skb_scrub_packet(struct sk_buff *skb, bool xnet); void skb_scrub_packet(struct sk_buff *skb, bool xnet);
bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu);
bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len);
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
struct sk_buff *skb_segment_list(struct sk_buff *skb, netdev_features_t features, struct sk_buff *skb_segment_list(struct sk_buff *skb, netdev_features_t features,
unsigned int offset); unsigned int offset);
@ -4841,75 +4839,6 @@ static inline struct sec_path *skb_sec_path(const struct sk_buff *skb)
#endif #endif
} }
/* Keeps track of mac header offset relative to skb->head.
* It is useful for TSO of Tunneling protocol. e.g. GRE.
* For non-tunnel skb it points to skb_mac_header() and for
* tunnel skb it points to outer mac header.
* Keeps track of level of encapsulation of network headers.
*/
struct skb_gso_cb {
union {
int mac_offset;
int data_offset;
};
int encap_level;
__wsum csum;
__u16 csum_start;
};
#define SKB_GSO_CB_OFFSET 32
#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)((skb)->cb + SKB_GSO_CB_OFFSET))
static inline int skb_tnl_header_len(const struct sk_buff *inner_skb)
{
return (skb_mac_header(inner_skb) - inner_skb->head) -
SKB_GSO_CB(inner_skb)->mac_offset;
}
static inline int gso_pskb_expand_head(struct sk_buff *skb, int extra)
{
int new_headroom, headroom;
int ret;
headroom = skb_headroom(skb);
ret = pskb_expand_head(skb, extra, 0, GFP_ATOMIC);
if (ret)
return ret;
new_headroom = skb_headroom(skb);
SKB_GSO_CB(skb)->mac_offset += (new_headroom - headroom);
return 0;
}
static inline void gso_reset_checksum(struct sk_buff *skb, __wsum res)
{
/* Do not update partial checksums if remote checksum is enabled. */
if (skb->remcsum_offload)
return;
SKB_GSO_CB(skb)->csum = res;
SKB_GSO_CB(skb)->csum_start = skb_checksum_start(skb) - skb->head;
}
/* Compute the checksum for a gso segment. First compute the checksum value
* from the start of transport header to SKB_GSO_CB(skb)->csum_start, and
* then add in skb->csum (checksum from csum_start to end of packet).
* skb->csum and csum_start are then updated to reflect the checksum of the
* resultant packet starting from the transport header-- the resultant checksum
* is in the res argument (i.e. normally zero or ~ of checksum of a pseudo
* header.
*/
static inline __sum16 gso_make_checksum(struct sk_buff *skb, __wsum res)
{
unsigned char *csum_start = skb_transport_header(skb);
int plen = (skb->head + SKB_GSO_CB(skb)->csum_start) - csum_start;
__wsum partial = SKB_GSO_CB(skb)->csum;
SKB_GSO_CB(skb)->csum = res;
SKB_GSO_CB(skb)->csum_start = csum_start - skb->head;
return csum_fold(csum_partial(csum_start, plen, partial));
}
static inline bool skb_is_gso(const struct sk_buff *skb) static inline bool skb_is_gso(const struct sk_buff *skb)
{ {
return skb_shinfo(skb)->gso_size; return skb_shinfo(skb)->gso_size;

View File

@ -452,5 +452,6 @@ static inline void gro_normal_one(struct napi_struct *napi, struct sk_buff *skb,
gro_normal_list(napi); gro_normal_list(napi);
} }
extern struct list_head offload_base;
#endif /* _NET_IPV6_GRO_H */ #endif /* _NET_IPV6_GRO_H */

109
include/net/gso.h Normal file
View File

@ -0,0 +1,109 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _NET_GSO_H
#define _NET_GSO_H
#include <linux/skbuff.h>
/* Keeps track of mac header offset relative to skb->head.
* It is useful for TSO of Tunneling protocol. e.g. GRE.
* For non-tunnel skb it points to skb_mac_header() and for
* tunnel skb it points to outer mac header.
* Keeps track of level of encapsulation of network headers.
*/
struct skb_gso_cb {
union {
int mac_offset;
int data_offset;
};
int encap_level;
__wsum csum;
__u16 csum_start;
};
#define SKB_GSO_CB_OFFSET 32
#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)((skb)->cb + SKB_GSO_CB_OFFSET))
static inline int skb_tnl_header_len(const struct sk_buff *inner_skb)
{
return (skb_mac_header(inner_skb) - inner_skb->head) -
SKB_GSO_CB(inner_skb)->mac_offset;
}
static inline int gso_pskb_expand_head(struct sk_buff *skb, int extra)
{
int new_headroom, headroom;
int ret;
headroom = skb_headroom(skb);
ret = pskb_expand_head(skb, extra, 0, GFP_ATOMIC);
if (ret)
return ret;
new_headroom = skb_headroom(skb);
SKB_GSO_CB(skb)->mac_offset += (new_headroom - headroom);
return 0;
}
static inline void gso_reset_checksum(struct sk_buff *skb, __wsum res)
{
/* Do not update partial checksums if remote checksum is enabled. */
if (skb->remcsum_offload)
return;
SKB_GSO_CB(skb)->csum = res;
SKB_GSO_CB(skb)->csum_start = skb_checksum_start(skb) - skb->head;
}
/* Compute the checksum for a gso segment. First compute the checksum value
* from the start of transport header to SKB_GSO_CB(skb)->csum_start, and
* then add in skb->csum (checksum from csum_start to end of packet).
* skb->csum and csum_start are then updated to reflect the checksum of the
* resultant packet starting from the transport header-- the resultant checksum
* is in the res argument (i.e. normally zero or ~ of checksum of a pseudo
* header.
*/
static inline __sum16 gso_make_checksum(struct sk_buff *skb, __wsum res)
{
unsigned char *csum_start = skb_transport_header(skb);
int plen = (skb->head + SKB_GSO_CB(skb)->csum_start) - csum_start;
__wsum partial = SKB_GSO_CB(skb)->csum;
SKB_GSO_CB(skb)->csum = res;
SKB_GSO_CB(skb)->csum_start = csum_start - skb->head;
return csum_fold(csum_partial(csum_start, plen, partial));
}
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
netdev_features_t features, bool tx_path);
static inline struct sk_buff *skb_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
return __skb_gso_segment(skb, features, true);
}
struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
netdev_features_t features, __be16 type);
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
netdev_features_t features);
bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu);
bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len);
static inline void skb_gso_error_unwind(struct sk_buff *skb, __be16 protocol,
int pulled_hlen, u16 mac_offset,
int mac_len)
{
skb->protocol = protocol;
skb->encapsulation = 1;
skb_push(skb, pulled_hlen);
skb_reset_transport_header(skb);
skb->mac_header = mac_offset;
skb->network_header = skb->mac_header + mac_len;
skb->mac_len = mac_len;
}
#endif /* _NET_GSO_H */

View File

@ -21,6 +21,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <net/inet_sock.h> #include <net/inet_sock.h>
#include <net/gso.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/snmp.h> #include <net/snmp.h>
#include <net/ip.h> #include <net/ip.h>

View File

@ -13,7 +13,7 @@ obj-y += dev.o dev_addr_lists.o dst.o netevent.o \
neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \ sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
fib_notifier.o xdp.o flow_offload.o gro.o \ fib_notifier.o xdp.o flow_offload.o gro.o \
netdev-genl.o netdev-genl-gen.o netdev-genl.o netdev-genl-gen.o gso.o
obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o

View File

@ -3209,7 +3209,7 @@ static u16 skb_tx_hash(const struct net_device *dev,
return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset; return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset;
} }
static void skb_warn_bad_offload(const struct sk_buff *skb) void skb_warn_bad_offload(const struct sk_buff *skb)
{ {
static const netdev_features_t null_features; static const netdev_features_t null_features;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
@ -3338,74 +3338,6 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth)
return vlan_get_protocol_and_depth(skb, type, depth); return vlan_get_protocol_and_depth(skb, type, depth);
} }
/* openvswitch calls this on rx path, so we need a different check.
*/
static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path)
{
if (tx_path)
return skb->ip_summed != CHECKSUM_PARTIAL &&
skb->ip_summed != CHECKSUM_UNNECESSARY;
return skb->ip_summed == CHECKSUM_NONE;
}
/**
* __skb_gso_segment - Perform segmentation on skb.
* @skb: buffer to segment
* @features: features for the output path (see dev->features)
* @tx_path: whether it is called in TX path
*
* This function segments the given skb and returns a list of segments.
*
* It may return NULL if the skb requires no segmentation. This is
* only possible when GSO is used for verifying header integrity.
*
* Segmentation preserves SKB_GSO_CB_OFFSET bytes of previous skb cb.
*/
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
netdev_features_t features, bool tx_path)
{
struct sk_buff *segs;
if (unlikely(skb_needs_check(skb, tx_path))) {
int err;
/* We're going to init ->check field in TCP or UDP header */
err = skb_cow_head(skb, 0);
if (err < 0)
return ERR_PTR(err);
}
/* Only report GSO partial support if it will enable us to
* support segmentation on this frame without needing additional
* work.
*/
if (features & NETIF_F_GSO_PARTIAL) {
netdev_features_t partial_features = NETIF_F_GSO_ROBUST;
struct net_device *dev = skb->dev;
partial_features |= dev->features & dev->gso_partial_features;
if (!skb_gso_ok(skb, features | partial_features))
features &= ~NETIF_F_GSO_PARTIAL;
}
BUILD_BUG_ON(SKB_GSO_CB_OFFSET +
sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb));
SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb);
SKB_GSO_CB(skb)->encap_level = 0;
skb_reset_mac_header(skb);
skb_reset_mac_len(skb);
segs = skb_mac_gso_segment(skb, features);
if (segs != skb && unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs)))
skb_warn_bad_offload(skb);
return segs;
}
EXPORT_SYMBOL(__skb_gso_segment);
/* Take action when hardware reception checksum errors are detected. */ /* Take action when hardware reception checksum errors are detected. */
#ifdef CONFIG_BUG #ifdef CONFIG_BUG

View File

@ -10,7 +10,7 @@
#define GRO_MAX_HEAD (MAX_HEADER + 128) #define GRO_MAX_HEAD (MAX_HEADER + 128)
static DEFINE_SPINLOCK(offload_lock); static DEFINE_SPINLOCK(offload_lock);
static struct list_head offload_base __read_mostly = LIST_HEAD_INIT(offload_base); struct list_head offload_base __read_mostly = LIST_HEAD_INIT(offload_base);
/* Maximum number of GRO_NORMAL skbs to batch up for list-RX */ /* Maximum number of GRO_NORMAL skbs to batch up for list-RX */
int gro_normal_batch __read_mostly = 8; int gro_normal_batch __read_mostly = 8;
@ -92,63 +92,6 @@ void dev_remove_offload(struct packet_offload *po)
} }
EXPORT_SYMBOL(dev_remove_offload); EXPORT_SYMBOL(dev_remove_offload);
/**
* skb_eth_gso_segment - segmentation handler for ethernet protocols.
* @skb: buffer to segment
* @features: features for the output path (see dev->features)
* @type: Ethernet Protocol ID
*/
struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
netdev_features_t features, __be16 type)
{
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
struct packet_offload *ptype;
rcu_read_lock();
list_for_each_entry_rcu(ptype, &offload_base, list) {
if (ptype->type == type && ptype->callbacks.gso_segment) {
segs = ptype->callbacks.gso_segment(skb, features);
break;
}
}
rcu_read_unlock();
return segs;
}
EXPORT_SYMBOL(skb_eth_gso_segment);
/**
* skb_mac_gso_segment - mac layer segmentation handler.
* @skb: buffer to segment
* @features: features for the output path (see dev->features)
*/
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
struct packet_offload *ptype;
int vlan_depth = skb->mac_len;
__be16 type = skb_network_protocol(skb, &vlan_depth);
if (unlikely(!type))
return ERR_PTR(-EINVAL);
__skb_pull(skb, vlan_depth);
rcu_read_lock();
list_for_each_entry_rcu(ptype, &offload_base, list) {
if (ptype->type == type && ptype->callbacks.gso_segment) {
segs = ptype->callbacks.gso_segment(skb, features);
break;
}
}
rcu_read_unlock();
__skb_push(skb, skb->data - skb_mac_header(skb));
return segs;
}
EXPORT_SYMBOL(skb_mac_gso_segment);
int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
{ {

273
net/core/gso.c Normal file
View File

@ -0,0 +1,273 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/skbuff.h>
#include <linux/sctp.h>
#include <net/gso.h>
#include <net/gro.h>
/**
* skb_eth_gso_segment - segmentation handler for ethernet protocols.
* @skb: buffer to segment
* @features: features for the output path (see dev->features)
* @type: Ethernet Protocol ID
*/
struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
netdev_features_t features, __be16 type)
{
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
struct packet_offload *ptype;
rcu_read_lock();
list_for_each_entry_rcu(ptype, &offload_base, list) {
if (ptype->type == type && ptype->callbacks.gso_segment) {
segs = ptype->callbacks.gso_segment(skb, features);
break;
}
}
rcu_read_unlock();
return segs;
}
EXPORT_SYMBOL(skb_eth_gso_segment);
/**
* skb_mac_gso_segment - mac layer segmentation handler.
* @skb: buffer to segment
* @features: features for the output path (see dev->features)
*/
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
struct packet_offload *ptype;
int vlan_depth = skb->mac_len;
__be16 type = skb_network_protocol(skb, &vlan_depth);
if (unlikely(!type))
return ERR_PTR(-EINVAL);
__skb_pull(skb, vlan_depth);
rcu_read_lock();
list_for_each_entry_rcu(ptype, &offload_base, list) {
if (ptype->type == type && ptype->callbacks.gso_segment) {
segs = ptype->callbacks.gso_segment(skb, features);
break;
}
}
rcu_read_unlock();
__skb_push(skb, skb->data - skb_mac_header(skb));
return segs;
}
EXPORT_SYMBOL(skb_mac_gso_segment);
/* openvswitch calls this on rx path, so we need a different check.
*/
static bool skb_needs_check(const struct sk_buff *skb, bool tx_path)
{
if (tx_path)
return skb->ip_summed != CHECKSUM_PARTIAL &&
skb->ip_summed != CHECKSUM_UNNECESSARY;
return skb->ip_summed == CHECKSUM_NONE;
}
/**
* __skb_gso_segment - Perform segmentation on skb.
* @skb: buffer to segment
* @features: features for the output path (see dev->features)
* @tx_path: whether it is called in TX path
*
* This function segments the given skb and returns a list of segments.
*
* It may return NULL if the skb requires no segmentation. This is
* only possible when GSO is used for verifying header integrity.
*
* Segmentation preserves SKB_GSO_CB_OFFSET bytes of previous skb cb.
*/
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
netdev_features_t features, bool tx_path)
{
struct sk_buff *segs;
if (unlikely(skb_needs_check(skb, tx_path))) {
int err;
/* We're going to init ->check field in TCP or UDP header */
err = skb_cow_head(skb, 0);
if (err < 0)
return ERR_PTR(err);
}
/* Only report GSO partial support if it will enable us to
* support segmentation on this frame without needing additional
* work.
*/
if (features & NETIF_F_GSO_PARTIAL) {
netdev_features_t partial_features = NETIF_F_GSO_ROBUST;
struct net_device *dev = skb->dev;
partial_features |= dev->features & dev->gso_partial_features;
if (!skb_gso_ok(skb, features | partial_features))
features &= ~NETIF_F_GSO_PARTIAL;
}
BUILD_BUG_ON(SKB_GSO_CB_OFFSET +
sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb));
SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb);
SKB_GSO_CB(skb)->encap_level = 0;
skb_reset_mac_header(skb);
skb_reset_mac_len(skb);
segs = skb_mac_gso_segment(skb, features);
if (segs != skb && unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs)))
skb_warn_bad_offload(skb);
return segs;
}
EXPORT_SYMBOL(__skb_gso_segment);
/**
* skb_gso_transport_seglen - Return length of individual segments of a gso packet
*
* @skb: GSO skb
*
* skb_gso_transport_seglen is used to determine the real size of the
* individual segments, including Layer4 headers (TCP/UDP).
*
* The MAC/L2 or network (IP, IPv6) headers are not accounted for.
*/
static unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
{
const struct skb_shared_info *shinfo = skb_shinfo(skb);
unsigned int thlen = 0;
if (skb->encapsulation) {
thlen = skb_inner_transport_header(skb) -
skb_transport_header(skb);
if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
thlen += inner_tcp_hdrlen(skb);
} else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
thlen = tcp_hdrlen(skb);
} else if (unlikely(skb_is_gso_sctp(skb))) {
thlen = sizeof(struct sctphdr);
} else if (shinfo->gso_type & SKB_GSO_UDP_L4) {
thlen = sizeof(struct udphdr);
}
/* UFO sets gso_size to the size of the fragmentation
* payload, i.e. the size of the L4 (UDP) header is already
* accounted for.
*/
return thlen + shinfo->gso_size;
}
/**
* skb_gso_network_seglen - Return length of individual segments of a gso packet
*
* @skb: GSO skb
*
* skb_gso_network_seglen is used to determine the real size of the
* individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP).
*
* The MAC/L2 header is not accounted for.
*/
static unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
{
unsigned int hdr_len = skb_transport_header(skb) -
skb_network_header(skb);
return hdr_len + skb_gso_transport_seglen(skb);
}
/**
* skb_gso_mac_seglen - Return length of individual segments of a gso packet
*
* @skb: GSO skb
*
* skb_gso_mac_seglen is used to determine the real size of the
* individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
* headers (TCP/UDP).
*/
static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
{
unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
return hdr_len + skb_gso_transport_seglen(skb);
}
/**
* skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS
*
* There are a couple of instances where we have a GSO skb, and we
* want to determine what size it would be after it is segmented.
*
* We might want to check:
* - L3+L4+payload size (e.g. IP forwarding)
* - L2+L3+L4+payload size (e.g. sanity check before passing to driver)
*
* This is a helper to do that correctly considering GSO_BY_FRAGS.
*
* @skb: GSO skb
*
* @seg_len: The segmented length (from skb_gso_*_seglen). In the
* GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS].
*
* @max_len: The maximum permissible length.
*
* Returns true if the segmented length <= max length.
*/
static inline bool skb_gso_size_check(const struct sk_buff *skb,
unsigned int seg_len,
unsigned int max_len) {
const struct skb_shared_info *shinfo = skb_shinfo(skb);
const struct sk_buff *iter;
if (shinfo->gso_size != GSO_BY_FRAGS)
return seg_len <= max_len;
/* Undo this so we can re-use header sizes */
seg_len -= GSO_BY_FRAGS;
skb_walk_frags(skb, iter) {
if (seg_len + skb_headlen(iter) > max_len)
return false;
}
return true;
}
/**
* skb_gso_validate_network_len - Will a split GSO skb fit into a given MTU?
*
* @skb: GSO skb
* @mtu: MTU to validate against
*
* skb_gso_validate_network_len validates if a given skb will fit a
* wanted MTU once split. It considers L3 headers, L4 headers, and the
* payload.
*/
bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu)
{
return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu);
}
EXPORT_SYMBOL_GPL(skb_gso_validate_network_len);
/**
* skb_gso_validate_mac_len - Will a split GSO skb fit in a given length?
*
* @skb: GSO skb
* @len: length to validate against
*
* skb_gso_validate_mac_len validates if a given skb will fit a wanted
* length once split, including L2, L3 and L4 headers and the payload.
*/
bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len)
{
return skb_gso_size_check(skb, skb_gso_mac_seglen(skb), len);
}
EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len);

View File

@ -67,6 +67,7 @@
#include <net/dst.h> #include <net/dst.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/gso.h>
#include <net/ip6_checksum.h> #include <net/ip6_checksum.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/mpls.h> #include <net/mpls.h>
@ -5766,147 +5767,6 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
} }
EXPORT_SYMBOL_GPL(skb_scrub_packet); EXPORT_SYMBOL_GPL(skb_scrub_packet);
/**
* skb_gso_transport_seglen - Return length of individual segments of a gso packet
*
* @skb: GSO skb
*
* skb_gso_transport_seglen is used to determine the real size of the
* individual segments, including Layer4 headers (TCP/UDP).
*
* The MAC/L2 or network (IP, IPv6) headers are not accounted for.
*/
static unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
{
const struct skb_shared_info *shinfo = skb_shinfo(skb);
unsigned int thlen = 0;
if (skb->encapsulation) {
thlen = skb_inner_transport_header(skb) -
skb_transport_header(skb);
if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
thlen += inner_tcp_hdrlen(skb);
} else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
thlen = tcp_hdrlen(skb);
} else if (unlikely(skb_is_gso_sctp(skb))) {
thlen = sizeof(struct sctphdr);
} else if (shinfo->gso_type & SKB_GSO_UDP_L4) {
thlen = sizeof(struct udphdr);
}
/* UFO sets gso_size to the size of the fragmentation
* payload, i.e. the size of the L4 (UDP) header is already
* accounted for.
*/
return thlen + shinfo->gso_size;
}
/**
* skb_gso_network_seglen - Return length of individual segments of a gso packet
*
* @skb: GSO skb
*
* skb_gso_network_seglen is used to determine the real size of the
* individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP).
*
* The MAC/L2 header is not accounted for.
*/
static unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
{
unsigned int hdr_len = skb_transport_header(skb) -
skb_network_header(skb);
return hdr_len + skb_gso_transport_seglen(skb);
}
/**
* skb_gso_mac_seglen - Return length of individual segments of a gso packet
*
* @skb: GSO skb
*
* skb_gso_mac_seglen is used to determine the real size of the
* individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
* headers (TCP/UDP).
*/
static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
{
unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
return hdr_len + skb_gso_transport_seglen(skb);
}
/**
* skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS
*
* There are a couple of instances where we have a GSO skb, and we
* want to determine what size it would be after it is segmented.
*
* We might want to check:
* - L3+L4+payload size (e.g. IP forwarding)
* - L2+L3+L4+payload size (e.g. sanity check before passing to driver)
*
* This is a helper to do that correctly considering GSO_BY_FRAGS.
*
* @skb: GSO skb
*
* @seg_len: The segmented length (from skb_gso_*_seglen). In the
* GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS].
*
* @max_len: The maximum permissible length.
*
* Returns true if the segmented length <= max length.
*/
static inline bool skb_gso_size_check(const struct sk_buff *skb,
unsigned int seg_len,
unsigned int max_len) {
const struct skb_shared_info *shinfo = skb_shinfo(skb);
const struct sk_buff *iter;
if (shinfo->gso_size != GSO_BY_FRAGS)
return seg_len <= max_len;
/* Undo this so we can re-use header sizes */
seg_len -= GSO_BY_FRAGS;
skb_walk_frags(skb, iter) {
if (seg_len + skb_headlen(iter) > max_len)
return false;
}
return true;
}
/**
* skb_gso_validate_network_len - Will a split GSO skb fit into a given MTU?
*
* @skb: GSO skb
* @mtu: MTU to validate against
*
* skb_gso_validate_network_len validates if a given skb will fit a
* wanted MTU once split. It considers L3 headers, L4 headers, and the
* payload.
*/
bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu)
{
return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu);
}
EXPORT_SYMBOL_GPL(skb_gso_validate_network_len);
/**
* skb_gso_validate_mac_len - Will a split GSO skb fit in a given length?
*
* @skb: GSO skb
* @len: length to validate against
*
* skb_gso_validate_mac_len validates if a given skb will fit a wanted
* length once split, including L2, L3 and L4 headers and the payload.
*/
bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len)
{
return skb_gso_size_check(skb, skb_gso_mac_seglen(skb), len);
}
EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len);
static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)
{ {
int mac_len, meta_len; int mac_len, meta_len;

View File

@ -100,6 +100,7 @@
#include <net/ip_fib.h> #include <net/ip_fib.h>
#include <net/inet_connection_sock.h> #include <net/inet_connection_sock.h>
#include <net/gro.h> #include <net/gro.h>
#include <net/gso.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/udp.h> #include <net/udp.h>
#include <net/udplite.h> #include <net/udplite.h>

View File

@ -17,6 +17,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <net/gro.h> #include <net/gro.h>
#include <net/gso.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/esp.h> #include <net/esp.h>

View File

@ -11,6 +11,7 @@
#include <net/protocol.h> #include <net/protocol.h>
#include <net/gre.h> #include <net/gre.h>
#include <net/gro.h> #include <net/gro.h>
#include <net/gso.h>
static struct sk_buff *gre_gso_segment(struct sk_buff *skb, static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
netdev_features_t features) netdev_features_t features)

View File

@ -73,6 +73,7 @@
#include <net/arp.h> #include <net/arp.h>
#include <net/icmp.h> #include <net/icmp.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/gso.h>
#include <net/inetpeer.h> #include <net/inetpeer.h>
#include <net/inet_ecn.h> #include <net/inet_ecn.h>
#include <net/lwtunnel.h> #include <net/lwtunnel.h>

View File

@ -9,6 +9,7 @@
#include <linux/indirect_call_wrapper.h> #include <linux/indirect_call_wrapper.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/gro.h> #include <net/gro.h>
#include <net/gso.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/protocol.h> #include <net/protocol.h>

View File

@ -103,6 +103,7 @@
#include <net/ip_tunnels.h> #include <net/ip_tunnels.h>
#include <net/route.h> #include <net/route.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/gso.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <trace/events/udp.h> #include <trace/events/udp.h>
#include <linux/static_key.h> #include <linux/static_key.h>

View File

@ -8,6 +8,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/gro.h> #include <net/gro.h>
#include <net/gso.h>
#include <net/udp.h> #include <net/udp.h>
#include <net/protocol.h> #include <net/protocol.h>
#include <net/inet_common.h> #include <net/inet_common.h>

View File

@ -17,6 +17,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <net/gro.h> #include <net/gro.h>
#include <net/gso.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/esp.h> #include <net/esp.h>

View File

@ -16,6 +16,7 @@
#include <net/tcp.h> #include <net/tcp.h>
#include <net/udp.h> #include <net/udp.h>
#include <net/gro.h> #include <net/gro.h>
#include <net/gso.h>
#include "ip6_offload.h" #include "ip6_offload.h"

View File

@ -42,6 +42,7 @@
#include <net/sock.h> #include <net/sock.h>
#include <net/snmp.h> #include <net/snmp.h>
#include <net/gso.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/ndisc.h> #include <net/ndisc.h>
#include <net/protocol.h> #include <net/protocol.h>

View File

@ -14,6 +14,7 @@
#include <net/ip6_checksum.h> #include <net/ip6_checksum.h>
#include "ip6_offload.h" #include "ip6_offload.h"
#include <net/gro.h> #include <net/gro.h>
#include <net/gso.h>
static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
netdev_features_t features) netdev_features_t features)

View File

@ -26,6 +26,7 @@
#include <net/codel_impl.h> #include <net/codel_impl.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <net/fq_impl.h> #include <net/fq_impl.h>
#include <net/gso.h>
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "driver-ops.h" #include "driver-ops.h"

View File

@ -12,6 +12,7 @@
#include <linux/nospec.h> #include <linux/nospec.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <net/gso.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/dst.h> #include <net/dst.h>
#include <net/sock.h> #include <net/sock.h>

View File

@ -14,6 +14,7 @@
#include <linux/netdev_features.h> #include <linux/netdev_features.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/gso.h>
#include <net/mpls.h> #include <net/mpls.h>
static struct sk_buff *mpls_gso_segment(struct sk_buff *skb, static struct sk_buff *mpls_gso_segment(struct sk_buff *skb,

View File

@ -8,6 +8,7 @@
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <net/gso.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/ip6_route.h> #include <net/ip6_route.h>

View File

@ -30,6 +30,7 @@
#include <linux/netfilter/nf_conntrack_common.h> #include <linux/netfilter/nf_conntrack_common.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/cgroup-defs.h> #include <linux/cgroup-defs.h>
#include <net/gso.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/tcp_states.h> #include <net/tcp_states.h>
#include <net/netfilter/nf_queue.h> #include <net/netfilter/nf_queue.h>

View File

@ -8,6 +8,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/gso.h>
#include <net/nsh.h> #include <net/nsh.h>
#include <net/tun_proto.h> #include <net/tun_proto.h>

View File

@ -17,6 +17,7 @@
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <net/dst.h> #include <net/dst.h>
#include <net/gso.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/ip6_fib.h> #include <net/ip6_fib.h>

View File

@ -35,6 +35,7 @@
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <net/genetlink.h> #include <net/genetlink.h>
#include <net/gso.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/netns/generic.h> #include <net/netns/generic.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>

View File

@ -16,6 +16,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/act_api.h> #include <net/act_api.h>
#include <net/gso.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include <net/tc_act/tc_police.h> #include <net/tc_act/tc_police.h>

View File

@ -65,6 +65,7 @@
#include <linux/reciprocal_div.h> #include <linux/reciprocal_div.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <net/gso.h>
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include <net/tcp.h> #include <net/tcp.h>

View File

@ -21,6 +21,7 @@
#include <linux/reciprocal_div.h> #include <linux/reciprocal_div.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <net/gso.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
#include <net/inet_ecn.h> #include <net/inet_ecn.h>

View File

@ -20,6 +20,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/time.h> #include <linux/time.h>
#include <net/gso.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>

View File

@ -13,6 +13,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/gso.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/sch_generic.h> #include <net/sch_generic.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>

View File

@ -22,6 +22,7 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/checksum.h> #include <net/sctp/checksum.h>
#include <net/protocol.h> #include <net/protocol.h>
#include <net/gso.h>
static __le32 sctp_gso_make_checksum(struct sk_buff *skb) static __le32 sctp_gso_make_checksum(struct sk_buff *skb)
{ {

View File

@ -15,6 +15,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <net/dst.h> #include <net/dst.h>
#include <net/gso.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <linux/notifier.h> #include <linux/notifier.h>

View File

@ -33,6 +33,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <net/gso.h>
#include <net/icmp.h> #include <net/icmp.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>

View File

@ -13,6 +13,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <net/dst.h> #include <net/dst.h>
#include <net/gso.h>
#include <net/icmp.h> #include <net/icmp.h>
#include <net/inet_ecn.h> #include <net/inet_ecn.h>
#include <net/xfrm.h> #include <net/xfrm.h>