stats: counters data model
[vpp.git] / src / vlib / main.c
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  * main.c: main vector processing loop
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 #include <math.h>
41 #include <vppinfra/format.h>
42 #include <vlib/vlib.h>
43 #include <vlib/threads.h>
44 #include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
45
46 #include <vlib/unix/unix.h>
47
48 /* Actually allocate a few extra slots of vector data to support
49    speculative vector enqueues which overflow vector data in next frame. */
50 #define VLIB_FRAME_SIZE_ALLOC (VLIB_FRAME_SIZE + 4)
51
52 always_inline u32
53 vlib_frame_bytes (u32 n_scalar_bytes, u32 n_vector_bytes)
54 {
55   u32 n_bytes;
56
57   /* Make room for vlib_frame_t plus scalar arguments. */
58   n_bytes = vlib_frame_vector_byte_offset (n_scalar_bytes);
59
60   /* Make room for vector arguments.
61      Allocate a few extra slots of vector data to support
62      speculative vector enqueues which overflow vector data in next frame. */
63 #define VLIB_FRAME_SIZE_EXTRA 4
64   n_bytes += (VLIB_FRAME_SIZE + VLIB_FRAME_SIZE_EXTRA) * n_vector_bytes;
65
66   /* Magic number is first 32bit number after vector data.
67      Used to make sure that vector data is never overrun. */
68 #define VLIB_FRAME_MAGIC (0xabadc0ed)
69   n_bytes += sizeof (u32);
70
71   /* Pad to cache line. */
72   n_bytes = round_pow2 (n_bytes, CLIB_CACHE_LINE_BYTES);
73
74   return n_bytes;
75 }
76
77 always_inline u32 *
78 vlib_frame_find_magic (vlib_frame_t * f, vlib_node_t * node)
79 {
80   void *p = f;
81
82   p += vlib_frame_vector_byte_offset (node->scalar_size);
83
84   p += (VLIB_FRAME_SIZE + VLIB_FRAME_SIZE_EXTRA) * node->vector_size;
85
86   return p;
87 }
88
89 static inline vlib_frame_size_t *
90 get_frame_size_info (vlib_node_main_t * nm,
91                      u32 n_scalar_bytes, u32 n_vector_bytes)
92 {
93 #ifdef VLIB_SUPPORTS_ARBITRARY_SCALAR_SIZES
94   uword key = (n_scalar_bytes << 16) | n_vector_bytes;
95   uword *p, i;
96
97   p = hash_get (nm->frame_size_hash, key);
98   if (p)
99     i = p[0];
100   else
101     {
102       i = vec_len (nm->frame_sizes);
103       vec_validate (nm->frame_sizes, i);
104       hash_set (nm->frame_size_hash, key, i);
105     }
106
107   return vec_elt_at_index (nm->frame_sizes, i);
108 #else
109   ASSERT (vlib_frame_bytes (n_scalar_bytes, n_vector_bytes)
110           == (vlib_frame_bytes (0, 4)));
111   return vec_elt_at_index (nm->frame_sizes, 0);
112 #endif
113 }
114
115 static vlib_frame_t *
116 vlib_frame_alloc_to_node (vlib_main_t * vm, u32 to_node_index,
117                           u32 frame_flags)
118 {
119   vlib_node_main_t *nm = &vm->node_main;
120   vlib_frame_size_t *fs;
121   vlib_node_t *to_node;
122   vlib_frame_t *f;
123   u32 l, n, scalar_size, vector_size;
124
125   to_node = vlib_get_node (vm, to_node_index);
126
127   scalar_size = to_node->scalar_size;
128   vector_size = to_node->vector_size;
129
130   fs = get_frame_size_info (nm, scalar_size, vector_size);
131   n = vlib_frame_bytes (scalar_size, vector_size);
132   if ((l = vec_len (fs->free_frames)) > 0)
133     {
134       /* Allocate from end of free list. */
135       f = fs->free_frames[l - 1];
136       _vec_len (fs->free_frames) = l - 1;
137     }
138   else
139     {
140       f = clib_mem_alloc_aligned_no_fail (n, VLIB_FRAME_ALIGN);
141     }
142
143   /* Poison frame when debugging. */
144   if (CLIB_DEBUG > 0)
145     clib_memset (f, 0xfe, n);
146
147   /* Insert magic number. */
148   {
149     u32 *magic;
150
151     magic = vlib_frame_find_magic (f, to_node);
152     *magic = VLIB_FRAME_MAGIC;
153   }
154
155   f->frame_flags = VLIB_FRAME_IS_ALLOCATED | frame_flags;
156   f->n_vectors = 0;
157   f->scalar_size = scalar_size;
158   f->vector_size = vector_size;
159   f->flags = 0;
160
161   fs->n_alloc_frames += 1;
162
163   return f;
164 }
165
166 /* Allocate a frame for from FROM_NODE to TO_NODE via TO_NEXT_INDEX.
167    Returns frame index. */
168 static vlib_frame_t *
169 vlib_frame_alloc (vlib_main_t * vm, vlib_node_runtime_t * from_node_runtime,
170                   u32 to_next_index)
171 {
172   vlib_node_t *from_node;
173
174   from_node = vlib_get_node (vm, from_node_runtime->node_index);
175   ASSERT (to_next_index < vec_len (from_node->next_nodes));
176
177   return vlib_frame_alloc_to_node (vm, from_node->next_nodes[to_next_index],
178                                    /* frame_flags */ 0);
179 }
180
181 vlib_frame_t *
182 vlib_get_frame_to_node (vlib_main_t * vm, u32 to_node_index)
183 {
184   vlib_frame_t *f = vlib_frame_alloc_to_node (vm, to_node_index,
185                                               /* frame_flags */
186                                               VLIB_FRAME_FREE_AFTER_DISPATCH);
187   return vlib_get_frame (vm, f);
188 }
189
190 static inline void
191 vlib_validate_frame_indices (vlib_frame_t * f)
192 {
193   if (CLIB_DEBUG > 0)
194     {
195       int i;
196       u32 *from = vlib_frame_vector_args (f);
197
198       /* Check for bad buffer index values */
199       for (i = 0; i < f->n_vectors; i++)
200         {
201           if (from[i] == 0)
202             {
203               clib_warning ("BUG: buffer index 0 at index %d", i);
204               ASSERT (0);
205             }
206           else if (from[i] == 0xfefefefe)
207             {
208               clib_warning ("BUG: frame poison pattern at index %d", i);
209               ASSERT (0);
210             }
211         }
212     }
213 }
214
215 void
216 vlib_put_frame_to_node (vlib_main_t * vm, u32 to_node_index, vlib_frame_t * f)
217 {
218   vlib_pending_frame_t *p;
219   vlib_node_t *to_node;
220
221   if (f->n_vectors == 0)
222     return;
223
224   vlib_validate_frame_indices (f);
225
226   to_node = vlib_get_node (vm, to_node_index);
227
228   vec_add2 (vm->node_main.pending_frames, p, 1);
229
230   f->frame_flags |= VLIB_FRAME_PENDING;
231   p->frame = vlib_get_frame (vm, f);
232   p->node_runtime_index = to_node->runtime_index;
233   p->next_frame_index = VLIB_PENDING_FRAME_NO_NEXT_FRAME;
234 }
235
236 /* Free given frame. */
237 void
238 vlib_frame_free (vlib_main_t * vm, vlib_node_runtime_t * r, vlib_frame_t * f)
239 {
240   vlib_node_main_t *nm = &vm->node_main;
241   vlib_node_t *node;
242   vlib_frame_size_t *fs;
243
244   ASSERT (f->frame_flags & VLIB_FRAME_IS_ALLOCATED);
245
246   node = vlib_get_node (vm, r->node_index);
247   fs = get_frame_size_info (nm, node->scalar_size, node->vector_size);
248
249   ASSERT (f->frame_flags & VLIB_FRAME_IS_ALLOCATED);
250
251   /* No next frames may point to freed frame. */
252   if (CLIB_DEBUG > 0)
253     {
254       vlib_next_frame_t *nf;
255       vec_foreach (nf, vm->node_main.next_frames) ASSERT (nf->frame != f);
256     }
257
258   f->frame_flags &= ~(VLIB_FRAME_IS_ALLOCATED | VLIB_FRAME_NO_APPEND);
259
260   vec_add1 (fs->free_frames, f);
261   ASSERT (fs->n_alloc_frames > 0);
262   fs->n_alloc_frames -= 1;
263 }
264
265 static clib_error_t *
266 show_frame_stats (vlib_main_t * vm,
267                   unformat_input_t * input, vlib_cli_command_t * cmd)
268 {
269   vlib_node_main_t *nm = &vm->node_main;
270   vlib_frame_size_t *fs;
271
272   vlib_cli_output (vm, "%=6s%=12s%=12s", "Size", "# Alloc", "# Free");
273   vec_foreach (fs, nm->frame_sizes)
274   {
275     u32 n_alloc = fs->n_alloc_frames;
276     u32 n_free = vec_len (fs->free_frames);
277
278     if (n_alloc + n_free > 0)
279       vlib_cli_output (vm, "%=6d%=12d%=12d",
280                        fs - nm->frame_sizes, n_alloc, n_free);
281   }
282
283   return 0;
284 }
285
286 /* *INDENT-OFF* */
287 VLIB_CLI_COMMAND (show_frame_stats_cli, static) = {
288   .path = "show vlib frame-allocation",
289   .short_help = "Show node dispatch frame statistics",
290   .function = show_frame_stats,
291 };
292 /* *INDENT-ON* */
293
294 /* Change ownership of enqueue rights to given next node. */
295 static void
296 vlib_next_frame_change_ownership (vlib_main_t * vm,
297                                   vlib_node_runtime_t * node_runtime,
298                                   u32 next_index)
299 {
300   vlib_node_main_t *nm = &vm->node_main;
301   vlib_next_frame_t *next_frame;
302   vlib_node_t *node, *next_node;
303
304   node = vec_elt (nm->nodes, node_runtime->node_index);
305
306   /* Only internal & input nodes are allowed to call other nodes. */
307   ASSERT (node->type == VLIB_NODE_TYPE_INTERNAL
308           || node->type == VLIB_NODE_TYPE_INPUT
309           || node->type == VLIB_NODE_TYPE_PROCESS);
310
311   ASSERT (vec_len (node->next_nodes) == node_runtime->n_next_nodes);
312
313   next_frame =
314     vlib_node_runtime_get_next_frame (vm, node_runtime, next_index);
315   next_node = vec_elt (nm->nodes, node->next_nodes[next_index]);
316
317   if (next_node->owner_node_index != VLIB_INVALID_NODE_INDEX)
318     {
319       /* Get frame from previous owner. */
320       vlib_next_frame_t *owner_next_frame;
321       vlib_next_frame_t tmp;
322
323       owner_next_frame =
324         vlib_node_get_next_frame (vm,
325                                   next_node->owner_node_index,
326                                   next_node->owner_next_index);
327
328       /* Swap target next frame with owner's. */
329       tmp = owner_next_frame[0];
330       owner_next_frame[0] = next_frame[0];
331       next_frame[0] = tmp;
332
333       /*
334        * If next_frame is already pending, we have to track down
335        * all pending frames and fix their next_frame_index fields.
336        */
337       if (next_frame->flags & VLIB_FRAME_PENDING)
338         {
339           vlib_pending_frame_t *p;
340           if (next_frame->frame != NULL)
341             {
342               vec_foreach (p, nm->pending_frames)
343               {
344                 if (p->frame == next_frame->frame)
345                   {
346                     p->next_frame_index =
347                       next_frame - vm->node_main.next_frames;
348                   }
349               }
350             }
351         }
352     }
353   else
354     {
355       /* No previous owner. Take ownership. */
356       next_frame->flags |= VLIB_FRAME_OWNER;
357     }
358
359   /* Record new owner. */
360   next_node->owner_node_index = node->index;
361   next_node->owner_next_index = next_index;
362
363   /* Now we should be owner. */
364   ASSERT (next_frame->flags & VLIB_FRAME_OWNER);
365 }
366
367 /* Make sure that magic number is still there.
368    Otherwise, it is likely that caller has overrun frame arguments. */
369 always_inline void
370 validate_frame_magic (vlib_main_t * vm,
371                       vlib_frame_t * f, vlib_node_t * n, uword next_index)
372 {
373   vlib_node_t *next_node = vlib_get_node (vm, n->next_nodes[next_index]);
374   u32 *magic = vlib_frame_find_magic (f, next_node);
375   ASSERT (VLIB_FRAME_MAGIC == magic[0]);
376 }
377
378 vlib_frame_t *
379 vlib_get_next_frame_internal (vlib_main_t * vm,
380                               vlib_node_runtime_t * node,
381                               u32 next_index, u32 allocate_new_next_frame)
382 {
383   vlib_frame_t *f;
384   vlib_next_frame_t *nf;
385   u32 n_used;
386
387   nf = vlib_node_runtime_get_next_frame (vm, node, next_index);
388
389   /* Make sure this next frame owns right to enqueue to destination frame. */
390   if (PREDICT_FALSE (!(nf->flags & VLIB_FRAME_OWNER)))
391     vlib_next_frame_change_ownership (vm, node, next_index);
392
393   /* ??? Don't need valid flag: can use frame_index == ~0 */
394   if (PREDICT_FALSE (!(nf->flags & VLIB_FRAME_IS_ALLOCATED)))
395     {
396       nf->frame = vlib_frame_alloc (vm, node, next_index);
397       nf->flags |= VLIB_FRAME_IS_ALLOCATED;
398     }
399
400   f = nf->frame;
401
402   /* Has frame been removed from pending vector (e.g. finished dispatching)?
403      If so we can reuse frame. */
404   if ((nf->flags & VLIB_FRAME_PENDING)
405       && !(f->frame_flags & VLIB_FRAME_PENDING))
406     {
407       nf->flags &= ~VLIB_FRAME_PENDING;
408       f->n_vectors = 0;
409       f->flags = 0;
410     }
411
412   /* Allocate new frame if current one is marked as no-append or
413      it is already full. */
414   n_used = f->n_vectors;
415   if (n_used >= VLIB_FRAME_SIZE || (allocate_new_next_frame && n_used > 0) ||
416       (f->frame_flags & VLIB_FRAME_NO_APPEND))
417     {
418       /* Old frame may need to be freed after dispatch, since we'll have
419          two redundant frames from node -> next node. */
420       if (!(nf->flags & VLIB_FRAME_NO_FREE_AFTER_DISPATCH))
421         {
422           vlib_frame_t *f_old = vlib_get_frame (vm, nf->frame);
423           f_old->frame_flags |= VLIB_FRAME_FREE_AFTER_DISPATCH;
424         }
425
426       /* Allocate new frame to replace full one. */
427       f = nf->frame = vlib_frame_alloc (vm, node, next_index);
428       n_used = f->n_vectors;
429     }
430
431   /* Should have free vectors in frame now. */
432   ASSERT (n_used < VLIB_FRAME_SIZE);
433
434   if (CLIB_DEBUG > 0)
435     {
436       validate_frame_magic (vm, f,
437                             vlib_get_node (vm, node->node_index), next_index);
438     }
439
440   return f;
441 }
442
443 static void
444 vlib_put_next_frame_validate (vlib_main_t * vm,
445                               vlib_node_runtime_t * rt,
446                               u32 next_index, u32 n_vectors_left)
447 {
448   vlib_node_main_t *nm = &vm->node_main;
449   vlib_next_frame_t *nf;
450   vlib_frame_t *f;
451   vlib_node_runtime_t *next_rt;
452   vlib_node_t *next_node;
453   u32 n_before, n_after;
454
455   nf = vlib_node_runtime_get_next_frame (vm, rt, next_index);
456   f = vlib_get_frame (vm, nf->frame);
457
458   ASSERT (n_vectors_left <= VLIB_FRAME_SIZE);
459
460   vlib_validate_frame_indices (f);
461
462   n_after = VLIB_FRAME_SIZE - n_vectors_left;
463   n_before = f->n_vectors;
464
465   ASSERT (n_after >= n_before);
466
467   next_rt = vec_elt_at_index (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL],
468                               nf->node_runtime_index);
469   next_node = vlib_get_node (vm, next_rt->node_index);
470   if (n_after > 0 && next_node->validate_frame)
471     {
472       u8 *msg = next_node->validate_frame (vm, rt, f);
473       if (msg)
474         {
475           clib_warning ("%v", msg);
476           ASSERT (0);
477         }
478       vec_free (msg);
479     }
480 }
481
482 void
483 vlib_put_next_frame (vlib_main_t * vm,
484                      vlib_node_runtime_t * r,
485                      u32 next_index, u32 n_vectors_left)
486 {
487   vlib_node_main_t *nm = &vm->node_main;
488   vlib_next_frame_t *nf;
489   vlib_frame_t *f;
490   u32 n_vectors_in_frame;
491
492   if (CLIB_DEBUG > 0)
493     vlib_put_next_frame_validate (vm, r, next_index, n_vectors_left);
494
495   nf = vlib_node_runtime_get_next_frame (vm, r, next_index);
496   f = vlib_get_frame (vm, nf->frame);
497
498   /* Make sure that magic number is still there.  Otherwise, caller
499      has overrun frame meta data. */
500   if (CLIB_DEBUG > 0)
501     {
502       vlib_node_t *node = vlib_get_node (vm, r->node_index);
503       validate_frame_magic (vm, f, node, next_index);
504     }
505
506   /* Convert # of vectors left -> number of vectors there. */
507   ASSERT (n_vectors_left <= VLIB_FRAME_SIZE);
508   n_vectors_in_frame = VLIB_FRAME_SIZE - n_vectors_left;
509
510   f->n_vectors = n_vectors_in_frame;
511
512   /* If vectors were added to frame, add to pending vector. */
513   if (PREDICT_TRUE (n_vectors_in_frame > 0))
514     {
515       vlib_pending_frame_t *p;
516       u32 v0, v1;
517
518       r->cached_next_index = next_index;
519
520       if (!(f->frame_flags & VLIB_FRAME_PENDING))
521         {
522           __attribute__ ((unused)) vlib_node_t *node;
523           vlib_node_t *next_node;
524           vlib_node_runtime_t *next_runtime;
525
526           node = vlib_get_node (vm, r->node_index);
527           next_node = vlib_get_next_node (vm, r->node_index, next_index);
528           next_runtime = vlib_node_get_runtime (vm, next_node->index);
529
530           vec_add2 (nm->pending_frames, p, 1);
531
532           p->frame = nf->frame;
533           p->node_runtime_index = nf->node_runtime_index;
534           p->next_frame_index = nf - nm->next_frames;
535           nf->flags |= VLIB_FRAME_PENDING;
536           f->frame_flags |= VLIB_FRAME_PENDING;
537
538           /*
539            * If we're going to dispatch this frame on another thread,
540            * force allocation of a new frame. Otherwise, we create
541            * a dangling frame reference. Each thread has its own copy of
542            * the next_frames vector.
543            */
544           if (0 && r->thread_index != next_runtime->thread_index)
545             {
546               nf->frame = NULL;
547               nf->flags &= ~(VLIB_FRAME_PENDING | VLIB_FRAME_IS_ALLOCATED);
548             }
549         }
550
551       /* Copy trace flag from next_frame and from runtime. */
552       nf->flags |=
553         (nf->flags & VLIB_NODE_FLAG_TRACE) | (r->
554                                               flags & VLIB_NODE_FLAG_TRACE);
555
556       v0 = nf->vectors_since_last_overflow;
557       v1 = v0 + n_vectors_in_frame;
558       nf->vectors_since_last_overflow = v1;
559       if (PREDICT_FALSE (v1 < v0))
560         {
561           vlib_node_t *node = vlib_get_node (vm, r->node_index);
562           vec_elt (node->n_vectors_by_next_node, next_index) += v0;
563         }
564     }
565 }
566
567 /* Sync up runtime (32 bit counters) and main node stats (64 bit counters). */
568 never_inline void
569 vlib_node_runtime_sync_stats (vlib_main_t * vm,
570                               vlib_node_runtime_t * r,
571                               uword n_calls, uword n_vectors, uword n_clocks)
572 {
573   vlib_node_t *n = vlib_get_node (vm, r->node_index);
574
575   n->stats_total.calls += n_calls + r->calls_since_last_overflow;
576   n->stats_total.vectors += n_vectors + r->vectors_since_last_overflow;
577   n->stats_total.clocks += n_clocks + r->clocks_since_last_overflow;
578   n->stats_total.max_clock = r->max_clock;
579   n->stats_total.max_clock_n = r->max_clock_n;
580
581   r->calls_since_last_overflow = 0;
582   r->vectors_since_last_overflow = 0;
583   r->clocks_since_last_overflow = 0;
584 }
585
586 always_inline void __attribute__ ((unused))
587 vlib_process_sync_stats (vlib_main_t * vm,
588                          vlib_process_t * p,
589                          uword n_calls, uword n_vectors, uword n_clocks)
590 {
591   vlib_node_runtime_t *rt = &p->node_runtime;
592   vlib_node_t *n = vlib_get_node (vm, rt->node_index);
593   vlib_node_runtime_sync_stats (vm, rt, n_calls, n_vectors, n_clocks);
594   n->stats_total.suspends += p->n_suspends;
595   p->n_suspends = 0;
596 }
597
598 void
599 vlib_node_sync_stats (vlib_main_t * vm, vlib_node_t * n)
600 {
601   vlib_node_runtime_t *rt;
602
603   if (n->type == VLIB_NODE_TYPE_PROCESS)
604     {
605       /* Nothing to do for PROCESS nodes except in main thread */
606       if (vm != &vlib_global_main)
607         return;
608
609       vlib_process_t *p = vlib_get_process_from_node (vm, n);
610       n->stats_total.suspends += p->n_suspends;
611       p->n_suspends = 0;
612       rt = &p->node_runtime;
613     }
614   else
615     rt =
616       vec_elt_at_index (vm->node_main.nodes_by_type[n->type],
617                         n->runtime_index);
618
619   vlib_node_runtime_sync_stats (vm, rt, 0, 0, 0);
620
621   /* Sync up runtime next frame vector counters with main node structure. */
622   {
623     vlib_next_frame_t *nf;
624     uword i;
625     for (i = 0; i < rt->n_next_nodes; i++)
626       {
627         nf = vlib_node_runtime_get_next_frame (vm, rt, i);
628         vec_elt (n->n_vectors_by_next_node, i) +=
629           nf->vectors_since_last_overflow;
630         nf->vectors_since_last_overflow = 0;
631       }
632   }
633 }
634
635 always_inline u32
636 vlib_node_runtime_update_stats (vlib_main_t * vm,
637                                 vlib_node_runtime_t * node,
638                                 uword n_calls,
639                                 uword n_vectors, uword n_clocks)
640 {
641   u32 ca0, ca1, v0, v1, cl0, cl1, r;
642
643   cl0 = cl1 = node->clocks_since_last_overflow;
644   ca0 = ca1 = node->calls_since_last_overflow;
645   v0 = v1 = node->vectors_since_last_overflow;
646
647   ca1 = ca0 + n_calls;
648   v1 = v0 + n_vectors;
649   cl1 = cl0 + n_clocks;
650
651   node->calls_since_last_overflow = ca1;
652   node->clocks_since_last_overflow = cl1;
653   node->vectors_since_last_overflow = v1;
654
655   node->max_clock_n = node->max_clock > n_clocks ?
656     node->max_clock_n : n_vectors;
657   node->max_clock = node->max_clock > n_clocks ? node->max_clock : n_clocks;
658
659   r = vlib_node_runtime_update_main_loop_vector_stats (vm, node, n_vectors);
660
661   if (PREDICT_FALSE (ca1 < ca0 || v1 < v0 || cl1 < cl0))
662     {
663       node->calls_since_last_overflow = ca0;
664       node->clocks_since_last_overflow = cl0;
665       node->vectors_since_last_overflow = v0;
666
667       vlib_node_runtime_sync_stats (vm, node, n_calls, n_vectors, n_clocks);
668     }
669
670   return r;
671 }
672
673 always_inline void
674 vlib_process_update_stats (vlib_main_t * vm,
675                            vlib_process_t * p,
676                            uword n_calls, uword n_vectors, uword n_clocks)
677 {
678   vlib_node_runtime_update_stats (vm, &p->node_runtime,
679                                   n_calls, n_vectors, n_clocks);
680 }
681
682 static clib_error_t *
683 vlib_cli_elog_clear (vlib_main_t * vm,
684                      unformat_input_t * input, vlib_cli_command_t * cmd)
685 {
686   elog_reset_buffer (&vm->elog_main);
687   return 0;
688 }
689
690 /* *INDENT-OFF* */
691 VLIB_CLI_COMMAND (elog_clear_cli, static) = {
692   .path = "event-logger clear",
693   .short_help = "Clear the event log",
694   .function = vlib_cli_elog_clear,
695 };
696 /* *INDENT-ON* */
697
698 #ifdef CLIB_UNIX
699 static clib_error_t *
700 elog_save_buffer (vlib_main_t * vm,
701                   unformat_input_t * input, vlib_cli_command_t * cmd)
702 {
703   elog_main_t *em = &vm->elog_main;
704   char *file, *chroot_file;
705   clib_error_t *error = 0;
706
707   if (!unformat (input, "%s", &file))
708     {
709       vlib_cli_output (vm, "expected file name, got `%U'",
710                        format_unformat_error, input);
711       return 0;
712     }
713
714   /* It's fairly hard to get "../oopsie" through unformat; just in case */
715   if (strstr (file, "..") || index (file, '/'))
716     {
717       vlib_cli_output (vm, "illegal characters in filename '%s'", file);
718       return 0;
719     }
720
721   chroot_file = (char *) format (0, "/tmp/%s%c", file, 0);
722
723   vec_free (file);
724
725   vlib_cli_output (vm, "Saving %wd of %wd events to %s",
726                    elog_n_events_in_buffer (em),
727                    elog_buffer_capacity (em), chroot_file);
728
729   vlib_worker_thread_barrier_sync (vm);
730   error = elog_write_file (em, chroot_file, 1 /* flush ring */ );
731   vlib_worker_thread_barrier_release (vm);
732   vec_free (chroot_file);
733   return error;
734 }
735
736 void
737 elog_post_mortem_dump (void)
738 {
739   vlib_main_t *vm = &vlib_global_main;
740   elog_main_t *em = &vm->elog_main;
741   u8 *filename;
742   clib_error_t *error;
743
744   if (!vm->elog_post_mortem_dump)
745     return;
746
747   filename = format (0, "/tmp/elog_post_mortem.%d%c", getpid (), 0);
748   error = elog_write_file (em, (char *) filename, 1 /* flush ring */ );
749   if (error)
750     clib_error_report (error);
751   vec_free (filename);
752 }
753
754 /* *INDENT-OFF* */
755 VLIB_CLI_COMMAND (elog_save_cli, static) = {
756   .path = "event-logger save",
757   .short_help = "event-logger save <filename> (saves log in /tmp/<filename>)",
758   .function = elog_save_buffer,
759 };
760 /* *INDENT-ON* */
761
762 static clib_error_t *
763 elog_stop (vlib_main_t * vm,
764            unformat_input_t * input, vlib_cli_command_t * cmd)
765 {
766   elog_main_t *em = &vm->elog_main;
767
768   em->n_total_events_disable_limit = em->n_total_events;
769
770   vlib_cli_output (vm, "Stopped the event logger...");
771   return 0;
772 }
773
774 /* *INDENT-OFF* */
775 VLIB_CLI_COMMAND (elog_stop_cli, static) = {
776   .path = "event-logger stop",
777   .short_help = "Stop the event-logger",
778   .function = elog_stop,
779 };
780 /* *INDENT-ON* */
781
782 static clib_error_t *
783 elog_restart (vlib_main_t * vm,
784               unformat_input_t * input, vlib_cli_command_t * cmd)
785 {
786   elog_main_t *em = &vm->elog_main;
787
788   em->n_total_events_disable_limit = ~0;
789
790   vlib_cli_output (vm, "Restarted the event logger...");
791   return 0;
792 }
793
794 /* *INDENT-OFF* */
795 VLIB_CLI_COMMAND (elog_restart_cli, static) = {
796   .path = "event-logger restart",
797   .short_help = "Restart the event-logger",
798   .function = elog_restart,
799 };
800 /* *INDENT-ON* */
801
802 static clib_error_t *
803 elog_resize (vlib_main_t * vm,
804              unformat_input_t * input, vlib_cli_command_t * cmd)
805 {
806   elog_main_t *em = &vm->elog_main;
807   u32 tmp;
808
809   /* Stop the parade */
810   elog_reset_buffer (&vm->elog_main);
811
812   if (unformat (input, "%d", &tmp))
813     {
814       elog_alloc (em, tmp);
815       em->n_total_events_disable_limit = ~0;
816     }
817   else
818     return clib_error_return (0, "Must specify how many events in the ring");
819
820   vlib_cli_output (vm, "Resized ring and restarted the event logger...");
821   return 0;
822 }
823
824 /* *INDENT-OFF* */
825 VLIB_CLI_COMMAND (elog_resize_cli, static) = {
826   .path = "event-logger resize",
827   .short_help = "event-logger resize <nnn>",
828   .function = elog_resize,
829 };
830 /* *INDENT-ON* */
831
832 #endif /* CLIB_UNIX */
833
834 static void
835 elog_show_buffer_internal (vlib_main_t * vm, u32 n_events_to_show)
836 {
837   elog_main_t *em = &vm->elog_main;
838   elog_event_t *e, *es;
839   f64 dt;
840
841   /* Show events in VLIB time since log clock starts after VLIB clock. */
842   dt = (em->init_time.cpu - vm->clib_time.init_cpu_time)
843     * vm->clib_time.seconds_per_clock;
844
845   es = elog_peek_events (em);
846   vlib_cli_output (vm, "%d of %d events in buffer, logger %s", vec_len (es),
847                    em->event_ring_size,
848                    em->n_total_events < em->n_total_events_disable_limit ?
849                    "running" : "stopped");
850   vec_foreach (e, es)
851   {
852     vlib_cli_output (vm, "%18.9f: %U",
853                      e->time + dt, format_elog_event, em, e);
854     n_events_to_show--;
855     if (n_events_to_show == 0)
856       break;
857   }
858   vec_free (es);
859
860 }
861
862 static clib_error_t *
863 elog_show_buffer (vlib_main_t * vm,
864                   unformat_input_t * input, vlib_cli_command_t * cmd)
865 {
866   u32 n_events_to_show;
867   clib_error_t *error = 0;
868
869   n_events_to_show = 250;
870   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
871     {
872       if (unformat (input, "%d", &n_events_to_show))
873         ;
874       else if (unformat (input, "all"))
875         n_events_to_show = ~0;
876       else
877         return unformat_parse_error (input);
878     }
879   elog_show_buffer_internal (vm, n_events_to_show);
880   return error;
881 }
882
883 /* *INDENT-OFF* */
884 VLIB_CLI_COMMAND (elog_show_cli, static) = {
885   .path = "show event-logger",
886   .short_help = "Show event logger info",
887   .function = elog_show_buffer,
888 };
889 /* *INDENT-ON* */
890
891 void
892 vlib_gdb_show_event_log (void)
893 {
894   elog_show_buffer_internal (vlib_get_main (), (u32) ~ 0);
895 }
896
897 static inline void
898 vlib_elog_main_loop_event (vlib_main_t * vm,
899                            u32 node_index,
900                            u64 time, u32 n_vectors, u32 is_return)
901 {
902   vlib_main_t *evm = &vlib_global_main;
903   elog_main_t *em = &evm->elog_main;
904   int enabled = evm->elog_trace_graph_dispatch |
905     evm->elog_trace_graph_circuit;
906
907   if (PREDICT_FALSE (enabled && n_vectors))
908     {
909       if (PREDICT_FALSE (!elog_is_enabled (em)))
910         {
911           evm->elog_trace_graph_dispatch = 0;
912           evm->elog_trace_graph_circuit = 0;
913           return;
914         }
915       if (PREDICT_TRUE
916           (evm->elog_trace_graph_dispatch ||
917            (evm->elog_trace_graph_circuit &&
918             node_index == evm->elog_trace_graph_circuit_node_index)))
919         {
920           elog_track (em,
921                       /* event type */
922                       vec_elt_at_index (is_return
923                                         ? evm->node_return_elog_event_types
924                                         : evm->node_call_elog_event_types,
925                                         node_index),
926                       /* track */
927                       (vm->thread_index ?
928                        &vlib_worker_threads[vm->thread_index].elog_track
929                        : &em->default_track),
930                       /* data to log */ n_vectors);
931         }
932     }
933 }
934
935 #if VLIB_BUFFER_TRACE_TRAJECTORY > 0
936 void (*vlib_buffer_trace_trajectory_cb) (vlib_buffer_t * b, u32 node_index);
937 void (*vlib_buffer_trace_trajectory_init_cb) (vlib_buffer_t * b);
938
939 void
940 vlib_buffer_trace_trajectory_init (vlib_buffer_t * b)
941 {
942   if (PREDICT_TRUE (vlib_buffer_trace_trajectory_init_cb != 0))
943     {
944       (*vlib_buffer_trace_trajectory_init_cb) (b);
945     }
946 }
947
948 #endif
949
950 static inline void
951 add_trajectory_trace (vlib_buffer_t * b, u32 node_index)
952 {
953 #if VLIB_BUFFER_TRACE_TRAJECTORY > 0
954   if (PREDICT_TRUE (vlib_buffer_trace_trajectory_cb != 0))
955     {
956       (*vlib_buffer_trace_trajectory_cb) (b, node_index);
957     }
958 #endif
959 }
960
961 u8 *format_vnet_buffer_flags (u8 * s, va_list * args) __attribute__ ((weak));
962 u8 *
963 format_vnet_buffer_flags (u8 * s, va_list * args)
964 {
965   s = format (s, "BUG STUB %s", __FUNCTION__);
966   return s;
967 }
968
969 u8 *format_vnet_buffer_opaque (u8 * s, va_list * args) __attribute__ ((weak));
970 u8 *
971 format_vnet_buffer_opaque (u8 * s, va_list * args)
972 {
973   s = format (s, "BUG STUB %s", __FUNCTION__);
974   return s;
975 }
976
977 u8 *format_vnet_buffer_opaque2 (u8 * s, va_list * args)
978   __attribute__ ((weak));
979 u8 *
980 format_vnet_buffer_opaque2 (u8 * s, va_list * args)
981 {
982   s = format (s, "BUG STUB %s", __FUNCTION__);
983   return s;
984 }
985
986 static u8 *
987 format_buffer_metadata (u8 * s, va_list * args)
988 {
989   vlib_buffer_t *b = va_arg (*args, vlib_buffer_t *);
990
991   s = format (s, "flags: %U\n", format_vnet_buffer_flags, b);
992   s = format (s, "current_data: %d, current_length: %d\n",
993               (i32) (b->current_data), (i32) (b->current_length));
994   s = format
995     (s,
996      "current_config_index/punt_reason: %d, flow_id: %x, next_buffer: %x\n",
997      b->current_config_index, b->flow_id, b->next_buffer);
998   s =
999     format (s, "error: %d, ref_count: %d, buffer_pool_index: %d\n",
1000             (u32) (b->error), (u32) (b->ref_count),
1001             (u32) (b->buffer_pool_index));
1002   s =
1003     format (s, "trace_handle: 0x%x, len_not_first_buf: %d\n", b->trace_handle,
1004             b->total_length_not_including_first_buffer);
1005   return s;
1006 }
1007
1008 #define A(x) vec_add1(vm->pcap_buffer, (x))
1009
1010 static void
1011 dispatch_pcap_trace (vlib_main_t * vm,
1012                      vlib_node_runtime_t * node, vlib_frame_t * frame)
1013 {
1014   int i;
1015   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **bufp, *b;
1016   pcap_main_t *pm = &vlib_global_main.dispatch_pcap_main;
1017   vlib_trace_main_t *tm = &vm->trace_main;
1018   u32 capture_size;
1019   vlib_node_t *n;
1020   i32 n_left;
1021   f64 time_now = vlib_time_now (vm);
1022   u32 *from;
1023   u8 *d;
1024   u8 string_count;
1025
1026   /* Input nodes don't have frames yet */
1027   if (frame == 0 || frame->n_vectors == 0)
1028     return;
1029
1030   from = vlib_frame_vector_args (frame);
1031   vlib_get_buffers (vm, from, bufs, frame->n_vectors);
1032   bufp = bufs;
1033
1034   n = vlib_get_node (vm, node->node_index);
1035
1036   for (i = 0; i < frame->n_vectors; i++)
1037     {
1038       if (PREDICT_TRUE (pm->n_packets_captured < pm->n_packets_to_capture))
1039         {
1040           b = bufp[i];
1041
1042           vec_reset_length (vm->pcap_buffer);
1043           string_count = 0;
1044
1045           /* Version, flags */
1046           A ((u8) VLIB_PCAP_MAJOR_VERSION);
1047           A ((u8) VLIB_PCAP_MINOR_VERSION);
1048           A (0 /* string_count */ );
1049           A (n->protocol_hint);
1050
1051           /* Buffer index (big endian) */
1052           A ((from[i] >> 24) & 0xff);
1053           A ((from[i] >> 16) & 0xff);
1054           A ((from[i] >> 8) & 0xff);
1055           A ((from[i] >> 0) & 0xff);
1056
1057           /* Node name, NULL-terminated ASCII */
1058           vm->pcap_buffer = format (vm->pcap_buffer, "%v%c", n->name, 0);
1059           string_count++;
1060
1061           vm->pcap_buffer = format (vm->pcap_buffer, "%U%c",
1062                                     format_buffer_metadata, b, 0);
1063           string_count++;
1064           vm->pcap_buffer = format (vm->pcap_buffer, "%U%c",
1065                                     format_vnet_buffer_opaque, b, 0);
1066           string_count++;
1067           vm->pcap_buffer = format (vm->pcap_buffer, "%U%c",
1068                                     format_vnet_buffer_opaque2, b, 0);
1069           string_count++;
1070
1071           /* Is this packet traced? */
1072           if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
1073             {
1074               vlib_trace_header_t **h
1075                 = pool_elt_at_index (tm->trace_buffer_pool,
1076                                      vlib_buffer_get_trace_index (b));
1077
1078               vm->pcap_buffer = format (vm->pcap_buffer, "%U%c",
1079                                         format_vlib_trace, vm, h[0], 0);
1080               string_count++;
1081             }
1082
1083           /* Save the string count */
1084           vm->pcap_buffer[2] = string_count;
1085
1086           /* Figure out how many bytes in the pcap trace */
1087           capture_size = vec_len (vm->pcap_buffer) +
1088             +vlib_buffer_length_in_chain (vm, b);
1089
1090           clib_spinlock_lock_if_init (&pm->lock);
1091           n_left = clib_min (capture_size, 16384);
1092           d = pcap_add_packet (pm, time_now, n_left, capture_size);
1093
1094           /* Copy the header */
1095           clib_memcpy_fast (d, vm->pcap_buffer, vec_len (vm->pcap_buffer));
1096           d += vec_len (vm->pcap_buffer);
1097
1098           n_left = clib_min
1099             (vlib_buffer_length_in_chain (vm, b),
1100              (16384 - vec_len (vm->pcap_buffer)));
1101           /* Copy the packet data */
1102           while (1)
1103             {
1104               u32 copy_length = clib_min ((u32) n_left, b->current_length);
1105               clib_memcpy_fast (d, b->data + b->current_data, copy_length);
1106               n_left -= b->current_length;
1107               if (n_left <= 0)
1108                 break;
1109               d += b->current_length;
1110               ASSERT (b->flags & VLIB_BUFFER_NEXT_PRESENT);
1111               b = vlib_get_buffer (vm, b->next_buffer);
1112             }
1113           clib_spinlock_unlock_if_init (&pm->lock);
1114         }
1115     }
1116 }
1117
1118 static_always_inline u64
1119 dispatch_node (vlib_main_t * vm,
1120                vlib_node_runtime_t * node,
1121                vlib_node_type_t type,
1122                vlib_node_state_t dispatch_state,
1123                vlib_frame_t * frame, u64 last_time_stamp)
1124 {
1125   uword n, v;
1126   u64 t;
1127   vlib_node_main_t *nm = &vm->node_main;
1128   vlib_next_frame_t *nf;
1129
1130   if (CLIB_DEBUG > 0)
1131     {
1132       vlib_node_t *n = vlib_get_node (vm, node->node_index);
1133       ASSERT (n->type == type);
1134     }
1135
1136   /* Only non-internal nodes may be disabled. */
1137   if (type != VLIB_NODE_TYPE_INTERNAL && node->state != dispatch_state)
1138     {
1139       ASSERT (type != VLIB_NODE_TYPE_INTERNAL);
1140       return last_time_stamp;
1141     }
1142
1143   if ((type == VLIB_NODE_TYPE_PRE_INPUT || type == VLIB_NODE_TYPE_INPUT)
1144       && dispatch_state != VLIB_NODE_STATE_INTERRUPT)
1145     {
1146       u32 c = node->input_main_loops_per_call;
1147       /* Only call node when count reaches zero. */
1148       if (c)
1149         {
1150           node->input_main_loops_per_call = c - 1;
1151           return last_time_stamp;
1152         }
1153     }
1154
1155   /* Speculatively prefetch next frames. */
1156   if (node->n_next_nodes > 0)
1157     {
1158       nf = vec_elt_at_index (nm->next_frames, node->next_frame_index);
1159       CLIB_PREFETCH (nf, 4 * sizeof (nf[0]), WRITE);
1160     }
1161
1162   vm->cpu_time_last_node_dispatch = last_time_stamp;
1163
1164   vlib_elog_main_loop_event (vm, node->node_index,
1165                              last_time_stamp, frame ? frame->n_vectors : 0,
1166                              /* is_after */ 0);
1167
1168   vlib_node_runtime_perf_counter (vm, node, frame, 0, last_time_stamp,
1169                                   VLIB_NODE_RUNTIME_PERF_BEFORE);
1170
1171   /*
1172    * Turn this on if you run into
1173    * "bad monkey" contexts, and you want to know exactly
1174    * which nodes they've visited... See ixge.c...
1175    */
1176   if (VLIB_BUFFER_TRACE_TRAJECTORY && frame)
1177     {
1178       int i;
1179       u32 *from;
1180       from = vlib_frame_vector_args (frame);
1181       for (i = 0; i < frame->n_vectors; i++)
1182         {
1183           vlib_buffer_t *b = vlib_get_buffer (vm, from[i]);
1184           add_trajectory_trace (b, node->node_index);
1185         }
1186       if (PREDICT_FALSE (vm->dispatch_pcap_enable))
1187         dispatch_pcap_trace (vm, node, frame);
1188       n = node->function (vm, node, frame);
1189     }
1190   else
1191     {
1192       if (PREDICT_FALSE (vm->dispatch_pcap_enable))
1193         dispatch_pcap_trace (vm, node, frame);
1194       n = node->function (vm, node, frame);
1195     }
1196
1197   t = clib_cpu_time_now ();
1198
1199   vlib_node_runtime_perf_counter (vm, node, frame, n, t,
1200                                   VLIB_NODE_RUNTIME_PERF_AFTER);
1201
1202   vlib_elog_main_loop_event (vm, node->node_index, t, n, 1 /* is_after */ );
1203
1204   vm->main_loop_vectors_processed += n;
1205   vm->main_loop_nodes_processed += n > 0;
1206
1207   v = vlib_node_runtime_update_stats (vm, node,
1208                                       /* n_calls */ 1,
1209                                       /* n_vectors */ n,
1210                                       /* n_clocks */ t - last_time_stamp);
1211
1212   /* When in interrupt mode and vector rate crosses threshold switch to
1213      polling mode. */
1214   if (PREDICT_FALSE ((dispatch_state == VLIB_NODE_STATE_INTERRUPT)
1215                      || (dispatch_state == VLIB_NODE_STATE_POLLING
1216                          && (node->flags
1217                              &
1218                              VLIB_NODE_FLAG_SWITCH_FROM_INTERRUPT_TO_POLLING_MODE))))
1219     {
1220       /* *INDENT-OFF* */
1221       ELOG_TYPE_DECLARE (e) =
1222         {
1223           .function = (char *) __FUNCTION__,
1224           .format = "%s vector length %d, switching to %s",
1225           .format_args = "T4i4t4",
1226           .n_enum_strings = 2,
1227           .enum_strings = {
1228             "interrupt", "polling",
1229           },
1230         };
1231       /* *INDENT-ON* */
1232       struct
1233       {
1234         u32 node_name, vector_length, is_polling;
1235       } *ed;
1236
1237       if ((dispatch_state == VLIB_NODE_STATE_INTERRUPT
1238            && v >= nm->polling_threshold_vector_length) &&
1239           !(node->flags &
1240             VLIB_NODE_FLAG_SWITCH_FROM_INTERRUPT_TO_POLLING_MODE))
1241         {
1242           vlib_node_t *n = vlib_get_node (vm, node->node_index);
1243           n->state = VLIB_NODE_STATE_POLLING;
1244           node->state = VLIB_NODE_STATE_POLLING;
1245           node->flags &=
1246             ~VLIB_NODE_FLAG_SWITCH_FROM_POLLING_TO_INTERRUPT_MODE;
1247           node->flags |= VLIB_NODE_FLAG_SWITCH_FROM_INTERRUPT_TO_POLLING_MODE;
1248           nm->input_node_counts_by_state[VLIB_NODE_STATE_INTERRUPT] -= 1;
1249           nm->input_node_counts_by_state[VLIB_NODE_STATE_POLLING] += 1;
1250
1251           if (PREDICT_FALSE (vlib_global_main.elog_trace_graph_dispatch))
1252             {
1253               vlib_worker_thread_t *w = vlib_worker_threads
1254                 + vm->thread_index;
1255
1256               ed = ELOG_TRACK_DATA (&vlib_global_main.elog_main, e,
1257                                     w->elog_track);
1258               ed->node_name = n->name_elog_string;
1259               ed->vector_length = v;
1260               ed->is_polling = 1;
1261             }
1262         }
1263       else if (dispatch_state == VLIB_NODE_STATE_POLLING
1264                && v <= nm->interrupt_threshold_vector_length)
1265         {
1266           vlib_node_t *n = vlib_get_node (vm, node->node_index);
1267           if (node->flags &
1268               VLIB_NODE_FLAG_SWITCH_FROM_POLLING_TO_INTERRUPT_MODE)
1269             {
1270               /* Switch to interrupt mode after dispatch in polling one more time.
1271                  This allows driver to re-enable interrupts. */
1272               n->state = VLIB_NODE_STATE_INTERRUPT;
1273               node->state = VLIB_NODE_STATE_INTERRUPT;
1274               node->flags &=
1275                 ~VLIB_NODE_FLAG_SWITCH_FROM_INTERRUPT_TO_POLLING_MODE;
1276               nm->input_node_counts_by_state[VLIB_NODE_STATE_POLLING] -= 1;
1277               nm->input_node_counts_by_state[VLIB_NODE_STATE_INTERRUPT] += 1;
1278
1279             }
1280           else
1281             {
1282               vlib_worker_thread_t *w = vlib_worker_threads
1283                 + vm->thread_index;
1284               node->flags |=
1285                 VLIB_NODE_FLAG_SWITCH_FROM_POLLING_TO_INTERRUPT_MODE;
1286               if (PREDICT_FALSE (vlib_global_main.elog_trace_graph_dispatch))
1287                 {
1288                   ed = ELOG_TRACK_DATA (&vlib_global_main.elog_main, e,
1289                                         w->elog_track);
1290                   ed->node_name = n->name_elog_string;
1291                   ed->vector_length = v;
1292                   ed->is_polling = 0;
1293                 }
1294             }
1295         }
1296     }
1297
1298   return t;
1299 }
1300
1301 static u64
1302 dispatch_pending_node (vlib_main_t * vm, uword pending_frame_index,
1303                        u64 last_time_stamp)
1304 {
1305   vlib_node_main_t *nm = &vm->node_main;
1306   vlib_frame_t *f;
1307   vlib_next_frame_t *nf, nf_placeholder;
1308   vlib_node_runtime_t *n;
1309   vlib_frame_t *restore_frame;
1310   vlib_pending_frame_t *p;
1311
1312   /* See comment below about dangling references to nm->pending_frames */
1313   p = nm->pending_frames + pending_frame_index;
1314
1315   n = vec_elt_at_index (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL],
1316                         p->node_runtime_index);
1317
1318   f = vlib_get_frame (vm, p->frame);
1319   if (p->next_frame_index == VLIB_PENDING_FRAME_NO_NEXT_FRAME)
1320     {
1321       /* No next frame: so use placeholder on stack. */
1322       nf = &nf_placeholder;
1323       nf->flags = f->frame_flags & VLIB_NODE_FLAG_TRACE;
1324       nf->frame = NULL;
1325     }
1326   else
1327     nf = vec_elt_at_index (nm->next_frames, p->next_frame_index);
1328
1329   ASSERT (f->frame_flags & VLIB_FRAME_IS_ALLOCATED);
1330
1331   /* Force allocation of new frame while current frame is being
1332      dispatched. */
1333   restore_frame = NULL;
1334   if (nf->frame == p->frame)
1335     {
1336       nf->frame = NULL;
1337       nf->flags &= ~VLIB_FRAME_IS_ALLOCATED;
1338       if (!(n->flags & VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH))
1339         restore_frame = p->frame;
1340     }
1341
1342   /* Frame must be pending. */
1343   ASSERT (f->frame_flags & VLIB_FRAME_PENDING);
1344   ASSERT (f->n_vectors > 0);
1345
1346   /* Copy trace flag from next frame to node.
1347      Trace flag indicates that at least one vector in the dispatched
1348      frame is traced. */
1349   n->flags &= ~VLIB_NODE_FLAG_TRACE;
1350   n->flags |= (nf->flags & VLIB_FRAME_TRACE) ? VLIB_NODE_FLAG_TRACE : 0;
1351   nf->flags &= ~VLIB_FRAME_TRACE;
1352
1353   last_time_stamp = dispatch_node (vm, n,
1354                                    VLIB_NODE_TYPE_INTERNAL,
1355                                    VLIB_NODE_STATE_POLLING,
1356                                    f, last_time_stamp);
1357   /* Internal node vector-rate accounting, for summary stats */
1358   vm->internal_node_vectors += f->n_vectors;
1359   vm->internal_node_calls++;
1360   vm->internal_node_last_vectors_per_main_loop =
1361     (f->n_vectors > vm->internal_node_last_vectors_per_main_loop) ?
1362     f->n_vectors : vm->internal_node_last_vectors_per_main_loop;
1363
1364   f->frame_flags &= ~(VLIB_FRAME_PENDING | VLIB_FRAME_NO_APPEND);
1365
1366   /* Frame is ready to be used again, so restore it. */
1367   if (restore_frame != NULL)
1368     {
1369       /*
1370        * We musn't restore a frame that is flagged to be freed. This
1371        * shouldn't happen since frames to be freed post dispatch are
1372        * those used when the to-node frame becomes full i.e. they form a
1373        * sort of queue of frames to a single node. If we get here then
1374        * the to-node frame and the pending frame *were* the same, and so
1375        * we removed the to-node frame.  Therefore this frame is no
1376        * longer part of the queue for that node and hence it cannot be
1377        * it's overspill.
1378        */
1379       ASSERT (!(f->frame_flags & VLIB_FRAME_FREE_AFTER_DISPATCH));
1380
1381       /*
1382        * NB: dispatching node n can result in the creation and scheduling
1383        * of new frames, and hence in the reallocation of nm->pending_frames.
1384        * Recompute p, or no supper. This was broken for more than 10 years.
1385        */
1386       p = nm->pending_frames + pending_frame_index;
1387
1388       /*
1389        * p->next_frame_index can change during node dispatch if node
1390        * function decides to change graph hook up.
1391        */
1392       nf = vec_elt_at_index (nm->next_frames, p->next_frame_index);
1393       nf->flags |= VLIB_FRAME_IS_ALLOCATED;
1394
1395       if (NULL == nf->frame)
1396         {
1397           /* no new frame has been assigned to this node, use the saved one */
1398           nf->frame = restore_frame;
1399           f->n_vectors = 0;
1400         }
1401       else
1402         {
1403           /* The node has gained a frame, implying packets from the current frame
1404              were re-queued to this same node. we don't need the saved one
1405              anymore */
1406           vlib_frame_free (vm, n, f);
1407         }
1408     }
1409   else
1410     {
1411       if (f->frame_flags & VLIB_FRAME_FREE_AFTER_DISPATCH)
1412         {
1413           ASSERT (!(n->flags & VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH));
1414           vlib_frame_free (vm, n, f);
1415         }
1416     }
1417
1418   return last_time_stamp;
1419 }
1420
1421 always_inline uword
1422 vlib_process_stack_is_valid (vlib_process_t * p)
1423 {
1424   return p->stack[0] == VLIB_PROCESS_STACK_MAGIC;
1425 }
1426
1427 typedef struct
1428 {
1429   vlib_main_t *vm;
1430   vlib_process_t *process;
1431   vlib_frame_t *frame;
1432 } vlib_process_bootstrap_args_t;
1433
1434 /* Called in process stack. */
1435 static uword
1436 vlib_process_bootstrap (uword _a)
1437 {
1438   vlib_process_bootstrap_args_t *a;
1439   vlib_main_t *vm;
1440   vlib_node_runtime_t *node;
1441   vlib_frame_t *f;
1442   vlib_process_t *p;
1443   uword n;
1444
1445   a = uword_to_pointer (_a, vlib_process_bootstrap_args_t *);
1446
1447   vm = a->vm;
1448   p = a->process;
1449   vlib_process_finish_switch_stack (vm);
1450
1451   f = a->frame;
1452   node = &p->node_runtime;
1453
1454   n = node->function (vm, node, f);
1455
1456   ASSERT (vlib_process_stack_is_valid (p));
1457
1458   vlib_process_start_switch_stack (vm, 0);
1459   clib_longjmp (&p->return_longjmp, n);
1460
1461   return n;
1462 }
1463
1464 /* Called in main stack. */
1465 static_always_inline uword
1466 vlib_process_startup (vlib_main_t * vm, vlib_process_t * p, vlib_frame_t * f)
1467 {
1468   vlib_process_bootstrap_args_t a;
1469   uword r;
1470
1471   a.vm = vm;
1472   a.process = p;
1473   a.frame = f;
1474
1475   r = clib_setjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_RETURN);
1476   if (r == VLIB_PROCESS_RETURN_LONGJMP_RETURN)
1477     {
1478       vlib_process_start_switch_stack (vm, p);
1479       r = clib_calljmp (vlib_process_bootstrap, pointer_to_uword (&a),
1480                         (void *) p->stack + (1 << p->log2_n_stack_bytes));
1481     }
1482   else
1483     vlib_process_finish_switch_stack (vm);
1484
1485   return r;
1486 }
1487
1488 static_always_inline uword
1489 vlib_process_resume (vlib_main_t * vm, vlib_process_t * p)
1490 {
1491   uword r;
1492   p->flags &= ~(VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
1493                 | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT
1494                 | VLIB_PROCESS_RESUME_PENDING);
1495   r = clib_setjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_RETURN);
1496   if (r == VLIB_PROCESS_RETURN_LONGJMP_RETURN)
1497     {
1498       vlib_process_start_switch_stack (vm, p);
1499       clib_longjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_RESUME);
1500     }
1501   else
1502     vlib_process_finish_switch_stack (vm);
1503   return r;
1504 }
1505
1506 static u64
1507 dispatch_process (vlib_main_t * vm,
1508                   vlib_process_t * p, vlib_frame_t * f, u64 last_time_stamp)
1509 {
1510   vlib_node_main_t *nm = &vm->node_main;
1511   vlib_node_runtime_t *node_runtime = &p->node_runtime;
1512   vlib_node_t *node = vlib_get_node (vm, node_runtime->node_index);
1513   u32 old_process_index;
1514   u64 t;
1515   uword n_vectors, is_suspend;
1516
1517   if (node->state != VLIB_NODE_STATE_POLLING
1518       || (p->flags & (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
1519                       | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT)))
1520     return last_time_stamp;
1521
1522   p->flags |= VLIB_PROCESS_IS_RUNNING;
1523
1524   t = last_time_stamp;
1525   vlib_elog_main_loop_event (vm, node_runtime->node_index, t,
1526                              f ? f->n_vectors : 0, /* is_after */ 0);
1527
1528   /* Save away current process for suspend. */
1529   old_process_index = nm->current_process_index;
1530   nm->current_process_index = node->runtime_index;
1531
1532   vlib_node_runtime_perf_counter (vm, node_runtime, f, 0, last_time_stamp,
1533                                   VLIB_NODE_RUNTIME_PERF_BEFORE);
1534
1535   n_vectors = vlib_process_startup (vm, p, f);
1536
1537   nm->current_process_index = old_process_index;
1538
1539   ASSERT (n_vectors != VLIB_PROCESS_RETURN_LONGJMP_RETURN);
1540   is_suspend = n_vectors == VLIB_PROCESS_RETURN_LONGJMP_SUSPEND;
1541   if (is_suspend)
1542     {
1543       vlib_pending_frame_t *pf;
1544
1545       n_vectors = 0;
1546       pool_get (nm->suspended_process_frames, pf);
1547       pf->node_runtime_index = node->runtime_index;
1548       pf->frame = f;
1549       pf->next_frame_index = ~0;
1550
1551       p->n_suspends += 1;
1552       p->suspended_process_frame_index = pf - nm->suspended_process_frames;
1553
1554       if (p->flags & VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK)
1555         {
1556           TWT (tw_timer_wheel) * tw =
1557             (TWT (tw_timer_wheel) *) nm->timing_wheel;
1558           p->stop_timer_handle =
1559             TW (tw_timer_start) (tw,
1560                                  vlib_timing_wheel_data_set_suspended_process
1561                                  (node->runtime_index) /* [sic] pool idex */ ,
1562                                  0 /* timer_id */ ,
1563                                  p->resume_clock_interval);
1564         }
1565     }
1566   else
1567     p->flags &= ~VLIB_PROCESS_IS_RUNNING;
1568
1569   t = clib_cpu_time_now ();
1570
1571   vlib_elog_main_loop_event (vm, node_runtime->node_index, t, is_suspend,
1572                              /* is_after */ 1);
1573
1574   vlib_node_runtime_perf_counter (vm, node_runtime, f, n_vectors, t,
1575                                   VLIB_NODE_RUNTIME_PERF_AFTER);
1576
1577   vlib_process_update_stats (vm, p,
1578                              /* n_calls */ !is_suspend,
1579                              /* n_vectors */ n_vectors,
1580                              /* n_clocks */ t - last_time_stamp);
1581
1582   return t;
1583 }
1584
1585 void
1586 vlib_start_process (vlib_main_t * vm, uword process_index)
1587 {
1588   vlib_node_main_t *nm = &vm->node_main;
1589   vlib_process_t *p = vec_elt (nm->processes, process_index);
1590   dispatch_process (vm, p, /* frame */ 0, /* cpu_time_now */ 0);
1591 }
1592
1593 static u64
1594 dispatch_suspended_process (vlib_main_t * vm,
1595                             uword process_index, u64 last_time_stamp)
1596 {
1597   vlib_node_main_t *nm = &vm->node_main;
1598   vlib_node_runtime_t *node_runtime;
1599   vlib_node_t *node;
1600   vlib_frame_t *f;
1601   vlib_process_t *p;
1602   vlib_pending_frame_t *pf;
1603   u64 t, n_vectors, is_suspend;
1604
1605   t = last_time_stamp;
1606
1607   p = vec_elt (nm->processes, process_index);
1608   if (PREDICT_FALSE (!(p->flags & VLIB_PROCESS_IS_RUNNING)))
1609     return last_time_stamp;
1610
1611   ASSERT (p->flags & (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
1612                       | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT));
1613
1614   pf = pool_elt_at_index (nm->suspended_process_frames,
1615                           p->suspended_process_frame_index);
1616
1617   node_runtime = &p->node_runtime;
1618   node = vlib_get_node (vm, node_runtime->node_index);
1619   f = pf->frame;
1620
1621   vlib_elog_main_loop_event (vm, node_runtime->node_index, t,
1622                              f ? f->n_vectors : 0, /* is_after */ 0);
1623
1624   /* Save away current process for suspend. */
1625   nm->current_process_index = node->runtime_index;
1626
1627   vlib_node_runtime_perf_counter (vm, node_runtime, f, 0, last_time_stamp,
1628                                   VLIB_NODE_RUNTIME_PERF_BEFORE);
1629
1630   n_vectors = vlib_process_resume (vm, p);
1631   t = clib_cpu_time_now ();
1632
1633   nm->current_process_index = ~0;
1634
1635   is_suspend = n_vectors == VLIB_PROCESS_RETURN_LONGJMP_SUSPEND;
1636   if (is_suspend)
1637     {
1638       /* Suspend it again. */
1639       n_vectors = 0;
1640       p->n_suspends += 1;
1641       if (p->flags & VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK)
1642         {
1643           p->stop_timer_handle =
1644             TW (tw_timer_start) ((TWT (tw_timer_wheel) *) nm->timing_wheel,
1645                                  vlib_timing_wheel_data_set_suspended_process
1646                                  (node->runtime_index) /* [sic] pool idex */ ,
1647                                  0 /* timer_id */ ,
1648                                  p->resume_clock_interval);
1649         }
1650     }
1651   else
1652     {
1653       p->flags &= ~VLIB_PROCESS_IS_RUNNING;
1654       pool_put_index (nm->suspended_process_frames,
1655                       p->suspended_process_frame_index);
1656       p->suspended_process_frame_index = ~0;
1657     }
1658
1659   t = clib_cpu_time_now ();
1660   vlib_elog_main_loop_event (vm, node_runtime->node_index, t, !is_suspend,
1661                              /* is_after */ 1);
1662
1663   vlib_node_runtime_perf_counter (vm, node_runtime, f, n_vectors, t,
1664                                   VLIB_NODE_RUNTIME_PERF_AFTER);
1665
1666   vlib_process_update_stats (vm, p,
1667                              /* n_calls */ !is_suspend,
1668                              /* n_vectors */ n_vectors,
1669                              /* n_clocks */ t - last_time_stamp);
1670
1671   return t;
1672 }
1673
1674 void vl_api_send_pending_rpc_requests (vlib_main_t *) __attribute__ ((weak));
1675 void
1676 vl_api_send_pending_rpc_requests (vlib_main_t * vm)
1677 {
1678 }
1679
1680 static_always_inline u64
1681 dispatch_pending_interrupts (vlib_main_t * vm, vlib_node_main_t * nm,
1682                              u64 cpu_time_now,
1683                              vlib_node_interrupt_t * interrupts)
1684 {
1685   vlib_node_runtime_t *n;
1686
1687   for (int i = 0; i < _vec_len (interrupts); i++)
1688     {
1689       vlib_node_interrupt_t *in;
1690       in = vec_elt_at_index (interrupts, i);
1691       n = vec_elt_at_index (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT],
1692                             in->node_runtime_index);
1693       n->interrupt_data = in->data;
1694       cpu_time_now = dispatch_node (vm, n, VLIB_NODE_TYPE_INPUT,
1695                                     VLIB_NODE_STATE_INTERRUPT, /* frame */ 0,
1696                                     cpu_time_now);
1697     }
1698   return cpu_time_now;
1699 }
1700
1701 static_always_inline void
1702 vlib_main_or_worker_loop (vlib_main_t * vm, int is_main)
1703 {
1704   vlib_node_main_t *nm = &vm->node_main;
1705   vlib_thread_main_t *tm = vlib_get_thread_main ();
1706   uword i;
1707   u64 cpu_time_now;
1708   f64 now;
1709   vlib_frame_queue_main_t *fqm;
1710   u32 frame_queue_check_counter = 0;
1711   vlib_node_interrupt_t *empty_int_list = 0;
1712
1713   /* Initialize pending node vector. */
1714   if (is_main)
1715     {
1716       vec_resize (nm->pending_frames, 32);
1717       _vec_len (nm->pending_frames) = 0;
1718     }
1719
1720   /* Mark time of main loop start. */
1721   if (is_main)
1722     {
1723       cpu_time_now = vm->clib_time.last_cpu_time;
1724       vm->cpu_time_main_loop_start = cpu_time_now;
1725     }
1726   else
1727     cpu_time_now = clib_cpu_time_now ();
1728
1729   /* Pre-allocate interupt runtime indices and lock. */
1730   vec_alloc (nm->pending_local_interrupts, 32);
1731   vec_alloc (nm->pending_remote_interrupts, 32);
1732   vec_alloc (empty_int_list, 32);
1733   vec_alloc_aligned (nm->pending_remote_interrupts_notify, 1,
1734                      CLIB_CACHE_LINE_BYTES);
1735   clib_spinlock_init (&nm->pending_interrupt_lock);
1736
1737   /* Pre-allocate expired nodes. */
1738   if (!nm->polling_threshold_vector_length)
1739     nm->polling_threshold_vector_length = 10;
1740   if (!nm->interrupt_threshold_vector_length)
1741     nm->interrupt_threshold_vector_length = 5;
1742
1743   vm->cpu_id = clib_get_current_cpu_id ();
1744   vm->numa_node = clib_get_current_numa_node ();
1745   os_set_numa_index (vm->numa_node);
1746
1747   /* Start all processes. */
1748   if (is_main)
1749     {
1750       uword i;
1751
1752       /*
1753        * Perform an initial barrier sync. Pays no attention to
1754        * the barrier sync hold-down timer scheme, which won't work
1755        * at this point in time.
1756        */
1757       vlib_worker_thread_initial_barrier_sync_and_release (vm);
1758
1759       nm->current_process_index = ~0;
1760       for (i = 0; i < vec_len (nm->processes); i++)
1761         cpu_time_now = dispatch_process (vm, nm->processes[i], /* frame */ 0,
1762                                          cpu_time_now);
1763     }
1764
1765   while (1)
1766     {
1767       vlib_node_runtime_t *n;
1768
1769       if (PREDICT_FALSE (_vec_len (vm->pending_rpc_requests) > 0))
1770         {
1771           if (!is_main)
1772             vl_api_send_pending_rpc_requests (vm);
1773         }
1774
1775       if (!is_main)
1776         vlib_worker_thread_barrier_check ();
1777
1778       if (PREDICT_FALSE (vm->check_frame_queues + frame_queue_check_counter))
1779         {
1780           u32 processed = 0;
1781
1782           if (vm->check_frame_queues)
1783             {
1784               frame_queue_check_counter = 100;
1785               vm->check_frame_queues = 0;
1786             }
1787
1788           vec_foreach (fqm, tm->frame_queue_mains)
1789             processed += vlib_frame_queue_dequeue (vm, fqm);
1790
1791           /* No handoff queue work found? */
1792           if (processed)
1793             frame_queue_check_counter = 100;
1794           else
1795             frame_queue_check_counter--;
1796         }
1797
1798       if (PREDICT_FALSE (vec_len (vm->worker_thread_main_loop_callbacks)))
1799         clib_call_callbacks (vm->worker_thread_main_loop_callbacks, vm,
1800                              cpu_time_now);
1801
1802       /* Process pre-input nodes. */
1803       cpu_time_now = clib_cpu_time_now ();
1804       vec_foreach (n, nm->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT])
1805         cpu_time_now = dispatch_node (vm, n,
1806                                       VLIB_NODE_TYPE_PRE_INPUT,
1807                                       VLIB_NODE_STATE_POLLING,
1808                                       /* frame */ 0,
1809                                       cpu_time_now);
1810
1811       /* Next process input nodes. */
1812       vec_foreach (n, nm->nodes_by_type[VLIB_NODE_TYPE_INPUT])
1813         cpu_time_now = dispatch_node (vm, n,
1814                                       VLIB_NODE_TYPE_INPUT,
1815                                       VLIB_NODE_STATE_POLLING,
1816                                       /* frame */ 0,
1817                                       cpu_time_now);
1818
1819       if (PREDICT_TRUE (is_main && vm->queue_signal_pending == 0))
1820         vm->queue_signal_callback (vm);
1821
1822       /* handle local interruots */
1823       if (_vec_len (nm->pending_local_interrupts))
1824         {
1825           vlib_node_interrupt_t *interrupts = nm->pending_local_interrupts;
1826           nm->pending_local_interrupts = empty_int_list;
1827           cpu_time_now = dispatch_pending_interrupts (vm, nm, cpu_time_now,
1828                                                       interrupts);
1829           empty_int_list = interrupts;
1830           vec_reset_length (empty_int_list);
1831         }
1832
1833       /* handle remote interruots */
1834       if (PREDICT_FALSE (_vec_len (nm->pending_remote_interrupts)))
1835         {
1836           vlib_node_interrupt_t *interrupts;
1837
1838           /* at this point it is known that
1839            * vec_len (nm->pending_local_interrupts) is zero so we quickly swap
1840            * local and remote vector under the spinlock */
1841           clib_spinlock_lock (&nm->pending_interrupt_lock);
1842           interrupts = nm->pending_remote_interrupts;
1843           nm->pending_remote_interrupts = empty_int_list;
1844           *nm->pending_remote_interrupts_notify = 0;
1845           clib_spinlock_unlock (&nm->pending_interrupt_lock);
1846
1847           cpu_time_now = dispatch_pending_interrupts (vm, nm, cpu_time_now,
1848                                                       interrupts);
1849           empty_int_list = interrupts;
1850           vec_reset_length (empty_int_list);
1851         }
1852
1853       /* Input nodes may have added work to the pending vector.
1854          Process pending vector until there is nothing left.
1855          All pending vectors will be processed from input -> output. */
1856       for (i = 0; i < _vec_len (nm->pending_frames); i++)
1857         cpu_time_now = dispatch_pending_node (vm, i, cpu_time_now);
1858       /* Reset pending vector for next iteration. */
1859       _vec_len (nm->pending_frames) = 0;
1860
1861       if (is_main)
1862         {
1863           /* *INDENT-OFF* */
1864           ELOG_TYPE_DECLARE (es) =
1865             {
1866               .format = "process tw start",
1867               .format_args = "",
1868             };
1869           ELOG_TYPE_DECLARE (ee) =
1870             {
1871               .format = "process tw end: %d",
1872               .format_args = "i4",
1873             };
1874           /* *INDENT-ON* */
1875
1876           struct
1877           {
1878             int nready_procs;
1879           } *ed;
1880
1881           /* Check if process nodes have expired from timing wheel. */
1882           ASSERT (nm->data_from_advancing_timing_wheel != 0);
1883
1884           if (PREDICT_FALSE (vm->elog_trace_graph_dispatch))
1885             ed = ELOG_DATA (&vlib_global_main.elog_main, es);
1886
1887           nm->data_from_advancing_timing_wheel =
1888             TW (tw_timer_expire_timers_vec)
1889             ((TWT (tw_timer_wheel) *) nm->timing_wheel, vlib_time_now (vm),
1890              nm->data_from_advancing_timing_wheel);
1891
1892           ASSERT (nm->data_from_advancing_timing_wheel != 0);
1893
1894           if (PREDICT_FALSE (vm->elog_trace_graph_dispatch))
1895             {
1896               ed = ELOG_DATA (&vlib_global_main.elog_main, ee);
1897               ed->nready_procs =
1898                 _vec_len (nm->data_from_advancing_timing_wheel);
1899             }
1900
1901           if (PREDICT_FALSE
1902               (_vec_len (nm->data_from_advancing_timing_wheel) > 0))
1903             {
1904               uword i;
1905
1906               for (i = 0; i < _vec_len (nm->data_from_advancing_timing_wheel);
1907                    i++)
1908                 {
1909                   u32 d = nm->data_from_advancing_timing_wheel[i];
1910                   u32 di = vlib_timing_wheel_data_get_index (d);
1911
1912                   if (vlib_timing_wheel_data_is_timed_event (d))
1913                     {
1914                       vlib_signal_timed_event_data_t *te =
1915                         pool_elt_at_index (nm->signal_timed_event_data_pool,
1916                                            di);
1917                       vlib_node_t *n =
1918                         vlib_get_node (vm, te->process_node_index);
1919                       vlib_process_t *p =
1920                         vec_elt (nm->processes, n->runtime_index);
1921                       void *data;
1922                       data =
1923                         vlib_process_signal_event_helper (nm, n, p,
1924                                                           te->event_type_index,
1925                                                           te->n_data_elts,
1926                                                           te->n_data_elt_bytes);
1927                       if (te->n_data_bytes < sizeof (te->inline_event_data))
1928                         clib_memcpy_fast (data, te->inline_event_data,
1929                                           te->n_data_bytes);
1930                       else
1931                         {
1932                           clib_memcpy_fast (data, te->event_data_as_vector,
1933                                             te->n_data_bytes);
1934                           vec_free (te->event_data_as_vector);
1935                         }
1936                       pool_put (nm->signal_timed_event_data_pool, te);
1937                     }
1938                   else
1939                     {
1940                       cpu_time_now = clib_cpu_time_now ();
1941                       cpu_time_now =
1942                         dispatch_suspended_process (vm, di, cpu_time_now);
1943                     }
1944                 }
1945               _vec_len (nm->data_from_advancing_timing_wheel) = 0;
1946             }
1947         }
1948       vlib_increment_main_loop_counter (vm);
1949       /* Record time stamp in case there are no enabled nodes and above
1950          calls do not update time stamp. */
1951       cpu_time_now = clib_cpu_time_now ();
1952       vm->loops_this_reporting_interval++;
1953       now = clib_time_now_internal (&vm->clib_time, cpu_time_now);
1954       /* Time to update loops_per_second? */
1955       if (PREDICT_FALSE (now >= vm->loop_interval_end))
1956         {
1957           /* Next sample ends in 20ms */
1958           if (vm->loop_interval_start)
1959             {
1960               f64 this_loops_per_second;
1961
1962               this_loops_per_second =
1963                 ((f64) vm->loops_this_reporting_interval) / (now -
1964                                                              vm->loop_interval_start);
1965
1966               vm->loops_per_second =
1967                 vm->loops_per_second * vm->damping_constant +
1968                 (1.0 - vm->damping_constant) * this_loops_per_second;
1969               if (vm->loops_per_second != 0.0)
1970                 vm->seconds_per_loop = 1.0 / vm->loops_per_second;
1971               else
1972                 vm->seconds_per_loop = 0.0;
1973             }
1974           /* New interval starts now, and ends in 20ms */
1975           vm->loop_interval_start = now;
1976           vm->loop_interval_end = now + 2e-4;
1977           vm->loops_this_reporting_interval = 0;
1978         }
1979     }
1980 }
1981
1982 static void
1983 vlib_main_loop (vlib_main_t * vm)
1984 {
1985   vlib_main_or_worker_loop (vm, /* is_main */ 1);
1986 }
1987
1988 void
1989 vlib_worker_loop (vlib_main_t * vm)
1990 {
1991   vlib_main_or_worker_loop (vm, /* is_main */ 0);
1992 }
1993
1994 vlib_main_t vlib_global_main;
1995
1996 static clib_error_t *
1997 vlib_main_configure (vlib_main_t * vm, unformat_input_t * input)
1998 {
1999   int turn_on_mem_trace = 0;
2000
2001   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2002     {
2003       if (unformat (input, "memory-trace"))
2004         turn_on_mem_trace = 1;
2005
2006       else if (unformat (input, "elog-events %d",
2007                          &vm->elog_main.event_ring_size))
2008         ;
2009       else if (unformat (input, "elog-post-mortem-dump"))
2010         vm->elog_post_mortem_dump = 1;
2011       else if (unformat (input, "buffer-alloc-success-rate %f",
2012                          &vm->buffer_alloc_success_rate))
2013         {
2014           if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR == 0)
2015             return clib_error_return
2016               (0, "Buffer fault injection not configured");
2017         }
2018       else if (unformat (input, "buffer-alloc-success-seed %u",
2019                          &vm->buffer_alloc_success_seed))
2020         {
2021           if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR == 0)
2022             return clib_error_return
2023               (0, "Buffer fault injection not configured");
2024         }
2025       else
2026         return unformat_parse_error (input);
2027     }
2028
2029   unformat_free (input);
2030
2031   /* Enable memory trace as early as possible. */
2032   if (turn_on_mem_trace)
2033     clib_mem_trace (1);
2034
2035   return 0;
2036 }
2037
2038 VLIB_EARLY_CONFIG_FUNCTION (vlib_main_configure, "vlib");
2039
2040 static void
2041 placeholder_queue_signal_callback (vlib_main_t * vm)
2042 {
2043 }
2044
2045 #define foreach_weak_reference_stub             \
2046 _(vlib_map_stat_segment_init)                   \
2047 _(vpe_api_init)                                 \
2048 _(vlibmemory_init)                              \
2049 _(map_api_segment_init)
2050
2051 #define _(name)                                                 \
2052 clib_error_t *name (vlib_main_t *vm) __attribute__((weak));     \
2053 clib_error_t *name (vlib_main_t *vm) { return 0; }
2054 foreach_weak_reference_stub;
2055 #undef _
2056
2057 void vl_api_set_elog_main (elog_main_t * m) __attribute__ ((weak));
2058 void
2059 vl_api_set_elog_main (elog_main_t * m)
2060 {
2061   clib_warning ("STUB");
2062 }
2063
2064 int vl_api_set_elog_trace_api_messages (int enable) __attribute__ ((weak));
2065 int
2066 vl_api_set_elog_trace_api_messages (int enable)
2067 {
2068   clib_warning ("STUB");
2069   return 0;
2070 }
2071
2072 int vl_api_get_elog_trace_api_messages (void) __attribute__ ((weak));
2073 int
2074 vl_api_get_elog_trace_api_messages (void)
2075 {
2076   clib_warning ("STUB");
2077   return 0;
2078 }
2079
2080 /* Main function. */
2081 int
2082 vlib_main (vlib_main_t * volatile vm, unformat_input_t * input)
2083 {
2084   clib_error_t *volatile error;
2085   vlib_node_main_t *nm = &vm->node_main;
2086
2087   vm->queue_signal_callback = placeholder_queue_signal_callback;
2088
2089   /* Turn on event log. */
2090   if (!vm->elog_main.event_ring_size)
2091     vm->elog_main.event_ring_size = 128 << 10;
2092   elog_init (&vm->elog_main, vm->elog_main.event_ring_size);
2093   elog_enable_disable (&vm->elog_main, 1);
2094   vl_api_set_elog_main (&vm->elog_main);
2095   (void) vl_api_set_elog_trace_api_messages (1);
2096
2097   /* Default name. */
2098   if (!vm->name)
2099     vm->name = "VLIB";
2100
2101   if ((error = vlib_physmem_init (vm)))
2102     {
2103       clib_error_report (error);
2104       goto done;
2105     }
2106
2107   if ((error = vlib_map_stat_segment_init (vm)))
2108     {
2109       clib_error_report (error);
2110       goto done;
2111     }
2112
2113   if ((error = vlib_buffer_main_init (vm)))
2114     {
2115       clib_error_report (error);
2116       goto done;
2117     }
2118
2119   if ((error = vlib_thread_init (vm)))
2120     {
2121       clib_error_report (error);
2122       goto done;
2123     }
2124
2125   /* Register static nodes so that init functions may use them. */
2126   vlib_register_all_static_nodes (vm);
2127
2128   /* Set seed for random number generator.
2129      Allow user to specify seed to make random sequence deterministic. */
2130   if (!unformat (input, "seed %wd", &vm->random_seed))
2131     vm->random_seed = clib_cpu_time_now ();
2132   clib_random_buffer_init (&vm->random_buffer, vm->random_seed);
2133
2134   /* Initialize node graph. */
2135   if ((error = vlib_node_main_init (vm)))
2136     {
2137       /* Arrange for graph hook up error to not be fatal when debugging. */
2138       if (CLIB_DEBUG > 0)
2139         clib_error_report (error);
2140       else
2141         goto done;
2142     }
2143
2144   /* Direct call / weak reference, for vlib standalone use-cases */
2145   if ((error = vpe_api_init (vm)))
2146     {
2147       clib_error_report (error);
2148       goto done;
2149     }
2150
2151   if ((error = vlibmemory_init (vm)))
2152     {
2153       clib_error_report (error);
2154       goto done;
2155     }
2156
2157   if ((error = map_api_segment_init (vm)))
2158     {
2159       clib_error_report (error);
2160       goto done;
2161     }
2162
2163   /* See unix/main.c; most likely already set up */
2164   if (vm->init_functions_called == 0)
2165     vm->init_functions_called = hash_create (0, /* value bytes */ 0);
2166   if ((error = vlib_call_all_init_functions (vm)))
2167     goto done;
2168
2169   nm->timing_wheel = clib_mem_alloc_aligned (sizeof (TWT (tw_timer_wheel)),
2170                                              CLIB_CACHE_LINE_BYTES);
2171
2172   vec_validate (nm->data_from_advancing_timing_wheel, 10);
2173   _vec_len (nm->data_from_advancing_timing_wheel) = 0;
2174
2175   /* Create the process timing wheel */
2176   TW (tw_timer_wheel_init) ((TWT (tw_timer_wheel) *) nm->timing_wheel,
2177                             0 /* no callback */ ,
2178                             10e-6 /* timer period 10us */ ,
2179                             ~0 /* max expirations per call */ );
2180
2181   vec_validate (vm->pending_rpc_requests, 0);
2182   _vec_len (vm->pending_rpc_requests) = 0;
2183   vec_validate (vm->processing_rpc_requests, 0);
2184   _vec_len (vm->processing_rpc_requests) = 0;
2185
2186   /* Default params for the buffer allocator fault injector, if configured */
2187   if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR > 0)
2188     {
2189       vm->buffer_alloc_success_seed = 0xdeaddabe;
2190       vm->buffer_alloc_success_rate = 0.80;
2191     }
2192
2193   if ((error = vlib_call_all_config_functions (vm, input, 0 /* is_early */ )))
2194     goto done;
2195
2196   /*
2197    * Use exponential smoothing, with a half-life of 1 second
2198    * reported_rate(t) = reported_rate(t-1) * K + rate(t)*(1-K)
2199    *
2200    * Sample every 20ms, aka 50 samples per second
2201    * K = exp (-1.0/20.0);
2202    * K = 0.95
2203    */
2204   vm->damping_constant = exp (-1.0 / 20.0);
2205
2206   /* Sort per-thread init functions before we start threads */
2207   vlib_sort_init_exit_functions (&vm->worker_init_function_registrations);
2208
2209   /* Call all main loop enter functions. */
2210   {
2211     clib_error_t *sub_error;
2212     sub_error = vlib_call_all_main_loop_enter_functions (vm);
2213     if (sub_error)
2214       clib_error_report (sub_error);
2215   }
2216
2217   switch (clib_setjmp (&vm->main_loop_exit, VLIB_MAIN_LOOP_EXIT_NONE))
2218     {
2219     case VLIB_MAIN_LOOP_EXIT_NONE:
2220       vm->main_loop_exit_set = 1;
2221       break;
2222
2223     case VLIB_MAIN_LOOP_EXIT_CLI:
2224       goto done;
2225
2226     default:
2227       error = vm->main_loop_error;
2228       goto done;
2229     }
2230
2231   vlib_main_loop (vm);
2232
2233 done:
2234   /* Call all exit functions. */
2235   {
2236     clib_error_t *sub_error;
2237     sub_error = vlib_call_all_main_loop_exit_functions (vm);
2238     if (sub_error)
2239       clib_error_report (sub_error);
2240   }
2241
2242   if (error)
2243     clib_error_report (error);
2244
2245   return 0;
2246 }
2247
2248 int
2249 vlib_pcap_dispatch_trace_configure (vlib_pcap_dispatch_trace_args_t * a)
2250 {
2251   vlib_main_t *vm = vlib_get_main ();
2252   pcap_main_t *pm = &vm->dispatch_pcap_main;
2253   vlib_trace_main_t *tm;
2254   vlib_trace_node_t *tn;
2255
2256   if (a->status)
2257     {
2258       if (vm->dispatch_pcap_enable)
2259         {
2260           int i;
2261           vlib_cli_output
2262             (vm, "pcap dispatch capture enabled: %d of %d pkts...",
2263              pm->n_packets_captured, pm->n_packets_to_capture);
2264           vlib_cli_output (vm, "capture to file %s", pm->file_name);
2265
2266           for (i = 0; i < vec_len (vm->dispatch_buffer_trace_nodes); i++)
2267             {
2268               vlib_cli_output (vm,
2269                                "Buffer trace of %d pkts from %U enabled...",
2270                                a->buffer_traces_to_capture,
2271                                format_vlib_node_name, vm,
2272                                vm->dispatch_buffer_trace_nodes[i]);
2273             }
2274         }
2275       else
2276         vlib_cli_output (vm, "pcap dispatch capture disabled");
2277       return 0;
2278     }
2279
2280   /* Consistency checks */
2281
2282   /* Enable w/ capture already enabled not allowed */
2283   if (vm->dispatch_pcap_enable && a->enable)
2284     return -7;                  /* VNET_API_ERROR_INVALID_VALUE */
2285
2286   /* Disable capture with capture already disabled, not interesting */
2287   if (vm->dispatch_pcap_enable == 0 && a->enable == 0)
2288     return -81;                 /* VNET_API_ERROR_VALUE_EXIST */
2289
2290   /* Change number of packets to capture while capturing */
2291   if (vm->dispatch_pcap_enable && a->enable
2292       && (pm->n_packets_to_capture != a->packets_to_capture))
2293     return -8;                  /* VNET_API_ERROR_INVALID_VALUE_2 */
2294
2295   /* Independent of enable/disable, to allow buffer trace multi nodes */
2296   if (a->buffer_trace_node_index != ~0)
2297     {
2298       /* *INDENT-OFF* */
2299       foreach_vlib_main ((
2300         {
2301           tm = &this_vlib_main->trace_main;
2302           tm->verbose = 0;  /* not sure this ever did anything... */
2303           vec_validate (tm->nodes, a->buffer_trace_node_index);
2304           tn = tm->nodes + a->buffer_trace_node_index;
2305           tn->limit += a->buffer_traces_to_capture;
2306           tm->trace_enable = 1;
2307         }));
2308       /* *INDENT-ON* */
2309       vec_add1 (vm->dispatch_buffer_trace_nodes, a->buffer_trace_node_index);
2310     }
2311
2312   if (a->enable)
2313     {
2314       /* Clean up from previous run, if any */
2315       vec_free (pm->file_name);
2316       vec_free (pm->pcap_data);
2317       memset (pm, 0, sizeof (*pm));
2318
2319       vec_validate_aligned (vnet_trace_placeholder, 2048,
2320                             CLIB_CACHE_LINE_BYTES);
2321       if (pm->lock == 0)
2322         clib_spinlock_init (&(pm->lock));
2323
2324       if (a->filename == 0)
2325         a->filename = format (0, "/tmp/dispatch.pcap%c", 0);
2326
2327       pm->file_name = (char *) a->filename;
2328       pm->n_packets_captured = 0;
2329       pm->packet_type = PCAP_PACKET_TYPE_vpp;
2330       pm->n_packets_to_capture = a->packets_to_capture;
2331       /* *INDENT-OFF* */
2332       foreach_vlib_main (({this_vlib_main->dispatch_pcap_enable = 1;}));
2333       /* *INDENT-ON* */
2334     }
2335   else
2336     {
2337       /* *INDENT-OFF* */
2338       foreach_vlib_main (({this_vlib_main->dispatch_pcap_enable = 0;}));
2339       /* *INDENT-ON* */
2340       vec_reset_length (vm->dispatch_buffer_trace_nodes);
2341       if (pm->n_packets_captured)
2342         {
2343           clib_error_t *error;
2344           pm->n_packets_to_capture = pm->n_packets_captured;
2345           vlib_cli_output (vm, "Write %d packets to %s, and stop capture...",
2346                            pm->n_packets_captured, pm->file_name);
2347           error = pcap_write (pm);
2348           if (pm->flags & PCAP_MAIN_INIT_DONE)
2349             pcap_close (pm);
2350           /* Report I/O errors... */
2351           if (error)
2352             {
2353               clib_error_report (error);
2354               return -11;       /* VNET_API_ERROR_SYSCALL_ERROR_1 */
2355             }
2356           return 0;
2357         }
2358       else
2359         return -6;              /* VNET_API_ERROR_NO_SUCH_ENTRY */
2360     }
2361
2362   return 0;
2363 }
2364
2365 static clib_error_t *
2366 dispatch_trace_command_fn (vlib_main_t * vm,
2367                            unformat_input_t * input, vlib_cli_command_t * cmd)
2368 {
2369   unformat_input_t _line_input, *line_input = &_line_input;
2370   vlib_pcap_dispatch_trace_args_t _a, *a = &_a;
2371   u8 *filename = 0;
2372   u32 max = 1000;
2373   int rv;
2374   int enable = 0;
2375   int status = 0;
2376   u32 node_index = ~0, buffer_traces_to_capture = 100;
2377
2378   /* Get a line of input. */
2379   if (!unformat_user (input, unformat_line_input, line_input))
2380     return 0;
2381
2382   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2383     {
2384       if (unformat (line_input, "on %=", &enable, 1))
2385         ;
2386       else if (unformat (line_input, "enable %=", &enable, 1))
2387         ;
2388       else if (unformat (line_input, "off %=", &enable, 0))
2389         ;
2390       else if (unformat (line_input, "disable %=", &enable, 0))
2391         ;
2392       else if (unformat (line_input, "max %d", &max))
2393         ;
2394       else if (unformat (line_input, "packets-to-capture %d", &max))
2395         ;
2396       else if (unformat (line_input, "file %U", unformat_vlib_tmpfile,
2397                          &filename))
2398         ;
2399       else if (unformat (line_input, "status %=", &status, 1))
2400         ;
2401       else if (unformat (line_input, "buffer-trace %U %d",
2402                          unformat_vlib_node, vm, &node_index,
2403                          &buffer_traces_to_capture))
2404         ;
2405       else
2406         {
2407           return clib_error_return (0, "unknown input `%U'",
2408                                     format_unformat_error, line_input);
2409         }
2410     }
2411
2412   unformat_free (line_input);
2413
2414   /* no need for memset (a, 0, sizeof (*a)), set all fields here. */
2415   a->filename = filename;
2416   a->enable = enable;
2417   a->status = status;
2418   a->packets_to_capture = max;
2419   a->buffer_trace_node_index = node_index;
2420   a->buffer_traces_to_capture = buffer_traces_to_capture;
2421
2422   rv = vlib_pcap_dispatch_trace_configure (a);
2423
2424   switch (rv)
2425     {
2426     case 0:
2427       break;
2428
2429     case -7:
2430       return clib_error_return (0, "dispatch trace already enabled...");
2431
2432     case -81:
2433       return clib_error_return (0, "dispatch trace already disabled...");
2434
2435     case -8:
2436       return clib_error_return
2437         (0, "can't change number of records to capture while tracing...");
2438
2439     case -11:
2440       return clib_error_return (0, "I/O writing trace capture...");
2441
2442     case -6:
2443       return clib_error_return (0, "No packets captured...");
2444
2445     default:
2446       vlib_cli_output (vm, "WARNING: trace configure returned %d", rv);
2447       break;
2448     }
2449   return 0;
2450 }
2451
2452 /*?
2453  * This command is used to start or stop pcap dispatch trace capture, or show
2454  * the capture status.
2455  *
2456  * This command has the following optional parameters:
2457  *
2458  * - <b>on|off</b> - Used to start or stop capture.
2459  *
2460  * - <b>max <nn></b> - Depth of local buffer. Once '<em>nn</em>' number
2461  *   of packets have been received, buffer is flushed to file. Once another
2462  *   '<em>nn</em>' number of packets have been received, buffer is flushed
2463  *   to file, overwriting previous write. If not entered, value defaults
2464  *   to 100. Can only be updated if packet capture is off.
2465  *
2466  * - <b>file <name></b> - Used to specify the output filename. The file will
2467  *   be placed in the '<em>/tmp</em>' directory, so only the filename is
2468  *   supported. Directory should not be entered. If file already exists, file
2469  *   will be overwritten. If no filename is provided, '<em>/tmp/vpe.pcap</em>'
2470  *   will be used. Can only be updated if packet capture is off.
2471  *
2472  * - <b>status</b> - Displays the current status and configured attributes
2473  *   associated with a packet capture. If packet capture is in progress,
2474  *   '<em>status</em>' also will return the number of packets currently in
2475  *   the local buffer. All additional attributes entered on command line
2476  *   with '<em>status</em>' will be ignored and not applied.
2477  *
2478  * @cliexpar
2479  * Example of how to display the status of capture when off:
2480  * @cliexstart{pcap dispatch trace status}
2481  * max is 100, for any interface to file /tmp/vpe.pcap
2482  * pcap dispatch capture is off...
2483  * @cliexend
2484  * Example of how to start a dispatch trace capture:
2485  * @cliexstart{pcap dispatch trace on max 35 file dispatchTrace.pcap}
2486  * pcap dispatch capture on...
2487  * @cliexend
2488  * Example of how to start a dispatch trace capture with buffer tracing
2489  * @cliexstart{pcap dispatch trace on max 10000 file dispatchTrace.pcap buffer-trace dpdk-input 1000}
2490  * pcap dispatch capture on...
2491  * @cliexend
2492  * Example of how to display the status of a tx packet capture in progress:
2493  * @cliexstart{pcap tx trace status}
2494  * max is 35, dispatch trace to file /tmp/vppTest.pcap
2495  * pcap tx capture is on: 20 of 35 pkts...
2496  * @cliexend
2497  * Example of how to stop a tx packet capture:
2498  * @cliexstart{vppctl pcap dispatch trace off}
2499  * captured 21 pkts...
2500  * saved to /tmp/dispatchTrace.pcap...
2501  * @cliexend
2502 ?*/
2503 /* *INDENT-OFF* */
2504 VLIB_CLI_COMMAND (pcap_dispatch_trace_command, static) = {
2505     .path = "pcap dispatch trace",
2506     .short_help =
2507     "pcap dispatch trace [on|off] [max <nn>] [file <name>] [status]\n"
2508     "              [buffer-trace <input-node-name> <nn>]",
2509     .function = dispatch_trace_command_fn,
2510 };
2511 /* *INDENT-ON* */
2512
2513 vlib_main_t *
2514 vlib_get_main_not_inline (void)
2515 {
2516   return vlib_get_main ();
2517 }
2518
2519 elog_main_t *
2520 vlib_get_elog_main_not_inline ()
2521 {
2522   return &vlib_global_main.elog_main;
2523 }
2524
2525 /*
2526  * fd.io coding-style-patch-verification: ON
2527  *
2528  * Local Variables:
2529  * eval: (c-set-style "gnu")
2530  * End:
2531  */