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