38821da78016c14766e4a1721465d2a9cc249ef0
[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   ip_lookup_main_t *lm = &im4->lookup_main;
581   static uword *results;
582   vl_api_vnet_ip4_fib_counters_t *mp = 0;
583   u32 items_this_message;
584   vl_api_ip4_fib_counter_t *ctrp = 0;
585   u32 start_at_fib_index = 0;
586   int i;
587
588 again:
589   /* *INDENT-OFF* */
590   pool_foreach (fib, im4->fibs,
591   ({
592     /* We may have bailed out due to control-plane activity */
593     while ((fib - im4->fibs) < start_at_fib_index)
594       continue;
595
596     v4_fib = pool_elt_at_index (im4->v4_fibs, fib->ft_index);
597
598     if (mp == 0)
599       {
600         items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
601         mp = vl_msg_api_alloc_as_if_client
602           (sizeof (*mp) +
603            items_this_message * sizeof (vl_api_ip4_fib_counter_t));
604         mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
605         mp->count = 0;
606         mp->vrf_id = ntohl (fib->ft_table_id);
607         ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
608       }
609     else
610       {
611         /* happens if the last FIB was empty... */
612         ASSERT (mp->count == 0);
613         mp->vrf_id = ntohl (fib->ft_table_id);
614       }
615
616     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
617
618     vec_reset_length (routes);
619     vec_reset_length (results);
620
621     for (i = 0; i < ARRAY_LEN (v4_fib->fib_entry_by_dst_address); i++)
622       {
623         uword *hash = v4_fib->fib_entry_by_dst_address[i];
624         hash_pair_t *p;
625         ip4_route_t x;
626
627         x.address_length = i;
628
629         hash_foreach_pair (p, hash,
630         ({
631           x.address.data_u32 = p->key;
632           x.index = p->value[0];
633
634           vec_add1 (routes, x);
635           if (sm->data_structure_lock->release_hint)
636             {
637               start_at_fib_index = fib - im4->fibs;
638               dsunlock (sm);
639               ip46_fib_stats_delay (sm, 0 /* sec */,
640                                     STATS_RELEASE_DELAY_NS);
641               mp->count = 0;
642               ctrp = (vl_api_ip4_fib_counter_t *)mp->c;
643               goto again;
644             }
645         }));
646       }
647
648     vec_foreach (r, routes)
649       {
650         vlib_counter_t c;
651
652         vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
653                                    r->index, &c);
654         /*
655          * If it has actually
656          * seen at least one packet, send it.
657          */
658         if (c.packets > 0)
659           {
660
661             /* already in net byte order */
662             ctrp->address = r->address.as_u32;
663             ctrp->address_length = r->address_length;
664             ctrp->packets = clib_host_to_net_u64 (c.packets);
665             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
666             mp->count++;
667             ctrp++;
668
669             if (mp->count == items_this_message)
670               {
671                 mp->count = htonl (items_this_message);
672                 /*
673                  * If the main thread's input queue is stuffed,
674                  * drop the data structure lock (which the main thread
675                  * may want), and take a pause.
676                  */
677                 unix_shared_memory_queue_lock (q);
678                 if (unix_shared_memory_queue_is_full (q))
679                   {
680                     dsunlock (sm);
681                     vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
682                     unix_shared_memory_queue_unlock (q);
683                     mp = 0;
684                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
685                                           STATS_RELEASE_DELAY_NS);
686                     goto again;
687                   }
688                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
689                 unix_shared_memory_queue_unlock (q);
690
691                 items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
692                 mp = vl_msg_api_alloc_as_if_client
693                   (sizeof (*mp) +
694                    items_this_message * sizeof (vl_api_ip4_fib_counter_t));
695                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
696                 mp->count = 0;
697                 mp->vrf_id = ntohl (fib->ft_table_id);
698                 ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
699               }
700           }                     /* for each (mp or single) adj */
701         if (sm->data_structure_lock->release_hint)
702           {
703             start_at_fib_index = fib - im4->fibs;
704             dsunlock (sm);
705             ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
706             mp->count = 0;
707             ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
708             goto again;
709           }
710       }                         /* vec_foreach (routes) */
711
712     dsunlock (sm);
713
714     /* Flush any data from this fib */
715     if (mp->count)
716       {
717         mp->count = htonl (mp->count);
718         vl_msg_api_send_shmem (q, (u8 *) & mp);
719         mp = 0;
720       }
721   }));
722   /* *INDENT-ON* */
723
724   /* If e.g. the last FIB had no reportable routes, free the buffer */
725   if (mp)
726     vl_msg_api_free (mp);
727 }
728
729 typedef struct
730 {
731   ip6_address_t address;
732   u32 address_length;
733   u32 index;
734 } ip6_route_t;
735
736 typedef struct
737 {
738   u32 fib_index;
739   ip6_route_t **routep;
740   stats_main_t *sm;
741 } add_routes_in_fib_arg_t;
742
743 static void
744 add_routes_in_fib (BVT (clib_bihash_kv) * kvp, void *arg)
745 {
746   add_routes_in_fib_arg_t *ap = arg;
747   stats_main_t *sm = ap->sm;
748
749   if (sm->data_structure_lock->release_hint)
750     clib_longjmp (&sm->jmp_buf, 1);
751
752   if (kvp->key[2] >> 32 == ap->fib_index)
753     {
754       ip6_address_t *addr;
755       ip6_route_t *r;
756       addr = (ip6_address_t *) kvp;
757       vec_add2 (*ap->routep, r, 1);
758       r->address = addr[0];
759       r->address_length = kvp->key[2] & 0xFF;
760       r->index = kvp->value;
761     }
762 }
763
764 static void
765 do_ip6_fibs (stats_main_t * sm)
766 {
767   ip6_main_t *im6 = &ip6_main;
768   api_main_t *am = sm->api_main;
769   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
770   unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
771   static ip6_route_t *routes;
772   ip6_route_t *r;
773   fib_table_t *fib;
774   static uword *results;
775   vl_api_vnet_ip6_fib_counters_t *mp = 0;
776   u32 items_this_message;
777   vl_api_ip6_fib_counter_t *ctrp = 0;
778   u32 start_at_fib_index = 0;
779   BVT (clib_bihash) * h = &im6->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash;
780   add_routes_in_fib_arg_t _a, *a = &_a;
781
782 again:
783   /* *INDENT-OFF* */
784   pool_foreach (fib, im6->fibs,
785   ({
786     /* We may have bailed out due to control-plane activity */
787     while ((fib - im6->fibs) < start_at_fib_index)
788       continue;
789
790     if (mp == 0)
791       {
792         items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
793         mp = vl_msg_api_alloc_as_if_client
794           (sizeof (*mp) +
795            items_this_message * sizeof (vl_api_ip6_fib_counter_t));
796         mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
797         mp->count = 0;
798         mp->vrf_id = ntohl (fib->ft_table_id);
799         ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
800       }
801
802     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
803
804     vec_reset_length (routes);
805     vec_reset_length (results);
806
807     a->fib_index = fib - im6->fibs;
808     a->routep = &routes;
809     a->sm = sm;
810
811     if (clib_setjmp (&sm->jmp_buf, 0) == 0)
812       {
813         start_at_fib_index = fib - im6->fibs;
814         BV (clib_bihash_foreach_key_value_pair) (h, add_routes_in_fib, a);
815       }
816     else
817       {
818         dsunlock (sm);
819         ip46_fib_stats_delay (sm, 0 /* sec */ ,
820                               STATS_RELEASE_DELAY_NS);
821         mp->count = 0;
822         ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
823         goto again;
824       }
825
826     vec_foreach (r, routes)
827     {
828         vlib_counter_t c;
829
830         vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
831                                    r->index, &c);
832         /*
833          * If it has actually
834          * seen at least one packet, send it.
835          */
836         if (c.packets > 0)
837           {
838             /* already in net byte order */
839             ctrp->address[0] = r->address.as_u64[0];
840             ctrp->address[1] = r->address.as_u64[1];
841             ctrp->address_length = (u8) r->address_length;
842             ctrp->packets = clib_host_to_net_u64 (c.packets);
843             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
844             mp->count++;
845             ctrp++;
846
847             if (mp->count == items_this_message)
848               {
849                 mp->count = htonl (items_this_message);
850                 /*
851                  * If the main thread's input queue is stuffed,
852                  * drop the data structure lock (which the main thread
853                  * may want), and take a pause.
854                  */
855                 unix_shared_memory_queue_lock (q);
856                 if (unix_shared_memory_queue_is_full (q))
857                   {
858                     dsunlock (sm);
859                     vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
860                     unix_shared_memory_queue_unlock (q);
861                     mp = 0;
862                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
863                                           STATS_RELEASE_DELAY_NS);
864                     goto again;
865                   }
866                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
867                 unix_shared_memory_queue_unlock (q);
868
869                 items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
870                 mp = vl_msg_api_alloc_as_if_client
871                   (sizeof (*mp) +
872                    items_this_message * sizeof (vl_api_ip6_fib_counter_t));
873                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
874                 mp->count = 0;
875                 mp->vrf_id = ntohl (fib->ft_table_id);
876                 ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
877               }
878           }
879
880         if (sm->data_structure_lock->release_hint)
881           {
882             start_at_fib_index = fib - im6->fibs;
883             dsunlock (sm);
884             ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
885             mp->count = 0;
886             ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
887             goto again;
888           }
889     }                           /* vec_foreach (routes) */
890
891     dsunlock (sm);
892
893     /* Flush any data from this fib */
894     if (mp->count)
895       {
896         mp->count = htonl (mp->count);
897         vl_msg_api_send_shmem (q, (u8 *) & mp);
898         mp = 0;
899       }
900   }));
901   /* *INDENT-ON* */
902
903   /* If e.g. the last FIB had no reportable routes, free the buffer */
904   if (mp)
905     vl_msg_api_free (mp);
906 }
907
908 static void
909 stats_thread_fn (void *arg)
910 {
911   stats_main_t *sm = &stats_main;
912   vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
913   vlib_thread_main_t *tm = vlib_get_thread_main ();
914
915   /* stats thread wants no signals. */
916   {
917     sigset_t s;
918     sigfillset (&s);
919     pthread_sigmask (SIG_SETMASK, &s, 0);
920   }
921
922   if (vec_len (tm->thread_prefix))
923     vlib_set_thread_name ((char *)
924                           format (0, "%v_stats%c", tm->thread_prefix, '\0'));
925
926   clib_mem_set_heap (w->thread_mheap);
927
928   while (1)
929     {
930       /* 10 second poll interval */
931       ip46_fib_stats_delay (sm, 10 /* secs */ , 0 /* nsec */ );
932
933       if (!(sm->enable_poller))
934         continue;
935       do_simple_interface_counters (sm);
936       do_combined_interface_counters (sm);
937       do_ip4_fibs (sm);
938       do_ip6_fibs (sm);
939       do_ip4_nbrs (sm);
940       do_ip6_nbrs (sm);
941     }
942 }
943
944 static void
945   vl_api_vnet_interface_simple_counters_t_handler
946   (vl_api_vnet_interface_simple_counters_t * mp)
947 {
948   vpe_client_registration_t *reg;
949   stats_main_t *sm = &stats_main;
950   unix_shared_memory_queue_t *q, *q_prev = NULL;
951   vl_api_vnet_interface_simple_counters_t *mp_copy = NULL;
952   u32 mp_size;
953
954 #if STATS_DEBUG > 0
955   char *counter_name;
956   u32 count, sw_if_index;
957   int i;
958 #endif
959
960   mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (u64));
961
962   /* *INDENT-OFF* */
963   pool_foreach(reg, sm->stats_registrations,
964                ({
965                  q = vl_api_client_index_to_input_queue (reg->client_index);
966                  if (q)
967                    {
968                      if (q_prev && (q_prev->cursize < q_prev->maxsize))
969                        {
970                          mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
971                          clib_memcpy(mp_copy, mp, mp_size);
972                          vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
973                          mp = mp_copy;
974                        }
975                      q_prev = q;
976                    }
977                }));
978   /* *INDENT-ON* */
979
980 #if STATS_DEBUG > 0
981   count = ntohl (mp->count);
982   sw_if_index = ntohl (mp->first_sw_if_index);
983   u64 *vp, v;
984   vp = (u64 *) mp->data;
985
986   switch (mp->vnet_counter_type)
987     {
988     case VNET_INTERFACE_COUNTER_DROP:
989       counter_name = "drop";
990       break;
991     case VNET_INTERFACE_COUNTER_PUNT:
992       counter_name = "punt";
993       break;
994     case VNET_INTERFACE_COUNTER_IP4:
995       counter_name = "ip4";
996       break;
997     case VNET_INTERFACE_COUNTER_IP6:
998       counter_name = "ip6";
999       break;
1000     case VNET_INTERFACE_COUNTER_RX_NO_BUF:
1001       counter_name = "rx-no-buff";
1002       break;
1003     case VNET_INTERFACE_COUNTER_RX_MISS:
1004       , counter_name = "rx-miss";
1005       break;
1006     case VNET_INTERFACE_COUNTER_RX_ERROR:
1007       , counter_name = "rx-error (fifo-full)";
1008       break;
1009     case VNET_INTERFACE_COUNTER_TX_ERROR:
1010       , counter_name = "tx-error (fifo-full)";
1011       break;
1012     default:
1013       counter_name = "bogus";
1014       break;
1015     }
1016   for (i = 0; i < count; i++)
1017     {
1018       v = clib_mem_unaligned (vp, u64);
1019       v = clib_net_to_host_u64 (v);
1020       vp++;
1021       fformat (stdout, "%U.%s %lld\n", format_vnet_sw_if_index_name,
1022                sm->vnet_main, sw_if_index, counter_name, v);
1023       sw_if_index++;
1024     }
1025 #endif
1026   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1027     {
1028       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1029     }
1030   else
1031     {
1032       vl_msg_api_free (mp);
1033     }
1034 }
1035
1036 static void
1037   vl_api_vnet_interface_combined_counters_t_handler
1038   (vl_api_vnet_interface_combined_counters_t * mp)
1039 {
1040   vpe_client_registration_t *reg;
1041   stats_main_t *sm = &stats_main;
1042   unix_shared_memory_queue_t *q, *q_prev = NULL;
1043   vl_api_vnet_interface_combined_counters_t *mp_copy = NULL;
1044   u32 mp_size;
1045
1046 #if STATS_DEBUG > 0
1047   char *counter_name;
1048   u32 count, sw_if_index;
1049   int i;
1050 #endif
1051
1052   mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (vlib_counter_t));
1053
1054   /* *INDENT-OFF* */
1055   pool_foreach(reg, sm->stats_registrations,
1056                ({
1057                  q = vl_api_client_index_to_input_queue (reg->client_index);
1058                  if (q)
1059                    {
1060                      if (q_prev && (q_prev->cursize < q_prev->maxsize))
1061                        {
1062                          mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1063                          clib_memcpy(mp_copy, mp, mp_size);
1064                          vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1065                          mp = mp_copy;
1066                        }
1067                      q_prev = q;
1068                    }
1069                }));
1070   /* *INDENT-ON* */
1071
1072 #if STATS_DEBUG > 0
1073   count = ntohl (mp->count);
1074   sw_if_index = ntohl (mp->first_sw_if_index);
1075
1076   vlib_counter_t *vp;
1077   u64 packets, bytes;
1078   vp = (vlib_counter_t *) mp->data;
1079
1080   switch (mp->vnet_counter_type)
1081     {
1082     case VNET_INTERFACE_COUNTER_RX:
1083       counter_name = "rx";
1084       break;
1085     case VNET_INTERFACE_COUNTER_TX:
1086       counter_name = "tx";
1087       break;
1088     default:
1089       counter_name = "bogus";
1090       break;
1091     }
1092   for (i = 0; i < count; i++)
1093     {
1094       packets = clib_mem_unaligned (&vp->packets, u64);
1095       packets = clib_net_to_host_u64 (packets);
1096       bytes = clib_mem_unaligned (&vp->bytes, u64);
1097       bytes = clib_net_to_host_u64 (bytes);
1098       vp++;
1099       fformat (stdout, "%U.%s.packets %lld\n",
1100                format_vnet_sw_if_index_name,
1101                sm->vnet_main, sw_if_index, counter_name, packets);
1102       fformat (stdout, "%U.%s.bytes %lld\n",
1103                format_vnet_sw_if_index_name,
1104                sm->vnet_main, sw_if_index, counter_name, bytes);
1105       sw_if_index++;
1106     }
1107
1108 #endif
1109   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1110     {
1111       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1112     }
1113   else
1114     {
1115       vl_msg_api_free (mp);
1116     }
1117 }
1118
1119 static void
1120 vl_api_vnet_ip4_fib_counters_t_handler (vl_api_vnet_ip4_fib_counters_t * mp)
1121 {
1122   vpe_client_registration_t *reg;
1123   stats_main_t *sm = &stats_main;
1124   unix_shared_memory_queue_t *q, *q_prev = NULL;
1125   vl_api_vnet_ip4_fib_counters_t *mp_copy = NULL;
1126   u32 mp_size;
1127
1128   mp_size = sizeof (*mp_copy) +
1129     ntohl (mp->count) * sizeof (vl_api_ip4_fib_counter_t);
1130
1131   /* *INDENT-OFF* */
1132   pool_foreach(reg, sm->stats_registrations,
1133   ({
1134     q = vl_api_client_index_to_input_queue (reg->client_index);
1135     if (q)
1136       {
1137         if (q_prev && (q_prev->cursize < q_prev->maxsize))
1138           {
1139             mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1140             clib_memcpy(mp_copy, mp, mp_size);
1141             vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1142             mp = mp_copy;
1143           }
1144         q_prev = q;
1145       }
1146   }));
1147   /* *INDENT-ON* */
1148   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1149     {
1150       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1151     }
1152   else
1153     {
1154       vl_msg_api_free (mp);
1155     }
1156 }
1157
1158 static void
1159 vl_api_vnet_ip4_nbr_counters_t_handler (vl_api_vnet_ip4_nbr_counters_t * mp)
1160 {
1161   vpe_client_registration_t *reg;
1162   stats_main_t *sm = &stats_main;
1163   unix_shared_memory_queue_t *q, *q_prev = NULL;
1164   vl_api_vnet_ip4_nbr_counters_t *mp_copy = NULL;
1165   u32 mp_size;
1166
1167   mp_size = sizeof (*mp_copy) +
1168     ntohl (mp->count) * sizeof (vl_api_ip4_nbr_counter_t);
1169
1170   /* *INDENT-OFF* */
1171   pool_foreach(reg, sm->stats_registrations,
1172   ({
1173     q = vl_api_client_index_to_input_queue (reg->client_index);
1174     if (q)
1175       {
1176         if (q_prev && (q_prev->cursize < q_prev->maxsize))
1177           {
1178             mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1179             clib_memcpy(mp_copy, mp, mp_size);
1180             vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1181             mp = mp_copy;
1182           }
1183         q_prev = q;
1184       }
1185   }));
1186   /* *INDENT-ON* */
1187   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1188     {
1189       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1190     }
1191   else
1192     {
1193       vl_msg_api_free (mp);
1194     }
1195 }
1196
1197 static void
1198 vl_api_vnet_ip6_fib_counters_t_handler (vl_api_vnet_ip6_fib_counters_t * mp)
1199 {
1200   vpe_client_registration_t *reg;
1201   stats_main_t *sm = &stats_main;
1202   unix_shared_memory_queue_t *q, *q_prev = NULL;
1203   vl_api_vnet_ip6_fib_counters_t *mp_copy = NULL;
1204   u32 mp_size;
1205
1206   mp_size = sizeof (*mp_copy) +
1207     ntohl (mp->count) * sizeof (vl_api_ip6_fib_counter_t);
1208
1209   /* *INDENT-OFF* */
1210   pool_foreach(reg, sm->stats_registrations,
1211   ({
1212     q = vl_api_client_index_to_input_queue (reg->client_index);
1213     if (q)
1214       {
1215         if (q_prev && (q_prev->cursize < q_prev->maxsize))
1216           {
1217             mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1218             clib_memcpy(mp_copy, mp, mp_size);
1219             vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1220             mp = mp_copy;
1221           }
1222         q_prev = q;
1223       }
1224   }));
1225   /* *INDENT-ON* */
1226   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1227     {
1228       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1229     }
1230   else
1231     {
1232       vl_msg_api_free (mp);
1233     }
1234 }
1235
1236 static void
1237 vl_api_vnet_ip6_nbr_counters_t_handler (vl_api_vnet_ip6_nbr_counters_t * mp)
1238 {
1239   vpe_client_registration_t *reg;
1240   stats_main_t *sm = &stats_main;
1241   unix_shared_memory_queue_t *q, *q_prev = NULL;
1242   vl_api_vnet_ip6_nbr_counters_t *mp_copy = NULL;
1243   u32 mp_size;
1244
1245   mp_size = sizeof (*mp_copy) +
1246     ntohl (mp->count) * sizeof (vl_api_ip6_nbr_counter_t);
1247
1248   /* *INDENT-OFF* */
1249   pool_foreach(reg, sm->stats_registrations,
1250   ({
1251     q = vl_api_client_index_to_input_queue (reg->client_index);
1252     if (q)
1253       {
1254         if (q_prev && (q_prev->cursize < q_prev->maxsize))
1255           {
1256             mp_copy = vl_msg_api_alloc_as_if_client(mp_size);
1257             clib_memcpy(mp_copy, mp, mp_size);
1258             vl_msg_api_send_shmem (q_prev, (u8 *)&mp);
1259             mp = mp_copy;
1260           }
1261         q_prev = q;
1262       }
1263   }));
1264   /* *INDENT-ON* */
1265   if (q_prev && (q_prev->cursize < q_prev->maxsize))
1266     {
1267       vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1268     }
1269   else
1270     {
1271       vl_msg_api_free (mp);
1272     }
1273 }
1274
1275 static void
1276 vl_api_want_stats_t_handler (vl_api_want_stats_t * mp)
1277 {
1278   stats_main_t *sm = &stats_main;
1279   vpe_client_registration_t *rp;
1280   vl_api_want_stats_reply_t *rmp;
1281   uword *p;
1282   i32 retval = 0;
1283   unix_shared_memory_queue_t *q;
1284
1285   p = hash_get (sm->stats_registration_hash, mp->client_index);
1286   if (p)
1287     {
1288       if (mp->enable_disable)
1289         {
1290           clib_warning ("pid %d: already enabled...", mp->pid);
1291           retval = -2;
1292           goto reply;
1293         }
1294       else
1295         {
1296           rp = pool_elt_at_index (sm->stats_registrations, p[0]);
1297           pool_put (sm->stats_registrations, rp);
1298           hash_unset (sm->stats_registration_hash, mp->client_index);
1299           goto reply;
1300         }
1301     }
1302   if (mp->enable_disable == 0)
1303     {
1304       clib_warning ("pid %d: already disabled...", mp->pid);
1305       retval = -3;
1306       goto reply;
1307     }
1308   pool_get (sm->stats_registrations, rp);
1309   rp->client_index = mp->client_index;
1310   rp->client_pid = mp->pid;
1311   hash_set (sm->stats_registration_hash, rp->client_index,
1312             rp - sm->stats_registrations);
1313
1314 reply:
1315   if (pool_elts (sm->stats_registrations))
1316     sm->enable_poller = 1;
1317   else
1318     sm->enable_poller = 0;
1319
1320   q = vl_api_client_index_to_input_queue (mp->client_index);
1321
1322   if (!q)
1323     return;
1324
1325   rmp = vl_msg_api_alloc (sizeof (*rmp));
1326   rmp->_vl_msg_id = ntohs (VL_API_WANT_STATS_REPLY);
1327   rmp->context = mp->context;
1328   rmp->retval = retval;
1329
1330   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1331 }
1332
1333 int
1334 stats_memclnt_delete_callback (u32 client_index)
1335 {
1336   vpe_client_registration_t *rp;
1337   stats_main_t *sm = &stats_main;
1338   uword *p;
1339
1340   p = hash_get (sm->stats_registration_hash, client_index);
1341   if (p)
1342     {
1343       rp = pool_elt_at_index (sm->stats_registrations, p[0]);
1344       pool_put (sm->stats_registrations, rp);
1345       hash_unset (sm->stats_registration_hash, client_index);
1346     }
1347
1348   return 0;
1349 }
1350
1351 #define vl_api_vnet_interface_simple_counters_t_endian vl_noop_handler
1352 #define vl_api_vnet_interface_simple_counters_t_print vl_noop_handler
1353 #define vl_api_vnet_interface_combined_counters_t_endian vl_noop_handler
1354 #define vl_api_vnet_interface_combined_counters_t_print vl_noop_handler
1355 #define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
1356 #define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
1357 #define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
1358 #define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler
1359 #define vl_api_vnet_ip4_nbr_counters_t_endian vl_noop_handler
1360 #define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
1361 #define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
1362 #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
1363
1364 static clib_error_t *
1365 stats_init (vlib_main_t * vm)
1366 {
1367   stats_main_t *sm = &stats_main;
1368   api_main_t *am = &api_main;
1369   void *vlib_worker_thread_bootstrap_fn (void *arg);
1370
1371   sm->vlib_main = vm;
1372   sm->vnet_main = vnet_get_main ();
1373   sm->interface_main = &vnet_get_main ()->interface_main;
1374   sm->api_main = am;
1375   sm->stats_poll_interval_in_seconds = 10;
1376   sm->data_structure_lock =
1377     clib_mem_alloc_aligned (sizeof (data_structure_lock_t),
1378                             CLIB_CACHE_LINE_BYTES);
1379   memset (sm->data_structure_lock, 0, sizeof (*sm->data_structure_lock));
1380
1381 #define _(N,n)                                                  \
1382     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1383                            vl_api_##n##_t_handler,              \
1384                            vl_noop_handler,                     \
1385                            vl_api_##n##_t_endian,               \
1386                            vl_api_##n##_t_print,                \
1387                            sizeof(vl_api_##n##_t), 0 /* do NOT trace! */);
1388   foreach_stats_msg;
1389 #undef _
1390
1391   /* tell the msg infra not to free these messages... */
1392   am->message_bounce[VL_API_VNET_INTERFACE_SIMPLE_COUNTERS] = 1;
1393   am->message_bounce[VL_API_VNET_INTERFACE_COMBINED_COUNTERS] = 1;
1394   am->message_bounce[VL_API_VNET_IP4_FIB_COUNTERS] = 1;
1395   am->message_bounce[VL_API_VNET_IP6_FIB_COUNTERS] = 1;
1396   am->message_bounce[VL_API_VNET_IP4_NBR_COUNTERS] = 1;
1397   am->message_bounce[VL_API_VNET_IP6_NBR_COUNTERS] = 1;
1398
1399   return 0;
1400 }
1401
1402 VLIB_INIT_FUNCTION (stats_init);
1403
1404 /* *INDENT-OFF* */
1405 VLIB_REGISTER_THREAD (stats_thread_reg, static) = {
1406   .name = "stats",
1407   .function = stats_thread_fn,
1408   .fixed_count = 1,
1409   .count = 1,
1410   .no_data_structure_clone = 1,
1411   .use_pthreads = 1,
1412 };
1413 /* *INDENT-ON* */
1414
1415 /*
1416  * fd.io coding-style-patch-verification: ON
1417  *
1418  * Local Variables:
1419  * eval: (c-set-style "gnu")
1420  * End:
1421  */