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