mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
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:
parent
cabb8b48e5
commit
d457a0e329
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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>
|
||||||
|
@ -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"
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
109
include/net/gso.h
Normal 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 */
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
273
net/core/gso.c
Normal 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);
|
||||||
|
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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>
|
||||||
|
@ -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,
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user