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