blob: a12aea4e462d7553cdcffda2d8c11469b6941cb0 [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 * node_funcs.h: processing nodes global functions/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
Dave Barach9b8ffd92016-07-08 08:13:45 -040040/** \file
Dave Barach9770e202016-07-06 10:29:27 -040041 vlib node functions
42*/
43
44
Ed Warnickecb9cada2015-12-08 15:45:58 -070045#ifndef included_vlib_node_funcs_h
46#define included_vlib_node_funcs_h
47
48#include <vppinfra/fifo.h>
Dave Barach5c20a012017-06-13 08:48:31 -040049#include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
Damjan Marion94100532020-11-06 23:25:57 +010050#include <vppinfra/interrupt.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070051
Damjan Marioncea46522020-05-21 16:47:05 +020052#ifdef CLIB_SANITIZE_ADDR
53#include <sanitizer/asan_interface.h>
54#endif
55
56static_always_inline void
57vlib_process_start_switch_stack (vlib_main_t * vm, vlib_process_t * p)
58{
59#ifdef CLIB_SANITIZE_ADDR
60 void *stack = p ? (void *) p->stack : vlib_thread_stacks[vm->thread_index];
61 u32 stack_bytes = p ? p->log2_n_stack_bytes : VLIB_THREAD_STACK_SIZE;
62 __sanitizer_start_switch_fiber (&vm->asan_stack_save, stack, stack_bytes);
63#endif
64}
65
66static_always_inline void
67vlib_process_finish_switch_stack (vlib_main_t * vm)
68{
69#ifdef CLIB_SANITIZE_ADDR
70 const void *bottom_old;
71 size_t size_old;
72
73 __sanitizer_finish_switch_fiber (&vm->asan_stack_save, &bottom_old,
74 &size_old);
75#endif
76}
77
Dave Barach9770e202016-07-06 10:29:27 -040078/** \brief Get vlib node by index.
79 @warning This function will ASSERT if @c i is out of range.
80 @param vm vlib_main_t pointer, varies by thread
81 @param i node index.
82 @return pointer to the requested vlib_node_t.
83*/
84
Ed Warnickecb9cada2015-12-08 15:45:58 -070085always_inline vlib_node_t *
86vlib_get_node (vlib_main_t * vm, u32 i)
Dave Barach9b8ffd92016-07-08 08:13:45 -040087{
88 return vec_elt (vm->node_main.nodes, i);
89}
Ed Warnickecb9cada2015-12-08 15:45:58 -070090
Dave Barach9770e202016-07-06 10:29:27 -040091/** \brief Get vlib node by graph arc (next) index.
92 @param vm vlib_main_t pointer, varies by thread
93 @param node_index index of original node
94 @param next_index graph arc index
95 @return pointer to the vlib_node_t at the end of the indicated arc
96*/
97
Ed Warnickecb9cada2015-12-08 15:45:58 -070098always_inline vlib_node_t *
99vlib_get_next_node (vlib_main_t * vm, u32 node_index, u32 next_index)
100{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400101 vlib_node_main_t *nm = &vm->node_main;
102 vlib_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103
104 n = vec_elt (nm->nodes, node_index);
105 ASSERT (next_index < vec_len (n->next_nodes));
106 return vlib_get_node (vm, n->next_nodes[next_index]);
107}
108
Dave Barach9770e202016-07-06 10:29:27 -0400109/** \brief Get node runtime by node index.
110 @param vm vlib_main_t pointer, varies by thread
111 @param node_index index of node
112 @return pointer to the indicated vlib_node_runtime_t
113*/
114
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115always_inline vlib_node_runtime_t *
116vlib_node_get_runtime (vlib_main_t * vm, u32 node_index)
117{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400118 vlib_node_main_t *nm = &vm->node_main;
119 vlib_node_t *n = vec_elt (nm->nodes, node_index);
120 vlib_process_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700121 if (n->type != VLIB_NODE_TYPE_PROCESS)
122 return vec_elt_at_index (nm->nodes_by_type[n->type], n->runtime_index);
123 else
124 {
125 p = vec_elt (nm->processes, n->runtime_index);
126 return &p->node_runtime;
127 }
128}
129
Dave Barach9770e202016-07-06 10:29:27 -0400130/** \brief Get node runtime private data by node index.
131 @param vm vlib_main_t pointer, varies by thread
132 @param node_index index of the node
133 @return pointer to the indicated vlib_node_runtime_t private data
134*/
135
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136always_inline void *
137vlib_node_get_runtime_data (vlib_main_t * vm, u32 node_index)
138{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400139 vlib_node_runtime_t *r = vlib_node_get_runtime (vm, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140 return r->runtime_data;
141}
142
Dave Barach9770e202016-07-06 10:29:27 -0400143/** \brief Set node runtime private data.
144 @param vm vlib_main_t pointer, varies by thread
145 @param node_index index of the node
146 @param runtime_data arbitrary runtime private data
147 @param n_runtime_data_bytes size of runtime private data
148*/
149
Ed Warnickecb9cada2015-12-08 15:45:58 -0700150always_inline void
151vlib_node_set_runtime_data (vlib_main_t * vm, u32 node_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400152 void *runtime_data, u32 n_runtime_data_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400154 vlib_node_t *n = vlib_get_node (vm, node_index);
155 vlib_node_runtime_t *r = vlib_node_get_runtime (vm, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156
157 n->runtime_data_bytes = n_runtime_data_bytes;
158 vec_free (n->runtime_data);
159 vec_add (n->runtime_data, runtime_data, n_runtime_data_bytes);
160
Damjan Marioneb90b7f2016-11-01 01:26:01 +0100161 ASSERT (vec_len (n->runtime_data) <= sizeof (vlib_node_runtime_t) -
162 STRUCT_OFFSET_OF (vlib_node_runtime_t, runtime_data));
163
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 if (vec_len (n->runtime_data) > 0)
Dave Barach178cf492018-11-13 16:34:13 -0500165 clib_memcpy_fast (r->runtime_data, n->runtime_data,
166 vec_len (n->runtime_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167}
168
Dave Barach9770e202016-07-06 10:29:27 -0400169/** \brief Set node dispatch state.
170 @param vm vlib_main_t pointer, varies by thread
171 @param node_index index of the node
172 @param new_state new state for node, see vlib_node_state_t
173*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400175vlib_node_set_state (vlib_main_t * vm, u32 node_index,
176 vlib_node_state_t new_state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400178 vlib_node_main_t *nm = &vm->node_main;
179 vlib_node_t *n;
180 vlib_node_runtime_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181
182 n = vec_elt (nm->nodes, node_index);
183 if (n->type == VLIB_NODE_TYPE_PROCESS)
184 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400185 vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 r = &p->node_runtime;
187
188 /* When disabling make sure flags are cleared. */
189 p->flags &= ~(VLIB_PROCESS_RESUME_PENDING
190 | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
191 | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT);
192 }
193 else
194 r = vec_elt_at_index (nm->nodes_by_type[n->type], n->runtime_index);
195
196 ASSERT (new_state < VLIB_N_NODE_STATE);
197
198 if (n->type == VLIB_NODE_TYPE_INPUT)
199 {
200 ASSERT (nm->input_node_counts_by_state[n->state] > 0);
201 nm->input_node_counts_by_state[n->state] -= 1;
202 nm->input_node_counts_by_state[new_state] += 1;
203 }
204
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +0000205 if (PREDICT_FALSE (r->state == VLIB_NODE_STATE_DISABLED))
206 vlib_node_runtime_perf_counter (vm, r, 0, 0, 0,
207 VLIB_NODE_RUNTIME_PERF_RESET);
208
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209 n->state = new_state;
210 r->state = new_state;
211}
212
Damjan Marion153646e2017-04-05 18:15:45 +0200213/** \brief Get node dispatch state.
214 @param vm vlib_main_t pointer, varies by thread
215 @param node_index index of the node
216 @return state for node, see vlib_node_state_t
217*/
218always_inline vlib_node_state_t
219vlib_node_get_state (vlib_main_t * vm, u32 node_index)
220{
221 vlib_node_main_t *nm = &vm->node_main;
222 vlib_node_t *n;
223 n = vec_elt (nm->nodes, node_index);
224 return n->state;
225}
226
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227always_inline void
Damjan Marion94100532020-11-06 23:25:57 +0100228vlib_node_set_interrupt_pending (vlib_main_t *vm, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400230 vlib_node_main_t *nm = &vm->node_main;
231 vlib_node_t *n = vec_elt (nm->nodes, node_index);
Damjan Marion94100532020-11-06 23:25:57 +0100232
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233 ASSERT (n->type == VLIB_NODE_TYPE_INPUT);
Damjan Marion1033b492020-06-03 12:20:41 +0200234
Damjan Marion94100532020-11-06 23:25:57 +0100235 if (vm != vlib_get_main ())
236 clib_interrupt_set_atomic (nm->interrupts, n->runtime_index);
Damjan Marion1033b492020-06-03 12:20:41 +0200237 else
Damjan Marion94100532020-11-06 23:25:57 +0100238 clib_interrupt_set (nm->interrupts, n->runtime_index);
Damjan Marion1033b492020-06-03 12:20:41 +0200239
Damjan Marion94100532020-11-06 23:25:57 +0100240 __atomic_store_n (nm->pending_interrupts, 1, __ATOMIC_RELEASE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241}
242
243always_inline vlib_process_t *
244vlib_get_process_from_node (vlib_main_t * vm, vlib_node_t * node)
245{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400246 vlib_node_main_t *nm = &vm->node_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 ASSERT (node->type == VLIB_NODE_TYPE_PROCESS);
248 return vec_elt (nm->processes, node->runtime_index);
249}
250
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251always_inline vlib_frame_t *
Andreas Schultz58b2eb12019-07-15 15:40:56 +0200252vlib_get_frame (vlib_main_t * vm, vlib_frame_t * f)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253{
Andreas Schultz58b2eb12019-07-15 15:40:56 +0200254 ASSERT (f != NULL);
Damjan Marion633b6fd2018-09-14 14:38:53 +0200255 ASSERT (f->frame_flags & VLIB_FRAME_IS_ALLOCATED);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256 return f;
257}
258
Damjan Marion296988d2019-02-21 20:24:54 +0100259always_inline void
260vlib_frame_no_append (vlib_frame_t * f)
261{
262 f->frame_flags |= VLIB_FRAME_NO_APPEND;
263}
264
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265/* Byte alignment for vector arguments. */
266#define VLIB_FRAME_VECTOR_ALIGN (1 << 4)
267
268always_inline u32
269vlib_frame_vector_byte_offset (u32 scalar_size)
270{
271 return round_pow2 (sizeof (vlib_frame_t) + scalar_size,
272 VLIB_FRAME_VECTOR_ALIGN);
273}
274
Dave Barach9770e202016-07-06 10:29:27 -0400275/** \brief Get pointer to frame vector data.
276 @param f vlib_frame_t pointer
277 @return pointer to first vector element in frame
278*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279always_inline void *
280vlib_frame_vector_args (vlib_frame_t * f)
281{
282 return (void *) f + vlib_frame_vector_byte_offset (f->scalar_size);
283}
284
Dave Barach9770e202016-07-06 10:29:27 -0400285/** \brief Get pointer to frame scalar data.
286
Dave Barach9770e202016-07-06 10:29:27 -0400287 @param f vlib_frame_t pointer
288
289 @return arbitrary node scalar data
290
291 @sa vlib_frame_vector_args
292*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293always_inline void *
Damjan Mariona3d59862018-11-10 10:23:00 +0100294vlib_frame_scalar_args (vlib_frame_t * f)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400295{
296 return vlib_frame_vector_args (f) - f->scalar_size;
297}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298
299always_inline vlib_next_frame_t *
300vlib_node_runtime_get_next_frame (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400301 vlib_node_runtime_t * n, u32 next_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400303 vlib_node_main_t *nm = &vm->node_main;
304 vlib_next_frame_t *nf;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305
306 ASSERT (next_index < n->n_next_nodes);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400307 nf = vec_elt_at_index (nm->next_frames, n->next_frame_index + next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700308
309 if (CLIB_DEBUG > 0)
310 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400311 vlib_node_t *node, *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700312 node = vec_elt (nm->nodes, n->node_index);
313 next = vec_elt (nm->nodes, node->next_nodes[next_index]);
314 ASSERT (nf->node_runtime_index == next->runtime_index);
315 }
316
317 return nf;
318}
319
Dave Barach9770e202016-07-06 10:29:27 -0400320/** \brief Get pointer to frame by (@c node_index, @c next_index).
321
322 @warning This is not a function that you should call directly.
323 See @ref vlib_get_next_frame instead.
324
325 @param vm vlib_main_t pointer, varies by thread
326 @param node_index index of the node
327 @param next_index graph arc index
328
329 @return pointer to the requested vlib_next_frame_t
330
331 @sa vlib_get_next_frame
332*/
333
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334always_inline vlib_next_frame_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400335vlib_node_get_next_frame (vlib_main_t * vm, u32 node_index, u32 next_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700336{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400337 vlib_node_main_t *nm = &vm->node_main;
338 vlib_node_t *n;
339 vlib_node_runtime_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340
341 n = vec_elt (nm->nodes, node_index);
342 r = vec_elt_at_index (nm->nodes_by_type[n->type], n->runtime_index);
343 return vlib_node_runtime_get_next_frame (vm, r, next_index);
344}
345
Dave Barach9b8ffd92016-07-08 08:13:45 -0400346vlib_frame_t *vlib_get_next_frame_internal (vlib_main_t * vm,
347 vlib_node_runtime_t * node,
348 u32 next_index,
349 u32 alloc_new_frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350
351#define vlib_get_next_frame_macro(vm,node,next_index,vectors,n_vectors_left,alloc_new_frame) \
352do { \
353 vlib_frame_t * _f \
354 = vlib_get_next_frame_internal ((vm), (node), (next_index), \
355 (alloc_new_frame)); \
356 u32 _n = _f->n_vectors; \
357 (vectors) = vlib_frame_vector_args (_f) + _n * sizeof ((vectors)[0]); \
358 (n_vectors_left) = VLIB_FRAME_SIZE - _n; \
359} while (0)
360
Dave Barach9770e202016-07-06 10:29:27 -0400361
Dave Barach9b8ffd92016-07-08 08:13:45 -0400362/** \brief Get pointer to next frame vector data by
Dave Barach9770e202016-07-06 10:29:27 -0400363 (@c vlib_node_runtime_t, @c next_index).
364 Standard single/dual loop boilerplate element.
365 @attention This is a MACRO, with SIDE EFFECTS.
366
367 @param vm vlib_main_t pointer, varies by thread
368 @param node current node vlib_node_runtime_t pointer
369 @param next_index requested graph arc index
370
371 @return @c vectors -- pointer to next available vector slot
372 @return @c n_vectors_left -- number of vector slots available
373*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700374#define vlib_get_next_frame(vm,node,next_index,vectors,n_vectors_left) \
375 vlib_get_next_frame_macro (vm, node, next_index, \
376 vectors, n_vectors_left, \
377 /* alloc new frame */ 0)
378
379#define vlib_get_new_next_frame(vm,node,next_index,vectors,n_vectors_left) \
380 vlib_get_next_frame_macro (vm, node, next_index, \
381 vectors, n_vectors_left, \
382 /* alloc new frame */ 1)
383
Dave Barach9770e202016-07-06 10:29:27 -0400384/** \brief Release pointer to next frame vector data.
385 Standard single/dual loop boilerplate element.
386 @param vm vlib_main_t pointer, varies by thread
387 @param r current node vlib_node_runtime_t pointer
388 @param next_index graph arc index
389 @param n_packets_left number of slots still available in vector
390*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391void
392vlib_put_next_frame (vlib_main_t * vm,
393 vlib_node_runtime_t * r,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400394 u32 next_index, u32 n_packets_left);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395
396/* Combination get plus put. Returns vector argument just added. */
397#define vlib_set_next_frame(vm,node,next_index,v) \
398({ \
399 uword _n_left; \
400 vlib_get_next_frame ((vm), (node), (next_index), (v), _n_left); \
401 ASSERT (_n_left > 0); \
402 vlib_put_next_frame ((vm), (node), (next_index), _n_left - 1); \
403 (v); \
404})
405
406always_inline void
407vlib_set_next_frame_buffer (vlib_main_t * vm,
408 vlib_node_runtime_t * node,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400409 u32 next_index, u32 buffer_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700410{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400411 u32 *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412 p = vlib_set_next_frame (vm, node, next_index, p);
413 p[0] = buffer_index;
414}
415
Dave Barach9b8ffd92016-07-08 08:13:45 -0400416vlib_frame_t *vlib_get_frame_to_node (vlib_main_t * vm, u32 to_node_index);
417void vlib_put_frame_to_node (vlib_main_t * vm, u32 to_node_index,
418 vlib_frame_t * f);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420always_inline uword
421vlib_in_process_context (vlib_main_t * vm)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400422{
423 return vm->node_main.current_process_index != ~0;
424}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425
Florin Coras66b11312017-07-31 17:18:03 -0700426always_inline vlib_process_t *
427vlib_get_current_process (vlib_main_t * vm)
428{
429 vlib_node_main_t *nm = &vm->node_main;
430 if (vlib_in_process_context (vm))
431 return vec_elt (nm->processes, nm->current_process_index);
432 return 0;
433}
434
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435always_inline uword
436vlib_current_process (vlib_main_t * vm)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400437{
438 return vlib_get_current_process (vm)->node_runtime.node_index;
439}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700440
Damjan Marion698eeb12020-09-11 14:11:11 +0200441always_inline u32
442vlib_get_current_process_node_index (vlib_main_t * vm)
443{
444 vlib_process_t *process = vlib_get_current_process (vm);
445 return process->node_runtime.node_index;
446}
447
Dave Barach5c20a012017-06-13 08:48:31 -0400448/** Returns TRUE if a process suspend time is less than 10us
Dave Barach2ab470a2016-08-10 18:38:36 -0400449 @param dt - remaining poll time in seconds
Dave Barach5c20a012017-06-13 08:48:31 -0400450 @returns 1 if dt < 10e-6, 0 otherwise
Dave Barach2ab470a2016-08-10 18:38:36 -0400451*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700452always_inline uword
453vlib_process_suspend_time_is_zero (f64 dt)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400454{
Dave Barach5c20a012017-06-13 08:48:31 -0400455 return dt < 10e-6;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400456}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700457
Dave Barach2ab470a2016-08-10 18:38:36 -0400458/** Suspend a vlib cooperative multi-tasking thread for a period of time
459 @param vm - vlib_main_t *
460 @param dt - suspend interval in seconds
461 @returns VLIB_PROCESS_RESUME_LONGJMP_RESUME, routinely ignored
462*/
463
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464always_inline uword
465vlib_process_suspend (vlib_main_t * vm, f64 dt)
466{
467 uword r;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400468 vlib_node_main_t *nm = &vm->node_main;
469 vlib_process_t *p = vec_elt (nm->processes, nm->current_process_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470
471 if (vlib_process_suspend_time_is_zero (dt))
472 return VLIB_PROCESS_RESUME_LONGJMP_RESUME;
473
474 p->flags |= VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK;
475 r = clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
476 if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
477 {
Dave Barach5c20a012017-06-13 08:48:31 -0400478 /* expiration time in 10us ticks */
479 p->resume_clock_interval = dt * 1e5;
Damjan Marioncea46522020-05-21 16:47:05 +0200480 vlib_process_start_switch_stack (vm, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481 clib_longjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
482 }
Damjan Marioncea46522020-05-21 16:47:05 +0200483 else
484 vlib_process_finish_switch_stack (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485
486 return r;
487}
488
489always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400490vlib_process_free_event_type (vlib_process_t * p, uword t,
491 uword is_one_time_event)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400493 ASSERT (!pool_is_free_index (p->event_type_pool, t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494 pool_put_index (p->event_type_pool, t);
495 if (is_one_time_event)
496 p->one_time_event_type_bitmap =
497 clib_bitmap_andnoti (p->one_time_event_type_bitmap, t);
498}
499
500always_inline void
501vlib_process_maybe_free_event_type (vlib_process_t * p, uword t)
502{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400503 ASSERT (!pool_is_free_index (p->event_type_pool, t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700504 if (clib_bitmap_get (p->one_time_event_type_bitmap, t))
505 vlib_process_free_event_type (p, t, /* is_one_time_event */ 1);
506}
507
508always_inline void *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400509vlib_process_get_event_data (vlib_main_t * vm,
510 uword * return_event_type_opaque)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700511{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400512 vlib_node_main_t *nm = &vm->node_main;
513 vlib_process_t *p;
514 vlib_process_event_type_t *et;
Gabriel Ganne71d73fe2017-02-04 10:51:04 +0100515 uword t;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400516 void *event_data_vector;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517
518 p = vec_elt (nm->processes, nm->current_process_index);
519
520 /* Find first type with events ready.
521 Return invalid type when there's nothing there. */
522 t = clib_bitmap_first_set (p->non_empty_event_type_bitmap);
523 if (t == ~0)
524 return 0;
525
Dave Barach9b8ffd92016-07-08 08:13:45 -0400526 p->non_empty_event_type_bitmap =
527 clib_bitmap_andnoti (p->non_empty_event_type_bitmap, t);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528
Gabriel Ganne71d73fe2017-02-04 10:51:04 +0100529 ASSERT (_vec_len (p->pending_event_data_by_type_index[t]) > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530 event_data_vector = p->pending_event_data_by_type_index[t];
531 p->pending_event_data_by_type_index[t] = 0;
532
533 et = pool_elt_at_index (p->event_type_pool, t);
534
535 /* Return user's opaque value and possibly index. */
536 *return_event_type_opaque = et->opaque;
537
538 vlib_process_maybe_free_event_type (p, t);
539
540 return event_data_vector;
541}
542
543/* Return event data vector for later reuse. We reuse event data to avoid
544 repeatedly allocating event vectors in cases where we care about speed. */
545always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400546vlib_process_put_event_data (vlib_main_t * vm, void *event_data)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400548 vlib_node_main_t *nm = &vm->node_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700549 vec_add1 (nm->recycled_event_data_vectors, event_data);
550}
551
Dave Barach2ab470a2016-08-10 18:38:36 -0400552/** Return the first event type which has occurred and a vector of per-event
553 data of that type, or a timeout indication
554
555 @param vm - vlib_main_t pointer
556 @param data_vector - pointer to a (uword *) vector to receive event data
557 @returns either an event type and a vector of per-event instance data,
558 or ~0 to indicate a timeout.
559*/
560
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561always_inline uword
562vlib_process_get_events (vlib_main_t * vm, uword ** data_vector)
563{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400564 vlib_node_main_t *nm = &vm->node_main;
565 vlib_process_t *p;
566 vlib_process_event_type_t *et;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700567 uword r, t, l;
568
569 p = vec_elt (nm->processes, nm->current_process_index);
570
571 /* Find first type with events ready.
572 Return invalid type when there's nothing there. */
573 t = clib_bitmap_first_set (p->non_empty_event_type_bitmap);
574 if (t == ~0)
575 return t;
576
Dave Barach9b8ffd92016-07-08 08:13:45 -0400577 p->non_empty_event_type_bitmap =
578 clib_bitmap_andnoti (p->non_empty_event_type_bitmap, t);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700579
580 l = _vec_len (p->pending_event_data_by_type_index[t]);
581 if (data_vector)
582 vec_add (*data_vector, p->pending_event_data_by_type_index[t], l);
583 _vec_len (p->pending_event_data_by_type_index[t]) = 0;
584
585 et = pool_elt_at_index (p->event_type_pool, t);
586
587 /* Return user's opaque value. */
588 r = et->opaque;
589
590 vlib_process_maybe_free_event_type (p, t);
591
592 return r;
593}
594
595always_inline uword
Dave Barach9b8ffd92016-07-08 08:13:45 -0400596vlib_process_get_events_helper (vlib_process_t * p, uword t,
597 uword ** data_vector)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700598{
599 uword l;
600
Dave Barach9b8ffd92016-07-08 08:13:45 -0400601 p->non_empty_event_type_bitmap =
602 clib_bitmap_andnoti (p->non_empty_event_type_bitmap, t);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700603
604 l = _vec_len (p->pending_event_data_by_type_index[t]);
605 if (data_vector)
606 vec_add (*data_vector, p->pending_event_data_by_type_index[t], l);
607 _vec_len (p->pending_event_data_by_type_index[t]) = 0;
608
609 vlib_process_maybe_free_event_type (p, t);
610
611 return l;
612}
613
614/* As above but query as specified type of event. Returns number of
615 events found. */
616always_inline uword
617vlib_process_get_events_with_type (vlib_main_t * vm, uword ** data_vector,
618 uword with_type_opaque)
619{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400620 vlib_node_main_t *nm = &vm->node_main;
621 vlib_process_t *p;
622 uword t, *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623
624 p = vec_elt (nm->processes, nm->current_process_index);
625 h = hash_get (p->event_type_index_by_type_opaque, with_type_opaque);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400626 if (!h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627 /* This can happen when an event has not yet been
628 signaled with given opaque type. */
629 return 0;
630
631 t = h[0];
Dave Barach9b8ffd92016-07-08 08:13:45 -0400632 if (!clib_bitmap_get (p->non_empty_event_type_bitmap, t))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633 return 0;
634
635 return vlib_process_get_events_helper (p, t, data_vector);
636}
637
638always_inline uword *
639vlib_process_wait_for_event (vlib_main_t * vm)
640{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400641 vlib_node_main_t *nm = &vm->node_main;
642 vlib_process_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643 uword r;
644
645 p = vec_elt (nm->processes, nm->current_process_index);
646 if (clib_bitmap_is_zero (p->non_empty_event_type_bitmap))
647 {
648 p->flags |= VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400649 r =
650 clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651 if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
Damjan Marioncea46522020-05-21 16:47:05 +0200652 {
653 vlib_process_start_switch_stack (vm, 0);
654 clib_longjmp (&p->return_longjmp,
655 VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
656 }
657 else
658 vlib_process_finish_switch_stack (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700659 }
660
661 return p->non_empty_event_type_bitmap;
662}
663
664always_inline uword
665vlib_process_wait_for_one_time_event (vlib_main_t * vm,
666 uword ** data_vector,
667 uword with_type_index)
668{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400669 vlib_node_main_t *nm = &vm->node_main;
670 vlib_process_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671 uword r;
672
673 p = vec_elt (nm->processes, nm->current_process_index);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400674 ASSERT (!pool_is_free_index (p->event_type_pool, with_type_index));
675 while (!clib_bitmap_get (p->non_empty_event_type_bitmap, with_type_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 {
677 p->flags |= VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400678 r =
679 clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680 if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
Damjan Marioncea46522020-05-21 16:47:05 +0200681 {
682 vlib_process_start_switch_stack (vm, 0);
683 clib_longjmp (&p->return_longjmp,
684 VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
685 }
686 else
687 vlib_process_finish_switch_stack (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688 }
689
690 return vlib_process_get_events_helper (p, with_type_index, data_vector);
691}
692
693always_inline uword
694vlib_process_wait_for_event_with_type (vlib_main_t * vm,
695 uword ** data_vector,
696 uword with_type_opaque)
697{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400698 vlib_node_main_t *nm = &vm->node_main;
699 vlib_process_t *p;
700 uword r, *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700701
702 p = vec_elt (nm->processes, nm->current_process_index);
703 h = hash_get (p->event_type_index_by_type_opaque, with_type_opaque);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400704 while (!h || !clib_bitmap_get (p->non_empty_event_type_bitmap, h[0]))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705 {
706 p->flags |= VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400707 r =
708 clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700709 if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
Damjan Marioncea46522020-05-21 16:47:05 +0200710 {
711 vlib_process_start_switch_stack (vm, 0);
712 clib_longjmp (&p->return_longjmp,
713 VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
714 }
715 else
716 vlib_process_finish_switch_stack (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700717
718 /* See if unknown event type has been signaled now. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400719 if (!h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700720 h = hash_get (p->event_type_index_by_type_opaque, with_type_opaque);
721 }
722
723 return vlib_process_get_events_helper (p, h[0], data_vector);
724}
725
Dave Barach2ab470a2016-08-10 18:38:36 -0400726/** Suspend a cooperative multi-tasking thread
727 Waits for an event, or for the indicated number of seconds to elapse
728 @param vm - vlib_main_t pointer
Damjan Marion607de1a2016-08-16 22:53:54 +0200729 @param dt - timeout, in seconds.
Dave Barach2ab470a2016-08-10 18:38:36 -0400730 @returns the remaining time interval
731*/
732
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733always_inline f64
734vlib_process_wait_for_event_or_clock (vlib_main_t * vm, f64 dt)
735{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400736 vlib_node_main_t *nm = &vm->node_main;
737 vlib_process_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700738 f64 wakeup_time;
739 uword r;
740
741 p = vec_elt (nm->processes, nm->current_process_index);
742
743 if (vlib_process_suspend_time_is_zero (dt)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400744 || !clib_bitmap_is_zero (p->non_empty_event_type_bitmap))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745 return dt;
746
747 wakeup_time = vlib_time_now (vm) + dt;
748
749 /* Suspend waiting for both clock and event to occur. */
750 p->flags |= (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT
751 | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK);
752
753 r = clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
754 if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
755 {
Dave Barach5c20a012017-06-13 08:48:31 -0400756 p->resume_clock_interval = dt * 1e5;
Damjan Marioncea46522020-05-21 16:47:05 +0200757 vlib_process_start_switch_stack (vm, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700758 clib_longjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
759 }
Damjan Marioncea46522020-05-21 16:47:05 +0200760 else
761 vlib_process_finish_switch_stack (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700762
763 /* Return amount of time still left to sleep.
764 If <= 0 then we've been waken up by the clock (and not an event). */
765 return wakeup_time - vlib_time_now (vm);
766}
767
768always_inline vlib_process_event_type_t *
769vlib_process_new_event_type (vlib_process_t * p, uword with_type_opaque)
770{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400771 vlib_process_event_type_t *et;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700772 pool_get (p->event_type_pool, et);
773 et->opaque = with_type_opaque;
774 return et;
775}
776
777always_inline uword
Dave Barach9b8ffd92016-07-08 08:13:45 -0400778vlib_process_create_one_time_event (vlib_main_t * vm, uword node_index,
779 uword with_type_opaque)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700780{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400781 vlib_node_main_t *nm = &vm->node_main;
782 vlib_node_t *n = vlib_get_node (vm, node_index);
783 vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
784 vlib_process_event_type_t *et;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700785 uword t;
786
787 et = vlib_process_new_event_type (p, with_type_opaque);
788 t = et - p->event_type_pool;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400789 p->one_time_event_type_bitmap =
790 clib_bitmap_ori (p->one_time_event_type_bitmap, t);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700791 return t;
792}
793
794always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400795vlib_process_delete_one_time_event (vlib_main_t * vm, uword node_index,
796 uword t)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700797{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400798 vlib_node_main_t *nm = &vm->node_main;
799 vlib_node_t *n = vlib_get_node (vm, node_index);
800 vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801
802 ASSERT (clib_bitmap_get (p->one_time_event_type_bitmap, t));
803 vlib_process_free_event_type (p, t, /* is_one_time_event */ 1);
804}
805
806always_inline void *
807vlib_process_signal_event_helper (vlib_node_main_t * nm,
808 vlib_node_t * n,
809 vlib_process_t * p,
810 uword t,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400811 uword n_data_elts, uword n_data_elt_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700812{
813 uword p_flags, add_to_pending, delete_from_wheel;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400814 void *data_to_be_written_by_caller;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815
Dave Barach1403fcd2018-02-05 09:45:43 -0500816 ASSERT (n->type == VLIB_NODE_TYPE_PROCESS);
817
Dave Barach9b8ffd92016-07-08 08:13:45 -0400818 ASSERT (!pool_is_free_index (p->event_type_pool, t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700819
820 vec_validate (p->pending_event_data_by_type_index, t);
821
822 /* Resize data vector and return caller's data to be written. */
823 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400824 void *data_vec = p->pending_event_data_by_type_index[t];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825 uword l;
826
Dave Barach9b8ffd92016-07-08 08:13:45 -0400827 if (!data_vec && vec_len (nm->recycled_event_data_vectors))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828 {
829 data_vec = vec_pop (nm->recycled_event_data_vectors);
830 _vec_len (data_vec) = 0;
831 }
832
833 l = vec_len (data_vec);
834
835 data_vec = _vec_resize (data_vec,
836 /* length_increment */ n_data_elts,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400837 /* total size after increment */
838 (l + n_data_elts) * n_data_elt_bytes,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839 /* header_bytes */ 0, /* data_align */ 0);
840
841 p->pending_event_data_by_type_index[t] = data_vec;
842 data_to_be_written_by_caller = data_vec + l * n_data_elt_bytes;
843 }
844
Dave Barach9b8ffd92016-07-08 08:13:45 -0400845 p->non_empty_event_type_bitmap =
846 clib_bitmap_ori (p->non_empty_event_type_bitmap, t);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700847
848 p_flags = p->flags;
849
850 /* Event was already signalled? */
851 add_to_pending = (p_flags & VLIB_PROCESS_RESUME_PENDING) == 0;
852
853 /* Process will resume when suspend time elapses? */
854 delete_from_wheel = 0;
855 if (p_flags & VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK)
856 {
857 /* Waiting for both event and clock? */
858 if (p_flags & VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT)
Florin Coras40f92462018-08-01 16:25:45 -0700859 {
860 if (!TW (tw_timer_handle_is_free)
861 ((TWT (tw_timer_wheel) *) nm->timing_wheel,
862 p->stop_timer_handle))
863 delete_from_wheel = 1;
864 else
865 /* timer just popped so process should already be on the list */
866 add_to_pending = 0;
867 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868 else
869 /* Waiting only for clock. Event will be queue and may be
870 handled when timer expires. */
871 add_to_pending = 0;
872 }
873
874 /* Never add current process to pending vector since current process is
875 already running. */
876 add_to_pending &= nm->current_process_index != n->runtime_index;
877
878 if (add_to_pending)
879 {
880 u32 x = vlib_timing_wheel_data_set_suspended_process (n->runtime_index);
881 p->flags = p_flags | VLIB_PROCESS_RESUME_PENDING;
882 vec_add1 (nm->data_from_advancing_timing_wheel, x);
883 if (delete_from_wheel)
Dave Barach5c20a012017-06-13 08:48:31 -0400884 TW (tw_timer_stop) ((TWT (tw_timer_wheel) *) nm->timing_wheel,
885 p->stop_timer_handle);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700886 }
887
888 return data_to_be_written_by_caller;
889}
890
891always_inline void *
892vlib_process_signal_event_data (vlib_main_t * vm,
893 uword node_index,
894 uword type_opaque,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400895 uword n_data_elts, uword n_data_elt_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400897 vlib_node_main_t *nm = &vm->node_main;
898 vlib_node_t *n = vlib_get_node (vm, node_index);
899 vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
900 uword *h, t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700901
John Lo609707e2017-09-19 21:45:10 -0400902 /* Must be in main thread */
903 ASSERT (vlib_get_thread_index () == 0);
904
Ed Warnickecb9cada2015-12-08 15:45:58 -0700905 h = hash_get (p->event_type_index_by_type_opaque, type_opaque);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400906 if (!h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400908 vlib_process_event_type_t *et =
909 vlib_process_new_event_type (p, type_opaque);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700910 t = et - p->event_type_pool;
911 hash_set (p->event_type_index_by_type_opaque, type_opaque, t);
912 }
913 else
914 t = h[0];
915
Dave Barach9b8ffd92016-07-08 08:13:45 -0400916 return vlib_process_signal_event_helper (nm, n, p, t, n_data_elts,
917 n_data_elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700918}
919
920always_inline void *
921vlib_process_signal_event_at_time (vlib_main_t * vm,
922 f64 dt,
923 uword node_index,
924 uword type_opaque,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400925 uword n_data_elts, uword n_data_elt_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700926{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400927 vlib_node_main_t *nm = &vm->node_main;
928 vlib_node_t *n = vlib_get_node (vm, node_index);
929 vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
930 uword *h, t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700931
932 h = hash_get (p->event_type_index_by_type_opaque, type_opaque);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400933 if (!h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400935 vlib_process_event_type_t *et =
936 vlib_process_new_event_type (p, type_opaque);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937 t = et - p->event_type_pool;
938 hash_set (p->event_type_index_by_type_opaque, type_opaque, t);
939 }
940 else
941 t = h[0];
942
943 if (vlib_process_suspend_time_is_zero (dt))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400944 return vlib_process_signal_event_helper (nm, n, p, t, n_data_elts,
945 n_data_elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946 else
947 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400948 vlib_signal_timed_event_data_t *te;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949
950 pool_get_aligned (nm->signal_timed_event_data_pool, te, sizeof (te[0]));
951
952 te->n_data_elts = n_data_elts;
953 te->n_data_elt_bytes = n_data_elt_bytes;
954 te->n_data_bytes = n_data_elts * n_data_elt_bytes;
955
956 /* Assert that structure fields are big enough. */
957 ASSERT (te->n_data_elts == n_data_elts);
958 ASSERT (te->n_data_elt_bytes == n_data_elt_bytes);
959 ASSERT (te->n_data_bytes == n_data_elts * n_data_elt_bytes);
960
961 te->process_node_index = n->runtime_index;
962 te->event_type_index = t;
963
Dave Barach5c20a012017-06-13 08:48:31 -0400964 p->stop_timer_handle =
965 TW (tw_timer_start) ((TWT (tw_timer_wheel) *) nm->timing_wheel,
966 vlib_timing_wheel_data_set_timed_event
967 (te - nm->signal_timed_event_data_pool),
968 0 /* timer_id */ ,
969 (vlib_time_now (vm) + dt) * 1e5);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700970
971 /* Inline data big enough to hold event? */
972 if (te->n_data_bytes < sizeof (te->inline_event_data))
973 return te->inline_event_data;
974 else
975 {
976 te->event_data_as_vector = 0;
977 vec_resize (te->event_data_as_vector, te->n_data_bytes);
978 return te->event_data_as_vector;
979 }
980 }
981}
982
983always_inline void *
984vlib_process_signal_one_time_event_data (vlib_main_t * vm,
985 uword node_index,
986 uword type_index,
987 uword n_data_elts,
988 uword n_data_elt_bytes)
989{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400990 vlib_node_main_t *nm = &vm->node_main;
991 vlib_node_t *n = vlib_get_node (vm, node_index);
992 vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
993 return vlib_process_signal_event_helper (nm, n, p, type_index, n_data_elts,
994 n_data_elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995}
996
997always_inline void
998vlib_process_signal_event (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400999 uword node_index, uword type_opaque, uword data)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001000{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001001 uword *d = vlib_process_signal_event_data (vm, node_index, type_opaque,
1002 1 /* elts */ , sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001003 d[0] = data;
1004}
1005
1006always_inline void
1007vlib_process_signal_event_pointer (vlib_main_t * vm,
1008 uword node_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -04001009 uword type_opaque, void *data)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001010{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001011 void **d = vlib_process_signal_event_data (vm, node_index, type_opaque,
1012 1 /* elts */ , sizeof (data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001013 d[0] = data;
1014}
1015
Dave Barach69128d02017-09-26 10:54:34 -04001016/**
1017 * Signal event to process from any thread.
1018 *
1019 * When in doubt, use this.
1020 */
1021always_inline void
1022vlib_process_signal_event_mt (vlib_main_t * vm,
1023 uword node_index, uword type_opaque, uword data)
1024{
1025 if (vlib_get_thread_index () != 0)
1026 {
1027 vlib_process_signal_event_mt_args_t args = {
1028 .node_index = node_index,
1029 .type_opaque = type_opaque,
1030 .data = data,
1031 };
1032 vlib_rpc_call_main_thread (vlib_process_signal_event_mt_helper,
1033 (u8 *) & args, sizeof (args));
1034 }
1035 else
1036 vlib_process_signal_event (vm, node_index, type_opaque, data);
1037}
1038
Ed Warnickecb9cada2015-12-08 15:45:58 -07001039always_inline void
1040vlib_process_signal_one_time_event (vlib_main_t * vm,
1041 uword node_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -04001042 uword type_index, uword data)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001044 uword *d =
1045 vlib_process_signal_one_time_event_data (vm, node_index, type_index,
1046 1 /* elts */ , sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 d[0] = data;
1048}
1049
1050always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -04001051vlib_signal_one_time_waiting_process (vlib_main_t * vm,
1052 vlib_one_time_waiting_process_t * p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001053{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001054 vlib_process_signal_one_time_event (vm, p->node_index, p->one_time_event,
1055 /* data */ ~0);
Dave Barachb7b92992018-10-17 10:38:51 -04001056 clib_memset (p, ~0, sizeof (p[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001057}
1058
1059always_inline void
1060vlib_signal_one_time_waiting_process_vector (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -04001061 vlib_one_time_waiting_process_t
1062 ** wps)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001064 vlib_one_time_waiting_process_t *wp;
1065 vec_foreach (wp, *wps) vlib_signal_one_time_waiting_process (vm, wp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001066 vec_free (*wps);
1067}
1068
1069always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -04001070vlib_current_process_wait_for_one_time_event (vlib_main_t * vm,
1071 vlib_one_time_waiting_process_t
1072 * p)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001073{
1074 p->node_index = vlib_current_process (vm);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001075 p->one_time_event = vlib_process_create_one_time_event (vm, p->node_index, /* type opaque */
1076 ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 vlib_process_wait_for_one_time_event (vm,
1078 /* don't care about data */ 0,
1079 p->one_time_event);
1080}
1081
1082always_inline void
1083vlib_current_process_wait_for_one_time_event_vector (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -04001084 vlib_one_time_waiting_process_t
1085 ** wps)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001086{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001087 vlib_one_time_waiting_process_t *wp;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088 vec_add2 (*wps, wp, 1);
1089 vlib_current_process_wait_for_one_time_event (vm, wp);
1090}
1091
1092always_inline u32
1093vlib_node_runtime_update_main_loop_vector_stats (vlib_main_t * vm,
1094 vlib_node_runtime_t * node,
1095 uword n_vectors)
1096{
1097 u32 i, d, vi0, vi1;
1098 u32 i0, i1;
1099
1100 ASSERT (is_pow2 (ARRAY_LEN (node->main_loop_vector_stats)));
1101 i = ((vm->main_loop_count >> VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE)
1102 & (ARRAY_LEN (node->main_loop_vector_stats) - 1));
1103 i0 = i ^ 0;
1104 i1 = i ^ 1;
1105 d = ((vm->main_loop_count >> VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001106 -
1107 (node->main_loop_count_last_dispatch >>
1108 VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001109 vi0 = node->main_loop_vector_stats[i0];
1110 vi1 = node->main_loop_vector_stats[i1];
1111 vi0 = d == 0 ? vi0 : 0;
1112 vi1 = d <= 1 ? vi1 : 0;
1113 vi0 += n_vectors;
1114 node->main_loop_vector_stats[i0] = vi0;
1115 node->main_loop_vector_stats[i1] = vi1;
1116 node->main_loop_count_last_dispatch = vm->main_loop_count;
1117 /* Return previous counter. */
1118 return node->main_loop_vector_stats[i1];
1119}
1120
1121always_inline f64
1122vlib_node_vectors_per_main_loop_as_float (vlib_main_t * vm, u32 node_index)
1123{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001124 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125 u32 v;
1126
Dave Barach9b8ffd92016-07-08 08:13:45 -04001127 v = vlib_node_runtime_update_main_loop_vector_stats (vm, rt, /* n_vectors */
1128 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001129 return (f64) v / (1 << VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE);
1130}
1131
1132always_inline u32
1133vlib_node_vectors_per_main_loop_as_integer (vlib_main_t * vm, u32 node_index)
1134{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001135 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001136 u32 v;
1137
Dave Barach9b8ffd92016-07-08 08:13:45 -04001138 v = vlib_node_runtime_update_main_loop_vector_stats (vm, rt, /* n_vectors */
1139 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001140 return v >> VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE;
1141}
1142
1143void
Dave Barach9b8ffd92016-07-08 08:13:45 -04001144vlib_frame_free (vlib_main_t * vm, vlib_node_runtime_t * r, vlib_frame_t * f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145
Neale Rannsbb620d72017-06-29 00:19:08 -07001146/* Return the edge index if present, ~0 otherwise */
1147uword vlib_node_get_next (vlib_main_t * vm, uword node, uword next_node);
1148
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149/* Add next node to given node in given slot. */
1150uword
1151vlib_node_add_next_with_slot (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -04001152 uword node, uword next_node, uword slot);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153
1154/* As above but adds to end of node's next vector. */
1155always_inline uword
1156vlib_node_add_next (vlib_main_t * vm, uword node, uword next_node)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001157{
1158 return vlib_node_add_next_with_slot (vm, node, next_node, ~0);
1159}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001160
1161/* Add next node to given node in given slot. */
1162uword
1163vlib_node_add_named_next_with_slot (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -04001164 uword node, char *next_name, uword slot);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165
1166/* As above but adds to end of node's next vector. */
1167always_inline uword
Dave Barach9b8ffd92016-07-08 08:13:45 -04001168vlib_node_add_named_next (vlib_main_t * vm, uword node, char *name)
1169{
1170 return vlib_node_add_named_next_with_slot (vm, node, name, ~0);
1171}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172
Florin Corase86a8ed2018-01-05 03:20:25 -08001173/**
1174 * Get list of nodes
1175 */
Dave Barach1ddbc012018-06-13 09:26:05 -04001176void
1177vlib_node_get_nodes (vlib_main_t * vm, u32 max_threads, int include_stats,
1178 int barrier_sync, vlib_node_t **** node_dupsp,
1179 vlib_main_t *** stat_vmsp);
Florin Corase86a8ed2018-01-05 03:20:25 -08001180
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181/* Query node given name. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001182vlib_node_t *vlib_get_node_by_name (vlib_main_t * vm, u8 * name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001183
1184/* Rename a node. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001185void vlib_node_rename (vlib_main_t * vm, u32 node_index, char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186
1187/* Register new packet processing node. Nodes can be registered
1188 dynamically via this call or statically via the VLIB_REGISTER_NODE
1189 macro. */
1190u32 vlib_register_node (vlib_main_t * vm, vlib_node_registration_t * r);
1191
1192/* Register all static nodes registered via VLIB_REGISTER_NODE. */
1193void vlib_register_all_static_nodes (vlib_main_t * vm);
1194
1195/* Start a process. */
1196void vlib_start_process (vlib_main_t * vm, uword process_index);
1197
1198/* Sync up runtime and main node stats. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001199void vlib_node_sync_stats (vlib_main_t * vm, vlib_node_t * n);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200
1201/* Node graph initialization function. */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001202clib_error_t *vlib_node_main_init (vlib_main_t * vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001203
1204format_function_t format_vlib_node_graph;
1205format_function_t format_vlib_node_name;
1206format_function_t format_vlib_next_node_name;
1207format_function_t format_vlib_node_and_next;
1208format_function_t format_vlib_cpu_time;
1209format_function_t format_vlib_time;
1210/* Parse node name -> node index. */
1211unformat_function_t unformat_vlib_node;
1212
Dave Barach9b8ffd92016-07-08 08:13:45 -04001213always_inline void
1214vlib_node_increment_counter (vlib_main_t * vm, u32 node_index,
1215 u32 counter_index, u64 increment)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001216{
Dave Barach9b8ffd92016-07-08 08:13:45 -04001217 vlib_node_t *n = vlib_get_node (vm, node_index);
1218 vlib_error_main_t *em = &vm->error_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219 u32 node_counter_base_index = n->error_heap_index;
1220 em->counters[node_counter_base_index + counter_index] += increment;
1221}
1222
Dave Barach11965c72019-05-28 16:31:05 -04001223/** @brief Create a vlib process
1224 * @param vm &vlib_global_main
1225 * @param f the process node function
1226 * @param log2_n_stack_bytes size of the process stack, defaults to 16K
1227 * @return newly-create node index
1228 * @warning call only on the main thread. Barrier sync required
1229 */
1230u32 vlib_process_create (vlib_main_t * vm, char *name,
1231 vlib_node_function_t * f, u32 log2_n_stack_bytes);
1232
Damjan Marion8b60fb02020-11-27 20:15:17 +01001233always_inline int
1234vlib_node_set_dispatch_wrapper (vlib_main_t *vm, vlib_node_function_t *fn)
1235{
1236 if (fn && vm->dispatch_wrapper_fn)
1237 return 1;
1238 vm->dispatch_wrapper_fn = fn;
1239 return 0;
1240}
1241
Ed Warnickecb9cada2015-12-08 15:45:58 -07001242#endif /* included_vlib_node_funcs_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001243
1244/*
1245 * fd.io coding-style-patch-verification: ON
1246 *
1247 * Local Variables:
1248 * eval: (c-set-style "gnu")
1249 * End:
1250 */