Detailed stats collection feature
[vpp.git] / src / vpp / stats / stats.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vpp/stats/stats.h>
16 #include <signal.h>
17 #include <vnet/fib/ip4_fib.h>
18 #include <vnet/fib/fib_entry.h>
19 #include <vnet/mfib/mfib_entry.h>
20 #include <vnet/dpo/load_balance.h>
21 #include <vnet/udp/udp_encap.h>
22
23 #define STATS_DEBUG 0
24
25 stats_main_t stats_main;
26
27 #include <vnet/ip/ip.h>
28
29 #include <vpp/api/vpe_msg_enum.h>
30
31 #define f64_endian(a)
32 #define f64_print(a,b)
33
34 #define vl_typedefs             /* define message structures */
35 #include <vpp/api/vpe_all_api_h.h>
36 #undef vl_typedefs
37
38 #define vl_endianfun            /* define message structures */
39 #include <vpp/api/vpe_all_api_h.h>
40 #undef vl_endianfun
41
42 /* instantiate all the print functions we know about */
43 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
44 #define vl_printfun
45 #include <vpp/api/vpe_all_api_h.h>
46 #undef vl_printfun
47
48 #define foreach_stats_msg                                               \
49 _(WANT_STATS, want_stats)                                               \
50 _(VNET_INTERFACE_SIMPLE_COUNTERS, vnet_interface_simple_counters)       \
51 _(WANT_INTERFACE_SIMPLE_STATS, want_interface_simple_stats)     \
52 _(VNET_INTERFACE_COMBINED_COUNTERS, vnet_interface_combined_counters)   \
53 _(WANT_INTERFACE_COMBINED_STATS, want_interface_combined_stats) \
54 _(WANT_PER_INTERFACE_COMBINED_STATS, want_per_interface_combined_stats) \
55 _(WANT_PER_INTERFACE_SIMPLE_STATS, want_per_interface_simple_stats) \
56 _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters)                         \
57 _(WANT_IP4_FIB_STATS, want_ip4_fib_stats)            \
58 _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters)                         \
59 _(WANT_IP6_FIB_STATS, want_ip6_fib_stats)        \
60 _(WANT_IP4_MFIB_STATS, want_ip4_mfib_stats)                             \
61 _(WANT_IP6_MFIB_STATS, want_ip6_mfib_stats)                             \
62 _(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters)                         \
63 _(WANT_IP4_NBR_STATS, want_ip4_nbr_stats)            \
64 _(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \
65 _(WANT_IP6_NBR_STATS, want_ip6_nbr_stats) \
66 _(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats) \
67 _(STATS_GET_POLLER_DELAY, stats_get_poller_delay) \
68 _(WANT_UDP_ENCAP_STATS, want_udp_encap_stats)
69
70 #define vl_msg_name_crc_list
71 #include <vpp/stats/stats.api.h>
72 #undef vl_msg_name_crc_list
73
74 static void
75 setup_message_id_table (api_main_t * am)
76 {
77 #define _(id,n,crc) \
78   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
79   foreach_vl_msg_name_crc_stats;
80 #undef _
81 }
82
83 /* These constants ensure msg sizes <= 1024, aka ring allocation */
84 #define SIMPLE_COUNTER_BATCH_SIZE       126
85 #define COMBINED_COUNTER_BATCH_SIZE     63
86 #define IP4_FIB_COUNTER_BATCH_SIZE      48
87 #define IP6_FIB_COUNTER_BATCH_SIZE      30
88 #define IP4_MFIB_COUNTER_BATCH_SIZE     24
89 #define IP6_MFIB_COUNTER_BATCH_SIZE     15
90 #define UDP_ENCAP_COUNTER_BATCH_SIZE    (1024 / sizeof(vl_api_udp_encap_counter_t))
91
92 /* 5ms */
93 #define STATS_RELEASE_DELAY_NS (1000 * 1000 * 5)
94 /*                              ns/us  us/ms        */
95
96 u8 *
97 format_vnet_interface_combined_counters (u8 * s, va_list * args)
98 {
99   stats_main_t *sm = &stats_main;
100   vl_api_vnet_interface_combined_counters_t *mp =
101     va_arg (*args, vl_api_vnet_interface_combined_counters_t *);
102
103   char *counter_name;
104   u32 count, sw_if_index;
105   int i;
106   count = ntohl (mp->count);
107   sw_if_index = ntohl (mp->first_sw_if_index);
108
109   vlib_counter_t *vp;
110   u64 packets, bytes;
111   vp = (vlib_counter_t *) mp->data;
112
113   switch (mp->vnet_counter_type)
114     {
115     case VNET_INTERFACE_COUNTER_RX:
116       counter_name = "rx";
117       break;
118     case VNET_INTERFACE_COUNTER_TX:
119       counter_name = "tx";
120       break;
121     default:
122       counter_name = "bogus";
123       break;
124     }
125   for (i = 0; i < count; i++)
126     {
127       packets = clib_mem_unaligned (&vp->packets, u64);
128       packets = clib_net_to_host_u64 (packets);
129       bytes = clib_mem_unaligned (&vp->bytes, u64);
130       bytes = clib_net_to_host_u64 (bytes);
131       vp++;
132       s = format (s, "%U.%s.packets %lld\n",
133                   format_vnet_sw_if_index_name,
134                   sm->vnet_main, sw_if_index, counter_name, packets);
135       s = format (s, "%U.%s.bytes %lld\n",
136                   format_vnet_sw_if_index_name,
137                   sm->vnet_main, sw_if_index, counter_name, bytes);
138       sw_if_index++;
139     }
140   return s;
141 }
142
143 u8 *
144 format_vnet_interface_simple_counters (u8 * s, va_list * args)
145 {
146   stats_main_t *sm = &stats_main;
147   vl_api_vnet_interface_simple_counters_t *mp =
148     va_arg (*args, vl_api_vnet_interface_simple_counters_t *);
149   char *counter_name;
150   u32 count, sw_if_index;
151   count = ntohl (mp->count);
152   sw_if_index = ntohl (mp->first_sw_if_index);
153   u64 *vp, v;
154   vp = (u64 *) mp->data;
155   int i;
156
157   switch (mp->vnet_counter_type)
158     {
159     case VNET_INTERFACE_COUNTER_DROP:
160       counter_name = "drop";
161       break;
162     case VNET_INTERFACE_COUNTER_PUNT:
163       counter_name = "punt";
164       break;
165     case VNET_INTERFACE_COUNTER_IP4:
166       counter_name = "ip4";
167       break;
168     case VNET_INTERFACE_COUNTER_IP6:
169       counter_name = "ip6";
170       break;
171     case VNET_INTERFACE_COUNTER_RX_NO_BUF:
172       counter_name = "rx-no-buff";
173       break;
174     case VNET_INTERFACE_COUNTER_RX_MISS:
175       counter_name = "rx-miss";
176       break;
177     case VNET_INTERFACE_COUNTER_RX_ERROR:
178       counter_name = "rx-error (fifo-full)";
179       break;
180     case VNET_INTERFACE_COUNTER_TX_ERROR:
181       counter_name = "tx-error (fifo-full)";
182       break;
183     default:
184       counter_name = "bogus";
185       break;
186     }
187   for (i = 0; i < count; i++)
188     {
189       v = clib_mem_unaligned (vp, u64);
190       v = clib_net_to_host_u64 (v);
191       vp++;
192       s = format (s, "%U.%s %lld\n", format_vnet_sw_if_index_name,
193                   sm->vnet_main, sw_if_index, counter_name, v);
194       sw_if_index++;
195     }
196
197   return s;
198 }
199
200 static void
201 dslock (stats_main_t * sm, int release_hint, int tag)
202 {
203   u32 thread_index;
204   data_structure_lock_t *l = sm->data_structure_lock;
205
206   if (PREDICT_FALSE (l == 0))
207     return;
208
209   thread_index = vlib_get_thread_index ();
210   if (l->lock && l->thread_index == thread_index)
211     {
212       l->count++;
213       return;
214     }
215
216   if (release_hint)
217     l->release_hint++;
218
219   while (__sync_lock_test_and_set (&l->lock, 1))
220     /* zzzz */ ;
221   l->tag = tag;
222   l->thread_index = thread_index;
223   l->count = 1;
224 }
225
226 void
227 stats_dslock_with_hint (int hint, int tag)
228 {
229   stats_main_t *sm = &stats_main;
230   dslock (sm, hint, tag);
231 }
232
233 static void
234 dsunlock (stats_main_t * sm)
235 {
236   u32 thread_index;
237   data_structure_lock_t *l = sm->data_structure_lock;
238
239   if (PREDICT_FALSE (l == 0))
240     return;
241
242   thread_index = vlib_get_thread_index ();
243   ASSERT (l->lock && l->thread_index == thread_index);
244   l->count--;
245   if (l->count == 0)
246     {
247       l->tag = -l->tag;
248       l->release_hint = 0;
249       CLIB_MEMORY_BARRIER ();
250       l->lock = 0;
251     }
252 }
253
254 void
255 stats_dsunlock (int hint, int tag)
256 {
257   stats_main_t *sm = &stats_main;
258   dsunlock (sm);
259 }
260
261 static vpe_client_registration_t *
262 get_client_for_stat (u32 reg, u32 item, u32 client_index)
263 {
264   stats_main_t *sm = &stats_main;
265   vpe_client_stats_registration_t *registration;
266   uword *p;
267
268   /* Is there anything listening for item in that reg */
269   p = hash_get (sm->stats_registration_hash[reg], item);
270
271   if (!p)
272     return 0;                   // Fail
273
274   /* If there is, is our client_index one of them */
275   registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
276   p = hash_get (registration->client_hash, client_index);
277
278   if (!p)
279     return 0;                   // Fail
280
281   return pool_elt_at_index (registration->clients, p[0]);
282
283 }
284
285 static int
286 set_client_for_stat (u32 reg, u32 item, vpe_client_registration_t * client)
287 {
288   stats_main_t *sm = &stats_main;
289   vpe_client_stats_registration_t *registration;
290   vpe_client_registration_t *cr;
291   uword *p;
292
293   /* Is there anything listening for item in that reg */
294   p = hash_get (sm->stats_registration_hash[reg], item);
295
296   if (!p)
297     {
298       pool_get (sm->stats_registrations[reg], registration);
299       registration->item = item;
300       hash_set (sm->stats_registration_hash[reg], item,
301                 registration - sm->stats_registrations[reg]);
302     }
303   else
304     {
305       registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
306     }
307
308   p = hash_get (registration->client_hash, client->client_index);
309
310   if (!p)
311     {
312       pool_get (registration->clients, cr);
313       cr->client_index = client->client_index;
314       cr->client_pid = client->client_pid;
315       hash_set (registration->client_hash, cr->client_index,
316                 cr - registration->clients);
317     }
318
319   return 1;                     //At least one client is doing something ... poll
320 }
321
322 int
323 clear_client_for_stat (u32 reg, u32 item, u32 client_index)
324 {
325   stats_main_t *sm = &stats_main;
326   vpe_client_stats_registration_t *registration;
327   vpe_client_registration_t *client;
328   uword *p;
329   int i, elts;
330
331   /* Clear the client first */
332   /* Is there anything listening for item in that reg */
333   p = hash_get (sm->stats_registration_hash[reg], item);
334
335   if (!p)
336     goto exit;
337
338   /* If there is, is our client_index one of them */
339   registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
340   p = hash_get (registration->client_hash, client_index);
341
342   if (!p)
343     goto exit;
344
345   client = pool_elt_at_index (registration->clients, p[0]);
346   hash_unset (registration->client_hash, client->client_index);
347   pool_put (registration->clients, client);
348
349   /* Now check if that was the last client for that item */
350   if (0 == pool_elts (registration->clients))
351     {
352       hash_unset (sm->stats_registration_hash[reg], item);
353       pool_put (sm->stats_registrations[reg], registration);
354     }
355
356 exit:
357   elts = 0;
358   /* Now check if that was the last item in any of the listened to stats */
359   for (i = 0; i < STATS_REG_N_IDX; i++)
360     {
361       elts += pool_elts (sm->stats_registrations[i]);
362     }
363   return elts;
364 }
365
366 vpe_client_registration_t *
367 get_clients_for_stat (u32 reg, u32 item)
368 {
369   stats_main_t *sm = &stats_main;
370   vpe_client_registration_t *client, *clients = 0;
371   vpe_client_stats_registration_t *registration;
372   uword *p;
373
374   /* Is there anything listening for item in that reg */
375   p = hash_get (sm->stats_registration_hash[reg], item);
376
377   if (!p)
378     return 0;                   // Fail
379
380   /* If there is, is our client_index one of them */
381   registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
382
383   vec_reset_length (clients);
384   pool_foreach (client, registration->clients, (
385                                                  {
386                                                  vec_add1 (clients, *client);}
387                 ));
388   return clients;
389 }
390
391
392 static void
393 clear_client_reg (u32 ** registrations)
394 {
395   /* When registrations[x] is a vector of pool indices
396      here is a good place to clean up the pools
397    */
398 #define stats_reg(n) vec_free(registrations[IDX_##n]);
399 #include <vpp/stats/stats.reg>
400 #undef stats_reg
401
402   vec_free (registrations);
403 }
404
405 u32 **
406 init_client_reg (u32 ** registrations)
407 {
408
409   /*
410      Initialise the stats registrations for each
411      type of stat a client can register for as well as
412      a vector of "interested" indexes.
413      Initially this is a u32 of either sw_if_index or fib_index
414      but eventually this should migrate to a pool_index (u32)
415      with a type specific pool that can include more complex things
416      such as timing and structured events.
417    */
418   vec_validate (registrations, STATS_REG_N_IDX);
419 #define stats_reg(n) \
420   vec_reset_length(registrations[IDX_##n]);
421 #include <vpp/stats/stats.reg>
422 #undef stats_reg
423
424   /*
425      When registrations[x] is a vector of pool indices, here
426      is a good place to init the pools.
427    */
428   return registrations;
429 }
430
431 u32 **
432 enable_all_client_reg (u32 ** registrations)
433 {
434
435   /*
436      Enable all stats known by adding
437      ~0 to the index vector. Eventually this
438      should be deprecated.
439    */
440 #define stats_reg(n)                            \
441   vec_add1(registrations[IDX_##n], ~0);
442 #include <vpp/stats/stats.reg>
443 #undef stats_reg
444   return registrations;
445 }
446
447 static void
448 do_simple_interface_counters (stats_main_t * sm)
449 {
450   vl_api_vnet_interface_simple_counters_t *mp = 0;
451   vnet_interface_main_t *im = sm->interface_main;
452   api_main_t *am = sm->api_main;
453   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
454   svm_queue_t *q = shmem_hdr->vl_input_queue;
455   vlib_simple_counter_main_t *cm;
456   u32 items_this_message = 0;
457   u64 v, *vp = 0;
458   int i, n_counts;
459
460   /*
461    * Prevent interface registration from expanding / moving the vectors...
462    * That tends never to happen, so we can hold this lock for a while.
463    */
464   vnet_interface_counter_lock (im);
465
466   vec_foreach (cm, im->sw_if_counters)
467   {
468     n_counts = vlib_simple_counter_n_counters (cm);
469     for (i = 0; i < n_counts; i++)
470       {
471         if (mp == 0)
472           {
473             items_this_message = clib_min (SIMPLE_COUNTER_BATCH_SIZE,
474                                            n_counts - i);
475
476             mp = vl_msg_api_alloc_as_if_client
477               (sizeof (*mp) + items_this_message * sizeof (v));
478             mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_SIMPLE_COUNTERS);
479             mp->vnet_counter_type = cm - im->sw_if_counters;
480             mp->first_sw_if_index = htonl (i);
481             mp->count = 0;
482             vp = (u64 *) mp->data;
483           }
484         v = vlib_get_simple_counter (cm, i);
485         clib_mem_unaligned (vp, u64) = clib_host_to_net_u64 (v);
486         vp++;
487         mp->count++;
488         if (mp->count == items_this_message)
489           {
490             mp->count = htonl (items_this_message);
491             /* Send to the main thread... */
492             vl_msg_api_send_shmem (q, (u8 *) & mp);
493             mp = 0;
494           }
495       }
496     ASSERT (mp == 0);
497   }
498   vnet_interface_counter_unlock (im);
499 }
500
501 void
502 handle_client_registration (vpe_client_registration_t * client, u32 stat,
503                             u32 item, int enable_disable)
504 {
505   stats_main_t *sm = &stats_main;
506   vpe_client_registration_t *rp, _rp;
507
508   rp = get_client_for_stat (stat, item, client->client_index);
509
510   /* Disable case */
511   if (enable_disable == 0)
512     {
513       if (!rp)                  // No client to disable
514         {
515           clib_warning ("pid %d: already disabled for stats...",
516                         client->client_pid);
517           return;
518         }
519       sm->enable_poller =
520         clear_client_for_stat (stat, item, client->client_index);
521       return;
522     }
523   /* Enable case */
524   if (!rp)
525     {
526       rp = &_rp;
527       rp->client_index = client->client_index;
528       rp->client_pid = client->client_pid;
529       sm->enable_poller = set_client_for_stat (stat, item, rp);
530     }
531 }
532
533
534 /**********************************
535  * ALL Interface Combined stats - to be deprecated
536  **********************************/
537
538 /*
539  * This API should be deprecated as _per_interface_ works with ~0 as sw_if_index.
540  */
541 static void
542   vl_api_want_interface_combined_stats_t_handler
543   (vl_api_want_interface_combined_stats_t * mp)
544 {
545   stats_main_t *sm = &stats_main;
546   vpe_client_registration_t rp;
547   vl_api_want_interface_combined_stats_reply_t *rmp;
548   uword *p;
549   i32 retval = 0;
550   vl_api_registration_t *reg;
551   u32 swif;
552
553   swif = ~0;                    //Using same mechanism as _per_interface_
554   rp.client_index = mp->client_index;
555   rp.client_pid = mp->pid;
556
557   handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
558                               mp->enable_disable);
559
560 reply:
561   reg = vl_api_client_index_to_registration (mp->client_index);
562   if (!reg)
563     {
564       sm->enable_poller =
565         clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
566                                mp->client_index);
567       return;
568     }
569
570   rmp = vl_msg_api_alloc (sizeof (*rmp));
571   rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_COMBINED_STATS_REPLY);
572   rmp->context = mp->context;
573   rmp->retval = retval;
574
575   vl_api_send_msg (reg, (u8 *) rmp);
576 }
577
578 static void
579   vl_api_vnet_interface_combined_counters_t_handler
580   (vl_api_vnet_interface_combined_counters_t * mp)
581 {
582   vpe_client_registration_t *clients, client;
583   stats_main_t *sm = &stats_main;
584   vl_api_registration_t *reg, *reg_prev = NULL;
585   vl_api_vnet_interface_combined_counters_t *mp_copy = NULL;
586   u32 mp_size;
587   int i;
588
589   mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (vlib_counter_t));
590
591   clients =
592     get_clients_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
593                           ~0 /*flag for all */ );
594
595   for (i = 0; i < vec_len (clients); i++)
596     {
597       client = clients[i];
598       reg = vl_api_client_index_to_registration (client.client_index);
599       if (reg)
600         {
601           if (reg_prev && vl_api_can_send_msg (reg_prev))
602             {
603               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
604               clib_memcpy (mp_copy, mp, mp_size);
605               vl_api_send_msg (reg_prev, (u8 *) mp);
606               mp = mp_copy;
607             }
608           reg_prev = reg;
609         }
610     }
611 #if STATS_DEBUG > 0
612   fformat (stdout, "%U\n", format_vnet_combined_counters, mp);
613 #endif
614
615   if (reg_prev && vl_api_can_send_msg (reg_prev))
616     {
617       vl_api_send_msg (reg_prev, (u8 *) mp);
618     }
619   else
620     {
621       vl_msg_api_free (mp);
622     }
623 }
624
625 static void
626 do_combined_interface_counters (stats_main_t * sm)
627 {
628   vl_api_vnet_interface_combined_counters_t *mp = 0;
629   vnet_interface_main_t *im = sm->interface_main;
630   api_main_t *am = sm->api_main;
631   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
632   svm_queue_t *q = shmem_hdr->vl_input_queue;
633   vlib_combined_counter_main_t *cm;
634   u32 items_this_message = 0;
635   vlib_counter_t v, *vp = 0;
636   int i, n_counts;
637
638   vnet_interface_counter_lock (im);
639
640   vec_foreach (cm, im->combined_sw_if_counters)
641   {
642     n_counts = vlib_combined_counter_n_counters (cm);
643     for (i = 0; i < n_counts; i++)
644       {
645         if (mp == 0)
646           {
647             items_this_message = clib_min (COMBINED_COUNTER_BATCH_SIZE,
648                                            n_counts - i);
649
650             mp = vl_msg_api_alloc_as_if_client
651               (sizeof (*mp) + items_this_message * sizeof (v));
652             mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_COMBINED_COUNTERS);
653             mp->vnet_counter_type = cm - im->combined_sw_if_counters;
654             mp->first_sw_if_index = htonl (i);
655             mp->count = 0;
656             vp = (vlib_counter_t *) mp->data;
657           }
658         vlib_get_combined_counter (cm, i, &v);
659         clib_mem_unaligned (&vp->packets, u64)
660           = clib_host_to_net_u64 (v.packets);
661         clib_mem_unaligned (&vp->bytes, u64) = clib_host_to_net_u64 (v.bytes);
662         vp++;
663         mp->count++;
664         if (mp->count == items_this_message)
665           {
666             mp->count = htonl (items_this_message);
667             /* Send to the main thread... */
668             vl_msg_api_send_shmem (q, (u8 *) & mp);
669             mp = 0;
670           }
671       }
672     ASSERT (mp == 0);
673   }
674   vnet_interface_counter_unlock (im);
675 }
676
677 /**********************************
678  * Per Interface Combined stats
679  **********************************/
680
681 /* Request from client registering interfaces it wants */
682 static void
683   vl_api_want_per_interface_combined_stats_t_handler
684   (vl_api_want_per_interface_combined_stats_t * mp)
685 {
686   stats_main_t *sm = &stats_main;
687   vpe_client_registration_t rp;
688   vl_api_want_per_interface_combined_stats_reply_t *rmp;
689   vlib_combined_counter_main_t *cm;
690   uword *p;
691   i32 retval = 0;
692   vl_api_registration_t *reg;
693   u32 i, swif, num = 0;
694
695   num = ntohl (mp->num);
696
697   /*
698    * Validate sw_if_indexes before registering
699    */
700   for (i = 0; i < num; i++)
701     {
702       swif = ntohl (mp->sw_ifs[i]);
703
704       /*
705        * Check its a real sw_if_index that the client is allowed to see
706        */
707       if (swif != ~0)
708         {
709           if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
710             {
711               retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
712               goto reply;
713             }
714         }
715     }
716
717   for (i = 0; i < num; i++)
718     {
719       swif = ntohl (mp->sw_ifs[i]);
720
721       rp.client_index = mp->client_index;
722       rp.client_pid = mp->pid;
723       handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
724                                   swif, ntohl (mp->enable_disable));
725     }
726
727 reply:
728   reg = vl_api_client_index_to_registration (mp->client_index);
729   if (!reg)
730     {
731       for (i = 0; i < num; i++)
732         {
733           swif = ntohl (mp->sw_ifs[i]);
734
735           sm->enable_poller =
736             clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
737                                    mp->client_index);
738         }
739       return;
740     }
741
742   rmp = vl_msg_api_alloc (sizeof (*rmp));
743   rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_COMBINED_STATS_REPLY);
744   rmp->context = mp->context;
745   rmp->retval = retval;
746
747   vl_api_send_msg (reg, (u8 *) rmp);
748 }
749
750 /* Per Interface Combined distribution to client */
751 static void
752 do_combined_per_interface_counters (stats_main_t * sm)
753 {
754   vl_api_vnet_per_interface_combined_counters_t *mp = 0;
755   vnet_interface_main_t *im = sm->interface_main;
756   api_main_t *am = sm->api_main;
757   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
758   vl_api_registration_t *vl_reg;
759   vlib_combined_counter_main_t *cm;
760   vl_api_vnet_combined_counter_t *vp = 0;
761   vlib_counter_t v;
762   u32 i, j;
763   vpe_client_stats_registration_t *reg;
764   vpe_client_registration_t *client;
765   u32 *sw_if_index = 0;
766
767   vnet_interface_counter_lock (im);
768
769   vec_reset_length (sm->regs_tmp);
770
771   /* *INDENT-OFF* */
772   pool_foreach (reg,
773                 sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS],
774                 ({ vec_add1 (sm->regs_tmp, reg); }));
775   /* *INDENT-ON* */
776
777   for (i = 0; i < vec_len (sm->regs_tmp); i++)
778     {
779       reg = sm->regs_tmp[i];
780       if (reg->item == ~0)
781         {
782           vnet_interface_counter_unlock (im);
783           do_combined_interface_counters (sm);
784           vnet_interface_counter_lock (im);
785           continue;
786         }
787       vec_reset_length (sm->clients_tmp);
788
789       /* *INDENT-OFF* */
790       pool_foreach (client, reg->clients, ({ vec_add1 (sm->clients_tmp,
791                                                       client);}));
792       /* *INDENT-ON* */
793
794       for (j = 0; j < vec_len (sm->clients_tmp); j++)
795         {
796           client = sm->clients_tmp[j];
797
798           vl_reg = vl_api_client_index_to_registration (client->client_index);
799
800           //Client may have disconnected abrubtly, clean up so we don't poll nothing.
801           if (!vl_reg)
802             {
803               sm->enable_poller =
804                 clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
805                                        reg->item, client->client_index);
806               continue;
807             }
808           mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + sizeof (*vp));
809           memset (mp, 0, sizeof (*mp));
810
811           mp->_vl_msg_id =
812             ntohs (VL_API_VNET_PER_INTERFACE_COMBINED_COUNTERS);
813
814           /*
815            * count will eventually be used to optimise the batching
816            * of per client messages for each stat. For now setting this to 1 then
817            * iterate. This will not affect API.
818            *
819            * FIXME instead of enqueueing here, this should be sent to a batch
820            * storer for per-client transmission. Each "mp" sent would be a single entry
821            * and if a client is listening to other sw_if_indexes for same, it would be
822            * appended to that *mp
823            *
824            *
825            * FIXME(s):
826            * - capturing the timestamp of the counters "when VPP knew them" is important.
827            * Less so is that the timing of the delivery to the control plane be in the same
828            * timescale.
829
830            * i.e. As long as the control plane can delta messages from VPP and work out
831            * velocity etc based on the timestamp, it can do so in a more "batch mode".
832
833            * It would be beneficial to keep a "per-client" message queue, and then
834            * batch all the stat messages for a client into one message, with
835            * discrete timestamps.
836
837            * Given this particular API is for "per interface" one assumes that the scale
838            * is less than the ~0 case, which the prior API is suited for.
839            */
840
841           /*
842            * 1 message per api call for now
843            */
844           mp->count = htonl (1);
845           mp->timestamp = htonl (vlib_time_now (sm->vlib_main));
846
847           vp = (vl_api_vnet_combined_counter_t *) mp->data;
848           vp->sw_if_index = htonl (reg->item);
849
850           im = &vnet_get_main ()->interface_main;
851
852 #define _(X, x)                  \
853           cm = im->combined_sw_if_counters + X; \
854           vlib_get_combined_counter (cm, reg->item, &v); \
855           clib_mem_unaligned (&vp->x##_packets, u64) = \
856             clib_host_to_net_u64 (v.packets); \
857           clib_mem_unaligned (&vp->x##_bytes, u64) = \
858             clib_host_to_net_u64 (v.bytes);
859
860
861           _(VNET_INTERFACE_COUNTER_RX, rx);
862           _(VNET_INTERFACE_COUNTER_TX, tx);
863           _(VNET_INTERFACE_COUNTER_RX_UNICAST, rx_unicast);
864           _(VNET_INTERFACE_COUNTER_TX_UNICAST, tx_unicast);
865           _(VNET_INTERFACE_COUNTER_RX_MULTICAST, rx_multicast);
866           _(VNET_INTERFACE_COUNTER_TX_MULTICAST, tx_multicast);
867           _(VNET_INTERFACE_COUNTER_RX_BROADCAST, rx_broadcast);
868           _(VNET_INTERFACE_COUNTER_TX_BROADCAST, tx_broadcast);
869
870 #undef _
871
872           vl_api_send_msg (vl_reg, (u8 *) mp);
873         }
874     }
875
876   vnet_interface_counter_unlock (im);
877 }
878
879 /**********************************
880  * Per Interface simple stats
881  **********************************/
882
883 /* Request from client registering interfaces it wants */
884 static void
885   vl_api_want_per_interface_simple_stats_t_handler
886   (vl_api_want_per_interface_simple_stats_t * mp)
887 {
888   stats_main_t *sm = &stats_main;
889   vpe_client_registration_t rp;
890   vl_api_want_per_interface_simple_stats_reply_t *rmp;
891   vlib_simple_counter_main_t *cm;
892   uword *p;
893   i32 retval = 0;
894   vl_api_registration_t *reg;
895   u32 i, swif, num = 0;
896
897   num = ntohl (mp->num);
898
899   for (i = 0; i < num; i++)
900     {
901       swif = ntohl (mp->sw_ifs[i]);
902
903       /* Check its a real sw_if_index that the client is allowed to see */
904       if (swif != ~0)
905         {
906           if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
907             {
908               retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
909               goto reply;
910             }
911         }
912     }
913
914   for (i = 0; i < num; i++)
915     {
916       swif = ntohl (mp->sw_ifs[i]);
917
918       rp.client_index = mp->client_index;
919       rp.client_pid = mp->pid;
920       handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
921                                   swif, ntohl (mp->enable_disable));
922     }
923
924 reply:
925   reg = vl_api_client_index_to_registration (mp->client_index);
926
927   /* Client may have disconnected abruptly, clean up */
928   if (!reg)
929     {
930       for (i = 0; i < num; i++)
931         {
932           swif = ntohl (mp->sw_ifs[i]);
933           sm->enable_poller =
934             clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
935                                    mp->client_index);
936         }
937
938       return;
939     }
940
941
942   rmp = vl_msg_api_alloc (sizeof (*rmp));
943   rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
944   rmp->context = mp->context;
945   rmp->retval = retval;
946
947   vl_api_send_msg (reg, (u8 *) rmp);
948 }
949
950 /* Per Interface Simple distribution to client */
951 static void
952 do_simple_per_interface_counters (stats_main_t * sm)
953 {
954   vl_api_vnet_per_interface_simple_counters_t *mp = 0;
955   vnet_interface_main_t *im = sm->interface_main;
956   api_main_t *am = sm->api_main;
957   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
958   vl_api_registration_t *vl_reg;
959   vlib_simple_counter_main_t *cm;
960   u32 i, j, size;
961   vpe_client_stats_registration_t *reg;
962   vpe_client_registration_t *client;
963   u32 timestamp, count;
964   vl_api_vnet_simple_counter_t *vp = 0;
965   counter_t v;
966
967   vnet_interface_counter_lock (im);
968
969   vec_reset_length (sm->regs_tmp);
970
971   /* *INDENT-OFF* */
972   pool_foreach (reg,
973                 sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS],
974                 ({ vec_add1 (sm->regs_tmp, reg); }));
975   /* *INDENT-ON* */
976
977   for (i = 0; i < vec_len (sm->regs_tmp); i++)
978     {
979       reg = sm->regs_tmp[i];
980       if (reg->item == ~0)
981         {
982           vnet_interface_counter_unlock (im);
983           do_simple_interface_counters (sm);
984           vnet_interface_counter_lock (im);
985           continue;
986         }
987       vec_reset_length (sm->clients_tmp);
988
989       /* *INDENT-OFF* */
990       pool_foreach (client, reg->clients, ({ vec_add1 (sm->clients_tmp,
991                                                       client);}));
992       /* *INDENT-ON* */
993
994       for (j = 0; j < vec_len (sm->clients_tmp); j++)
995         {
996           client = sm->clients_tmp[j];
997           vl_reg = vl_api_client_index_to_registration (client->client_index);
998
999           /* Client may have disconnected abrubtly, clean up */
1000           if (!vl_reg)
1001             {
1002               sm->enable_poller =
1003                 clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
1004                                        reg->item, client->client_index);
1005               continue;
1006             }
1007
1008           mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + sizeof (*vp));
1009           memset (mp, 0, sizeof (*mp));
1010           mp->_vl_msg_id = ntohs (VL_API_VNET_PER_INTERFACE_SIMPLE_COUNTERS);
1011
1012           /*
1013            * count will eventually be used to optimise the batching
1014            * of per client messages for each stat. For now setting this to 1 then
1015            * iterate. This will not affect API.
1016            *
1017            * FIXME instead of enqueueing here, this should be sent to a batch
1018            * storer for per-client transmission. Each "mp" sent would be a single entry
1019            * and if a client is listening to other sw_if_indexes for same, it would be
1020            * appended to that *mp
1021            *
1022            *
1023            * FIXME(s):
1024            * - capturing the timestamp of the counters "when VPP knew them" is important.
1025            * Less so is that the timing of the delivery to the control plane be in the same
1026            * timescale.
1027
1028            * i.e. As long as the control plane can delta messages from VPP and work out
1029            * velocity etc based on the timestamp, it can do so in a more "batch mode".
1030
1031            * It would be beneficial to keep a "per-client" message queue, and then
1032            * batch all the stat messages for a client into one message, with
1033            * discrete timestamps.
1034
1035            * Given this particular API is for "per interface" one assumes that the scale
1036            * is less than the ~0 case, which the prior API is suited for.
1037            */
1038
1039           /*
1040            * 1 message per api call for now
1041            */
1042           mp->count = htonl (1);
1043           mp->timestamp = htonl (vlib_time_now (sm->vlib_main));
1044           vp = (vl_api_vnet_simple_counter_t *) mp->data;
1045
1046           vp->sw_if_index = htonl (reg->item);
1047
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 typedef struct udp_encap_stat_t_
2083 {
2084   u32 ue_id;
2085   u64 stats[2];
2086 } udp_encap_stat_t;
2087
2088 typedef struct udp_encap_stats_walk_t_
2089 {
2090   udp_encap_stat_t *stats;
2091 } udp_encap_stats_walk_t;
2092
2093 static int
2094 udp_encap_stats_walk_cb (index_t uei, void *arg)
2095 {
2096   udp_encap_stats_walk_t *ctx = arg;
2097   udp_encap_stat_t *stat;
2098   udp_encap_t *ue;
2099
2100   ue = udp_encap_get (uei);
2101   vec_add2 (ctx->stats, stat, 1);
2102
2103   stat->ue_id = uei;
2104   udp_encap_get_stats (ue->ue_id, &stat->stats[0], &stat->stats[1]);
2105
2106   return (1);
2107 }
2108
2109 static void
2110 udp_encap_ship (udp_encap_stats_walk_t * ctx)
2111 {
2112   vl_api_vnet_udp_encap_counters_t *mp;
2113   vl_shmem_hdr_t *shmem_hdr;
2114   stats_main_t *sm;
2115   api_main_t *am;
2116   svm_queue_t *q;
2117
2118   mp = NULL;
2119   sm = &stats_main;
2120   am = sm->api_main;
2121   shmem_hdr = am->shmem_hdr;
2122   q = shmem_hdr->vl_input_queue;
2123
2124   /*
2125    * If the walk context has counters, which may be left over from the last
2126    * suspend, then we continue from there.
2127    */
2128   while (0 != vec_len (ctx->stats))
2129     {
2130       u32 n_items = MIN (vec_len (ctx->stats),
2131                          UDP_ENCAP_COUNTER_BATCH_SIZE);
2132       u8 pause = 0;
2133
2134       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
2135
2136       mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
2137                                           (n_items *
2138                                            sizeof
2139                                            (vl_api_udp_encap_counter_t)));
2140       mp->_vl_msg_id = ntohs (VL_API_VNET_UDP_ENCAP_COUNTERS);
2141       mp->count = ntohl (n_items);
2142
2143       /*
2144        * copy the counters from the back of the context, then we can easily
2145        * 'erase' them by resetting the vector length.
2146        * The order we push the stats to the caller is not important.
2147        */
2148       clib_memcpy (mp->c,
2149                    &ctx->stats[vec_len (ctx->stats) - n_items],
2150                    n_items * sizeof (*ctx->stats));
2151
2152       _vec_len (ctx->stats) = vec_len (ctx->stats) - n_items;
2153
2154       /*
2155        * send to the shm q
2156        */
2157       svm_queue_lock (q);
2158       pause = svm_queue_is_full (q);
2159
2160       vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
2161       svm_queue_unlock (q);
2162       dsunlock (sm);
2163
2164       if (pause)
2165         ip46_fib_stats_delay (sm, 0 /* sec */ ,
2166                               STATS_RELEASE_DELAY_NS);
2167     }
2168 }
2169
2170 static void
2171 do_udp_encap_counters (stats_main_t * sm)
2172 {
2173   udp_encap_stat_t *stat;
2174
2175   udp_encap_stats_walk_t ctx = {
2176     .stats = NULL,
2177   };
2178
2179   dslock (sm, 0 /* release hint */ , 1 /* tag */ );
2180   udp_encap_walk (udp_encap_stats_walk_cb, &ctx);
2181   dsunlock (sm);
2182
2183   udp_encap_ship (&ctx);
2184 }
2185
2186 int
2187 stats_set_poller_delay (u32 poller_delay_sec)
2188 {
2189   stats_main_t *sm = &stats_main;
2190   if (!poller_delay_sec)
2191     {
2192       return VNET_API_ERROR_INVALID_ARGUMENT;
2193     }
2194   else
2195     {
2196       sm->stats_poll_interval_in_seconds = poller_delay_sec;
2197       return 0;
2198     }
2199 }
2200
2201 static clib_error_t *
2202 stats_config (vlib_main_t * vm, unformat_input_t * input)
2203 {
2204   u32 sec;
2205
2206   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2207     {
2208       if (unformat (input, "interval %u", &sec))
2209         {
2210           int rv = stats_set_poller_delay (sec);
2211           if (rv)
2212             {
2213               return clib_error_return (0,
2214                                         "`stats_set_poller_delay' API call failed, rv=%d:%U",
2215                                         (int) rv, format_vnet_api_errno, rv);
2216             }
2217           return 0;
2218         }
2219       else
2220         {
2221           return clib_error_return (0, "unknown input '%U'",
2222                                     format_unformat_error, input);
2223         }
2224     }
2225   return 0;
2226 }
2227
2228 /* stats { ... } configuration. */
2229 /*?
2230  *
2231  * @cfgcmd{interval, &lt;seconds&gt;}
2232  * Configure stats poller delay to be @c seconds.
2233  *
2234 ?*/
2235 VLIB_CONFIG_FUNCTION (stats_config, "stats");
2236
2237 static void
2238   vl_api_stats_get_poller_delay_t_handler
2239   (vl_api_stats_get_poller_delay_t * mp)
2240 {
2241   stats_main_t *sm = &stats_main;
2242   vl_api_registration_t *reg;
2243   reg = vl_api_client_index_to_registration (mp->client_index);
2244   if (!reg)
2245     return;
2246   vl_api_stats_get_poller_delay_reply_t *rmp;
2247
2248   rmp = vl_msg_api_alloc (sizeof (*rmp));
2249   rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
2250   rmp->context = mp->context;
2251   rmp->retval = 0;
2252   rmp->delay = clib_host_to_net_u32 (sm->stats_poll_interval_in_seconds);
2253
2254   vl_api_send_msg (reg, (u8 *) rmp);
2255
2256 }
2257
2258 static void
2259 stats_thread_fn (void *arg)
2260 {
2261   stats_main_t *sm = &stats_main;
2262   vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
2263   vlib_thread_main_t *tm = vlib_get_thread_main ();
2264
2265   /* stats thread wants no signals. */
2266   {
2267     sigset_t s;
2268     sigfillset (&s);
2269     pthread_sigmask (SIG_SETMASK, &s, 0);
2270   }
2271
2272   if (vec_len (tm->thread_prefix))
2273     vlib_set_thread_name ((char *)
2274                           format (0, "%v_stats%c", tm->thread_prefix, '\0'));
2275
2276   clib_mem_set_heap (w->thread_mheap);
2277
2278   while (1)
2279     {
2280       ip46_fib_stats_delay (sm, sm->stats_poll_interval_in_seconds,
2281                             0 /* nsec */ );
2282
2283       if (!(sm->enable_poller))
2284         {
2285           continue;
2286         }
2287       if (pool_elts
2288           (sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS]))
2289         do_combined_per_interface_counters (sm);
2290
2291       if (pool_elts
2292           (sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS]))
2293         do_simple_per_interface_counters (sm);
2294
2295       if (pool_elts (sm->stats_registrations[IDX_IP4_FIB_COUNTERS]))
2296         do_ip4_fib_counters (sm);
2297
2298       if (pool_elts (sm->stats_registrations[IDX_IP6_FIB_COUNTERS]))
2299         do_ip6_fib_counters (sm);
2300
2301       if (pool_elts (sm->stats_registrations[IDX_IP4_MFIB_COUNTERS]))
2302         do_ip4_mfib_counters (sm);
2303
2304       if (pool_elts (sm->stats_registrations[IDX_IP6_MFIB_COUNTERS]))
2305         do_ip6_mfib_counters (sm);
2306
2307       if (pool_elts (sm->stats_registrations[IDX_IP4_NBR_COUNTERS]))
2308         do_ip4_nbr_counters (sm);
2309
2310       if (pool_elts (sm->stats_registrations[IDX_IP6_NBR_COUNTERS]))
2311         do_ip6_nbr_counters (sm);
2312
2313       if (pool_elts (sm->stats_registrations[IDX_UDP_ENCAP_COUNTERS]))
2314         do_udp_encap_counters (sm);
2315     }
2316 }
2317
2318 static void
2319   vl_api_vnet_interface_simple_counters_t_handler
2320   (vl_api_vnet_interface_simple_counters_t * mp)
2321 {
2322   vpe_client_registration_t *clients, client;
2323   stats_main_t *sm = &stats_main;
2324   vl_api_registration_t *reg, *reg_prev = NULL;
2325   vl_api_vnet_interface_simple_counters_t *mp_copy = NULL;
2326   u32 mp_size;
2327   int i;
2328
2329   mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (u64));
2330
2331   clients =
2332     get_clients_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
2333                           ~0 /*flag for all */ );
2334
2335   for (i = 0; i < vec_len (clients); i++)
2336     {
2337       client = clients[i];
2338       reg = vl_api_client_index_to_registration (client.client_index);
2339       if (reg)
2340         {
2341           if (reg_prev && vl_api_can_send_msg (reg_prev))
2342             {
2343               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2344               clib_memcpy (mp_copy, mp, mp_size);
2345               vl_api_send_msg (reg_prev, (u8 *) mp);
2346               mp = mp_copy;
2347             }
2348           reg_prev = reg;
2349         }
2350       else
2351         {
2352           sm->enable_poller =
2353             clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, ~0,
2354                                    client.client_index);
2355           continue;
2356         }
2357     }
2358
2359 #if STATS_DEBUG > 0
2360   fformat (stdout, "%U\n", format_vnet_simple_counters, mp);
2361 #endif
2362
2363   if (reg_prev && vl_api_can_send_msg (reg_prev))
2364     {
2365       vl_api_send_msg (reg_prev, (u8 *) mp);
2366     }
2367   else
2368     {
2369       vl_msg_api_free (mp);
2370     }
2371 }
2372
2373 static void
2374 vl_api_vnet_ip4_fib_counters_t_handler (vl_api_vnet_ip4_fib_counters_t * mp)
2375 {
2376   stats_main_t *sm = &stats_main;
2377   vl_api_registration_t *reg, *reg_prev = NULL;
2378   vl_api_vnet_ip4_fib_counters_t *mp_copy = NULL;
2379   u32 mp_size;
2380   vpe_client_registration_t *clients, client;
2381   int i;
2382
2383   mp_size = sizeof (*mp_copy) +
2384     ntohl (mp->count) * sizeof (vl_api_ip4_fib_counter_t);
2385
2386   clients =
2387     get_clients_for_stat (IDX_IP4_FIB_COUNTERS, ~0 /*flag for all */ );
2388
2389   for (i = 0; i < vec_len (clients); i++)
2390     {
2391       client = clients[i];
2392       reg = vl_api_client_index_to_registration (client.client_index);
2393       if (reg)
2394         {
2395           if (reg_prev && vl_api_can_send_msg (reg_prev))
2396             {
2397               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2398               clib_memcpy (mp_copy, mp, mp_size);
2399               vl_api_send_msg (reg_prev, (u8 *) mp);
2400               mp = mp_copy;
2401             }
2402           reg_prev = reg;
2403         }
2404       else
2405         {
2406           sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
2407                                                      ~0, client.client_index);
2408           continue;
2409         }
2410     }
2411
2412   if (reg_prev && vl_api_can_send_msg (reg_prev))
2413     {
2414       vl_api_send_msg (reg_prev, (u8 *) mp);
2415     }
2416   else
2417     {
2418       vl_msg_api_free (mp);
2419     }
2420 }
2421
2422 static void
2423 vl_api_vnet_ip4_nbr_counters_t_handler (vl_api_vnet_ip4_nbr_counters_t * mp)
2424 {
2425   stats_main_t *sm = &stats_main;
2426   vl_api_registration_t *reg, *reg_prev = NULL;
2427   vl_api_vnet_ip4_nbr_counters_t *mp_copy = NULL;
2428   u32 mp_size;
2429   vpe_client_registration_t *clients, client;
2430   int i;
2431
2432   mp_size = sizeof (*mp_copy) +
2433     ntohl (mp->count) * sizeof (vl_api_ip4_nbr_counter_t);
2434
2435   clients =
2436     get_clients_for_stat (IDX_IP4_NBR_COUNTERS, ~0 /*flag for all */ );
2437
2438   for (i = 0; i < vec_len (clients); i++)
2439     {
2440       client = clients[i];
2441       reg = vl_api_client_index_to_registration (client.client_index);
2442       if (reg)
2443         {
2444           if (reg_prev && vl_api_can_send_msg (reg_prev))
2445             {
2446               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2447               clib_memcpy (mp_copy, mp, mp_size);
2448               vl_api_send_msg (reg_prev, (u8 *) mp);
2449               mp = mp_copy;
2450             }
2451           reg_prev = reg;
2452         }
2453       else
2454         {
2455           sm->enable_poller = clear_client_for_stat (IDX_IP4_NBR_COUNTERS,
2456                                                      ~0, client.client_index);
2457           continue;
2458         }
2459     }
2460
2461   /* *INDENT-ON* */
2462   if (reg_prev && vl_api_can_send_msg (reg_prev))
2463     {
2464       vl_api_send_msg (reg_prev, (u8 *) mp);
2465     }
2466   else
2467     {
2468       vl_msg_api_free (mp);
2469     }
2470 }
2471
2472 static void
2473 vl_api_vnet_ip6_fib_counters_t_handler (vl_api_vnet_ip6_fib_counters_t * mp)
2474 {
2475   stats_main_t *sm = &stats_main;
2476   vl_api_registration_t *reg, *reg_prev = NULL;
2477   vl_api_vnet_ip6_fib_counters_t *mp_copy = NULL;
2478   u32 mp_size;
2479   vpe_client_registration_t *clients, client;
2480   int i;
2481
2482   mp_size = sizeof (*mp_copy) +
2483     ntohl (mp->count) * sizeof (vl_api_ip6_fib_counter_t);
2484
2485   clients =
2486     get_clients_for_stat (IDX_IP6_FIB_COUNTERS, ~0 /*flag for all */ );
2487
2488   for (i = 0; i < vec_len (clients); i++)
2489     {
2490       client = clients[i];
2491       reg = vl_api_client_index_to_registration (client.client_index);
2492       if (reg)
2493         {
2494           if (reg_prev && vl_api_can_send_msg (reg_prev))
2495             {
2496               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2497               clib_memcpy (mp_copy, mp, mp_size);
2498               vl_api_send_msg (reg_prev, (u8 *) mp);
2499               mp = mp_copy;
2500             }
2501           reg_prev = reg;
2502         }
2503       else
2504         {
2505           sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2506                                                      ~0, client.client_index);
2507           continue;
2508         }
2509     }
2510   /* *INDENT-ON* */
2511   if (reg_prev && vl_api_can_send_msg (reg_prev))
2512     {
2513       vl_api_send_msg (reg_prev, (u8 *) mp);
2514     }
2515   else
2516     {
2517       vl_msg_api_free (mp);
2518     }
2519 }
2520
2521 static void
2522 vl_api_vnet_ip6_nbr_counters_t_handler (vl_api_vnet_ip6_nbr_counters_t * mp)
2523 {
2524   stats_main_t *sm = &stats_main;
2525   vl_api_registration_t *reg, *reg_prev = NULL;
2526   vl_api_vnet_ip6_nbr_counters_t *mp_copy = NULL;
2527   u32 mp_size;
2528   vpe_client_registration_t *clients, client;
2529   int i;
2530
2531   mp_size = sizeof (*mp_copy) +
2532     ntohl (mp->count) * sizeof (vl_api_ip6_nbr_counter_t);
2533
2534   clients =
2535     get_clients_for_stat (IDX_IP6_NBR_COUNTERS, ~0 /*flag for all */ );
2536
2537   for (i = 0; i < vec_len (clients); i++)
2538     {
2539       client = clients[i];
2540       reg = vl_api_client_index_to_registration (client.client_index);
2541       if (reg)
2542         {
2543           if (reg_prev && vl_api_can_send_msg (reg_prev))
2544             {
2545               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2546               clib_memcpy (mp_copy, mp, mp_size);
2547               vl_api_send_msg (reg_prev, (u8 *) mp);
2548               mp = mp_copy;
2549             }
2550           reg_prev = reg;
2551         }
2552       else
2553         {
2554           sm->enable_poller = clear_client_for_stat (IDX_IP6_NBR_COUNTERS,
2555                                                      ~0, client.client_index);
2556           continue;
2557         }
2558     }
2559   /* *INDENT-ON* */
2560   if (reg_prev && vl_api_can_send_msg (reg_prev))
2561     {
2562       vl_api_send_msg (reg_prev, (u8 *) mp);
2563     }
2564   else
2565     {
2566       vl_msg_api_free (mp);
2567     }
2568 }
2569
2570 static void
2571 vl_api_want_udp_encap_stats_t_handler (vl_api_want_udp_encap_stats_t * mp)
2572 {
2573   stats_main_t *sm = &stats_main;
2574   vpe_client_registration_t rp;
2575   vl_api_want_udp_encap_stats_reply_t *rmp;
2576   uword *p;
2577   i32 retval = 0;
2578   vl_api_registration_t *reg;
2579   u32 fib;
2580
2581   fib = ~0;                     //Using same mechanism as _per_interface_
2582   rp.client_index = mp->client_index;
2583   rp.client_pid = mp->pid;
2584
2585   handle_client_registration (&rp, IDX_UDP_ENCAP_COUNTERS, fib, mp->enable);
2586
2587 reply:
2588   reg = vl_api_client_index_to_registration (mp->client_index);
2589
2590   if (!reg)
2591     {
2592       sm->enable_poller = clear_client_for_stat (IDX_UDP_ENCAP_COUNTERS,
2593                                                  fib, mp->client_index);
2594       return;
2595     }
2596
2597   rmp = vl_msg_api_alloc (sizeof (*rmp));
2598   rmp->_vl_msg_id = ntohs (VL_API_WANT_UDP_ENCAP_STATS_REPLY);
2599   rmp->context = mp->context;
2600   rmp->retval = retval;
2601
2602   vl_api_send_msg (reg, (u8 *) rmp);
2603 }
2604
2605 static void
2606 vl_api_want_stats_t_handler (vl_api_want_stats_t * mp)
2607 {
2608   stats_main_t *sm = &stats_main;
2609   vpe_client_registration_t rp;
2610   vl_api_want_stats_reply_t *rmp;
2611   uword *p;
2612   i32 retval = 0;
2613   u32 item;
2614   vl_api_registration_t *reg;
2615
2616   item = ~0;                    //"ALL THE THINGS IN THE THINGS
2617   rp.client_index = mp->client_index;
2618   rp.client_pid = mp->pid;
2619
2620   handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
2621                               item, mp->enable_disable);
2622
2623   handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
2624                               item, mp->enable_disable);
2625
2626   handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS,
2627                               item, mp->enable_disable);
2628
2629   handle_client_registration (&rp, IDX_IP4_NBR_COUNTERS,
2630                               item, mp->enable_disable);
2631
2632   handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS,
2633                               item, mp->enable_disable);
2634
2635   handle_client_registration (&rp, IDX_IP6_NBR_COUNTERS,
2636                               item, mp->enable_disable);
2637
2638 reply:
2639   reg = vl_api_client_index_to_registration (mp->client_index);
2640   if (!reg)
2641     return;
2642
2643   rmp = vl_msg_api_alloc (sizeof (*rmp));
2644   rmp->_vl_msg_id = ntohs (VL_API_WANT_STATS_REPLY);
2645   rmp->context = mp->context;
2646   rmp->retval = retval;
2647
2648   vl_api_send_msg (reg, (u8 *) rmp);
2649 }
2650
2651 static void
2652   vl_api_want_interface_simple_stats_t_handler
2653   (vl_api_want_interface_simple_stats_t * mp)
2654 {
2655   stats_main_t *sm = &stats_main;
2656   vpe_client_registration_t rp;
2657   vl_api_want_interface_simple_stats_reply_t *rmp;
2658   uword *p;
2659   i32 retval = 0;
2660   u32 swif;
2661   vl_api_registration_t *reg;
2662
2663   swif = ~0;                    //Using same mechanism as _per_interface_
2664   rp.client_index = mp->client_index;
2665   rp.client_pid = mp->pid;
2666
2667   handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2668                               mp->enable_disable);
2669
2670 reply:
2671   reg = vl_api_client_index_to_registration (mp->client_index);
2672
2673   if (!reg)
2674     {
2675       sm->enable_poller =
2676         clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2677                                mp->client_index);
2678       return;
2679     }
2680
2681   rmp = vl_msg_api_alloc (sizeof (*rmp));
2682   rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_SIMPLE_STATS_REPLY);
2683   rmp->context = mp->context;
2684   rmp->retval = retval;
2685
2686   vl_api_send_msg (reg, (u8 *) rmp);
2687 }
2688
2689
2690 static void
2691 vl_api_want_ip4_fib_stats_t_handler (vl_api_want_ip4_fib_stats_t * mp)
2692 {
2693   stats_main_t *sm = &stats_main;
2694   vpe_client_registration_t rp;
2695   vl_api_want_ip4_fib_stats_reply_t *rmp;
2696   uword *p;
2697   i32 retval = 0;
2698   vl_api_registration_t *reg;
2699   u32 fib;
2700
2701   fib = ~0;                     //Using same mechanism as _per_interface_
2702   rp.client_index = mp->client_index;
2703   rp.client_pid = mp->pid;
2704
2705   handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS, fib,
2706                               mp->enable_disable);
2707
2708 reply:
2709   reg = vl_api_client_index_to_registration (mp->client_index);
2710
2711   if (!reg)
2712     {
2713       sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
2714                                                  fib, mp->client_index);
2715       return;
2716     }
2717
2718   rmp = vl_msg_api_alloc (sizeof (*rmp));
2719   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_FIB_STATS_REPLY);
2720   rmp->context = mp->context;
2721   rmp->retval = retval;
2722
2723   vl_api_send_msg (reg, (u8 *) rmp);
2724 }
2725
2726 static void
2727 vl_api_want_ip4_mfib_stats_t_handler (vl_api_want_ip4_mfib_stats_t * mp)
2728 {
2729   stats_main_t *sm = &stats_main;
2730   vpe_client_registration_t rp;
2731   vl_api_want_ip4_mfib_stats_reply_t *rmp;
2732   uword *p;
2733   i32 retval = 0;
2734   vl_api_registration_t *reg;
2735   u32 mfib;
2736
2737   mfib = ~0;                    //Using same mechanism as _per_interface_
2738   rp.client_index = mp->client_index;
2739   rp.client_pid = mp->pid;
2740
2741   handle_client_registration (&rp, IDX_IP4_MFIB_COUNTERS, mfib,
2742                               mp->enable_disable);
2743
2744 reply:
2745   reg = vl_api_client_index_to_registration (mp->client_index);
2746   if (!reg)
2747     {
2748       sm->enable_poller = clear_client_for_stat (IDX_IP4_MFIB_COUNTERS,
2749                                                  mfib, mp->client_index);
2750       return;
2751     }
2752
2753   rmp = vl_msg_api_alloc (sizeof (*rmp));
2754   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_MFIB_STATS_REPLY);
2755   rmp->context = mp->context;
2756   rmp->retval = retval;
2757
2758   vl_api_send_msg (reg, (u8 *) rmp);
2759 }
2760
2761 static void
2762 vl_api_want_ip6_fib_stats_t_handler (vl_api_want_ip6_fib_stats_t * mp)
2763 {
2764   stats_main_t *sm = &stats_main;
2765   vpe_client_registration_t rp;
2766   vl_api_want_ip4_fib_stats_reply_t *rmp;
2767   uword *p;
2768   i32 retval = 0;
2769   vl_api_registration_t *reg;
2770   u32 fib;
2771
2772   fib = ~0;                     //Using same mechanism as _per_interface_
2773   rp.client_index = mp->client_index;
2774   rp.client_pid = mp->pid;
2775
2776   handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS, fib,
2777                               mp->enable_disable);
2778
2779 reply:
2780   reg = vl_api_client_index_to_registration (mp->client_index);
2781   if (!reg)
2782     {
2783       sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2784                                                  fib, mp->client_index);
2785       return;
2786     }
2787
2788   rmp = vl_msg_api_alloc (sizeof (*rmp));
2789   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_FIB_STATS_REPLY);
2790   rmp->context = mp->context;
2791   rmp->retval = retval;
2792
2793   vl_api_send_msg (reg, (u8 *) rmp);
2794 }
2795
2796 static void
2797 vl_api_want_ip6_mfib_stats_t_handler (vl_api_want_ip6_mfib_stats_t * mp)
2798 {
2799   stats_main_t *sm = &stats_main;
2800   vpe_client_registration_t rp;
2801   vl_api_want_ip4_mfib_stats_reply_t *rmp;
2802   uword *p;
2803   i32 retval = 0;
2804   vl_api_registration_t *reg;
2805   u32 mfib;
2806
2807   mfib = ~0;                    //Using same mechanism as _per_interface_
2808   rp.client_index = mp->client_index;
2809   rp.client_pid = mp->pid;
2810
2811   handle_client_registration (&rp, IDX_IP6_MFIB_COUNTERS, mfib,
2812                               mp->enable_disable);
2813
2814 reply:
2815   reg = vl_api_client_index_to_registration (mp->client_index);
2816   if (!reg)
2817     {
2818       sm->enable_poller = clear_client_for_stat (IDX_IP6_MFIB_COUNTERS,
2819                                                  mfib, mp->client_index);
2820       return;
2821     }
2822
2823   rmp = vl_msg_api_alloc (sizeof (*rmp));
2824   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_MFIB_STATS_REPLY);
2825   rmp->context = mp->context;
2826   rmp->retval = retval;
2827
2828   vl_api_send_msg (reg, (u8 *) rmp);
2829 }
2830
2831 /* FIXME - NBR stats broken - this will be fixed in subsequent patch */
2832 static void
2833 vl_api_want_ip4_nbr_stats_t_handler (vl_api_want_ip4_nbr_stats_t * mp)
2834 {
2835 }
2836
2837 static void
2838 vl_api_want_ip6_nbr_stats_t_handler (vl_api_want_ip6_nbr_stats_t * mp)
2839 {
2840 }
2841
2842 static void
2843 vl_api_vnet_get_summary_stats_t_handler (vl_api_vnet_get_summary_stats_t * mp)
2844 {
2845   stats_main_t *sm = &stats_main;
2846   vnet_interface_main_t *im = sm->interface_main;
2847   vl_api_vnet_get_summary_stats_reply_t *rmp;
2848   vlib_combined_counter_main_t *cm;
2849   vlib_counter_t v;
2850   int i, which;
2851   u64 total_pkts[VLIB_N_RX_TX];
2852   u64 total_bytes[VLIB_N_RX_TX];
2853   vl_api_registration_t *reg;
2854
2855   reg = vl_api_client_index_to_registration (mp->client_index);
2856   if (!reg)
2857     return;
2858
2859   rmp = vl_msg_api_alloc (sizeof (*rmp));
2860   rmp->_vl_msg_id = ntohs (VL_API_VNET_GET_SUMMARY_STATS_REPLY);
2861   rmp->context = mp->context;
2862   rmp->retval = 0;
2863
2864   memset (total_pkts, 0, sizeof (total_pkts));
2865   memset (total_bytes, 0, sizeof (total_bytes));
2866
2867   vnet_interface_counter_lock (im);
2868
2869   vec_foreach (cm, im->combined_sw_if_counters)
2870   {
2871     which = cm - im->combined_sw_if_counters;
2872
2873     for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
2874       {
2875         vlib_get_combined_counter (cm, i, &v);
2876         total_pkts[which] += v.packets;
2877         total_bytes[which] += v.bytes;
2878       }
2879   }
2880   vnet_interface_counter_unlock (im);
2881
2882   rmp->total_pkts[VLIB_RX] = clib_host_to_net_u64 (total_pkts[VLIB_RX]);
2883   rmp->total_bytes[VLIB_RX] = clib_host_to_net_u64 (total_bytes[VLIB_RX]);
2884   rmp->total_pkts[VLIB_TX] = clib_host_to_net_u64 (total_pkts[VLIB_TX]);
2885   rmp->total_bytes[VLIB_TX] = clib_host_to_net_u64 (total_bytes[VLIB_TX]);
2886   rmp->vector_rate =
2887     clib_host_to_net_u64 (vlib_last_vector_length_per_node (sm->vlib_main));
2888
2889   vl_api_send_msg (reg, (u8 *) rmp);
2890 }
2891
2892 int
2893 stats_memclnt_delete_callback (u32 client_index)
2894 {
2895   vpe_client_stats_registration_t *rp;
2896   stats_main_t *sm = &stats_main;
2897   uword *p;
2898
2899   // FIXME
2900   /* p = hash_get (sm->stats_registration_hash, client_index); */
2901   /* if (p) */
2902   /*   { */
2903   /*     rp = pool_elt_at_index (sm->stats_registrations, p[0]); */
2904   /*     pool_put (sm->stats_registrations, rp); */
2905   /*     hash_unset (sm->stats_registration_hash, client_index); */
2906   /*   } */
2907
2908   return 0;
2909 }
2910
2911 #define vl_api_vnet_interface_simple_counters_t_endian vl_noop_handler
2912 #define vl_api_vnet_interface_simple_counters_t_print vl_noop_handler
2913 #define vl_api_vnet_interface_combined_counters_t_endian vl_noop_handler
2914 #define vl_api_vnet_interface_combined_counters_t_print vl_noop_handler
2915 #define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
2916 #define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
2917 #define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
2918 #define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler
2919 #define vl_api_vnet_ip4_nbr_counters_t_endian vl_noop_handler
2920 #define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
2921 #define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
2922 #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
2923
2924 static clib_error_t *
2925 stats_init (vlib_main_t * vm)
2926 {
2927   stats_main_t *sm = &stats_main;
2928   api_main_t *am = &api_main;
2929   void *vlib_worker_thread_bootstrap_fn (void *arg);
2930
2931   sm->vlib_main = vm;
2932   sm->vnet_main = vnet_get_main ();
2933   sm->interface_main = &vnet_get_main ()->interface_main;
2934   sm->api_main = am;
2935   sm->stats_poll_interval_in_seconds = 10;
2936   sm->data_structure_lock =
2937     clib_mem_alloc_aligned (sizeof (data_structure_lock_t),
2938                             CLIB_CACHE_LINE_BYTES);
2939   memset (sm->data_structure_lock, 0, sizeof (*sm->data_structure_lock));
2940
2941 #define _(N,n)                                                  \
2942     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
2943                            vl_api_##n##_t_handler,              \
2944                            vl_noop_handler,                     \
2945                            vl_api_##n##_t_endian,               \
2946                            vl_api_##n##_t_print,                \
2947                            sizeof(vl_api_##n##_t), 0 /* do NOT trace! */);
2948   foreach_stats_msg;
2949 #undef _
2950
2951   /* tell the msg infra not to free these messages... */
2952   am->message_bounce[VL_API_VNET_INTERFACE_SIMPLE_COUNTERS] = 1;
2953   am->message_bounce[VL_API_VNET_INTERFACE_COMBINED_COUNTERS] = 1;
2954   am->message_bounce[VL_API_VNET_IP4_FIB_COUNTERS] = 1;
2955   am->message_bounce[VL_API_VNET_IP6_FIB_COUNTERS] = 1;
2956   am->message_bounce[VL_API_VNET_IP4_NBR_COUNTERS] = 1;
2957   am->message_bounce[VL_API_VNET_IP6_NBR_COUNTERS] = 1;
2958
2959   /*
2960    * Set up the (msg_name, crc, message-id) table
2961    */
2962   setup_message_id_table (am);
2963
2964   vec_validate (sm->stats_registrations, STATS_REG_N_IDX);
2965   vec_validate (sm->stats_registration_hash, STATS_REG_N_IDX);
2966 #define stats_reg(n)                            \
2967   sm->stats_registrations[IDX_##n] = 0; \
2968   sm->stats_registration_hash[IDX_##n] = 0;
2969 #include <vpp/stats/stats.reg>
2970 #undef stats_reg
2971
2972   return 0;
2973 }
2974
2975 VLIB_INIT_FUNCTION (stats_init);
2976
2977 /* *INDENT-OFF* */
2978 VLIB_REGISTER_THREAD (stats_thread_reg, static) = {
2979   .name = "stats",
2980   .function = stats_thread_fn,
2981   .fixed_count = 1,
2982   .count = 1,
2983   .no_data_structure_clone = 1,
2984   .use_pthreads = 1,
2985 };
2986 /* *INDENT-ON* */
2987
2988 /*
2989  * fd.io coding-style-patch-verification: ON
2990  *
2991  * Local Variables:
2992  * eval: (c-set-style "gnu")
2993  * End:
2994  */