From f8da64e60e9f536b62a82a415f04b277a35b3224 Mon Sep 17 00:00:00 2001 From: Mohsin Kazmi Date: Thu, 22 May 2025 19:34:42 +0000 Subject: [PATCH] ip: compute checksums before fragmentation if offloaded Type: fix When a packet with checksum offloading enabled is fragmented into multiple IP fragments, due to the egress interface's MTU being smaller than the original packet size, it gets dropped after reassembly because the reconstructed packet contains an invalid checksum. This patch addresses the issue by computing the checksum in the IP fragmentation logic before the packet is fragmented, ensuring the resulting fragments carry a valid checksum upon reassembly. Signed-off-by: Mohsin Kazmi Change-Id: I202f169887ae9594f9580a4c7901d7b4483ef5f9 --- src/vnet/ip/ip_frag.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/vnet/ip/ip_frag.c b/src/vnet/ip/ip_frag.c index 934e40a5d18..729aa677d48 100644 --- a/src/vnet/ip/ip_frag.c +++ b/src/vnet/ip/ip_frag.c @@ -22,6 +22,7 @@ #include "ip_frag.h" #include +#include typedef struct { @@ -99,6 +100,14 @@ ip4_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u16 mtu, u8 *org_from_packet, more; from_b = vlib_get_buffer (vm, from_bi); + + if (from_b->flags & VNET_BUFFER_F_OFFLOAD) + { + ASSERT ((from_b->flags & VNET_BUFFER_F_GSO) == 0); + vnet_calc_checksums_inline (vm, from_b, 1 /* is_v4 */, 0 /* is_v6 */); + vnet_calc_outer_checksums_inline (vm, from_b); + } + org_from_packet = vlib_buffer_get_current (from_b); ip4 = vlib_buffer_get_current (from_b) + l2unfragmentablesize; @@ -172,15 +181,6 @@ ip4_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u16 mtu, vlib_buffer_copy_trace_flag (vm, from_b, to_bi); to_b->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID; - if (from_b->flags & VNET_BUFFER_F_L4_HDR_OFFSET_VALID) - { - vnet_buffer (to_b)->l4_hdr_offset = - (vnet_buffer (to_b)->l3_hdr_offset + - (vnet_buffer (from_b)->l4_hdr_offset - - vnet_buffer (from_b)->l3_hdr_offset)); - to_b->flags |= VNET_BUFFER_F_L4_HDR_OFFSET_VALID; - } - /* Spin through from buffers filling up the to buffer */ u16 left_in_to_buffer = len, to_ptr = 0; while (1) @@ -221,9 +221,6 @@ ip4_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u16 mtu, to_ip4->length = clib_host_to_net_u16 (len + sizeof (ip4_header_t)); to_ip4->checksum = ip4_header_checksum (to_ip4); - /* we've just done the IP checksum .. */ - vnet_buffer_offload_flags_clear (to_b, VNET_BUFFER_OFFLOAD_F_IP_CKSUM); - rem -= len; fo += len; } @@ -385,6 +382,14 @@ ip6_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u16 mtu, u16 head_bytes; from_b = vlib_get_buffer (vm, from_bi); + + if (from_b->flags & VNET_BUFFER_F_OFFLOAD) + { + ASSERT ((from_b->flags & VNET_BUFFER_F_GSO) == 0); + vnet_calc_checksums_inline (vm, from_b, 0 /* is_v4 */, 1 /* is_v6 */); + vnet_calc_outer_checksums_inline (vm, from_b); + } + org_from_packet = vlib_buffer_get_current (from_b); ip6 = vlib_buffer_get_current (from_b) + l2unfragmentablesize; @@ -443,15 +448,6 @@ ip6_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u16 mtu, vnet_buffer (to_b)->l3_hdr_offset = to_b->current_data; to_b->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID; - - if (from_b->flags & VNET_BUFFER_F_L4_HDR_OFFSET_VALID) - { - vnet_buffer (to_b)->l4_hdr_offset = - (vnet_buffer (to_b)->l3_hdr_offset + - (vnet_buffer (from_b)->l4_hdr_offset - - vnet_buffer (from_b)->l3_hdr_offset)); - to_b->flags |= VNET_BUFFER_F_L4_HDR_OFFSET_VALID; - } to_b->flags |= VNET_BUFFER_F_IS_IP6; /* Spin through from buffers filling up the to buffer */ -- 2.16.6