Commit 12de5f0f authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'net-gso-restore-outer-ip-ids-correctly'

Richard Gobert says:

====================
net: gso: restore outer ip ids correctly

GRO currently ignores outer IPv4 header IDs for encapsulated packets
that have their don't-fragment flag set. GSO, however, always assumes
that outer IP IDs are incrementing. This results in GSO mangling the
outer IDs when they aren't incrementing. For example, GSO mangles the
outer IDs of IPv6 packets that were converted to IPv4, which must
have an ID of 0 according to RFC 6145, sect. 5.1.

GRO+GSO is supposed to be entirely transparent by default. GSO already
correctly restores inner IDs and IDs of non-encapsulated packets. The
tx-tcp-mangleid-segmentation feature can be enabled to allow the
mangling of such IDs so that TSO can be used.

This series fixes outer ID restoration for encapsulated packets when
tx-tcp-mangleid-segmentation is disabled. It also allows GRO to merge
packets with fixed IDs that don't have their don't-fragment flag set.

v1: https://lore.kernel.org/netdev/20250814114030.7683-1-richardbgobert@gmail.com/
v2: https://lore.kernel.org/netdev/20250819063223.5239-1-richardbgobert@gmail.com/
v3: https://lore.kernel.org/netdev/20250821073047.2091-1-richardbgobert@gmail.com/
v4: https://lore.kernel.org/netdev/20250901113826.6508-1-richardbgobert@gmail.com/
v5: https://lore.kernel.org/netdev/20250915113933.3293-1-richardbgobert@gmail.com/
v6: https://lore.kernel.org/netdev/20250916144841.4884-1-richardbgobert@gmail.com/
v7: https://lore.kernel.org/netdev/20250922084103.4764-1-richardbgobert@gmail.com/
====================

Link: https://patch.msgid.link/20250923085908.4687-1-richardbgobert@gmail.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents bb6a2265 5e9ff937
Loading
Loading
Loading
Loading
+14 −8
Original line number Diff line number Diff line
@@ -43,10 +43,19 @@ also point to the TCP header of the packet.
For IPv4 segmentation we support one of two types in terms of the IP ID.
The default behavior is to increment the IP ID with every segment.  If the
GSO type SKB_GSO_TCP_FIXEDID is specified then we will not increment the IP
ID and all segments will use the same IP ID.  If a device has
NETIF_F_TSO_MANGLEID set then the IP ID can be ignored when performing TSO
and we will either increment the IP ID for all frames, or leave it at a
static value based on driver preference.
ID and all segments will use the same IP ID.

For encapsulated packets, SKB_GSO_TCP_FIXEDID refers only to the outer header.
SKB_GSO_TCP_FIXEDID_INNER can be used to specify the same for the inner header.
Any combination of these two GSO types is allowed.

If a device has NETIF_F_TSO_MANGLEID set then the IP ID can be ignored when
performing TSO and we will either increment the IP ID for all frames, or leave
it at a static value based on driver preference.  For encapsulated packets,
NETIF_F_TSO_MANGLEID is relevant for both outer and inner headers, unless the
DF bit is not set on the outer header, in which case the device driver must
guarantee that the IP ID field is incremented in the outer header with every
segment.


UDP Fragmentation Offload
@@ -124,10 +133,7 @@ Generic Receive Offload
Generic receive offload is the complement to GSO.  Ideally any frame
assembled by GRO should be segmented to create an identical sequence of
frames using GSO, and any sequence of frames segmented by GSO should be
able to be reassembled back to the original by GRO.  The only exception to
this is IPv4 ID in the case that the DF bit is set for a given IP header.
If the value of the IPv4 ID is not sequentially incrementing it will be
altered so that it is when a frame assembled via GRO is segmented via GSO.
able to be reassembled back to the original by GRO.


