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