blob: dee5da5c70b1222e86b0177bfb1f59c1ecfa9212 [file] [log] [blame]
Mohsin Kazmi29467b52019-10-08 19:42:38 +02001/*
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 Kazmid9e7ac32021-10-15 22:45:51 +000020#include <vnet/gso/hdr_offset_parser.h>
Mohsin Kazmid431d742021-10-21 20:20:24 +000021#include <vnet/ip/ip_psh_cksum.h>
Mohsin Kazmi29467b52019-10-08 19:42:38 +020022
23typedef struct
24{
25 vlib_main_t *vlib_main;
26 vnet_main_t *vnet_main;
27 u16 msg_id_base;
28} gso_main_t;
29
30extern gso_main_t gso_main;
31
32int vnet_sw_interface_gso_enable_disable (u32 sw_if_index, u8 enable);
Mohsin Kazmid9e7ac32021-10-15 22:45:51 +000033u32 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 Kazmi29467b52019-10-08 19:42:38 +020036
Mohsin Kazmid431d742021-10-21 20:20:24 +000037static_always_inline void
38gso_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 Kazmi7b3339e2022-09-29 15:28:04 +000042 while (i >= 6)
Mohsin Kazmid431d742021-10-21 20:20:24 +000043 {
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 Kazmi7b3339e2022-09-29 15:28:04 +000047 vlib_prefetch_buffer_data (bufs[4], LOAD);
48 vlib_prefetch_buffer_data (bufs[5], LOAD);
Mohsin Kazmid431d742021-10-21 20:20:24 +000049
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 Kazmi7b3339e2022-09-29 15:28:04 +000073 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 Kazmid431d742021-10-21 20:20:24 +000076 /* 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 Kazmi7b3339e2022-09-29 15:28:04 +000080 /* 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 Kazmid431d742021-10-21 20:20:24 +000093 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 Kazmi7b3339e2022-09-29 15:28:04 +0000111 clib_memcpy_fast (&bufs[0]->opaque2, &b0->opaque2, sizeof (b0->opaque2));
Mohsin Kazmid431d742021-10-21 20:20:24 +0000112
113 /* copying data */
114 clib_memcpy_fast (bufs[0]->data, vlib_buffer_get_current (b0), hdr_sz);
115
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000116 /* 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 Kazmid431d742021-10-21 20:20:24 +0000123 bufs++;
124 i--;
125 }
126}
127
128static_always_inline void
129gso_fixup_segmented_buf (vlib_main_t *vm, vlib_buffer_t *b0, u32 next_tcp_seq,
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000130 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 Kazmid431d742021-10-21 20:20:24 +0000133{
134
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000135 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 Kazmid431d742021-10-21 20:20:24 +0000141
142 tcp->flags = tcp_flags;
143 tcp->seq_number = clib_host_to_net_u32 (next_tcp_seq);
Mohsin Kazmi6b8874e2022-10-06 15:43:36 +0000144 c->odd = 0;
Mohsin Kazmid431d742021-10-21 20:20:24 +0000145
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000146 if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
Mohsin Kazmid431d742021-10-21 20:20:24 +0000147 {
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000148 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 Kazmid431d742021-10-21 20:20:24 +0000165 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 Kazmi7b3339e2022-09-29 15:28:04 +0000175
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 Kazmid431d742021-10-21 20:20:24 +0000181 tcp->checksum = clib_ip_csum_fold (c);
182
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000183 if (!is_l2 && ((oflags & VNET_BUFFER_OFFLOAD_F_TNL_MASK) == 0))
Mohsin Kazmid431d742021-10-21 20:20:24 +0000184 {
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
197static_always_inline u32
198gso_segment_buffer_inline (vlib_main_t *vm,
199 vnet_interface_per_thread_data_t *ptd,
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000200 vlib_buffer_t *b, int is_l2)
Mohsin Kazmid431d742021-10-21 20:20:24 +0000201{
202 vlib_buffer_t **bufs = 0;
203 u32 n_tx_bytes = 0;
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000204
205 u8 oflags = vnet_buffer (b)->oflags;
206 i16 l4_hdr_offset = vnet_buffer (b)->l4_hdr_offset;
Mohsin Kazmid431d742021-10-21 20:20:24 +0000207 u16 gso_size = vnet_buffer2 (b)->gso_size;
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000208 u16 l4_hdr_sz = vnet_buffer2 (b)->gso_l4_hdr_sz;
209
Mohsin Kazmid431d742021-10-21 20:20:24 +0000210 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 Kazmi7b3339e2022-09-29 15:28:04 +0000213 u16 hdr_sz = (l4_hdr_offset - b->current_data) + l4_hdr_sz;
Mohsin Kazmid431d742021-10-21 20:20:24 +0000214 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 Kazmi7b3339e2022-09-29 15:28:04 +0000235 tcp_header_t *tcp = (tcp_header_t *) (b->data + l4_hdr_offset);
236
Mohsin Kazmid431d742021-10-21 20:20:24 +0000237 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 Kazmid431d742021-10-21 20:20:24 +0000281
282 n_tx_bytes += bufs[i]->current_length;
Mohsin Kazmi7b3339e2022-09-29 15:28:04 +0000283 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 Kazmid431d742021-10-21 20:20:24 +0000286 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 Kazmi7b3339e2022-09-29 15:28:04 +0000298 gso_fixup_segmented_buf (vm, bufs[i], tcp_seq, is_l2, oflags, hdr_sz,
299 l4_hdr_sz, &c, tcp_flags, 0, NULL);
Mohsin Kazmid431d742021-10-21 20:20:24 +0000300
301 vec_free (bufs);
302 return n_tx_bytes;
303}
304
Mohsin Kazmi29467b52019-10-08 19:42:38 +0200305#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 */