Initial commit of vpp code.
[vpp.git] / vlib / 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
45 #include <vlib/unix/cj.h>
46
47 CJ_GLOBAL_LOG_PROTOTYPE;
48
49
50 //#define VLIB_ELOG_MAIN_LOOP 1
51
52 /* Actually allocate a few extra slots of vector data to support
53    speculative vector enqueues which overflow vector data in next frame. */
54 #define VLIB_FRAME_SIZE_ALLOC (VLIB_FRAME_SIZE + 4)
55
56 always_inline u32
57 vlib_frame_bytes (u32 n_scalar_bytes, u32 n_vector_bytes)
58 {
59   u32 n_bytes;
60
61   /* Make room for vlib_frame_t plus scalar arguments. */
62   n_bytes = vlib_frame_vector_byte_offset (n_scalar_bytes);
63
64   /* Make room for vector arguments.
65      Allocate a few extra slots of vector data to support
66      speculative vector enqueues which overflow vector data in next frame. */
67 #define VLIB_FRAME_SIZE_EXTRA 4
68   n_bytes += (VLIB_FRAME_SIZE + VLIB_FRAME_SIZE_EXTRA) * n_vector_bytes;
69
70   /* Magic number is first 32bit number after vector data.
71      Used to make sure that vector data is never overrun. */
72 #define VLIB_FRAME_MAGIC (0xabadc0ed)
73   n_bytes += sizeof (u32);
74
75   /* Pad to cache line. */
76   n_bytes = round_pow2 (n_bytes, CLIB_CACHE_LINE_BYTES);
77
78   return n_bytes;
79 }
80
81 always_inline u32 *
82 vlib_frame_find_magic (vlib_frame_t * f, vlib_node_t * node)
83 {
84   void * p = f;
85
86   p += vlib_frame_vector_byte_offset (node->scalar_size);
87
88   p += (VLIB_FRAME_SIZE + VLIB_FRAME_SIZE_EXTRA) * node->vector_size;
89
90   return p;
91 }
92
93 static vlib_frame_size_t *
94 get_frame_size_info (vlib_node_main_t * nm,
95                      u32 n_scalar_bytes, u32 n_vector_bytes)
96 {
97   uword key = (n_scalar_bytes << 16) | n_vector_bytes;
98   uword * p, i;
99
100   p = hash_get (nm->frame_size_hash, key);
101   if (p)
102     i = p[0];
103   else
104     {
105       i = vec_len (nm->frame_sizes);
106       vec_validate (nm->frame_sizes, i);
107       hash_set (nm->frame_size_hash, key, i);
108     }
109
110   return vec_elt_at_index (nm->frame_sizes, i);
111 }
112
113 static u32
114 vlib_frame_alloc_to_node (vlib_main_t * vm, u32 to_node_index, u32 frame_flags)
115 {
116   vlib_node_main_t * nm = &vm->node_main;
117   vlib_frame_size_t * fs;
118   vlib_node_t * to_node;
119   vlib_frame_t * f;
120   u32 fi, l, n, scalar_size, vector_size;
121
122   to_node = vlib_get_node (vm, to_node_index);
123
124   scalar_size = to_node->scalar_size;
125   vector_size = to_node->vector_size;
126
127   fs = get_frame_size_info (nm, scalar_size, vector_size);
128   n = vlib_frame_bytes (scalar_size, vector_size);
129   if ((l = vec_len (fs->free_frame_indices)) > 0)
130     {
131       /* Allocate from end of free list. */
132       fi = fs->free_frame_indices[l - 1];
133       f = vlib_get_frame_no_check (vm, fi);
134       _vec_len (fs->free_frame_indices) = l - 1;
135     }
136   else
137     {
138       f = clib_mem_alloc_aligned_no_fail (n, CLIB_CACHE_LINE_BYTES);
139       f->cpu_index = vm->cpu_index;
140       fi = vlib_frame_index_no_check (vm, f);
141     }
142
143   /* Poison frame when debugging. */
144   if (CLIB_DEBUG > 0)
145     {
146       u32 save_cpu_index = f->cpu_index;
147
148       memset (f, 0xfe, n);
149
150       f->cpu_index = save_cpu_index;
151     }
152
153   /* Insert magic number. */
154   {
155     u32 * magic;
156
157     magic = vlib_frame_find_magic (f, to_node);
158     *magic = VLIB_FRAME_MAGIC;
159   }
160
161   f->flags = VLIB_FRAME_IS_ALLOCATED | frame_flags;
162   f->n_vectors = 0;
163   f->scalar_size = scalar_size;
164   f->vector_size = vector_size;
165
166   fs->n_alloc_frames += 1;
167
168   return fi;
169 }
170
171 /* Allocate a frame for from FROM_NODE to TO_NODE via TO_NEXT_INDEX.
172    Returns frame index. */
173 static u32
174 vlib_frame_alloc (vlib_main_t * vm, vlib_node_runtime_t * from_node_runtime, u32 to_next_index)
175 {
176   vlib_node_t * from_node;
177
178   from_node = vlib_get_node (vm, from_node_runtime->node_index);
179   ASSERT (to_next_index < vec_len (from_node->next_nodes));
180
181   return vlib_frame_alloc_to_node (vm,
182                                    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   u32 fi = vlib_frame_alloc_to_node (vm, to_node_index,
190                                      /* frame_flags */ VLIB_FRAME_FREE_AFTER_DISPATCH);
191   return vlib_get_frame (vm, fi);
192 }
193
194 void vlib_put_frame_to_node (vlib_main_t * vm, u32 to_node_index, vlib_frame_t * f)
195 {
196   vlib_pending_frame_t * p;
197   vlib_node_t * to_node;
198
199   if (f->n_vectors == 0)
200     return;
201
202   to_node = vlib_get_node (vm, to_node_index);
203
204   vec_add2 (vm->node_main.pending_frames, p, 1);
205
206   f->flags |= VLIB_FRAME_PENDING;
207   p->frame_index = vlib_frame_index (vm, f);
208   p->node_runtime_index = to_node->runtime_index;
209   p->next_frame_index = VLIB_PENDING_FRAME_NO_NEXT_FRAME;
210 }
211
212 /* Free given frame. */
213 void
214 vlib_frame_free (vlib_main_t * vm,
215                  vlib_node_runtime_t * r,
216                  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   u32 frame_index;
222   
223   ASSERT (f->flags & VLIB_FRAME_IS_ALLOCATED);
224
225   node = vlib_get_node (vm, r->node_index);
226   fs = get_frame_size_info (nm, node->scalar_size, node->vector_size);
227
228   frame_index = vlib_frame_index (vm, f);
229
230   ASSERT (f->flags & VLIB_FRAME_IS_ALLOCATED);
231
232   /* No next frames may point to freed frame. */
233   if (CLIB_DEBUG > 0)
234     {
235       vlib_next_frame_t * nf;
236       vec_foreach (nf, vm->node_main.next_frames)
237         ASSERT (nf->frame_index != frame_index);
238     }
239
240   f->flags &= ~VLIB_FRAME_IS_ALLOCATED;
241
242   vec_add1 (fs->free_frame_indices, frame_index);
243   ASSERT (fs->n_alloc_frames > 0);
244   fs->n_alloc_frames -= 1;
245 }
246
247 static clib_error_t *
248 show_frame_stats (vlib_main_t * vm,
249                   unformat_input_t * input,
250                   vlib_cli_command_t * cmd)
251 {
252   vlib_node_main_t * nm = &vm->node_main;
253   vlib_frame_size_t * fs;
254   
255   vlib_cli_output (vm, "%=6s%=12s%=12s", "Size", "# Alloc", "# Free");
256   vec_foreach (fs, nm->frame_sizes)
257     {
258       u32 n_alloc = fs->n_alloc_frames;
259       u32 n_free = vec_len (fs->free_frame_indices);
260
261       if (n_alloc + n_free > 0)
262         vlib_cli_output (vm, "%=6d%=12d%=12d",
263                          fs - nm->frame_sizes, n_alloc, n_free);
264     }
265
266   return 0;
267 }
268
269 VLIB_CLI_COMMAND (show_frame_stats_cli, static) = {
270   .path = "show vlib frame-allocation",
271   .short_help = "Show node dispatch frame statistics",
272   .function = show_frame_stats,
273 };
274
275 /* Change ownership of enqueue rights to given next node. */
276 static void
277 vlib_next_frame_change_ownership (vlib_main_t * vm,
278                                   vlib_node_runtime_t * node_runtime,
279                                   u32 next_index)
280 {
281   vlib_node_main_t * nm = &vm->node_main;
282   vlib_next_frame_t * next_frame;
283   vlib_node_t * node, * next_node;
284
285   node = vec_elt (nm->nodes, node_runtime->node_index);
286
287   /* Only internal & input nodes are allowed to call other nodes. */
288   ASSERT (node->type == VLIB_NODE_TYPE_INTERNAL
289           || node->type == VLIB_NODE_TYPE_INPUT
290           || node->type == VLIB_NODE_TYPE_PROCESS);
291
292   ASSERT (vec_len (node->next_nodes) == node_runtime->n_next_nodes);
293
294   next_frame = vlib_node_runtime_get_next_frame (vm, node_runtime, next_index);
295   next_node = vec_elt (nm->nodes, node->next_nodes[next_index]);
296
297   if (next_node->owner_node_index != VLIB_INVALID_NODE_INDEX)
298     {
299       /* Get frame from previous owner. */
300       vlib_next_frame_t * owner_next_frame;
301       vlib_next_frame_t tmp;
302
303       owner_next_frame =
304         vlib_node_get_next_frame (vm,
305                                   next_node->owner_node_index,
306                                   next_node->owner_next_index);
307
308       /* Swap target next frame with owner's. */
309       tmp = owner_next_frame[0];
310       owner_next_frame[0] = next_frame[0];
311       next_frame[0] = tmp;
312
313       /*
314        * If next_frame is already pending, we have to track down
315        * all pending frames and fix their next_frame_index fields.
316        */
317       if (next_frame->flags & VLIB_FRAME_PENDING)
318         {
319           vlib_pending_frame_t * p;
320           if (next_frame->frame_index != ~0)
321             {
322               vec_foreach (p, nm->pending_frames)
323                 {
324                   if (p->frame_index == next_frame->frame_index)
325                     {
326                       p->next_frame_index = 
327                         next_frame - vm->node_main.next_frames;
328                     }
329                 }
330             }
331         }
332     }
333   else
334     {
335       /* No previous owner. Take ownership. */
336       next_frame->flags |= VLIB_FRAME_OWNER;
337     }
338                                            
339   /* Record new owner. */
340   next_node->owner_node_index = node->index;
341   next_node->owner_next_index = next_index;
342
343   /* Now we should be owner. */
344   ASSERT (next_frame->flags & VLIB_FRAME_OWNER);
345 }             
346
347 /* Make sure that magic number is still there.
348    Otherwise, it is likely that caller has overrun frame arguments. */
349 always_inline void
350 validate_frame_magic (vlib_main_t * vm,
351                       vlib_frame_t * f,
352                       vlib_node_t * n,
353                       uword next_index)
354 {
355   vlib_node_t * next_node = vlib_get_node (vm, n->next_nodes[next_index]);
356   u32 * magic = vlib_frame_find_magic (f, next_node);
357   ASSERT (VLIB_FRAME_MAGIC == magic[0]);
358 }
359
360 vlib_frame_t *
361 vlib_get_next_frame_internal (vlib_main_t * vm,
362                               vlib_node_runtime_t * node,
363                               u32 next_index,
364                               u32 allocate_new_next_frame)
365 {
366   vlib_frame_t * f;
367   vlib_next_frame_t * nf;
368   u32 n_used;
369
370   nf = vlib_node_runtime_get_next_frame (vm, node, next_index);
371
372   /* Make sure this next frame owns right to enqueue to destination frame. */
373   if (PREDICT_FALSE (! (nf->flags & VLIB_FRAME_OWNER)))
374     vlib_next_frame_change_ownership (vm, node, next_index);
375
376   /* ??? Don't need valid flag: can use frame_index == ~0 */
377   if (PREDICT_FALSE (! (nf->flags & VLIB_FRAME_IS_ALLOCATED)))
378     {
379       nf->frame_index = vlib_frame_alloc (vm, node, next_index);
380       nf->flags |= VLIB_FRAME_IS_ALLOCATED;
381     }
382
383   f = vlib_get_frame (vm, nf->frame_index);
384
385   /* Has frame been removed from pending vector (e.g. finished dispatching)?
386      If so we can reuse frame. */
387   if ((nf->flags & VLIB_FRAME_PENDING) && ! (f->flags & VLIB_FRAME_PENDING))
388     {
389       nf->flags &= ~VLIB_FRAME_PENDING;
390       f->n_vectors = 0;
391     }
392
393   /* Allocate new frame if current one is already full. */
394   n_used = f->n_vectors;
395   if (n_used >= VLIB_FRAME_SIZE || (allocate_new_next_frame && n_used > 0))
396     {
397       /* Old frame may need to be freed after dispatch, since we'll have
398          two redundant frames from node -> next node. */
399       if (! (nf->flags & VLIB_FRAME_NO_FREE_AFTER_DISPATCH))
400         {
401           vlib_frame_t * f_old = vlib_get_frame (vm, nf->frame_index);
402           f_old->flags |= VLIB_FRAME_FREE_AFTER_DISPATCH;
403         }
404
405       /* Allocate new frame to replace full one. */
406       nf->frame_index = vlib_frame_alloc (vm, node, next_index);
407       f = vlib_get_frame (vm, nf->frame_index);
408       n_used = f->n_vectors;
409     }
410
411   /* Should have free vectors in frame now. */
412   ASSERT (n_used < VLIB_FRAME_SIZE);
413
414   if (CLIB_DEBUG > 0)
415     {
416       validate_frame_magic (vm, f,
417                             vlib_get_node (vm, node->node_index),
418                             next_index);
419     }
420
421   return f;
422 }
423
424 static void
425 vlib_put_next_frame_validate (vlib_main_t * vm,
426                               vlib_node_runtime_t * rt,
427                               u32 next_index,
428                               u32 n_vectors_left)
429 {
430   vlib_node_main_t * nm = &vm->node_main;
431   vlib_next_frame_t * nf;
432   vlib_frame_t * f;
433   vlib_node_runtime_t * next_rt;
434   vlib_node_t * next_node;
435   u32 n_before, n_after;
436
437   nf = vlib_node_runtime_get_next_frame (vm, rt, next_index);
438   f = vlib_get_frame (vm, nf->frame_index);
439
440   ASSERT (n_vectors_left <= VLIB_FRAME_SIZE);
441   n_after = VLIB_FRAME_SIZE - n_vectors_left;
442   n_before = f->n_vectors;
443
444   ASSERT (n_after >= n_before);
445
446   next_rt = vec_elt_at_index (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL],
447                               nf->node_runtime_index);
448   next_node = vlib_get_node (vm, next_rt->node_index);
449   if (n_after > 0 && next_node->validate_frame)
450     {
451       u8 * msg = next_node->validate_frame (vm, rt, f);
452       if (msg)
453         {
454           clib_warning ("%v", msg);
455           ASSERT (0);
456         }
457       vec_free (msg);
458     }
459 }
460
461 void
462 vlib_put_next_frame (vlib_main_t * vm,
463                      vlib_node_runtime_t * r,
464                      u32 next_index,
465                      u32 n_vectors_left)
466 {
467   vlib_node_main_t * nm = &vm->node_main;
468   vlib_next_frame_t * nf;
469   vlib_frame_t * f;
470   u32 n_vectors_in_frame;
471
472   if (DPDK == 0 && CLIB_DEBUG > 0)
473     vlib_put_next_frame_validate (vm, r, next_index, n_vectors_left);
474
475   nf = vlib_node_runtime_get_next_frame (vm, r, next_index);
476   f = vlib_get_frame (vm, nf->frame_index);
477
478   /* Make sure that magic number is still there.  Otherwise, caller
479      has overrun frame meta data. */
480   if (CLIB_DEBUG > 0)
481     {
482       vlib_node_t * node = vlib_get_node (vm, r->node_index);
483       validate_frame_magic (vm, f, node, next_index);
484     }
485
486   /* Convert # of vectors left -> number of vectors there. */
487   ASSERT (n_vectors_left <= VLIB_FRAME_SIZE);
488   n_vectors_in_frame = VLIB_FRAME_SIZE - n_vectors_left;
489
490   f->n_vectors = n_vectors_in_frame;
491
492   /* If vectors were added to frame, add to pending vector. */
493   if (PREDICT_TRUE (n_vectors_in_frame > 0))
494     {
495       vlib_pending_frame_t * p;
496       u32 v0, v1;
497       
498       r->cached_next_index = next_index;
499
500       if (!(f->flags & VLIB_FRAME_PENDING))
501         {
502           __attribute__((unused)) vlib_node_t *node;
503           vlib_node_t *next_node;
504           vlib_node_runtime_t *next_runtime;
505
506           node = vlib_get_node (vm, r->node_index);
507           next_node = vlib_get_next_node (vm, r->node_index, next_index);
508           next_runtime = vlib_node_get_runtime (vm, next_node->index);
509
510           vec_add2 (nm->pending_frames, p, 1);
511
512           p->frame_index = nf->frame_index;
513           p->node_runtime_index = nf->node_runtime_index;
514           p->next_frame_index = nf - nm->next_frames;
515           nf->flags |= VLIB_FRAME_PENDING;
516           f->flags |= VLIB_FRAME_PENDING;
517
518           /* 
519            * If we're going to dispatch this frame on another thread,
520            * force allocation of a new frame. Otherwise, we create
521            * a dangling frame reference. Each thread has its own copy of
522            * the next_frames vector.
523            */
524           if (0 && r->cpu_index != next_runtime->cpu_index)
525             {
526               nf->frame_index = ~0;
527               nf->flags &= ~(VLIB_FRAME_PENDING | VLIB_FRAME_IS_ALLOCATED);
528             }
529         }
530
531       /* Copy trace flag from next_frame and from runtime. */
532       nf->flags |= (nf->flags & VLIB_NODE_FLAG_TRACE) | (r->flags & VLIB_NODE_FLAG_TRACE);
533
534       v0 = nf->vectors_since_last_overflow;
535       v1 = v0 + n_vectors_in_frame;
536       nf->vectors_since_last_overflow = v1;
537       if (PREDICT_FALSE (v1 < v0))
538         {
539           vlib_node_t * node = vlib_get_node (vm, r->node_index);
540           vec_elt (node->n_vectors_by_next_node, next_index) += v0;
541         }
542     }
543 }
544
545 /* Sync up runtime (32 bit counters) and main node stats (64 bit counters). */
546 never_inline void
547 vlib_node_runtime_sync_stats (vlib_main_t * vm,
548                               vlib_node_runtime_t * r,
549                               uword n_calls,
550                               uword n_vectors,
551                               uword n_clocks)
552 {
553   vlib_node_t * n = vlib_get_node (vm, r->node_index);
554
555   n->stats_total.calls += n_calls + r->calls_since_last_overflow;
556   n->stats_total.vectors += n_vectors + r->vectors_since_last_overflow;
557   n->stats_total.clocks += n_clocks + r->clocks_since_last_overflow;
558   n->stats_total.max_clock = r->max_clock;
559   n->stats_total.max_clock_n = r->max_clock_n;
560
561   r->calls_since_last_overflow = 0;
562   r->vectors_since_last_overflow = 0;
563   r->clocks_since_last_overflow = 0;
564 }
565
566 always_inline void
567 vlib_process_sync_stats (vlib_main_t * vm,
568                          vlib_process_t * p,
569                          uword n_calls,
570                          uword n_vectors,
571                          uword n_clocks)
572 {
573   vlib_node_runtime_t * rt = &p->node_runtime;
574   vlib_node_t * n = vlib_get_node (vm, rt->node_index);
575   vlib_node_runtime_sync_stats (vm, rt, n_calls, n_vectors, n_clocks);
576   n->stats_total.suspends += p->n_suspends;
577   p->n_suspends = 0;
578 }
579
580 void vlib_node_sync_stats (vlib_main_t * vm, vlib_node_t * n)
581 {
582   vlib_node_runtime_t * rt;
583
584   if (n->type == VLIB_NODE_TYPE_PROCESS)
585     {
586       /* Nothing to do for PROCESS nodes except in main thread */
587       if (vm != &vlib_global_main) return;
588
589       vlib_process_t * p = vlib_get_process_from_node (vm, n);
590       n->stats_total.suspends += p->n_suspends;
591       p->n_suspends = 0;
592       rt = &p->node_runtime;
593     }
594   else
595     rt = vec_elt_at_index (vm->node_main.nodes_by_type[n->type], n->runtime_index);
596
597   vlib_node_runtime_sync_stats (vm, rt, 0, 0, 0);
598
599   /* Sync up runtime next frame vector counters with main node structure. */
600   {
601     vlib_next_frame_t * nf;
602     uword i;
603     for (i = 0; i < rt->n_next_nodes; i++)
604       {
605         nf = vlib_node_runtime_get_next_frame (vm, rt, i);
606         vec_elt (n->n_vectors_by_next_node, i) += nf->vectors_since_last_overflow;
607         nf->vectors_since_last_overflow = 0;
608       }
609   }
610 }
611
612 always_inline u32
613 vlib_node_runtime_update_stats (vlib_main_t * vm,
614                                 vlib_node_runtime_t * node,
615                                 uword n_calls,
616                                 uword n_vectors,
617                                 uword n_clocks)
618 {
619   u32 ca0, ca1, v0, v1, cl0, cl1, r;
620
621   cl0 = cl1 = node->clocks_since_last_overflow;
622   ca0 = ca1 = node->calls_since_last_overflow;
623   v0 = v1 = node->vectors_since_last_overflow;
624
625   ca1 = ca0 + n_calls;
626   v1 = v0 + n_vectors;
627   cl1 = cl0 + n_clocks;
628
629   node->calls_since_last_overflow = ca1;
630   node->clocks_since_last_overflow = cl1;
631   node->vectors_since_last_overflow = v1;
632   node->max_clock_n = node->max_clock > n_clocks ?
633                       node->max_clock_n : n_vectors;
634   node->max_clock = node->max_clock > n_clocks ?
635                     node->max_clock : n_clocks;
636
637   r = vlib_node_runtime_update_main_loop_vector_stats (vm, node, n_vectors);
638
639   if (PREDICT_FALSE (ca1 < ca0 || v1 < v0 || cl1 < cl0))
640     {
641       node->calls_since_last_overflow = ca0;
642       node->clocks_since_last_overflow = cl0;
643       node->vectors_since_last_overflow = v0;
644       vlib_node_runtime_sync_stats (vm, node, n_calls, n_vectors, n_clocks);
645     }
646
647   return r;
648 }
649
650 always_inline void
651 vlib_process_update_stats (vlib_main_t * vm,
652                            vlib_process_t * p,
653                            uword n_calls,
654                            uword n_vectors,
655                            uword n_clocks)
656 {
657   vlib_node_runtime_update_stats (vm, &p->node_runtime,
658                                   n_calls, n_vectors, n_clocks);
659 }
660
661 static clib_error_t *
662 vlib_cli_elog_clear (vlib_main_t * vm,
663                      unformat_input_t * input,
664                      vlib_cli_command_t * cmd)
665 {
666   elog_reset_buffer (&vm->elog_main);
667   return 0;
668 }
669
670 VLIB_CLI_COMMAND (elog_clear_cli, static) = {
671   .path = "clear event-logger",
672   .short_help = "Clear current event log",
673   .function = vlib_cli_elog_clear,
674 };
675
676 #ifdef CLIB_UNIX
677 static clib_error_t *
678 elog_save_buffer (vlib_main_t * vm,
679                   unformat_input_t * input,
680                   vlib_cli_command_t * cmd)
681 {
682   elog_main_t * em = &vm->elog_main;
683   char * file, * chroot_file;
684   clib_error_t * error = 0;
685
686   if (! unformat (input, "%s", &file))
687     {
688       vlib_cli_output (vm, "expected file name, got `%U'",
689                        format_unformat_error, input);
690       return 0;
691     }
692
693   /* It's fairly hard to get "../oopsie" through unformat; just in case */
694   if (strstr(file, "..") || index(file, '/'))
695     {
696       vlib_cli_output (vm, "illegal characters in filename '%s'", file);
697       return 0;
698     }
699
700   chroot_file = (char *) format (0, "/tmp/%s%c", file, 0);
701
702   vec_free(file);
703
704   vlib_cli_output (vm, "Saving %wd of %wd events to %s",
705                    elog_n_events_in_buffer (em),
706                    elog_buffer_capacity (em),
707                    chroot_file);
708   
709   vlib_worker_thread_barrier_sync (vm);
710   error =  elog_write_file (em, chroot_file);
711   vlib_worker_thread_barrier_release(vm);
712   vec_free (chroot_file);
713   return error;
714 }
715
716 VLIB_CLI_COMMAND (elog_save_cli, static) = {
717   .path = "save event-logger",
718   .short_help = "save event-logger <filename> (saves log in /tmp/<filename>)",
719   .function = elog_save_buffer,
720 };
721
722 #endif /* CLIB_UNIX */
723
724 static void elog_show_buffer_internal (vlib_main_t * vm, u32 n_events_to_show)
725 {
726   elog_main_t * em = &vm->elog_main;
727   elog_event_t * e, * es;
728   f64 dt;
729
730   /* Show events in VLIB time since log clock starts after VLIB clock. */
731   dt = (em->init_time.cpu - vm->clib_time.init_cpu_time) 
732     * vm->clib_time.seconds_per_clock;
733
734   es = elog_peek_events (em);
735   vlib_cli_output (vm, "%d events in buffer", vec_len (es));
736   vec_foreach (e, es)
737     {
738       vlib_cli_output (vm, "%18.9f: %U",
739                        e->time + dt,
740                        format_elog_event, em, e);
741       n_events_to_show--;
742       if (n_events_to_show == 0)
743         break;
744     }
745   vec_free (es);
746   
747 }
748
749 static clib_error_t *
750 elog_show_buffer (vlib_main_t * vm,
751                   unformat_input_t * input,
752                   vlib_cli_command_t * cmd)
753 {
754   u32 n_events_to_show;
755   clib_error_t * error = 0;
756
757   n_events_to_show = 250;
758   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
759     {
760       if (unformat (input, "%d", &n_events_to_show))
761         ;
762       else if (unformat (input, "all"))
763         n_events_to_show = ~0;
764       else
765         return unformat_parse_error (input);
766     }
767   elog_show_buffer_internal (vm, n_events_to_show);
768   return error;
769 }
770
771 VLIB_CLI_COMMAND (elog_show_cli, static) = {
772   .path = "show event-logger",
773   .short_help = "Show event logger info",
774   .function = elog_show_buffer,
775 };
776
777 void vlib_gdb_show_event_log (void)
778 {
779   elog_show_buffer_internal (vlib_get_main(), (u32)~0);
780 }
781
782 always_inline void
783 vlib_elog_main_loop_event (vlib_main_t * vm,
784                            u32 node_index,
785                            u64 time,
786                            u32 n_vectors,
787                            u32 is_return)
788 {
789   elog_main_t * em = &vm->elog_main;
790
791   if (VLIB_ELOG_MAIN_LOOP)
792     elog (em,
793           /* event type */
794           vec_elt_at_index (is_return
795                             ? vm->node_return_elog_event_types
796                             : vm->node_call_elog_event_types,
797                             node_index),
798           /* data to log */ n_vectors);
799 }
800
801 void vlib_dump_context_trace (vlib_main_t *vm, u32 bi)
802 {
803   vlib_node_main_t * vnm = &vm->node_main;
804   vlib_buffer_t * b;
805   u8 i, n;
806
807   if (VLIB_BUFFER_TRACE_TRAJECTORY)
808     {
809       b = vlib_get_buffer (vm, bi);
810       n = b->pre_data[0];
811
812       fformat(stderr, "Context trace for bi %d b 0x%llx, visited %d\n",
813               bi, b, n);
814
815       if (n == 0 || n > 20)
816         {
817           fformat(stderr, "n is unreasonable\n");
818           return;
819         }
820
821
822       for (i = 0; i < n; i++)
823         {
824           u32 node_index;
825
826           node_index = b->pre_data[i+1];
827
828           if (node_index > vec_len (vnm->nodes))
829             {
830               fformat(stderr, "Skip bogus node index %d\n", node_index);
831               continue;
832             }
833       
834           fformat(stderr, "%v (%d)\n", vnm->nodes[node_index]->name, 
835                   node_index);
836         }
837     }
838   else
839     {
840       fformat(stderr, 
841               "in vlib/buffers.h, #define VLIB_BUFFER_TRACE_TRAJECTORY 1\n");
842     }
843 }
844
845
846 /* static_always_inline */ u64
847 dispatch_node (vlib_main_t * vm,
848                vlib_node_runtime_t * node,
849                vlib_node_type_t type,
850                vlib_node_state_t dispatch_state,
851                vlib_frame_t * frame,
852                u64 last_time_stamp)
853 {
854   uword n, v;
855   u64 t;
856   vlib_node_main_t * nm = &vm->node_main;
857   vlib_next_frame_t * nf;
858
859   if (CLIB_DEBUG > 0)
860     {
861       vlib_node_t * n = vlib_get_node (vm, node->node_index);
862       ASSERT (n->type == type);
863     }
864
865   /* Only non-internal nodes may be disabled. */
866   if (type != VLIB_NODE_TYPE_INTERNAL && node->state != dispatch_state)
867     {
868       ASSERT (type != VLIB_NODE_TYPE_INTERNAL);
869       return last_time_stamp;
870     }
871
872   if ((type == VLIB_NODE_TYPE_PRE_INPUT || type == VLIB_NODE_TYPE_INPUT)
873       && dispatch_state != VLIB_NODE_STATE_INTERRUPT)
874     {
875       u32 c = node->input_main_loops_per_call;
876       /* Only call node when count reaches zero. */
877       if (c)
878         {
879           node->input_main_loops_per_call = c - 1;
880           return last_time_stamp;
881         }
882     }
883
884   /* Speculatively prefetch next frames. */
885   if (node->n_next_nodes > 0)
886     {
887       nf = vec_elt_at_index (nm->next_frames, node->next_frame_index);
888       CLIB_PREFETCH (nf, 4 * sizeof (nf[0]), WRITE);
889     }
890
891   vm->cpu_time_last_node_dispatch = last_time_stamp;
892
893   if (1  /* || vm->cpu_index == node->cpu_index */)
894     {
895       vlib_main_t *stat_vm;
896
897       stat_vm = /* vlib_mains ? vlib_mains[0] : */ vm;
898
899       vlib_elog_main_loop_event (vm, node->node_index,
900                                  last_time_stamp,
901                                  frame ? frame->n_vectors : 0,
902                                  /* is_after */ 0);
903       
904       /*
905        * Turn this on if you run into
906        * "bad monkey" contexts, and you want to know exactly
907        * which nodes they've visited... See ixge.c...
908        */
909       if (VLIB_BUFFER_TRACE_TRAJECTORY && frame)
910         {
911           int i;
912           int log_index;
913           u32 * from;
914           from = vlib_frame_vector_args (frame);
915           for (i = 0; i < frame->n_vectors; i++)
916             {
917               vlib_buffer_t *b = vlib_get_buffer (vm, from[i]);
918               ASSERT (b->pre_data[0] < 32);
919               log_index = b->pre_data[0]++ + 1;
920               b->pre_data[log_index] = node->node_index;
921             }
922           n = node->function (vm, node, frame);
923         }
924       else
925           n = node->function (vm, node, frame);
926
927       t = clib_cpu_time_now ();
928
929       vlib_elog_main_loop_event (vm, node->node_index, t, n, /* is_after */ 1);
930
931       vm->main_loop_vectors_processed += n;
932       vm->main_loop_nodes_processed += n > 0;
933
934       v = vlib_node_runtime_update_stats (stat_vm, node,
935                                           /* n_calls */ 1,
936                                           /* n_vectors */ n,
937                                           /* n_clocks */ t - last_time_stamp);
938
939       /* When in interrupt mode and vector rate crosses threshold switch to
940          polling mode. */
941       if ((DPDK == 0 && dispatch_state == VLIB_NODE_STATE_INTERRUPT)
942           || (DPDK == 0 && dispatch_state == VLIB_NODE_STATE_POLLING
943               && (node->flags 
944                   & VLIB_NODE_FLAG_SWITCH_FROM_INTERRUPT_TO_POLLING_MODE)))
945         {
946           ELOG_TYPE_DECLARE (e) = {
947             .function = (char *) __FUNCTION__,
948             .format = "%s vector length %d, switching to %s",
949             .format_args = "T4i4t4",
950             .n_enum_strings = 2,
951             .enum_strings = {
952               "interrupt", "polling",
953             },
954           };
955           struct { u32 node_name, vector_length, is_polling; } * ed;
956           
957           if (dispatch_state == VLIB_NODE_STATE_INTERRUPT
958               && v >= nm->polling_threshold_vector_length)
959             {
960               vlib_node_t * n = vlib_get_node (vm, node->node_index);
961               n->state = VLIB_NODE_STATE_POLLING;
962               node->state = VLIB_NODE_STATE_POLLING;
963               ASSERT (! (node->flags & VLIB_NODE_FLAG_SWITCH_FROM_INTERRUPT_TO_POLLING_MODE));
964               node->flags &= ~VLIB_NODE_FLAG_SWITCH_FROM_POLLING_TO_INTERRUPT_MODE;
965               node->flags |= VLIB_NODE_FLAG_SWITCH_FROM_INTERRUPT_TO_POLLING_MODE;
966               nm->input_node_counts_by_state[VLIB_NODE_STATE_INTERRUPT] -= 1;
967               nm->input_node_counts_by_state[VLIB_NODE_STATE_POLLING] += 1;
968
969               ed = ELOG_DATA (&vm->elog_main, e);
970               ed->node_name = n->name_elog_string;
971               ed->vector_length = v;
972               ed->is_polling = 1;
973             }
974           else if (dispatch_state == VLIB_NODE_STATE_POLLING
975                    && v <= nm->interrupt_threshold_vector_length)
976             {
977               vlib_node_t * n = vlib_get_node (vm, node->node_index);
978               if (node->flags & VLIB_NODE_FLAG_SWITCH_FROM_POLLING_TO_INTERRUPT_MODE)
979                 {
980                   /* Switch to interrupt mode after dispatch in polling one more time.
981                      This allows driver to re-enable interrupts. */
982                   n->state = VLIB_NODE_STATE_INTERRUPT;
983                   node->state = VLIB_NODE_STATE_INTERRUPT;
984                   node->flags &= ~VLIB_NODE_FLAG_SWITCH_FROM_INTERRUPT_TO_POLLING_MODE;
985                   nm->input_node_counts_by_state[VLIB_NODE_STATE_POLLING] -= 1;
986                   nm->input_node_counts_by_state[VLIB_NODE_STATE_INTERRUPT] += 1;
987
988                 }
989               else
990                 {
991                   node->flags |= VLIB_NODE_FLAG_SWITCH_FROM_POLLING_TO_INTERRUPT_MODE;
992                   ed = ELOG_DATA (&vm->elog_main, e);
993                   ed->node_name = n->name_elog_string;
994                   ed->vector_length = v;
995                   ed->is_polling = 0;
996                 }
997             }
998         }
999     }
1000
1001   return t;
1002 }
1003
1004 /* static */ u64
1005 dispatch_pending_node (vlib_main_t * vm,
1006                        vlib_pending_frame_t * p,
1007                        u64 last_time_stamp)
1008 {
1009   vlib_node_main_t * nm = &vm->node_main;
1010   vlib_frame_t * f;
1011   vlib_next_frame_t * nf, nf_dummy;
1012   vlib_node_runtime_t * n;
1013   u32 restore_frame_index;
1014
1015   n = vec_elt_at_index (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL],
1016                         p->node_runtime_index);
1017
1018   f = vlib_get_frame (vm, p->frame_index);
1019   if (p->next_frame_index == VLIB_PENDING_FRAME_NO_NEXT_FRAME)
1020     {
1021       /* No next frame: so use dummy on stack. */
1022       nf = &nf_dummy;
1023       nf->flags = f->flags & VLIB_NODE_FLAG_TRACE;
1024       nf->frame_index = ~p->frame_index;
1025     }
1026   else
1027     nf = vec_elt_at_index (nm->next_frames, p->next_frame_index);
1028
1029   ASSERT (f->flags & VLIB_FRAME_IS_ALLOCATED);
1030
1031   /* Force allocation of new frame while current frame is being
1032      dispatched. */
1033   restore_frame_index = ~0;
1034   if (nf->frame_index == p->frame_index)
1035     {
1036       nf->frame_index = ~0;
1037       nf->flags &= ~VLIB_FRAME_IS_ALLOCATED;
1038       if (! (n->flags & VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH))
1039         restore_frame_index = p->frame_index;
1040     }
1041
1042   /* Frame must be pending. */
1043   ASSERT (f->flags & VLIB_FRAME_PENDING);
1044   ASSERT (f->n_vectors > 0);
1045
1046   /* Copy trace flag from next frame to node.
1047      Trace flag indicates that at least one vector in the dispatched
1048      frame is traced. */
1049   n->flags &= ~VLIB_NODE_FLAG_TRACE;
1050   n->flags |= (nf->flags & VLIB_FRAME_TRACE) ? VLIB_NODE_FLAG_TRACE : 0;
1051   nf->flags &= ~VLIB_FRAME_TRACE;
1052
1053   last_time_stamp = dispatch_node (vm, n,
1054                                    VLIB_NODE_TYPE_INTERNAL,
1055                                    VLIB_NODE_STATE_POLLING,
1056                                    f, last_time_stamp);
1057
1058   f->flags &= ~VLIB_FRAME_PENDING;
1059
1060   /* Frame is ready to be used again, so restore it. */
1061   if (restore_frame_index != ~0)
1062     {
1063       /* p->next_frame_index can change during node dispatch if node
1064          function decides to change graph hook up. */
1065       nf = vec_elt_at_index (nm->next_frames, p->next_frame_index);
1066       nf->frame_index = restore_frame_index;
1067       nf->flags |= VLIB_FRAME_IS_ALLOCATED;
1068     }
1069
1070   if (f->flags & VLIB_FRAME_FREE_AFTER_DISPATCH)
1071     {
1072       ASSERT (! (n->flags & VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH));
1073       vlib_frame_free (vm, n, f);
1074     }
1075
1076   return last_time_stamp;
1077 }
1078
1079 always_inline uword
1080 vlib_process_stack_is_valid (vlib_process_t * p)
1081 { return p->stack[0] == VLIB_PROCESS_STACK_MAGIC; }
1082
1083 typedef struct {
1084   vlib_main_t * vm;
1085   vlib_process_t * process;
1086   vlib_frame_t * frame;
1087 } vlib_process_bootstrap_args_t;
1088
1089 /* Called in process stack. */
1090 static uword vlib_process_bootstrap (uword _a)
1091 {
1092   vlib_process_bootstrap_args_t * a;
1093   vlib_main_t * vm;
1094   vlib_node_runtime_t * node;
1095   vlib_frame_t * f;
1096   vlib_process_t * p;
1097   uword n;
1098
1099   a = uword_to_pointer (_a, vlib_process_bootstrap_args_t *);
1100
1101   vm = a->vm;
1102   p = a->process;
1103   f = a->frame;
1104   node = &p->node_runtime;
1105
1106   n = node->function (vm, node, f);
1107
1108   ASSERT (vlib_process_stack_is_valid (p));
1109
1110   clib_longjmp (&p->return_longjmp, n);
1111
1112   return n;
1113 }
1114
1115 /* Called in main stack. */
1116 static_always_inline uword
1117 vlib_process_startup (vlib_main_t * vm,
1118                       vlib_process_t * p,
1119                       vlib_frame_t * f)
1120 {
1121   vlib_process_bootstrap_args_t a;
1122   uword r;
1123
1124   a.vm = vm;
1125   a.process = p;
1126   a.frame = f;
1127
1128   r = clib_setjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_RETURN);
1129   if (r == VLIB_PROCESS_RETURN_LONGJMP_RETURN)
1130     r = clib_calljmp (vlib_process_bootstrap, pointer_to_uword (&a),
1131                       (void *) p->stack + (1 << p->log2_n_stack_bytes));
1132
1133   return r;
1134 }
1135
1136 static_always_inline uword
1137 vlib_process_resume (vlib_process_t * p)
1138 {
1139   uword r;
1140   p->flags &= ~(VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
1141                 | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT
1142                 | VLIB_PROCESS_RESUME_PENDING);
1143   r = clib_setjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_RETURN);
1144   if (r == VLIB_PROCESS_RETURN_LONGJMP_RETURN)
1145     clib_longjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_RESUME);
1146   return r;
1147 }
1148
1149 static u64
1150 dispatch_process (vlib_main_t * vm,
1151                   vlib_process_t * p,
1152                   vlib_frame_t * f,
1153                   u64 last_time_stamp)
1154 {
1155   vlib_node_main_t * nm = &vm->node_main;
1156   vlib_node_runtime_t * node_runtime = &p->node_runtime;
1157   vlib_node_t * node = vlib_get_node (vm, node_runtime->node_index);
1158   u64 t;
1159   uword n_vectors, is_suspend;
1160
1161   if (node->state != VLIB_NODE_STATE_POLLING
1162       || (p->flags & (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
1163                       | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT)))
1164     return last_time_stamp;
1165
1166   p->flags |= VLIB_PROCESS_IS_RUNNING;
1167
1168   t = last_time_stamp;
1169   vlib_elog_main_loop_event (vm, node_runtime->node_index, t,
1170                              f ? f->n_vectors : 0, /* is_after */ 0);
1171
1172   /* Save away current process for suspend. */
1173   nm->current_process_index = node->runtime_index;
1174
1175   n_vectors = vlib_process_startup (vm, p, f);
1176
1177   nm->current_process_index = ~0;
1178
1179   ASSERT (n_vectors != VLIB_PROCESS_RETURN_LONGJMP_RETURN);
1180   is_suspend = n_vectors == VLIB_PROCESS_RETURN_LONGJMP_SUSPEND;
1181   if (is_suspend)
1182     {
1183       vlib_pending_frame_t * pf;
1184
1185       n_vectors = 0;
1186       pool_get (nm->suspended_process_frames, pf);
1187       pf->node_runtime_index = node->runtime_index;
1188       pf->frame_index = f ? vlib_frame_index (vm, f) : ~0;
1189       pf->next_frame_index = ~0;
1190
1191       p->n_suspends += 1;
1192       p->suspended_process_frame_index = pf - nm->suspended_process_frames;
1193
1194       if (p->flags & VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK)
1195         timing_wheel_insert (&nm->timing_wheel, p->resume_cpu_time,
1196                              vlib_timing_wheel_data_set_suspended_process (node->runtime_index));
1197     }
1198   else
1199     p->flags &= ~VLIB_PROCESS_IS_RUNNING;
1200
1201   t = clib_cpu_time_now ();
1202
1203   vlib_elog_main_loop_event (vm, node_runtime->node_index, t, is_suspend, /* is_after */ 1);
1204
1205   vlib_process_update_stats (vm, p,
1206                              /* n_calls */ ! is_suspend,
1207                              /* n_vectors */ n_vectors,
1208                              /* n_clocks */ t - last_time_stamp);
1209
1210   return t;
1211 }
1212
1213 void vlib_start_process (vlib_main_t * vm, uword process_index)
1214 {
1215   vlib_node_main_t * nm = &vm->node_main;
1216   vlib_process_t * p = vec_elt (nm->processes, process_index);
1217   dispatch_process (vm, p, /* frame */ 0, /* cpu_time_now */ 0);
1218 }
1219
1220 static u64
1221 dispatch_suspended_process (vlib_main_t * vm,
1222                             uword process_index,
1223                             u64 last_time_stamp)
1224 {
1225   vlib_node_main_t * nm = &vm->node_main;
1226   vlib_node_runtime_t * node_runtime;
1227   vlib_node_t * node;
1228   vlib_frame_t * f;
1229   vlib_process_t * p;
1230   vlib_pending_frame_t * pf;
1231   u64 t, n_vectors, is_suspend;
1232   
1233   t = last_time_stamp;
1234
1235   p = vec_elt (nm->processes, process_index);
1236   if (PREDICT_FALSE (! (p->flags & VLIB_PROCESS_IS_RUNNING)))
1237     return last_time_stamp;
1238
1239   ASSERT (p->flags & (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
1240                       | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT));
1241
1242   pf = pool_elt_at_index (nm->suspended_process_frames, p->suspended_process_frame_index);
1243
1244   node_runtime = &p->node_runtime;
1245   node = vlib_get_node (vm, node_runtime->node_index);
1246   f = pf->frame_index != ~0 ? vlib_get_frame (vm, pf->frame_index) : 0;
1247
1248   vlib_elog_main_loop_event (vm, node_runtime->node_index, t, f ? f->n_vectors : 0, /* is_after */ 0);
1249
1250   /* Save away current process for suspend. */
1251   nm->current_process_index = node->runtime_index;
1252
1253   n_vectors = vlib_process_resume (p);
1254   t = clib_cpu_time_now ();
1255
1256   nm->current_process_index = ~0;
1257
1258   is_suspend = n_vectors == VLIB_PROCESS_RETURN_LONGJMP_SUSPEND;
1259   if (is_suspend)
1260     {
1261       /* Suspend it again. */
1262       n_vectors = 0;
1263       p->n_suspends += 1;
1264       if (p->flags & VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK)
1265         timing_wheel_insert (&nm->timing_wheel, p->resume_cpu_time,
1266                              vlib_timing_wheel_data_set_suspended_process (node->runtime_index));
1267     }
1268   else
1269     {
1270       p->flags &= ~VLIB_PROCESS_IS_RUNNING;
1271       p->suspended_process_frame_index = ~0;
1272       pool_put (nm->suspended_process_frames, pf);
1273     }
1274
1275   t = clib_cpu_time_now ();
1276   vlib_elog_main_loop_event (vm, node_runtime->node_index, t, ! is_suspend, /* is_after */ 1);
1277
1278   vlib_process_update_stats (vm, p,
1279                              /* n_calls */ ! is_suspend,
1280                              /* n_vectors */ n_vectors,
1281                              /* n_clocks */ t - last_time_stamp);
1282
1283   return t;
1284 }
1285
1286 static void vlib_main_loop (vlib_main_t * vm)
1287 {
1288   vlib_node_main_t * nm = &vm->node_main;
1289   uword i;
1290   u64 cpu_time_now;
1291
1292   /* Initialize pending node vector. */
1293   vec_resize (nm->pending_frames, 32);
1294   _vec_len (nm->pending_frames) = 0;
1295
1296   /* Mark time of main loop start. */
1297   cpu_time_now = vm->clib_time.last_cpu_time;
1298   vm->cpu_time_main_loop_start = cpu_time_now;
1299
1300   /* Arrange for first level of timing wheel to cover times we care
1301      most about. */
1302   nm->timing_wheel.min_sched_time = 10e-6;
1303   nm->timing_wheel.max_sched_time = 10e-3;
1304   timing_wheel_init (&nm->timing_wheel,
1305                      cpu_time_now,
1306                      vm->clib_time.clocks_per_second);
1307
1308   /* Pre-allocate expired nodes. */
1309   vec_alloc (nm->data_from_advancing_timing_wheel, 32);
1310   vec_alloc (nm->pending_interrupt_node_runtime_indices, 32);
1311
1312   if (! nm->polling_threshold_vector_length)
1313     nm->polling_threshold_vector_length = 10;
1314   if (! nm->interrupt_threshold_vector_length)
1315     nm->interrupt_threshold_vector_length = 5;
1316
1317   nm->current_process_index = ~0;
1318
1319   /* Start all processes. */
1320   {
1321     uword i;
1322     for (i = 0; i < vec_len (nm->processes); i++)
1323       cpu_time_now = dispatch_process (vm, nm->processes[i], /* frame */ 0, cpu_time_now);
1324   }
1325
1326   while (1)
1327     {
1328       vlib_node_runtime_t * n;
1329
1330       /* Process pre-input nodes. */
1331       vec_foreach (n, nm->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT])
1332         cpu_time_now = dispatch_node (vm, n,
1333                                       VLIB_NODE_TYPE_PRE_INPUT,
1334                                       VLIB_NODE_STATE_POLLING,
1335                                       /* frame */ 0,
1336                                       cpu_time_now);
1337
1338       /* Next process input nodes. */
1339       vec_foreach (n, nm->nodes_by_type[VLIB_NODE_TYPE_INPUT])
1340         cpu_time_now = dispatch_node (vm, n,
1341                                       VLIB_NODE_TYPE_INPUT,
1342                                       VLIB_NODE_STATE_POLLING,
1343                                       /* frame */ 0,
1344                                       cpu_time_now);
1345
1346       if (PREDICT_FALSE(vm->queue_signal_pending))
1347           if (vm->queue_signal_callback)
1348               vm->queue_signal_callback (vm);
1349
1350       /* Next handle interrupts. */
1351       {
1352         uword l = _vec_len (nm->pending_interrupt_node_runtime_indices);
1353         uword i;
1354         if (l > 0)
1355           {
1356             _vec_len (nm->pending_interrupt_node_runtime_indices) = 0;
1357             for (i = 0; i < l; i++)
1358               {
1359                 n = vec_elt_at_index (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT],
1360                                       nm->pending_interrupt_node_runtime_indices[i]);
1361                 cpu_time_now = dispatch_node (vm, n,
1362                                               VLIB_NODE_TYPE_INPUT,
1363                                               VLIB_NODE_STATE_INTERRUPT,
1364                                               /* frame */ 0,
1365                                               cpu_time_now);
1366               }
1367           }
1368       }
1369
1370       /* Check if process nodes have expired from timing wheel. */
1371       nm->data_from_advancing_timing_wheel
1372         = timing_wheel_advance (&nm->timing_wheel, cpu_time_now,
1373                                 nm->data_from_advancing_timing_wheel,
1374                                 &nm->cpu_time_next_process_ready);
1375
1376       ASSERT (nm->data_from_advancing_timing_wheel != 0);
1377       if (PREDICT_FALSE (_vec_len (nm->data_from_advancing_timing_wheel) > 0))
1378         {
1379           uword i;
1380
1381         processes_timing_wheel_data:
1382           for (i = 0; i < _vec_len (nm->data_from_advancing_timing_wheel); i++)
1383             {
1384               u32 d = nm->data_from_advancing_timing_wheel[i];
1385               u32 di = vlib_timing_wheel_data_get_index (d);
1386
1387               if (vlib_timing_wheel_data_is_timed_event (d))
1388                 {
1389                   vlib_signal_timed_event_data_t * te = pool_elt_at_index (nm->signal_timed_event_data_pool, di);
1390                   vlib_node_t * n = vlib_get_node (vm, te->process_node_index);
1391                   vlib_process_t * p = vec_elt (nm->processes, n->runtime_index);
1392                   void * data;
1393                   data = vlib_process_signal_event_helper (nm, n, p, te->event_type_index, te->n_data_elts, te->n_data_elt_bytes);
1394                   if (te->n_data_bytes < sizeof (te->inline_event_data))
1395                     memcpy (data, te->inline_event_data, te->n_data_bytes);
1396                   else
1397                     {
1398                       memcpy (data, te->event_data_as_vector, te->n_data_bytes);
1399                       vec_free (te->event_data_as_vector);
1400                     }
1401                   pool_put (nm->signal_timed_event_data_pool, te);
1402                 }
1403               else
1404                 {
1405                   cpu_time_now = clib_cpu_time_now();
1406                   cpu_time_now = dispatch_suspended_process (vm, di, cpu_time_now);
1407                 }
1408             }
1409
1410           /* Reset vector. */
1411           _vec_len (nm->data_from_advancing_timing_wheel) = 0;
1412         }
1413
1414       /* Input nodes may have added work to the pending vector.
1415          Process pending vector until there is nothing left.
1416          All pending vectors will be processed from input -> output. */
1417       for (i = 0; i < _vec_len (nm->pending_frames); i++)
1418           cpu_time_now = dispatch_pending_node (vm, nm->pending_frames + i,
1419                                                 cpu_time_now);
1420       /* Reset pending vector for next iteration. */
1421       _vec_len (nm->pending_frames) = 0;
1422       
1423       /* Pending internal nodes may resume processes. */
1424       if (_vec_len (nm->data_from_advancing_timing_wheel) > 0)
1425         goto processes_timing_wheel_data;
1426
1427       vlib_increment_main_loop_counter (vm);
1428
1429       /* Record time stamp in case there are no enabled nodes and above
1430          calls do not update time stamp. */
1431       cpu_time_now = clib_cpu_time_now ();
1432     }
1433 }
1434                
1435 vlib_main_t vlib_global_main;
1436
1437 static clib_error_t *
1438 vlib_main_configure (vlib_main_t * vm, unformat_input_t * input)
1439 {
1440   int turn_on_mem_trace = 0;
1441
1442   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1443     {
1444       if (unformat (input, "memory-trace"))
1445         turn_on_mem_trace = 1;
1446
1447       else if (unformat (input, "elog-events %d",
1448                          &vm->elog_main.event_ring_size))
1449         ;
1450       else
1451         return unformat_parse_error (input);
1452     }
1453
1454   unformat_free (input);
1455
1456   /* Enable memory trace as early as possible. */
1457   if (turn_on_mem_trace)
1458     clib_mem_trace (1);
1459
1460   return 0;
1461 }
1462
1463 VLIB_EARLY_CONFIG_FUNCTION (vlib_main_configure, "vlib");
1464
1465 /* Main function. */
1466 int vlib_main (vlib_main_t * vm, unformat_input_t * input)
1467 {
1468   clib_error_t * error;
1469
1470   clib_time_init (&vm->clib_time);
1471
1472   /* Turn on event log. */
1473   if (! vm->elog_main.event_ring_size)
1474     vm->elog_main.event_ring_size = 128 << 10;
1475   elog_init (&vm->elog_main, vm->elog_main.event_ring_size);
1476   elog_enable_disable (&vm->elog_main, 1);
1477
1478   /* Default name. */
1479   if (! vm->name)
1480     vm->name = "VLIB";
1481
1482   vec_validate (vm->buffer_main, 0);
1483
1484   if ((error = vlib_thread_init (vm)))
1485     {
1486       clib_error_report (error);
1487       goto done;
1488     }
1489
1490   /* Register static nodes so that init functions may use them. */
1491   vlib_register_all_static_nodes (vm);
1492
1493   /* Set seed for random number generator.
1494      Allow user to specify seed to make random sequence deterministic. */
1495   if (! unformat (input, "seed %wd", &vm->random_seed))
1496     vm->random_seed = clib_cpu_time_now ();
1497   clib_random_buffer_init (&vm->random_buffer, vm->random_seed);
1498
1499   /* See unix/main.c; most likely already set up */
1500   if (vm->init_functions_called == 0)
1501       vm->init_functions_called = hash_create (0, /* value bytes */ 0);
1502   if ((error = vlib_call_all_init_functions (vm)))
1503     goto done;
1504
1505   /* Initialize node graph. */
1506   if ((error = vlib_node_main_init (vm)))
1507     {
1508       /* Arrange for graph hook up error to not be fatal when debugging. */
1509       if (CLIB_DEBUG > 0)
1510         clib_error_report (error);
1511       else
1512         goto done;
1513     }
1514
1515   /* Create default buffer free list. */
1516   vlib_buffer_get_or_create_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES,
1517                                        "default");
1518
1519   switch (clib_setjmp (&vm->main_loop_exit, VLIB_MAIN_LOOP_EXIT_NONE))
1520     {
1521     case VLIB_MAIN_LOOP_EXIT_NONE:
1522       vm->main_loop_exit_set = 1;
1523       break;
1524
1525     case VLIB_MAIN_LOOP_EXIT_CLI:
1526       goto done;
1527
1528     default:
1529       error = vm->main_loop_error;
1530       goto done;
1531     }
1532
1533   if ((error = vlib_call_all_config_functions (vm, input, 0 /* is_early */)))
1534     goto done;
1535
1536   /* Call all main loop enter functions. */
1537   {
1538     clib_error_t * sub_error;
1539     sub_error = vlib_call_all_main_loop_enter_functions (vm);
1540     if (sub_error)
1541       clib_error_report (sub_error);
1542   }
1543
1544   vlib_main_loop (vm);
1545
1546  done:
1547   /* Call all exit functions. */
1548   {
1549     clib_error_t * sub_error;
1550     sub_error = vlib_call_all_main_loop_exit_functions (vm);
1551     if (sub_error)
1552       clib_error_report (sub_error);
1553   }
1554
1555   if (error)
1556     clib_error_report (error);
1557
1558   return 0;
1559 }