UDP Encap counters
[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           cm = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX;
852           vlib_get_combined_counter (cm, reg->item, &v);
853           clib_mem_unaligned (&vp->rx_packets, u64) =
854             clib_host_to_net_u64 (v.packets);
855           clib_mem_unaligned (&vp->rx_bytes, u64) =
856             clib_host_to_net_u64 (v.bytes);
857           cm = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX;
858           vlib_get_combined_counter (cm, reg->item, &v);
859           clib_mem_unaligned (&vp->tx_packets, u64) =
860             clib_host_to_net_u64 (v.packets);
861           clib_mem_unaligned (&vp->tx_bytes, u64) =
862             clib_host_to_net_u64 (v.bytes);
863
864           vl_api_send_msg (vl_reg, (u8 *) mp);
865         }
866     }
867
868   vnet_interface_counter_unlock (im);
869 }
870
871 /**********************************
872  * Per Interface simple stats
873  **********************************/
874
875 /* Request from client registering interfaces it wants */
876 static void
877   vl_api_want_per_interface_simple_stats_t_handler
878   (vl_api_want_per_interface_simple_stats_t * mp)
879 {
880   stats_main_t *sm = &stats_main;
881   vpe_client_registration_t rp;
882   vl_api_want_per_interface_simple_stats_reply_t *rmp;
883   vlib_simple_counter_main_t *cm;
884   uword *p;
885   i32 retval = 0;
886   vl_api_registration_t *reg;
887   u32 i, swif, num = 0;
888
889   num = ntohl (mp->num);
890
891   for (i = 0; i < num; i++)
892     {
893       swif = ntohl (mp->sw_ifs[i]);
894
895       /* Check its a real sw_if_index that the client is allowed to see */
896       if (swif != ~0)
897         {
898           if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
899             {
900               retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
901               goto reply;
902             }
903         }
904     }
905
906   for (i = 0; i < num; i++)
907     {
908       swif = ntohl (mp->sw_ifs[i]);
909
910       rp.client_index = mp->client_index;
911       rp.client_pid = mp->pid;
912       handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
913                                   swif, ntohl (mp->enable_disable));
914     }
915
916 reply:
917   reg = vl_api_client_index_to_registration (mp->client_index);
918
919   /* Client may have disconnected abruptly, clean up */
920   if (!reg)
921     {
922       for (i = 0; i < num; i++)
923         {
924           swif = ntohl (mp->sw_ifs[i]);
925           sm->enable_poller =
926             clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
927                                    mp->client_index);
928         }
929
930       return;
931     }
932
933
934   rmp = vl_msg_api_alloc (sizeof (*rmp));
935   rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
936   rmp->context = mp->context;
937   rmp->retval = retval;
938
939   vl_api_send_msg (reg, (u8 *) rmp);
940 }
941
942 /* Per Interface Simple distribution to client */
943 static void
944 do_simple_per_interface_counters (stats_main_t * sm)
945 {
946   vl_api_vnet_per_interface_simple_counters_t *mp = 0;
947   vnet_interface_main_t *im = sm->interface_main;
948   api_main_t *am = sm->api_main;
949   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
950   vl_api_registration_t *vl_reg;
951   vlib_simple_counter_main_t *cm;
952   u32 i, j, size;
953   vpe_client_stats_registration_t *reg;
954   vpe_client_registration_t *client;
955   u32 timestamp, count;
956   vl_api_vnet_simple_counter_t *vp = 0;
957   counter_t v;
958
959   vnet_interface_counter_lock (im);
960
961   vec_reset_length (sm->regs_tmp);
962
963   /* *INDENT-OFF* */
964   pool_foreach (reg,
965                 sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS],
966                 ({ vec_add1 (sm->regs_tmp, reg); }));
967   /* *INDENT-ON* */
968
969   for (i = 0; i < vec_len (sm->regs_tmp); i++)
970     {
971       reg = sm->regs_tmp[i];
972       if (reg->item == ~0)
973         {
974           vnet_interface_counter_unlock (im);
975           do_simple_interface_counters (sm);
976           vnet_interface_counter_lock (im);
977           continue;
978         }
979       vec_reset_length (sm->clients_tmp);
980
981       /* *INDENT-OFF* */
982       pool_foreach (client, reg->clients, ({ vec_add1 (sm->clients_tmp,
983                                                       client);}));
984       /* *INDENT-ON* */
985
986       for (j = 0; j < vec_len (sm->clients_tmp); j++)
987         {
988           client = sm->clients_tmp[j];
989           vl_reg = vl_api_client_index_to_registration (client->client_index);
990
991           /* Client may have disconnected abrubtly, clean up */
992           if (!vl_reg)
993             {
994               sm->enable_poller =
995                 clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
996                                        reg->item, client->client_index);
997               continue;
998             }
999
1000           mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + sizeof (*vp));
1001           memset (mp, 0, sizeof (*mp));
1002           mp->_vl_msg_id = ntohs (VL_API_VNET_PER_INTERFACE_SIMPLE_COUNTERS);
1003
1004           /*
1005            * count will eventually be used to optimise the batching
1006            * of per client messages for each stat. For now setting this to 1 then
1007            * iterate. This will not affect API.
1008            *
1009            * FIXME instead of enqueueing here, this should be sent to a batch
1010            * storer for per-client transmission. Each "mp" sent would be a single entry
1011            * and if a client is listening to other sw_if_indexes for same, it would be
1012            * appended to that *mp
1013            *
1014            *
1015            * FIXME(s):
1016            * - capturing the timestamp of the counters "when VPP knew them" is important.
1017            * Less so is that the timing of the delivery to the control plane be in the same
1018            * timescale.
1019
1020            * i.e. As long as the control plane can delta messages from VPP and work out
1021            * velocity etc based on the timestamp, it can do so in a more "batch mode".
1022
1023            * It would be beneficial to keep a "per-client" message queue, and then
1024            * batch all the stat messages for a client into one message, with
1025            * discrete timestamps.
1026
1027            * Given this particular API is for "per interface" one assumes that the scale
1028            * is less than the ~0 case, which the prior API is suited for.
1029            */
1030
1031           /*
1032            * 1 message per api call for now
1033            */
1034           mp->count = htonl (1);
1035           mp->timestamp = htonl (vlib_time_now (sm->vlib_main));
1036           vp = (vl_api_vnet_simple_counter_t *) mp->data;
1037
1038           vp->sw_if_index = htonl (reg->item);
1039
1040           // VNET_INTERFACE_COUNTER_DROP
1041           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
1042           v = vlib_get_simple_counter (cm, reg->item);
1043           clib_mem_unaligned (&vp->drop, u64) = clib_host_to_net_u64 (v);
1044
1045           // VNET_INTERFACE_COUNTER_PUNT
1046           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_PUNT;
1047           v = vlib_get_simple_counter (cm, reg->item);
1048           clib_mem_unaligned (&vp->punt, u64) = clib_host_to_net_u64 (v);
1049
1050           // VNET_INTERFACE_COUNTER_IP4
1051           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP4;
1052           v = vlib_get_simple_counter (cm, reg->item);
1053           clib_mem_unaligned (&vp->rx_ip4, u64) = clib_host_to_net_u64 (v);
1054
1055           //VNET_INTERFACE_COUNTER_IP6
1056           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP6;
1057           v = vlib_get_simple_counter (cm, reg->item);
1058           clib_mem_unaligned (&vp->rx_ip6, u64) = clib_host_to_net_u64 (v);
1059
1060           //VNET_INTERFACE_COUNTER_RX_NO_BUF
1061           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_NO_BUF;
1062           v = vlib_get_simple_counter (cm, reg->item);
1063           clib_mem_unaligned (&vp->rx_no_buffer, u64) =
1064             clib_host_to_net_u64 (v);
1065
1066           //VNET_INTERFACE_COUNTER_RX_MISS
1067           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_MISS;
1068           v = vlib_get_simple_counter (cm, reg->item);
1069           clib_mem_unaligned (&vp->rx_miss, u64) = clib_host_to_net_u64 (v);
1070
1071           //VNET_INTERFACE_COUNTER_RX_ERROR
1072           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_ERROR;
1073           v = vlib_get_simple_counter (cm, reg->item);
1074           clib_mem_unaligned (&vp->rx_error, u64) = clib_host_to_net_u64 (v);
1075
1076           //VNET_INTERFACE_COUNTER_TX_ERROR
1077           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_TX_ERROR;
1078           v = vlib_get_simple_counter (cm, reg->item);
1079           clib_mem_unaligned (&vp->tx_error, u64) = clib_host_to_net_u64 (v);
1080
1081           //VNET_INTERFACE_COUNTER_MPLS
1082           cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_MPLS;
1083           v = vlib_get_simple_counter (cm, reg->item);
1084           clib_mem_unaligned (&vp->rx_mpls, u64) = clib_host_to_net_u64 (v);
1085
1086           vl_api_send_msg (vl_reg, (u8 *) mp);
1087         }
1088     }
1089
1090   vnet_interface_counter_unlock (im);
1091 }
1092
1093 /**********************************
1094  * Per FIB IP4 stats
1095  **********************************/
1096
1097 static void
1098 ip46_fib_stats_delay (stats_main_t * sm, u32 sec, u32 nsec)
1099 {
1100   struct timespec _req, *req = &_req;
1101   struct timespec _rem, *rem = &_rem;
1102
1103   req->tv_sec = sec;
1104   req->tv_nsec = nsec;
1105   while (1)
1106     {
1107       if (nanosleep (req, rem) == 0)
1108         break;
1109       *req = *rem;
1110       if (errno == EINTR)
1111         continue;
1112       clib_unix_warning ("nanosleep");
1113       break;
1114     }
1115 }
1116
1117 /**
1118  * @brief The context passed when collecting adjacency counters
1119  */
1120 typedef struct ip4_nbr_stats_ctx_t_
1121 {
1122   /**
1123    * The SW IF index all these adjs belong to
1124    */
1125   u32 sw_if_index;
1126
1127   /**
1128    * A vector of ip4 nbr counters
1129    */
1130   vl_api_ip4_nbr_counter_t *counters;
1131 } ip4_nbr_stats_ctx_t;
1132
1133 static adj_walk_rc_t
1134 ip4_nbr_stats_cb (adj_index_t ai, void *arg)
1135 {
1136   vl_api_ip4_nbr_counter_t *vl_counter;
1137   vlib_counter_t adj_counter;
1138   ip4_nbr_stats_ctx_t *ctx;
1139   ip_adjacency_t *adj;
1140
1141   ctx = arg;
1142   vlib_get_combined_counter (&adjacency_counters, ai, &adj_counter);
1143
1144   if (0 != adj_counter.packets)
1145     {
1146       vec_add2 (ctx->counters, vl_counter, 1);
1147       adj = adj_get (ai);
1148
1149       vl_counter->packets = clib_host_to_net_u64 (adj_counter.packets);
1150       vl_counter->bytes = clib_host_to_net_u64 (adj_counter.bytes);
1151       vl_counter->address = adj->sub_type.nbr.next_hop.ip4.as_u32;
1152       vl_counter->link_type = adj->ia_link;
1153     }
1154   return (ADJ_WALK_RC_CONTINUE);
1155 }
1156
1157 #define MIN(x,y) (((x)<(y))?(x):(y))
1158
1159 static void
1160 ip4_nbr_ship (stats_main_t * sm, ip4_nbr_stats_ctx_t * ctx)
1161 {
1162   api_main_t *am = sm->api_main;
1163   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1164   svm_queue_t *q = shmem_hdr->vl_input_queue;
1165   vl_api_vnet_ip4_nbr_counters_t *mp = 0;
1166   int first = 0;
1167
1168   /*
1169    * If the walk context has counters, which may be left over from the last
1170    * suspend, then we continue from there.
1171    */
1172   while (0 != vec_len (ctx->counters))
1173     {
1174       u32 n_items = MIN (vec_len (ctx->counters),
1175                          IP4_FIB_COUNTER_BATCH_SIZE);
1176       u8 pause = 0;
1177
1178       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1179
1180       mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
1181                                           (n_items *
1182                                            sizeof
1183                                            (vl_api_ip4_nbr_counter_t)));
1184       mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_NBR_COUNTERS);
1185       mp->count = ntohl (n_items);
1186       mp->sw_if_index = ntohl (ctx->sw_if_index);
1187       mp->begin = first;
1188       first = 0;
1189
1190       /*
1191        * copy the counters from the back of the context, then we can easily
1192        * 'erase' them by resetting the vector length.
1193        * The order we push the stats to the caller is not important.
1194        */
1195       clib_memcpy (mp->c,
1196                    &ctx->counters[vec_len (ctx->counters) - n_items],
1197                    n_items * sizeof (*ctx->counters));
1198
1199       _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
1200
1201       /*
1202        * send to the shm q
1203        */
1204       svm_queue_lock (q);
1205       pause = svm_queue_is_full (q);
1206
1207       vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1208       svm_queue_unlock (q);
1209       dsunlock (sm);
1210
1211       if (pause)
1212         ip46_fib_stats_delay (sm, 0 /* sec */ ,
1213                               STATS_RELEASE_DELAY_NS);
1214     }
1215 }
1216
1217 static void
1218 do_ip4_nbr_counters (stats_main_t * sm)
1219 {
1220   vnet_main_t *vnm = vnet_get_main ();
1221   vnet_interface_main_t *im = &vnm->interface_main;
1222   vnet_sw_interface_t *si;
1223
1224   ip4_nbr_stats_ctx_t ctx = {
1225     .sw_if_index = 0,
1226     .counters = NULL,
1227   };
1228
1229   /* *INDENT-OFF* */
1230   pool_foreach (si, im->sw_interfaces,
1231   ({
1232     /*
1233      * update the interface we are now concerned with
1234      */
1235     ctx.sw_if_index = si->sw_if_index;
1236
1237     /*
1238      * we are about to walk another interface, so we shouldn't have any pending
1239      * stats to export.
1240      */
1241     ASSERT(ctx.counters == NULL);
1242
1243     /*
1244      * visit each neighbour adjacency on the interface and collect
1245      * its current stats.
1246      * Because we hold the lock the walk is synchronous, so safe to routing
1247      * updates. It's limited in work by the number of adjacenies on an
1248      * interface, which is typically not huge.
1249      */
1250     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1251     adj_nbr_walk (si->sw_if_index,
1252                   FIB_PROTOCOL_IP4,
1253                   ip4_nbr_stats_cb,
1254                   &ctx);
1255     dsunlock (sm);
1256
1257     /*
1258      * if this interface has some adjacencies with counters then ship them,
1259      * else continue to the next interface.
1260      */
1261     if (NULL != ctx.counters)
1262       {
1263         ip4_nbr_ship(sm, &ctx);
1264       }
1265   }));
1266   /* *INDENT-OFF* */
1267 }
1268
1269 /**
1270  * @brief The context passed when collecting adjacency counters
1271  */
1272 typedef struct ip6_nbr_stats_ctx_t_
1273 {
1274   /**
1275    * The SW IF index all these adjs belong to
1276    */
1277   u32 sw_if_index;
1278
1279   /**
1280    * A vector of ip6 nbr counters
1281    */
1282   vl_api_ip6_nbr_counter_t *counters;
1283 } ip6_nbr_stats_ctx_t;
1284
1285 static adj_walk_rc_t
1286 ip6_nbr_stats_cb (adj_index_t ai,
1287                   void *arg)
1288 {
1289   vl_api_ip6_nbr_counter_t *vl_counter;
1290   vlib_counter_t adj_counter;
1291   ip6_nbr_stats_ctx_t *ctx;
1292   ip_adjacency_t *adj;
1293
1294   ctx = arg;
1295   vlib_get_combined_counter(&adjacency_counters, ai, &adj_counter);
1296
1297   if (0 != adj_counter.packets)
1298     {
1299       vec_add2(ctx->counters, vl_counter, 1);
1300       adj = adj_get(ai);
1301
1302       vl_counter->packets = clib_host_to_net_u64(adj_counter.packets);
1303       vl_counter->bytes   = clib_host_to_net_u64(adj_counter.bytes);
1304       vl_counter->address[0] = adj->sub_type.nbr.next_hop.ip6.as_u64[0];
1305       vl_counter->address[1] = adj->sub_type.nbr.next_hop.ip6.as_u64[1];
1306       vl_counter->link_type = adj->ia_link;
1307     }
1308   return (ADJ_WALK_RC_CONTINUE);
1309 }
1310
1311 #define MIN(x,y) (((x)<(y))?(x):(y))
1312
1313 static void
1314 ip6_nbr_ship (stats_main_t * sm,
1315               ip6_nbr_stats_ctx_t *ctx)
1316 {
1317   api_main_t *am = sm->api_main;
1318   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1319   svm_queue_t *q = shmem_hdr->vl_input_queue;
1320   vl_api_vnet_ip6_nbr_counters_t *mp = 0;
1321   int first = 0;
1322
1323   /*
1324    * If the walk context has counters, which may be left over from the last
1325    * suspend, then we continue from there.
1326    */
1327   while (0 != vec_len(ctx->counters))
1328     {
1329       u32 n_items = MIN (vec_len (ctx->counters),
1330                          IP6_FIB_COUNTER_BATCH_SIZE);
1331       u8 pause = 0;
1332
1333       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1334
1335       mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
1336                                           (n_items *
1337                                            sizeof
1338                                            (vl_api_ip6_nbr_counter_t)));
1339       mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_NBR_COUNTERS);
1340       mp->count = ntohl (n_items);
1341       mp->sw_if_index = ntohl (ctx->sw_if_index);
1342       mp->begin = first;
1343       first = 0;
1344
1345       /*
1346        * copy the counters from the back of the context, then we can easily
1347        * 'erase' them by resetting the vector length.
1348        * The order we push the stats to the caller is not important.
1349        */
1350       clib_memcpy (mp->c,
1351                    &ctx->counters[vec_len (ctx->counters) - n_items],
1352                    n_items * sizeof (*ctx->counters));
1353
1354       _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
1355
1356       /*
1357        * send to the shm q
1358        */
1359       svm_queue_lock (q);
1360       pause = svm_queue_is_full (q);
1361
1362       vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1363       svm_queue_unlock (q);
1364       dsunlock (sm);
1365
1366       if (pause)
1367         ip46_fib_stats_delay (sm, 0 /* sec */ ,
1368                               STATS_RELEASE_DELAY_NS);
1369     }
1370 }
1371
1372 static void
1373 do_ip6_nbr_counters (stats_main_t * sm)
1374 {
1375   vnet_main_t *vnm = vnet_get_main ();
1376   vnet_interface_main_t *im = &vnm->interface_main;
1377   vnet_sw_interface_t *si;
1378
1379   ip6_nbr_stats_ctx_t ctx = {
1380     .sw_if_index = 0,
1381     .counters = NULL,
1382   };
1383
1384   /* *INDENT-OFF* */
1385   pool_foreach (si, im->sw_interfaces,
1386   ({
1387     /*
1388      * update the interface we are now concerned with
1389      */
1390     ctx.sw_if_index = si->sw_if_index;
1391
1392     /*
1393      * we are about to walk another interface, so we shouldn't have any pending
1394      * stats to export.
1395      */
1396     ASSERT(ctx.counters == NULL);
1397
1398     /*
1399      * visit each neighbour adjacency on the interface and collect
1400      * its current stats.
1401      * Because we hold the lock the walk is synchronous, so safe to routing
1402      * updates. It's limited in work by the number of adjacenies on an
1403      * interface, which is typically not huge.
1404      */
1405     dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1406     adj_nbr_walk (si->sw_if_index,
1407                   FIB_PROTOCOL_IP6,
1408                   ip6_nbr_stats_cb,
1409                   &ctx);
1410     dsunlock (sm);
1411
1412     /*
1413      * if this interface has some adjacencies with counters then ship them,
1414      * else continue to the next interface.
1415      */
1416     if (NULL != ctx.counters)
1417       {
1418         ip6_nbr_ship(sm, &ctx);
1419       }
1420   }));
1421   /* *INDENT-OFF* */
1422 }
1423
1424 static void
1425 do_ip4_fib_counters (stats_main_t * sm)
1426 {
1427   ip4_main_t *im4 = &ip4_main;
1428   api_main_t *am = sm->api_main;
1429   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1430   svm_queue_t *q = shmem_hdr->vl_input_queue;
1431   ip4_route_t *r;
1432   fib_table_t *fib;
1433   ip4_fib_t *v4_fib;
1434   do_ip46_fibs_t *do_fibs;
1435   vl_api_vnet_ip4_fib_counters_t *mp = 0;
1436   u32 items_this_message;
1437   vl_api_ip4_fib_counter_t *ctrp = 0;
1438   u32 start_at_fib_index = 0;
1439   int i, j, k;
1440
1441   do_fibs = &sm->do_ip46_fibs;
1442
1443 again:
1444   vec_reset_length (do_fibs->fibs);
1445   /* *INDENT-OFF* */
1446   pool_foreach (fib, im4->fibs,
1447                 ({vec_add1(do_fibs->fibs,fib);}));
1448
1449   /* *INDENT-ON* */
1450
1451   for (j = 0; j < vec_len (do_fibs->fibs); j++)
1452     {
1453       fib = do_fibs->fibs[j];
1454       /* We may have bailed out due to control-plane activity */
1455       while ((fib - im4->fibs) < start_at_fib_index)
1456         continue;
1457
1458       v4_fib = pool_elt_at_index (im4->v4_fibs, fib->ft_index);
1459
1460       if (mp == 0)
1461         {
1462           items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
1463           mp = vl_msg_api_alloc_as_if_client
1464             (sizeof (*mp) +
1465              items_this_message * sizeof (vl_api_ip4_fib_counter_t));
1466           mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
1467           mp->count = 0;
1468           mp->vrf_id = ntohl (fib->ft_table_id);
1469           ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1470         }
1471       else
1472         {
1473           /* happens if the last FIB was empty... */
1474           ASSERT (mp->count == 0);
1475           mp->vrf_id = ntohl (fib->ft_table_id);
1476         }
1477
1478       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1479
1480       vec_reset_length (do_fibs->ip4routes);
1481       vec_reset_length (do_fibs->results);
1482
1483       for (i = 0; i < ARRAY_LEN (v4_fib->fib_entry_by_dst_address); i++)
1484         {
1485           uword *hash = v4_fib->fib_entry_by_dst_address[i];
1486           hash_pair_t *p;
1487           ip4_route_t x;
1488
1489           vec_reset_length (do_fibs->pvec);
1490
1491           x.address_length = i;
1492
1493           hash_foreach_pair (p, hash, (
1494                                         {
1495                                         vec_add1 (do_fibs->pvec, p);}
1496                              ));
1497           for (k = 0; k < vec_len (do_fibs->pvec); k++)
1498             {
1499               p = do_fibs->pvec[k];
1500               x.address.data_u32 = p->key;
1501               x.index = p->value[0];
1502
1503               vec_add1 (do_fibs->ip4routes, x);
1504               if (sm->data_structure_lock->release_hint)
1505                 {
1506                   start_at_fib_index = fib - im4->fibs;
1507                   dsunlock (sm);
1508                   ip46_fib_stats_delay (sm, 0 /* sec */ ,
1509                                         STATS_RELEASE_DELAY_NS);
1510                   mp->count = 0;
1511                   ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1512                   goto again;
1513                 }
1514             }
1515         }
1516
1517       vec_foreach (r, do_fibs->ip4routes)
1518       {
1519         vlib_counter_t c;
1520         const dpo_id_t *dpo_id;
1521         u32 index;
1522
1523         dpo_id = fib_entry_contribute_ip_forwarding (r->index);
1524         index = (u32) dpo_id->dpoi_index;
1525
1526         vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
1527                                    index, &c);
1528         /*
1529          * If it has actually
1530          * seen at least one packet, send it.
1531          */
1532         if (c.packets > 0)
1533           {
1534
1535             /* already in net byte order */
1536             ctrp->address = r->address.as_u32;
1537             ctrp->address_length = r->address_length;
1538             ctrp->packets = clib_host_to_net_u64 (c.packets);
1539             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1540             mp->count++;
1541             ctrp++;
1542
1543             if (mp->count == items_this_message)
1544               {
1545                 mp->count = htonl (items_this_message);
1546                 /*
1547                  * If the main thread's input queue is stuffed,
1548                  * drop the data structure lock (which the main thread
1549                  * may want), and take a pause.
1550                  */
1551                 svm_queue_lock (q);
1552                 if (svm_queue_is_full (q))
1553                   {
1554                     dsunlock (sm);
1555                     vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1556                     svm_queue_unlock (q);
1557                     mp = 0;
1558                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
1559                                           STATS_RELEASE_DELAY_NS);
1560                     goto again;
1561                   }
1562                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1563                 svm_queue_unlock (q);
1564
1565                 items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
1566                 mp = vl_msg_api_alloc_as_if_client
1567                   (sizeof (*mp) +
1568                    items_this_message * sizeof (vl_api_ip4_fib_counter_t));
1569                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
1570                 mp->count = 0;
1571                 mp->vrf_id = ntohl (fib->ft_table_id);
1572                 ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1573               }
1574           }                     /* for each (mp or single) adj */
1575         if (sm->data_structure_lock->release_hint)
1576           {
1577             start_at_fib_index = fib - im4->fibs;
1578             dsunlock (sm);
1579             ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
1580             mp->count = 0;
1581             ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1582             goto again;
1583           }
1584       }                         /* vec_foreach (routes) */
1585
1586       dsunlock (sm);
1587
1588       /* Flush any data from this fib */
1589       if (mp->count)
1590         {
1591           mp->count = htonl (mp->count);
1592           vl_msg_api_send_shmem (q, (u8 *) & mp);
1593           mp = 0;
1594         }
1595     }
1596
1597   /* If e.g. the last FIB had no reportable routes, free the buffer */
1598   if (mp)
1599     vl_msg_api_free (mp);
1600 }
1601
1602 static int
1603 mfib_table_stats_walk_cb (fib_node_index_t fei, void *ctx)
1604 {
1605   stats_main_t *sm = ctx;
1606   do_ip46_fibs_t *do_fibs;
1607   mfib_entry_t *entry;
1608
1609   do_fibs = &sm->do_ip46_fibs;
1610   entry = mfib_entry_get (fei);
1611
1612   vec_add1 (do_fibs->mroutes, entry->mfe_prefix);
1613
1614   return (1);
1615 }
1616
1617 static void
1618 do_ip4_mfib_counters (stats_main_t * sm)
1619 {
1620   ip4_main_t *im4 = &ip4_main;
1621   api_main_t *am = sm->api_main;
1622   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1623   svm_queue_t *q = shmem_hdr->vl_input_queue;
1624   mfib_prefix_t *pfx;
1625   mfib_table_t *mfib;
1626   do_ip46_fibs_t *do_fibs;
1627   vl_api_vnet_ip4_mfib_counters_t *mp = 0;
1628   u32 items_this_message;
1629   vl_api_ip4_mfib_counter_t *ctrp = 0;
1630   u32 start_at_mfib_index = 0;
1631   int i, j, k;
1632
1633   do_fibs = &sm->do_ip46_fibs;
1634
1635   vec_reset_length (do_fibs->mfibs);
1636   /* *INDENT-OFF* */
1637   pool_foreach (mfib, im4->mfibs, ({vec_add1(do_fibs->mfibs, mfib);}));
1638   /* *INDENT-ON* */
1639
1640   for (j = 0; j < vec_len (do_fibs->mfibs); j++)
1641     {
1642       mfib = do_fibs->mfibs[j];
1643       /* We may have bailed out due to control-plane activity */
1644       while ((mfib - im4->mfibs) < start_at_mfib_index)
1645         continue;
1646
1647       if (mp == 0)
1648         {
1649           items_this_message = IP4_MFIB_COUNTER_BATCH_SIZE;
1650           mp = vl_msg_api_alloc_as_if_client
1651             (sizeof (*mp) +
1652              items_this_message * sizeof (vl_api_ip4_mfib_counter_t));
1653           mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_MFIB_COUNTERS);
1654           mp->count = 0;
1655           mp->vrf_id = ntohl (mfib->mft_table_id);
1656           ctrp = (vl_api_ip4_mfib_counter_t *) mp->c;
1657         }
1658       else
1659         {
1660           /* happens if the last MFIB was empty... */
1661           ASSERT (mp->count == 0);
1662           mp->vrf_id = ntohl (mfib->mft_table_id);
1663         }
1664
1665       vec_reset_length (do_fibs->mroutes);
1666
1667       /*
1668        * walk the table with table updates blocked
1669        */
1670       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1671
1672       mfib_table_walk (mfib->mft_index,
1673                        FIB_PROTOCOL_IP4, mfib_table_stats_walk_cb, sm);
1674       dsunlock (sm);
1675
1676       vec_foreach (pfx, do_fibs->mroutes)
1677       {
1678         const dpo_id_t *dpo_id;
1679         fib_node_index_t mfei;
1680         vlib_counter_t c;
1681         u32 index;
1682
1683         /*
1684          * re-lookup the entry, since we suspend during the collection
1685          */
1686         mfei = mfib_table_lookup (mfib->mft_index, pfx);
1687
1688         if (FIB_NODE_INDEX_INVALID == mfei)
1689           continue;
1690
1691         dpo_id = mfib_entry_contribute_ip_forwarding (mfei);
1692         index = (u32) dpo_id->dpoi_index;
1693
1694         vlib_get_combined_counter (&replicate_main.repm_counters,
1695                                    dpo_id->dpoi_index, &c);
1696         /*
1697          * If it has seen at least one packet, send it.
1698          */
1699         if (c.packets > 0)
1700           {
1701             /* already in net byte order */
1702             memcpy (ctrp->group, &pfx->fp_grp_addr.ip4, 4);
1703             memcpy (ctrp->source, &pfx->fp_src_addr.ip4, 4);
1704             ctrp->group_length = pfx->fp_len;
1705             ctrp->packets = clib_host_to_net_u64 (c.packets);
1706             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1707             mp->count++;
1708             ctrp++;
1709
1710             if (mp->count == items_this_message)
1711               {
1712                 mp->count = htonl (items_this_message);
1713                 /*
1714                  * If the main thread's input queue is stuffed,
1715                  * drop the data structure lock (which the main thread
1716                  * may want), and take a pause.
1717                  */
1718                 svm_queue_lock (q);
1719
1720                 while (svm_queue_is_full (q))
1721                   {
1722                     svm_queue_unlock (q);
1723                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
1724                                           STATS_RELEASE_DELAY_NS);
1725                     svm_queue_lock (q);
1726                   }
1727                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1728                 svm_queue_unlock (q);
1729
1730                 items_this_message = IP4_MFIB_COUNTER_BATCH_SIZE;
1731                 mp = vl_msg_api_alloc_as_if_client
1732                   (sizeof (*mp) +
1733                    items_this_message * sizeof (vl_api_ip4_mfib_counter_t));
1734                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_MFIB_COUNTERS);
1735                 mp->count = 0;
1736                 mp->vrf_id = ntohl (mfib->mft_table_id);
1737                 ctrp = (vl_api_ip4_mfib_counter_t *) mp->c;
1738               }
1739           }
1740       }
1741
1742       /* Flush any data from this mfib */
1743       if (mp->count)
1744         {
1745           mp->count = htonl (mp->count);
1746           vl_msg_api_send_shmem (q, (u8 *) & mp);
1747           mp = 0;
1748         }
1749     }
1750
1751   /* If e.g. the last FIB had no reportable routes, free the buffer */
1752   if (mp)
1753     vl_msg_api_free (mp);
1754 }
1755
1756 static void
1757 do_ip6_mfib_counters (stats_main_t * sm)
1758 {
1759   ip6_main_t *im6 = &ip6_main;
1760   api_main_t *am = sm->api_main;
1761   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1762   svm_queue_t *q = shmem_hdr->vl_input_queue;
1763   mfib_prefix_t *pfx;
1764   mfib_table_t *mfib;
1765   do_ip46_fibs_t *do_fibs;
1766   vl_api_vnet_ip6_mfib_counters_t *mp = 0;
1767   u32 items_this_message;
1768   vl_api_ip6_mfib_counter_t *ctrp = 0;
1769   u32 start_at_mfib_index = 0;
1770   int i, j, k;
1771
1772   do_fibs = &sm->do_ip46_fibs;
1773
1774   vec_reset_length (do_fibs->mfibs);
1775   /* *INDENT-OFF* */
1776   pool_foreach (mfib, im6->mfibs, ({vec_add1(do_fibs->mfibs, mfib);}));
1777   /* *INDENT-ON* */
1778
1779   for (j = 0; j < vec_len (do_fibs->mfibs); j++)
1780     {
1781       mfib = do_fibs->mfibs[j];
1782       /* We may have bailed out due to control-plane activity */
1783       while ((mfib - im6->mfibs) < start_at_mfib_index)
1784         continue;
1785
1786       if (mp == 0)
1787         {
1788           items_this_message = IP6_MFIB_COUNTER_BATCH_SIZE;
1789           mp = vl_msg_api_alloc_as_if_client
1790             (sizeof (*mp) +
1791              items_this_message * sizeof (vl_api_ip6_mfib_counter_t));
1792           mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_MFIB_COUNTERS);
1793           mp->count = 0;
1794           mp->vrf_id = ntohl (mfib->mft_table_id);
1795           ctrp = (vl_api_ip6_mfib_counter_t *) mp->c;
1796         }
1797       else
1798         {
1799           /* happens if the last MFIB was empty... */
1800           ASSERT (mp->count == 0);
1801           mp->vrf_id = ntohl (mfib->mft_table_id);
1802         }
1803
1804       vec_reset_length (do_fibs->mroutes);
1805
1806       /*
1807        * walk the table with table updates blocked
1808        */
1809       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1810
1811       mfib_table_walk (mfib->mft_index,
1812                        FIB_PROTOCOL_IP6, mfib_table_stats_walk_cb, sm);
1813       dsunlock (sm);
1814
1815       vec_foreach (pfx, do_fibs->mroutes)
1816       {
1817         const dpo_id_t *dpo_id;
1818         fib_node_index_t mfei;
1819         vlib_counter_t c;
1820         u32 index;
1821
1822         /*
1823          * re-lookup the entry, since we suspend during the collection
1824          */
1825         mfei = mfib_table_lookup (mfib->mft_index, pfx);
1826
1827         if (FIB_NODE_INDEX_INVALID == mfei)
1828           continue;
1829
1830         dpo_id = mfib_entry_contribute_ip_forwarding (mfei);
1831         index = (u32) dpo_id->dpoi_index;
1832
1833         vlib_get_combined_counter (&replicate_main.repm_counters,
1834                                    dpo_id->dpoi_index, &c);
1835         /*
1836          * If it has seen at least one packet, send it.
1837          */
1838         if (c.packets > 0)
1839           {
1840             /* already in net byte order */
1841             memcpy (ctrp->group, &pfx->fp_grp_addr.ip6, 16);
1842             memcpy (ctrp->source, &pfx->fp_src_addr.ip6, 16);
1843             ctrp->group_length = pfx->fp_len;
1844             ctrp->packets = clib_host_to_net_u64 (c.packets);
1845             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1846             mp->count++;
1847             ctrp++;
1848
1849             if (mp->count == items_this_message)
1850               {
1851                 mp->count = htonl (items_this_message);
1852                 /*
1853                  * If the main thread's input queue is stuffed,
1854                  * drop the data structure lock (which the main thread
1855                  * may want), and take a pause.
1856                  */
1857                 svm_queue_lock (q);
1858
1859                 while (svm_queue_is_full (q))
1860                   {
1861                     svm_queue_unlock (q);
1862                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
1863                                           STATS_RELEASE_DELAY_NS);
1864                     svm_queue_lock (q);
1865                   }
1866                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1867                 svm_queue_unlock (q);
1868
1869                 items_this_message = IP6_MFIB_COUNTER_BATCH_SIZE;
1870                 mp = vl_msg_api_alloc_as_if_client
1871                   (sizeof (*mp) +
1872                    items_this_message * sizeof (vl_api_ip6_mfib_counter_t));
1873                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_MFIB_COUNTERS);
1874                 mp->count = 0;
1875                 mp->vrf_id = ntohl (mfib->mft_table_id);
1876                 ctrp = (vl_api_ip6_mfib_counter_t *) mp->c;
1877               }
1878           }
1879       }
1880
1881       /* Flush any data from this mfib */
1882       if (mp->count)
1883         {
1884           mp->count = htonl (mp->count);
1885           vl_msg_api_send_shmem (q, (u8 *) & mp);
1886           mp = 0;
1887         }
1888     }
1889
1890   /* If e.g. the last FIB had no reportable routes, free the buffer */
1891   if (mp)
1892     vl_msg_api_free (mp);
1893 }
1894
1895 typedef struct
1896 {
1897   u32 fib_index;
1898   ip6_route_t **routep;
1899   stats_main_t *sm;
1900 } add_routes_in_fib_arg_t;
1901
1902 static void
1903 add_routes_in_fib (BVT (clib_bihash_kv) * kvp, void *arg)
1904 {
1905   add_routes_in_fib_arg_t *ap = arg;
1906   stats_main_t *sm = ap->sm;
1907
1908   if (sm->data_structure_lock->release_hint)
1909     clib_longjmp (&sm->jmp_buf, 1);
1910
1911   if (kvp->key[2] >> 32 == ap->fib_index)
1912     {
1913       ip6_address_t *addr;
1914       ip6_route_t *r;
1915       addr = (ip6_address_t *) kvp;
1916       vec_add2 (*ap->routep, r, 1);
1917       r->address = addr[0];
1918       r->address_length = kvp->key[2] & 0xFF;
1919       r->index = kvp->value;
1920     }
1921 }
1922
1923 static void
1924 do_ip6_fib_counters (stats_main_t * sm)
1925 {
1926   ip6_main_t *im6 = &ip6_main;
1927   api_main_t *am = sm->api_main;
1928   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1929   svm_queue_t *q = shmem_hdr->vl_input_queue;
1930   ip6_route_t *r;
1931   fib_table_t *fib;
1932   do_ip46_fibs_t *do_fibs;
1933   vl_api_vnet_ip6_fib_counters_t *mp = 0;
1934   u32 items_this_message;
1935   vl_api_ip6_fib_counter_t *ctrp = 0;
1936   u32 start_at_fib_index = 0;
1937   BVT (clib_bihash) * h = &im6->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash;
1938   add_routes_in_fib_arg_t _a, *a = &_a;
1939   int i;
1940
1941   do_fibs = &sm->do_ip46_fibs;
1942 again:
1943   vec_reset_length (do_fibs->fibs);
1944   /* *INDENT-OFF* */
1945   pool_foreach (fib, im6->fibs,
1946                 ({vec_add1(do_fibs->fibs,fib);}));
1947   /* *INDENT-ON* */
1948
1949
1950   for (i = 0; i < vec_len (do_fibs->fibs); i++)
1951     {
1952       fib = do_fibs->fibs[i];
1953       /* We may have bailed out due to control-plane activity */
1954       while ((fib - im6->fibs) < start_at_fib_index)
1955         continue;
1956
1957       if (mp == 0)
1958         {
1959           items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
1960           mp = vl_msg_api_alloc_as_if_client
1961             (sizeof (*mp) +
1962              items_this_message * sizeof (vl_api_ip6_fib_counter_t));
1963           mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
1964           mp->count = 0;
1965           mp->vrf_id = ntohl (fib->ft_table_id);
1966           ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
1967         }
1968
1969       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1970
1971       vec_reset_length (do_fibs->ip6routes);
1972       vec_reset_length (do_fibs->results);
1973
1974       a->fib_index = fib - im6->fibs;
1975       a->routep = &do_fibs->ip6routes;
1976       a->sm = sm;
1977
1978       if (clib_setjmp (&sm->jmp_buf, 0) == 0)
1979         {
1980           start_at_fib_index = fib - im6->fibs;
1981           BV (clib_bihash_foreach_key_value_pair) (h, add_routes_in_fib, a);
1982         }
1983       else
1984         {
1985           dsunlock (sm);
1986           ip46_fib_stats_delay (sm, 0 /* sec */ ,
1987                                 STATS_RELEASE_DELAY_NS);
1988           mp->count = 0;
1989           ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
1990           goto again;
1991         }
1992
1993       vec_foreach (r, do_fibs->ip6routes)
1994       {
1995         vlib_counter_t c;
1996
1997         vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
1998                                    r->index, &c);
1999         /*
2000          * If it has actually
2001          * seen at least one packet, send it.
2002          */
2003         if (c.packets > 0)
2004           {
2005             /* already in net byte order */
2006             ctrp->address[0] = r->address.as_u64[0];
2007             ctrp->address[1] = r->address.as_u64[1];
2008             ctrp->address_length = (u8) r->address_length;
2009             ctrp->packets = clib_host_to_net_u64 (c.packets);
2010             ctrp->bytes = clib_host_to_net_u64 (c.bytes);
2011             mp->count++;
2012             ctrp++;
2013
2014             if (mp->count == items_this_message)
2015               {
2016                 mp->count = htonl (items_this_message);
2017                 /*
2018                  * If the main thread's input queue is stuffed,
2019                  * drop the data structure lock (which the main thread
2020                  * may want), and take a pause.
2021                  */
2022                 svm_queue_lock (q);
2023                 if (svm_queue_is_full (q))
2024                   {
2025                     dsunlock (sm);
2026                     vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
2027                     svm_queue_unlock (q);
2028                     mp = 0;
2029                     ip46_fib_stats_delay (sm, 0 /* sec */ ,
2030                                           STATS_RELEASE_DELAY_NS);
2031                     goto again;
2032                   }
2033                 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
2034                 svm_queue_unlock (q);
2035
2036                 items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
2037                 mp = vl_msg_api_alloc_as_if_client
2038                   (sizeof (*mp) +
2039                    items_this_message * sizeof (vl_api_ip6_fib_counter_t));
2040                 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
2041                 mp->count = 0;
2042                 mp->vrf_id = ntohl (fib->ft_table_id);
2043                 ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
2044               }
2045           }
2046
2047         if (sm->data_structure_lock->release_hint)
2048           {
2049             start_at_fib_index = fib - im6->fibs;
2050             dsunlock (sm);
2051             ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
2052             mp->count = 0;
2053             ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
2054             goto again;
2055           }
2056       }                         /* vec_foreach (routes) */
2057
2058       dsunlock (sm);
2059
2060       /* Flush any data from this fib */
2061       if (mp->count)
2062         {
2063           mp->count = htonl (mp->count);
2064           vl_msg_api_send_shmem (q, (u8 *) & mp);
2065           mp = 0;
2066         }
2067     }
2068
2069   /* If e.g. the last FIB had no reportable routes, free the buffer */
2070   if (mp)
2071     vl_msg_api_free (mp);
2072 }
2073
2074 typedef struct udp_encap_stat_t_
2075 {
2076   u32 ue_id;
2077   u64 stats[2];
2078 } udp_encap_stat_t;
2079
2080 typedef struct udp_encap_stats_walk_t_
2081 {
2082   udp_encap_stat_t *stats;
2083 } udp_encap_stats_walk_t;
2084
2085 static int
2086 udp_encap_stats_walk_cb (index_t uei, void *arg)
2087 {
2088   udp_encap_stats_walk_t *ctx = arg;
2089   udp_encap_stat_t *stat;
2090   udp_encap_t *ue;
2091
2092   ue = udp_encap_get (uei);
2093   vec_add2 (ctx->stats, stat, 1);
2094
2095   stat->ue_id = uei;
2096   udp_encap_get_stats (ue->ue_id, &stat->stats[0], &stat->stats[1]);
2097
2098   return (1);
2099 }
2100
2101 static void
2102 udp_encap_ship (udp_encap_stats_walk_t * ctx)
2103 {
2104   vl_api_vnet_udp_encap_counters_t *mp;
2105   vl_shmem_hdr_t *shmem_hdr;
2106   stats_main_t *sm;
2107   api_main_t *am;
2108   svm_queue_t *q;
2109
2110   mp = NULL;
2111   sm = &stats_main;
2112   am = sm->api_main;
2113   shmem_hdr = am->shmem_hdr;
2114   q = shmem_hdr->vl_input_queue;
2115
2116   /*
2117    * If the walk context has counters, which may be left over from the last
2118    * suspend, then we continue from there.
2119    */
2120   while (0 != vec_len (ctx->stats))
2121     {
2122       u32 n_items = MIN (vec_len (ctx->stats),
2123                          UDP_ENCAP_COUNTER_BATCH_SIZE);
2124       u8 pause = 0;
2125
2126       dslock (sm, 0 /* release hint */ , 1 /* tag */ );
2127
2128       mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
2129                                           (n_items *
2130                                            sizeof
2131                                            (vl_api_udp_encap_counter_t)));
2132       mp->_vl_msg_id = ntohs (VL_API_VNET_UDP_ENCAP_COUNTERS);
2133       mp->count = ntohl (n_items);
2134
2135       /*
2136        * copy the counters from the back of the context, then we can easily
2137        * 'erase' them by resetting the vector length.
2138        * The order we push the stats to the caller is not important.
2139        */
2140       clib_memcpy (mp->c,
2141                    &ctx->stats[vec_len (ctx->stats) - n_items],
2142                    n_items * sizeof (*ctx->stats));
2143
2144       _vec_len (ctx->stats) = vec_len (ctx->stats) - n_items;
2145
2146       /*
2147        * send to the shm q
2148        */
2149       svm_queue_lock (q);
2150       pause = svm_queue_is_full (q);
2151
2152       vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
2153       svm_queue_unlock (q);
2154       dsunlock (sm);
2155
2156       if (pause)
2157         ip46_fib_stats_delay (sm, 0 /* sec */ ,
2158                               STATS_RELEASE_DELAY_NS);
2159     }
2160 }
2161
2162 static void
2163 do_udp_encap_counters (stats_main_t * sm)
2164 {
2165   udp_encap_stat_t *stat;
2166
2167   udp_encap_stats_walk_t ctx = {
2168     .stats = NULL,
2169   };
2170
2171   dslock (sm, 0 /* release hint */ , 1 /* tag */ );
2172   udp_encap_walk (udp_encap_stats_walk_cb, &ctx);
2173   dsunlock (sm);
2174
2175   udp_encap_ship (&ctx);
2176 }
2177
2178 int
2179 stats_set_poller_delay (u32 poller_delay_sec)
2180 {
2181   stats_main_t *sm = &stats_main;
2182   if (!poller_delay_sec)
2183     {
2184       return VNET_API_ERROR_INVALID_ARGUMENT;
2185     }
2186   else
2187     {
2188       sm->stats_poll_interval_in_seconds = poller_delay_sec;
2189       return 0;
2190     }
2191 }
2192
2193 static clib_error_t *
2194 stats_config (vlib_main_t * vm, unformat_input_t * input)
2195 {
2196   u32 sec;
2197
2198   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2199     {
2200       if (unformat (input, "interval %u", &sec))
2201         {
2202           int rv = stats_set_poller_delay (sec);
2203           if (rv)
2204             {
2205               return clib_error_return (0,
2206                                         "`stats_set_poller_delay' API call failed, rv=%d:%U",
2207                                         (int) rv, format_vnet_api_errno, rv);
2208             }
2209           return 0;
2210         }
2211       else
2212         {
2213           return clib_error_return (0, "unknown input '%U'",
2214                                     format_unformat_error, input);
2215         }
2216     }
2217   return 0;
2218 }
2219
2220 /* stats { ... } configuration. */
2221 /*?
2222  *
2223  * @cfgcmd{interval, &lt;seconds&gt;}
2224  * Configure stats poller delay to be @c seconds.
2225  *
2226 ?*/
2227 VLIB_CONFIG_FUNCTION (stats_config, "stats");
2228
2229 static void
2230   vl_api_stats_get_poller_delay_t_handler
2231   (vl_api_stats_get_poller_delay_t * mp)
2232 {
2233   stats_main_t *sm = &stats_main;
2234   vl_api_registration_t *reg;
2235   reg = vl_api_client_index_to_registration (mp->client_index);
2236   if (!reg)
2237     return;
2238   vl_api_stats_get_poller_delay_reply_t *rmp;
2239
2240   rmp = vl_msg_api_alloc (sizeof (*rmp));
2241   rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
2242   rmp->context = mp->context;
2243   rmp->retval = 0;
2244   rmp->delay = clib_host_to_net_u32 (sm->stats_poll_interval_in_seconds);
2245
2246   vl_api_send_msg (reg, (u8 *) rmp);
2247
2248 }
2249
2250 static void
2251 stats_thread_fn (void *arg)
2252 {
2253   stats_main_t *sm = &stats_main;
2254   vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
2255   vlib_thread_main_t *tm = vlib_get_thread_main ();
2256
2257   /* stats thread wants no signals. */
2258   {
2259     sigset_t s;
2260     sigfillset (&s);
2261     pthread_sigmask (SIG_SETMASK, &s, 0);
2262   }
2263
2264   if (vec_len (tm->thread_prefix))
2265     vlib_set_thread_name ((char *)
2266                           format (0, "%v_stats%c", tm->thread_prefix, '\0'));
2267
2268   clib_mem_set_heap (w->thread_mheap);
2269
2270   while (1)
2271     {
2272       ip46_fib_stats_delay (sm, sm->stats_poll_interval_in_seconds,
2273                             0 /* nsec */ );
2274
2275       if (!(sm->enable_poller))
2276         {
2277           continue;
2278         }
2279       if (pool_elts
2280           (sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS]))
2281         do_combined_per_interface_counters (sm);
2282
2283       if (pool_elts
2284           (sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS]))
2285         do_simple_per_interface_counters (sm);
2286
2287       if (pool_elts (sm->stats_registrations[IDX_IP4_FIB_COUNTERS]))
2288         do_ip4_fib_counters (sm);
2289
2290       if (pool_elts (sm->stats_registrations[IDX_IP6_FIB_COUNTERS]))
2291         do_ip6_fib_counters (sm);
2292
2293       if (pool_elts (sm->stats_registrations[IDX_IP4_MFIB_COUNTERS]))
2294         do_ip4_mfib_counters (sm);
2295
2296       if (pool_elts (sm->stats_registrations[IDX_IP6_MFIB_COUNTERS]))
2297         do_ip6_mfib_counters (sm);
2298
2299       if (pool_elts (sm->stats_registrations[IDX_IP4_NBR_COUNTERS]))
2300         do_ip4_nbr_counters (sm);
2301
2302       if (pool_elts (sm->stats_registrations[IDX_IP6_NBR_COUNTERS]))
2303         do_ip6_nbr_counters (sm);
2304
2305       if (pool_elts (sm->stats_registrations[IDX_UDP_ENCAP_COUNTERS]))
2306         do_udp_encap_counters (sm);
2307     }
2308 }
2309
2310 static void
2311   vl_api_vnet_interface_simple_counters_t_handler
2312   (vl_api_vnet_interface_simple_counters_t * mp)
2313 {
2314   vpe_client_registration_t *clients, client;
2315   stats_main_t *sm = &stats_main;
2316   vl_api_registration_t *reg, *reg_prev = NULL;
2317   vl_api_vnet_interface_simple_counters_t *mp_copy = NULL;
2318   u32 mp_size;
2319   int i;
2320
2321   mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (u64));
2322
2323   clients =
2324     get_clients_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
2325                           ~0 /*flag for all */ );
2326
2327   for (i = 0; i < vec_len (clients); i++)
2328     {
2329       client = clients[i];
2330       reg = vl_api_client_index_to_registration (client.client_index);
2331       if (reg)
2332         {
2333           if (reg_prev && vl_api_can_send_msg (reg_prev))
2334             {
2335               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2336               clib_memcpy (mp_copy, mp, mp_size);
2337               vl_api_send_msg (reg_prev, (u8 *) mp);
2338               mp = mp_copy;
2339             }
2340           reg_prev = reg;
2341         }
2342       else
2343         {
2344           sm->enable_poller =
2345             clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, ~0,
2346                                    client.client_index);
2347           continue;
2348         }
2349     }
2350
2351 #if STATS_DEBUG > 0
2352   fformat (stdout, "%U\n", format_vnet_simple_counters, mp);
2353 #endif
2354
2355   if (reg_prev && vl_api_can_send_msg (reg_prev))
2356     {
2357       vl_api_send_msg (reg_prev, (u8 *) mp);
2358     }
2359   else
2360     {
2361       vl_msg_api_free (mp);
2362     }
2363 }
2364
2365 static void
2366 vl_api_vnet_ip4_fib_counters_t_handler (vl_api_vnet_ip4_fib_counters_t * mp)
2367 {
2368   stats_main_t *sm = &stats_main;
2369   vl_api_registration_t *reg, *reg_prev = NULL;
2370   vl_api_vnet_ip4_fib_counters_t *mp_copy = NULL;
2371   u32 mp_size;
2372   vpe_client_registration_t *clients, client;
2373   int i;
2374
2375   mp_size = sizeof (*mp_copy) +
2376     ntohl (mp->count) * sizeof (vl_api_ip4_fib_counter_t);
2377
2378   clients =
2379     get_clients_for_stat (IDX_IP4_FIB_COUNTERS, ~0 /*flag for all */ );
2380
2381   for (i = 0; i < vec_len (clients); i++)
2382     {
2383       client = clients[i];
2384       reg = vl_api_client_index_to_registration (client.client_index);
2385       if (reg)
2386         {
2387           if (reg_prev && vl_api_can_send_msg (reg_prev))
2388             {
2389               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2390               clib_memcpy (mp_copy, mp, mp_size);
2391               vl_api_send_msg (reg_prev, (u8 *) mp);
2392               mp = mp_copy;
2393             }
2394           reg_prev = reg;
2395         }
2396       else
2397         {
2398           sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
2399                                                      ~0, client.client_index);
2400           continue;
2401         }
2402     }
2403
2404   if (reg_prev && vl_api_can_send_msg (reg_prev))
2405     {
2406       vl_api_send_msg (reg_prev, (u8 *) mp);
2407     }
2408   else
2409     {
2410       vl_msg_api_free (mp);
2411     }
2412 }
2413
2414 static void
2415 vl_api_vnet_ip4_nbr_counters_t_handler (vl_api_vnet_ip4_nbr_counters_t * mp)
2416 {
2417   stats_main_t *sm = &stats_main;
2418   vl_api_registration_t *reg, *reg_prev = NULL;
2419   vl_api_vnet_ip4_nbr_counters_t *mp_copy = NULL;
2420   u32 mp_size;
2421   vpe_client_registration_t *clients, client;
2422   int i;
2423
2424   mp_size = sizeof (*mp_copy) +
2425     ntohl (mp->count) * sizeof (vl_api_ip4_nbr_counter_t);
2426
2427   clients =
2428     get_clients_for_stat (IDX_IP4_NBR_COUNTERS, ~0 /*flag for all */ );
2429
2430   for (i = 0; i < vec_len (clients); i++)
2431     {
2432       client = clients[i];
2433       reg = vl_api_client_index_to_registration (client.client_index);
2434       if (reg)
2435         {
2436           if (reg_prev && vl_api_can_send_msg (reg_prev))
2437             {
2438               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2439               clib_memcpy (mp_copy, mp, mp_size);
2440               vl_api_send_msg (reg_prev, (u8 *) mp);
2441               mp = mp_copy;
2442             }
2443           reg_prev = reg;
2444         }
2445       else
2446         {
2447           sm->enable_poller = clear_client_for_stat (IDX_IP4_NBR_COUNTERS,
2448                                                      ~0, client.client_index);
2449           continue;
2450         }
2451     }
2452
2453   /* *INDENT-ON* */
2454   if (reg_prev && vl_api_can_send_msg (reg_prev))
2455     {
2456       vl_api_send_msg (reg_prev, (u8 *) mp);
2457     }
2458   else
2459     {
2460       vl_msg_api_free (mp);
2461     }
2462 }
2463
2464 static void
2465 vl_api_vnet_ip6_fib_counters_t_handler (vl_api_vnet_ip6_fib_counters_t * mp)
2466 {
2467   stats_main_t *sm = &stats_main;
2468   vl_api_registration_t *reg, *reg_prev = NULL;
2469   vl_api_vnet_ip6_fib_counters_t *mp_copy = NULL;
2470   u32 mp_size;
2471   vpe_client_registration_t *clients, client;
2472   int i;
2473
2474   mp_size = sizeof (*mp_copy) +
2475     ntohl (mp->count) * sizeof (vl_api_ip6_fib_counter_t);
2476
2477   clients =
2478     get_clients_for_stat (IDX_IP6_FIB_COUNTERS, ~0 /*flag for all */ );
2479
2480   for (i = 0; i < vec_len (clients); i++)
2481     {
2482       client = clients[i];
2483       reg = vl_api_client_index_to_registration (client.client_index);
2484       if (reg)
2485         {
2486           if (reg_prev && vl_api_can_send_msg (reg_prev))
2487             {
2488               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2489               clib_memcpy (mp_copy, mp, mp_size);
2490               vl_api_send_msg (reg_prev, (u8 *) mp);
2491               mp = mp_copy;
2492             }
2493           reg_prev = reg;
2494         }
2495       else
2496         {
2497           sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2498                                                      ~0, client.client_index);
2499           continue;
2500         }
2501     }
2502   /* *INDENT-ON* */
2503   if (reg_prev && vl_api_can_send_msg (reg_prev))
2504     {
2505       vl_api_send_msg (reg_prev, (u8 *) mp);
2506     }
2507   else
2508     {
2509       vl_msg_api_free (mp);
2510     }
2511 }
2512
2513 static void
2514 vl_api_vnet_ip6_nbr_counters_t_handler (vl_api_vnet_ip6_nbr_counters_t * mp)
2515 {
2516   stats_main_t *sm = &stats_main;
2517   vl_api_registration_t *reg, *reg_prev = NULL;
2518   vl_api_vnet_ip6_nbr_counters_t *mp_copy = NULL;
2519   u32 mp_size;
2520   vpe_client_registration_t *clients, client;
2521   int i;
2522
2523   mp_size = sizeof (*mp_copy) +
2524     ntohl (mp->count) * sizeof (vl_api_ip6_nbr_counter_t);
2525
2526   clients =
2527     get_clients_for_stat (IDX_IP6_NBR_COUNTERS, ~0 /*flag for all */ );
2528
2529   for (i = 0; i < vec_len (clients); i++)
2530     {
2531       client = clients[i];
2532       reg = vl_api_client_index_to_registration (client.client_index);
2533       if (reg)
2534         {
2535           if (reg_prev && vl_api_can_send_msg (reg_prev))
2536             {
2537               mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2538               clib_memcpy (mp_copy, mp, mp_size);
2539               vl_api_send_msg (reg_prev, (u8 *) mp);
2540               mp = mp_copy;
2541             }
2542           reg_prev = reg;
2543         }
2544       else
2545         {
2546           sm->enable_poller = clear_client_for_stat (IDX_IP6_NBR_COUNTERS,
2547                                                      ~0, client.client_index);
2548           continue;
2549         }
2550     }
2551   /* *INDENT-ON* */
2552   if (reg_prev && vl_api_can_send_msg (reg_prev))
2553     {
2554       vl_api_send_msg (reg_prev, (u8 *) mp);
2555     }
2556   else
2557     {
2558       vl_msg_api_free (mp);
2559     }
2560 }
2561
2562 static void
2563 vl_api_want_udp_encap_stats_t_handler (vl_api_want_udp_encap_stats_t * mp)
2564 {
2565   stats_main_t *sm = &stats_main;
2566   vpe_client_registration_t rp;
2567   vl_api_want_udp_encap_stats_reply_t *rmp;
2568   uword *p;
2569   i32 retval = 0;
2570   vl_api_registration_t *reg;
2571   u32 fib;
2572
2573   fib = ~0;                     //Using same mechanism as _per_interface_
2574   rp.client_index = mp->client_index;
2575   rp.client_pid = mp->pid;
2576
2577   handle_client_registration (&rp, IDX_UDP_ENCAP_COUNTERS, fib, mp->enable);
2578
2579 reply:
2580   reg = vl_api_client_index_to_registration (mp->client_index);
2581
2582   if (!reg)
2583     {
2584       sm->enable_poller = clear_client_for_stat (IDX_UDP_ENCAP_COUNTERS,
2585                                                  fib, mp->client_index);
2586       return;
2587     }
2588
2589   rmp = vl_msg_api_alloc (sizeof (*rmp));
2590   rmp->_vl_msg_id = ntohs (VL_API_WANT_UDP_ENCAP_STATS_REPLY);
2591   rmp->context = mp->context;
2592   rmp->retval = retval;
2593
2594   vl_api_send_msg (reg, (u8 *) rmp);
2595 }
2596
2597 static void
2598 vl_api_want_stats_t_handler (vl_api_want_stats_t * mp)
2599 {
2600   stats_main_t *sm = &stats_main;
2601   vpe_client_registration_t rp;
2602   vl_api_want_stats_reply_t *rmp;
2603   uword *p;
2604   i32 retval = 0;
2605   u32 item;
2606   vl_api_registration_t *reg;
2607
2608   item = ~0;                    //"ALL THE THINGS IN THE THINGS
2609   rp.client_index = mp->client_index;
2610   rp.client_pid = mp->pid;
2611
2612   handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
2613                               item, mp->enable_disable);
2614
2615   handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
2616                               item, mp->enable_disable);
2617
2618   handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS,
2619                               item, mp->enable_disable);
2620
2621   handle_client_registration (&rp, IDX_IP4_NBR_COUNTERS,
2622                               item, mp->enable_disable);
2623
2624   handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS,
2625                               item, mp->enable_disable);
2626
2627   handle_client_registration (&rp, IDX_IP6_NBR_COUNTERS,
2628                               item, mp->enable_disable);
2629
2630 reply:
2631   reg = vl_api_client_index_to_registration (mp->client_index);
2632   if (!reg)
2633     return;
2634
2635   rmp = vl_msg_api_alloc (sizeof (*rmp));
2636   rmp->_vl_msg_id = ntohs (VL_API_WANT_STATS_REPLY);
2637   rmp->context = mp->context;
2638   rmp->retval = retval;
2639
2640   vl_api_send_msg (reg, (u8 *) rmp);
2641 }
2642
2643 static void
2644   vl_api_want_interface_simple_stats_t_handler
2645   (vl_api_want_interface_simple_stats_t * mp)
2646 {
2647   stats_main_t *sm = &stats_main;
2648   vpe_client_registration_t rp;
2649   vl_api_want_interface_simple_stats_reply_t *rmp;
2650   uword *p;
2651   i32 retval = 0;
2652   u32 swif;
2653   vl_api_registration_t *reg;
2654
2655   swif = ~0;                    //Using same mechanism as _per_interface_
2656   rp.client_index = mp->client_index;
2657   rp.client_pid = mp->pid;
2658
2659   handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2660                               mp->enable_disable);
2661
2662 reply:
2663   reg = vl_api_client_index_to_registration (mp->client_index);
2664
2665   if (!reg)
2666     {
2667       sm->enable_poller =
2668         clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2669                                mp->client_index);
2670       return;
2671     }
2672
2673   rmp = vl_msg_api_alloc (sizeof (*rmp));
2674   rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_SIMPLE_STATS_REPLY);
2675   rmp->context = mp->context;
2676   rmp->retval = retval;
2677
2678   vl_api_send_msg (reg, (u8 *) rmp);
2679 }
2680
2681
2682 static void
2683 vl_api_want_ip4_fib_stats_t_handler (vl_api_want_ip4_fib_stats_t * mp)
2684 {
2685   stats_main_t *sm = &stats_main;
2686   vpe_client_registration_t rp;
2687   vl_api_want_ip4_fib_stats_reply_t *rmp;
2688   uword *p;
2689   i32 retval = 0;
2690   vl_api_registration_t *reg;
2691   u32 fib;
2692
2693   fib = ~0;                     //Using same mechanism as _per_interface_
2694   rp.client_index = mp->client_index;
2695   rp.client_pid = mp->pid;
2696
2697   handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS, fib,
2698                               mp->enable_disable);
2699
2700 reply:
2701   reg = vl_api_client_index_to_registration (mp->client_index);
2702
2703   if (!reg)
2704     {
2705       sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
2706                                                  fib, mp->client_index);
2707       return;
2708     }
2709
2710   rmp = vl_msg_api_alloc (sizeof (*rmp));
2711   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_FIB_STATS_REPLY);
2712   rmp->context = mp->context;
2713   rmp->retval = retval;
2714
2715   vl_api_send_msg (reg, (u8 *) rmp);
2716 }
2717
2718 static void
2719 vl_api_want_ip4_mfib_stats_t_handler (vl_api_want_ip4_mfib_stats_t * mp)
2720 {
2721   stats_main_t *sm = &stats_main;
2722   vpe_client_registration_t rp;
2723   vl_api_want_ip4_mfib_stats_reply_t *rmp;
2724   uword *p;
2725   i32 retval = 0;
2726   vl_api_registration_t *reg;
2727   u32 mfib;
2728
2729   mfib = ~0;                    //Using same mechanism as _per_interface_
2730   rp.client_index = mp->client_index;
2731   rp.client_pid = mp->pid;
2732
2733   handle_client_registration (&rp, IDX_IP4_MFIB_COUNTERS, mfib,
2734                               mp->enable_disable);
2735
2736 reply:
2737   reg = vl_api_client_index_to_registration (mp->client_index);
2738   if (!reg)
2739     {
2740       sm->enable_poller = clear_client_for_stat (IDX_IP4_MFIB_COUNTERS,
2741                                                  mfib, mp->client_index);
2742       return;
2743     }
2744
2745   rmp = vl_msg_api_alloc (sizeof (*rmp));
2746   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_MFIB_STATS_REPLY);
2747   rmp->context = mp->context;
2748   rmp->retval = retval;
2749
2750   vl_api_send_msg (reg, (u8 *) rmp);
2751 }
2752
2753 static void
2754 vl_api_want_ip6_fib_stats_t_handler (vl_api_want_ip6_fib_stats_t * mp)
2755 {
2756   stats_main_t *sm = &stats_main;
2757   vpe_client_registration_t rp;
2758   vl_api_want_ip4_fib_stats_reply_t *rmp;
2759   uword *p;
2760   i32 retval = 0;
2761   vl_api_registration_t *reg;
2762   u32 fib;
2763
2764   fib = ~0;                     //Using same mechanism as _per_interface_
2765   rp.client_index = mp->client_index;
2766   rp.client_pid = mp->pid;
2767
2768   handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS, fib,
2769                               mp->enable_disable);
2770
2771 reply:
2772   reg = vl_api_client_index_to_registration (mp->client_index);
2773   if (!reg)
2774     {
2775       sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2776                                                  fib, mp->client_index);
2777       return;
2778     }
2779
2780   rmp = vl_msg_api_alloc (sizeof (*rmp));
2781   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_FIB_STATS_REPLY);
2782   rmp->context = mp->context;
2783   rmp->retval = retval;
2784
2785   vl_api_send_msg (reg, (u8 *) rmp);
2786 }
2787
2788 static void
2789 vl_api_want_ip6_mfib_stats_t_handler (vl_api_want_ip6_mfib_stats_t * mp)
2790 {
2791   stats_main_t *sm = &stats_main;
2792   vpe_client_registration_t rp;
2793   vl_api_want_ip4_mfib_stats_reply_t *rmp;
2794   uword *p;
2795   i32 retval = 0;
2796   vl_api_registration_t *reg;
2797   u32 mfib;
2798
2799   mfib = ~0;                    //Using same mechanism as _per_interface_
2800   rp.client_index = mp->client_index;
2801   rp.client_pid = mp->pid;
2802
2803   handle_client_registration (&rp, IDX_IP6_MFIB_COUNTERS, mfib,
2804                               mp->enable_disable);
2805
2806 reply:
2807   reg = vl_api_client_index_to_registration (mp->client_index);
2808   if (!reg)
2809     {
2810       sm->enable_poller = clear_client_for_stat (IDX_IP6_MFIB_COUNTERS,
2811                                                  mfib, mp->client_index);
2812       return;
2813     }
2814
2815   rmp = vl_msg_api_alloc (sizeof (*rmp));
2816   rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_MFIB_STATS_REPLY);
2817   rmp->context = mp->context;
2818   rmp->retval = retval;
2819
2820   vl_api_send_msg (reg, (u8 *) rmp);
2821 }
2822
2823 /* FIXME - NBR stats broken - this will be fixed in subsequent patch */
2824 static void
2825 vl_api_want_ip4_nbr_stats_t_handler (vl_api_want_ip4_nbr_stats_t * mp)
2826 {
2827 }
2828
2829 static void
2830 vl_api_want_ip6_nbr_stats_t_handler (vl_api_want_ip6_nbr_stats_t * mp)
2831 {
2832 }
2833
2834 static void
2835 vl_api_vnet_get_summary_stats_t_handler (vl_api_vnet_get_summary_stats_t * mp)
2836 {
2837   stats_main_t *sm = &stats_main;
2838   vnet_interface_main_t *im = sm->interface_main;
2839   vl_api_vnet_get_summary_stats_reply_t *rmp;
2840   vlib_combined_counter_main_t *cm;
2841   vlib_counter_t v;
2842   int i, which;
2843   u64 total_pkts[VLIB_N_RX_TX];
2844   u64 total_bytes[VLIB_N_RX_TX];
2845   vl_api_registration_t *reg;
2846
2847   reg = vl_api_client_index_to_registration (mp->client_index);
2848   if (!reg)
2849     return;
2850
2851   rmp = vl_msg_api_alloc (sizeof (*rmp));
2852   rmp->_vl_msg_id = ntohs (VL_API_VNET_GET_SUMMARY_STATS_REPLY);
2853   rmp->context = mp->context;
2854   rmp->retval = 0;
2855
2856   memset (total_pkts, 0, sizeof (total_pkts));
2857   memset (total_bytes, 0, sizeof (total_bytes));
2858
2859   vnet_interface_counter_lock (im);
2860
2861   vec_foreach (cm, im->combined_sw_if_counters)
2862   {
2863     which = cm - im->combined_sw_if_counters;
2864
2865     for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
2866       {
2867         vlib_get_combined_counter (cm, i, &v);
2868         total_pkts[which] += v.packets;
2869         total_bytes[which] += v.bytes;
2870       }
2871   }
2872   vnet_interface_counter_unlock (im);
2873
2874   rmp->total_pkts[VLIB_RX] = clib_host_to_net_u64 (total_pkts[VLIB_RX]);
2875   rmp->total_bytes[VLIB_RX] = clib_host_to_net_u64 (total_bytes[VLIB_RX]);
2876   rmp->total_pkts[VLIB_TX] = clib_host_to_net_u64 (total_pkts[VLIB_TX]);
2877   rmp->total_bytes[VLIB_TX] = clib_host_to_net_u64 (total_bytes[VLIB_TX]);
2878   rmp->vector_rate =
2879     clib_host_to_net_u64 (vlib_last_vector_length_per_node (sm->vlib_main));
2880
2881   vl_api_send_msg (reg, (u8 *) rmp);
2882 }
2883
2884 int
2885 stats_memclnt_delete_callback (u32 client_index)
2886 {
2887   vpe_client_stats_registration_t *rp;
2888   stats_main_t *sm = &stats_main;
2889   uword *p;
2890
2891   // FIXME
2892   /* p = hash_get (sm->stats_registration_hash, client_index); */
2893   /* if (p) */
2894   /*   { */
2895   /*     rp = pool_elt_at_index (sm->stats_registrations, p[0]); */
2896   /*     pool_put (sm->stats_registrations, rp); */
2897   /*     hash_unset (sm->stats_registration_hash, client_index); */
2898   /*   } */
2899
2900   return 0;
2901 }
2902
2903 #define vl_api_vnet_interface_simple_counters_t_endian vl_noop_handler
2904 #define vl_api_vnet_interface_simple_counters_t_print vl_noop_handler
2905 #define vl_api_vnet_interface_combined_counters_t_endian vl_noop_handler
2906 #define vl_api_vnet_interface_combined_counters_t_print vl_noop_handler
2907 #define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
2908 #define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
2909 #define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
2910 #define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler
2911 #define vl_api_vnet_ip4_nbr_counters_t_endian vl_noop_handler
2912 #define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
2913 #define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
2914 #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
2915
2916 static clib_error_t *
2917 stats_init (vlib_main_t * vm)
2918 {
2919   stats_main_t *sm = &stats_main;
2920   api_main_t *am = &api_main;
2921   void *vlib_worker_thread_bootstrap_fn (void *arg);
2922
2923   sm->vlib_main = vm;
2924   sm->vnet_main = vnet_get_main ();
2925   sm->interface_main = &vnet_get_main ()->interface_main;
2926   sm->api_main = am;
2927   sm->stats_poll_interval_in_seconds = 10;
2928   sm->data_structure_lock =
2929     clib_mem_alloc_aligned (sizeof (data_structure_lock_t),
2930                             CLIB_CACHE_LINE_BYTES);
2931   memset (sm->data_structure_lock, 0, sizeof (*sm->data_structure_lock));
2932
2933 #define _(N,n)                                                  \
2934     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
2935                            vl_api_##n##_t_handler,              \
2936                            vl_noop_handler,                     \
2937                            vl_api_##n##_t_endian,               \
2938                            vl_api_##n##_t_print,                \
2939                            sizeof(vl_api_##n##_t), 0 /* do NOT trace! */);
2940   foreach_stats_msg;
2941 #undef _
2942
2943   /* tell the msg infra not to free these messages... */
2944   am->message_bounce[VL_API_VNET_INTERFACE_SIMPLE_COUNTERS] = 1;
2945   am->message_bounce[VL_API_VNET_INTERFACE_COMBINED_COUNTERS] = 1;
2946   am->message_bounce[VL_API_VNET_IP4_FIB_COUNTERS] = 1;
2947   am->message_bounce[VL_API_VNET_IP6_FIB_COUNTERS] = 1;
2948   am->message_bounce[VL_API_VNET_IP4_NBR_COUNTERS] = 1;
2949   am->message_bounce[VL_API_VNET_IP6_NBR_COUNTERS] = 1;
2950
2951   /*
2952    * Set up the (msg_name, crc, message-id) table
2953    */
2954   setup_message_id_table (am);
2955
2956   vec_validate (sm->stats_registrations, STATS_REG_N_IDX);
2957   vec_validate (sm->stats_registration_hash, STATS_REG_N_IDX);
2958 #define stats_reg(n)                            \
2959   sm->stats_registrations[IDX_##n] = 0; \
2960   sm->stats_registration_hash[IDX_##n] = 0;
2961 #include <vpp/stats/stats.reg>
2962 #undef stats_reg
2963
2964   return 0;
2965 }
2966
2967 VLIB_INIT_FUNCTION (stats_init);
2968
2969 /* *INDENT-OFF* */
2970 VLIB_REGISTER_THREAD (stats_thread_reg, static) = {
2971   .name = "stats",
2972   .function = stats_thread_fn,
2973   .fixed_count = 1,
2974   .count = 1,
2975   .no_data_structure_clone = 1,
2976   .use_pthreads = 1,
2977 };
2978 /* *INDENT-ON* */
2979
2980 /*
2981  * fd.io coding-style-patch-verification: ON
2982  *
2983  * Local Variables:
2984  * eval: (c-set-style "gnu")
2985  * End:
2986  */