f1c40e630d2d001cc36f1ea8049c630763622a21
[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 <vnet/fib/ip4_fib.h>
18 #include <vnet/fib/fib_entry.h>
19 #include <vnet/mfib/mfib_entry.h>
20 #include <vnet/dpo/load_balance.h>
21 #include <vnet/udp/udp_encap.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 _(WANT_INTERFACE_SIMPLE_STATS, want_interface_simple_stats)             \
52 _(VNET_INTERFACE_COMBINED_COUNTERS, vnet_interface_combined_counters)   \
53 _(WANT_INTERFACE_COMBINED_STATS, want_interface_combined_stats)         \
54 _(WANT_PER_INTERFACE_COMBINED_STATS, want_per_interface_combined_stats) \
55 _(WANT_PER_INTERFACE_SIMPLE_STATS, want_per_interface_simple_stats)     \
56 _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters)                         \
57 _(WANT_IP4_FIB_STATS, want_ip4_fib_stats)                               \
58 _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters)                         \
59 _(WANT_IP6_FIB_STATS, want_ip6_fib_stats)                               \
60 _(WANT_IP4_MFIB_STATS, want_ip4_mfib_stats)                             \
61 _(WANT_IP6_MFIB_STATS, want_ip6_mfib_stats)                             \
62 _(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters)                         \
63 _(WANT_IP4_NBR_STATS, want_ip4_nbr_stats)                               \
64 _(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters)                         \
65 _(WANT_IP6_NBR_STATS, want_ip6_nbr_stats)                               \
66 _(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats)                       \
67 _(STATS_GET_POLLER_DELAY, stats_get_poller_delay)                       \
68 _(WANT_UDP_ENCAP_STATS, want_udp_encap_stats)                           \
69 _(MAP_STATS_SEGMENT, map_stats_segment)
70
71 #define vl_msg_name_crc_list
72 #include <vpp/stats/stats.api.h>
73 #undef vl_msg_name_crc_list
74
75 static void
76 setup_message_id_table (api_main_t * am)
77 {
78 #define _(id,n,crc) \
79   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
80   foreach_vl_msg_name_crc_stats;
81 #undef _
82 }
83
84 /* These constants ensure msg sizes <= 1024, aka ring allocation */
85 #define SIMPLE_COUNTER_BATCH_SIZE       126
86 #define COMBINED_COUNTER_BATCH_SIZE     63
87 #define IP4_FIB_COUNTER_BATCH_SIZE      48
88 #define IP6_FIB_COUNTER_BATCH_SIZE      30
89 #define IP4_MFIB_COUNTER_BATCH_SIZE     24
90 #define IP6_MFIB_COUNTER_BATCH_SIZE     15
91 #define UDP_ENCAP_COUNTER_BATCH_SIZE    (1024 / sizeof(vl_api_udp_encap_counter_t))
92
93 /* 5ms */
94 #define STATS_RELEASE_DELAY_NS (1000 * 1000 * 5)
95 /*                              ns/us  us/ms        */
96
97 u8 *
98 format_vnet_interface_combined_counters (u8 * s, va_list * args)
99 {
100   stats_main_t *sm = &stats_main;
101   vl_api_vnet_interface_combined_counters_t *mp =
102     va_arg (*args, vl_api_vnet_interface_combined_counters_t *);
103
104   char *counter_name;
105   u32 count, sw_if_index;
106   int i;
107   count = ntohl (mp->count);
108   sw_if_index = ntohl (mp->first_sw_if_index);
109
110   vlib_counter_t *vp;
111   u64 packets, bytes;
112   vp = (vlib_counter_t *) mp->data;
113
114   switch (mp->vnet_counter_type)
115     {
116     case VNET_INTERFACE_COUNTER_RX:
117       counter_name = "rx";
118       break;
119     case VNET_INTERFACE_COUNTER_TX:
120       counter_name = "tx";
121       break;
122     default:
123       counter_name = "bogus";
124       break;
125     }
126   for (i = 0; i < count; i++)
127     {
128       packets = clib_mem_unaligned (&vp->packets, u64);
129       packets = clib_net_to_host_u64 (packets);
130       bytes = clib_mem_unaligned (&vp->bytes, u64);
131       bytes = clib_net_to_host_u64 (bytes);
132       vp++;
133       s = format (s, "%U.%s.packets %lld\n",
134                   format_vnet_sw_if_index_name,
135                   sm->vnet_main, sw_if_index, counter_name, packets);
136       s = format (s, "%U.%s.bytes %lld\n",
137                   format_vnet_sw_if_index_name,
138                   sm->vnet_main, sw_if_index, counter_name, bytes);
139       sw_if_index++;
140     }
141   return s;
142 }
143
144 u8 *
145 format_vnet_interface_simple_counters (u8 * s, va_list * args)
146 {
147   stats_main_t *sm = &stats_main;
148   vl_api_vnet_interface_simple_counters_t *mp =
149     va_arg (*args, vl_api_vnet_interface_simple_counters_t *);
150   char *counter_name;
151   u32 count, sw_if_index;
152   count = ntohl (mp->count);
153   sw_if_index = ntohl (mp->first_sw_if_index);
154   u64 *vp, v;
155   vp = (u64 *) mp->data;
156   int i;
157
158   switch (mp->vnet_counter_type)
159     {
160     case VNET_INTERFACE_COUNTER_DROP:
161       counter_name = "drop";
162       break;
163     case VNET_INTERFACE_COUNTER_PUNT:
164       counter_name = "punt";
165       break;
166     case VNET_INTERFACE_COUNTER_IP4:
167       counter_name = "ip4";
168       break;
169     case VNET_INTERFACE_COUNTER_IP6:
170       counter_name = "ip6";
171       break;
172     case VNET_INTERFACE_COUNTER_RX_NO_BUF:
173       counter_name = "rx-no-buff";
174       break;
175     case VNET_INTERFACE_COUNTER_RX_MISS:
176       counter_name = "rx-miss";
177       break;
178     case VNET_INTERFACE_COUNTER_RX_ERROR:
179       counter_name = "rx-error (fifo-full)";
180       break;
181     case VNET_INTERFACE_COUNTER_TX_ERROR:
182       counter_name = "tx-error (fifo-full)";
183       break;
184     default:
185       counter_name = "bogus";
186       break;
187     }
188   for (i = 0; i < count; i++)
189     {
190       v = clib_mem_unaligned (vp, u64);
191       v = clib_net_to_host_u64 (v);
192       vp++;
193       s = format (s, "%U.%s %lld\n", format_vnet_sw_if_index_name,
194                   sm->vnet_main, sw_if_index, counter_name, v);
195       sw_if_index++;
196     }
197
198   return s;
199 }
200
201 static void
202 dslock (stats_main_t * sm, int release_hint, int tag)
203 {
204   u32 thread_index;
205   data_structure_lock_t *l = sm->data_structure_lock;
206
207   if (PREDICT_FALSE (l == 0))
208     return;
209
210   thread_index = vlib_get_thread_index ();
211   if (l->lock && l->thread_index == thread_index)
212     {
213       l->count++;
214       return;
215     }
216
217   if (release_hint)
218     l->release_hint++;
219
220   while (__sync_lock_test_and_set (&l->lock, 1))
221     /* zzzz */ ;
222   l->tag = tag;
223   l->thread_index = thread_index;
224   l->count = 1;
225 }
226
227 void
228 stats_dslock_with_hint (int hint, int tag)
229 {
230   stats_main_t *sm = &stats_main;
231   dslock (sm, hint, tag);
232 }
233
234 static void
235 dsunlock (stats_main_t * sm)
236 {
237   u32 thread_index;
238   data_structure_lock_t *l = sm->data_structure_lock;
239
240   if (PREDICT_FALSE (l == 0))
241     return;
242
243   thread_index = vlib_get_thread_index ();
244   ASSERT (l->lock && l->thread_index == thread_index);
245   l->count--;
246   if (l->count == 0)
247     {
248       l->tag = -l->tag;
249       l->release_hint = 0;
250       CLIB_MEMORY_BARRIER ();
251       l->lock = 0;
252     }
253 }
254
255 void
256 stats_dsunlock (int hint, int tag)
257 {
258   stats_main_t *sm = &stats_main;
259   dsunlock (sm);
260 }
261
262 static vpe_client_registration_t *
263 get_client_for_stat (u32 reg, u32 item, u32 client_index)
264 {
265   stats_main_t *sm = &stats_main;
266   vpe_client_stats_registration_t *registration;
267   uword *p;
268
269   /* Is there anything listening for item in that reg */
270   p = hash_get (sm->stats_registration_hash[reg], item);
271
272   if (!p)
273     return 0;                   // Fail
274
275   /* If there is, is our client_index one of them */
276   registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
277   p = hash_get (registration->client_hash, client_index);
278
279   if (!p)
280     return 0;                   // Fail
281
282   return pool_elt_at_index (registration->clients, p[0]);
283
284 }
285
286 static int
287 set_client_for_stat (u32 reg, u32 item, vpe_client_registration_t * client)
288 {
289   stats_main_t *sm = &stats_main;
290   vpe_client_stats_registration_t *registration;
291   vpe_client_registration_t *cr;
292   uword *p;
293
294   /* Is there anything listening for item in that reg */
295   p = hash_get (sm->stats_registration_hash[reg], item);
296
297   if (!p)
298     {
299       pool_get (sm->stats_registrations[reg], registration);
300       registration->item = item;
301       registration->client_hash = NULL;
302       registration->clients = NULL;
303       hash_set (sm->stats_registration_hash[reg], item,
304                 registration - sm->stats_registrations[reg]);
305     }
306   else
307     {
308       registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
309     }
310
311   p = hash_get (registration->client_hash, client->client_index);
312
313   if (!p)
314     {
315       pool_get (registration->clients, cr);
316       cr->client_index = client->client_index;
317       cr->client_pid = client->client_pid;
318       hash_set (registration->client_hash, cr->client_index,
319                 cr - registration->clients);
320     }
321
322   return 1;                     //At least one client is doing something ... poll
323 }
324
325 static void
326 clear_one_client (u32 reg_index, u32 reg, u32 item, u32 client_index)
327 {
328   stats_main_t *sm = &stats_main;
329   vpe_client_stats_registration_t *registration;
330   vpe_client_registration_t *client;
331   uword *p;
332
333   registration = pool_elt_at_index (sm->stats_registrations[reg], reg_index);
334   p = hash_get (registration->client_hash, client_index);
335
336   if (p)
337     {
338       client = pool_elt_at_index (registration->clients, p[0]);
339       hash_unset (registration->client_hash, client->client_index);
340       pool_put (registration->clients, client);
341
342       /* Now check if that was the last client for that item */
343       if (0 == pool_elts (registration->clients))
344         {
345           hash_unset (sm->stats_registration_hash[reg], item);
346           hash_free (registration->client_hash);
347           pool_free (registration->clients);
348           pool_put (sm->stats_registrations[reg], registration);
349         }
350     }
351 }
352
353 int
354 clear_client_for_stat (u32 reg, u32 item, u32 client_index)
355 {
356   stats_main_t *sm = &stats_main;
357   uword *p;
358   int i, elts;
359
360   /* Clear the client first */
361   /* Is there anything listening for item in that reg */
362   p = hash_get (sm->stats_registration_hash[reg], item);
363
364   if (!p)
365     goto exit;
366
367   /* If there is, is our client_index one of them */
368   clear_one_client (p[0], reg, item, client_index);
369
370 exit:
371   elts = 0;
372   /* Now check if that was the last item in any of the listened to stats */
373   for (i = 0; i < STATS_REG_N_IDX; i++)
374     {
375       elts += pool_elts (sm->stats_registrations[i]);
376     }
377   return elts;
378 }
379
380 static int
381 clear_client_for_all_stats (u32 client_index)
382 {
383   stats_main_t *sm = &stats_main;
384   u32 reg_index, item, reg;
385   int i, elts;
386
387   /* *INDENT-OFF* */
388   vec_foreach_index(reg, sm->stats_registration_hash)
389     {
390       hash_foreach(item, reg_index, sm->stats_registration_hash[reg],
391       ({
392         clear_one_client(reg_index, reg, item, client_index);
393       }));
394     }
395   /* *INDENT-OFF* */
396
397   elts = 0;
398   /* Now check if that was the last item in any of the listened to stats */
399   for (i = 0; i < STATS_REG_N_IDX; i++)
400     {
401       elts += pool_elts (sm->stats_registrations[i]);
402     }
403   return elts;
404 }
405
406 static clib_error_t *
407 want_stats_reaper (u32 client_index)
408 {
409   stats_main_t *sm = &stats_main;
410
411   sm->enable_poller = clear_client_for_all_stats (client_index);
412
413   return (NULL);
414 }
415
416 VL_MSG_API_REAPER_FUNCTION (want_stats_reaper);
417
418
419 /*
420  * Return a copy of the clients list.
421  */
422 vpe_client_registration_t *
423 get_clients_for_stat (u32 reg, u32 item)
424 {
425   stats_main_t *sm = &stats_main;
426   vpe_client_registration_t *client, *clients = 0;
427   vpe_client_stats_registration_t *registration;
428   uword *p;
429
430   /* Is there anything listening for item in that reg */
431   p = hash_get (sm->stats_registration_hash[reg], item);
432
433   if (!p)
434     return 0;                   // Fail
435
436   /* If there is, is our client_index one of them */
437   registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
438
439   vec_reset_length (clients);
440
441   /* *INDENT-OFF* */
442   pool_foreach (client, registration->clients,
443   ({
444     vec_add1 (clients, *client);}
445   ));
446   /* *INDENT-ON* */
447   return clients;
448 }
449
450
451 static void
452 clear_client_reg (u32 ** registrations)
453 {
454   /* When registrations[x] is a vector of pool indices
455      here is a good place to clean up the pools
456    */
457 #define stats_reg(n) vec_free(registrations[IDX_##n]);
458 #include <vpp/stats/stats.reg>
459 #undef stats_reg
460
461   vec_free (registrations);
462 }
463
464 u32 **
465 init_client_reg (u32 ** registrations)
466 {
467
468   /*
469      Initialise the stats registrations for each
470      type of stat a client can register for as well as
471      a vector of "interested" indexes.
472      Initially this is a u32 of either sw_if_index or fib_index
473      but eventually this should migrate to a pool_index (u32)
474      with a type specific pool that can include more complex things
475      such as timing and structured events.
476    */
477   vec_validate (registrations, STATS_REG_N_IDX);
478 #define stats_reg(n) \
479   vec_reset_length(registrations[IDX_##n]);
480 #include <vpp/stats/stats.reg>
481 #undef stats_reg
482
483   /*
484      When registrations[x] is a vector of pool indices, here
485      is a good place to init the pools.
486    */
487   return registrations;
488 }
489
490 u32 **
491 enable_all_client_reg (u32 ** registrations)
492 {
493
494   /*
495      Enable all stats known by adding
496      ~0 to the index vector. Eventually this
497      should be deprecated.
498    */
499 #define stats_reg(n)                            \
500   vec_add1(registrations[IDX_##n], ~0);
501 #include <vpp/stats/stats.reg>
502 #undef stats_reg
503   return registrations;
504 }
505
506 static void
507 do_simple_interface_counters (stats_main_t * sm)
508 {
509   vl_api_vnet_interface_simple_counters_t *mp = 0;
510   vnet_interface_main_t *im = sm->interface_main;
511   api_main_t *am = sm->api_main;
512   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
513   svm_queue_t *q = shmem_hdr->vl_input_queue;
514   vlib_simple_counter_main_t *cm;
515   u32 items_this_message = 0;
516   u64 v, *vp = 0;
517   int i, n_counts;
518
519   /*
520    * Prevent interface registration from expanding / moving the vectors...
521    * That tends never to happen, so we can hold this lock for a while.
522    */
523   vnet_interface_counter_lock (im);
524
525   vec_foreach (cm, im->sw_if_counters)
526   {
527     n_counts = vlib_simple_counter_n_counters (cm);
528     for (i = 0; i < n_counts; i++)
529       {
530         if (mp == 0)
531           {
532             items_this_message = clib_min (SIMPLE_COUNTER_BATCH_SIZE,
533                                            n_counts - i);
534
535             mp = vl_msg_api_alloc_as_if_client
536               (sizeof (*mp) + items_this_message * sizeof (v));
537             mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_SIMPLE_COUNTERS);
538             mp->vnet_counter_type = cm - im->sw_if_counters;
539             mp->first_sw_if_index = htonl (i);
540             mp->count = 0;
541             vp = (u64 *) mp->data;
542           }
543         v = vlib_get_simple_counter (cm, i);
544         clib_mem_unaligned (vp, u64) = clib_host_to_net_u64 (v);
545         vp++;
546         mp->count++;
547         if (mp->count == items_this_message)
548           {
549             mp->count = htonl (items_this_message);
550             /* Send to the main thread... */
551             vl_msg_api_send_shmem (q, (u8 *) & mp);
552             mp = 0;
553           }
554       }
555     ASSERT (mp == 0);
556   }
557   vnet_interface_counter_unlock (im);
558 }
559
560 void
561 handle_client_registration (vpe_client_registration_t * client, u32 stat,
562                             u32 item, int enable_disable)
563 {
564   stats_main_t *sm = &stats_main;
565   vpe_client_registration_t *rp, _rp;
566
567   rp = get_client_for_stat (stat, item, client->client_index);
568
569   /* Disable case */
570   if (enable_disable == 0)
571     {
572       if (!rp)                  // No client to disable
573         {
574           clib_warning ("pid %d: already disabled for stats...",
575                         client->client_pid);
576           return;
577         }
578       sm->enable_poller =
579         clear_client_for_stat (stat, item, client->client_index);
580       return;
581     }
582   /* Enable case */
583   if (!rp)
584     {
585       rp = &_rp;
586       rp->client_index = client->client_index;
587       rp->client_pid = client->client_pid;
588       sm->enable_poller = set_client_for_stat (stat, item, rp);
589     }
590 }
591
592
593 /**********************************
594  * ALL Interface Combined stats - to be deprecated
595  **********************************/
596
597 /*
598  * This API should be deprecated as _per_interface_ works with ~0 as sw_if_index.
599  */
600 static void
601   vl_api_want_interface_combined_stats_t_handler
602   (vl_api_want_interface_combined_stats_t * mp)
603 {
604   stats_main_t *sm = &stats_main;
605   vpe_client_registration_t rp;
606   vl_api_want_interface_combined_stats_reply_t *rmp;
607   uword *p;
608   i32 retval = 0;
609   vl_api_registration_t *reg;
610   u32 swif;
611
612   swif = ~0;                    //Using same mechanism as _per_interface_
613   rp.client_index = mp->client_index;
614   rp.client_pid = mp->pid;
615
616   handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
617                               mp->enable_disable);
618
619 reply:
620   reg = vl_api_client_index_to_registration (mp->client_index);
621   if (!reg)
622     {
623       sm->enable_poller =
624         clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
625                                mp->client_index);
626       return;
627     }
628
629   rmp = vl_msg_api_alloc (sizeof (*rmp));
630   rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_COMBINED_STATS_REPLY);
631   rmp->context = mp->context;
632   rmp->retval = retval;
633
634   vl_api_send_msg (reg, (u8 *) rmp);
635 }
636
637 static void
638   vl_api_vnet_interface_combined_counters_t_handler
639   (vl_api_vnet_interface_combined_counters_t * mp)
640 {
641   vpe_client_registration_t *clients, client;
642   stats_main_t *sm = &stats_main;
643   vl_api_registration_t *reg, *reg_prev = NULL;
644   vl_api_vnet_interface_combined_counters_t *mp_copy = NULL;
645   u32 mp_size;
646   int i;
647
648   mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (vlib_counter_t));
649
650   clients =
651     get_clients_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
652                           ~0 /*flag for all */ );
653
654   for (i = 0; i < vec_len (clients); i++)
655     {
656       client = clients[i];
657       reg = vl_api_client_index_to_registration (client.client_index);
658       if (reg)
659         {
660           if (reg_prev && vl_api_can_send_msg (reg_prev))
661             {
662               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
663               clib_memcpy (mp_copy, mp, mp_size);
664               vl_api_send_msg (reg_prev, (u8 *) mp);
665               mp = mp_copy;
666             }
667           reg_prev = reg;
668         }
669     }
670   vec_free (clients);
671 #if STATS_DEBUG > 0
672   fformat (stdout, "%U\n", format_vnet_combined_counters, mp);
673 #endif
674
675   if (reg_prev && vl_api_can_send_msg (reg_prev))
676     {
677       vl_api_send_msg (reg_prev, (u8 *) mp);
678     }
679   else
680     {
681       vl_msg_api_free (mp);
682     }
683 }
684
685 static void
686 do_combined_interface_counters (stats_main_t * sm)
687 {
688   vl_api_vnet_interface_combined_counters_t *mp = 0;
689   vnet_interface_main_t *im = sm->interface_main;
690   api_main_t *am = sm->api_main;
691   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
692   svm_queue_t *q = shmem_hdr->vl_input_queue;
693   vlib_combined_counter_main_t *cm;
694   u32 items_this_message = 0;
695   vlib_counter_t v, *vp = 0;
696   int i, n_counts;
697
698   vnet_interface_counter_lock (im);
699
700   vec_foreach (cm, im->combined_sw_if_counters)
701   {
702     n_counts = vlib_combined_counter_n_counters (cm);
703     for (i = 0; i < n_counts; i++)
704       {
705         if (mp == 0)
706           {
707             items_this_message = clib_min (COMBINED_COUNTER_BATCH_SIZE,
708                                            n_counts - i);
709
710             mp = vl_msg_api_alloc_as_if_client
711               (sizeof (*mp) + items_this_message * sizeof (v));
712             mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_COMBINED_COUNTERS);
713             mp->vnet_counter_type = cm - im->combined_sw_if_counters;
714             mp->first_sw_if_index = htonl (i);
715             mp->count = 0;
716             vp = (vlib_counter_t *) mp->data;
717           }
718         vlib_get_combined_counter (cm, i, &v);
719         clib_mem_unaligned (&vp->packets, u64)
720           = clib_host_to_net_u64 (v.packets);
721         clib_mem_unaligned (&vp->bytes, u64) = clib_host_to_net_u64 (v.bytes);
722         vp++;
723         mp->count++;
724         if (mp->count == items_this_message)
725           {
726             mp->count = htonl (items_this_message);
727             /* Send to the main thread... */
728             vl_msg_api_send_shmem (q, (u8 *) & mp);
729             mp = 0;
730           }
731       }
732     ASSERT (mp == 0);
733   }
734   vnet_interface_counter_unlock (im);
735 }
736
737 /**********************************
738  * Per Interface Combined stats
739  **********************************/
740
741 /* Request from client registering interfaces it wants */
742 static void
743   vl_api_want_per_interface_combined_stats_t_handler
744   (vl_api_want_per_interface_combined_stats_t * mp)
745 {
746   stats_main_t *sm = &stats_main;
747   vpe_client_registration_t rp;
748   vl_api_want_per_interface_combined_stats_reply_t *rmp;
749   vlib_combined_counter_main_t *cm;
750   uword *p;
751   i32 retval = 0;
752   vl_api_registration_t *reg;
753   u32 i, swif, num = 0;
754
755   num = ntohl (mp->num);
756
757   /*
758    * Validate sw_if_indexes before registering
759    */
760   for (i = 0; i < num; i++)
761     {
762       swif = ntohl (mp->sw_ifs[i]);
763
764       /*
765        * Check its a real sw_if_index that the client is allowed to see
766        */
767       if (swif != ~0)
768         {
769           if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
770             {
771               retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
772               goto reply;
773             }
774         }
775     }
776
777   for (i = 0; i < num; i++)
778     {
779       swif = ntohl (mp->sw_ifs[i]);
780
781       rp.client_index = mp->client_index;
782       rp.client_pid = mp->pid;
783       handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
784                                   swif, ntohl (mp->enable_disable));
785     }
786
787 reply:
788   reg = vl_api_client_index_to_registration (mp->client_index);
789   if (!reg)
790     {
791       for (i = 0; i < num; i++)
792         {
793           swif = ntohl (mp->sw_ifs[i]);
794
795           sm->enable_poller =
796             clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
797                                    mp->client_index);
798         }
799       return;
800     }
801
802   rmp = vl_msg_api_alloc (sizeof (*rmp));
803   rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_COMBINED_STATS_REPLY);
804   rmp->context = mp->context;
805   rmp->retval = retval;
806
807   vl_api_send_msg (reg, (u8 *) rmp);
808 }
809
810 /* Per Interface Combined distribution to client */
811 static void
812 do_combined_per_interface_counters (stats_main_t * sm)
813 {
814   vl_api_vnet_per_interface_combined_counters_t *mp = 0;
815   vnet_interface_main_t *im = sm->interface_main;
816   api_main_t *am = sm->api_main;
817   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
818   vl_api_registration_t *vl_reg;
819   vlib_combined_counter_main_t *cm;
820   vl_api_vnet_combined_counter_t *vp = 0;
821   vlib_counter_t v;
822   u32 i, j;
823   vpe_client_stats_registration_t *reg;
824   vpe_client_registration_t *client;
825   u32 *sw_if_index = 0;
826
827   vnet_interface_counter_lock (im);
828
829   vec_reset_length (sm->regs_tmp);
830
831   /* *INDENT-OFF* */
832   pool_foreach (reg,
833                 sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS],
834                 ({ vec_add1 (sm->regs_tmp, reg); }));
835   /* *INDENT-ON* */
836
837   for (i = 0; i < vec_len (sm->regs_tmp); i++)
838     {
839       reg = sm->regs_tmp[i];
840       if (reg->item == ~0)
841         {
842           vnet_interface_counter_unlock (im);
843           do_combined_interface_counters (sm);
844           vnet_interface_counter_lock (im);
845           continue;
846         }
847       vec_reset_length (sm->clients_tmp);
848
849       /* *INDENT-OFF* */
850       pool_foreach (client, reg->clients, ({ vec_add1 (sm->clients_tmp,
851                                                       client);}));
852       /* *INDENT-ON* */
853
854       for (j = 0; j < vec_len (sm->clients_tmp); j++)
855         {
856           client = sm->clients_tmp[j];
857
858           vl_reg = vl_api_client_index_to_registration (client->client_index);
859
860           //Client may have disconnected abrubtly, clean up so we don't poll nothing.
861           if (!vl_reg)
862             {
863               sm->enable_poller =
864                 clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
865                                        reg->item, client->client_index);
866               continue;
867             }
868           mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + sizeof (*vp));
869           memset (mp, 0, sizeof (*mp));
870
871           mp->_vl_msg_id =
872             ntohs (VL_API_VNET_PER_INTERFACE_COMBINED_COUNTERS);
873
874           /*
875            * count will eventually be used to optimise the batching
876            * of per client messages for each stat. For now setting this to 1 then
877            * iterate. This will not affect API.
878            *
879            * FIXME instead of enqueueing here, this should be sent to a batch
880            * storer for per-client transmission. Each "mp" sent would be a single entry
881            * and if a client is listening to other sw_if_indexes for same, it would be
882            * appended to that *mp
883            *
884            *
885            * FIXME(s):
886            * - capturing the timestamp of the counters "when VPP knew them" is important.
887            * Less so is that the timing of the delivery to the control plane be in the same
888            * timescale.
889
890            * i.e. As long as the control plane can delta messages from VPP and work out
891            * velocity etc based on the timestamp, it can do so in a more "batch mode".
892
893            * It would be beneficial to keep a "per-client" message queue, and then
894            * batch all the stat messages for a client into one message, with
895            * discrete timestamps.
896
897            * Given this particular API is for "per interface" one assumes that the scale
898            * is less than the ~0 case, which the prior API is suited for.
899            */
900
901           /*
902            * 1 message per api call for now
903            */
904           mp->count = htonl (1);
905           mp->timestamp = htonl (vlib_time_now (sm->vlib_main));
906
907           vp = (vl_api_vnet_combined_counter_t *) mp->data;
908           vp->sw_if_index = htonl (reg->item);
909
910           im = &vnet_get_main ()->interface_main;
911
912 #define _(X, x)                  \
913           cm = im->combined_sw_if_counters + X; \
914           vlib_get_combined_counter (cm, reg->item, &v); \
915           clib_mem_unaligned (&vp->x##_packets, u64) = \
916             clib_host_to_net_u64 (v.packets); \
917           clib_mem_unaligned (&vp->x##_bytes, u64) = \
918             clib_host_to_net_u64 (v.bytes);
919
920
921           _(VNET_INTERFACE_COUNTER_RX, rx);
922           _(VNET_INTERFACE_COUNTER_TX, tx);
923           _(VNET_INTERFACE_COUNTER_RX_UNICAST, rx_unicast);
924           _(VNET_INTERFACE_COUNTER_TX_UNICAST, tx_unicast);
925           _(VNET_INTERFACE_COUNTER_RX_MULTICAST, rx_multicast);
926           _(VNET_INTERFACE_COUNTER_TX_MULTICAST, tx_multicast);
927           _(VNET_INTERFACE_COUNTER_RX_BROADCAST, rx_broadcast);
928           _(VNET_INTERFACE_COUNTER_TX_BROADCAST, tx_broadcast);
929
930 #undef _
931
932           vl_api_send_msg (vl_reg, (u8 *) mp);
933         }
934     }
935
936   vnet_interface_counter_unlock (im);
937 }
938
939 /**********************************
940  * Per Interface simple stats
941  **********************************/
942
943 /* Request from client registering interfaces it wants */
944 static void
945   vl_api_want_per_interface_simple_stats_t_handler
946   (vl_api_want_per_interface_simple_stats_t * mp)
947 {
948   stats_main_t *sm = &stats_main;
949   vpe_client_registration_t rp;
950   vl_api_want_per_interface_simple_stats_reply_t *rmp;
951   vlib_simple_counter_main_t *cm;
952   uword *p;
953   i32 retval = 0;
954   vl_api_registration_t *reg;
955   u32 i, swif, num = 0;
956
957   num = ntohl (mp->num);
958
959   for (i = 0; i < num; i++)
960     {
961       swif = ntohl (mp->sw_ifs[i]);
962
963       /* Check its a real sw_if_index that the client is allowed to see */
964       if (swif != ~0)
965         {
966           if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
967             {
968               retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
969               goto reply;
970             }
971         }
972     }
973
974   for (i = 0; i < num; i++)
975     {
976       swif = ntohl (mp->sw_ifs[i]);
977
978       rp.client_index = mp->client_index;
979       rp.client_pid = mp->pid;
980       handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
981                                   swif, ntohl (mp->enable_disable));
982     }
983
984 reply:
985   reg = vl_api_client_index_to_registration (mp->client_index);
986
987   /* Client may have disconnected abruptly, clean up */
988   if (!reg)
989     {
990       for (i = 0; i < num; i++)
991         {
992           swif = ntohl (mp->sw_ifs[i]);
993           sm->enable_poller =
994             clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
995                                    mp->client_index);
996         }
997
998       return;
999     }
1000
1001
1002   rmp = vl_msg_api_alloc (sizeof (*rmp));
1003   rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
1004   rmp->context = mp->context;
1005   rmp->retval = retval;
1006
1007   vl_api_send_msg (reg, (u8 *) rmp);
1008 }
1009
1010 /* Per Interface Simple distribution to client */
1011 static void
1012 do_simple_per_interface_counters (stats_main_t * sm)
1013 {
1014   vl_api_vnet_per_interface_simple_counters_t *mp = 0;
1015   vnet_interface_main_t *im = sm->interface_main;
1016   api_main_t *am = sm->api_main;
1017   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1018   vl_api_registration_t *vl_reg;
1019   vlib_simple_counter_main_t *cm;
1020   u32 i, j, size;
1021   vpe_client_stats_registration_t *reg;
1022   vpe_client_registration_t *client;
1023   u32 timestamp, count;
1024   vl_api_vnet_simple_counter_t *vp = 0;
1025   counter_t v;
1026
1027   vnet_interface_counter_lock (im);
1028
1029   vec_reset_length (sm->regs_tmp);
1030
1031   /* *INDENT-OFF* */
1032   pool_foreach (reg,
1033                 sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS],
1034                 ({ vec_add1 (sm->regs_tmp, reg); }));
1035   /* *INDENT-ON* */
1036
1037   for (i = 0; i < vec_len (sm->regs_tmp); i++)
1038     {
1039       reg = sm->regs_tmp[i];
1040       if (reg->item == ~0)
1041         {
1042           vnet_interface_counter_unlock (im);
1043           do_simple_interface_counters (sm);
1044           vnet_interface_counter_lock (im);
1045           continue;
1046         }
1047       vec_reset_length (sm->clients_tmp);
1048
1049       /* *INDENT-OFF* */
1050       pool_foreach (client, reg->clients, ({ vec_add1 (sm->clients_tmp,
1051                                                       client);}));
1052       /* *INDENT-ON* */
1053
1054       for (j = 0; j < vec_len (sm->clients_tmp); j++)
1055         {
1056           client = sm->clients_tmp[j];
1057           vl_reg = vl_api_client_index_to_registration (client->client_index);
1058
1059           /* Client may have disconnected abrubtly, clean up */
1060           if (!vl_reg)
1061             {
1062               sm->enable_poller =
1063                 clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
1064                                        reg->item, client->client_index);
1065               continue;
1066             }
1067
1068           mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + sizeof (*vp));
1069           memset (mp, 0, sizeof (*mp));
1070           mp->_vl_msg_id = ntohs (VL_API_VNET_PER_INTERFACE_SIMPLE_COUNTERS);
1071
1072           /*
1073            * count will eventually be used to optimise the batching
1074            * of per client messages for each stat. For now setting this to 1 then
1075            * iterate. This will not affect API.
1076            *
1077            * FIXME instead of enqueueing here, this should be sent to a batch
1078            * storer for per-client transmission. Each "mp" sent would be a single entry
1079            * and if a client is listening to other sw_if_indexes for same, it would be
1080            * appended to that *mp
1081            *
1082            *
1083            * FIXME(s):
1084            * - capturing the timestamp of the counters "when VPP knew them" is important.
1085            * Less so is that the timing of the delivery to the control plane be in the same
1086            * timescale.
1087
1088            * i.e. As long as the control plane can delta messages from VPP and work out
1089            * velocity etc based on the timestamp, it can do so in a more "batch mode".
1090
1091            * It would be beneficial to keep a "per-client" message queue, and then
1092            * batch all the stat messages for a client into one message, with
1093            * discrete timestamps.
1094
1095            * Given this particular API is for "per interface" one assumes that the scale
1096            * is less than the ~0 case, which the prior API is suited for.
1097            */
1098
1099           /*
1100            * 1 message per api call for now
1101            */
1102           mp->count = htonl (1);
1103           mp->timestamp = htonl (vlib_time_now (sm->vlib_main));
1104           vp = (vl_api_vnet_simple_counter_t *) mp->data;
1105
1106           vp->sw_if_index = htonl (reg->item);
1107
1108           // VNET_INTERFACE_COUNTER_DROP
1109           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
1110           v = vlib_get_simple_counter (cm, reg->item);
1111           clib_mem_unaligned (&vp->drop, u64) = clib_host_to_net_u64 (v);
1112
1113           // VNET_INTERFACE_COUNTER_PUNT
1114           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_PUNT;
1115           v = vlib_get_simple_counter (cm, reg->item);
1116           clib_mem_unaligned (&vp->punt, u64) = clib_host_to_net_u64 (v);
1117
1118           // VNET_INTERFACE_COUNTER_IP4
1119           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP4;
1120           v = vlib_get_simple_counter (cm, reg->item);
1121           clib_mem_unaligned (&vp->rx_ip4, u64) = clib_host_to_net_u64 (v);
1122
1123           //VNET_INTERFACE_COUNTER_IP6
1124           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP6;
1125           v = vlib_get_simple_counter (cm, reg->item);
1126           clib_mem_unaligned (&vp->rx_ip6, u64) = clib_host_to_net_u64 (v);
1127
1128           //VNET_INTERFACE_COUNTER_RX_NO_BUF
1129           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_NO_BUF;
1130           v = vlib_get_simple_counter (cm, reg->item);
1131           clib_mem_unaligned (&vp->rx_no_buffer, u64) =
1132             clib_host_to_net_u64 (v);
1133
1134           //VNET_INTERFACE_COUNTER_RX_MISS
1135           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_MISS;
1136           v = vlib_get_simple_counter (cm, reg->item);
1137           clib_mem_unaligned (&vp->rx_miss, u64) = clib_host_to_net_u64 (v);
1138
1139           //VNET_INTERFACE_COUNTER_RX_ERROR
1140           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_ERROR;
1141           v = vlib_get_simple_counter (cm, reg->item);
1142           clib_mem_unaligned (&vp->rx_error, u64) = clib_host_to_net_u64 (v);
1143
1144           //VNET_INTERFACE_COUNTER_TX_ERROR
1145           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_TX_ERROR;
1146           v = vlib_get_simple_counter (cm, reg->item);
1147           clib_mem_unaligned (&vp->tx_error, u64) = clib_host_to_net_u64 (v);
1148
1149           //VNET_INTERFACE_COUNTER_MPLS
1150           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_MPLS;
1151           v = vlib_get_simple_counter (cm, reg->item);
1152           clib_mem_unaligned (&vp->rx_mpls, u64) = clib_host_to_net_u64 (v);
1153
1154           vl_api_send_msg (vl_reg, (u8 *) mp);
1155         }
1156     }
1157
1158   vnet_interface_counter_unlock (im);
1159 }
1160
1161 /**********************************
1162  * Per FIB IP4 stats
1163  **********************************/
1164
1165 static void
1166 ip46_fib_stats_delay (stats_main_t * sm, u32 sec, u32 nsec)
1167 {
1168   struct timespec _req, *req = &_req;
1169   struct timespec _rem, *rem = &_rem;
1170
1171   req->tv_sec = sec;
1172   req->tv_nsec = nsec;
1173   while (1)
1174     {
1175       if (nanosleep (req, rem) == 0)
1176         break;
1177       *req = *rem;
1178       if (errno == EINTR)
1179         continue;
1180       clib_unix_warning ("nanosleep");
1181       break;
1182     }
1183 }
1184
1185 /**
1186  * @brief The context passed when collecting adjacency counters
1187  */
1188 typedef struct ip4_nbr_stats_ctx_t_
1189 {
1190   /**
1191    * The SW IF index all these adjs belong to
1192    */
1193   u32 sw_if_index;
1194
1195   /**
1196    * A vector of ip4 nbr counters
1197    */
1198   vl_api_ip4_nbr_counter_t *counters;
1199 } ip4_nbr_stats_ctx_t;
1200
1201 static adj_walk_rc_t
1202 ip4_nbr_stats_cb (adj_index_t ai, void *arg)
1203 {
1204   vl_api_ip4_nbr_counter_t *vl_counter;
1205   vlib_counter_t adj_counter;
1206   ip4_nbr_stats_ctx_t *ctx;
1207   ip_adjacency_t *adj;
1208
1209   ctx = arg;
1210   vlib_get_combined_counter (&adjacency_counters, ai, &adj_counter);
1211
1212   if (0 != adj_counter.packets)
1213     {
1214       vec_add2 (ctx->counters, vl_counter, 1);
1215       adj = adj_get (ai);
1216
1217       vl_counter->packets = clib_host_to_net_u64 (adj_counter.packets);
1218       vl_counter->bytes = clib_host_to_net_u64 (adj_counter.bytes);
1219       vl_counter->address = adj->sub_type.nbr.next_hop.ip4.as_u32;
1220       vl_counter->link_type = adj->ia_link;
1221     }
1222   return (ADJ_WALK_RC_CONTINUE);
1223 }
1224
1225 #define MIN(x,y) (((x)<(y))?(x):(y))
1226
1227 static void
1228 ip4_nbr_ship (stats_main_t * sm, ip4_nbr_stats_ctx_t * ctx)
1229 {
1230   api_main_t *am = sm->api_main;
1231   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1232   svm_queue_t *q = shmem_hdr->vl_input_queue;
1233   vl_api_vnet_ip4_nbr_counters_t *mp = 0;
1234   int first = 0;
1235
1236   /*
1237    * If the walk context has counters, which may be left over from the last
1238    * suspend, then we continue from there.
1239    */
1240   while (0 != vec_len (ctx->counters))
1241     {
1242       u32 n_items = MIN (vec_len (ctx->counters),
1243                          IP4_FIB_COUNTER_BATCH_SIZE);
1244       u8 pause = 0;
1245
1246       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1247
1248       mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
1249                                           (n_items *
1250                                            sizeof
1251                                            (vl_api_ip4_nbr_counter_t)));
1252       mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_NBR_COUNTERS);
1253       mp->count = ntohl (n_items);
1254       mp->sw_if_index = ntohl (ctx->sw_if_index);
1255       mp->begin = first;
1256       first = 0;
1257
1258       /*
1259        * copy the counters from the back of the context, then we can easily
1260        * 'erase' them by resetting the vector length.
1261        * The order we push the stats to the caller is not important.
1262        */
1263       clib_memcpy (mp->c,
1264                    &ctx->counters[vec_len (ctx->counters) - n_items],
1265                    n_items * sizeof (*ctx->counters));
1266
1267       _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
1268
1269       /*
1270        * send to the shm q
1271        */
1272       svm_queue_lock (q);
1273       pause = svm_queue_is_full (q);
1274
1275       vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1276       svm_queue_unlock (q);
1277       dsunlock (sm);
1278
1279       if (pause)
1280         ip46_fib_stats_delay (sm, 0 /* sec */ ,
1281                               STATS_RELEASE_DELAY_NS);
1282     }
1283 }
1284
1285 static void
1286 do_ip4_nbr_counters (stats_main_t * sm)
1287 {
1288   vnet_main_t *vnm = vnet_get_main ();
1289   vnet_interface_main_t *im = &vnm->interface_main;
1290   vnet_sw_interface_t *si;
1291
1292   ip4_nbr_stats_ctx_t ctx = {
1293     .sw_if_index = 0,
1294     .counters = NULL,
1295   };
1296
1297   /* *INDENT-OFF* */
1298   pool_foreach (si, im->sw_interfaces,
1299   ({
1300     /*
1301      * update the interface we are now concerned with
1302      */
1303     ctx.sw_if_index = si->sw_if_index;
1304
1305     /*
1306      * we are about to walk another interface, so we shouldn't have any pending
1307      * stats to export.
1308      */
1309     ASSERT(ctx.counters == NULL);
1310
1311     /*
1312      * visit each neighbour adjacency on the interface and collect
1313      * its current stats.
1314      * Because we hold the lock the walk is synchronous, so safe to routing
1315      * updates. It's limited in work by the number of adjacenies on an
1316      * interface, which is typically not huge.
1317      */
1318     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1319     adj_nbr_walk (si->sw_if_index,
1320                   FIB_PROTOCOL_IP4,
1321                   ip4_nbr_stats_cb,
1322                   &ctx);
1323     dsunlock (sm);
1324
1325     /*
1326      * if this interface has some adjacencies with counters then ship them,
1327      * else continue to the next interface.
1328      */
1329     if (NULL != ctx.counters)
1330       {
1331         ip4_nbr_ship(sm, &ctx);
1332       }
1333   }));
1334   /* *INDENT-OFF* */
1335 }
1336
1337 /**
1338  * @brief The context passed when collecting adjacency counters
1339  */
1340 typedef struct ip6_nbr_stats_ctx_t_
1341 {
1342   /**
1343    * The SW IF index all these adjs belong to
1344    */
1345   u32 sw_if_index;
1346
1347   /**
1348    * A vector of ip6 nbr counters
1349    */
1350   vl_api_ip6_nbr_counter_t *counters;
1351 } ip6_nbr_stats_ctx_t;
1352
1353 static adj_walk_rc_t
1354 ip6_nbr_stats_cb (adj_index_t ai,
1355                   void *arg)
1356 {
1357   vl_api_ip6_nbr_counter_t *vl_counter;
1358   vlib_counter_t adj_counter;
1359   ip6_nbr_stats_ctx_t *ctx;
1360   ip_adjacency_t *adj;
1361
1362   ctx = arg;
1363   vlib_get_combined_counter(&adjacency_counters, ai, &adj_counter);
1364
1365   if (0 != adj_counter.packets)
1366     {
1367       vec_add2(ctx->counters, vl_counter, 1);
1368       adj = adj_get(ai);
1369
1370       vl_counter->packets = clib_host_to_net_u64(adj_counter.packets);
1371       vl_counter->bytes   = clib_host_to_net_u64(adj_counter.bytes);
1372       vl_counter->address[0] = adj->sub_type.nbr.next_hop.ip6.as_u64[0];
1373       vl_counter->address[1] = adj->sub_type.nbr.next_hop.ip6.as_u64[1];
1374       vl_counter->link_type = adj->ia_link;
1375     }
1376   return (ADJ_WALK_RC_CONTINUE);
1377 }
1378
1379 #define MIN(x,y) (((x)<(y))?(x):(y))
1380
1381 static void
1382 ip6_nbr_ship (stats_main_t * sm,
1383               ip6_nbr_stats_ctx_t *ctx)
1384 {
1385   api_main_t *am = sm->api_main;
1386   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1387   svm_queue_t *q = shmem_hdr->vl_input_queue;
1388   vl_api_vnet_ip6_nbr_counters_t *mp = 0;
1389   int first = 0;
1390
1391   /*
1392    * If the walk context has counters, which may be left over from the last
1393    * suspend, then we continue from there.
1394    */
1395   while (0 != vec_len(ctx->counters))
1396     {
1397       u32 n_items = MIN (vec_len (ctx->counters),
1398                          IP6_FIB_COUNTER_BATCH_SIZE);
1399       u8 pause = 0;
1400
1401       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1402
1403       mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
1404                                           (n_items *
1405                                            sizeof
1406                                            (vl_api_ip6_nbr_counter_t)));
1407       mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_NBR_COUNTERS);
1408       mp->count = ntohl (n_items);
1409       mp->sw_if_index = ntohl (ctx->sw_if_index);
1410       mp->begin = first;
1411       first = 0;
1412
1413       /*
1414        * copy the counters from the back of the context, then we can easily
1415        * 'erase' them by resetting the vector length.
1416        * The order we push the stats to the caller is not important.
1417        */
1418       clib_memcpy (mp->c,
1419                    &ctx->counters[vec_len (ctx->counters) - n_items],
1420                    n_items * sizeof (*ctx->counters));
1421
1422       _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
1423
1424       /*
1425        * send to the shm q
1426        */
1427       svm_queue_lock (q);
1428       pause = svm_queue_is_full (q);
1429
1430       vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1431       svm_queue_unlock (q);
1432       dsunlock (sm);
1433
1434       if (pause)
1435         ip46_fib_stats_delay (sm, 0 /* sec */ ,
1436                               STATS_RELEASE_DELAY_NS);
1437     }
1438 }
1439
1440 static void
1441 do_ip6_nbr_counters (stats_main_t * sm)
1442 {
1443   vnet_main_t *vnm = vnet_get_main ();
1444   vnet_interface_main_t *im = &vnm->interface_main;
1445   vnet_sw_interface_t *si;
1446
1447   ip6_nbr_stats_ctx_t ctx = {
1448     .sw_if_index = 0,
1449     .counters = NULL,
1450   };
1451
1452   /* *INDENT-OFF* */
1453   pool_foreach (si, im->sw_interfaces,
1454   ({
1455     /*
1456      * update the interface we are now concerned with
1457      */
1458     ctx.sw_if_index = si->sw_if_index;
1459
1460     /*
1461      * we are about to walk another interface, so we shouldn't have any pending
1462      * stats to export.
1463      */
1464     ASSERT(ctx.counters == NULL);
1465
1466     /*
1467      * visit each neighbour adjacency on the interface and collect
1468      * its current stats.
1469      * Because we hold the lock the walk is synchronous, so safe to routing
1470      * updates. It's limited in work by the number of adjacenies on an
1471      * interface, which is typically not huge.
1472      */
1473     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1474     adj_nbr_walk (si->sw_if_index,
1475                   FIB_PROTOCOL_IP6,
1476                   ip6_nbr_stats_cb,
1477                   &ctx);
1478     dsunlock (sm);
1479
1480     /*
1481      * if this interface has some adjacencies with counters then ship them,
1482      * else continue to the next interface.
1483      */
1484     if (NULL != ctx.counters)
1485       {
1486         ip6_nbr_ship(sm, &ctx);
1487       }
1488   }));
1489   /* *INDENT-OFF* */
1490 }
1491
1492 static void
1493 do_ip4_fib_counters (stats_main_t * sm)
1494 {
1495   ip4_main_t *im4 = &ip4_main;
1496   api_main_t *am = sm->api_main;
1497   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1498   svm_queue_t *q = shmem_hdr->vl_input_queue;
1499   ip4_route_t *r;
1500   fib_table_t *fib;
1501   ip4_fib_t *v4_fib;
1502   do_ip46_fibs_t *do_fibs;
1503   vl_api_vnet_ip4_fib_counters_t *mp = 0;
1504   u32 items_this_message;
1505   vl_api_ip4_fib_counter_t *ctrp = 0;
1506   u32 start_at_fib_index = 0;
1507   int i, j, k;
1508
1509   do_fibs = &sm->do_ip46_fibs;
1510
1511 again:
1512   vec_reset_length (do_fibs->fibs);
1513   /* *INDENT-OFF* */
1514   pool_foreach (fib, im4->fibs,
1515                 ({vec_add1(do_fibs->fibs,fib);}));
1516
1517   /* *INDENT-ON* */
1518
1519   for (j = 0; j < vec_len (do_fibs->fibs); j++)
1520     {
1521       fib = do_fibs->fibs[j];
1522       /* We may have bailed out due to control-plane activity */
1523       while ((fib - im4->fibs) < start_at_fib_index)
1524         continue;
1525
1526       v4_fib = pool_elt_at_index (im4->v4_fibs, fib->ft_index);
1527
1528       if (mp == 0)
1529         {
1530           items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
1531           mp = vl_msg_api_alloc_as_if_client
1532             (sizeof (*mp) +
1533              items_this_message * sizeof (vl_api_ip4_fib_counter_t));
1534           mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
1535           mp->count = 0;
1536           mp->vrf_id = ntohl (fib->ft_table_id);
1537           ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1538         }
1539       else
1540         {
1541           /* happens if the last FIB was empty... */
1542           ASSERT (mp->count == 0);
1543           mp->vrf_id = ntohl (fib->ft_table_id);
1544         }
1545
1546       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1547
1548       vec_reset_length (do_fibs->ip4routes);
1549       vec_reset_length (do_fibs->results);
1550
1551       for (i = 0; i < ARRAY_LEN (v4_fib->fib_entry_by_dst_address); i++)
1552         {
1553           uword *hash = v4_fib->fib_entry_by_dst_address[i];
1554           hash_pair_t *p;
1555           ip4_route_t x;
1556
1557           vec_reset_length (do_fibs->pvec);
1558
1559           x.address_length = i;
1560
1561           hash_foreach_pair (p, hash, (
1562                                         {
1563                                         vec_add1 (do_fibs->pvec, p);}
1564                              ));
1565           for (k = 0; k < vec_len (do_fibs->pvec); k++)
1566             {
1567               p = do_fibs->pvec[k];
1568               x.address.data_u32 = p->key;
1569               x.index = p->value[0];
1570
1571               vec_add1 (do_fibs->ip4routes, x);
1572               if (sm->data_structure_lock->release_hint)
1573                 {
1574                   start_at_fib_index = fib - im4->fibs;
1575                   dsunlock (sm);
1576                   ip46_fib_stats_delay (sm, 0 /* sec */ ,
1577                                         STATS_RELEASE_DELAY_NS);
1578                   mp->count = 0;
1579                   ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1580                   goto again;
1581                 }
1582             }
1583         }
1584
1585       vec_foreach (r, do_fibs->ip4routes)
1586       {
1587         vlib_counter_t c;
1588         const dpo_id_t *dpo_id;
1589         u32 index;
1590
1591         dpo_id = fib_entry_contribute_ip_forwarding (r->index);
1592         index = (u32) dpo_id->dpoi_index;
1593
1594         vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
1595                                    index, &c);
1596         /*
1597          * If it has actually
1598          * seen at least one packet, send it.
1599          */
1600         if (c.packets > 0)
1601           {
1602
1603             /* already in net byte order */
1604             ctrp->address = r->address.as_u32;
1605             ctrp->address_length = r->address_length;
1606             ctrp->packets = clib_host_to_net_u64 (c.packets);
1607             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1608             mp->count++;
1609             ctrp++;
1610
1611             if (mp->count == items_this_message)
1612               {
1613                 mp->count = htonl (items_this_message);
1614                 /*
1615                  * If the main thread's input queue is stuffed,
1616                  * drop the data structure lock (which the main thread
1617                  * may want), and take a pause.
1618                  */
1619                 svm_queue_lock (q);
1620                 if (svm_queue_is_full (q))
1621                   {
1622                     dsunlock (sm);
1623                     vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1624                     svm_queue_unlock (q);
1625                     mp = 0;
1626                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
1627                                           STATS_RELEASE_DELAY_NS);
1628                     goto again;
1629                   }
1630                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1631                 svm_queue_unlock (q);
1632
1633                 items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
1634                 mp = vl_msg_api_alloc_as_if_client
1635                   (sizeof (*mp) +
1636                    items_this_message * sizeof (vl_api_ip4_fib_counter_t));
1637                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
1638                 mp->count = 0;
1639                 mp->vrf_id = ntohl (fib->ft_table_id);
1640                 ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1641               }
1642           }                     /* for each (mp or single) adj */
1643         if (sm->data_structure_lock->release_hint)
1644           {
1645             start_at_fib_index = fib - im4->fibs;
1646             dsunlock (sm);
1647             ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
1648             mp->count = 0;
1649             ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1650             goto again;
1651           }
1652       }                         /* vec_foreach (routes) */
1653
1654       dsunlock (sm);
1655
1656       /* Flush any data from this fib */
1657       if (mp->count)
1658         {
1659           mp->count = htonl (mp->count);
1660           vl_msg_api_send_shmem (q, (u8 *) & mp);
1661           mp = 0;
1662         }
1663     }
1664
1665   /* If e.g. the last FIB had no reportable routes, free the buffer */
1666   if (mp)
1667     vl_msg_api_free (mp);
1668 }
1669
1670 static int
1671 mfib_table_stats_walk_cb (fib_node_index_t fei, void *ctx)
1672 {
1673   stats_main_t *sm = ctx;
1674   do_ip46_fibs_t *do_fibs;
1675   mfib_entry_t *entry;
1676
1677   do_fibs = &sm->do_ip46_fibs;
1678   entry = mfib_entry_get (fei);
1679
1680   vec_add1 (do_fibs->mroutes, entry->mfe_prefix);
1681
1682   return (1);
1683 }
1684
1685 static void
1686 do_ip4_mfib_counters (stats_main_t * sm)
1687 {
1688   ip4_main_t *im4 = &ip4_main;
1689   api_main_t *am = sm->api_main;
1690   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1691   svm_queue_t *q = shmem_hdr->vl_input_queue;
1692   mfib_prefix_t *pfx;
1693   mfib_table_t *mfib;
1694   do_ip46_fibs_t *do_fibs;
1695   vl_api_vnet_ip4_mfib_counters_t *mp = 0;
1696   u32 items_this_message;
1697   vl_api_ip4_mfib_counter_t *ctrp = 0;
1698   u32 start_at_mfib_index = 0;
1699   int i, j, k;
1700
1701   do_fibs = &sm->do_ip46_fibs;
1702
1703   vec_reset_length (do_fibs->mfibs);
1704   /* *INDENT-OFF* */
1705   pool_foreach (mfib, im4->mfibs, ({vec_add1(do_fibs->mfibs, mfib);}));
1706   /* *INDENT-ON* */
1707
1708   for (j = 0; j < vec_len (do_fibs->mfibs); j++)
1709     {
1710       mfib = do_fibs->mfibs[j];
1711       /* We may have bailed out due to control-plane activity */
1712       while ((mfib - im4->mfibs) < start_at_mfib_index)
1713         continue;
1714
1715       if (mp == 0)
1716         {
1717           items_this_message = IP4_MFIB_COUNTER_BATCH_SIZE;
1718           mp = vl_msg_api_alloc_as_if_client
1719             (sizeof (*mp) +
1720              items_this_message * sizeof (vl_api_ip4_mfib_counter_t));
1721           mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_MFIB_COUNTERS);
1722           mp->count = 0;
1723           mp->vrf_id = ntohl (mfib->mft_table_id);
1724           ctrp = (vl_api_ip4_mfib_counter_t *) mp->c;
1725         }
1726       else
1727         {
1728           /* happens if the last MFIB was empty... */
1729           ASSERT (mp->count == 0);
1730           mp->vrf_id = ntohl (mfib->mft_table_id);
1731         }
1732
1733       vec_reset_length (do_fibs->mroutes);
1734
1735       /*
1736        * walk the table with table updates blocked
1737        */
1738       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1739
1740       mfib_table_walk (mfib->mft_index,
1741                        FIB_PROTOCOL_IP4, mfib_table_stats_walk_cb, sm);
1742       dsunlock (sm);
1743
1744       vec_foreach (pfx, do_fibs->mroutes)
1745       {
1746         const dpo_id_t *dpo_id;
1747         fib_node_index_t mfei;
1748         vlib_counter_t c;
1749         u32 index;
1750
1751         /*
1752          * re-lookup the entry, since we suspend during the collection
1753          */
1754         mfei = mfib_table_lookup (mfib->mft_index, pfx);
1755
1756         if (FIB_NODE_INDEX_INVALID == mfei)
1757           continue;
1758
1759         dpo_id = mfib_entry_contribute_ip_forwarding (mfei);
1760         index = (u32) dpo_id->dpoi_index;
1761
1762         vlib_get_combined_counter (&replicate_main.repm_counters,
1763                                    dpo_id->dpoi_index, &c);
1764         /*
1765          * If it has seen at least one packet, send it.
1766          */
1767         if (c.packets > 0)
1768           {
1769             /* already in net byte order */
1770             memcpy (ctrp->group, &pfx->fp_grp_addr.ip4, 4);
1771             memcpy (ctrp->source, &pfx->fp_src_addr.ip4, 4);
1772             ctrp->group_length = pfx->fp_len;
1773             ctrp->packets = clib_host_to_net_u64 (c.packets);
1774             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1775             mp->count++;
1776             ctrp++;
1777
1778             if (mp->count == items_this_message)
1779               {
1780                 mp->count = htonl (items_this_message);
1781                 /*
1782                  * If the main thread's input queue is stuffed,
1783                  * drop the data structure lock (which the main thread
1784                  * may want), and take a pause.
1785                  */
1786                 svm_queue_lock (q);
1787
1788                 while (svm_queue_is_full (q))
1789                   {
1790                     svm_queue_unlock (q);
1791                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
1792                                           STATS_RELEASE_DELAY_NS);
1793                     svm_queue_lock (q);
1794                   }
1795                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1796                 svm_queue_unlock (q);
1797
1798                 items_this_message = IP4_MFIB_COUNTER_BATCH_SIZE;
1799                 mp = vl_msg_api_alloc_as_if_client
1800                   (sizeof (*mp) +
1801                    items_this_message * sizeof (vl_api_ip4_mfib_counter_t));
1802                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_MFIB_COUNTERS);
1803                 mp->count = 0;
1804                 mp->vrf_id = ntohl (mfib->mft_table_id);
1805                 ctrp = (vl_api_ip4_mfib_counter_t *) mp->c;
1806               }
1807           }
1808       }
1809
1810       /* Flush any data from this mfib */
1811       if (mp->count)
1812         {
1813           mp->count = htonl (mp->count);
1814           vl_msg_api_send_shmem (q, (u8 *) & mp);
1815           mp = 0;
1816         }
1817     }
1818
1819   /* If e.g. the last FIB had no reportable routes, free the buffer */
1820   if (mp)
1821     vl_msg_api_free (mp);
1822 }
1823
1824 static void
1825 do_ip6_mfib_counters (stats_main_t * sm)
1826 {
1827   ip6_main_t *im6 = &ip6_main;
1828   api_main_t *am = sm->api_main;
1829   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1830   svm_queue_t *q = shmem_hdr->vl_input_queue;
1831   mfib_prefix_t *pfx;
1832   mfib_table_t *mfib;
1833   do_ip46_fibs_t *do_fibs;
1834   vl_api_vnet_ip6_mfib_counters_t *mp = 0;
1835   u32 items_this_message;
1836   vl_api_ip6_mfib_counter_t *ctrp = 0;
1837   u32 start_at_mfib_index = 0;
1838   int i, j, k;
1839
1840   do_fibs = &sm->do_ip46_fibs;
1841
1842   vec_reset_length (do_fibs->mfibs);
1843   /* *INDENT-OFF* */
1844   pool_foreach (mfib, im6->mfibs, ({vec_add1(do_fibs->mfibs, mfib);}));
1845   /* *INDENT-ON* */
1846
1847   for (j = 0; j < vec_len (do_fibs->mfibs); j++)
1848     {
1849       mfib = do_fibs->mfibs[j];
1850       /* We may have bailed out due to control-plane activity */
1851       while ((mfib - im6->mfibs) < start_at_mfib_index)
1852         continue;
1853
1854       if (mp == 0)
1855         {
1856           items_this_message = IP6_MFIB_COUNTER_BATCH_SIZE;
1857           mp = vl_msg_api_alloc_as_if_client
1858             (sizeof (*mp) +
1859              items_this_message * sizeof (vl_api_ip6_mfib_counter_t));
1860           mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_MFIB_COUNTERS);
1861           mp->count = 0;
1862           mp->vrf_id = ntohl (mfib->mft_table_id);
1863           ctrp = (vl_api_ip6_mfib_counter_t *) mp->c;
1864         }
1865       else
1866         {
1867           /* happens if the last MFIB was empty... */
1868           ASSERT (mp->count == 0);
1869           mp->vrf_id = ntohl (mfib->mft_table_id);
1870         }
1871
1872       vec_reset_length (do_fibs->mroutes);
1873
1874       /*
1875        * walk the table with table updates blocked
1876        */
1877       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1878
1879       mfib_table_walk (mfib->mft_index,
1880                        FIB_PROTOCOL_IP6, mfib_table_stats_walk_cb, sm);
1881       dsunlock (sm);
1882
1883       vec_foreach (pfx, do_fibs->mroutes)
1884       {
1885         const dpo_id_t *dpo_id;
1886         fib_node_index_t mfei;
1887         vlib_counter_t c;
1888         u32 index;
1889
1890         /*
1891          * re-lookup the entry, since we suspend during the collection
1892          */
1893         mfei = mfib_table_lookup (mfib->mft_index, pfx);
1894
1895         if (FIB_NODE_INDEX_INVALID == mfei)
1896           continue;
1897
1898         dpo_id = mfib_entry_contribute_ip_forwarding (mfei);
1899         index = (u32) dpo_id->dpoi_index;
1900
1901         vlib_get_combined_counter (&replicate_main.repm_counters,
1902                                    dpo_id->dpoi_index, &c);
1903         /*
1904          * If it has seen at least one packet, send it.
1905          */
1906         if (c.packets > 0)
1907           {
1908             /* already in net byte order */
1909             memcpy (ctrp->group, &pfx->fp_grp_addr.ip6, 16);
1910             memcpy (ctrp->source, &pfx->fp_src_addr.ip6, 16);
1911             ctrp->group_length = pfx->fp_len;
1912             ctrp->packets = clib_host_to_net_u64 (c.packets);
1913             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1914             mp->count++;
1915             ctrp++;
1916
1917             if (mp->count == items_this_message)
1918               {
1919                 mp->count = htonl (items_this_message);
1920                 /*
1921                  * If the main thread's input queue is stuffed,
1922                  * drop the data structure lock (which the main thread
1923                  * may want), and take a pause.
1924                  */
1925                 svm_queue_lock (q);
1926
1927                 while (svm_queue_is_full (q))
1928                   {
1929                     svm_queue_unlock (q);
1930                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
1931                                           STATS_RELEASE_DELAY_NS);
1932                     svm_queue_lock (q);
1933                   }
1934                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1935                 svm_queue_unlock (q);
1936
1937                 items_this_message = IP6_MFIB_COUNTER_BATCH_SIZE;
1938                 mp = vl_msg_api_alloc_as_if_client
1939                   (sizeof (*mp) +
1940                    items_this_message * sizeof (vl_api_ip6_mfib_counter_t));
1941                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_MFIB_COUNTERS);
1942                 mp->count = 0;
1943                 mp->vrf_id = ntohl (mfib->mft_table_id);
1944                 ctrp = (vl_api_ip6_mfib_counter_t *) mp->c;
1945               }
1946           }
1947       }
1948
1949       /* Flush any data from this mfib */
1950       if (mp->count)
1951         {
1952           mp->count = htonl (mp->count);
1953           vl_msg_api_send_shmem (q, (u8 *) & mp);
1954           mp = 0;
1955         }
1956     }
1957
1958   /* If e.g. the last FIB had no reportable routes, free the buffer */
1959   if (mp)
1960     vl_msg_api_free (mp);
1961 }
1962
1963 typedef struct
1964 {
1965   u32 fib_index;
1966   ip6_route_t **routep;
1967   stats_main_t *sm;
1968 } add_routes_in_fib_arg_t;
1969
1970 static void
1971 add_routes_in_fib (BVT (clib_bihash_kv) * kvp, void *arg)
1972 {
1973   add_routes_in_fib_arg_t *ap = arg;
1974   stats_main_t *sm = ap->sm;
1975
1976   if (sm->data_structure_lock->release_hint)
1977     clib_longjmp (&sm->jmp_buf, 1);
1978
1979   if (kvp->key[2] >> 32 == ap->fib_index)
1980     {
1981       ip6_address_t *addr;
1982       ip6_route_t *r;
1983       addr = (ip6_address_t *) kvp;
1984       vec_add2 (*ap->routep, r, 1);
1985       r->address = addr[0];
1986       r->address_length = kvp->key[2] & 0xFF;
1987       r->index = kvp->value;
1988     }
1989 }
1990
1991 static void
1992 do_ip6_fib_counters (stats_main_t * sm)
1993 {
1994   ip6_main_t *im6 = &ip6_main;
1995   api_main_t *am = sm->api_main;
1996   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1997   svm_queue_t *q = shmem_hdr->vl_input_queue;
1998   ip6_route_t *r;
1999   fib_table_t *fib;
2000   do_ip46_fibs_t *do_fibs;
2001   vl_api_vnet_ip6_fib_counters_t *mp = 0;
2002   u32 items_this_message;
2003   vl_api_ip6_fib_counter_t *ctrp = 0;
2004   u32 start_at_fib_index = 0;
2005   BVT (clib_bihash) * h = &im6->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash;
2006   add_routes_in_fib_arg_t _a, *a = &_a;
2007   int i;
2008
2009   do_fibs = &sm->do_ip46_fibs;
2010 again:
2011   vec_reset_length (do_fibs->fibs);
2012   /* *INDENT-OFF* */
2013   pool_foreach (fib, im6->fibs,
2014                 ({vec_add1(do_fibs->fibs,fib);}));
2015   /* *INDENT-ON* */
2016
2017
2018   for (i = 0; i < vec_len (do_fibs->fibs); i++)
2019     {
2020       fib = do_fibs->fibs[i];
2021       /* We may have bailed out due to control-plane activity */
2022       while ((fib - im6->fibs) < start_at_fib_index)
2023         continue;
2024
2025       if (mp == 0)
2026         {
2027           items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
2028           mp = vl_msg_api_alloc_as_if_client
2029             (sizeof (*mp) +
2030              items_this_message * sizeof (vl_api_ip6_fib_counter_t));
2031           mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
2032           mp->count = 0;
2033           mp->vrf_id = ntohl (fib->ft_table_id);
2034           ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
2035         }
2036
2037       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
2038
2039       vec_reset_length (do_fibs->ip6routes);
2040       vec_reset_length (do_fibs->results);
2041
2042       a->fib_index = fib - im6->fibs;
2043       a->routep = &do_fibs->ip6routes;
2044       a->sm = sm;
2045
2046       if (clib_setjmp (&sm->jmp_buf, 0) == 0)
2047         {
2048           start_at_fib_index = fib - im6->fibs;
2049           BV (clib_bihash_foreach_key_value_pair) (h, add_routes_in_fib, a);
2050         }
2051       else
2052         {
2053           dsunlock (sm);
2054           ip46_fib_stats_delay (sm, 0 /* sec */ ,
2055                                 STATS_RELEASE_DELAY_NS);
2056           mp->count = 0;
2057           ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
2058           goto again;
2059         }
2060
2061       vec_foreach (r, do_fibs->ip6routes)
2062       {
2063         vlib_counter_t c;
2064
2065         vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
2066                                    r->index, &c);
2067         /*
2068          * If it has actually
2069          * seen at least one packet, send it.
2070          */
2071         if (c.packets > 0)
2072           {
2073             /* already in net byte order */
2074             ctrp->address[0] = r->address.as_u64[0];
2075             ctrp->address[1] = r->address.as_u64[1];
2076             ctrp->address_length = (u8) r->address_length;
2077             ctrp->packets = clib_host_to_net_u64 (c.packets);
2078             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
2079             mp->count++;
2080             ctrp++;
2081
2082             if (mp->count == items_this_message)
2083               {
2084                 mp->count = htonl (items_this_message);
2085                 /*
2086                  * If the main thread's input queue is stuffed,
2087                  * drop the data structure lock (which the main thread
2088                  * may want), and take a pause.
2089                  */
2090                 svm_queue_lock (q);
2091                 if (svm_queue_is_full (q))
2092                   {
2093                     dsunlock (sm);
2094                     vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
2095                     svm_queue_unlock (q);
2096                     mp = 0;
2097                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
2098                                           STATS_RELEASE_DELAY_NS);
2099                     goto again;
2100                   }
2101                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
2102                 svm_queue_unlock (q);
2103
2104                 items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
2105                 mp = vl_msg_api_alloc_as_if_client
2106                   (sizeof (*mp) +
2107                    items_this_message * sizeof (vl_api_ip6_fib_counter_t));
2108                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
2109                 mp->count = 0;
2110                 mp->vrf_id = ntohl (fib->ft_table_id);
2111                 ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
2112               }
2113           }
2114
2115         if (sm->data_structure_lock->release_hint)
2116           {
2117             start_at_fib_index = fib - im6->fibs;
2118             dsunlock (sm);
2119             ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
2120             mp->count = 0;
2121             ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
2122             goto again;
2123           }
2124       }                         /* vec_foreach (routes) */
2125
2126       dsunlock (sm);
2127
2128       /* Flush any data from this fib */
2129       if (mp->count)
2130         {
2131           mp->count = htonl (mp->count);
2132           vl_msg_api_send_shmem (q, (u8 *) & mp);
2133           mp = 0;
2134         }
2135     }
2136
2137   /* If e.g. the last FIB had no reportable routes, free the buffer */
2138   if (mp)
2139     vl_msg_api_free (mp);
2140 }
2141
2142 typedef struct udp_encap_stat_t_
2143 {
2144   u32 ue_id;
2145   u64 stats[2];
2146 } udp_encap_stat_t;
2147
2148 typedef struct udp_encap_stats_walk_t_
2149 {
2150   udp_encap_stat_t *stats;
2151 } udp_encap_stats_walk_t;
2152
2153 static int
2154 udp_encap_stats_walk_cb (index_t uei, void *arg)
2155 {
2156   udp_encap_stats_walk_t *ctx = arg;
2157   udp_encap_stat_t *stat;
2158   udp_encap_t *ue;
2159
2160   ue = udp_encap_get (uei);
2161   vec_add2 (ctx->stats, stat, 1);
2162
2163   stat->ue_id = uei;
2164   udp_encap_get_stats (ue->ue_id, &stat->stats[0], &stat->stats[1]);
2165
2166   return (1);
2167 }
2168
2169 static void
2170 udp_encap_ship (udp_encap_stats_walk_t * ctx)
2171 {
2172   vl_api_vnet_udp_encap_counters_t *mp;
2173   vl_shmem_hdr_t *shmem_hdr;
2174   stats_main_t *sm;
2175   api_main_t *am;
2176   svm_queue_t *q;
2177
2178   mp = NULL;
2179   sm = &stats_main;
2180   am = sm->api_main;
2181   shmem_hdr = am->shmem_hdr;
2182   q = shmem_hdr->vl_input_queue;
2183
2184   /*
2185    * If the walk context has counters, which may be left over from the last
2186    * suspend, then we continue from there.
2187    */
2188   while (0 != vec_len (ctx->stats))
2189     {
2190       u32 n_items = MIN (vec_len (ctx->stats),
2191                          UDP_ENCAP_COUNTER_BATCH_SIZE);
2192       u8 pause = 0;
2193
2194       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
2195
2196       mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
2197                                           (n_items *
2198                                            sizeof
2199                                            (vl_api_udp_encap_counter_t)));
2200       mp->_vl_msg_id = ntohs (VL_API_VNET_UDP_ENCAP_COUNTERS);
2201       mp->count = ntohl (n_items);
2202
2203       /*
2204        * copy the counters from the back of the context, then we can easily
2205        * 'erase' them by resetting the vector length.
2206        * The order we push the stats to the caller is not important.
2207        */
2208       clib_memcpy (mp->c,
2209                    &ctx->stats[vec_len (ctx->stats) - n_items],
2210                    n_items * sizeof (*ctx->stats));
2211
2212       _vec_len (ctx->stats) = vec_len (ctx->stats) - n_items;
2213
2214       /*
2215        * send to the shm q
2216        */
2217       svm_queue_lock (q);
2218       pause = svm_queue_is_full (q);
2219
2220       vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
2221       svm_queue_unlock (q);
2222       dsunlock (sm);
2223
2224       if (pause)
2225         ip46_fib_stats_delay (sm, 0 /* sec */ ,
2226                               STATS_RELEASE_DELAY_NS);
2227     }
2228 }
2229
2230 static void
2231 do_udp_encap_counters (stats_main_t * sm)
2232 {
2233   udp_encap_stat_t *stat;
2234
2235   udp_encap_stats_walk_t ctx = {
2236     .stats = NULL,
2237   };
2238
2239   dslock (sm, 0 /* release hint */ , 1 /* tag */ );
2240   udp_encap_walk (udp_encap_stats_walk_cb, &ctx);
2241   dsunlock (sm);
2242
2243   udp_encap_ship (&ctx);
2244 }
2245
2246 int
2247 stats_set_poller_delay (u32 poller_delay_sec)
2248 {
2249   stats_main_t *sm = &stats_main;
2250   if (!poller_delay_sec)
2251     {
2252       return VNET_API_ERROR_INVALID_ARGUMENT;
2253     }
2254   else
2255     {
2256       sm->stats_poll_interval_in_seconds = poller_delay_sec;
2257       return 0;
2258     }
2259 }
2260
2261 static clib_error_t *
2262 stats_config (vlib_main_t * vm, unformat_input_t * input)
2263 {
2264   u32 sec;
2265
2266   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2267     {
2268       if (unformat (input, "interval %u", &sec))
2269         {
2270           int rv = stats_set_poller_delay (sec);
2271           if (rv)
2272             {
2273               return clib_error_return (0,
2274                                         "`stats_set_poller_delay' API call failed, rv=%d:%U",
2275                                         (int) rv, format_vnet_api_errno, rv);
2276             }
2277           return 0;
2278         }
2279       else
2280         {
2281           return clib_error_return (0, "unknown input '%U'",
2282                                     format_unformat_error, input);
2283         }
2284     }
2285   return 0;
2286 }
2287
2288 /* stats { ... } configuration. */
2289 /*?
2290  *
2291  * @cfgcmd{interval, &lt;seconds&gt;}
2292  * Configure stats poller delay to be @c seconds.
2293  *
2294 ?*/
2295 VLIB_CONFIG_FUNCTION (stats_config, "stats");
2296
2297 static void
2298   vl_api_stats_get_poller_delay_t_handler
2299   (vl_api_stats_get_poller_delay_t * mp)
2300 {
2301   stats_main_t *sm = &stats_main;
2302   vl_api_registration_t *reg;
2303   reg = vl_api_client_index_to_registration (mp->client_index);
2304   if (!reg)
2305     return;
2306   vl_api_stats_get_poller_delay_reply_t *rmp;
2307
2308   rmp = vl_msg_api_alloc (sizeof (*rmp));
2309   rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
2310   rmp->context = mp->context;
2311   rmp->retval = 0;
2312   rmp->delay = clib_host_to_net_u32 (sm->stats_poll_interval_in_seconds);
2313
2314   vl_api_send_msg (reg, (u8 *) rmp);
2315
2316 }
2317
2318 static void
2319 stats_thread_fn (void *arg)
2320 {
2321   stats_main_t *sm = &stats_main;
2322   vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
2323   vlib_thread_main_t *tm = vlib_get_thread_main ();
2324
2325   /* stats thread wants no signals. */
2326   {
2327     sigset_t s;
2328     sigfillset (&s);
2329     pthread_sigmask (SIG_SETMASK, &s, 0);
2330   }
2331
2332   if (vec_len (tm->thread_prefix))
2333     vlib_set_thread_name ((char *)
2334                           format (0, "%v_stats%c", tm->thread_prefix, '\0'));
2335
2336   clib_mem_set_heap (w->thread_mheap);
2337
2338   while (1)
2339     {
2340       ip46_fib_stats_delay (sm, sm->stats_poll_interval_in_seconds,
2341                             0 /* nsec */ );
2342
2343       if (!(sm->enable_poller))
2344         {
2345           continue;
2346         }
2347       if (pool_elts
2348           (sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS]))
2349         do_combined_per_interface_counters (sm);
2350
2351       if (pool_elts
2352           (sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS]))
2353         do_simple_per_interface_counters (sm);
2354
2355       if (pool_elts (sm->stats_registrations[IDX_IP4_FIB_COUNTERS]))
2356         do_ip4_fib_counters (sm);
2357
2358       if (pool_elts (sm->stats_registrations[IDX_IP6_FIB_COUNTERS]))
2359         do_ip6_fib_counters (sm);
2360
2361       if (pool_elts (sm->stats_registrations[IDX_IP4_MFIB_COUNTERS]))
2362         do_ip4_mfib_counters (sm);
2363
2364       if (pool_elts (sm->stats_registrations[IDX_IP6_MFIB_COUNTERS]))
2365         do_ip6_mfib_counters (sm);
2366
2367       if (pool_elts (sm->stats_registrations[IDX_IP4_NBR_COUNTERS]))
2368         do_ip4_nbr_counters (sm);
2369
2370       if (pool_elts (sm->stats_registrations[IDX_IP6_NBR_COUNTERS]))
2371         do_ip6_nbr_counters (sm);
2372
2373       if (pool_elts (sm->stats_registrations[IDX_UDP_ENCAP_COUNTERS]))
2374         do_udp_encap_counters (sm);
2375     }
2376 }
2377
2378 static void
2379   vl_api_vnet_interface_simple_counters_t_handler
2380   (vl_api_vnet_interface_simple_counters_t * mp)
2381 {
2382   vpe_client_registration_t *clients, client;
2383   stats_main_t *sm = &stats_main;
2384   vl_api_registration_t *reg, *reg_prev = NULL;
2385   vl_api_vnet_interface_simple_counters_t *mp_copy = NULL;
2386   u32 mp_size;
2387   int i;
2388
2389   mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (u64));
2390
2391   clients =
2392     get_clients_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
2393                           ~0 /*flag for all */ );
2394
2395   for (i = 0; i < vec_len (clients); i++)
2396     {
2397       client = clients[i];
2398       reg = vl_api_client_index_to_registration (client.client_index);
2399       if (reg)
2400         {
2401           if (reg_prev && vl_api_can_send_msg (reg_prev))
2402             {
2403               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2404               clib_memcpy (mp_copy, mp, mp_size);
2405               vl_api_send_msg (reg_prev, (u8 *) mp);
2406               mp = mp_copy;
2407             }
2408           reg_prev = reg;
2409         }
2410       else
2411         {
2412           sm->enable_poller =
2413             clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, ~0,
2414                                    client.client_index);
2415           continue;
2416         }
2417     }
2418   vec_free (clients);
2419
2420 #if STATS_DEBUG > 0
2421   fformat (stdout, "%U\n", format_vnet_simple_counters, mp);
2422 #endif
2423
2424   if (reg_prev && vl_api_can_send_msg (reg_prev))
2425     {
2426       vl_api_send_msg (reg_prev, (u8 *) mp);
2427     }
2428   else
2429     {
2430       vl_msg_api_free (mp);
2431     }
2432 }
2433
2434 static void
2435 vl_api_vnet_ip4_fib_counters_t_handler (vl_api_vnet_ip4_fib_counters_t * mp)
2436 {
2437   stats_main_t *sm = &stats_main;
2438   vl_api_registration_t *reg, *reg_prev = NULL;
2439   vl_api_vnet_ip4_fib_counters_t *mp_copy = NULL;
2440   u32 mp_size;
2441   vpe_client_registration_t *clients, client;
2442   int i;
2443
2444   mp_size = sizeof (*mp_copy) +
2445     ntohl (mp->count) * sizeof (vl_api_ip4_fib_counter_t);
2446
2447   clients =
2448     get_clients_for_stat (IDX_IP4_FIB_COUNTERS, ~0 /*flag for all */ );
2449
2450   for (i = 0; i < vec_len (clients); i++)
2451     {
2452       client = clients[i];
2453       reg = vl_api_client_index_to_registration (client.client_index);
2454       if (reg)
2455         {
2456           if (reg_prev && vl_api_can_send_msg (reg_prev))
2457             {
2458               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2459               clib_memcpy (mp_copy, mp, mp_size);
2460               vl_api_send_msg (reg_prev, (u8 *) mp);
2461               mp = mp_copy;
2462             }
2463           reg_prev = reg;
2464         }
2465       else
2466         {
2467           sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
2468                                                      ~0, client.client_index);
2469           continue;
2470         }
2471     }
2472   vec_free (clients);
2473
2474   if (reg_prev && vl_api_can_send_msg (reg_prev))
2475     {
2476       vl_api_send_msg (reg_prev, (u8 *) mp);
2477     }
2478   else
2479     {
2480       vl_msg_api_free (mp);
2481     }
2482 }
2483
2484 static void
2485 vl_api_vnet_ip4_nbr_counters_t_handler (vl_api_vnet_ip4_nbr_counters_t * mp)
2486 {
2487   stats_main_t *sm = &stats_main;
2488   vl_api_registration_t *reg, *reg_prev = NULL;
2489   vl_api_vnet_ip4_nbr_counters_t *mp_copy = NULL;
2490   u32 mp_size;
2491   vpe_client_registration_t *clients, client;
2492   int i;
2493
2494   mp_size = sizeof (*mp_copy) +
2495     ntohl (mp->count) * sizeof (vl_api_ip4_nbr_counter_t);
2496
2497   clients =
2498     get_clients_for_stat (IDX_IP4_NBR_COUNTERS, ~0 /*flag for all */ );
2499
2500   for (i = 0; i < vec_len (clients); i++)
2501     {
2502       client = clients[i];
2503       reg = vl_api_client_index_to_registration (client.client_index);
2504       if (reg)
2505         {
2506           if (reg_prev && vl_api_can_send_msg (reg_prev))
2507             {
2508               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2509               clib_memcpy (mp_copy, mp, mp_size);
2510               vl_api_send_msg (reg_prev, (u8 *) mp);
2511               mp = mp_copy;
2512             }
2513           reg_prev = reg;
2514         }
2515       else
2516         {
2517           sm->enable_poller = clear_client_for_stat (IDX_IP4_NBR_COUNTERS,
2518                                                      ~0, client.client_index);
2519           continue;
2520         }
2521     }
2522   vec_free (clients);
2523
2524   /* *INDENT-ON* */
2525   if (reg_prev && vl_api_can_send_msg (reg_prev))
2526     {
2527       vl_api_send_msg (reg_prev, (u8 *) mp);
2528     }
2529   else
2530     {
2531       vl_msg_api_free (mp);
2532     }
2533 }
2534
2535 static void
2536 vl_api_vnet_ip6_fib_counters_t_handler (vl_api_vnet_ip6_fib_counters_t * mp)
2537 {
2538   stats_main_t *sm = &stats_main;
2539   vl_api_registration_t *reg, *reg_prev = NULL;
2540   vl_api_vnet_ip6_fib_counters_t *mp_copy = NULL;
2541   u32 mp_size;
2542   vpe_client_registration_t *clients, client;
2543   int i;
2544
2545   mp_size = sizeof (*mp_copy) +
2546     ntohl (mp->count) * sizeof (vl_api_ip6_fib_counter_t);
2547
2548   clients =
2549     get_clients_for_stat (IDX_IP6_FIB_COUNTERS, ~0 /*flag for all */ );
2550
2551   for (i = 0; i < vec_len (clients); i++)
2552     {
2553       client = clients[i];
2554       reg = vl_api_client_index_to_registration (client.client_index);
2555       if (reg)
2556         {
2557           if (reg_prev && vl_api_can_send_msg (reg_prev))
2558             {
2559               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2560               clib_memcpy (mp_copy, mp, mp_size);
2561               vl_api_send_msg (reg_prev, (u8 *) mp);
2562               mp = mp_copy;
2563             }
2564           reg_prev = reg;
2565         }
2566       else
2567         {
2568           sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2569                                                      ~0, client.client_index);
2570           continue;
2571         }
2572     }
2573   vec_free (clients);
2574
2575   /* *INDENT-ON* */
2576   if (reg_prev && vl_api_can_send_msg (reg_prev))
2577     {
2578       vl_api_send_msg (reg_prev, (u8 *) mp);
2579     }
2580   else
2581     {
2582       vl_msg_api_free (mp);
2583     }
2584 }
2585
2586 static void
2587 vl_api_vnet_ip6_nbr_counters_t_handler (vl_api_vnet_ip6_nbr_counters_t * mp)
2588 {
2589   stats_main_t *sm = &stats_main;
2590   vl_api_registration_t *reg, *reg_prev = NULL;
2591   vl_api_vnet_ip6_nbr_counters_t *mp_copy = NULL;
2592   u32 mp_size;
2593   vpe_client_registration_t *clients, client;
2594   int i;
2595
2596   mp_size = sizeof (*mp_copy) +
2597     ntohl (mp->count) * sizeof (vl_api_ip6_nbr_counter_t);
2598
2599   clients =
2600     get_clients_for_stat (IDX_IP6_NBR_COUNTERS, ~0 /*flag for all */ );
2601
2602   for (i = 0; i < vec_len (clients); i++)
2603     {
2604       client = clients[i];
2605       reg = vl_api_client_index_to_registration (client.client_index);
2606       if (reg)
2607         {
2608           if (reg_prev && vl_api_can_send_msg (reg_prev))
2609             {
2610               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2611               clib_memcpy (mp_copy, mp, mp_size);
2612               vl_api_send_msg (reg_prev, (u8 *) mp);
2613               mp = mp_copy;
2614             }
2615           reg_prev = reg;
2616         }
2617       else
2618         {
2619           sm->enable_poller = clear_client_for_stat (IDX_IP6_NBR_COUNTERS,
2620                                                      ~0, client.client_index);
2621           continue;
2622         }
2623     }
2624   vec_free (clients);
2625
2626   /* *INDENT-ON* */
2627   if (reg_prev && vl_api_can_send_msg (reg_prev))
2628     {
2629       vl_api_send_msg (reg_prev, (u8 *) mp);
2630     }
2631   else
2632     {
2633       vl_msg_api_free (mp);
2634     }
2635 }
2636
2637 static void
2638 vl_api_want_udp_encap_stats_t_handler (vl_api_want_udp_encap_stats_t * mp)
2639 {
2640   stats_main_t *sm = &stats_main;
2641   vpe_client_registration_t rp;
2642   vl_api_want_udp_encap_stats_reply_t *rmp;
2643   uword *p;
2644   i32 retval = 0;
2645   vl_api_registration_t *reg;
2646   u32 fib;
2647
2648   fib = ~0;                     //Using same mechanism as _per_interface_
2649   rp.client_index = mp->client_index;
2650   rp.client_pid = mp->pid;
2651
2652   handle_client_registration (&rp, IDX_UDP_ENCAP_COUNTERS, fib, mp->enable);
2653
2654 reply:
2655   reg = vl_api_client_index_to_registration (mp->client_index);
2656
2657   if (!reg)
2658     {
2659       sm->enable_poller = clear_client_for_stat (IDX_UDP_ENCAP_COUNTERS,
2660                                                  fib, mp->client_index);
2661       return;
2662     }
2663
2664   rmp = vl_msg_api_alloc (sizeof (*rmp));
2665   rmp->_vl_msg_id = ntohs (VL_API_WANT_UDP_ENCAP_STATS_REPLY);
2666   rmp->context = mp->context;
2667   rmp->retval = retval;
2668
2669   vl_api_send_msg (reg, (u8 *) rmp);
2670 }
2671
2672 static void
2673 vl_api_want_stats_t_handler (vl_api_want_stats_t * mp)
2674 {
2675   stats_main_t *sm = &stats_main;
2676   vpe_client_registration_t rp;
2677   vl_api_want_stats_reply_t *rmp;
2678   uword *p;
2679   i32 retval = 0;
2680   u32 item;
2681   vl_api_registration_t *reg;
2682
2683   item = ~0;                    //"ALL THE THINGS IN THE THINGS
2684   rp.client_index = mp->client_index;
2685   rp.client_pid = mp->pid;
2686
2687   handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
2688                               item, mp->enable_disable);
2689
2690   handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
2691                               item, mp->enable_disable);
2692
2693   handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS,
2694                               item, mp->enable_disable);
2695
2696   handle_client_registration (&rp, IDX_IP4_NBR_COUNTERS,
2697                               item, mp->enable_disable);
2698
2699   handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS,
2700                               item, mp->enable_disable);
2701
2702   handle_client_registration (&rp, IDX_IP6_NBR_COUNTERS,
2703                               item, mp->enable_disable);
2704
2705 reply:
2706   reg = vl_api_client_index_to_registration (mp->client_index);
2707   if (!reg)
2708     return;
2709
2710   rmp = vl_msg_api_alloc (sizeof (*rmp));
2711   rmp->_vl_msg_id = ntohs (VL_API_WANT_STATS_REPLY);
2712   rmp->context = mp->context;
2713   rmp->retval = retval;
2714
2715   vl_api_send_msg (reg, (u8 *) rmp);
2716 }
2717
2718 static void
2719   vl_api_want_interface_simple_stats_t_handler
2720   (vl_api_want_interface_simple_stats_t * mp)
2721 {
2722   stats_main_t *sm = &stats_main;
2723   vpe_client_registration_t rp;
2724   vl_api_want_interface_simple_stats_reply_t *rmp;
2725   uword *p;
2726   i32 retval = 0;
2727   u32 swif;
2728   vl_api_registration_t *reg;
2729
2730   swif = ~0;                    //Using same mechanism as _per_interface_
2731   rp.client_index = mp->client_index;
2732   rp.client_pid = mp->pid;
2733
2734   handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2735                               mp->enable_disable);
2736
2737 reply:
2738   reg = vl_api_client_index_to_registration (mp->client_index);
2739
2740   if (!reg)
2741     {
2742       sm->enable_poller =
2743         clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2744                                mp->client_index);
2745       return;
2746     }
2747
2748   rmp = vl_msg_api_alloc (sizeof (*rmp));
2749   rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_SIMPLE_STATS_REPLY);
2750   rmp->context = mp->context;
2751   rmp->retval = retval;
2752
2753   vl_api_send_msg (reg, (u8 *) rmp);
2754 }
2755
2756
2757 static void
2758 vl_api_want_ip4_fib_stats_t_handler (vl_api_want_ip4_fib_stats_t * mp)
2759 {
2760   stats_main_t *sm = &stats_main;
2761   vpe_client_registration_t rp;
2762   vl_api_want_ip4_fib_stats_reply_t *rmp;
2763   uword *p;
2764   i32 retval = 0;
2765   vl_api_registration_t *reg;
2766   u32 fib;
2767
2768   fib = ~0;                     //Using same mechanism as _per_interface_
2769   rp.client_index = mp->client_index;
2770   rp.client_pid = mp->pid;
2771
2772   handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS, fib,
2773                               mp->enable_disable);
2774
2775 reply:
2776   reg = vl_api_client_index_to_registration (mp->client_index);
2777
2778   if (!reg)
2779     {
2780       sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
2781                                                  fib, mp->client_index);
2782       return;
2783     }
2784
2785   rmp = vl_msg_api_alloc (sizeof (*rmp));
2786   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_FIB_STATS_REPLY);
2787   rmp->context = mp->context;
2788   rmp->retval = retval;
2789
2790   vl_api_send_msg (reg, (u8 *) rmp);
2791 }
2792
2793 static void
2794 vl_api_want_ip4_mfib_stats_t_handler (vl_api_want_ip4_mfib_stats_t * mp)
2795 {
2796   stats_main_t *sm = &stats_main;
2797   vpe_client_registration_t rp;
2798   vl_api_want_ip4_mfib_stats_reply_t *rmp;
2799   uword *p;
2800   i32 retval = 0;
2801   vl_api_registration_t *reg;
2802   u32 mfib;
2803
2804   mfib = ~0;                    //Using same mechanism as _per_interface_
2805   rp.client_index = mp->client_index;
2806   rp.client_pid = mp->pid;
2807
2808   handle_client_registration (&rp, IDX_IP4_MFIB_COUNTERS, mfib,
2809                               mp->enable_disable);
2810
2811 reply:
2812   reg = vl_api_client_index_to_registration (mp->client_index);
2813   if (!reg)
2814     {
2815       sm->enable_poller = clear_client_for_stat (IDX_IP4_MFIB_COUNTERS,
2816                                                  mfib, mp->client_index);
2817       return;
2818     }
2819
2820   rmp = vl_msg_api_alloc (sizeof (*rmp));
2821   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_MFIB_STATS_REPLY);
2822   rmp->context = mp->context;
2823   rmp->retval = retval;
2824
2825   vl_api_send_msg (reg, (u8 *) rmp);
2826 }
2827
2828 static void
2829 vl_api_want_ip6_fib_stats_t_handler (vl_api_want_ip6_fib_stats_t * mp)
2830 {
2831   stats_main_t *sm = &stats_main;
2832   vpe_client_registration_t rp;
2833   vl_api_want_ip4_fib_stats_reply_t *rmp;
2834   uword *p;
2835   i32 retval = 0;
2836   vl_api_registration_t *reg;
2837   u32 fib;
2838
2839   fib = ~0;                     //Using same mechanism as _per_interface_
2840   rp.client_index = mp->client_index;
2841   rp.client_pid = mp->pid;
2842
2843   handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS, fib,
2844                               mp->enable_disable);
2845
2846 reply:
2847   reg = vl_api_client_index_to_registration (mp->client_index);
2848   if (!reg)
2849     {
2850       sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2851                                                  fib, mp->client_index);
2852       return;
2853     }
2854
2855   rmp = vl_msg_api_alloc (sizeof (*rmp));
2856   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_FIB_STATS_REPLY);
2857   rmp->context = mp->context;
2858   rmp->retval = retval;
2859
2860   vl_api_send_msg (reg, (u8 *) rmp);
2861 }
2862
2863 static void
2864 vl_api_want_ip6_mfib_stats_t_handler (vl_api_want_ip6_mfib_stats_t * mp)
2865 {
2866   stats_main_t *sm = &stats_main;
2867   vpe_client_registration_t rp;
2868   vl_api_want_ip4_mfib_stats_reply_t *rmp;
2869   uword *p;
2870   i32 retval = 0;
2871   vl_api_registration_t *reg;
2872   u32 mfib;
2873
2874   mfib = ~0;                    //Using same mechanism as _per_interface_
2875   rp.client_index = mp->client_index;
2876   rp.client_pid = mp->pid;
2877
2878   handle_client_registration (&rp, IDX_IP6_MFIB_COUNTERS, mfib,
2879                               mp->enable_disable);
2880
2881 reply:
2882   reg = vl_api_client_index_to_registration (mp->client_index);
2883   if (!reg)
2884     {
2885       sm->enable_poller = clear_client_for_stat (IDX_IP6_MFIB_COUNTERS,
2886                                                  mfib, mp->client_index);
2887       return;
2888     }
2889
2890   rmp = vl_msg_api_alloc (sizeof (*rmp));
2891   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_MFIB_STATS_REPLY);
2892   rmp->context = mp->context;
2893   rmp->retval = retval;
2894
2895   vl_api_send_msg (reg, (u8 *) rmp);
2896 }
2897
2898 /* FIXME - NBR stats broken - this will be fixed in subsequent patch */
2899 static void
2900 vl_api_want_ip4_nbr_stats_t_handler (vl_api_want_ip4_nbr_stats_t * mp)
2901 {
2902 }
2903
2904 static void
2905 vl_api_want_ip6_nbr_stats_t_handler (vl_api_want_ip6_nbr_stats_t * mp)
2906 {
2907 }
2908
2909 static void
2910 vl_api_vnet_get_summary_stats_t_handler (vl_api_vnet_get_summary_stats_t * mp)
2911 {
2912   stats_main_t *sm = &stats_main;
2913   vnet_interface_main_t *im = sm->interface_main;
2914   vl_api_vnet_get_summary_stats_reply_t *rmp;
2915   vlib_combined_counter_main_t *cm;
2916   vlib_counter_t v;
2917   int i, which;
2918   u64 total_pkts[VLIB_N_RX_TX];
2919   u64 total_bytes[VLIB_N_RX_TX];
2920   vl_api_registration_t *reg;
2921
2922   reg = vl_api_client_index_to_registration (mp->client_index);
2923   if (!reg)
2924     return;
2925
2926   rmp = vl_msg_api_alloc (sizeof (*rmp));
2927   rmp->_vl_msg_id = ntohs (VL_API_VNET_GET_SUMMARY_STATS_REPLY);
2928   rmp->context = mp->context;
2929   rmp->retval = 0;
2930
2931   memset (total_pkts, 0, sizeof (total_pkts));
2932   memset (total_bytes, 0, sizeof (total_bytes));
2933
2934   vnet_interface_counter_lock (im);
2935
2936   vec_foreach (cm, im->combined_sw_if_counters)
2937   {
2938     which = cm - im->combined_sw_if_counters;
2939
2940     for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
2941       {
2942         vlib_get_combined_counter (cm, i, &v);
2943         total_pkts[which] += v.packets;
2944         total_bytes[which] += v.bytes;
2945       }
2946   }
2947   vnet_interface_counter_unlock (im);
2948
2949   rmp->total_pkts[VLIB_RX] = clib_host_to_net_u64 (total_pkts[VLIB_RX]);
2950   rmp->total_bytes[VLIB_RX] = clib_host_to_net_u64 (total_bytes[VLIB_RX]);
2951   rmp->total_pkts[VLIB_TX] = clib_host_to_net_u64 (total_pkts[VLIB_TX]);
2952   rmp->total_bytes[VLIB_TX] = clib_host_to_net_u64 (total_bytes[VLIB_TX]);
2953   rmp->vector_rate =
2954     clib_host_to_net_u64 (vlib_last_vector_length_per_node (sm->vlib_main));
2955
2956   vl_api_send_msg (reg, (u8 *) rmp);
2957 }
2958
2959 int
2960 stats_memclnt_delete_callback (u32 client_index)
2961 {
2962   vpe_client_stats_registration_t *rp;
2963   stats_main_t *sm = &stats_main;
2964   uword *p;
2965
2966   // FIXME
2967   /* p = hash_get (sm->stats_registration_hash, client_index); */
2968   /* if (p) */
2969   /*   { */
2970   /*     rp = pool_elt_at_index (sm->stats_registrations, p[0]); */
2971   /*     pool_put (sm->stats_registrations, rp); */
2972   /*     hash_unset (sm->stats_registration_hash, client_index); */
2973   /*   } */
2974
2975   return 0;
2976 }
2977
2978 #define vl_api_vnet_interface_simple_counters_t_endian vl_noop_handler
2979 #define vl_api_vnet_interface_simple_counters_t_print vl_noop_handler
2980 #define vl_api_vnet_interface_combined_counters_t_endian vl_noop_handler
2981 #define vl_api_vnet_interface_combined_counters_t_print vl_noop_handler
2982 #define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
2983 #define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
2984 #define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
2985 #define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler
2986 #define vl_api_vnet_ip4_nbr_counters_t_endian vl_noop_handler
2987 #define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
2988 #define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
2989 #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
2990 #define vl_api_map_stats_segment_t_print vl_noop_handler
2991
2992 static void
2993 vl_api_map_stats_segment_t_handler (vl_api_map_stats_segment_t * mp)
2994 {
2995   vl_api_map_stats_segment_reply_t *rmp;
2996   stats_main_t *sm = &stats_main;
2997   ssvm_private_t *ssvmp = &sm->stat_segment;
2998   vl_api_registration_t *regp;
2999   api_main_t *am = &api_main;
3000   clib_file_t *cf;
3001   vl_api_shm_elem_config_t *config = 0;
3002   vl_shmem_hdr_t *shmem_hdr;
3003   int rv = 0;
3004
3005   regp = vl_api_client_index_to_registration (mp->client_index);
3006   if (regp == 0)
3007     {
3008       clib_warning ("API client disconnected");
3009       return;
3010     }
3011   if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
3012     rv = VNET_API_ERROR_INVALID_REGISTRATION;
3013
3014   rmp = vl_msg_api_alloc (sizeof (*rmp));
3015   rmp->_vl_msg_id = htons (VL_API_MAP_STATS_SEGMENT_REPLY);
3016   rmp->context = mp->context;
3017   rmp->retval = htonl (rv);
3018
3019   vl_api_send_msg (regp, (u8 *) rmp);
3020
3021   if (rv != 0)
3022     return;
3023
3024   /*
3025    * We need the reply message to make it out the back door
3026    * before we send the magic fd message so force a flush
3027    */
3028   cf = vl_api_registration_file (regp);
3029   cf->write_function (cf);
3030
3031   /* Send the magic "here's your sign (aka fd)" socket message */
3032   vl_sock_api_send_fd_msg (cf->file_descriptor, ssvmp->fd);
3033 }
3034
3035 static clib_error_t *
3036 stats_init (vlib_main_t * vm)
3037 {
3038   stats_main_t *sm = &stats_main;
3039   api_main_t *am = &api_main;
3040   void *vlib_worker_thread_bootstrap_fn (void *arg);
3041
3042   sm->vlib_main = vm;
3043   sm->vnet_main = vnet_get_main ();
3044   sm->interface_main = &vnet_get_main ()->interface_main;
3045   sm->api_main = am;
3046   sm->stats_poll_interval_in_seconds = 10;
3047   sm->data_structure_lock =
3048     clib_mem_alloc_aligned (sizeof (data_structure_lock_t),
3049                             CLIB_CACHE_LINE_BYTES);
3050   memset (sm->data_structure_lock, 0, sizeof (*sm->data_structure_lock));
3051
3052 #define _(N,n)                                                  \
3053     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
3054                            vl_api_##n##_t_handler,              \
3055                            vl_noop_handler,                     \
3056                            vl_api_##n##_t_endian,               \
3057                            vl_api_##n##_t_print,                \
3058                            sizeof(vl_api_##n##_t), 0 /* do NOT trace! */);
3059   foreach_stats_msg;
3060 #undef _
3061
3062   /* tell the msg infra not to free these messages... */
3063   am->message_bounce[VL_API_VNET_INTERFACE_SIMPLE_COUNTERS] = 1;
3064   am->message_bounce[VL_API_VNET_INTERFACE_COMBINED_COUNTERS] = 1;
3065   am->message_bounce[VL_API_VNET_IP4_FIB_COUNTERS] = 1;
3066   am->message_bounce[VL_API_VNET_IP6_FIB_COUNTERS] = 1;
3067   am->message_bounce[VL_API_VNET_IP4_NBR_COUNTERS] = 1;
3068   am->message_bounce[VL_API_VNET_IP6_NBR_COUNTERS] = 1;
3069
3070   /*
3071    * Set up the (msg_name, crc, message-id) table
3072    */
3073   setup_message_id_table (am);
3074
3075   vec_validate (sm->stats_registrations, STATS_REG_N_IDX);
3076   vec_validate (sm->stats_registration_hash, STATS_REG_N_IDX);
3077 #define stats_reg(n)                            \
3078   sm->stats_registrations[IDX_##n] = 0; \
3079   sm->stats_registration_hash[IDX_##n] = 0;
3080 #include <vpp/stats/stats.reg>
3081 #undef stats_reg
3082
3083   return 0;
3084 }
3085
3086 VLIB_INIT_FUNCTION (stats_init);
3087
3088 /* *INDENT-OFF* */
3089 VLIB_REGISTER_THREAD (stats_thread_reg, static) = {
3090   .name = "stats",
3091   .function = stats_thread_fn,
3092   .fixed_count = 1,
3093   .count = 1,
3094   .no_data_structure_clone = 1,
3095   .use_pthreads = 1,
3096 };
3097 /* *INDENT-ON* */
3098
3099 /*
3100  * fd.io coding-style-patch-verification: ON
3101  *
3102  * Local Variables:
3103  * eval: (c-set-style "gnu")
3104  * End:
3105  */