Partial Generic Segmentation Offload
+6 −2
Original line number Diff line number Diff line
@@ -1290,8 +1290,12 @@ static void mlx5e_shampo_update_ipv4_tcp_hdr(struct mlx5e_rq *rq, struct iphdr *
	tcp->check = ~tcp_v4_check(skb->len - tcp_off, ipv4->saddr,
				   ipv4->daddr, 0);
	skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
	if (ntohs(ipv4->id) == rq->hw_gro_data->second_ip_id)
		skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_FIXEDID;
	if (ntohs(ipv4->id) == rq->hw_gro_data->second_ip_id) {
		bool encap = rq->hw_gro_data->fk.control.flags & FLOW_DIS_ENCAPSULATION;

		skb_shinfo(skb)->gso_type |= encap ? SKB_GSO_TCP_FIXEDID_INNER :
						     SKB_GSO_TCP_FIXEDID;
	}

	skb->csum_start = (unsigned char *)tcp - skb->head;
	skb->csum_offset = offsetof(struct tcphdr, check);
+13 −4
Original line number Diff line number Diff line
@@ -189,6 +189,7 @@ static void ef100_make_tso_desc(struct efx_nic *efx,
{
	bool gso_partial = skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL;
	unsigned int len, ip_offset, tcp_offset, payload_segs;
	u32 mangleid_outer = ESE_GZ_TX_DESC_IP4_ID_INC_MOD16;
	u32 mangleid = ESE_GZ_TX_DESC_IP4_ID_INC_MOD16;
	unsigned int outer_ip_offset, outer_l4_offset;
	u16 vlan_tci = skb_vlan_tag_get(skb);
@@ -200,8 +201,17 @@ static void ef100_make_tso_desc(struct efx_nic *efx,
	bool outer_csum;
	u32 paylen;

	if (encap) {
		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID_INNER)
			mangleid = ESE_GZ_TX_DESC_IP4_ID_NO_OP;
		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID)
			mangleid_outer = ESE_GZ_TX_DESC_IP4_ID_NO_OP;
	} else {
		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID)
			mangleid = ESE_GZ_TX_DESC_IP4_ID_NO_OP;
		mangleid_outer = ESE_GZ_TX_DESC_IP4_ID_NO_OP;
	}

	if (efx->net_dev->features & NETIF_F_HW_VLAN_CTAG_TX)
		vlan_enable = skb_vlan_tag_present(skb);

@@ -245,8 +255,7 @@ static void ef100_make_tso_desc(struct efx_nic *efx,
			      ESF_GZ_TX_TSO_OUTER_L4_OFF_W, outer_l4_offset >> 1,
			      ESF_GZ_TX_TSO_ED_OUTER_UDP_LEN, udp_encap && !gso_partial,
			      ESF_GZ_TX_TSO_ED_OUTER_IP_LEN, encap && !gso_partial,
			      ESF_GZ_TX_TSO_ED_OUTER_IP4_ID, encap ? mangleid :
								     ESE_GZ_TX_DESC_IP4_ID_NO_OP,
			      ESF_GZ_TX_TSO_ED_OUTER_IP4_ID, mangleid_outer,
			      ESF_GZ_TX_TSO_VLAN_INSERT_EN, vlan_enable,
			      ESF_GZ_TX_TSO_VLAN_INSERT_TCI, vlan_tci
		);
+7 −2
Original line number Diff line number Diff line
@@ -5320,13 +5320,18 @@ void skb_warn_bad_offload(const struct sk_buff *skb);

static inline bool net_gso_ok(netdev_features_t features, int gso_type)
{
	netdev_features_t feature = (netdev_features_t)gso_type << NETIF_F_GSO_SHIFT;
	netdev_features_t feature;

	if (gso_type & (SKB_GSO_TCP_FIXEDID | SKB_GSO_TCP_FIXEDID_INNER))
		gso_type |= __SKB_GSO_TCP_FIXEDID;

	feature = ((netdev_features_t)gso_type << NETIF_F_GSO_SHIFT) & NETIF_F_GSO_MASK;

	/* check flags correspondence */
	BUILD_BUG_ON(SKB_GSO_TCPV4   != (NETIF_F_TSO >> NETIF_F_GSO_SHIFT));
	BUILD_BUG_ON(SKB_GSO_DODGY   != (NETIF_F_GSO_ROBUST >> NETIF_F_GSO_SHIFT));
	BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT));
	BUILD_BUG_ON(SKB_GSO_TCP_FIXEDID != (NETIF_F_TSO_MANGLEID >> NETIF_F_GSO_SHIFT));
	BUILD_BUG_ON(__SKB_GSO_TCP_FIXEDID != (NETIF_F_TSO_MANGLEID >> NETIF_F_GSO_SHIFT));
	BUILD_BUG_ON(SKB_GSO_TCPV6   != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT));
	BUILD_BUG_ON(SKB_GSO_FCOE    != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT));
	BUILD_BUG_ON(SKB_GSO_GRE     != (NETIF_F_GSO_GRE >> NETIF_F_GSO_SHIFT));
+7 −1
Original line number Diff line number Diff line
@@ -674,7 +674,7 @@ enum {
	/* This indicates the tcp segment has CWR set. */
	SKB_GSO_TCP_ECN = 1 << 2,

	SKB_GSO_TCP_FIXEDID = 1 << 3,
	__SKB_GSO_TCP_FIXEDID = 1 << 3,

	SKB_GSO_TCPV6 = 1 << 4,

@@ -707,6 +707,12 @@ enum {
	SKB_GSO_FRAGLIST = 1 << 18,

	SKB_GSO_TCP_ACCECN = 1 << 19,

	/* These indirectly map onto the same netdev feature.
	 * If NETIF_F_TSO_MANGLEID is set it may mangle both inner and outer IDs.
	 */
	SKB_GSO_TCP_FIXEDID = 1 << 30,
	SKB_GSO_TCP_FIXEDID_INNER = 1 << 31,
};

#if BITS_PER_LONG > 32
Loading