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