Mohsin Kazmi | 29467b5 | 2019-10-08 19:42:38 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2019 Cisco and/or its affiliates. |
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | * you may not use this file except in compliance with the License. |
| 5 | * You may obtain a copy of the License at: |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software |
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | * See the License for the specific language governing permissions and |
| 13 | * limitations under the License. |
| 14 | */ |
| 15 | |
| 16 | #ifndef included_gso_h |
| 17 | #define included_gso_h |
| 18 | |
| 19 | #include <vnet/vnet.h> |
Mohsin Kazmi | d9e7ac3 | 2021-10-15 22:45:51 +0000 | [diff] [blame] | 20 | #include <vnet/gso/hdr_offset_parser.h> |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 21 | #include <vnet/ip/ip_psh_cksum.h> |
Mohsin Kazmi | 29467b5 | 2019-10-08 19:42:38 +0200 | [diff] [blame] | 22 | |
| 23 | typedef struct |
| 24 | { |
| 25 | vlib_main_t *vlib_main; |
| 26 | vnet_main_t *vnet_main; |
| 27 | u16 msg_id_base; |
| 28 | } gso_main_t; |
| 29 | |
| 30 | extern gso_main_t gso_main; |
| 31 | |
| 32 | int vnet_sw_interface_gso_enable_disable (u32 sw_if_index, u8 enable); |
Mohsin Kazmi | d9e7ac3 | 2021-10-15 22:45:51 +0000 | [diff] [blame] | 33 | u32 gso_segment_buffer (vlib_main_t *vm, vnet_interface_per_thread_data_t *ptd, |
| 34 | u32 bi, vlib_buffer_t *b, generic_header_offset_t *gho, |
| 35 | u32 n_bytes_b, u8 is_l2, u8 is_ip6); |
Mohsin Kazmi | 29467b5 | 2019-10-08 19:42:38 +0200 | [diff] [blame] | 36 | |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 37 | static_always_inline void |
| 38 | gso_init_bufs_from_template_base (vlib_buffer_t **bufs, vlib_buffer_t *b0, |
| 39 | u32 flags, u16 n_bufs, u16 hdr_sz) |
| 40 | { |
| 41 | u32 i = n_bufs; |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 42 | while (i >= 6) |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 43 | { |
| 44 | /* prefetches */ |
| 45 | CLIB_PREFETCH (bufs[2], 2 * CLIB_CACHE_LINE_BYTES, LOAD); |
| 46 | CLIB_PREFETCH (bufs[3], 2 * CLIB_CACHE_LINE_BYTES, LOAD); |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 47 | vlib_prefetch_buffer_data (bufs[4], LOAD); |
| 48 | vlib_prefetch_buffer_data (bufs[5], LOAD); |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 49 | |
| 50 | /* copying objects from cacheline 0 */ |
| 51 | bufs[0]->current_data = 0; |
| 52 | bufs[1]->current_data = 0; |
| 53 | |
| 54 | bufs[0]->current_length = hdr_sz; |
| 55 | bufs[1]->current_length = hdr_sz; |
| 56 | |
| 57 | bufs[0]->flags = bufs[1]->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID | flags; |
| 58 | bufs[0]->flow_id = bufs[1]->flow_id = b0->flow_id; |
| 59 | bufs[0]->error = bufs[1]->error = b0->error; |
| 60 | bufs[0]->current_config_index = bufs[1]->current_config_index = |
| 61 | b0->current_config_index; |
| 62 | |
| 63 | clib_memcpy_fast (&bufs[0]->opaque, &b0->opaque, sizeof (b0->opaque)); |
| 64 | clib_memcpy_fast (&bufs[1]->opaque, &b0->opaque, sizeof (b0->opaque)); |
| 65 | |
| 66 | /* copying objects from cacheline 1 */ |
| 67 | bufs[0]->trace_handle = b0->trace_handle; |
| 68 | bufs[1]->trace_handle = b0->trace_handle; |
| 69 | |
| 70 | bufs[0]->total_length_not_including_first_buffer = 0; |
| 71 | bufs[1]->total_length_not_including_first_buffer = 0; |
| 72 | |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 73 | clib_memcpy_fast (&bufs[0]->opaque2, &b0->opaque2, sizeof (b0->opaque2)); |
| 74 | clib_memcpy_fast (&bufs[1]->opaque2, &b0->opaque2, sizeof (b0->opaque2)); |
| 75 | |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 76 | /* copying data */ |
| 77 | clib_memcpy_fast (bufs[0]->data, vlib_buffer_get_current (b0), hdr_sz); |
| 78 | clib_memcpy_fast (bufs[1]->data, vlib_buffer_get_current (b0), hdr_sz); |
| 79 | |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 80 | /* header offset fixup */ |
| 81 | vnet_buffer (bufs[0])->l2_hdr_offset -= b0->current_data; |
| 82 | vnet_buffer (bufs[0])->l3_hdr_offset -= b0->current_data; |
| 83 | vnet_buffer (bufs[0])->l4_hdr_offset -= b0->current_data; |
| 84 | vnet_buffer2 (bufs[0])->outer_l3_hdr_offset -= b0->current_data; |
| 85 | vnet_buffer2 (bufs[0])->outer_l4_hdr_offset -= b0->current_data; |
| 86 | |
| 87 | vnet_buffer (bufs[1])->l2_hdr_offset -= b0->current_data; |
| 88 | vnet_buffer (bufs[1])->l3_hdr_offset -= b0->current_data; |
| 89 | vnet_buffer (bufs[1])->l4_hdr_offset -= b0->current_data; |
| 90 | vnet_buffer2 (bufs[1])->outer_l3_hdr_offset -= b0->current_data; |
| 91 | vnet_buffer2 (bufs[1])->outer_l4_hdr_offset -= b0->current_data; |
| 92 | |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 93 | bufs += 2; |
| 94 | i -= 2; |
| 95 | } |
| 96 | |
| 97 | while (i > 0) |
| 98 | { |
| 99 | /* copying objects from cacheline 0 */ |
| 100 | bufs[0]->current_data = 0; |
| 101 | bufs[0]->current_length = hdr_sz; |
| 102 | bufs[0]->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID | flags; |
| 103 | bufs[0]->flow_id = b0->flow_id; |
| 104 | bufs[0]->error = b0->error; |
| 105 | bufs[0]->current_config_index = b0->current_config_index; |
| 106 | clib_memcpy_fast (&bufs[0]->opaque, &b0->opaque, sizeof (b0->opaque)); |
| 107 | |
| 108 | /* copying objects from cacheline 1 */ |
| 109 | bufs[0]->trace_handle = b0->trace_handle; |
| 110 | bufs[0]->total_length_not_including_first_buffer = 0; |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 111 | clib_memcpy_fast (&bufs[0]->opaque2, &b0->opaque2, sizeof (b0->opaque2)); |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 112 | |
| 113 | /* copying data */ |
| 114 | clib_memcpy_fast (bufs[0]->data, vlib_buffer_get_current (b0), hdr_sz); |
| 115 | |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 116 | /* header offset fixup */ |
| 117 | vnet_buffer (bufs[0])->l2_hdr_offset -= b0->current_data; |
| 118 | vnet_buffer (bufs[0])->l3_hdr_offset -= b0->current_data; |
| 119 | vnet_buffer (bufs[0])->l4_hdr_offset -= b0->current_data; |
| 120 | vnet_buffer2 (bufs[0])->outer_l3_hdr_offset -= b0->current_data; |
| 121 | vnet_buffer2 (bufs[0])->outer_l4_hdr_offset -= b0->current_data; |
| 122 | |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 123 | bufs++; |
| 124 | i--; |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | static_always_inline void |
| 129 | gso_fixup_segmented_buf (vlib_main_t *vm, vlib_buffer_t *b0, u32 next_tcp_seq, |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 130 | int is_l2, u8 oflags, u16 hdr_sz, u16 l4_hdr_sz, |
| 131 | clib_ip_csum_t *c, u8 tcp_flags, u8 is_prefetch, |
| 132 | vlib_buffer_t *b1) |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 133 | { |
| 134 | |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 135 | i16 l3_hdr_offset = vnet_buffer (b0)->l3_hdr_offset; |
| 136 | i16 l4_hdr_offset = vnet_buffer (b0)->l4_hdr_offset; |
| 137 | |
| 138 | ip4_header_t *ip4 = (ip4_header_t *) (b0->data + l3_hdr_offset); |
| 139 | ip6_header_t *ip6 = (ip6_header_t *) (b0->data + l3_hdr_offset); |
| 140 | tcp_header_t *tcp = (tcp_header_t *) (b0->data + l4_hdr_offset); |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 141 | |
| 142 | tcp->flags = tcp_flags; |
| 143 | tcp->seq_number = clib_host_to_net_u32 (next_tcp_seq); |
Mohsin Kazmi | 6b8874e | 2022-10-06 15:43:36 +0000 | [diff] [blame] | 144 | c->odd = 0; |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 145 | |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 146 | if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 147 | { |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 148 | ip4->length = |
| 149 | clib_host_to_net_u16 (b0->current_length - hdr_sz + |
| 150 | (l4_hdr_offset - l3_hdr_offset) + l4_hdr_sz); |
| 151 | ip4->checksum = 0; |
| 152 | ip4->checksum = ip4_header_checksum (ip4); |
| 153 | vnet_buffer_offload_flags_clear (b0, (VNET_BUFFER_OFFLOAD_F_IP_CKSUM | |
| 154 | VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)); |
| 155 | c->sum += clib_mem_unaligned (&ip4->src_address, u32); |
| 156 | c->sum += clib_mem_unaligned (&ip4->dst_address, u32); |
| 157 | c->sum += clib_host_to_net_u32 ( |
| 158 | (clib_net_to_host_u16 (ip4->length) - ip4_header_bytes (ip4)) + |
| 159 | (ip4->protocol << 16)); |
| 160 | } |
| 161 | else |
| 162 | { |
| 163 | ip6->payload_length = |
| 164 | clib_host_to_net_u16 (b0->current_length - hdr_sz + l4_hdr_sz); |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 165 | vnet_buffer_offload_flags_clear (b0, VNET_BUFFER_OFFLOAD_F_TCP_CKSUM); |
| 166 | ip6_psh_t psh = { 0 }; |
| 167 | u32 *p = (u32 *) &psh; |
| 168 | psh.src = ip6->src_address; |
| 169 | psh.dst = ip6->dst_address; |
| 170 | psh.l4len = ip6->payload_length; |
| 171 | psh.proto = clib_host_to_net_u32 ((u32) ip6->protocol); |
| 172 | for (int i = 0; i < 10; i++) |
| 173 | c->sum += p[i]; |
| 174 | } |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 175 | |
| 176 | if (is_prefetch) |
| 177 | CLIB_PREFETCH (vlib_buffer_get_current (b1) + hdr_sz, |
| 178 | CLIB_CACHE_LINE_BYTES, LOAD); |
| 179 | |
| 180 | clib_ip_csum_chunk (c, (u8 *) tcp, l4_hdr_sz); |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 181 | tcp->checksum = clib_ip_csum_fold (c); |
| 182 | |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 183 | if (!is_l2 && ((oflags & VNET_BUFFER_OFFLOAD_F_TNL_MASK) == 0)) |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 184 | { |
| 185 | u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX]; |
| 186 | |
| 187 | ip_adjacency_t *adj0 = adj_get (adj_index0); |
| 188 | |
| 189 | if (adj0->lookup_next_index == IP_LOOKUP_NEXT_MIDCHAIN && |
| 190 | adj0->sub_type.midchain.fixup_func) |
| 191 | /* calls e.g. ipip44_fixup */ |
| 192 | adj0->sub_type.midchain.fixup_func ( |
| 193 | vm, adj0, b0, adj0->sub_type.midchain.fixup_data); |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | static_always_inline u32 |
| 198 | gso_segment_buffer_inline (vlib_main_t *vm, |
| 199 | vnet_interface_per_thread_data_t *ptd, |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 200 | vlib_buffer_t *b, int is_l2) |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 201 | { |
| 202 | vlib_buffer_t **bufs = 0; |
| 203 | u32 n_tx_bytes = 0; |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 204 | |
| 205 | u8 oflags = vnet_buffer (b)->oflags; |
| 206 | i16 l4_hdr_offset = vnet_buffer (b)->l4_hdr_offset; |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 207 | u16 gso_size = vnet_buffer2 (b)->gso_size; |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 208 | u16 l4_hdr_sz = vnet_buffer2 (b)->gso_l4_hdr_sz; |
| 209 | |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 210 | u8 tcp_flags = 0, tcp_flags_no_fin_psh = 0; |
| 211 | u32 default_bflags = |
| 212 | b->flags & ~(VNET_BUFFER_F_GSO | VLIB_BUFFER_NEXT_PRESENT); |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 213 | u16 hdr_sz = (l4_hdr_offset - b->current_data) + l4_hdr_sz; |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 214 | u32 next_tcp_seq = 0, tcp_seq = 0; |
| 215 | u32 data_size = vlib_buffer_length_in_chain (vm, b) - hdr_sz; |
| 216 | u16 size = |
| 217 | clib_min (gso_size, vlib_buffer_get_default_data_size (vm) - hdr_sz); |
| 218 | u16 n_alloc = 0, n_bufs = ((data_size + size - 1) / size); |
| 219 | clib_ip_csum_t c = { .sum = 0, .odd = 0 }; |
| 220 | u8 *src_ptr, *dst_ptr; |
| 221 | u16 src_left, dst_left, bytes_to_copy; |
| 222 | u32 i = 0; |
| 223 | |
| 224 | vec_validate (ptd->split_buffers, n_bufs - 1); |
| 225 | n_alloc = vlib_buffer_alloc (vm, ptd->split_buffers, n_bufs); |
| 226 | if (n_alloc < n_bufs) |
| 227 | { |
| 228 | vlib_buffer_free (vm, ptd->split_buffers, n_alloc); |
| 229 | return 0; |
| 230 | } |
| 231 | |
| 232 | vec_validate (bufs, n_bufs - 1); |
| 233 | vlib_get_buffers (vm, ptd->split_buffers, bufs, n_bufs); |
| 234 | |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 235 | tcp_header_t *tcp = (tcp_header_t *) (b->data + l4_hdr_offset); |
| 236 | |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 237 | tcp_seq = next_tcp_seq = clib_net_to_host_u32 (tcp->seq_number); |
| 238 | /* store original flags for last packet and reset FIN and PSH */ |
| 239 | tcp_flags = tcp->flags; |
| 240 | tcp_flags_no_fin_psh = tcp->flags & ~(TCP_FLAG_FIN | TCP_FLAG_PSH); |
| 241 | tcp->checksum = 0; |
| 242 | |
| 243 | gso_init_bufs_from_template_base (bufs, b, default_bflags, n_bufs, hdr_sz); |
| 244 | |
| 245 | src_ptr = vlib_buffer_get_current (b) + hdr_sz; |
| 246 | src_left = b->current_length - hdr_sz; |
| 247 | dst_ptr = vlib_buffer_get_current (bufs[i]) + hdr_sz; |
| 248 | dst_left = size; |
| 249 | |
| 250 | while (data_size) |
| 251 | { |
| 252 | bytes_to_copy = clib_min (src_left, dst_left); |
| 253 | clib_ip_csum_and_copy_chunk (&c, src_ptr, dst_ptr, bytes_to_copy); |
| 254 | |
| 255 | src_left -= bytes_to_copy; |
| 256 | src_ptr += bytes_to_copy; |
| 257 | data_size -= bytes_to_copy; |
| 258 | dst_left -= bytes_to_copy; |
| 259 | dst_ptr += bytes_to_copy; |
| 260 | next_tcp_seq += bytes_to_copy; |
| 261 | bufs[i]->current_length += bytes_to_copy; |
| 262 | |
| 263 | if (0 == src_left) |
| 264 | { |
| 265 | /* init src to the next buffer in chain */ |
| 266 | if (b->flags & VLIB_BUFFER_NEXT_PRESENT) |
| 267 | { |
| 268 | b = vlib_get_buffer (vm, b->next_buffer); |
| 269 | src_left = b->current_length; |
| 270 | src_ptr = vlib_buffer_get_current (b); |
| 271 | } |
| 272 | else |
| 273 | { |
| 274 | ASSERT (data_size == 0); |
| 275 | break; |
| 276 | } |
| 277 | } |
| 278 | if (0 == dst_left && data_size) |
| 279 | { |
| 280 | vlib_prefetch_buffer_header (bufs[i + 1], LOAD); |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 281 | |
| 282 | n_tx_bytes += bufs[i]->current_length; |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 283 | gso_fixup_segmented_buf (vm, bufs[i], tcp_seq, is_l2, oflags, hdr_sz, |
| 284 | l4_hdr_sz, &c, tcp_flags_no_fin_psh, 1, |
| 285 | bufs[i + 1]); |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 286 | i++; |
| 287 | dst_left = size; |
| 288 | dst_ptr = vlib_buffer_get_current (bufs[i]) + hdr_sz; |
| 289 | tcp_seq = next_tcp_seq; |
| 290 | // reset clib_ip_csum_t |
| 291 | c.odd = 0; |
| 292 | c.sum = 0; |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | ASSERT ((i + 1) == n_alloc); |
| 297 | n_tx_bytes += bufs[i]->current_length; |
Mohsin Kazmi | 7b3339e | 2022-09-29 15:28:04 +0000 | [diff] [blame^] | 298 | gso_fixup_segmented_buf (vm, bufs[i], tcp_seq, is_l2, oflags, hdr_sz, |
| 299 | l4_hdr_sz, &c, tcp_flags, 0, NULL); |
Mohsin Kazmi | d431d74 | 2021-10-21 20:20:24 +0000 | [diff] [blame] | 300 | |
| 301 | vec_free (bufs); |
| 302 | return n_tx_bytes; |
| 303 | } |
| 304 | |
Mohsin Kazmi | 29467b5 | 2019-10-08 19:42:38 +0200 | [diff] [blame] | 305 | #endif /* included_gso_h */ |
| 306 | |
| 307 | /* |
| 308 | * fd.io coding-style-patch-verification: ON |
| 309 | * |
| 310 | * Local Variables: |
| 311 | * eval: (c-set-style "gnu") |
| 312 | * End: |
| 313 | */ |