diff mbox series

[ovs-dev,v4,1/4] netdev-linux: Favour inner packet for multi-encapsulated TSO.

Message ID 20240215225305.408579-1-mkp@redhat.com
State Accepted
Commit cb0cbffbe8fb949a0dc7f1d14782655aae566d61
Headers show
Series [ovs-dev,v4,1/4] netdev-linux: Favour inner packet for multi-encapsulated TSO. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/intel-ovs-compilation success test: success

Commit Message

Mike Pattrick Feb. 15, 2024, 10:53 p.m. UTC
Previously if an OVS configuration nested multiple layers of UDP tunnels
like VXLAN or GENEVE on top of each other through netdev-linux
interfaces, the vnet header would be incorrectly set to the outermost
UDP tunnel layer instead of the intermediary tunnel layer.

This resulted in the middle UDP tunnel not checksum offloading properly.

Fixes: 85bcbbed839a ("userspace: Enable tunnel tests with TSO.")
Reported-by: David Marchand <david.marchand@redhat.com>
Signed-off-by: Mike Pattrick <mkp@redhat.com>
---
nb: The first patch was removed from the v2 version of this series,
which was not explicitly a bug fix.
---
 lib/netdev-linux.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 00df7f634..8964cd670 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -7247,14 +7247,23 @@  netdev_linux_prepend_vnet_hdr(struct dp_packet *b, int mtu)
             vnet->csum_offset = (OVS_FORCE __virtio16) __builtin_offsetof(
                                     struct tcp_header, tcp_csum);
         } else if (dp_packet_hwol_l4_is_udp(b)) {
-            struct udp_header *udp_hdr = dp_packet_l4(b);
+            /* Favour the inner packet when indicating checksum offsets. */
+            void *l3_off = dp_packet_inner_l3(b);
+            void *l4_off = dp_packet_inner_l4(b);
+
+            if (!l3_off || !l4_off) {
+                l3_off = dp_packet_l3(b);
+                l4_off = dp_packet_l4(b);
+            }
+            struct udp_header *udp_hdr = l4_off;
+
             ovs_be16 csum = 0;
 
             if (dp_packet_hwol_is_ipv4(b)) {
-                const struct ip_header *ip_hdr = dp_packet_l3(b);
+                const struct ip_header *ip_hdr = l3_off;
                 csum = ~csum_finish(packet_csum_pseudoheader(ip_hdr));
             } else if (dp_packet_hwol_tx_ipv6(b)) {
-                const struct ovs_16aligned_ip6_hdr *ip6_hdr = dp_packet_l3(b);
+                const struct ovs_16aligned_ip6_hdr *ip6_hdr = l4_off;
                 csum = ~csum_finish(packet_csum_pseudoheader6(ip6_hdr));
             }