vlib: address sanitizer support for stack switch, enable clang
[vpp.git] / src / vlib / node_funcs.h
1 /*
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
40 /** \file
41     vlib node functions
42 */
43
44
45 #ifndef included_vlib_node_funcs_h
46 #define included_vlib_node_funcs_h
47
48 #include <vppinfra/fifo.h>
49 #include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
50
51 #ifdef CLIB_SANITIZE_ADDR
52 #include <sanitizer/asan_interface.h>
53 #endif
54
55 static_always_inline void
56 vlib_process_start_switch_stack (vlib_main_t * vm, vlib_process_t * p)
57 {
58 #ifdef CLIB_SANITIZE_ADDR
59   void *stack = p ? (void *) p->stack : vlib_thread_stacks[vm->thread_index];
60   u32 stack_bytes = p ? p->log2_n_stack_bytes : VLIB_THREAD_STACK_SIZE;
61   __sanitizer_start_switch_fiber (&vm->asan_stack_save, stack, stack_bytes);
62 #endif
63 }
64
65 static_always_inline void
66 vlib_process_finish_switch_stack (vlib_main_t * vm)
67 {
68 #ifdef CLIB_SANITIZE_ADDR
69   const void *bottom_old;
70   size_t size_old;
71
72   __sanitizer_finish_switch_fiber (&vm->asan_stack_save, &bottom_old,
73                                    &size_old);
74 #endif
75 }
76
77 /** \brief Get vlib node by index.
78  @warning This function will ASSERT if @c i is out of range.
79  @param vm vlib_main_t pointer, varies by thread
80  @param i node index.
81  @return pointer to the requested vlib_node_t.
82 */
83
84 always_inline vlib_node_t *
85 vlib_get_node (vlib_main_t * vm, u32 i)
86 {
87   return vec_elt (vm->node_main.nodes, i);
88 }
89
90 /** \brief Get vlib node by graph arc (next) index.
91  @param vm vlib_main_t pointer, varies by thread
92  @param node_index index of original node
93  @param next_index graph arc index
94  @return pointer to the vlib_node_t at the end of the indicated arc
95 */
96
97 always_inline vlib_node_t *
98 vlib_get_next_node (vlib_main_t * vm, u32 node_index, u32 next_index)
99 {
100   vlib_node_main_t *nm = &vm->node_main;
101   vlib_node_t *n;
102
103   n = vec_elt (nm->nodes, node_index);
104   ASSERT (next_index < vec_len (n->next_nodes));
105   return vlib_get_node (vm, n->next_nodes[next_index]);
106 }
107
108 /** \brief Get node runtime by node index.
109  @param vm vlib_main_t pointer, varies by thread
110  @param node_index index of node
111  @return pointer to the indicated vlib_node_runtime_t
112 */
113
114 always_inline vlib_node_runtime_t *
115 vlib_node_get_runtime (vlib_main_t * vm, u32 node_index)
116 {
117   vlib_node_main_t *nm = &vm->node_main;
118   vlib_node_t *n = vec_elt (nm->nodes, node_index);
119   vlib_process_t *p;
120   if (n->type != VLIB_NODE_TYPE_PROCESS)
121     return vec_elt_at_index (nm->nodes_by_type[n->type], n->runtime_index);
122   else
123     {
124       p = vec_elt (nm->processes, n->runtime_index);
125       return &p->node_runtime;
126     }
127 }
128
129 /** \brief Get node runtime private data by node index.
130  @param vm vlib_main_t pointer, varies by thread
131  @param node_index index of the node
132  @return pointer to the indicated vlib_node_runtime_t private data
133 */
134
135 always_inline void *
136 vlib_node_get_runtime_data (vlib_main_t * vm, u32 node_index)
137 {
138   vlib_node_runtime_t *r = vlib_node_get_runtime (vm, node_index);
139   return r->runtime_data;
140 }
141
142 /** \brief Set node runtime private data.
143  @param vm vlib_main_t pointer, varies by thread
144  @param node_index index of the node
145  @param runtime_data arbitrary runtime private data
146  @param n_runtime_data_bytes size of runtime private data
147 */
148
149 always_inline void
150 vlib_node_set_runtime_data (vlib_main_t * vm, u32 node_index,
151                             void *runtime_data, u32 n_runtime_data_bytes)
152 {
153   vlib_node_t *n = vlib_get_node (vm, node_index);
154   vlib_node_runtime_t *r = vlib_node_get_runtime (vm, node_index);
155
156   n->runtime_data_bytes = n_runtime_data_bytes;
157   vec_free (n->runtime_data);
158   vec_add (n->runtime_data, runtime_data, n_runtime_data_bytes);
159
160   ASSERT (vec_len (n->runtime_data) <= sizeof (vlib_node_runtime_t) -
161           STRUCT_OFFSET_OF (vlib_node_runtime_t, runtime_data));
162
163   if (vec_len (n->runtime_data) > 0)
164     clib_memcpy_fast (r->runtime_data, n->runtime_data,
165                       vec_len (n->runtime_data));
166 }
167
168 /** \brief Set node dispatch state.
169  @param vm vlib_main_t pointer, varies by thread
170  @param node_index index of the node
171  @param new_state new state for node, see vlib_node_state_t
172 */
173 always_inline void
174 vlib_node_set_state (vlib_main_t * vm, u32 node_index,
175                      vlib_node_state_t new_state)
176 {
177   vlib_node_main_t *nm = &vm->node_main;
178   vlib_node_t *n;
179   vlib_node_runtime_t *r;
180
181   n = vec_elt (nm->nodes, node_index);
182   if (n->type == VLIB_NODE_TYPE_PROCESS)
183     {
184       vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
185       r = &p->node_runtime;
186
187       /* When disabling make sure flags are cleared. */
188       p->flags &= ~(VLIB_PROCESS_RESUME_PENDING
189                     | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
190                     | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT);
191     }
192   else
193     r = vec_elt_at_index (nm->nodes_by_type[n->type], n->runtime_index);
194
195   ASSERT (new_state < VLIB_N_NODE_STATE);
196
197   if (n->type == VLIB_NODE_TYPE_INPUT)
198     {
199       ASSERT (nm->input_node_counts_by_state[n->state] > 0);
200       nm->input_node_counts_by_state[n->state] -= 1;
201       nm->input_node_counts_by_state[new_state] += 1;
202     }
203
204   n->state = new_state;
205   r->state = new_state;
206 }
207
208 /** \brief Get node dispatch state.
209  @param vm vlib_main_t pointer, varies by thread
210  @param node_index index of the node
211  @return state for node, see vlib_node_state_t
212 */
213 always_inline vlib_node_state_t
214 vlib_node_get_state (vlib_main_t * vm, u32 node_index)
215 {
216   vlib_node_main_t *nm = &vm->node_main;
217   vlib_node_t *n;
218   n = vec_elt (nm->nodes, node_index);
219   return n->state;
220 }
221
222 always_inline void
223 vlib_node_set_interrupt_pending_with_data (vlib_main_t * vm, u32 node_index,
224                                            u32 data)
225 {
226   vlib_node_main_t *nm = &vm->node_main;
227   vlib_node_t *n = vec_elt (nm->nodes, node_index);
228   vlib_node_interrupt_t *i;
229   ASSERT (n->type == VLIB_NODE_TYPE_INPUT);
230
231   if (vm == vlib_get_main ())
232     {
233       /* local thread */
234       vec_add2 (nm->pending_local_interrupts, i, 1);
235       i->node_runtime_index = n->runtime_index;
236       i->data = data;
237     }
238   else
239     {
240       /* remote thread */
241       clib_spinlock_lock (&nm->pending_interrupt_lock);
242       vec_add2 (nm->pending_remote_interrupts, i, 1);
243       i->node_runtime_index = n->runtime_index;
244       i->data = data;
245       clib_spinlock_unlock (&nm->pending_interrupt_lock);
246     }
247 }
248
249 always_inline void
250 vlib_node_set_interrupt_pending (vlib_main_t * vm, u32 node_index)
251 {
252   vlib_node_set_interrupt_pending_with_data (vm, node_index, 0);
253 }
254
255 always_inline vlib_process_t *
256 vlib_get_process_from_node (vlib_main_t * vm, vlib_node_t * node)
257 {
258   vlib_node_main_t *nm = &vm->node_main;
259   ASSERT (node->type == VLIB_NODE_TYPE_PROCESS);
260   return vec_elt (nm->processes, node->runtime_index);
261 }
262
263 always_inline vlib_frame_t *
264 vlib_get_frame (vlib_main_t * vm, vlib_frame_t * f)
265 {
266   ASSERT (f != NULL);
267   ASSERT (f->frame_flags & VLIB_FRAME_IS_ALLOCATED);
268   return f;
269 }
270
271 always_inline void
272 vlib_frame_no_append (vlib_frame_t * f)
273 {
274   f->frame_flags |= VLIB_FRAME_NO_APPEND;
275 }
276
277 /* Byte alignment for vector arguments. */
278 #define VLIB_FRAME_VECTOR_ALIGN (1 << 4)
279
280 always_inline u32
281 vlib_frame_vector_byte_offset (u32 scalar_size)
282 {
283   return round_pow2 (sizeof (vlib_frame_t) + scalar_size,
284                      VLIB_FRAME_VECTOR_ALIGN);
285 }
286
287 /** \brief Get pointer to frame vector data.
288  @param f vlib_frame_t pointer
289  @return pointer to first vector element in frame
290 */
291 always_inline void *
292 vlib_frame_vector_args (vlib_frame_t * f)
293 {
294   return (void *) f + vlib_frame_vector_byte_offset (f->scalar_size);
295 }
296
297 /** \brief Get pointer to frame scalar data.
298
299  @param f vlib_frame_t pointer
300
301  @return arbitrary node scalar data
302
303  @sa vlib_frame_vector_args
304 */
305 always_inline void *
306 vlib_frame_scalar_args (vlib_frame_t * f)
307 {
308   return vlib_frame_vector_args (f) - f->scalar_size;
309 }
310
311 always_inline vlib_next_frame_t *
312 vlib_node_runtime_get_next_frame (vlib_main_t * vm,
313                                   vlib_node_runtime_t * n, u32 next_index)
314 {
315   vlib_node_main_t *nm = &vm->node_main;
316   vlib_next_frame_t *nf;
317
318   ASSERT (next_index < n->n_next_nodes);
319   nf = vec_elt_at_index (nm->next_frames, n->next_frame_index + next_index);
320
321   if (CLIB_DEBUG > 0)
322     {
323       vlib_node_t *node, *next;
324       node = vec_elt (nm->nodes, n->node_index);
325       next = vec_elt (nm->nodes, node->next_nodes[next_index]);
326       ASSERT (nf->node_runtime_index == next->runtime_index);
327     }
328
329   return nf;
330 }
331
332 /** \brief Get pointer to frame by (@c node_index, @c next_index).
333
334  @warning This is not a function that you should call directly.
335  See @ref vlib_get_next_frame instead.
336
337  @param vm vlib_main_t pointer, varies by thread
338  @param node_index index of the node
339  @param next_index graph arc index
340
341  @return pointer to the requested vlib_next_frame_t
342
343  @sa vlib_get_next_frame
344 */
345
346 always_inline vlib_next_frame_t *
347 vlib_node_get_next_frame (vlib_main_t * vm, u32 node_index, u32 next_index)
348 {
349   vlib_node_main_t *nm = &vm->node_main;
350   vlib_node_t *n;
351   vlib_node_runtime_t *r;
352
353   n = vec_elt (nm->nodes, node_index);
354   r = vec_elt_at_index (nm->nodes_by_type[n->type], n->runtime_index);
355   return vlib_node_runtime_get_next_frame (vm, r, next_index);
356 }
357
358 vlib_frame_t *vlib_get_next_frame_internal (vlib_main_t * vm,
359                                             vlib_node_runtime_t * node,
360                                             u32 next_index,
361                                             u32 alloc_new_frame);
362
363 #define vlib_get_next_frame_macro(vm,node,next_index,vectors,n_vectors_left,alloc_new_frame) \
364 do {                                                                    \
365   vlib_frame_t * _f                                                     \
366     = vlib_get_next_frame_internal ((vm), (node), (next_index),         \
367                                     (alloc_new_frame));                 \
368   u32 _n = _f->n_vectors;                                               \
369   (vectors) = vlib_frame_vector_args (_f) + _n * sizeof ((vectors)[0]); \
370   (n_vectors_left) = VLIB_FRAME_SIZE - _n;                              \
371 } while (0)
372
373
374 /** \brief Get pointer to next frame vector data by
375     (@c vlib_node_runtime_t, @c next_index).
376  Standard single/dual loop boilerplate element.
377  @attention This is a MACRO, with SIDE EFFECTS.
378
379  @param vm vlib_main_t pointer, varies by thread
380  @param node current node vlib_node_runtime_t pointer
381  @param next_index requested graph arc index
382
383  @return @c vectors -- pointer to next available vector slot
384  @return @c n_vectors_left -- number of vector slots available
385 */
386 #define vlib_get_next_frame(vm,node,next_index,vectors,n_vectors_left)  \
387   vlib_get_next_frame_macro (vm, node, next_index,                      \
388                              vectors, n_vectors_left,                   \
389                              /* alloc new frame */ 0)
390
391 #define vlib_get_new_next_frame(vm,node,next_index,vectors,n_vectors_left) \
392   vlib_get_next_frame_macro (vm, node, next_index,                      \
393                              vectors, n_vectors_left,                   \
394                              /* alloc new frame */ 1)
395
396 /** \brief Release pointer to next frame vector data.
397  Standard single/dual loop boilerplate element.
398  @param vm vlib_main_t pointer, varies by thread
399  @param r current node vlib_node_runtime_t pointer
400  @param next_index graph arc index
401  @param n_packets_left number of slots still available in vector
402 */
403 void
404 vlib_put_next_frame (vlib_main_t * vm,
405                      vlib_node_runtime_t * r,
406                      u32 next_index, u32 n_packets_left);
407
408 /* Combination get plus put.  Returns vector argument just added. */
409 #define vlib_set_next_frame(vm,node,next_index,v)                       \
410 ({                                                                      \
411   uword _n_left;                                                        \
412   vlib_get_next_frame ((vm), (node), (next_index), (v), _n_left);       \
413   ASSERT (_n_left > 0);                                                 \
414   vlib_put_next_frame ((vm), (node), (next_index), _n_left - 1);        \
415   (v);                                                                  \
416 })
417
418 always_inline void
419 vlib_set_next_frame_buffer (vlib_main_t * vm,
420                             vlib_node_runtime_t * node,
421                             u32 next_index, u32 buffer_index)
422 {
423   u32 *p;
424   p = vlib_set_next_frame (vm, node, next_index, p);
425   p[0] = buffer_index;
426 }
427
428 vlib_frame_t *vlib_get_frame_to_node (vlib_main_t * vm, u32 to_node_index);
429 void vlib_put_frame_to_node (vlib_main_t * vm, u32 to_node_index,
430                              vlib_frame_t * f);
431
432 always_inline uword
433 vlib_in_process_context (vlib_main_t * vm)
434 {
435   return vm->node_main.current_process_index != ~0;
436 }
437
438 always_inline vlib_process_t *
439 vlib_get_current_process (vlib_main_t * vm)
440 {
441   vlib_node_main_t *nm = &vm->node_main;
442   if (vlib_in_process_context (vm))
443     return vec_elt (nm->processes, nm->current_process_index);
444   return 0;
445 }
446
447 always_inline uword
448 vlib_current_process (vlib_main_t * vm)
449 {
450   return vlib_get_current_process (vm)->node_runtime.node_index;
451 }
452
453 /** Returns TRUE if a process suspend time is less than 10us
454     @param dt - remaining poll time in seconds
455     @returns 1 if dt < 10e-6, 0 otherwise
456 */
457 always_inline uword
458 vlib_process_suspend_time_is_zero (f64 dt)
459 {
460   return dt < 10e-6;
461 }
462
463 /** Suspend a vlib cooperative multi-tasking thread for a period of time
464     @param vm - vlib_main_t *
465     @param dt - suspend interval in seconds
466     @returns VLIB_PROCESS_RESUME_LONGJMP_RESUME, routinely ignored
467 */
468
469 always_inline uword
470 vlib_process_suspend (vlib_main_t * vm, f64 dt)
471 {
472   uword r;
473   vlib_node_main_t *nm = &vm->node_main;
474   vlib_process_t *p = vec_elt (nm->processes, nm->current_process_index);
475
476   if (vlib_process_suspend_time_is_zero (dt))
477     return VLIB_PROCESS_RESUME_LONGJMP_RESUME;
478
479   p->flags |= VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK;
480   r = clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
481   if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
482     {
483       /* expiration time in 10us ticks */
484       p->resume_clock_interval = dt * 1e5;
485       vlib_process_start_switch_stack (vm, 0);
486       clib_longjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
487     }
488   else
489     vlib_process_finish_switch_stack (vm);
490
491   return r;
492 }
493
494 always_inline void
495 vlib_process_free_event_type (vlib_process_t * p, uword t,
496                               uword is_one_time_event)
497 {
498   ASSERT (!pool_is_free_index (p->event_type_pool, t));
499   pool_put_index (p->event_type_pool, t);
500   if (is_one_time_event)
501     p->one_time_event_type_bitmap =
502       clib_bitmap_andnoti (p->one_time_event_type_bitmap, t);
503 }
504
505 always_inline void
506 vlib_process_maybe_free_event_type (vlib_process_t * p, uword t)
507 {
508   ASSERT (!pool_is_free_index (p->event_type_pool, t));
509   if (clib_bitmap_get (p->one_time_event_type_bitmap, t))
510     vlib_process_free_event_type (p, t, /* is_one_time_event */ 1);
511 }
512
513 always_inline void *
514 vlib_process_get_event_data (vlib_main_t * vm,
515                              uword * return_event_type_opaque)
516 {
517   vlib_node_main_t *nm = &vm->node_main;
518   vlib_process_t *p;
519   vlib_process_event_type_t *et;
520   uword t;
521   void *event_data_vector;
522
523   p = vec_elt (nm->processes, nm->current_process_index);
524
525   /* Find first type with events ready.
526      Return invalid type when there's nothing there. */
527   t = clib_bitmap_first_set (p->non_empty_event_type_bitmap);
528   if (t == ~0)
529     return 0;
530
531   p->non_empty_event_type_bitmap =
532     clib_bitmap_andnoti (p->non_empty_event_type_bitmap, t);
533
534   ASSERT (_vec_len (p->pending_event_data_by_type_index[t]) > 0);
535   event_data_vector = p->pending_event_data_by_type_index[t];
536   p->pending_event_data_by_type_index[t] = 0;
537
538   et = pool_elt_at_index (p->event_type_pool, t);
539
540   /* Return user's opaque value and possibly index. */
541   *return_event_type_opaque = et->opaque;
542
543   vlib_process_maybe_free_event_type (p, t);
544
545   return event_data_vector;
546 }
547
548 /* Return event data vector for later reuse.  We reuse event data to avoid
549    repeatedly allocating event vectors in cases where we care about speed. */
550 always_inline void
551 vlib_process_put_event_data (vlib_main_t * vm, void *event_data)
552 {
553   vlib_node_main_t *nm = &vm->node_main;
554   vec_add1 (nm->recycled_event_data_vectors, event_data);
555 }
556
557 /** Return the first event type which has occurred and a vector of per-event
558     data of that type, or a timeout indication
559
560     @param vm - vlib_main_t pointer
561     @param data_vector - pointer to a (uword *) vector to receive event data
562     @returns either an event type and a vector of per-event instance data,
563     or ~0 to indicate a timeout.
564 */
565
566 always_inline uword
567 vlib_process_get_events (vlib_main_t * vm, uword ** data_vector)
568 {
569   vlib_node_main_t *nm = &vm->node_main;
570   vlib_process_t *p;
571   vlib_process_event_type_t *et;
572   uword r, t, l;
573
574   p = vec_elt (nm->processes, nm->current_process_index);
575
576   /* Find first type with events ready.
577      Return invalid type when there's nothing there. */
578   t = clib_bitmap_first_set (p->non_empty_event_type_bitmap);
579   if (t == ~0)
580     return t;
581
582   p->non_empty_event_type_bitmap =
583     clib_bitmap_andnoti (p->non_empty_event_type_bitmap, t);
584
585   l = _vec_len (p->pending_event_data_by_type_index[t]);
586   if (data_vector)
587     vec_add (*data_vector, p->pending_event_data_by_type_index[t], l);
588   _vec_len (p->pending_event_data_by_type_index[t]) = 0;
589
590   et = pool_elt_at_index (p->event_type_pool, t);
591
592   /* Return user's opaque value. */
593   r = et->opaque;
594
595   vlib_process_maybe_free_event_type (p, t);
596
597   return r;
598 }
599
600 always_inline uword
601 vlib_process_get_events_helper (vlib_process_t * p, uword t,
602                                 uword ** data_vector)
603 {
604   uword l;
605
606   p->non_empty_event_type_bitmap =
607     clib_bitmap_andnoti (p->non_empty_event_type_bitmap, t);
608
609   l = _vec_len (p->pending_event_data_by_type_index[t]);
610   if (data_vector)
611     vec_add (*data_vector, p->pending_event_data_by_type_index[t], l);
612   _vec_len (p->pending_event_data_by_type_index[t]) = 0;
613
614   vlib_process_maybe_free_event_type (p, t);
615
616   return l;
617 }
618
619 /* As above but query as specified type of event.  Returns number of
620    events found. */
621 always_inline uword
622 vlib_process_get_events_with_type (vlib_main_t * vm, uword ** data_vector,
623                                    uword with_type_opaque)
624 {
625   vlib_node_main_t *nm = &vm->node_main;
626   vlib_process_t *p;
627   uword t, *h;
628
629   p = vec_elt (nm->processes, nm->current_process_index);
630   h = hash_get (p->event_type_index_by_type_opaque, with_type_opaque);
631   if (!h)
632     /* This can happen when an event has not yet been
633        signaled with given opaque type. */
634     return 0;
635
636   t = h[0];
637   if (!clib_bitmap_get (p->non_empty_event_type_bitmap, t))
638     return 0;
639
640   return vlib_process_get_events_helper (p, t, data_vector);
641 }
642
643 always_inline uword *
644 vlib_process_wait_for_event (vlib_main_t * vm)
645 {
646   vlib_node_main_t *nm = &vm->node_main;
647   vlib_process_t *p;
648   uword r;
649
650   p = vec_elt (nm->processes, nm->current_process_index);
651   if (clib_bitmap_is_zero (p->non_empty_event_type_bitmap))
652     {
653       p->flags |= VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT;
654       r =
655         clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
656       if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
657         {
658           vlib_process_start_switch_stack (vm, 0);
659           clib_longjmp (&p->return_longjmp,
660                         VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
661         }
662       else
663         vlib_process_finish_switch_stack (vm);
664     }
665
666   return p->non_empty_event_type_bitmap;
667 }
668
669 always_inline uword
670 vlib_process_wait_for_one_time_event (vlib_main_t * vm,
671                                       uword ** data_vector,
672                                       uword with_type_index)
673 {
674   vlib_node_main_t *nm = &vm->node_main;
675   vlib_process_t *p;
676   uword r;
677
678   p = vec_elt (nm->processes, nm->current_process_index);
679   ASSERT (!pool_is_free_index (p->event_type_pool, with_type_index));
680   while (!clib_bitmap_get (p->non_empty_event_type_bitmap, with_type_index))
681     {
682       p->flags |= VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT;
683       r =
684         clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
685       if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
686         {
687           vlib_process_start_switch_stack (vm, 0);
688           clib_longjmp (&p->return_longjmp,
689                         VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
690         }
691       else
692         vlib_process_finish_switch_stack (vm);
693     }
694
695   return vlib_process_get_events_helper (p, with_type_index, data_vector);
696 }
697
698 always_inline uword
699 vlib_process_wait_for_event_with_type (vlib_main_t * vm,
700                                        uword ** data_vector,
701                                        uword with_type_opaque)
702 {
703   vlib_node_main_t *nm = &vm->node_main;
704   vlib_process_t *p;
705   uword r, *h;
706
707   p = vec_elt (nm->processes, nm->current_process_index);
708   h = hash_get (p->event_type_index_by_type_opaque, with_type_opaque);
709   while (!h || !clib_bitmap_get (p->non_empty_event_type_bitmap, h[0]))
710     {
711       p->flags |= VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT;
712       r =
713         clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
714       if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
715         {
716           vlib_process_start_switch_stack (vm, 0);
717           clib_longjmp (&p->return_longjmp,
718                         VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
719         }
720       else
721         vlib_process_finish_switch_stack (vm);
722
723       /* See if unknown event type has been signaled now. */
724       if (!h)
725         h = hash_get (p->event_type_index_by_type_opaque, with_type_opaque);
726     }
727
728   return vlib_process_get_events_helper (p, h[0], data_vector);
729 }
730
731 /** Suspend a cooperative multi-tasking thread
732     Waits for an event, or for the indicated number of seconds to elapse
733     @param vm - vlib_main_t pointer
734     @param dt - timeout, in seconds.
735     @returns the remaining time interval
736 */
737
738 always_inline f64
739 vlib_process_wait_for_event_or_clock (vlib_main_t * vm, f64 dt)
740 {
741   vlib_node_main_t *nm = &vm->node_main;
742   vlib_process_t *p;
743   f64 wakeup_time;
744   uword r;
745
746   p = vec_elt (nm->processes, nm->current_process_index);
747
748   if (vlib_process_suspend_time_is_zero (dt)
749       || !clib_bitmap_is_zero (p->non_empty_event_type_bitmap))
750     return dt;
751
752   wakeup_time = vlib_time_now (vm) + dt;
753
754   /* Suspend waiting for both clock and event to occur. */
755   p->flags |= (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT
756                | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK);
757
758   r = clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
759   if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
760     {
761       p->resume_clock_interval = dt * 1e5;
762       vlib_process_start_switch_stack (vm, 0);
763       clib_longjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
764     }
765   else
766     vlib_process_finish_switch_stack (vm);
767
768   /* Return amount of time still left to sleep.
769      If <= 0 then we've been waken up by the clock (and not an event). */
770   return wakeup_time - vlib_time_now (vm);
771 }
772
773 always_inline vlib_process_event_type_t *
774 vlib_process_new_event_type (vlib_process_t * p, uword with_type_opaque)
775 {
776   vlib_process_event_type_t *et;
777   pool_get (p->event_type_pool, et);
778   et->opaque = with_type_opaque;
779   return et;
780 }
781
782 always_inline uword
783 vlib_process_create_one_time_event (vlib_main_t * vm, uword node_index,
784                                     uword with_type_opaque)
785 {
786   vlib_node_main_t *nm = &vm->node_main;
787   vlib_node_t *n = vlib_get_node (vm, node_index);
788   vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
789   vlib_process_event_type_t *et;
790   uword t;
791
792   et = vlib_process_new_event_type (p, with_type_opaque);
793   t = et - p->event_type_pool;
794   p->one_time_event_type_bitmap =
795     clib_bitmap_ori (p->one_time_event_type_bitmap, t);
796   return t;
797 }
798
799 always_inline void
800 vlib_process_delete_one_time_event (vlib_main_t * vm, uword node_index,
801                                     uword t)
802 {
803   vlib_node_main_t *nm = &vm->node_main;
804   vlib_node_t *n = vlib_get_node (vm, node_index);
805   vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
806
807   ASSERT (clib_bitmap_get (p->one_time_event_type_bitmap, t));
808   vlib_process_free_event_type (p, t, /* is_one_time_event */ 1);
809 }
810
811 always_inline void *
812 vlib_process_signal_event_helper (vlib_node_main_t * nm,
813                                   vlib_node_t * n,
814                                   vlib_process_t * p,
815                                   uword t,
816                                   uword n_data_elts, uword n_data_elt_bytes)
817 {
818   uword p_flags, add_to_pending, delete_from_wheel;
819   void *data_to_be_written_by_caller;
820
821   ASSERT (n->type == VLIB_NODE_TYPE_PROCESS);
822
823   ASSERT (!pool_is_free_index (p->event_type_pool, t));
824
825   vec_validate (p->pending_event_data_by_type_index, t);
826
827   /* Resize data vector and return caller's data to be written. */
828   {
829     void *data_vec = p->pending_event_data_by_type_index[t];
830     uword l;
831
832     if (!data_vec && vec_len (nm->recycled_event_data_vectors))
833       {
834         data_vec = vec_pop (nm->recycled_event_data_vectors);
835         _vec_len (data_vec) = 0;
836       }
837
838     l = vec_len (data_vec);
839
840     data_vec = _vec_resize (data_vec,
841                             /* length_increment */ n_data_elts,
842                             /* total size after increment */
843                             (l + n_data_elts) * n_data_elt_bytes,
844                             /* header_bytes */ 0, /* data_align */ 0);
845
846     p->pending_event_data_by_type_index[t] = data_vec;
847     data_to_be_written_by_caller = data_vec + l * n_data_elt_bytes;
848   }
849
850   p->non_empty_event_type_bitmap =
851     clib_bitmap_ori (p->non_empty_event_type_bitmap, t);
852
853   p_flags = p->flags;
854
855   /* Event was already signalled? */
856   add_to_pending = (p_flags & VLIB_PROCESS_RESUME_PENDING) == 0;
857
858   /* Process will resume when suspend time elapses? */
859   delete_from_wheel = 0;
860   if (p_flags & VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK)
861     {
862       /* Waiting for both event and clock? */
863       if (p_flags & VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT)
864         {
865           if (!TW (tw_timer_handle_is_free)
866               ((TWT (tw_timer_wheel) *) nm->timing_wheel,
867                p->stop_timer_handle))
868             delete_from_wheel = 1;
869           else
870             /* timer just popped so process should already be on the list */
871             add_to_pending = 0;
872         }
873       else
874         /* Waiting only for clock.  Event will be queue and may be
875            handled when timer expires. */
876         add_to_pending = 0;
877     }
878
879   /* Never add current process to pending vector since current process is
880      already running. */
881   add_to_pending &= nm->current_process_index != n->runtime_index;
882
883   if (add_to_pending)
884     {
885       u32 x = vlib_timing_wheel_data_set_suspended_process (n->runtime_index);
886       p->flags = p_flags | VLIB_PROCESS_RESUME_PENDING;
887       vec_add1 (nm->data_from_advancing_timing_wheel, x);
888       if (delete_from_wheel)
889         TW (tw_timer_stop) ((TWT (tw_timer_wheel) *) nm->timing_wheel,
890                             p->stop_timer_handle);
891     }
892
893   return data_to_be_written_by_caller;
894 }
895
896 always_inline void *
897 vlib_process_signal_event_data (vlib_main_t * vm,
898                                 uword node_index,
899                                 uword type_opaque,
900                                 uword n_data_elts, uword n_data_elt_bytes)
901 {
902   vlib_node_main_t *nm = &vm->node_main;
903   vlib_node_t *n = vlib_get_node (vm, node_index);
904   vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
905   uword *h, t;
906
907   /* Must be in main thread */
908   ASSERT (vlib_get_thread_index () == 0);
909
910   h = hash_get (p->event_type_index_by_type_opaque, type_opaque);
911   if (!h)
912     {
913       vlib_process_event_type_t *et =
914         vlib_process_new_event_type (p, type_opaque);
915       t = et - p->event_type_pool;
916       hash_set (p->event_type_index_by_type_opaque, type_opaque, t);
917     }
918   else
919     t = h[0];
920
921   return vlib_process_signal_event_helper (nm, n, p, t, n_data_elts,
922                                            n_data_elt_bytes);
923 }
924
925 always_inline void *
926 vlib_process_signal_event_at_time (vlib_main_t * vm,
927                                    f64 dt,
928                                    uword node_index,
929                                    uword type_opaque,
930                                    uword n_data_elts, uword n_data_elt_bytes)
931 {
932   vlib_node_main_t *nm = &vm->node_main;
933   vlib_node_t *n = vlib_get_node (vm, node_index);
934   vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
935   uword *h, t;
936
937   h = hash_get (p->event_type_index_by_type_opaque, type_opaque);
938   if (!h)
939     {
940       vlib_process_event_type_t *et =
941         vlib_process_new_event_type (p, type_opaque);
942       t = et - p->event_type_pool;
943       hash_set (p->event_type_index_by_type_opaque, type_opaque, t);
944     }
945   else
946     t = h[0];
947
948   if (vlib_process_suspend_time_is_zero (dt))
949     return vlib_process_signal_event_helper (nm, n, p, t, n_data_elts,
950                                              n_data_elt_bytes);
951   else
952     {
953       vlib_signal_timed_event_data_t *te;
954
955       pool_get_aligned (nm->signal_timed_event_data_pool, te, sizeof (te[0]));
956
957       te->n_data_elts = n_data_elts;
958       te->n_data_elt_bytes = n_data_elt_bytes;
959       te->n_data_bytes = n_data_elts * n_data_elt_bytes;
960
961       /* Assert that structure fields are big enough. */
962       ASSERT (te->n_data_elts == n_data_elts);
963       ASSERT (te->n_data_elt_bytes == n_data_elt_bytes);
964       ASSERT (te->n_data_bytes == n_data_elts * n_data_elt_bytes);
965
966       te->process_node_index = n->runtime_index;
967       te->event_type_index = t;
968
969       p->stop_timer_handle =
970         TW (tw_timer_start) ((TWT (tw_timer_wheel) *) nm->timing_wheel,
971                              vlib_timing_wheel_data_set_timed_event
972                              (te - nm->signal_timed_event_data_pool),
973                              0 /* timer_id */ ,
974                              (vlib_time_now (vm) + dt) * 1e5);
975
976       /* Inline data big enough to hold event? */
977       if (te->n_data_bytes < sizeof (te->inline_event_data))
978         return te->inline_event_data;
979       else
980         {
981           te->event_data_as_vector = 0;
982           vec_resize (te->event_data_as_vector, te->n_data_bytes);
983           return te->event_data_as_vector;
984         }
985     }
986 }
987
988 always_inline void *
989 vlib_process_signal_one_time_event_data (vlib_main_t * vm,
990                                          uword node_index,
991                                          uword type_index,
992                                          uword n_data_elts,
993                                          uword n_data_elt_bytes)
994 {
995   vlib_node_main_t *nm = &vm->node_main;
996   vlib_node_t *n = vlib_get_node (vm, node_index);
997   vlib_process_t *p = vec_elt (nm->processes, n->runtime_index);
998   return vlib_process_signal_event_helper (nm, n, p, type_index, n_data_elts,
999                                            n_data_elt_bytes);
1000 }
1001
1002 always_inline void
1003 vlib_process_signal_event (vlib_main_t * vm,
1004                            uword node_index, uword type_opaque, uword data)
1005 {
1006   uword *d = vlib_process_signal_event_data (vm, node_index, type_opaque,
1007                                              1 /* elts */ , sizeof (uword));
1008   d[0] = data;
1009 }
1010
1011 always_inline void
1012 vlib_process_signal_event_pointer (vlib_main_t * vm,
1013                                    uword node_index,
1014                                    uword type_opaque, void *data)
1015 {
1016   void **d = vlib_process_signal_event_data (vm, node_index, type_opaque,
1017                                              1 /* elts */ , sizeof (data));
1018   d[0] = data;
1019 }
1020
1021 /**
1022  * Signal event to process from any thread.
1023  *
1024  * When in doubt, use this.
1025  */
1026 always_inline void
1027 vlib_process_signal_event_mt (vlib_main_t * vm,
1028                               uword node_index, uword type_opaque, uword data)
1029 {
1030   if (vlib_get_thread_index () != 0)
1031     {
1032       vlib_process_signal_event_mt_args_t args = {
1033         .node_index = node_index,
1034         .type_opaque = type_opaque,
1035         .data = data,
1036       };
1037       vlib_rpc_call_main_thread (vlib_process_signal_event_mt_helper,
1038                                  (u8 *) & args, sizeof (args));
1039     }
1040   else
1041     vlib_process_signal_event (vm, node_index, type_opaque, data);
1042 }
1043
1044 always_inline void
1045 vlib_process_signal_one_time_event (vlib_main_t * vm,
1046                                     uword node_index,
1047                                     uword type_index, uword data)
1048 {
1049   uword *d =
1050     vlib_process_signal_one_time_event_data (vm, node_index, type_index,
1051                                              1 /* elts */ , sizeof (uword));
1052   d[0] = data;
1053 }
1054
1055 always_inline void
1056 vlib_signal_one_time_waiting_process (vlib_main_t * vm,
1057                                       vlib_one_time_waiting_process_t * p)
1058 {
1059   vlib_process_signal_one_time_event (vm, p->node_index, p->one_time_event,
1060                                       /* data */ ~0);
1061   clib_memset (p, ~0, sizeof (p[0]));
1062 }
1063
1064 always_inline void
1065 vlib_signal_one_time_waiting_process_vector (vlib_main_t * vm,
1066                                              vlib_one_time_waiting_process_t
1067                                              ** wps)
1068 {
1069   vlib_one_time_waiting_process_t *wp;
1070   vec_foreach (wp, *wps) vlib_signal_one_time_waiting_process (vm, wp);
1071   vec_free (*wps);
1072 }
1073
1074 always_inline void
1075 vlib_current_process_wait_for_one_time_event (vlib_main_t * vm,
1076                                               vlib_one_time_waiting_process_t
1077                                               * p)
1078 {
1079   p->node_index = vlib_current_process (vm);
1080   p->one_time_event = vlib_process_create_one_time_event (vm, p->node_index,    /* type opaque */
1081                                                           ~0);
1082   vlib_process_wait_for_one_time_event (vm,
1083                                         /* don't care about data */ 0,
1084                                         p->one_time_event);
1085 }
1086
1087 always_inline void
1088 vlib_current_process_wait_for_one_time_event_vector (vlib_main_t * vm,
1089                                                      vlib_one_time_waiting_process_t
1090                                                      ** wps)
1091 {
1092   vlib_one_time_waiting_process_t *wp;
1093   vec_add2 (*wps, wp, 1);
1094   vlib_current_process_wait_for_one_time_event (vm, wp);
1095 }
1096
1097 always_inline u32
1098 vlib_node_runtime_update_main_loop_vector_stats (vlib_main_t * vm,
1099                                                  vlib_node_runtime_t * node,
1100                                                  uword n_vectors)
1101 {
1102   u32 i, d, vi0, vi1;
1103   u32 i0, i1;
1104
1105   ASSERT (is_pow2 (ARRAY_LEN (node->main_loop_vector_stats)));
1106   i = ((vm->main_loop_count >> VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE)
1107        & (ARRAY_LEN (node->main_loop_vector_stats) - 1));
1108   i0 = i ^ 0;
1109   i1 = i ^ 1;
1110   d = ((vm->main_loop_count >> VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE)
1111        -
1112        (node->main_loop_count_last_dispatch >>
1113         VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE));
1114   vi0 = node->main_loop_vector_stats[i0];
1115   vi1 = node->main_loop_vector_stats[i1];
1116   vi0 = d == 0 ? vi0 : 0;
1117   vi1 = d <= 1 ? vi1 : 0;
1118   vi0 += n_vectors;
1119   node->main_loop_vector_stats[i0] = vi0;
1120   node->main_loop_vector_stats[i1] = vi1;
1121   node->main_loop_count_last_dispatch = vm->main_loop_count;
1122   /* Return previous counter. */
1123   return node->main_loop_vector_stats[i1];
1124 }
1125
1126 always_inline f64
1127 vlib_node_vectors_per_main_loop_as_float (vlib_main_t * vm, u32 node_index)
1128 {
1129   vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, node_index);
1130   u32 v;
1131
1132   v = vlib_node_runtime_update_main_loop_vector_stats (vm, rt,  /* n_vectors */
1133                                                        0);
1134   return (f64) v / (1 << VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE);
1135 }
1136
1137 always_inline u32
1138 vlib_node_vectors_per_main_loop_as_integer (vlib_main_t * vm, u32 node_index)
1139 {
1140   vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, node_index);
1141   u32 v;
1142
1143   v = vlib_node_runtime_update_main_loop_vector_stats (vm, rt,  /* n_vectors */
1144                                                        0);
1145   return v >> VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE;
1146 }
1147
1148 void
1149 vlib_frame_free (vlib_main_t * vm, vlib_node_runtime_t * r, vlib_frame_t * f);
1150
1151 /* Return the edge index if present, ~0 otherwise */
1152 uword vlib_node_get_next (vlib_main_t * vm, uword node, uword next_node);
1153
1154 /* Add next node to given node in given slot. */
1155 uword
1156 vlib_node_add_next_with_slot (vlib_main_t * vm,
1157                               uword node, uword next_node, uword slot);
1158
1159 /* As above but adds to end of node's next vector. */
1160 always_inline uword
1161 vlib_node_add_next (vlib_main_t * vm, uword node, uword next_node)
1162 {
1163   return vlib_node_add_next_with_slot (vm, node, next_node, ~0);
1164 }
1165
1166 /* Add next node to given node in given slot. */
1167 uword
1168 vlib_node_add_named_next_with_slot (vlib_main_t * vm,
1169                                     uword node, char *next_name, uword slot);
1170
1171 /* As above but adds to end of node's next vector. */
1172 always_inline uword
1173 vlib_node_add_named_next (vlib_main_t * vm, uword node, char *name)
1174 {
1175   return vlib_node_add_named_next_with_slot (vm, node, name, ~0);
1176 }
1177
1178 /**
1179  * Get list of nodes
1180  */
1181 void
1182 vlib_node_get_nodes (vlib_main_t * vm, u32 max_threads, int include_stats,
1183                      int barrier_sync, vlib_node_t **** node_dupsp,
1184                      vlib_main_t *** stat_vmsp);
1185
1186 /* Query node given name. */
1187 vlib_node_t *vlib_get_node_by_name (vlib_main_t * vm, u8 * name);
1188
1189 /* Rename a node. */
1190 void vlib_node_rename (vlib_main_t * vm, u32 node_index, char *fmt, ...);
1191
1192 /* Register new packet processing node.  Nodes can be registered
1193    dynamically via this call or statically via the VLIB_REGISTER_NODE
1194    macro. */
1195 u32 vlib_register_node (vlib_main_t * vm, vlib_node_registration_t * r);
1196
1197 /* Register all static nodes registered via VLIB_REGISTER_NODE. */
1198 void vlib_register_all_static_nodes (vlib_main_t * vm);
1199
1200 /* Start a process. */
1201 void vlib_start_process (vlib_main_t * vm, uword process_index);
1202
1203 /* Sync up runtime and main node stats. */
1204 void vlib_node_sync_stats (vlib_main_t * vm, vlib_node_t * n);
1205
1206 /* Node graph initialization function. */
1207 clib_error_t *vlib_node_main_init (vlib_main_t * vm);
1208
1209 format_function_t format_vlib_node_graph;
1210 format_function_t format_vlib_node_name;
1211 format_function_t format_vlib_next_node_name;
1212 format_function_t format_vlib_node_and_next;
1213 format_function_t format_vlib_cpu_time;
1214 format_function_t format_vlib_time;
1215 /* Parse node name -> node index. */
1216 unformat_function_t unformat_vlib_node;
1217
1218 always_inline void
1219 vlib_node_increment_counter (vlib_main_t * vm, u32 node_index,
1220                              u32 counter_index, u64 increment)
1221 {
1222   vlib_node_t *n = vlib_get_node (vm, node_index);
1223   vlib_error_main_t *em = &vm->error_main;
1224   u32 node_counter_base_index = n->error_heap_index;
1225   em->counters[node_counter_base_index + counter_index] += increment;
1226 }
1227
1228 /** @brief Create a vlib process
1229  *  @param vm &vlib_global_main
1230  *  @param f the process node function
1231  *  @param log2_n_stack_bytes size of the process stack, defaults to 16K
1232  *  @return newly-create node index
1233  *  @warning call only on the main thread. Barrier sync required
1234  */
1235 u32 vlib_process_create (vlib_main_t * vm, char *name,
1236                          vlib_node_function_t * f, u32 log2_n_stack_bytes);
1237
1238 #endif /* included_vlib_node_funcs_h */
1239
1240 /*
1241  * fd.io coding-style-patch-verification: ON
1242  *
1243  * Local Variables:
1244  * eval: (c-set-style "gnu")
1245  * End:
1246  */