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