blob: c0268b215627800133dfbe84cd3536dc1d511a6c [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 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 * buffer_node.h: VLIB buffer handling node helper macros/inlines
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#ifndef included_vlib_buffer_node_h
41#define included_vlib_buffer_node_h
42
Dave Barach9b8ffd92016-07-08 08:13:45 -040043/** \file
Dave Barach9770e202016-07-06 10:29:27 -040044 vlib buffer/node functions
45*/
46
47/** \brief Finish enqueueing two buffers forward in the graph.
48 Standard dual loop boilerplate element. This is a MACRO,
Dave Barach9b8ffd92016-07-08 08:13:45 -040049 with MULTIPLE SIDE EFFECTS. In the ideal case,
Dave Barach9770e202016-07-06 10:29:27 -040050 <code>next_index == next0 == next1</code>,
51 which means that the speculative enqueue at the top of the dual loop
52 has correctly dealt with both packets. In that case, the macro does
53 nothing at all.
54
55 @param vm vlib_main_t pointer, varies by thread
56 @param node current node vlib_node_runtime_t pointer
57 @param next_index speculated next index used for both packets
58 @param to_next speculated vector pointer used for both packets
59 @param n_left_to_next number of slots left in speculated vector
60 @param bi0 first buffer index
61 @param bi1 second buffer index
62 @param next0 actual next index to be used for the first packet
63 @param next1 actual next index to be used for the second packet
64
65 @return @c next_index -- speculative next index to be used for future packets
66 @return @c to_next -- speculative frame to be used for future packets
67 @return @c n_left_to_next -- number of slots left in speculative frame
68*/
69
Ed Warnickecb9cada2015-12-08 15:45:58 -070070#define vlib_validate_buffer_enqueue_x2(vm,node,next_index,to_next,n_left_to_next,bi0,bi1,next0,next1) \
71do { \
Dave Barachc74b43c2020-04-09 17:24:07 -040072 ASSERT (bi0 != 0); \
73 ASSERT (bi1 != 0); \
Ed Warnickecb9cada2015-12-08 15:45:58 -070074 int enqueue_code = (next0 != next_index) + 2*(next1 != next_index); \
75 \
76 if (PREDICT_FALSE (enqueue_code != 0)) \
77 { \
78 switch (enqueue_code) \
79 { \
80 case 1: \
81 /* A B A */ \
82 to_next[-2] = bi1; \
83 to_next -= 1; \
84 n_left_to_next += 1; \
85 vlib_set_next_frame_buffer (vm, node, next0, bi0); \
86 break; \
87 \
88 case 2: \
89 /* A A B */ \
90 to_next -= 1; \
91 n_left_to_next += 1; \
92 vlib_set_next_frame_buffer (vm, node, next1, bi1); \
93 break; \
94 \
95 case 3: \
96 /* A B B or A B C */ \
97 to_next -= 2; \
98 n_left_to_next += 2; \
99 vlib_set_next_frame_buffer (vm, node, next0, bi0); \
100 vlib_set_next_frame_buffer (vm, node, next1, bi1); \
101 if (next0 == next1) \
102 { \
103 vlib_put_next_frame (vm, node, next_index, \
104 n_left_to_next); \
105 next_index = next1; \
106 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); \
107 } \
108 } \
109 } \
110} while (0)
111
Dave Barach670909e2016-10-18 15:25:35 -0400112
113/** \brief Finish enqueueing four buffers forward in the graph.
114 Standard quad loop boilerplate element. This is a MACRO,
115 with MULTIPLE SIDE EFFECTS. In the ideal case,
116 <code>next_index == next0 == next1 == next2 == next3</code>,
117 which means that the speculative enqueue at the top of the quad loop
118 has correctly dealt with all four packets. In that case, the macro does
119 nothing at all.
120
121 @param vm vlib_main_t pointer, varies by thread
122 @param node current node vlib_node_runtime_t pointer
123 @param next_index speculated next index used for both packets
124 @param to_next speculated vector pointer used for both packets
125 @param n_left_to_next number of slots left in speculated vector
126 @param bi0 first buffer index
127 @param bi1 second buffer index
128 @param bi2 third buffer index
129 @param bi3 fourth buffer index
130 @param next0 actual next index to be used for the first packet
131 @param next1 actual next index to be used for the second packet
132 @param next2 actual next index to be used for the third packet
133 @param next3 actual next index to be used for the fourth packet
134
135 @return @c next_index -- speculative next index to be used for future packets
136 @return @c to_next -- speculative frame to be used for future packets
137 @return @c n_left_to_next -- number of slots left in speculative frame
138*/
139
140#define vlib_validate_buffer_enqueue_x4(vm,node,next_index,to_next,n_left_to_next,bi0,bi1,bi2,bi3,next0,next1,next2,next3) \
141do { \
Dave Barachc74b43c2020-04-09 17:24:07 -0400142 ASSERT (bi0 != 0); \
143 ASSERT (bi1 != 0); \
144 ASSERT (bi2 != 0); \
145 ASSERT (bi3 != 0); \
Dave Barach670909e2016-10-18 15:25:35 -0400146 /* After the fact: check the [speculative] enqueue to "next" */ \
Eyal Bari2e292c62017-12-04 13:57:45 +0200147 u32 fix_speculation = (next_index ^ next0) | (next_index ^ next1) \
148 | (next_index ^ next2) | (next_index ^ next3); \
Dave Barach670909e2016-10-18 15:25:35 -0400149 if (PREDICT_FALSE(fix_speculation)) \
150 { \
151 /* rewind... */ \
152 to_next -= 4; \
153 n_left_to_next += 4; \
154 \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500155 /* If bi0 belongs to "next", send it there */ \
Dave Barach670909e2016-10-18 15:25:35 -0400156 if (next_index == next0) \
157 { \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500158 to_next[0] = bi0; \
Dave Barach670909e2016-10-18 15:25:35 -0400159 to_next++; \
160 n_left_to_next --; \
161 } \
162 else /* send it where it needs to go */ \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500163 vlib_set_next_frame_buffer (vm, node, next0, bi0); \
Dave Barach670909e2016-10-18 15:25:35 -0400164 \
165 if (next_index == next1) \
166 { \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500167 to_next[0] = bi1; \
Dave Barach670909e2016-10-18 15:25:35 -0400168 to_next++; \
169 n_left_to_next --; \
170 } \
171 else \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500172 vlib_set_next_frame_buffer (vm, node, next1, bi1); \
Dave Barach670909e2016-10-18 15:25:35 -0400173 \
174 if (next_index == next2) \
175 { \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500176 to_next[0] = bi2; \
Dave Barach670909e2016-10-18 15:25:35 -0400177 to_next++; \
178 n_left_to_next --; \
179 } \
180 else \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500181 vlib_set_next_frame_buffer (vm, node, next2, bi2); \
Dave Barach670909e2016-10-18 15:25:35 -0400182 \
183 if (next_index == next3) \
184 { \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500185 to_next[0] = bi3; \
Dave Barach670909e2016-10-18 15:25:35 -0400186 to_next++; \
187 n_left_to_next --; \
188 } \
189 else \
Dave Barach670909e2016-10-18 15:25:35 -0400190 { \
Eyal Bari2e292c62017-12-04 13:57:45 +0200191 vlib_set_next_frame_buffer (vm, node, next3, bi3); \
192 \
193 /* Change speculation: last 2 packets went to the same node*/ \
194 if (next2 == next3) \
195 { \
196 vlib_put_next_frame (vm, node, next_index, n_left_to_next); \
197 next_index = next3; \
198 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); \
199 } \
200 } \
Dave Barach670909e2016-10-18 15:25:35 -0400201 } \
202 } while(0);
203
Dave Barach9770e202016-07-06 10:29:27 -0400204/** \brief Finish enqueueing one buffer forward in the graph.
205 Standard single loop boilerplate element. This is a MACRO,
206 with MULTIPLE SIDE EFFECTS. In the ideal case,
207 <code>next_index == next0</code>,
208 which means that the speculative enqueue at the top of the single loop
209 has correctly dealt with the packet in hand. In that case, the macro does
210 nothing at all.
211
212 @param vm vlib_main_t pointer, varies by thread
213 @param node current node vlib_node_runtime_t pointer
214 @param next_index speculated next index used for both packets
215 @param to_next speculated vector pointer used for both packets
216 @param n_left_to_next number of slots left in speculated vector
217 @param bi0 first buffer index
218 @param next0 actual next index to be used for the first packet
219
220 @return @c next_index -- speculative next index to be used for future packets
221 @return @c to_next -- speculative frame to be used for future packets
222 @return @c n_left_to_next -- number of slots left in speculative frame
223*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224#define vlib_validate_buffer_enqueue_x1(vm,node,next_index,to_next,n_left_to_next,bi0,next0) \
225do { \
Dave Barachc74b43c2020-04-09 17:24:07 -0400226 ASSERT (bi0 != 0); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227 if (PREDICT_FALSE (next0 != next_index)) \
228 { \
229 vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1); \
230 next_index = next0; \
231 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); \
232 \
233 to_next[0] = bi0; \
234 to_next += 1; \
235 n_left_to_next -= 1; \
236 } \
237} while (0)
238
Mohammed Hawari16052482022-06-02 13:55:36 +0200239/** \brief Finish enqueueing one buffer forward in the graph, along with its
240 aux_data if possible. Standard single loop boilerplate element. This is a
241 MACRO, with MULTIPLE SIDE EFFECTS. In the ideal case, <code>next_index ==
242 next0</code>, which means that the speculative enqueue at the top of the
243 single loop has correctly dealt with the packet in hand. In that case, the
244 macro does nothing at all. This function MAY return to_next_aux = NULL if
245 next_index does not support aux data
246
247 @param vm vlib_main_t pointer, varies by thread
248 @param node current node vlib_node_runtime_t pointer
249 @param next_index speculated next index used for both packets
250 @param to_next speculated vector pointer used for both packets
251 @param to_next_aux speculated aux_data pointer used for both packets
252 @param n_left_to_next number of slots left in speculated vector
253 @param bi0 first buffer index
254 @param aux0 first aux_data
255 @param next0 actual next index to be used for the first packet
256
257 @return @c next_index -- speculative next index to be used for future packets
258 @return @c to_next -- speculative frame to be used for future packets
259 @return @c n_left_to_next -- number of slots left in speculative frame
260*/
261#define vlib_validate_buffer_enqueue_with_aux_x1( \
262 vm, node, next_index, to_next, to_next_aux, n_left_to_next, bi0, aux0, \
263 next0) \
264 do \
265 { \
266 ASSERT (bi0 != 0); \
267 if (PREDICT_FALSE (next0 != next_index)) \
268 { \
269 vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1); \
270 next_index = next0; \
271 vlib_get_next_frame_with_aux_safe (vm, node, next_index, to_next, \
272 to_next_aux, n_left_to_next); \
273 \
274 to_next[0] = bi0; \
275 to_next += 1; \
276 if (to_next_aux) \
277 { \
278 to_next_aux[0] = aux0; \
279 to_next_aux += 1; \
280 } \
281 n_left_to_next -= 1; \
282 } \
283 } \
284 while (0)
285
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286always_inline uword
287generic_buffer_node_inline (vlib_main_t * vm,
288 vlib_node_runtime_t * node,
289 vlib_frame_t * frame,
290 uword sizeof_trace,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400291 void *opaque1,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 uword opaque2,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400293 void (*two_buffers) (vlib_main_t * vm,
294 void *opaque1,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 uword opaque2,
296 vlib_buffer_t * b0,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400297 vlib_buffer_t * b1,
298 u32 * next0, u32 * next1),
299 void (*one_buffer) (vlib_main_t * vm,
300 void *opaque1, uword opaque2,
301 vlib_buffer_t * b0,
302 u32 * next0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400304 u32 n_left_from, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305 u32 next_index;
306
307 from = vlib_frame_vector_args (frame);
308 n_left_from = frame->n_vectors;
309 next_index = node->cached_next_index;
310
311 if (node->flags & VLIB_NODE_FLAG_TRACE)
312 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
313 /* stride */ 1, sizeof_trace);
314
315 while (n_left_from > 0)
316 {
317 u32 n_left_to_next;
318
Dave Barach9b8ffd92016-07-08 08:13:45 -0400319 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320
321 while (n_left_from >= 4 && n_left_to_next >= 2)
322 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400323 vlib_buffer_t *p0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324 u32 pi0, next0;
325 u32 pi1, next1;
326
327 /* Prefetch next iteration. */
328 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400329 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330
331 p2 = vlib_get_buffer (vm, from[2]);
332 p3 = vlib_get_buffer (vm, from[3]);
333
334 vlib_prefetch_buffer_header (p2, LOAD);
335 vlib_prefetch_buffer_header (p3, LOAD);
336
Damjan Marionaf7fb042021-07-15 11:54:41 +0200337 clib_prefetch_load (p2->data);
338 clib_prefetch_load (p3->data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339 }
340
341 pi0 = to_next[0] = from[0];
342 pi1 = to_next[1] = from[1];
343 from += 2;
344 to_next += 2;
345 n_left_from -= 2;
346 n_left_to_next -= 2;
347
348 p0 = vlib_get_buffer (vm, pi0);
349 p1 = vlib_get_buffer (vm, pi1);
350
351 two_buffers (vm, opaque1, opaque2, p0, p1, &next0, &next1);
352
353 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
354 to_next, n_left_to_next,
355 pi0, pi1, next0, next1);
356 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400357
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358 while (n_left_from > 0 && n_left_to_next > 0)
359 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400360 vlib_buffer_t *p0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361 u32 pi0, next0;
362
363 pi0 = from[0];
364 to_next[0] = pi0;
365 from += 1;
366 to_next += 1;
367 n_left_from -= 1;
368 n_left_to_next -= 1;
369
370 p0 = vlib_get_buffer (vm, pi0);
371
372 one_buffer (vm, opaque1, opaque2, p0, &next0);
373
374 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
375 to_next, n_left_to_next,
376 pi0, next0);
377 }
378
379 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
380 }
381
382 return frame->n_vectors;
383}
384
Benoît Ganne10bb21f2021-09-08 16:26:52 +0200385/* Minimum size for the 'buffers' and 'nexts' arrays to be used when calling
386 * vlib_buffer_enqueue_to_next().
387 * Because of optimizations, vlib_buffer_enqueue_to_next() will access
388 * past 'count' elements in the 'buffers' and 'nexts' arrays, IOW it
389 * will overflow.
390 * Those overflow elements are ignored in the final result so they do not
391 * need to be properly initialized, however if the array is allocated right
392 * before the end of a page and the next page is not mapped, accessing the
393 * overflow elements will trigger a segfault. */
394#define VLIB_BUFFER_ENQUEUE_MIN_SIZE(n) round_pow2 ((n), 64)
395
Damjan Marion8c3f8a22018-05-17 21:12:13 +0200396static_always_inline void
397vlib_buffer_enqueue_to_next (vlib_main_t * vm, vlib_node_runtime_t * node,
398 u32 * buffers, u16 * nexts, uword count)
399{
Damjan Marion1c229712021-04-21 12:55:15 +0200400 vlib_buffer_enqueue_to_next_fn_t *fn;
401 fn = vlib_buffer_func_main.buffer_enqueue_to_next_fn;
402 (fn) (vm, node, buffers, nexts, count);
Damjan Marion8c3f8a22018-05-17 21:12:13 +0200403}
404
Damjan Marion142eb852018-11-20 09:56:01 +0100405static_always_inline void
Mohammed Hawaricd758e62022-05-31 18:11:05 +0200406vlib_buffer_enqueue_to_next_with_aux (vlib_main_t *vm,
407 vlib_node_runtime_t *node, u32 *buffers,
408 u32 *aux_data, u16 *nexts, uword count)
409{
410 vlib_buffer_enqueue_to_next_with_aux_fn_t *fn;
411 fn = vlib_buffer_func_main.buffer_enqueue_to_next_with_aux_fn;
412 (fn) (vm, node, buffers, aux_data, nexts, count);
413}
414
415static_always_inline void
Benoît Ganne10bb21f2021-09-08 16:26:52 +0200416vlib_buffer_enqueue_to_next_vec (vlib_main_t *vm, vlib_node_runtime_t *node,
417 u32 **buffers, u16 **nexts, uword count)
418{
419 const u32 bl = vec_len (*buffers), nl = vec_len (*nexts);
420 const u32 c = VLIB_BUFFER_ENQUEUE_MIN_SIZE (count);
421 ASSERT (bl >= count && nl >= count);
422 vec_validate (*buffers, c);
423 vec_validate (*nexts, c);
424 vlib_buffer_enqueue_to_next (vm, node, *buffers, *nexts, count);
425 vec_set_len (*buffers, bl);
426 vec_set_len (*nexts, nl);
427}
428
429static_always_inline void
Damjan Marion142eb852018-11-20 09:56:01 +0100430vlib_buffer_enqueue_to_single_next (vlib_main_t * vm,
431 vlib_node_runtime_t * node, u32 * buffers,
432 u16 next_index, u32 count)
433{
Damjan Marion1c229712021-04-21 12:55:15 +0200434 vlib_buffer_enqueue_to_single_next_fn_t *fn;
435 fn = vlib_buffer_func_main.buffer_enqueue_to_single_next_fn;
436 (fn) (vm, node, buffers, next_index, count);
Damjan Marion142eb852018-11-20 09:56:01 +0100437}
438
Mohammed Hawaricd758e62022-05-31 18:11:05 +0200439static_always_inline void
440vlib_buffer_enqueue_to_single_next_with_aux (vlib_main_t *vm,
441 vlib_node_runtime_t *node,
442 u32 *buffers, u32 *aux_data,
443 u16 next_index, u32 count)
444{
445 vlib_buffer_enqueue_to_single_next_with_aux_fn_t *fn;
446 fn = vlib_buffer_func_main.buffer_enqueue_to_single_next_with_aux_fn;
447 (fn) (vm, node, buffers, aux_data, next_index, count);
448}
449
Damjan Marion78fd7e82018-07-20 18:47:05 +0200450static_always_inline u32
Damjan Marion9e7a0b42021-05-14 14:50:01 +0200451vlib_buffer_enqueue_to_thread (vlib_main_t *vm, vlib_node_runtime_t *node,
452 u32 frame_queue_index, u32 *buffer_indices,
453 u16 *thread_indices, u32 n_packets,
454 int drop_on_congestion)
Damjan Marion4d56e052018-07-19 17:52:31 +0200455{
Damjan Marion1c229712021-04-21 12:55:15 +0200456 vlib_buffer_enqueue_to_thread_fn_t *fn;
457 fn = vlib_buffer_func_main.buffer_enqueue_to_thread_fn;
Damjan Marion9e7a0b42021-05-14 14:50:01 +0200458 return (fn) (vm, node, frame_queue_index, buffer_indices, thread_indices,
Damjan Marion1c229712021-04-21 12:55:15 +0200459 n_packets, drop_on_congestion);
Damjan Marion4d56e052018-07-19 17:52:31 +0200460}
461
Mohammed Hawarie7149262022-05-18 10:08:47 +0200462static_always_inline u32
463vlib_buffer_enqueue_to_thread_with_aux (vlib_main_t *vm,
464 vlib_node_runtime_t *node,
465 u32 frame_queue_index,
466 u32 *buffer_indices, u32 *aux,
467 u16 *thread_indices, u32 n_packets,
468 int drop_on_congestion)
469{
470 vlib_buffer_enqueue_to_thread_with_aux_fn_t *fn;
471 fn = vlib_buffer_func_main.buffer_enqueue_to_thread_with_aux_fn;
472 return (fn) (vm, node, frame_queue_index, buffer_indices, aux,
473 thread_indices, n_packets, drop_on_congestion);
474}
475
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476#endif /* included_vlib_buffer_node_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400477
478/*
479 * fd.io coding-style-patch-verification: ON
480 *
481 * Local Variables:
482 * eval: (c-set-style "gnu")
483 * End:
484 */