From 698eb87a8eed847fe555ef327bcc99a4467ed59a Mon Sep 17 00:00:00 2001 From: Vladimir Isaev Date: Thu, 21 May 2020 16:34:17 +0300 Subject: vxlan: Fixed checksum caclculation offset VXLAN uses csum_offload for IPv6 packets. But without gso node we have csum calculated only for inner packet. This patch adds support for outer header csum calculation. Checksum for inner packet should be calculated before interface-output node (for example in vxlan node). Type: fix Signed-off-by: Mohsin Kazmi Signed-off-by: Vladimir Isaev Change-Id: Ica68429ede4426293769207cd83c791ebe72fe56 --- src/vnet/gso/hdr_offset_parser.h | 2 +- src/vnet/interface_output.c | 10 ++++---- src/vnet/interface_output.h | 54 +++++++++------------------------------- src/vnet/ip/ip4_forward.c | 12 +++------ src/vnet/ip/ip6_forward.c | 9 +++---- src/vnet/pg/input.c | 29 +++++++++++++-------- 6 files changed, 44 insertions(+), 72 deletions(-) (limited to 'src/vnet') diff --git a/src/vnet/gso/hdr_offset_parser.h b/src/vnet/gso/hdr_offset_parser.h index b194333e780..8fa5cad56d1 100644 --- a/src/vnet/gso/hdr_offset_parser.h +++ b/src/vnet/gso/hdr_offset_parser.h @@ -376,7 +376,7 @@ vnet_generic_outer_header_parser_inline (vlib_buffer_t * b0, u16 ethertype = 0; u16 l2hdr_sz = 0; - ASSERT (is_ip4 ^ is_ip6); + ASSERT (!(is_ip4 && is_ip6)); if (is_l2) { diff --git a/src/vnet/interface_output.c b/src/vnet/interface_output.c index 8e3d53ab76f..f9490f34f6a 100644 --- a/src/vnet/interface_output.c +++ b/src/vnet/interface_output.c @@ -344,22 +344,22 @@ vnet_interface_output_node_inline (vlib_main_t * vm, vnet_calc_checksums_inline (vm, b[0], b[0]->flags & VNET_BUFFER_F_IS_IP4, - b[0]->flags & VNET_BUFFER_F_IS_IP6, 1 /* with gso */ ); + b[0]->flags & VNET_BUFFER_F_IS_IP6); if (b[1]->flags & vnet_buffer_offload_flags) vnet_calc_checksums_inline (vm, b[1], b[1]->flags & VNET_BUFFER_F_IS_IP4, - b[1]->flags & VNET_BUFFER_F_IS_IP6, 1 /* with gso */ ); + b[1]->flags & VNET_BUFFER_F_IS_IP6); if (b[2]->flags & vnet_buffer_offload_flags) vnet_calc_checksums_inline (vm, b[2], b[2]->flags & VNET_BUFFER_F_IS_IP4, - b[2]->flags & VNET_BUFFER_F_IS_IP6, 1 /* with gso */ ); + b[2]->flags & VNET_BUFFER_F_IS_IP6); if (b[3]->flags & vnet_buffer_offload_flags) vnet_calc_checksums_inline (vm, b[3], b[3]->flags & VNET_BUFFER_F_IS_IP4, - b[3]->flags & VNET_BUFFER_F_IS_IP6, 1 /* with gso */ ); + b[3]->flags & VNET_BUFFER_F_IS_IP6); } } b += 4; @@ -410,7 +410,7 @@ vnet_interface_output_node_inline (vlib_main_t * vm, vnet_calc_checksums_inline (vm, b[0], b[0]->flags & VNET_BUFFER_F_IS_IP4, - b[0]->flags & VNET_BUFFER_F_IS_IP6, 1 /* with gso */ ); + b[0]->flags & VNET_BUFFER_F_IS_IP6); } b += 1; } diff --git a/src/vnet/interface_output.h b/src/vnet/interface_output.h index c408fca9ca9..4b082b314ad 100644 --- a/src/vnet/interface_output.h +++ b/src/vnet/interface_output.h @@ -82,59 +82,29 @@ vnet_calc_ip6_checksums (vlib_main_t * vm, vlib_buffer_t * b, static_always_inline void vnet_calc_checksums_inline (vlib_main_t * vm, vlib_buffer_t * b, - int is_ip4, int is_ip6, int with_gso) + int is_ip4, int is_ip6) { ip4_header_t *ip4; ip6_header_t *ip6; tcp_header_t *th; udp_header_t *uh; - if (with_gso) - { - generic_header_offset_t gho = { 0 }; - vnet_generic_header_offset_parser (b, &gho, 1 /* l2 */ , is_ip4, - is_ip6); - - ASSERT (gho.gho_flags ^ (GHO_F_IP4 | GHO_F_IP6)); - - vnet_get_inner_header (b, &gho); - - ip4 = (ip4_header_t *) - (vlib_buffer_get_current (b) + gho.l3_hdr_offset); - ip6 = (ip6_header_t *) - (vlib_buffer_get_current (b) + gho.l3_hdr_offset); - th = (tcp_header_t *) (vlib_buffer_get_current (b) + gho.l4_hdr_offset); - uh = (udp_header_t *) (vlib_buffer_get_current (b) + gho.l4_hdr_offset); + ASSERT (!(is_ip4 && is_ip6)); - if (gho.gho_flags & GHO_F_IP4) - { - vnet_calc_ip4_checksums (vm, b, ip4, th, uh); - } - else if (gho.gho_flags & GHO_F_IP6) - { - vnet_calc_ip6_checksums (vm, b, ip6, th, uh); - } + ip4 = (ip4_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset); + ip6 = (ip6_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset); + th = (tcp_header_t *) (b->data + vnet_buffer (b)->l4_hdr_offset); + uh = (udp_header_t *) (b->data + vnet_buffer (b)->l4_hdr_offset); - vnet_get_outer_header (b, &gho); + if (is_ip4) + { + vnet_calc_ip4_checksums (vm, b, ip4, th, uh); } - else + else if (is_ip6) { - ASSERT (!(is_ip4 && is_ip6)); - - ip4 = (ip4_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset); - ip6 = (ip6_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset); - th = (tcp_header_t *) (b->data + vnet_buffer (b)->l4_hdr_offset); - uh = (udp_header_t *) (b->data + vnet_buffer (b)->l4_hdr_offset); - - if (is_ip4) - { - vnet_calc_ip4_checksums (vm, b, ip4, th, uh); - } - if (is_ip6) - { - vnet_calc_ip6_checksums (vm, b, ip6, th, uh); - } + vnet_calc_ip6_checksums (vm, b, ip6, th, uh); } + b->flags &= ~VNET_BUFFER_F_OFFLOAD_TCP_CKSUM; b->flags &= ~VNET_BUFFER_F_OFFLOAD_UDP_CKSUM; b->flags &= ~VNET_BUFFER_F_OFFLOAD_IP_CKSUM; diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index b76da0a248b..0fa9da22c93 100644 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -2241,8 +2241,7 @@ ip4_rewrite_inline_with_gso (vlib_main_t * vm, next[0] = next_index; if (is_midchain) vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ , - 0 /* is_ip6 */ , - 0 /* with gso */ ); + 0 /* is_ip6 */ ); } else { @@ -2267,8 +2266,7 @@ ip4_rewrite_inline_with_gso (vlib_main_t * vm, next[1] = next_index; if (is_midchain) vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ , - 0 /* is_ip6 */ , - 0 /* with gso */ ); + 0 /* is_ip6 */ ); } else { @@ -2419,8 +2417,7 @@ ip4_rewrite_inline_with_gso (vlib_main_t * vm, if (is_midchain) { vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ , - 0 /* is_ip6 */ , - 0 /* with gso */ ); + 0 /* is_ip6 */ ); /* Guess we are only writing on ipv4 header. */ vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t)); @@ -2527,8 +2524,7 @@ ip4_rewrite_inline_with_gso (vlib_main_t * vm, { /* this acts on the packet that is about to be encapped */ vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ , - 0 /* is_ip6 */ , - 0 /* with gso */ ); + 0 /* is_ip6 */ ); /* Guess we are only writing on ipv4 header. */ vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t)); diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index e4d8fc0ea88..d6ef8c842e7 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -1936,11 +1936,9 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, /* before we paint on the next header, update the L4 * checksums if required, since there's no offload on a tunnel */ vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ , - 1 /* is_ip6 */ , - 0 /* with gso */ ); + 1 /* is_ip6 */ ); vnet_calc_checksums_inline (vm, p1, 0 /* is_ip4 */ , - 1 /* is_ip6 */ , - 0 /* with gso */ ); + 1 /* is_ip6 */ ); /* Guess we are only writing on ipv6 header. */ vnet_rewrite_two_headers (adj0[0], adj1[0], @@ -2036,8 +2034,7 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, if (is_midchain) { vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ , - 1 /* is_ip6 */ , - 0 /* with gso */ ); + 1 /* is_ip6 */ ); /* Guess we are only writing on ip6 header. */ vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip6_header_t)); diff --git a/src/vnet/pg/input.c b/src/vnet/pg/input.c index 8ba3b361894..483add0b5f3 100644 --- a/src/vnet/pg/input.c +++ b/src/vnet/pg/input.c @@ -1530,10 +1530,9 @@ pg_input_trace (pg_main_t * pg, } static_always_inline void -fill_gso_buffer_flags (vlib_main_t * vm, u32 * buffers, u32 n_buffers, - u32 packet_data_size) +fill_buffer_offload_flags (vlib_main_t * vm, u32 * buffers, u32 n_buffers, + int gso_enabled, u32 gso_size) { - for (int i = 0; i < n_buffers; i++) { vlib_buffer_t *b0 = vlib_get_buffer (vm, buffers[i]); @@ -1586,16 +1585,21 @@ fill_gso_buffer_flags (vlib_main_t * vm, u32 * buffers, u32 n_buffers, VNET_BUFFER_F_L3_HDR_OFFSET_VALID | VNET_BUFFER_F_L4_HDR_OFFSET_VALID); } + if (l4_proto == IP_PROTOCOL_TCP) { - b0->flags |= (VNET_BUFFER_F_OFFLOAD_TCP_CKSUM | VNET_BUFFER_F_GSO); + b0->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM; tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) + vnet_buffer (b0)->l4_hdr_offset); - l4_hdr_sz = tcp_header_bytes (tcp); tcp->checksum = 0; - vnet_buffer2 (b0)->gso_l4_hdr_sz = l4_hdr_sz; - vnet_buffer2 (b0)->gso_size = packet_data_size; + if (gso_enabled) + { + b0->flags |= VNET_BUFFER_F_GSO; + l4_hdr_sz = tcp_header_bytes (tcp); + vnet_buffer2 (b0)->gso_l4_hdr_sz = l4_hdr_sz; + vnet_buffer2 (b0)->gso_size = gso_size; + } } else if (l4_proto == IP_PROTOCOL_UDP) { @@ -1603,7 +1607,6 @@ fill_gso_buffer_flags (vlib_main_t * vm, u32 * buffers, u32 n_buffers, udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) + vnet_buffer (b0)->l4_hdr_offset); - vnet_buffer2 (b0)->gso_l4_hdr_sz = sizeof (*udp); udp->checksum = 0; } } @@ -1700,8 +1703,14 @@ pg_generate_packets (vlib_node_runtime_t * node, vnet_buffer (b)->feature_arc_index = feature_arc_index; } - if (pi->gso_enabled) - fill_gso_buffer_flags (vm, to_next, n_this_frame, pi->gso_size); + if (pi->gso_enabled || + (s->buffer_flags & (VNET_BUFFER_F_OFFLOAD_TCP_CKSUM | + VNET_BUFFER_F_OFFLOAD_UDP_CKSUM | + VNET_BUFFER_F_OFFLOAD_IP_CKSUM))) + { + fill_buffer_offload_flags (vm, to_next, n_this_frame, + pi->gso_enabled, pi->gso_size); + } n_trace = vlib_get_trace_count (vm, node); if (n_trace > 0) -- cgit 1.2.3-korg