net: move gso declarations and functions to their own files
authorEric Dumazet <edumazet@google.com>
Thu, 8 Jun 2023 19:17:37 +0000 (19:17 +0000)
committerJakub Kicinski <kuba@kernel.org>
Sat, 10 Jun 2023 07:11:41 +0000 (00:11 -0700)
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>
46 files changed:
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/ethernet/sfc/siena/tx_common.c
drivers/net/ethernet/sfc/tx_common.c
drivers/net/tap.c
drivers/net/usb/r8152.c
drivers/net/wireguard/device.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
include/linux/netdevice.h
include/linux/skbuff.h
include/net/gro.h
include/net/gso.h [new file with mode: 0644]
include/net/udp.h
net/core/Makefile
net/core/dev.c
net/core/gro.c
net/core/gso.c [new file with mode: 0644]
net/core/skbuff.c
net/ipv4/af_inet.c
net/ipv4/esp4_offload.c
net/ipv4/gre_offload.c
net/ipv4/ip_output.c
net/ipv4/tcp_offload.c
net/ipv4/udp.c
net/ipv4/udp_offload.c
net/ipv6/esp6_offload.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_output.c
net/ipv6/udp_offload.c
net/mac80211/tx.c
net/mpls/af_mpls.c
net/mpls/mpls_gso.c
net/netfilter/nf_flow_table_ip.c
net/netfilter/nfnetlink_queue.c
net/nsh/nsh.c
net/openvswitch/actions.c
net/openvswitch/datapath.c
net/sched/act_police.c
net/sched/sch_cake.c
net/sched/sch_netem.c
net/sched/sch_taprio.c
net/sched/sch_tbf.c
net/sctp/offload.c
net/xfrm/xfrm_device.c
net/xfrm/xfrm_interface_core.c
net/xfrm/xfrm_output.c

index 5874729..5e68a6a 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/crc32poly.h>
 
 #include <net/checksum.h>
+#include <net/gso.h>
 #include <net/ip.h>
 
 #include <linux/io.h>
index c5687d9..7b7e1c5 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/slab.h>
 #include <linux/prefetch.h>
 #include <net/checksum.h>
+#include <net/gso.h>
 #include <net/ip.h>
 #include <net/tcp.h>
 #include <asm/byteorder.h>
index 93a32d6..a7a9ab3 100644 (file)
@@ -12,6 +12,7 @@
 #include "efx.h"
 #include "nic_common.h"
 #include "tx_common.h"
