Fix unlinking of /dev/shm files.
[vpp.git] / src / vpp / stats / stats.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 #include <vpp/stats/stats.h>
16 #include <signal.h>
17 #include <vlib/threads.h>
18 #include <vnet/fib/fib_entry.h>
19 #include <vnet/fib/fib_table.h>
20 #include <vnet/fib/ip4_fib.h>
21 #include <vnet/dpo/load_balance.h>
22
23 #define STATS_DEBUG 0
24
25 stats_main_t stats_main;
26
27 #include <vnet/ip/ip.h>
28
29 #include <vpp/api/vpe_msg_enum.h>
30
31 #define f64_endian(a)
32 #define f64_print(a,b)
33
34 #define vl_typedefs             /* define message structures */
35 #include <vpp/api/vpe_all_api_h.h>
36 #undef vl_typedefs
37
38 #define vl_endianfun            /* define message structures */
39 #include <vpp/api/vpe_all_api_h.h>
40 #undef vl_endianfun
41
42 /* instantiate all the print functions we know about */
43 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
44 #define vl_printfun
45 #include <vpp/api/vpe_all_api_h.h>
46 #undef vl_printfun
47
48 #define foreach_stats_msg                                               \
49 _(WANT_STATS, want_stats)                                               \
50 _(VNET_INTERFACE_SIMPLE_COUNTERS, vnet_interface_simple_counters)       \
51 _(VNET_INTERFACE_COMBINED_COUNTERS, vnet_interface_combined_counters)   \
52 _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters)                         \
53 _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters)                         \
54 _(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters)                         \
55 _(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters)
56
57 /* These constants ensure msg sizes <= 1024, aka ring allocation */
58 #define SIMPLE_COUNTER_BATCH_SIZE       126
59 #define COMBINED_COUNTER_BATCH_SIZE     63
60 #define IP4_FIB_COUNTER_BATCH_SIZE      48
61 #define IP6_FIB_COUNTER_BATCH_SIZE      30
62
63 /* 5ms */
64 #define STATS_RELEASE_DELAY_NS (1000 * 1000 * 5)
65 /*                              ns/us  us/ms        */
66
67 void
68 dslock (stats_main_t * sm, int release_hint, int tag)
69 {
70   u32 thread_index;
71   data_structure_lock_t *l = sm->data_structure_lock;
72
73   if (PREDICT_FALSE (l == 0))
74     return;
75
76   thread_index = vlib_get_thread_index ();
77   if (l->lock && l->thread_index == thread_index)
78     {
79       l->count++;
80       return;
81     }
82
83   if (release_hint)
84     l->release_hint++;
85
86   while (__sync_lock_test_and_set (&l->lock, 1))
87     /* zzzz */ ;
88   l->tag = tag;
89   l->thread_index = thread_index;
90   l->count = 1;
91 }
92
93 void
94 stats_dslock_with_hint (int hint, int tag)
95 {
96   stats_main_t *sm = &stats_main;
97   dslock (sm, hint, tag);
98 }
99
100 void
101 dsunlock (stats_main_t * sm)
102 {
103   u32 thread_index;
104   data_structure_lock_t *l = sm->data_structure_lock;
105
106   if (PREDICT_FALSE (l == 0))
107     return;
108
109   thread_index = vlib_get_thread_index ();
110   ASSERT (l->lock && l->thread_index == thread_index);
111   l->count--;
112   if (l->count == 0)
113     {
114       l->tag = -l->tag;
115       l->release_hint = 0;
116       CLIB_MEMORY_BARRIER ();
117       l->lock = 0;
118     }
119 }
120
121 void
122 stats_dsunlock (int hint, int tag)
123 {
124   stats_main_t *sm = &stats_main;
125   dsunlock (sm);
126 }
127
128 static void
129 do_simple_interface_counters (stats_main_t * sm)
130 {
131   vl_api_vnet_interface_simple_counters_t *mp = 0;
132   vnet_interface_main_t *im = sm->interface_main;
133   api_main_t *am = sm->api_main;
134   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
135   unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
136   vlib_simple_counter_main_t *cm;
137   u32 items_this_message = 0;
138   u64 v, *vp = 0;
139   int i, n_counts;
140
141   /*
142    * Prevent interface registration from expanding / moving the vectors...
143    * That tends never to happen, so we can hold this lock for a while.
144    */
145   vnet_interface_counter_lock (im);
146
147   vec_foreach (cm, im->sw_if_counters)
148   {
149     n_counts = vlib_simple_counter_n_counters (cm);
150     for (i = 0; i < n_counts; i++)
151       {
152         if (mp == 0)
153           {
154             items_this_message = clib_min (SIMPLE_COUNTER_BATCH_SIZE,
155                                            n_counts - i);
156
157             mp = vl_msg_api_alloc_as_if_client
158               (sizeof (*mp) + items_this_message * sizeof (v));
159             mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_SIMPLE_COUNTERS);
160             mp->vnet_counter_type = cm - im->sw_if_counters;
161             mp->first_sw_if_index = htonl (i);
162             mp->count = 0;
163             vp = (u64 *) mp->data;
164           }
165         v = vlib_get_simple_counter (cm, i);
166         clib_mem_unaligned (vp, u64) = clib_host_to_net_u64 (v);
167         vp++;
168         mp->count++;
169         if (mp->count == items_this_message)
170           {
171             mp->count = htonl (items_this_message);
172             /* Send to the main thread... */
173             vl_msg_api_send_shmem (q, (u8 *) & mp);
174             mp = 0;
175           }
176       }
177     ASSERT (mp == 0);
178   }
179   vnet_interface_counter_unlock (im);
180 }
181
182 static void
183 do_combined_interface_counters (stats_main_t * sm)
184 {
185   vl_api_vnet_interface_combined_counters_t *mp = 0;
186   vnet_interface_main_t *im = sm->interface_main;
187   api_main_t *am = sm->api_main;
188   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
189   unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
190   vlib_combined_counter_main_t *cm;
191   u32 items_this_message = 0;
192   vlib_counter_t v, *vp = 0;
193   int i, n_counts;
194
195   vnet_interface_counter_lock (im);
196
197   vec_foreach (cm, im->combined_sw_if_counters)
198   {
199     n_counts = vlib_combined_counter_n_counters (cm);
200     for (i = 0; i < n_counts; i++)
201       {
202         if (mp == 0)
203           {
204             items_this_message = clib_min (COMBINED_COUNTER_BATCH_SIZE,
205                                            n_counts - i);
206
207             mp = vl_msg_api_alloc_as_if_client
208               (sizeof (*mp) + items_this_message * sizeof (v));
209             mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_COMBINED_COUNTERS);
210             mp->vnet_counter_type = cm - im->combined_sw_if_counters;
211             mp->first_sw_if_index = htonl (i);
212             mp->count = 0;
213             vp = (vlib_counter_t *) mp->data;
214           }
215         vlib_get_combined_counter (cm, i, &v);
216         clib_mem_unaligned (&vp->packets, u64)
217           = clib_host_to_net_u64 (v.packets);
218         clib_mem_unaligned (&vp->bytes, u64) = clib_host_to_net_u64 (v.bytes);
219         vp++;
220         mp->count++;
221         if (mp->count == items_this_message)
222           {
223             mp->count = htonl (items_this_message);
224             /* Send to the main thread... */
225             vl_msg_api_send_shmem (q, (u8 *) & mp);
226             mp = 0;
227           }
228       }
229     ASSERT (mp == 0);
230   }
231   vnet_interface_counter_unlock (im);
232 }
233
234 /* from .../vnet/vnet/ip/lookup.c. Yuck */
235 typedef CLIB_PACKED (struct
236                      {
237                      ip4_address_t address;
238 u32 address_length: 6;
239 u32 index:           26;
240                      }) ip4_route_t;
241
242 static void
243 ip46_fib_stats_delay (stats_main_t * sm, u32 sec, u32 nsec)
244 {
245   struct timespec _req, *req = &_req;
246   struct timespec _rem, *rem = &_rem;
247
248   req->tv_sec = sec;
249   req->tv_nsec = nsec;
250   while (1)
251     {
252       if (nanosleep (req, rem) == 0)
253         break;
254       *req = *rem;
255       if (errno == EINTR)
256         continue;
257       clib_unix_warning ("nanosleep");
258       break;
259     }
260 }
261
262 /**
263  * @brief The context passed when collecting adjacency counters
264  */
265 typedef struct ip4_nbr_stats_ctx_t_
266 {
267   /**
268    * The SW IF index all these adjs belong to
269    */
270   u32 sw_if_index;
271
272   /**
273    * A vector of ip4 nbr counters
274    */
275   vl_api_ip4_nbr_counter_t *counters;
276 } ip4_nbr_stats_ctx_t;
277
278 static adj_walk_rc_t
279 ip4_nbr_stats_cb (adj_index_t ai, void *arg)
280 {
281   vl_api_ip4_nbr_counter_t *vl_counter;
282   vlib_counter_t adj_counter;
283   ip4_nbr_stats_ctx_t *ctx;
284   ip_adjacency_t *adj;
285
286   ctx = arg;
287   vlib_get_combined_counter (&adjacency_counters, ai, &adj_counter);
288
289   if (0 != adj_counter.packets)
290     {
291       vec_add2 (ctx->counters, vl_counter, 1);
292       adj = adj_get (ai);
293
294       vl_counter->packets = clib_host_to_net_u64 (adj_counter.packets);
295       vl_counter->bytes = clib_host_to_net_u64 (adj_counter.bytes);
296       vl_counter->address = adj->sub_type.nbr.next_hop.ip4.as_u32;
297       vl_counter->link_type = adj->ia_link;
298     }
299   return (ADJ_WALK_RC_CONTINUE);
300 }
301
302 #define MIN(x,y) (((x)<(y))?(x):(y))
303
304 static void
305 ip4_nbr_ship (stats_main_t * sm, ip4_nbr_stats_ctx_t * ctx)
306 {
307   api_main_t *am = sm->api_main;
308   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
309   unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
310   vl_api_vnet_ip4_nbr_counters_t *mp = 0;
311   int first = 0;
312
313   /*
314    * If the walk context has counters, which may be left over from the last
315    * suspend, then we continue from there.
316    */
317   while (0 != vec_len (ctx->counters))
318     {
319       u32 n_items = MIN (vec_len (ctx->counters),
320                          IP4_FIB_COUNTER_BATCH_SIZE);
321       u8 pause = 0;
322
323       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
324
325       mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
326                                           (n_items *
327                                            sizeof
328                                            (vl_api_ip4_nbr_counter_t)));
329       mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_NBR_COUNTERS);
330       mp->count = ntohl (n_items);
331       mp->sw_if_index = ntohl (ctx->sw_if_index);
332       mp->begin = first;
333       first = 0;
334
335       /*
336        * copy the counters from the back of the context, then we can easily
337        * 'erase' them by resetting the vector length.
338        * The order we push the stats to the caller is not important.
339        */
340       clib_memcpy (mp->c,
341                    &ctx->counters[vec_len (ctx->counters) - n_items],
342                    n_items * sizeof (*ctx->counters));
343
344       _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
345
346       /*
347        * send to the shm q
348        */
349       unix_shared_memory_queue_lock (q);
350       pause = unix_shared_memory_queue_is_full (q);
351
352       vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
353       unix_shared_memory_queue_unlock (q);
354       dsunlock (sm);
355
356       if (pause)
357         ip46_fib_stats_delay (sm, 0 /* sec */ ,
358                               STATS_RELEASE_DELAY_NS);
359     }
360 }
361
362 static void
363 do_ip4_nbrs (stats_main_t * sm)
364 {
365   vnet_main_t *vnm = vnet_get_main ();
366   vnet_interface_main_t *im = &vnm->interface_main;
367   vnet_sw_interface_t *si;
368
369   ip4_nbr_stats_ctx_t ctx = {
370     .sw_if_index = 0,
371     .counters = NULL,
372   };
373
374   /* *INDENT-OFF* */
375   pool_foreach (si, im->sw_interfaces,
376   ({
377     /*
378      * update the interface we are now concerned with
379      */
380     ctx.sw_if_index = si->sw_if_index;
381
382     /*
383      * we are about to walk another interface, so we shouldn't have any pending
384      * stats to export.
385      */
386     ASSERT(ctx.counters == NULL);
387
388     /*
389      * visit each neighbour adjacency on the interface and collect
390      * its current stats.
391      * Because we hold the lock the walk is synchronous, so safe to routing
392      * updates. It's limited in work by the number of adjacenies on an
393      * interface, which is typically not huge.
394      */
395     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
396     adj_nbr_walk (si->sw_if_index,
397                   FIB_PROTOCOL_IP4,
398                   ip4_nbr_stats_cb,
399                   &ctx);
400     dsunlock (sm);
401
402     /*
403      * if this interface has some adjacencies with counters then ship them,
404      * else continue to the next interface.
405      */
406     if (NULL != ctx.counters)
407       {
408         ip4_nbr_ship(sm, &ctx);
409       }
410   }));
411   /* *INDENT-OFF* */
412 }
413
414 /**
415  * @brief The context passed when collecting adjacency counters
416  */
417 typedef struct ip6_nbr_stats_ctx_t_
418 {
419   /**
420    * The SW IF index all these adjs belong to
421    */
422   u32 sw_if_index;
423
424   /**
425    * A vector of ip6 nbr counters
426    */
427   vl_api_ip6_nbr_counter_t *counters;
428 } ip6_nbr_stats_ctx_t;
429
430 static adj_walk_rc_t
431 ip6_nbr_stats_cb (adj_index_t ai,
432                   void *arg)
433 {
434   vl_api_ip6_nbr_counter_t *vl_counter;
435   vlib_counter_t adj_counter;
436   ip6_nbr_stats_ctx_t *ctx;
437   ip_adjacency_t *adj;
438
439   ctx = arg;
440   vlib_get_combined_counter(&adjacency_counters, ai, &adj_counter);
441
442   if (0 != adj_counter.packets)
443     {
444       vec_add2(ctx->counters, vl_counter, 1);
445       adj = adj_get(ai);
446
447       vl_counter->packets = clib_host_to_net_u64(adj_counter.packets);
448       vl_counter->bytes   = clib_host_to_net_u64(adj_counter.bytes);
449       vl_counter->address[0] = adj->sub_type.nbr.next_hop.ip6.as_u64[0];
450       vl_counter->address[1] = adj->sub_type.nbr.next_hop.ip6.as_u64[1];
451       vl_counter->link_type = adj->ia_link;
452     }
453   return (ADJ_WALK_RC_CONTINUE);
454 }
455
456 #define MIN(x,y) (((x)<(y))?(x):(y))
457
458 static void
459 ip6_nbr_ship (stats_main_t * sm,
460               ip6_nbr_stats_ctx_t *ctx)
461 {
462   api_main_t *am = sm->api_main;
463   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
464   unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
465   vl_api_vnet_ip6_nbr_counters_t *mp = 0;
466   int first = 0;
467
468   /*
469    * If the walk context has counters, which may be left over from the last
470    * suspend, then we continue from there.
471    */
472   while (0 != vec_len(ctx->counters))
473     {
474       u32 n_items = MIN (vec_len (ctx->counters),
475                          IP6_FIB_COUNTER_BATCH_SIZE);
476       u8 pause = 0;
477
478       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
479
480       mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
481                                           (n_items *
482                                            sizeof
483                                            (vl_api_ip6_nbr_counter_t)));
484       mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_NBR_COUNTERS);
485       mp->count = ntohl (n_items);
486       mp->sw_if_index = ntohl (ctx->sw_if_index);
487       mp->begin = first;
488       first = 0;
489
490       /*
491        * copy the counters from the back of the context, then we can easily
492        * 'erase' them by resetting the vector length.
493        * The order we push the stats to the caller is not important.
494        */
495       clib_memcpy (mp->c,
496                    &ctx->counters[vec_len (ctx->counters) - n_items],
497                    n_items * sizeof (*ctx->counters));
498
499       _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
500
501       /*
502        * send to the shm q
503        */
504       unix_shared_memory_queue_lock (q);
505       pause = unix_shared_memory_queue_is_full (q);
506
507       vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
508       unix_shared_memory_queue_unlock (q);
509       dsunlock (sm);
510
511       if (pause)
512         ip46_fib_stats_delay (sm, 0 /* sec */ ,
513                               STATS_RELEASE_DELAY_NS);
514     }
515 }
516
517 static void
518 do_ip6_nbrs (stats_main_t * sm)
519 {
520   vnet_main_t *vnm = vnet_get_main ();
521   vnet_interface_main_t *im = &vnm->interface_main;
522   vnet_sw_interface_t *si;
523
524   ip6_nbr_stats_ctx_t ctx = {
525     .sw_if_index = 0,
526     .counters = NULL,
527   };
528
529   /* *INDENT-OFF* */
530   pool_foreach (si, im->sw_interfaces,
531   ({
532     /*
533      * update the interface we are now concerned with
534      */
535     ctx.sw_if_index = si->sw_if_index;
536
537     /*
538      * we are about to walk another interface, so we shouldn't have any pending
539      * stats to export.
540      */
541     ASSERT(ctx.counters == NULL);
542
543     /*
544      * visit each neighbour adjacency on the interface and collect
545      * its current stats.
546      * Because we hold the lock the walk is synchronous, so safe to routing
547      * updates. It's limited in work by the number of adjacenies on an
548      * interface, which is typically not huge.
549      */
550     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
551     adj_nbr_walk (si->sw_if_index,
552                   FIB_PROTOCOL_IP6,
553                   ip6_nbr_stats_cb,
554                   &ctx);
555     dsunlock (sm);
556
557     /*
558      * if this interface has some adjacencies with counters then ship them,
559      * else continue to the next interface.
560      */
561     if (NULL != ctx.counters)
562       {
563         ip6_nbr_ship(sm, &ctx);
564       }
565   }));
566   /* *INDENT-OFF* */
567 }
568
569 static void
570 do_ip4_fibs (stats_main_t * sm)
571 {
572   ip4_main_t *im4 = &ip4_main;
573   api_main_t *am = sm->api_main;
574   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
575   unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
576   static ip4_route_t *routes;
577   ip4_route_t *r;
578   fib_table_t *fib;
579   ip4_fib_t *v4_fib;
580   static uword *results;
581   vl_api_vnet_ip4_fib_counters_t *mp = 0;
582   u32 items_this_message;
583   vl_api_ip4_fib_counter_t *ctrp = 0;
584   u32 start_at_fib_index = 0;
585   int i;
586
587 again:
588   /* *INDENT-OFF* */
589   pool_foreach (fib, im4->fibs,
590   ({
591     /* We may have bailed out due to control-plane activity */
592     while ((fib - im4->fibs) < start_at_fib_index)
593       continue;
594
595     v4_fib = pool_elt_at_index (im4->v4_fibs, fib->ft_index);
596
597     if (mp == 0)
598       {
599         items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
600         mp = vl_msg_api_alloc_as_if_client
601           (sizeof (*mp) +
602            items_this_message * sizeof (vl_api_ip4_fib_counter_t));
603         mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
604         mp->count = 0;
605         mp->vrf_id = ntohl (fib->ft_table_id);
606         ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
607       }
608     else
609       {
610         /* happens if the last FIB was empty... */
611         ASSERT (mp->count == 0);
612         mp->vrf_id = ntohl (fib->ft_table_id);
613       }
614
615     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
616
617     vec_reset_length (routes);
618     vec_reset_length (results);
619
620     for (i = 0; i < ARRAY_LEN (v4_fib->fib_entry_by_dst_address); i++)
621       {
622         uword *hash = v4_fib->fib_entry_by_dst_address[i];
623         hash_pair_t *p;
624         ip4_route_t x;
625
626         x.address_length = i;
627
628         hash_foreach_pair (p, hash,
629         ({
630           x.address.data_u32 = p->key;
631           x.index = p->value[0];
632
633           vec_add1 (routes, x);
634           if (sm->data_structure_lock->release_hint)
635             {
636               start_at_fib_index = fib - im4->fibs;
637               dsunlock (sm);
638               ip46_fib_stats_delay (sm, 0 /* sec */,
639                                     STATS_RELEASE_DELAY_NS);
640               mp->count = 0;
641               ctrp = (vl_api_ip4_fib_counter_t *)mp->c;
642               goto again;
643             }
644         }));
645       }
646
647     vec_foreach (r, routes)
648       {
649         vlib_counter_t c;
650
651         vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
652                                    r->index, &c);
653         /*
654          * If it has actually
655          * seen at least one packet, send it.
656          */
657         if (c.packets > 0)
658           {
659
660             /* already in net byte order */
661             ctrp->address = r->address.as_u32;
662             ctrp->address_length = r->address_length;
663             ctrp->packets = clib_host_to_net_u64 (c.packets);
664             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
665             mp->count++;
666             ctrp++;
667
668             if (mp->count == items_this_message)
669               {
670                 mp->count = htonl (items_this_message);
671                 /*
672                  * If the main thread's input queue is stuffed,
673                  * drop the data structure lock (which the main thread
674                  * may want), and take a pause.
675                  */
676                 unix_shared_memory_queue_lock (q);
677                 if (unix_shared_memory_queue_is_full (q))
678                   {
679                     dsunlock (sm);
680                     vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
681                     unix_shared_memory_queue_unlock (q);
682                     mp = 0;
683                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
684                                           STATS_RELEASE_DELAY_NS);
685                     goto again;
686                   }
687                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
688                 unix_shared_memory_queue_unlock (q);
689
690                 items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
691                 mp = vl_msg_api_alloc_as_if_client
692                   (sizeof (*mp) +
693                    items_this_message * sizeof (vl_api_ip4_fib_counter_t));
694                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
695                 mp->count = 0;
696                 mp->vrf_id = ntohl (fib->ft_table_id);
697                 ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
698               }
699           }                     /* for each (mp or single) adj */
700         if (sm->data_structure_lock->release_hint)
701           {
702             start_at_fib_index = fib - im4->fibs;
703             dsunlock (sm);
704             ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
705             mp->count = 0;
706             ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
707             goto again;
708           }
709       }                         /* vec_foreach (routes) */
710
711     dsunlock (sm);
712
713     /* Flush any data from this fib */
714     if (mp->count)
715       {
716         mp->count = htonl (mp->count);
717         vl_msg_api_send_shmem (q, (u8 *) & mp);
718         mp = 0;
719       }
720   }));
721   /* *INDENT-ON* */
722
723   /* If e.g. the last FIB had no reportable routes, free the buffer */
724   if (mp)
725     vl_msg_api_free (mp);
726 }
727
728 typedef struct
729 {
730   ip6_address_t address;
731   u32 address_length;
732   u32 index;
733 } ip6_route_t;
734
735 typedef struct
736 {
737   u32 fib_index;
738   ip6_route_t **routep;
739   stats_main_t *sm;
740 } add_routes_in_fib_arg_t;
741
742 static void
743 add_routes_in_fib (BVT (clib_bihash_kv) * kvp, void *arg)
744 {
745   add_routes_in_fib_arg_t *ap = arg;
746   stats_main_t *sm = ap->sm;
747
748   if (sm->data_structure_lock->release_hint)
749     clib_longjmp (&sm->jmp_buf, 1);
750
751   if (kvp->key[2] >> 32 == ap->fib_index)
752     {
753       ip6_address_t *addr;
754       ip6_route_t *r;
755       addr = (ip6_address_t *) kvp;
756       vec_add2 (*ap->routep, r, 1);
757       r->address = addr[0];
758       r->address_length = kvp->key[2] & 0xFF;
759       r->index = kvp->value;
760     }
761 }
762
763 static void
764 do_ip6_fibs (stats_main_t * sm)
765 {
766   ip6_main_t *im6 = &ip6_main;
767   api_main_t *am = sm->api_main;
768   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
769   unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
770   static ip6_route_t *routes;
771   ip6_route_t *r;
772   fib_table_t *fib;
773   static uword *results;
774   vl_api_vnet_ip6_fib_counters_t *mp = 0;
775   u32 items_this_message;
776   vl_api_ip6_fib_counter_t *ctrp = 0;
777   u32 start_at_fib_index = 0;
778   BVT (clib_bihash) * h = &im6->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash;
779   add_routes_in_fib_arg_t _a, *a = &_a;
780
781 again:
782   /* *INDENT-OFF* */
783   pool_foreach (fib, im6->fibs,
784   ({
785     /* We may have bailed out due to control-plane activity */
786     while ((fib - im6->fibs) < start_at_fib_index)
787       continue;
788
789     if (mp == 0)
790       {
791         items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
792         mp = vl_msg_api_alloc_as_if_client
793           (sizeof (*mp) +
794            items_this_message * sizeof (vl_api_ip6_fib_counter_t));
795         mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
796         mp->count = 0;
797         mp->vrf_id = ntohl (fib->ft_table_id);
798         ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
799       }
800
801     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
802
803     vec_reset_length (routes);
804     vec_reset_length (results);
805
806     a->fib_index = fib - im6->fibs;
807     a->routep = &routes;
808     a->sm = sm;
809
810     if (clib_setjmp (&sm->jmp_buf, 0) == 0)
811       {
812         start_at_fib_index = fib - im6->fibs;
813         BV (clib_bihash_foreach_key_value_pair) (h, add_routes_in_fib, a);
814       }
815     else
816       {
817         dsunlock (sm);
818         ip46_fib_stats_delay (sm, 0 /* sec */ ,
819                               STATS_RELEASE_DELAY_NS);
820         mp->count = 0;
821         ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
822         goto again;
823       }
824
825     vec_foreach (r, routes)
826     {
827         vlib_counter_t c;
828
829         vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
830                                    r->index, &c);
831         /*
832          * If it has actually
833          * seen at least one packet, send it.
834          */
835         if (c.packets > 0)
836           {
837             /* already in net byte order */
838             ctrp->address[0] = r->address.as_u64[0];
839             ctrp->address[1] = r->address.as_u64[1];
840             ctrp->address_length = (u8) r->address_length;
841             ctrp->packets = clib_host_to_net_u64 (c.packets);
842             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
843             mp->count++;
844             ctrp++;
845
846             if (mp->count == items_this_message)
847               {
848                 mp->count = htonl (items_this_message);
849                 /*
850                  * If the main thread's input queue is stuffed,
851                  * drop the data structure lock (which the main thread
852                  * may want), and take a pause.
853                  */
854                 unix_shared_memory_queue_lock (q);
855                 if (unix_shared_memory_queue_is_full (q))
856                   {
857                     dsunlock (sm);
858                     vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
859                     unix_shared_memory_queue_unlock (q);
860                     mp = 0;
861                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
862                                           STATS_RELEASE_DELAY_NS);
863                     goto again;
864                   }
865                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
866                 unix_shared_memory_queue_unlock (q);
867
868                 items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
869                 mp = vl_msg_api_alloc_as_if_client
870                   (sizeof (*mp) +
871                    items_this_message * sizeof (vl_api_ip6_fib_counter_t));
872                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
873                 mp->count = 0;
874                 mp->vrf_id = ntohl (fib->ft_table_id);
875                 ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
876               }
877           }
878
879         if (sm->data_structure_lock->release_hint)
880           {
881             start_at_fib_index = fib - im6->fibs;
882             dsunlock (sm);
883             ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
884             mp->count = 0;
885             ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
886             goto again;
887           }
888     }                           /* vec_foreach (routes) */
889
890     dsunlock (sm);
891
892     /* Flush any data from this fib */
893     if (mp->count)
894       {
895         mp->count = htonl (mp->count);
896         vl_msg_api_send_shmem (q, (u8 *) & mp);
897         mp = 0;
898       }
899   }));
900   /* *INDENT-ON* */
901
902   /* If e.g. the last FIB had no reportable routes, free the buffer */
903   if (mp)
904     vl_msg_api_free (mp);
905 }
906
907 static void
908 stats_thread_fn (void *arg)
909 {
910   stats_main_t *sm = &stats_main;
911   vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
912   vlib_thread_main_t *tm = vlib_get_thread_main ();
913
914   /* stats thread wants no signals. */
915   {
916     sigset_t s;
917     sigfillset (&s);
918     pthread_sigmask (SIG_SETMASK, &s, 0);
919   }
920
921   if (vec_len (tm->thread_prefix))
922     vlib_set_thread_name ((char *)
923                           format (0, "%v_stats%c", tm->thread_prefix, '\0'));
924
925   clib_mem_set_heap (w->thread_mheap);
926
927   while (1)
928     {
929       /* 10 second poll interval */
930       ip46_fib_stats_delay (sm, 10 /* secs */ , 0 /* nsec */ );
931
932       if (!(sm->enable_poller))
933         continue;
934       do_simple_interface_counters (sm);
935       do_combined_interface_counters (sm);
936       do_ip4_fibs (sm);
937       do_ip6_fibs (sm);
938       do_ip4_nbrs (sm);
939       do_ip6_nbrs (sm);
940     }
941 }
942
943 static void
944   vl_api_vnet_interface_simple_counters_t_handler
945   (vl_api_vnet_interface_simple_counters_t * mp)
946 {
947   vpe_client_registration_t *reg;
948   stats_main_t *sm = &stats_main;
949   unix_shared_memory_queue_t *q, *q_prev = NULL;
950   vl_api_vnet_interface_simple_counters_t *mp_copy = NULL;
951   u32 mp_size;
952
953 #if STATS_DEBUG > 0
954   char *counter_name;
955   u32 count, sw_if_index;
956   int i;
957 #endif
958
959   mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (u64));
960
961   /* *INDENT-OFF* */
962   pool_foreach(reg, sm->stats_registrations,
963                ({
964                  q = vl_api_client_index_to_input_queue (reg->client_index);
965                  if (q)
966                    {
967                      if (q_prev && (q_prev->cursize < q_prev->maxsize))
968                        {
969                          mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
970                          clib_memcpy(mp_copy, mp, mp_size);
971                          vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
972                          mp = mp_copy;
973                        }
974                      q_prev = q;
975                    }
976                }));
977   /* *INDENT-ON* */
978
979 #if STATS_DEBUG > 0
980   count = ntohl (mp->count);
981   sw_if_index = ntohl (mp->first_sw_if_index);
982   u64 *vp, v;
983   vp = (u64 *) mp->data;
984
985   switch (mp->vnet_counter_type)
986     {
987     case VNET_INTERFACE_COUNTER_DROP:
988       counter_name = "drop";
989       break;
990     case VNET_INTERFACE_COUNTER_PUNT:
991       counter_name = "punt";
992       break;
993     case VNET_INTERFACE_COUNTER_IP4:
994       counter_name = "ip4";
995       break;
996     case VNET_INTERFACE_COUNTER_IP6:
997       counter_name = "ip6";
998       break;
999     case VNET_INTERFACE_COUNTER_RX_NO_BUF:
1000       counter_name = "rx-no-buff";
1001       break;
1002     case VNET_INTERFACE_COUNTER_RX_MISS:
1003       , counter_name = "rx-miss";
1004       break;
1005     case VNET_INTERFACE_COUNTER_RX_ERROR:
1006       , counter_name = "rx-error (fifo-full)";
1007       break;
1008     case VNET_INTERFACE_COUNTER_TX_ERROR:
1009       , counter_name = "tx-error (fifo-full)";
1010       break;
1011     default:
1012       counter_name = "bogus";
1013       break;
1014     }
1015   for (i = 0; i < count; i++)
1016     {
1017       v = clib_mem_unaligned (vp, u64);
1018       v = clib_net_to_host_u64 (v);
1019       vp++;
1020       fformat (stdout, "%U.%s %lld\n", format_vnet_sw_if_index_name,
1021                sm->vnet_main, sw_if_index, counter_name, v);
1022       sw_if_index++;
1023     }
1024 #endif
1025   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1026     {
1027       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1028     }
1029   else
1030     {
1031       vl_msg_api_free (mp);
1032     }
1033 }
1034
1035 static void
1036   vl_api_vnet_interface_combined_counters_t_handler
1037   (vl_api_vnet_interface_combined_counters_t * mp)
1038 {
1039   vpe_client_registration_t *reg;
1040   stats_main_t *sm = &stats_main;
1041   unix_shared_memory_queue_t *q, *q_prev = NULL;
1042   vl_api_vnet_interface_combined_counters_t *mp_copy = NULL;
1043   u32 mp_size;
1044
1045 #if STATS_DEBUG > 0
1046   char *counter_name;
1047   u32 count, sw_if_index;
1048   int i;
1049 #endif
1050
1051   mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (vlib_counter_t));
1052
1053   /* *INDENT-OFF* */
1054   pool_foreach(reg, sm->stats_registrations,
1055                ({
1056                  q = vl_api_client_index_to_input_queue (reg->client_index);
1057                  if (q)
1058                    {
1059                      if (q_prev && (q_prev->cursize < q_prev->maxsize))
1060                        {
1061                          mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1062                          clib_memcpy(mp_copy, mp, mp_size);
1063                          vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1064                          mp = mp_copy;
1065                        }
1066                      q_prev = q;
1067                    }
1068                }));
1069   /* *INDENT-ON* */
1070
1071 #if STATS_DEBUG > 0
1072   count = ntohl (mp->count);
1073   sw_if_index = ntohl (mp->first_sw_if_index);
1074
1075   vlib_counter_t *vp;
1076   u64 packets, bytes;
1077   vp = (vlib_counter_t *) mp->data;
1078
1079   switch (mp->vnet_counter_type)
1080     {
1081     case VNET_INTERFACE_COUNTER_RX:
1082       counter_name = "rx";
1083       break;
1084     case VNET_INTERFACE_COUNTER_TX:
1085       counter_name = "tx";
1086       break;
1087     default:
1088       counter_name = "bogus";
1089       break;
1090     }
1091   for (i = 0; i < count; i++)
1092     {
1093       packets = clib_mem_unaligned (&vp->packets, u64);
1094       packets = clib_net_to_host_u64 (packets);
1095       bytes = clib_mem_unaligned (&vp->bytes, u64);
1096       bytes = clib_net_to_host_u64 (bytes);
1097       vp++;
1098       fformat (stdout, "%U.%s.packets %lld\n",
1099                format_vnet_sw_if_index_name,
1100                sm->vnet_main, sw_if_index, counter_name, packets);
1101       fformat (stdout, "%U.%s.bytes %lld\n",
1102                format_vnet_sw_if_index_name,
1103                sm->vnet_main, sw_if_index, counter_name, bytes);
1104       sw_if_index++;
1105     }
1106
1107 #endif
1108   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1109     {
1110       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1111     }
1112   else
1113     {
1114       vl_msg_api_free (mp);
1115     }
1116 }
1117
1118 static void
1119 vl_api_vnet_ip4_fib_counters_t_handler (vl_api_vnet_ip4_fib_counters_t * mp)
1120 {
1121   vpe_client_registration_t *reg;
1122   stats_main_t *sm = &stats_main;
1123   unix_shared_memory_queue_t *q, *q_prev = NULL;
1124   vl_api_vnet_ip4_fib_counters_t *mp_copy = NULL;
1125   u32 mp_size;
1126
1127   mp_size = sizeof (*mp_copy) +
1128     ntohl (mp->count) * sizeof (vl_api_ip4_fib_counter_t);
1129
1130   /* *INDENT-OFF* */
1131   pool_foreach(reg, sm->stats_registrations,
1132   ({
1133     q = vl_api_client_index_to_input_queue (reg->client_index);
1134     if (q)
1135       {
1136         if (q_prev && (q_prev->cursize < q_prev->maxsize))
1137           {
1138             mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1139             clib_memcpy(mp_copy, mp, mp_size);
1140             vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1141             mp = mp_copy;
1142           }
1143         q_prev = q;
1144       }
1145   }));
1146   /* *INDENT-ON* */
1147   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1148     {
1149       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1150     }
1151   else
1152     {
1153       vl_msg_api_free (mp);
1154     }
1155 }
1156
1157 static void
1158 vl_api_vnet_ip4_nbr_counters_t_handler (vl_api_vnet_ip4_nbr_counters_t * mp)
1159 {
1160   vpe_client_registration_t *reg;
1161   stats_main_t *sm = &stats_main;
1162   unix_shared_memory_queue_t *q, *q_prev = NULL;
1163   vl_api_vnet_ip4_nbr_counters_t *mp_copy = NULL;
1164   u32 mp_size;
1165
1166   mp_size = sizeof (*mp_copy) +
1167     ntohl (mp->count) * sizeof (vl_api_ip4_nbr_counter_t);
1168
1169   /* *INDENT-OFF* */
1170   pool_foreach(reg, sm->stats_registrations,
1171   ({
1172     q = vl_api_client_index_to_input_queue (reg->client_index);
1173     if (q)
1174       {
1175         if (q_prev && (q_prev->cursize < q_prev->maxsize))
1176           {
1177             mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1178             clib_memcpy(mp_copy, mp, mp_size);
1179             vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1180             mp = mp_copy;
1181           }
1182         q_prev = q;
1183       }
1184   }));
1185   /* *INDENT-ON* */
1186   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1187     {
1188       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1189     }
1190   else
1191     {
1192       vl_msg_api_free (mp);
1193     }
1194 }
1195
1196 static void
1197 vl_api_vnet_ip6_fib_counters_t_handler (vl_api_vnet_ip6_fib_counters_t * mp)
1198 {
1199   vpe_client_registration_t *reg;
1200   stats_main_t *sm = &stats_main;
1201   unix_shared_memory_queue_t *q, *q_prev = NULL;
1202   vl_api_vnet_ip6_fib_counters_t *mp_copy = NULL;
1203   u32 mp_size;
1204
1205   mp_size = sizeof (*mp_copy) +
1206     ntohl (mp->count) * sizeof (vl_api_ip6_fib_counter_t);
1207
1208   /* *INDENT-OFF* */
1209   pool_foreach(reg, sm->stats_registrations,
1210   ({
1211     q = vl_api_client_index_to_input_queue (reg->client_index);
1212     if (q)
1213       {
1214         if (q_prev && (q_prev->cursize < q_prev->maxsize))
1215           {
1216             mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1217             clib_memcpy(mp_copy, mp, mp_size);
1218             vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1219             mp = mp_copy;
1220           }
1221         q_prev = q;
1222       }
1223   }));
1224   /* *INDENT-ON* */
1225   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1226     {
1227       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1228     }
1229   else
1230     {
1231       vl_msg_api_free (mp);
1232     }
1233 }
1234
1235 static void
1236 vl_api_vnet_ip6_nbr_counters_t_handler (vl_api_vnet_ip6_nbr_counters_t * mp)
1237 {
1238   vpe_client_registration_t *reg;
1239   stats_main_t *sm = &stats_main;
1240   unix_shared_memory_queue_t *q, *q_prev = NULL;
1241   vl_api_vnet_ip6_nbr_counters_t *mp_copy = NULL;
1242   u32 mp_size;
1243
1244   mp_size = sizeof (*mp_copy) +
1245     ntohl (mp->count) * sizeof (vl_api_ip6_nbr_counter_t);
1246
1247   /* *INDENT-OFF* */
1248   pool_foreach(reg, sm->stats_registrations,
1249   ({
1250     q = vl_api_client_index_to_input_queue (reg->client_index);
1251     if (q)
1252       {
1253         if (q_prev && (q_prev->cursize < q_prev->maxsize))
1254           {
1255             mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1256             clib_memcpy(mp_copy, mp, mp_size);
1257             vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1258             mp = mp_copy;
1259           }
1260         q_prev = q;
1261       }
1262   }));
1263   /* *INDENT-ON* */
1264   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1265     {
1266       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1267     }
1268   else
1269     {
1270       vl_msg_api_free (mp);
1271     }
1272 }
1273
1274 static void
1275 vl_api_want_stats_t_handler (vl_api_want_stats_t * mp)
1276 {
1277   stats_main_t *sm = &stats_main;
1278   vpe_client_registration_t *rp;
1279   vl_api_want_stats_reply_t *rmp;
1280   uword *p;
1281   i32 retval = 0;
1282   unix_shared_memory_queue_t *q;
1283
1284   p = hash_get (sm->stats_registration_hash, mp->client_index);
1285   if (p)
1286     {
1287       if (mp->enable_disable)
1288         {
1289           clib_warning ("pid %d: already enabled...", mp->pid);
1290           retval = -2;
1291           goto reply;
1292         }
1293       else
1294         {
1295           rp = pool_elt_at_index (sm->stats_registrations, p[0]);
1296           pool_put (sm->stats_registrations, rp);
1297           hash_unset (sm->stats_registration_hash, mp->client_index);
1298           goto reply;
1299         }
1300     }
1301   if (mp->enable_disable == 0)
1302     {
1303       clib_warning ("pid %d: already disabled...", mp->pid);
1304       retval = -3;
1305       goto reply;
1306     }
1307   pool_get (sm->stats_registrations, rp);
1308   rp->client_index = mp->client_index;
1309   rp->client_pid = mp->pid;
1310   hash_set (sm->stats_registration_hash, rp->client_index,
1311             rp - sm->stats_registrations);
1312
1313 reply:
1314   if (pool_elts (sm->stats_registrations))
1315     sm->enable_poller = 1;
1316   else
1317     sm->enable_poller = 0;
1318
1319   q = vl_api_client_index_to_input_queue (mp->client_index);
1320
1321   if (!q)
1322     return;
1323
1324   rmp = vl_msg_api_alloc (sizeof (*rmp));
1325   rmp->_vl_msg_id = ntohs (VL_API_WANT_STATS_REPLY);
1326   rmp->context = mp->context;
1327   rmp->retval = retval;
1328
1329   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1330 }
1331
1332 int
1333 stats_memclnt_delete_callback (u32 client_index)
1334 {
1335   vpe_client_registration_t *rp;
1336   stats_main_t *sm = &stats_main;
1337   uword *p;
1338
1339   p = hash_get (sm->stats_registration_hash, client_index);
1340   if (p)
1341     {
1342       rp = pool_elt_at_index (sm->stats_registrations, p[0]);
1343       pool_put (sm->stats_registrations, rp);
1344       hash_unset (sm->stats_registration_hash, client_index);
1345     }
1346
1347   return 0;
1348 }
1349
1350 #define vl_api_vnet_interface_simple_counters_t_endian vl_noop_handler
1351 #define vl_api_vnet_interface_simple_counters_t_print vl_noop_handler
1352 #define vl_api_vnet_interface_combined_counters_t_endian vl_noop_handler
1353 #define vl_api_vnet_interface_combined_counters_t_print vl_noop_handler
1354 #define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
1355 #define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
1356 #define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
1357 #define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler
1358 #define vl_api_vnet_ip4_nbr_counters_t_endian vl_noop_handler
1359 #define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
1360 #define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
1361 #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
1362
1363 static clib_error_t *
1364 stats_init (vlib_main_t * vm)
1365 {
1366   stats_main_t *sm = &stats_main;
1367   api_main_t *am = &api_main;
1368   void *vlib_worker_thread_bootstrap_fn (void *arg);
1369
1370   sm->vlib_main = vm;
1371   sm->vnet_main = vnet_get_main ();
1372   sm->interface_main = &vnet_get_main ()->interface_main;
1373   sm->api_main = am;
1374   sm->stats_poll_interval_in_seconds = 10;
1375   sm->data_structure_lock =
1376     clib_mem_alloc_aligned (sizeof (data_structure_lock_t),
1377                             CLIB_CACHE_LINE_BYTES);
1378   memset (sm->data_structure_lock, 0, sizeof (*sm->data_structure_lock));
1379
1380 #define _(N,n)                                                  \
1381     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1382                            vl_api_##n##_t_handler,              \
1383                            vl_noop_handler,                     \
1384                            vl_api_##n##_t_endian,               \
1385                            vl_api_##n##_t_print,                \
1386                            sizeof(vl_api_##n##_t), 0 /* do NOT trace! */);
1387   foreach_stats_msg;
1388 #undef _
1389
1390   /* tell the msg infra not to free these messages... */
1391   am->message_bounce[VL_API_VNET_INTERFACE_SIMPLE_COUNTERS] = 1;
1392   am->message_bounce[VL_API_VNET_INTERFACE_COMBINED_COUNTERS] = 1;
1393   am->message_bounce[VL_API_VNET_IP4_FIB_COUNTERS] = 1;
1394   am->message_bounce[VL_API_VNET_IP6_FIB_COUNTERS] = 1;
1395   am->message_bounce[VL_API_VNET_IP4_NBR_COUNTERS] = 1;
1396   am->message_bounce[VL_API_VNET_IP6_NBR_COUNTERS] = 1;
1397
1398   return 0;
1399 }
1400
1401 VLIB_INIT_FUNCTION (stats_init);
1402
1403 /* *INDENT-OFF* */
1404 VLIB_REGISTER_THREAD (stats_thread_reg, static) = {
1405   .name = "stats",
1406   .function = stats_thread_fn,
1407   .fixed_count = 1,
1408   .count = 1,
1409   .no_data_structure_clone = 1,
1410   .use_pthreads = 1,
1411 };
1412 /* *INDENT-ON* */
1413
1414 /*
1415  * fd.io coding-style-patch-verification: ON
1416  *
1417  * Local Variables:
1418  * eval: (c-set-style "gnu")
1419  * End:
1420  */