+#include <net/gso.h>
 
 static unsigned int efx_tx_cb_page_count(struct efx_tx_queue *tx_queue)
 {
index 67e789b..4ce7d00 100644 (file)
@@ -12,6 +12,7 @@
 #include "efx.h"
 #include "nic_common.h"
 #include "tx_common.h"
+#include <net/gso.h>
 
 static unsigned int efx_tx_cb_page_count(struct efx_tx_queue *tx_queue)
 {
index d30d730..9137fb8 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/fs.h>
 #include <linux/uio.h>
 
+#include <net/gso.h>
 #include <net/net_namespace.h>
 #include <net/rtnetlink.h>
 #include <net/sock.h>
index 0999a58..0738baa 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/firmware.h>
 #include <crypto/hash.h>
 #include <linux/usb/r8152.h>
+#include <net/gso.h>
 
 /* Information for net-next */
 #define NETNEXT_VERSION                "12"
index d58e9f8..258dcc1 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/icmp.h>
 #include <linux/suspend.h>
 #include <net/dst_metadata.h>
+#include <net/gso.h>
 #include <net/icmp.h>
 #include <net/rtnetlink.h>
 #include <net/ip_tunnels.h>
index 5fa6f98..ef0f53b 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/ieee80211.h>
 #include <linux/etherdevice.h>
 #include <linux/tcp.h>
+#include <net/gso.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 
index c2f0c60..2d6cb2b 100644 (file)
@@ -4827,13 +4827,6 @@ int skb_crc32c_csum_help(struct sk_buff *skb);
 int skb_csum_hwoffload_help(struct sk_buff *skb,
                            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 {
        ifslave slave;
        ifbond  master;
@@ -4856,11 +4849,6 @@ static inline void ethtool_notify(struct net_device *dev, unsigned int cmd,
 }
 #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);
 
 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,
                                          netdev_features_t features);
 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)
 {
@@ -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,
                           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)
 {
        return dev->priv_flags & IFF_MACSEC;
index e2f48dd..91ed669 100644 (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);
 int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
 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_list(struct sk_buff *skb, netdev_features_t features,
                                 unsigned int offset);
@@ -4841,75 +4839,6 @@ static inline struct sec_path *skb_sec_path(const struct sk_buff *skb)
 #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)
 {
        return skb_shinfo(skb)->gso_size;
index 7b47dd6..75efa6f 100644 (file)
@@ -452,5 +452,6 @@ static inline void gro_normal_one(struct napi_struct *napi, struct sk_buff *skb,
                gro_normal_list(napi);
 }
 
+extern struct list_head offload_base;
 
 #endif /* _NET_IPV6_GRO_H */
diff --git a/include/net/gso.h b/include/net/gso.h
new file mode 100644 (file)
index 0000000..2997544
--- /dev/null
@@ -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 */
index 4ed0b47..e01340a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/list.h>
 #include <linux/bug.h>
 #include <net/inet_sock.h>
+#include <net/gso.h>
 #include <net/sock.h>
 #include <net/snmp.h>
 #include <net/ip.h>
index 8f36781..731db2e 100644 (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 \
                        sock_diag.o dev_ioctl.o tso.o sock_reuseport.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
 
index 6d6f8a7..c2456b3 100644 (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;
 }
 
-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;
        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);
 }
 
-/* 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. */
 #ifdef CONFIG_BUG
index 4d45f78..dca8000 100644 (file)
@@ -10,7 +10,7 @@
 #define GRO_MAX_HEAD (MAX_HEADER + 128)
 
 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 */
 int gro_normal_batch __read_mostly = 8;
 
@@ -92,63 +92,6 @@ void dev_remove_offload(struct packet_offload *po)
 }
 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)
 {
diff --git a/net/core/gso.c b/net/core/gso.c
new file mode 100644 (file)
index 0000000..9e1803b
--- /dev/null
@@ -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);
+
index 7c43382..fee2b1c 100644 (file)
@@ -67,6 +67,7 @@
 #include <net/dst.h>
 #include <net/sock.h>
 #include <net/checksum.h>
+#include <net/gso.h>
 #include <net/ip6_checksum.h>
 #include <net/xfrm.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);
 
-/**
- * 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)
 {
        int mac_len, meta_len;
index fd233c4..0e16ac8 100644 (file)
 #include <net/ip_fib.h>
 #include <net/inet_connection_sock.h>
 #include <net/gro.h>
+#include <net/gso.h>
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <net/udplite.h>
index 3969fa8..12c5fb3 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <net/gro.h>
+#include <net/gso.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/esp.h>
index 2b9cb53..311e70b 100644 (file)
@@ -11,6 +11,7 @@
 #include <net/protocol.h>
 #include <net/gre.h>
 #include <net/gro.h>
+#include <net/gso.h>
 
 static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
                                       netdev_features_t features)
index 244fb93..457598d 100644 (file)
@@ -73,6 +73,7 @@
 #include <net/arp.h>
 #include <net/icmp.h>
 #include <net/checksum.h>
+#include <net/gso.h>
 #include <net/inetpeer.h>
 #include <net/inet_ecn.h>
 #include <net/lwtunnel.h>
index 05b38f5..8311c38 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/indirect_call_wrapper.h>
 #include <linux/skbuff.h>
 #include <net/gro.h>
+#include <net/gso.h>
 #include <net/tcp.h>
 #include <net/protocol.h>
 
index df5e407..7e0542c 100644 (file)
 #include <net/ip_tunnels.h>
 #include <net/route.h>
 #include <net/checksum.h>
+#include <net/gso.h>
 #include <net/xfrm.h>
 #include <trace/events/udp.h>
 #include <linux/static_key.h>
index 1f01e15..75aa4de 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/skbuff.h>
 #include <net/gro.h>
+#include <net/gso.h>
 #include <net/udp.h>
 #include <net/protocol.h>
 #include <net/inet_common.h>
index 75c0299..b33c7de 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <net/gro.h>
+#include <net/gso.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/esp.h>
index 00dc2e3..d631428 100644 (file)
@@ -16,6 +16,7 @@
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <net/gro.h>
+#include <net/gso.h>
 
 #include "ip6_offload.h"
 
index c722cb8..c06ff75 100644 (file)
@@ -42,6 +42,7 @@
 #include <net/sock.h>
 #include <net/snmp.h>
 
+#include <net/gso.h>
 #include <net/ipv6.h>
 #include <net/ndisc.h>
 #include <net/protocol.h>
index c39c1e3..ad3b872 100644 (file)
@@ -14,6 +14,7 @@
 #include <net/ip6_checksum.h>
 #include "ip6_offload.h"
 #include <net/gro.h>
+#include <net/gso.h>
 
 static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                                         netdev_features_t features)
index 148a0e2..cfbe4be 100644 (file)
@@ -26,6 +26,7 @@
 #include <net/codel_impl.h>
 #include <asm/unaligned.h>
 #include <net/fq_impl.h>
+#include <net/gso.h>
 
 #include "ieee80211_i.h"
 #include "driver-ops.h"
index dc5165d..bf6e81d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/nospec.h>
 #include <linux/vmalloc.h>
 #include <linux/percpu.h>
+#include <net/gso.h>
 #include <net/ip.h>
 #include <net/dst.h>
 #include <net/sock.h>
index 1482259..533d082 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/netdev_features.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <net/gso.h>
 #include <net/mpls.h>
 
 static struct sk_buff *mpls_gso_segment(struct sk_buff *skb,
index d248763..d885d34 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/ipv6.h>
 #include <linux/netdevice.h>
 #include <linux/if_ether.h>
+#include <net/gso.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
index e311462..556bc90 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/netfilter/nf_conntrack_common.h>
 #include <linux/list.h>
 #include <linux/cgroup-defs.h>
+#include <net/gso.h>
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <net/netfilter/nf_queue.h>
index 0f23e5e..f4a38bd 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <net/gso.h>
 #include <net/nsh.h>
 #include <net/tun_proto.h>
 
index a8cf9a8..8074ea0 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/if_vlan.h>
 
 #include <net/dst.h>
+#include <net/gso.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/ip6_fib.h>
index 58f530f..a6d2a0b 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/rculist.h>
 #include <linux/dmi.h>
 #include <net/genetlink.h>
+#include <net/gso.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 #include <net/pkt_cls.h>
index 2e9dce0..f3121c5 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <net/act_api.h>
+#include <net/gso.h>
 #include <net/netlink.h>
 #include <net/pkt_cls.h>
 #include <net/tc_act/tc_police.h>
index 891e007..9cff995 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/reciprocal_div.h>
 #include <net/netlink.h>
 #include <linux/if_vlan.h>
+#include <net/gso.h>
 #include <net/pkt_sched.h>
 #include <net/pkt_cls.h>
 #include <net/tcp.h>
index 6ef3021..0c9e93d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/reciprocal_div.h>
 #include <linux/rbtree.h>
 
+#include <net/gso.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/inet_ecn.h>
index 5076da1..4a4e6ff 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
 #include <linux/time.h>
+#include <net/gso.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/pkt_cls.h>
index 277ad11..17d2d00 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/skbuff.h>
+#include <net/gso.h>
 #include <net/netlink.h>
 #include <net/sch_generic.h>
 #include <net/pkt_cls.h>
index eb874e3..5020951 100644 (file)
@@ -22,6 +22,7 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/checksum.h>
 #include <net/protocol.h>
+#include <net/gso.h>
 
 static __le32 sctp_gso_make_checksum(struct sk_buff *skb)
 {
index 408f5e5..533697e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <net/dst.h>
+#include <net/gso.h>
 #include <net/xfrm.h>
 #include <linux/notifier.h>
 
index 1f99dc4..0ee864a 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/uaccess.h>
 #include <linux/atomic.h>
 
+#include <net/gso.h>
 #include <net/icmp.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
index 369e5de..662c83b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <net/dst.h>
+#include <net/gso.h>
 #include <net/icmp.h>
 #include <net/inet_ecn.h>
 #include <net/xfrm.h>