FD.io VPP  v17.10-9-gd594711
Vector Packet Processing
stats.c
Go to the documentation of this file.
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/dpo/load_balance.h>
20 
21 #define STATS_DEBUG 0
22 
24 
25 #include <vnet/ip/ip.h>
26 
27 #include <vpp/api/vpe_msg_enum.h>
28 
29 #define f64_endian(a)
30 #define f64_print(a,b)
31 
32 #define vl_typedefs /* define message structures */
33 #include <vpp/api/vpe_all_api_h.h>
34 #undef vl_typedefs
35 
36 #define vl_endianfun /* define message structures */
37 #include <vpp/api/vpe_all_api_h.h>
38 #undef vl_endianfun
39 
40 /* instantiate all the print functions we know about */
41 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
42 #define vl_printfun
43 #include <vpp/api/vpe_all_api_h.h>
44 #undef vl_printfun
45 
46 #define foreach_stats_msg \
47 _(WANT_STATS, want_stats) \
48 _(VNET_INTERFACE_SIMPLE_COUNTERS, vnet_interface_simple_counters) \
49 _(WANT_INTERFACE_SIMPLE_STATS, want_interface_simple_stats) \
50 _(VNET_INTERFACE_COMBINED_COUNTERS, vnet_interface_combined_counters) \
51 _(WANT_INTERFACE_COMBINED_STATS, want_interface_combined_stats) \
52 _(WANT_PER_INTERFACE_COMBINED_STATS, want_per_interface_combined_stats) \
53 _(WANT_PER_INTERFACE_SIMPLE_STATS, want_per_interface_simple_stats) \
54 _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \
55 _(WANT_IP4_FIB_STATS, want_ip4_fib_stats) \
56 _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \
57 _(WANT_IP6_FIB_STATS, want_ip6_fib_stats) \
58 _(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \
59 _(WANT_IP4_NBR_STATS, want_ip4_nbr_stats) \
60 _(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \
61 _(WANT_IP6_NBR_STATS, want_ip6_nbr_stats) \
62 _(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats)
63 
64 
65 #define vl_msg_name_crc_list
66 #include <vpp/stats/stats.api.h>
67 #undef vl_msg_name_crc_list
68 
69 static void
71 {
72 #define _(id,n,crc) \
73  vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
74  foreach_vl_msg_name_crc_stats;
75 #undef _
76 }
77 
78 /* These constants ensure msg sizes <= 1024, aka ring allocation */
79 #define SIMPLE_COUNTER_BATCH_SIZE 126
80 #define COMBINED_COUNTER_BATCH_SIZE 63
81 #define IP4_FIB_COUNTER_BATCH_SIZE 48
82 #define IP6_FIB_COUNTER_BATCH_SIZE 30
83 
84 /* 5ms */
85 #define STATS_RELEASE_DELAY_NS (1000 * 1000 * 5)
86 /* ns/us us/ms */
87 
88 u8 *
90 {
91  stats_main_t *sm = &stats_main;
94 
95  char *counter_name;
96  u32 count, sw_if_index;
97  int i;
98  count = ntohl (mp->count);
99  sw_if_index = ntohl (mp->first_sw_if_index);
100 
101  vlib_counter_t *vp;
102  u64 packets, bytes;
103  vp = (vlib_counter_t *) mp->data;
104 
105  switch (mp->vnet_counter_type)
106  {
108  counter_name = "rx";
109  break;
111  counter_name = "tx";
112  break;
113  default:
114  counter_name = "bogus";
115  break;
116  }
117  for (i = 0; i < count; i++)
118  {
119  packets = clib_mem_unaligned (&vp->packets, u64);
120  packets = clib_net_to_host_u64 (packets);
121  bytes = clib_mem_unaligned (&vp->bytes, u64);
122  bytes = clib_net_to_host_u64 (bytes);
123  vp++;
124  s = format (s, "%U.%s.packets %lld\n",
126  sm->vnet_main, sw_if_index, counter_name, packets);
127  s = format (s, "%U.%s.bytes %lld\n",
129  sm->vnet_main, sw_if_index, counter_name, bytes);
130  sw_if_index++;
131  }
132  return s;
133 }
134 
135 u8 *
137 {
138  stats_main_t *sm = &stats_main;
140  va_arg (*args, vl_api_vnet_interface_simple_counters_t *);
141  char *counter_name;
142  u32 count, sw_if_index;
143  count = ntohl (mp->count);
144  sw_if_index = ntohl (mp->first_sw_if_index);
145  u64 *vp, v;
146  vp = (u64 *) mp->data;
147  int i;
148 
149  switch (mp->vnet_counter_type)
150  {
152  counter_name = "drop";
153  break;
155  counter_name = "punt";
156  break;
158  counter_name = "ip4";
159  break;
161  counter_name = "ip6";
162  break;
164  counter_name = "rx-no-buff";
165  break;
167  counter_name = "rx-miss";
168  break;
170  counter_name = "rx-error (fifo-full)";
171  break;
173  counter_name = "tx-error (fifo-full)";
174  break;
175  default:
176  counter_name = "bogus";
177  break;
178  }
179  for (i = 0; i < count; i++)
180  {
181  v = clib_mem_unaligned (vp, u64);
182  v = clib_net_to_host_u64 (v);
183  vp++;
184  s = format (s, "%U.%s %lld\n", format_vnet_sw_if_index_name,
185  sm->vnet_main, sw_if_index, counter_name, v);
186  sw_if_index++;
187  }
188 
189  return s;
190 }
191 
192 void
193 dslock (stats_main_t * sm, int release_hint, int tag)
194 {
195  u32 thread_index;
197 
198  if (PREDICT_FALSE (l == 0))
199  return;
200 
201  thread_index = vlib_get_thread_index ();
202  if (l->lock && l->thread_index == thread_index)
203  {
204  l->count++;
205  return;
206  }
207 
208  if (release_hint)
209  l->release_hint++;
210 
211  while (__sync_lock_test_and_set (&l->lock, 1))
212  /* zzzz */ ;
213  l->tag = tag;
214  l->thread_index = thread_index;
215  l->count = 1;
216 }
217 
218 void
219 stats_dslock_with_hint (int hint, int tag)
220 {
221  stats_main_t *sm = &stats_main;
222  dslock (sm, hint, tag);
223 }
224 
225 void
227 {
228  u32 thread_index;
230 
231  if (PREDICT_FALSE (l == 0))
232  return;
233 
234  thread_index = vlib_get_thread_index ();
235  ASSERT (l->lock && l->thread_index == thread_index);
236  l->count--;
237  if (l->count == 0)
238  {
239  l->tag = -l->tag;
240  l->release_hint = 0;
242  l->lock = 0;
243  }
244 }
245 
246 void
247 stats_dsunlock (int hint, int tag)
248 {
249  stats_main_t *sm = &stats_main;
250  dsunlock (sm);
251 }
252 
254 get_client_for_stat (u32 reg, u32 item, u32 client_index)
255 {
256  stats_main_t *sm = &stats_main;
257  vpe_client_stats_registration_t *registration;
258  uword *p;
259 
260  /* Is there anything listening for item in that reg */
261  p = hash_get (sm->stats_registration_hash[reg], item);
262 
263  if (!p)
264  return 0; // Fail
265 
266  /* If there is, is our client_index one of them */
267  registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
268  p = hash_get (registration->client_hash, client_index);
269 
270  if (!p)
271  return 0; // Fail
272 
273  return pool_elt_at_index (registration->clients, p[0]);
274 
275 }
276 
277 static int
279 {
280  stats_main_t *sm = &stats_main;
281  vpe_client_stats_registration_t *registration;
283  uword *p;
284 
285  /* Is there anything listening for item in that reg */
286  p = hash_get (sm->stats_registration_hash[reg], item);
287 
288  if (!p)
289  {
290  pool_get (sm->stats_registrations[reg], registration);
291  registration->item = item;
292  hash_set (sm->stats_registration_hash[reg], item,
293  registration - sm->stats_registrations[reg]);
294  }
295  else
296  {
297  registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
298  }
299 
300  p = hash_get (registration->client_hash, client->client_index);
301 
302  if (!p)
303  {
304  pool_get (registration->clients, cr);
305  cr->client_index = client->client_index;
306  cr->client_pid = client->client_pid;
307  hash_set (registration->client_hash, cr->client_index,
308  cr - registration->clients);
309  }
310 
311  return 1; //At least one client is doing something ... poll
312 }
313 
314 int
315 clear_client_for_stat (u32 reg, u32 item, u32 client_index)
316 {
317  stats_main_t *sm = &stats_main;
318  vpe_client_stats_registration_t *registration;
320  uword *p;
321  int i, elts;
322 
323  /* Clear the client first */
324  /* Is there anything listening for item in that reg */
325  p = hash_get (sm->stats_registration_hash[reg], item);
326 
327  if (!p)
328  goto exit;
329 
330  /* If there is, is our client_index one of them */
331  registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
332  p = hash_get (registration->client_hash, client_index);
333 
334  if (!p)
335  goto exit;
336 
337  client = pool_elt_at_index (registration->clients, p[0]);
338  hash_unset (registration->client_hash, client->client_index);
339  pool_put (registration->clients, client);
340 
341  /* Now check if that was the last client for that item */
342  if (0 == pool_elts (registration->clients))
343  {
344  hash_unset (sm->stats_registration_hash[reg], item);
345  pool_put (sm->stats_registrations[reg], registration);
346  }
347 
348 exit:
349  elts = 0;
350  /* Now check if that was the last item in any of the listened to stats */
351  for (i = 0; i < STATS_REG_N_IDX; i++)
352  {
353  elts += pool_elts (sm->stats_registrations[i]);
354  }
355  return elts;
356 }
357 
360 {
361  stats_main_t *sm = &stats_main;
362  vpe_client_registration_t *client, *clients = 0;
363  vpe_client_stats_registration_t *registration;
364  uword *p;
365 
366  /* Is there anything listening for item in that reg */
367  p = hash_get (sm->stats_registration_hash[reg], item);
368 
369  if (!p)
370  return 0; // Fail
371 
372  /* If there is, is our client_index one of them */
373  registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
374 
375  vec_reset_length (clients);
376  pool_foreach (client, registration->clients, (
377  {
378  vec_add1 (clients, *client);}
379  ));
380  return clients;
381 }
382 
383 
384 static void
385 clear_client_reg (u32 ** registrations)
386 {
387  /* When registrations[x] is a vector of pool indices
388  here is a good place to clean up the pools
389  */
390 #define stats_reg(n) vec_free(registrations[IDX_##n]);
391 #include <vpp/stats/stats.reg>
392 #undef stats_reg
393 
394  vec_free (registrations);
395 }
396 
397 u32 **
398 init_client_reg (u32 ** registrations)
399 {
400 
401  /*
402  Initialise the stats registrations for each
403  type of stat a client can register for as well as
404  a vector of "interested" indexes.
405  Initially this is a u32 of either sw_if_index or fib_index
406  but eventually this should migrate to a pool_index (u32)
407  with a type specific pool that can include more complex things
408  such as timing and structured events.
409  */
410  vec_validate (registrations, STATS_REG_N_IDX);
411 #define stats_reg(n) \
412  vec_reset_length(registrations[IDX_##n]);
413 #include <vpp/stats/stats.reg>
414 #undef stats_reg
415 
416  /*
417  When registrations[x] is a vector of pool indices, here
418  is a good place to init the pools.
419  */
420  return registrations;
421 }
422 
423 u32 **
424 enable_all_client_reg (u32 ** registrations)
425 {
426 
427  /*
428  Enable all stats known by adding
429  ~0 to the index vector. Eventually this
430  should be deprecated.
431  */
432 #define stats_reg(n) \
433  vec_add1(registrations[IDX_##n], ~0);
434 #include <vpp/stats/stats.reg>
435 #undef stats_reg
436  return registrations;
437 }
438 
439 static void
441 {
444  api_main_t *am = sm->api_main;
448  u32 items_this_message = 0;
449  u64 v, *vp = 0;
450  int i, n_counts;
451 
452  /*
453  * Prevent interface registration from expanding / moving the vectors...
454  * That tends never to happen, so we can hold this lock for a while.
455  */
457 
458  vec_foreach (cm, im->sw_if_counters)
459  {
460  n_counts = vlib_simple_counter_n_counters (cm);
461  for (i = 0; i < n_counts; i++)
462  {
463  if (mp == 0)
464  {
465  items_this_message = clib_min (SIMPLE_COUNTER_BATCH_SIZE,
466  n_counts - i);
467 
469  (sizeof (*mp) + items_this_message * sizeof (v));
470  mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_SIMPLE_COUNTERS);
471  mp->vnet_counter_type = cm - im->sw_if_counters;
472  mp->first_sw_if_index = htonl (i);
473  mp->count = 0;
474  vp = (u64 *) mp->data;
475  }
476  v = vlib_get_simple_counter (cm, i);
477  clib_mem_unaligned (vp, u64) = clib_host_to_net_u64 (v);
478  vp++;
479  mp->count++;
480  if (mp->count == items_this_message)
481  {
482  mp->count = htonl (items_this_message);
483  /* Send to the main thread... */
484  vl_msg_api_send_shmem (q, (u8 *) & mp);
485  mp = 0;
486  }
487  }
488  ASSERT (mp == 0);
489  }
491 }
492 
493 void
495  u32 item, int enable_disable)
496 {
497  stats_main_t *sm = &stats_main;
498  vpe_client_registration_t *rp, _rp;
499 
500  rp = get_client_for_stat (stat, item, client->client_index);
501 
502  /* Disable case */
503  if (enable_disable == 0)
504  {
505  if (!rp) // No client to disable
506  {
507  clib_warning ("pid %d: already disabled for stats...",
508  client->client_pid);
509  return;
510  }
511  sm->enable_poller =
512  clear_client_for_stat (stat, item, client->client_index);
513  return;
514  }
515  /* Enable case */
516  if (!rp)
517  {
518  rp = &_rp;
519  rp->client_index = client->client_index;
520  rp->client_pid = client->client_pid;
521  sm->enable_poller = set_client_for_stat (stat, item, rp);
522  }
523 }
524 
525 
526 /**********************************
527  * ALL Interface Combined stats - to be deprecated
528  **********************************/
529 
530 /*
531  * This API should be deprecated as _per_interface_ works with ~0 as sw_if_index.
532  */
533 static void
536 {
537  stats_main_t *sm = &stats_main;
539  vl_api_want_interface_combined_stats_reply_t *rmp;
540  uword *p;
541  i32 retval = 0;
543  u32 swif;
544 
545  swif = ~0; //Using same mechanism as _per_interface_
546  rp.client_index = mp->client_index;
547  rp.client_pid = mp->pid;
548 
549  handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
550  mp->enable_disable);
551 
552 reply:
554 
555  if (!q)
556  {
557  sm->enable_poller =
558  clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
559  mp->client_index);
560  return;
561  }
562 
563  rmp = vl_msg_api_alloc (sizeof (*rmp));
564  rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_COMBINED_STATS_REPLY);
565  rmp->context = mp->context;
566  rmp->retval = retval;
567 
568  vl_msg_api_send_shmem (q, (u8 *) & rmp);
569 }
570 
571 static void
574 {
575  vpe_client_registration_t *clients, client;
576  stats_main_t *sm = &stats_main;
577  unix_shared_memory_queue_t *q, *q_prev = NULL;
579  u32 mp_size;
580  int i;
581 
582  mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (vlib_counter_t));
583 
584  clients =
585  get_clients_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
586  ~0 /*flag for all */ );
587 
588  for (i = 0; i < vec_len (clients); i++)
589  {
590  client = clients[i];
592  if (q)
593  {
594  if (q_prev && (q_prev->cursize < q_prev->maxsize))
595  {
596  mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
597  clib_memcpy (mp_copy, mp, mp_size);
598  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
599  mp = mp_copy;
600  }
601  q_prev = q;
602  }
603  }
604 #if STATS_DEBUG > 0
605  fformat (stdout, "%U\n", format_vnet_combined_counters, mp);
606 #endif
607 
608  if (q_prev && (q_prev->cursize < q_prev->maxsize))
609  {
610  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
611  }
612  else
613  {
614  vl_msg_api_free (mp);
615  }
616 }
617 
618 static void
620 {
623  api_main_t *am = sm->api_main;
627  u32 items_this_message = 0;
628  vlib_counter_t v, *vp = 0;
629  int i, n_counts;
630 
632 
634  {
635  n_counts = vlib_combined_counter_n_counters (cm);
636  for (i = 0; i < n_counts; i++)
637  {
638  if (mp == 0)
639  {
640  items_this_message = clib_min (COMBINED_COUNTER_BATCH_SIZE,
641  n_counts - i);
642 
644  (sizeof (*mp) + items_this_message * sizeof (v));
645  mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_COMBINED_COUNTERS);
647  mp->first_sw_if_index = htonl (i);
648  mp->count = 0;
649  vp = (vlib_counter_t *) mp->data;
650  }
651  vlib_get_combined_counter (cm, i, &v);
653  = clib_host_to_net_u64 (v.packets);
654  clib_mem_unaligned (&vp->bytes, u64) = clib_host_to_net_u64 (v.bytes);
655  vp++;
656  mp->count++;
657  if (mp->count == items_this_message)
658  {
659  mp->count = htonl (items_this_message);
660  /* Send to the main thread... */
661  vl_msg_api_send_shmem (q, (u8 *) & mp);
662  mp = 0;
663  }
664  }
665  ASSERT (mp == 0);
666  }
668 }
669 
670 /**********************************
671  * Per Interface Combined stats
672  **********************************/
673 
674 /* Request from client registering interfaces it wants */
675 static void
678 {
679  stats_main_t *sm = &stats_main;
681  vl_api_want_per_interface_combined_stats_reply_t *rmp;
683  uword *p;
684  i32 retval = 0;
686  int i;
687  u32 swif;
688 
689  // Validate we have good sw_if_indexes before registering
690  for (i = 0; i < mp->num; i++)
691  {
692  swif = mp->sw_ifs[i];
693 
694  /* Check its a real sw_if_index that the client is allowed to see */
695  if (swif != ~0)
696  {
698  {
699  retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
700  goto reply;
701  }
702  }
703  }
704 
705  for (i = 0; i < mp->num; i++)
706  {
707  swif = mp->sw_ifs[i];
708 
709  rp.client_index = mp->client_index;
710  rp.client_pid = mp->pid;
711  handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
712  swif, mp->enable_disable);
713  }
714 
715 reply:
717 
718  if (!q)
719  {
720  for (i = 0; i < mp->num; i++)
721  {
722  swif = mp->sw_ifs[i];
723  sm->enable_poller =
724  clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
725  mp->client_index);
726  }
727  return;
728  }
729 
730  rmp = vl_msg_api_alloc (sizeof (*rmp));
731  rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_COMBINED_STATS_REPLY);
732  rmp->context = mp->context;
733  rmp->retval = retval;
734 
735  vl_msg_api_send_shmem (q, (u8 *) & rmp);
736 }
737 
738 /* Per Interface Combined distribution to client */
739 static void
741 {
744  api_main_t *am = sm->api_main;
748  /*
749  * items_this_message will eventually be used to optimise the batching
750  * of per client messages for each stat. For now setting this to 1 then
751  * iterate. This will not affect API.
752  *
753  * FIXME instead of enqueueing here, this should be sent to a batch
754  * storer for per-client transmission. Each "mp" sent would be a single entry
755  * and if a client is listening to other sw_if_indexes for same, it would be
756  * appended to that *mp
757  */
758  u32 items_this_message = 1;
759  vnet_combined_counter_t *vp = 0;
761  int i, j;
762  u32 timestamp;
765  u32 *sw_if_index = 0;
766 
767  /*
768  FIXME(s):
769  - capturing the timestamp of the counters "when VPP knew them" is important.
770  Less so is that the timing of the delivery to the control plane be in the same
771  timescale.
772 
773  i.e. As long as the control plane can delta messages from VPP and work out
774  velocity etc based on the timestamp, it can do so in a more "batch mode".
775 
776  It would be beneficial to keep a "per-client" message queue, and then
777  batch all the stat messages for a client into one message, with
778  discrete timestamps.
779 
780  Given this particular API is for "per interface" one assumes that the scale
781  is less than the ~0 case, which the prior API is suited for.
782  */
784 
785  timestamp = vlib_time_now (sm->vlib_main);
786 
788  pool_foreach (reg,
789  sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS],
790  (
791  {
792  vec_add1 (sm->regs_tmp, reg);}));
793 
794  for (i = 0; i < vec_len (sm->regs_tmp); i++)
795  {
796  reg = sm->regs_tmp[i];
797  if (reg->item == ~0)
798  {
802  continue;
803  }
805  pool_foreach (client, reg->clients, (
806  {
807  vec_add1 (sm->clients_tmp,
808  client);}
809  ));
810 
811  //FIXME - should be doing non-variant part of mp here and managing
812  // any alloc per client in that vec_foreach
813  for (j = 0; j < vec_len (sm->clients_tmp); j++)
814  {
815  client = sm->clients_tmp[j];
817 
818  //Client may have disconnected abrubtly, clean up so we don't poll nothing.
819  if (!q)
820  {
821  sm->enable_poller =
822  clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
823  reg->item, client->client_index);
824  continue;
825  }
826 
827  mp = vl_msg_api_alloc (sizeof (*mp) +
828  (items_this_message *
829  (sizeof (*vp) /* rx */ )));
830 
831  // FIXME when optimising for items_this_message > 1 need to include a
832  // SIMPLE_INTERFACE_BATCH_SIZE check.
833  mp->_vl_msg_id =
834  ntohs (VL_API_VNET_PER_INTERFACE_COMBINED_COUNTERS);
835 
836  mp->count = items_this_message;
837  mp->timestamp = timestamp;
838  vp = (vnet_combined_counter_t *) mp->data;
839 
840  vp->sw_if_index = htonl (reg->item);
841 
843  vlib_get_combined_counter (cm, reg->item, &v);
845  = clib_host_to_net_u64 (v.packets);
847  clib_host_to_net_u64 (v.bytes);
848 
849 
850  /* TX vlib_counter_t packets/bytes */
852  vlib_get_combined_counter (cm, reg->item, &v);
854  = clib_host_to_net_u64 (v.packets);
856  clib_host_to_net_u64 (v.bytes);
857 
858  vl_msg_api_send_shmem (q, (u8 *) & mp);
859  }
860  }
861 
863 }
864 
865 /**********************************
866  * Per Interface simple stats
867  **********************************/
868 
869 /* Request from client registering interfaces it wants */
870 static void
873 {
874  stats_main_t *sm = &stats_main;
876  vl_api_want_per_interface_simple_stats_reply_t *rmp;
878  uword *p;
879  i32 retval = 0;
881  int i;
882  u32 swif;
883 
884  for (i = 0; i < mp->num; i++)
885  {
886  swif = mp->sw_ifs[i];
887 
888  /* Check its a real sw_if_index that the client is allowed to see */
889  if (swif != ~0)
890  {
892  {
893  retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
894  goto reply;
895  }
896  }
897  }
898 
899  for (i = 0; i < mp->num; i++)
900  {
901  swif = mp->sw_ifs[i];
902 
903  rp.client_index = mp->client_index;
904  rp.client_pid = mp->pid;
905  handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
906  swif, mp->enable_disable);
907  }
908 
909 reply:
911 
912  //Client may have disconnected abrubtly, clean up so we don't poll nothing.
913  if (!q)
914  {
915  for (i = 0; i < mp->num; i++)
916  {
917  swif = mp->sw_ifs[i];
918  sm->enable_poller =
919  clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
920  mp->client_index);
921  }
922 
923  return;
924  }
925 
926 
927  rmp = vl_msg_api_alloc (sizeof (*rmp));
928  rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
929  rmp->context = mp->context;
930  rmp->retval = retval;
931 
932  vl_msg_api_send_shmem (q, (u8 *) & rmp);
933 }
934 
935 /* Per Interface Simple distribution to client */
936 static void
938 {
941  api_main_t *am = sm->api_main;
945  /*
946  * items_this_message will eventually be used to optimise the batching
947  * of per client messages for each stat. For now setting this to 1 then
948  * iterate. This will not affect API.
949  *
950  * FIXME instead of enqueueing here, this should be sent to a batch
951  * storer for per-client transmission. Each "mp" sent would be a single entry
952  * and if a client is listening to other sw_if_indexes for same, it would be
953  * appended to that *mp
954  */
955  u32 items_this_message = 1;
956  int i, j, size;
959  u32 timestamp;
960  u32 count;
961  vnet_simple_counter_t *vp = 0;
962  counter_t v;
963 
964  /*
965  FIXME(s):
966  - capturing the timestamp of the counters "when VPP knew them" is important.
967  Less so is that the timing of the delivery to the control plane be in the same
968  timescale.
969 
970  i.e. As long as the control plane can delta messages from VPP and work out
971  velocity etc based on the timestamp, it can do so in a more "batch mode".
972 
973  It would be beneficial to keep a "per-client" message queue, and then
974  batch all the stat messages for a client into one message, with
975  discrete timestamps.
976 
977  Given this particular API is for "per interface" one assumes that the scale
978  is less than the ~0 case, which the prior API is suited for.
979  */
981 
982  timestamp = vlib_time_now (sm->vlib_main);
983 
985  pool_foreach (reg,
986  sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS], (
987  {
988  vec_add1
989  (sm->regs_tmp,
990  reg);}));
991 
992  for (i = 0; i < vec_len (sm->regs_tmp); i++)
993  {
994  reg = sm->regs_tmp[i];
995  if (reg->item == ~0)
996  {
1000  continue;
1001  }
1003  pool_foreach (client, reg->clients, (
1004  {
1005  vec_add1 (sm->clients_tmp,
1006  client);}
1007  ));
1008 
1009  //FIXME - should be doing non-variant part of mp here and managing
1010  // any alloc per client in that vec_foreach
1011  for (j = 0; j < vec_len (sm->clients_tmp); j++)
1012  {
1013  client = sm->clients_tmp[j];
1015 
1016  //Client may have disconnected abrubtly, clean up so we don't poll nothing.
1017  if (!q)
1018  {
1019  sm->enable_poller =
1020  clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
1021  reg->item, client->client_index);
1022  continue;
1023  }
1024 
1025  size = (sizeof (*mp) + (items_this_message * (sizeof (u64) * 10)));
1026  mp = vl_msg_api_alloc (size);
1027  // FIXME when optimising for items_this_message > 1 need to include a
1028  // SIMPLE_INTERFACE_BATCH_SIZE check.
1029  mp->_vl_msg_id = ntohs (VL_API_VNET_PER_INTERFACE_SIMPLE_COUNTERS);
1030 
1031  mp->count = items_this_message;
1032  mp->timestamp = timestamp;
1033  vp = (vnet_simple_counter_t *) mp->data;
1034 
1035  vp->sw_if_index = htonl (reg->item);
1036 
1037  //FIXME will be simpler with a preprocessor macro
1038  // VNET_INTERFACE_COUNTER_DROP
1040  v = vlib_get_simple_counter (cm, reg->item);
1041  clib_mem_unaligned (&vp->drop, u64) = clib_host_to_net_u64 (v);
1042 
1043  // VNET_INTERFACE_COUNTER_PUNT
1045  v = vlib_get_simple_counter (cm, reg->item);
1046  clib_mem_unaligned (&vp->punt, u64) = clib_host_to_net_u64 (v);
1047 
1048  // VNET_INTERFACE_COUNTER_IP4
1050  v = vlib_get_simple_counter (cm, reg->item);
1051  clib_mem_unaligned (&vp->rx_ip4, u64) = clib_host_to_net_u64 (v);
1052 
1053  //VNET_INTERFACE_COUNTER_IP6
1055  v = vlib_get_simple_counter (cm, reg->item);
1056  clib_mem_unaligned (&vp->rx_ip6, u64) = clib_host_to_net_u64 (v);
1057 
1058  //VNET_INTERFACE_COUNTER_RX_NO_BUF
1060  v = vlib_get_simple_counter (cm, reg->item);
1062  clib_host_to_net_u64 (v);
1063 
1064  //VNET_INTERFACE_COUNTER_RX_MISS
1066  v = vlib_get_simple_counter (cm, reg->item);
1067  clib_mem_unaligned (&vp->rx_miss, u64) = clib_host_to_net_u64 (v);
1068 
1069  //VNET_INTERFACE_COUNTER_RX_ERROR
1071  v = vlib_get_simple_counter (cm, reg->item);
1072  clib_mem_unaligned (&vp->rx_error, u64) = clib_host_to_net_u64 (v);
1073 
1074  //VNET_INTERFACE_COUNTER_TX_ERROR
1076  v = vlib_get_simple_counter (cm, reg->item);
1077  clib_mem_unaligned (&vp->tx_error, u64) = clib_host_to_net_u64 (v);
1078 
1079  //VNET_INTERFACE_COUNTER_MPLS
1081  v = vlib_get_simple_counter (cm, reg->item);
1082  clib_mem_unaligned (&vp->rx_mpls, u64) = clib_host_to_net_u64 (v);
1083 
1084  vl_msg_api_send_shmem (q, (u8 *) & mp);
1085  }
1086  }
1087 
1089 }
1090 
1091 /**********************************
1092  * Per FIB IP4 stats
1093  **********************************/
1094 
1095 static void
1097 {
1098  struct timespec _req, *req = &_req;
1099  struct timespec _rem, *rem = &_rem;
1100 
1101  req->tv_sec = sec;
1102  req->tv_nsec = nsec;
1103  while (1)
1104  {
1105  if (nanosleep (req, rem) == 0)
1106  break;
1107  *req = *rem;
1108  if (errno == EINTR)
1109  continue;
1110  clib_unix_warning ("nanosleep");
1111  break;
1112  }
1113 }
1114 
1115 /**
1116  * @brief The context passed when collecting adjacency counters
1117  */
1118 typedef struct ip4_nbr_stats_ctx_t_
1119 {
1120  /**
1121  * The SW IF index all these adjs belong to
1122  */
1124 
1125  /**
1126  * A vector of ip4 nbr counters
1127  */
1130 
1131 static adj_walk_rc_t
1133 {
1134  vl_api_ip4_nbr_counter_t *vl_counter;
1135  vlib_counter_t adj_counter;
1137  ip_adjacency_t *adj;
1138 
1139  ctx = arg;
1140  vlib_get_combined_counter (&adjacency_counters, ai, &adj_counter);
1141 
1142  if (0 != adj_counter.packets)
1143  {
1144  vec_add2 (ctx->counters, vl_counter, 1);
1145  adj = adj_get (ai);
1146 
1147  vl_counter->packets = clib_host_to_net_u64 (adj_counter.packets);
1148  vl_counter->bytes = clib_host_to_net_u64 (adj_counter.bytes);
1149  vl_counter->address = adj->sub_type.nbr.next_hop.ip4.as_u32;
1150  vl_counter->link_type = adj->ia_link;
1151  }
1152  return (ADJ_WALK_RC_CONTINUE);
1153 }
1154 
1155 #define MIN(x,y) (((x)<(y))?(x):(y))
1156 
1157 static void
1159 {
1160  api_main_t *am = sm->api_main;
1164  int first = 0;
1165 
1166  /*
1167  * If the walk context has counters, which may be left over from the last
1168  * suspend, then we continue from there.
1169  */
1170  while (0 != vec_len (ctx->counters))
1171  {
1172  u32 n_items = MIN (vec_len (ctx->counters),
1174  u8 pause = 0;
1175 
1176  dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1177 
1178  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
1179  (n_items *
1180  sizeof
1182  mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_NBR_COUNTERS);
1183  mp->count = ntohl (n_items);
1184  mp->sw_if_index = ntohl (ctx->sw_if_index);
1185  mp->begin = first;
1186  first = 0;
1187 
1188  /*
1189  * copy the counters from the back of the context, then we can easily
1190  * 'erase' them by resetting the vector length.
1191  * The order we push the stats to the caller is not important.
1192  */
1193  clib_memcpy (mp->c,
1194  &ctx->counters[vec_len (ctx->counters) - n_items],
1195  n_items * sizeof (*ctx->counters));
1196 
1197  _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
1198 
1199  /*
1200  * send to the shm q
1201  */
1204 
1205  vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1207  dsunlock (sm);
1208 
1209  if (pause)
1210  ip46_fib_stats_delay (sm, 0 /* sec */ ,
1212  }
1213 }
1214 
1215 static void
1217 {
1218  vnet_main_t *vnm = vnet_get_main ();
1220  vnet_sw_interface_t *si;
1221 
1223  .sw_if_index = 0,
1224  .counters = NULL,
1225  };
1226 
1227  /* *INDENT-OFF* */
1228  pool_foreach (si, im->sw_interfaces,
1229  ({
1230  /*
1231  * update the interface we are now concerned with
1232  */
1233  ctx.sw_if_index = si->sw_if_index;
1234 
1235  /*
1236  * we are about to walk another interface, so we shouldn't have any pending
1237  * stats to export.
1238  */
1239  ASSERT(ctx.counters == NULL);
1240 
1241  /*
1242  * visit each neighbour adjacency on the interface and collect
1243  * its current stats.
1244  * Because we hold the lock the walk is synchronous, so safe to routing
1245  * updates. It's limited in work by the number of adjacenies on an
1246  * interface, which is typically not huge.
1247  */
1248  dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1249  adj_nbr_walk (si->sw_if_index,
1250  FIB_PROTOCOL_IP4,
1251  ip4_nbr_stats_cb,
1252  &ctx);
1253  dsunlock (sm);
1254 
1255  /*
1256  * if this interface has some adjacencies with counters then ship them,
1257  * else continue to the next interface.
1258  */
1259  if (NULL != ctx.counters)
1260  {
1261  ip4_nbr_ship(sm, &ctx);
1262  }
1263  }));
1264  /* *INDENT-OFF* */
1265 }
1266 
1267 /**
1268  * @brief The context passed when collecting adjacency counters
1269  */
1270 typedef struct ip6_nbr_stats_ctx_t_
1271 {
1272  /**
1273  * The SW IF index all these adjs belong to
1274  */
1276 
1277  /**
1278  * A vector of ip6 nbr counters
1279  */
1282 
1283 static adj_walk_rc_t
1285  void *arg)
1286 {
1287  vl_api_ip6_nbr_counter_t *vl_counter;
1288  vlib_counter_t adj_counter;
1290  ip_adjacency_t *adj;
1291 
1292  ctx = arg;
1293  vlib_get_combined_counter(&adjacency_counters, ai, &adj_counter);
1294 
1295  if (0 != adj_counter.packets)
1296  {
1297  vec_add2(ctx->counters, vl_counter, 1);
1298  adj = adj_get(ai);
1299 
1300  vl_counter->packets = clib_host_to_net_u64(adj_counter.packets);
1301  vl_counter->bytes = clib_host_to_net_u64(adj_counter.bytes);
1302  vl_counter->address[0] = adj->sub_type.nbr.next_hop.ip6.as_u64[0];
1303  vl_counter->address[1] = adj->sub_type.nbr.next_hop.ip6.as_u64[1];
1304  vl_counter->link_type = adj->ia_link;
1305  }
1306  return (ADJ_WALK_RC_CONTINUE);
1307 }
1308 
1309 #define MIN(x,y) (((x)<(y))?(x):(y))
1310 
1311 static void
1314 {
1315  api_main_t *am = sm->api_main;
1319  int first = 0;
1320 
1321  /*
1322  * If the walk context has counters, which may be left over from the last
1323  * suspend, then we continue from there.
1324  */
1325  while (0 != vec_len(ctx->counters))
1326  {
1327  u32 n_items = MIN (vec_len (ctx->counters),
1329  u8 pause = 0;
1330 
1331  dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1332 
1333  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
1334  (n_items *
1335  sizeof
1337  mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_NBR_COUNTERS);
1338  mp->count = ntohl (n_items);
1339  mp->sw_if_index = ntohl (ctx->sw_if_index);
1340  mp->begin = first;
1341  first = 0;
1342 
1343  /*
1344  * copy the counters from the back of the context, then we can easily
1345  * 'erase' them by resetting the vector length.
1346  * The order we push the stats to the caller is not important.
1347  */
1348  clib_memcpy (mp->c,
1349  &ctx->counters[vec_len (ctx->counters) - n_items],
1350  n_items * sizeof (*ctx->counters));
1351 
1352  _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
1353 
1354  /*
1355  * send to the shm q
1356  */
1359 
1360  vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1362  dsunlock (sm);
1363 
1364  if (pause)
1365  ip46_fib_stats_delay (sm, 0 /* sec */ ,
1367  }
1368 }
1369 
1370 static void
1372 {
1373  vnet_main_t *vnm = vnet_get_main ();
1375  vnet_sw_interface_t *si;
1376 
1378  .sw_if_index = 0,
1379  .counters = NULL,
1380  };
1381 
1382  /* *INDENT-OFF* */
1383  pool_foreach (si, im->sw_interfaces,
1384  ({
1385  /*
1386  * update the interface we are now concerned with
1387  */
1388  ctx.sw_if_index = si->sw_if_index;
1389 
1390  /*
1391  * we are about to walk another interface, so we shouldn't have any pending
1392  * stats to export.
1393  */
1394  ASSERT(ctx.counters == NULL);
1395 
1396  /*
1397  * visit each neighbour adjacency on the interface and collect
1398  * its current stats.
1399  * Because we hold the lock the walk is synchronous, so safe to routing
1400  * updates. It's limited in work by the number of adjacenies on an
1401  * interface, which is typically not huge.
1402  */
1403  dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1404  adj_nbr_walk (si->sw_if_index,
1405  FIB_PROTOCOL_IP6,
1406  ip6_nbr_stats_cb,
1407  &ctx);
1408  dsunlock (sm);
1409 
1410  /*
1411  * if this interface has some adjacencies with counters then ship them,
1412  * else continue to the next interface.
1413  */
1414  if (NULL != ctx.counters)
1415  {
1416  ip6_nbr_ship(sm, &ctx);
1417  }
1418  }));
1419  /* *INDENT-OFF* */
1420 }
1421 
1422 static void
1424 {
1425  ip4_main_t *im4 = &ip4_main;
1426  api_main_t *am = sm->api_main;
1429  ip4_route_t *r;
1430  fib_table_t *fib;
1431  ip4_fib_t *v4_fib;
1432  do_ip46_fibs_t *do_fibs;
1434  u32 items_this_message;
1435  vl_api_ip4_fib_counter_t *ctrp = 0;
1436  u32 start_at_fib_index = 0;
1437  int i, j, k;
1438 
1439  do_fibs = &sm->do_ip46_fibs;
1440 
1441 again:
1442  vec_reset_length (do_fibs->fibs);
1443  /* *INDENT-OFF* */
1444  pool_foreach (fib, im4->fibs,
1445  ({vec_add1(do_fibs->fibs,fib);}));
1446 
1447  /* *INDENT-ON* */
1448 
1449  for (j = 0; j < vec_len (do_fibs->fibs); j++)
1450  {
1451  fib = do_fibs->fibs[j];
1452  /* We may have bailed out due to control-plane activity */
1453  while ((fib - im4->fibs) < start_at_fib_index)
1454  continue;
1455 
1456  v4_fib = pool_elt_at_index (im4->v4_fibs, fib->ft_index);
1457 
1458  if (mp == 0)
1459  {
1460  items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
1462  (sizeof (*mp) +
1463  items_this_message * sizeof (vl_api_ip4_fib_counter_t));
1464  mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
1465  mp->count = 0;
1466  mp->vrf_id = ntohl (fib->ft_table_id);
1467  ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1468  }
1469  else
1470  {
1471  /* happens if the last FIB was empty... */
1472  ASSERT (mp->count == 0);
1473  mp->vrf_id = ntohl (fib->ft_table_id);
1474  }
1475 
1476  dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1477 
1478  vec_reset_length (do_fibs->ip4routes);
1479  vec_reset_length (do_fibs->results);
1480 
1481  for (i = 0; i < ARRAY_LEN (v4_fib->fib_entry_by_dst_address); i++)
1482  {
1483  uword *hash = v4_fib->fib_entry_by_dst_address[i];
1484  hash_pair_t *p;
1485  ip4_route_t x;
1486 
1487  vec_reset_length (do_fibs->pvec);
1488 
1489  x.address_length = i;
1490 
1491  hash_foreach_pair (p, hash, (
1492  {
1493  vec_add1 (do_fibs->pvec, p);}
1494  ));
1495  for (k = 0; k < vec_len (do_fibs->pvec); k++)
1496  {
1497  p = do_fibs->pvec[k];
1498  x.address.data_u32 = p->key;
1499  x.index = p->value[0];
1500 
1501  vec_add1 (do_fibs->ip4routes, x);
1503  {
1504  start_at_fib_index = fib - im4->fibs;
1505  dsunlock (sm);
1506  ip46_fib_stats_delay (sm, 0 /* sec */ ,
1508  mp->count = 0;
1509  ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1510  goto again;
1511  }
1512  }
1513  }
1514 
1515  vec_foreach (r, do_fibs->ip4routes)
1516  {
1517  vlib_counter_t c;
1518  const dpo_id_t *dpo_id;
1519  u32 index;
1520 
1521  dpo_id = fib_entry_contribute_ip_forwarding (r->index);
1522  index = (u32) dpo_id->dpoi_index;
1523 
1525  index, &c);
1526  /*
1527  * If it has actually
1528  * seen at least one packet, send it.
1529  */
1530  if (c.packets > 0)
1531  {
1532 
1533  /* already in net byte order */
1534  ctrp->address = r->address.as_u32;
1535  ctrp->address_length = r->address_length;
1536  ctrp->packets = clib_host_to_net_u64 (c.packets);
1537  ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1538  mp->count++;
1539  ctrp++;
1540 
1541  if (mp->count == items_this_message)
1542  {
1543  mp->count = htonl (items_this_message);
1544  /*
1545  * If the main thread's input queue is stuffed,
1546  * drop the data structure lock (which the main thread
1547  * may want), and take a pause.
1548  */
1551  {
1552  dsunlock (sm);
1553  vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1555  mp = 0;
1556  ip46_fib_stats_delay (sm, 0 /* sec */ ,
1558  goto again;
1559  }
1560  vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1562 
1563  items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
1565  (sizeof (*mp) +
1566  items_this_message * sizeof (vl_api_ip4_fib_counter_t));
1567  mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
1568  mp->count = 0;
1569  mp->vrf_id = ntohl (fib->ft_table_id);
1570  ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1571  }
1572  } /* for each (mp or single) adj */
1574  {
1575  start_at_fib_index = fib - im4->fibs;
1576  dsunlock (sm);
1577  ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
1578  mp->count = 0;
1579  ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1580  goto again;
1581  }
1582  } /* vec_foreach (routes) */
1583 
1584  dsunlock (sm);
1585 
1586  /* Flush any data from this fib */
1587  if (mp->count)
1588  {
1589  mp->count = htonl (mp->count);
1590  vl_msg_api_send_shmem (q, (u8 *) & mp);
1591  mp = 0;
1592  }
1593  }
1594 
1595  /* If e.g. the last FIB had no reportable routes, free the buffer */
1596  if (mp)
1597  vl_msg_api_free (mp);
1598 }
1599 
1600 typedef struct
1601 {
1606 
1607 static void
1608 add_routes_in_fib (BVT (clib_bihash_kv) * kvp, void *arg)
1609 {
1610  add_routes_in_fib_arg_t *ap = arg;
1611  stats_main_t *sm = ap->sm;
1612 
1614  clib_longjmp (&sm->jmp_buf, 1);
1615 
1616  if (kvp->key[2] >> 32 == ap->fib_index)
1617  {
1619  ip6_route_t *r;
1620  addr = (ip6_address_t *) kvp;
1621  vec_add2 (*ap->routep, r, 1);
1622  r->address = addr[0];
1623  r->address_length = kvp->key[2] & 0xFF;
1624  r->index = kvp->value;
1625  }
1626 }
1627 
1628 static void
1630 {
1631  ip6_main_t *im6 = &ip6_main;
1632  api_main_t *am = sm->api_main;
1635  ip6_route_t *r;
1636  fib_table_t *fib;
1637  do_ip46_fibs_t *do_fibs;
1639  u32 items_this_message;
1640  vl_api_ip6_fib_counter_t *ctrp = 0;
1641  u32 start_at_fib_index = 0;
1642  BVT (clib_bihash) * h = &im6->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash;
1643  add_routes_in_fib_arg_t _a, *a = &_a;
1644  int i;
1645 
1646  do_fibs = &sm->do_ip46_fibs;
1647 again:
1648  vec_reset_length (do_fibs->fibs);
1649  /* *INDENT-OFF* */
1650  pool_foreach (fib, im6->fibs,
1651  ({vec_add1(do_fibs->fibs,fib);}));
1652  /* *INDENT-ON* */
1653 
1654 
1655  for (i = 0; i < vec_len (do_fibs->fibs); i++)
1656  {
1657  fib = do_fibs->fibs[i];
1658  /* We may have bailed out due to control-plane activity */
1659  while ((fib - im6->fibs) < start_at_fib_index)
1660  continue;
1661 
1662  if (mp == 0)
1663  {
1664  items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
1666  (sizeof (*mp) +
1667  items_this_message * sizeof (vl_api_ip6_fib_counter_t));
1668  mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
1669  mp->count = 0;
1670  mp->vrf_id = ntohl (fib->ft_table_id);
1671  ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
1672  }
1673 
1674  dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1675 
1676  vec_reset_length (do_fibs->ip6routes);
1677  vec_reset_length (do_fibs->results);
1678 
1679  a->fib_index = fib - im6->fibs;
1680  a->routep = &do_fibs->ip6routes;
1681  a->sm = sm;
1682 
1683  if (clib_setjmp (&sm->jmp_buf, 0) == 0)
1684  {
1685  start_at_fib_index = fib - im6->fibs;
1687  }
1688  else
1689  {
1690  dsunlock (sm);
1691  ip46_fib_stats_delay (sm, 0 /* sec */ ,
1693  mp->count = 0;
1694  ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
1695  goto again;
1696  }
1697 
1698  vec_foreach (r, do_fibs->ip6routes)
1699  {
1700  vlib_counter_t c;
1701 
1703  r->index, &c);
1704  /*
1705  * If it has actually
1706  * seen at least one packet, send it.
1707  */
1708  if (c.packets > 0)
1709  {
1710  /* already in net byte order */
1711  ctrp->address[0] = r->address.as_u64[0];
1712  ctrp->address[1] = r->address.as_u64[1];
1713  ctrp->address_length = (u8) r->address_length;
1714  ctrp->packets = clib_host_to_net_u64 (c.packets);
1715  ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1716  mp->count++;
1717  ctrp++;
1718 
1719  if (mp->count == items_this_message)
1720  {
1721  mp->count = htonl (items_this_message);
1722  /*
1723  * If the main thread's input queue is stuffed,
1724  * drop the data structure lock (which the main thread
1725  * may want), and take a pause.
1726  */
1729  {
1730  dsunlock (sm);
1731  vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1733  mp = 0;
1734  ip46_fib_stats_delay (sm, 0 /* sec */ ,
1736  goto again;
1737  }
1738  vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1740 
1741  items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
1743  (sizeof (*mp) +
1744  items_this_message * sizeof (vl_api_ip6_fib_counter_t));
1745  mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
1746  mp->count = 0;
1747  mp->vrf_id = ntohl (fib->ft_table_id);
1748  ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
1749  }
1750  }
1751 
1753  {
1754  start_at_fib_index = fib - im6->fibs;
1755  dsunlock (sm);
1756  ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
1757  mp->count = 0;
1758  ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
1759  goto again;
1760  }
1761  } /* vec_foreach (routes) */
1762 
1763  dsunlock (sm);
1764 
1765  /* Flush any data from this fib */
1766  if (mp->count)
1767  {
1768  mp->count = htonl (mp->count);
1769  vl_msg_api_send_shmem (q, (u8 *) & mp);
1770  mp = 0;
1771  }
1772  }
1773 
1774  /* If e.g. the last FIB had no reportable routes, free the buffer */
1775  if (mp)
1776  vl_msg_api_free (mp);
1777 }
1778 
1779 static void
1780 stats_thread_fn (void *arg)
1781 {
1782  stats_main_t *sm = &stats_main;
1785 
1786  /* stats thread wants no signals. */
1787  {
1788  sigset_t s;
1789  sigfillset (&s);
1790  pthread_sigmask (SIG_SETMASK, &s, 0);
1791  }
1792 
1793  if (vec_len (tm->thread_prefix))
1794  vlib_set_thread_name ((char *)
1795  format (0, "%v_stats%c", tm->thread_prefix, '\0'));
1796 
1798 
1799  while (1)
1800  {
1801  /* 10 second poll interval */
1802  ip46_fib_stats_delay (sm, 10 /* secs */ , 0 /* nsec */ );
1803 
1804  if (!(sm->enable_poller))
1805  {
1806  continue;
1807  }
1808  if (pool_elts
1809  (sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS]))
1811 
1812  if (pool_elts
1813  (sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS]))
1815 
1816  if (pool_elts (sm->stats_registrations[IDX_IP4_FIB_COUNTERS]))
1817  do_ip4_fib_counters (sm);
1818 
1819  if (pool_elts (sm->stats_registrations[IDX_IP6_FIB_COUNTERS]))
1820  do_ip6_fib_counters (sm);
1821 
1822  if (pool_elts (sm->stats_registrations[IDX_IP4_NBR_COUNTERS]))
1823  do_ip4_nbr_counters (sm);
1824 
1825  if (pool_elts (sm->stats_registrations[IDX_IP6_NBR_COUNTERS]))
1826  do_ip6_nbr_counters (sm);
1827  }
1828 }
1829 
1830 static void
1833 {
1834  vpe_client_registration_t *clients, client;
1835  stats_main_t *sm = &stats_main;
1836  unix_shared_memory_queue_t *q, *q_prev = NULL;
1838  u32 mp_size;
1839  int i;
1840 
1841  mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (u64));
1842 
1843  clients =
1844  get_clients_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
1845  ~0 /*flag for all */ );
1846 
1847  for (i = 0; i < vec_len (clients); i++)
1848  {
1849  client = clients[i];
1851  if (q)
1852  {
1853  if (q_prev && (q_prev->cursize < q_prev->maxsize))
1854  {
1855  mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
1856  clib_memcpy (mp_copy, mp, mp_size);
1857  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1858  mp = mp_copy;
1859  }
1860  q_prev = q;
1861  }
1862  else
1863  {
1864  sm->enable_poller =
1865  clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, ~0,
1866  client.client_index);
1867  continue;
1868  }
1869  }
1870 
1871 #if STATS_DEBUG > 0
1872  fformat (stdout, "%U\n", format_vnet_simple_counters, mp);
1873 #endif
1874 
1875  if (q_prev && (q_prev->cursize < q_prev->maxsize))
1876  {
1877  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1878  }
1879  else
1880  {
1881  vl_msg_api_free (mp);
1882  }
1883 }
1884 
1885 
1886 
1887 
1888 
1889 static void
1891 {
1892  stats_main_t *sm = &stats_main;
1893  unix_shared_memory_queue_t *q, *q_prev = NULL;
1895  u32 mp_size;
1896  vpe_client_registration_t *clients, client;
1897  int i;
1898 
1899  mp_size = sizeof (*mp_copy) +
1900  ntohl (mp->count) * sizeof (vl_api_ip4_fib_counter_t);
1901 
1902  clients =
1903  get_clients_for_stat (IDX_IP4_FIB_COUNTERS, ~0 /*flag for all */ );
1904 
1905  for (i = 0; i < vec_len (clients); i++)
1906  {
1907  client = clients[i];
1909  if (q)
1910  {
1911  if (q_prev && (q_prev->cursize < q_prev->maxsize))
1912  {
1913  mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
1914  clib_memcpy (mp_copy, mp, mp_size);
1915  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1916  mp = mp_copy;
1917  }
1918  q_prev = q;
1919  }
1920  else
1921  {
1922  sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
1923  ~0, client.client_index);
1924  continue;
1925  }
1926  }
1927 
1928  if (q_prev && (q_prev->cursize < q_prev->maxsize))
1929  {
1930  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1931  }
1932  else
1933  {
1934  vl_msg_api_free (mp);
1935  }
1936 }
1937 
1938 static void
1940 {
1941  stats_main_t *sm = &stats_main;
1942  unix_shared_memory_queue_t *q, *q_prev = NULL;
1944  u32 mp_size;
1945  vpe_client_registration_t *clients, client;
1946  int i;
1947 
1948  mp_size = sizeof (*mp_copy) +
1949  ntohl (mp->count) * sizeof (vl_api_ip4_nbr_counter_t);
1950 
1951  clients =
1952  get_clients_for_stat (IDX_IP4_NBR_COUNTERS, ~0 /*flag for all */ );
1953 
1954  for (i = 0; i < vec_len (clients); i++)
1955  {
1956  client = clients[i];
1958  if (q)
1959  {
1960  if (q_prev && (q_prev->cursize < q_prev->maxsize))
1961  {
1962  mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
1963  clib_memcpy (mp_copy, mp, mp_size);
1964  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1965  mp = mp_copy;
1966  }
1967  q_prev = q;
1968  }
1969  else
1970  {
1971  sm->enable_poller = clear_client_for_stat (IDX_IP4_NBR_COUNTERS,
1972  ~0, client.client_index);
1973  continue;
1974  }
1975  }
1976 
1977  /* *INDENT-ON* */
1978  if (q_prev && (q_prev->cursize < q_prev->maxsize))
1979  {
1980  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
1981  }
1982  else
1983  {
1984  vl_msg_api_free (mp);
1985  }
1986 }
1987 
1988 static void
1990 {
1991  stats_main_t *sm = &stats_main;
1992  unix_shared_memory_queue_t *q, *q_prev = NULL;
1994  u32 mp_size;
1995  vpe_client_registration_t *clients, client;
1996  int i;
1997 
1998  mp_size = sizeof (*mp_copy) +
1999  ntohl (mp->count) * sizeof (vl_api_ip6_fib_counter_t);
2000 
2001  clients =
2002  get_clients_for_stat (IDX_IP6_FIB_COUNTERS, ~0 /*flag for all */ );
2003 
2004  for (i = 0; i < vec_len (clients); i++)
2005  {
2006  client = clients[i];
2008  if (q)
2009  {
2010  if (q_prev && (q_prev->cursize < q_prev->maxsize))
2011  {
2012  mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2013  clib_memcpy (mp_copy, mp, mp_size);
2014  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
2015  mp = mp_copy;
2016  }
2017  q_prev = q;
2018  }
2019  else
2020  {
2021  sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2022  ~0, client.client_index);
2023  continue;
2024  }
2025  }
2026  /* *INDENT-ON* */
2027  if (q_prev && (q_prev->cursize < q_prev->maxsize))
2028  {
2029  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
2030  }
2031  else
2032  {
2033  vl_msg_api_free (mp);
2034  }
2035 }
2036 
2037 static void
2039 {
2040  stats_main_t *sm = &stats_main;
2041  unix_shared_memory_queue_t *q, *q_prev = NULL;
2043  u32 mp_size;
2044  vpe_client_registration_t *clients, client;
2045  int i;
2046 
2047  mp_size = sizeof (*mp_copy) +
2048  ntohl (mp->count) * sizeof (vl_api_ip6_nbr_counter_t);
2049 
2050  clients =
2051  get_clients_for_stat (IDX_IP6_NBR_COUNTERS, ~0 /*flag for all */ );
2052 
2053  for (i = 0; i < vec_len (clients); i++)
2054  {
2055  client = clients[i];
2057  if (q)
2058  {
2059  if (q_prev && (q_prev->cursize < q_prev->maxsize))
2060  {
2061  mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2062  clib_memcpy (mp_copy, mp, mp_size);
2063  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
2064  mp = mp_copy;
2065  }
2066  q_prev = q;
2067  }
2068  else
2069  {
2070  sm->enable_poller = clear_client_for_stat (IDX_IP6_NBR_COUNTERS,
2071  ~0, client.client_index);
2072  continue;
2073  }
2074  }
2075  /* *INDENT-ON* */
2076  if (q_prev && (q_prev->cursize < q_prev->maxsize))
2077  {
2078  vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
2079  }
2080  else
2081  {
2082  vl_msg_api_free (mp);
2083  }
2084 }
2085 
2086 static void
2088 {
2089  stats_main_t *sm = &stats_main;
2091  vl_api_want_stats_reply_t *rmp;
2092  uword *p;
2093  i32 retval = 0;
2094  u32 item;
2096 
2097  item = ~0; //"ALL THE THINGS IN THE THINGS
2098  rp.client_index = mp->client_index;
2099  rp.client_pid = mp->pid;
2100 
2101  handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
2102  item, mp->enable_disable);
2103 
2104  handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
2105  item, mp->enable_disable);
2106 
2107  handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS,
2108  item, mp->enable_disable);
2109 
2110  handle_client_registration (&rp, IDX_IP4_NBR_COUNTERS,
2111  item, mp->enable_disable);
2112 
2113  handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS,
2114  item, mp->enable_disable);
2115 
2116  handle_client_registration (&rp, IDX_IP6_NBR_COUNTERS,
2117  item, mp->enable_disable);
2118 
2119 reply:
2121 
2122  if (!q)
2123  return;
2124 
2125  rmp = vl_msg_api_alloc (sizeof (*rmp));
2126  rmp->_vl_msg_id = ntohs (VL_API_WANT_STATS_REPLY);
2127  rmp->context = mp->context;
2128  rmp->retval = retval;
2129 
2130  vl_msg_api_send_shmem (q, (u8 *) & rmp);
2131 }
2132 
2133 static void
2136 {
2137  stats_main_t *sm = &stats_main;
2139  vl_api_want_interface_simple_stats_reply_t *rmp;
2140  uword *p;
2141  i32 retval = 0;
2142  u32 swif;
2144 
2145  swif = ~0; //Using same mechanism as _per_interface_
2146  rp.client_index = mp->client_index;
2147  rp.client_pid = mp->pid;
2148 
2149  handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2150  mp->enable_disable);
2151 
2152 reply:
2154 
2155  if (!q)
2156  {
2157  sm->enable_poller =
2158  clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2159  mp->client_index);
2160  return;
2161  }
2162 
2163  rmp = vl_msg_api_alloc (sizeof (*rmp));
2164  rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_SIMPLE_STATS_REPLY);
2165  rmp->context = mp->context;
2166  rmp->retval = retval;
2167 
2168  vl_msg_api_send_shmem (q, (u8 *) & rmp);
2169 }
2170 
2171 
2172 static void
2174 {
2175  stats_main_t *sm = &stats_main;
2177  vl_api_want_ip4_fib_stats_reply_t *rmp;
2178  uword *p;
2179  i32 retval = 0;
2181  u32 fib;
2182 
2183  fib = ~0; //Using same mechanism as _per_interface_
2184  rp.client_index = mp->client_index;
2185  rp.client_pid = mp->pid;
2186 
2187  handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS, fib,
2188  mp->enable_disable);
2189 
2190 reply:
2192 
2193  if (!q)
2194  {
2195  sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
2196  fib, mp->client_index);
2197  return;
2198  }
2199 
2200  rmp = vl_msg_api_alloc (sizeof (*rmp));
2201  rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_FIB_STATS_REPLY);
2202  rmp->context = mp->context;
2203  rmp->retval = retval;
2204 
2205  vl_msg_api_send_shmem (q, (u8 *) & rmp);
2206 }
2207 
2208 static void
2210 {
2211  stats_main_t *sm = &stats_main;
2213  vl_api_want_ip4_fib_stats_reply_t *rmp;
2214  uword *p;
2215  i32 retval = 0;
2217  u32 fib;
2218 
2219  fib = ~0; //Using same mechanism as _per_interface_
2220  rp.client_index = mp->client_index;
2221  rp.client_pid = mp->pid;
2222 
2223  handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS, fib,
2224  mp->enable_disable);
2225 
2226 reply:
2228 
2229  if (!q)
2230  {
2231  sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2232  fib, mp->client_index);
2233  return;
2234  }
2235 
2236  rmp = vl_msg_api_alloc (sizeof (*rmp));
2237  rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_FIB_STATS_REPLY);
2238  rmp->context = mp->context;
2239  rmp->retval = retval;
2240 
2241  vl_msg_api_send_shmem (q, (u8 *) & rmp);
2242 }
2243 
2244 /* FIXME - NBR stats broken - this will be fixed in subsequent patch */
2245 static void
2247 {
2248 }
2249 
2250 static void
2252 {
2253 }
2254 
2255 static void
2257 {
2258  stats_main_t *sm = &stats_main;
2262  vlib_counter_t v;
2263  int i, which;
2264  u64 total_pkts[VLIB_N_RX_TX];
2265  u64 total_bytes[VLIB_N_RX_TX];
2266 
2269 
2270  if (!q)
2271  {
2272  return;
2273  }
2274 
2275  rmp = vl_msg_api_alloc (sizeof (*rmp));
2276  rmp->_vl_msg_id = ntohs (VL_API_VNET_GET_SUMMARY_STATS_REPLY);
2277  rmp->context = mp->context;
2278  rmp->retval = 0;
2279 
2280  memset (total_pkts, 0, sizeof (total_pkts));
2281  memset (total_bytes, 0, sizeof (total_bytes));
2282 
2284 
2286  {
2287  which = cm - im->combined_sw_if_counters;
2288 
2289  for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
2290  {
2291  vlib_get_combined_counter (cm, i, &v);
2292  total_pkts[which] += v.packets;
2293  total_bytes[which] += v.bytes;
2294  }
2295  }
2297 
2298  rmp->total_pkts[VLIB_RX] = clib_host_to_net_u64 (total_pkts[VLIB_RX]);
2299  rmp->total_bytes[VLIB_RX] = clib_host_to_net_u64 (total_bytes[VLIB_RX]);
2300  rmp->total_pkts[VLIB_TX] = clib_host_to_net_u64 (total_pkts[VLIB_TX]);
2301  rmp->total_bytes[VLIB_TX] = clib_host_to_net_u64 (total_bytes[VLIB_TX]);
2302  rmp->vector_rate =
2303  clib_host_to_net_u64 (vlib_last_vector_length_per_node (sm->vlib_main));
2304 
2305  vl_msg_api_send_shmem (q, (u8 *) & rmp);
2306 }
2307 
2308 int
2310 {
2312  stats_main_t *sm = &stats_main;
2313  uword *p;
2314 
2315  // FIXME
2316  /* p = hash_get (sm->stats_registration_hash, client_index); */
2317  /* if (p) */
2318  /* { */
2319  /* rp = pool_elt_at_index (sm->stats_registrations, p[0]); */
2320  /* pool_put (sm->stats_registrations, rp); */
2321  /* hash_unset (sm->stats_registration_hash, client_index); */
2322  /* } */
2323 
2324  return 0;
2325 }
2326 
2327 #define vl_api_vnet_interface_simple_counters_t_endian vl_noop_handler
2328 #define vl_api_vnet_interface_simple_counters_t_print vl_noop_handler
2329 #define vl_api_vnet_interface_combined_counters_t_endian vl_noop_handler
2330 #define vl_api_vnet_interface_combined_counters_t_print vl_noop_handler
2331 #define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
2332 #define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
2333 #define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
2334 #define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler
2335 #define vl_api_vnet_ip4_nbr_counters_t_endian vl_noop_handler
2336 #define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
2337 #define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
2338 #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
2339 
2340 static clib_error_t *
2342 {
2343  stats_main_t *sm = &stats_main;
2344  api_main_t *am = &api_main;
2345  void *vlib_worker_thread_bootstrap_fn (void *arg);
2346 
2347  sm->vlib_main = vm;
2348  sm->vnet_main = vnet_get_main ();
2350  sm->api_main = am;
2352  sm->data_structure_lock =
2355  memset (sm->data_structure_lock, 0, sizeof (*sm->data_structure_lock));
2356 
2357 #define _(N,n) \
2358  vl_msg_api_set_handlers(VL_API_##N, #n, \
2359  vl_api_##n##_t_handler, \
2360  vl_noop_handler, \
2361  vl_api_##n##_t_endian, \
2362  vl_api_##n##_t_print, \
2363  sizeof(vl_api_##n##_t), 0 /* do NOT trace! */);
2365 #undef _
2366 
2367  /* tell the msg infra not to free these messages... */
2368  am->message_bounce[VL_API_VNET_INTERFACE_SIMPLE_COUNTERS] = 1;
2369  am->message_bounce[VL_API_VNET_INTERFACE_COMBINED_COUNTERS] = 1;
2370  am->message_bounce[VL_API_VNET_IP4_FIB_COUNTERS] = 1;
2371  am->message_bounce[VL_API_VNET_IP6_FIB_COUNTERS] = 1;
2372  am->message_bounce[VL_API_VNET_IP4_NBR_COUNTERS] = 1;
2373  am->message_bounce[VL_API_VNET_IP6_NBR_COUNTERS] = 1;
2374 
2375  /*
2376  * Set up the (msg_name, crc, message-id) table
2377  */
2379 
2382 #define stats_reg(n) \
2383  sm->stats_registrations[IDX_##n] = 0; \
2384  sm->stats_registration_hash[IDX_##n] = 0;
2385 #include <vpp/stats/stats.reg>
2386 #undef stats_reg
2387 
2388  return 0;
2389 }
2390 
2392 
2393 /* *INDENT-OFF* */
2394 VLIB_REGISTER_THREAD (stats_thread_reg, static) = {
2395  .name = "stats",
2396  .function = stats_thread_fn,
2397  .fixed_count = 1,
2398  .count = 1,
2399  .no_data_structure_clone = 1,
2400  .use_pthreads = 1,
2401 };
2402 /* *INDENT-ON* */
2403 
2404 /*
2405  * fd.io coding-style-patch-verification: ON
2406  *
2407  * Local Variables:
2408  * eval: (c-set-style "gnu")
2409  * End:
2410  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
static void vl_api_vnet_get_summary_stats_t_handler(vl_api_vnet_get_summary_stats_t *mp)
Definition: stats.c:2256
Want Interface Simple Stats, register for detailed interface stats.
Definition: stats.api:44
static void stats_thread_fn(void *arg)
Definition: stats.c:1780
void * vl_msg_api_alloc_as_if_client(int nbytes)
static int set_client_for_stat(u32 reg, u32 item, vpe_client_registration_t *client)
Definition: stats.c:278
vpe_client_registration_t ** clients_tmp
Definition: stats.h:178
Want Stats, enable/disable ALL stats updates.
Definition: stats.api:28
vlib_combined_counter_main_t lbm_to_counters
Definition: load_balance.h:46
#define hash_set(h, key, value)
Definition: hash.h:254
u32 vlib_simple_counter_n_counters(const vlib_simple_counter_main_t *cm)
The number of counters (not the number of per-thread counters)
Definition: counter.c:107
do_ip46_fibs_t do_ip46_fibs
Definition: stats.h:171
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define clib_min(x, y)
Definition: clib.h:332
vl_api_vlib_counter_t data[count]
Definition: interface.api:305
vl_api_vnet_combined_counter_t data[count]
Definition: interface.api:331
vpe_client_registration_t * clients
Definition: stats.h:113
#define hash_unset(h, key)
Definition: hash.h:260
a
Definition: bitmap.h:516
int unix_shared_memory_queue_is_full(unix_shared_memory_queue_t *q)
vl_api_vnet_simple_counter_t data[count]
Definition: interface.api:319
static adj_walk_rc_t ip6_nbr_stats_cb(adj_index_t ai, void *arg)
Definition: stats.c:1284
hash_pair_t ** pvec
Definition: stats.h:88
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static void vl_api_want_interface_simple_stats_t_handler(vl_api_want_interface_simple_stats_t *mp)
Definition: stats.c:2135
vnet_interface_main_t interface_main
Definition: vnet.h:56
static void vl_api_vnet_interface_simple_counters_t_handler(vl_api_vnet_interface_simple_counters_t *mp)
Definition: stats.c:1832
u64 as_u64[2]
Definition: ip6_packet.h:51
unix_shared_memory_queue_t * vl_input_queue
Definition: api_common.h:68
#define NULL
Definition: clib.h:55
Request for a single block of summary stats.
Definition: stats.api:239
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:221
IP unicast adjacency.
Definition: adj.h:174
const dpo_id_t * fib_entry_contribute_ip_forwarding(fib_node_index_t fib_entry_index)
Definition: fib_entry.c:460
u8 * message_bounce
Don&#39;t automatically free message buffer vetor.
Definition: api_common.h:202
u32 enable_poller
Definition: stats.h:126
u32 sw_if_index
The SW IF index all these adjs belong to.
Definition: stats.c:1275
vlib_main_t * vlib_main
Definition: stats.h:181
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:518
Combined counter to hold both packets and byte differences.
Definition: counter.h:139
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:557
vl_api_ip4_nbr_counter_t c[count]
Definition: stats.api:200
VLIB_REGISTER_THREAD(stats_thread_reg, static)
void clib_longjmp(clib_longjmp_t *save, uword return_value)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static void ip46_fib_stats_delay(stats_main_t *sm, u32 sec, u32 nsec)
Definition: stats.c:1096
void handle_client_registration(vpe_client_registration_t *client, u32 stat, u32 item, int enable_disable)
Definition: stats.c:494
Combined stats counters structure.
Definition: interface.api:300
#define MIN(x, y)
Definition: stats.c:1309
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:225
u64 rx_bytes
byte counter
Definition: stats.h:70
uword clib_setjmp(clib_longjmp_t *save, uword return_value_not_taken)
static void vl_api_vnet_ip4_fib_counters_t_handler(vl_api_vnet_ip4_fib_counters_t *mp)
Definition: stats.c:1890
static clib_error_t * stats_init(vlib_main_t *vm)
Definition: stats.c:2341
format_function_t format_vnet_sw_if_index_name
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
uword value[0]
Definition: hash.h:164
vnet_link_t ia_link
link/ether-type 1 bytes
Definition: adj.h:195
static void do_ip6_nbr_counters(stats_main_t *sm)
Definition: stats.c:1371
static void vl_api_vnet_ip4_nbr_counters_t_handler(vl_api_vnet_ip4_nbr_counters_t *mp)
Definition: stats.c:1939
static f64 vlib_last_vector_length_per_node(vlib_main_t *vm)
Definition: main.h:312
volatile u32 release_hint
Definition: stats.h:33
static counter_t vlib_get_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Get the value of a simple counter Scrapes the entire set of per-thread counters.
Definition: counter.h:97
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:365
Combined stats counters structure per interface.
Definition: interface.api:327
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:437
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
vpe_client_stats_registration_t ** regs_tmp
Definition: stats.h:177
static void do_ip4_fib_counters(stats_main_t *sm)
Definition: stats.c:1423
vlib_combined_counter_main_t * combined_sw_if_counters
Definition: interface.h:668
static BVT(clib_bihash)
Definition: adj_nbr.c:26
enum adj_walk_rc_t_ adj_walk_rc_t
return codes from a adjacency walker callback function
int i32
Definition: types.h:81
#define IP6_FIB_COUNTER_BATCH_SIZE
Definition: stats.c:82
unsigned long u64
Definition: types.h:89
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
Definition: api_common.h:241
volatile u32 lock
Definition: stats.h:32
A collection of simple counters.
Definition: counter.h:58
static adj_walk_rc_t ip4_nbr_stats_cb(adj_index_t ai, void *arg)
Definition: stats.c:1132
void vlib_set_thread_name(char *name)
Definition: threads.c:267
void * vl_msg_api_alloc(int nbytes)
stats_main_t stats_main
Definition: stats.c:23
#define foreach_stats_msg
Definition: stats.c:46
static void vl_api_want_ip4_fib_stats_t_handler(vl_api_want_ip4_fib_stats_t *mp)
Definition: stats.c:2173
vl_shmem_hdr_t * shmem_hdr
static heap_elt_t * first(heap_header_t *h)
Definition: heap.c:59
void dsunlock(stats_main_t *sm)
Definition: stats.c:226
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:150
struct ip4_nbr_stats_ctx_t_ ip4_nbr_stats_ctx_t
The context passed when collecting adjacency counters.
vl_api_ip4_nbr_counter_t * counters
A vector of ip4 nbr counters.
Definition: stats.c:1128
#define hash_get(h, key)
Definition: hash.h:248
Want Per Interface simple Stats, register for continuous stats.
Definition: stats.api:60
static void vl_api_want_per_interface_combined_stats_t_handler(vl_api_want_per_interface_combined_stats_t *mp)
Definition: stats.c:677
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:458
ip6_route_t * ip6routes
Definition: stats.h:86
u32 ** enable_all_client_reg(u32 **registrations)
Definition: stats.c:424
counter_t packets
packet counter
Definition: counter.h:141
static void vl_api_want_ip6_fib_stats_t_handler(vl_api_want_ip6_fib_stats_t *mp)
Definition: stats.c:2209
struct ip_adjacency_t_::@38::@39 nbr
IP_LOOKUP_NEXT_ARP/IP_LOOKUP_NEXT_REWRITE.
static void vl_api_want_ip4_nbr_stats_t_handler(vl_api_want_ip4_nbr_stats_t *mp)
Definition: stats.c:2246
#define v
Definition: acl.c:323
u32 vlib_combined_counter_n_counters(const vlib_combined_counter_main_t *cm)
The number of counters (not the number of per-thread counters)
Definition: counter.c:100
static void vl_api_want_ip6_nbr_stats_t_handler(vl_api_want_ip6_nbr_stats_t *mp)
Definition: stats.c:2251
void vl_msg_api_free(void *)
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:270
#define PREDICT_FALSE(x)
Definition: clib.h:97
vlib_simple_counter_main_t * sw_if_counters
Definition: interface.h:667
load_balance_main_t load_balance_main
The one instance of load-balance main.
Definition: load_balance.c:55
static void ip4_nbr_ship(stats_main_t *sm, ip4_nbr_stats_ctx_t *ctx)
Definition: stats.c:1158
#define SIMPLE_COUNTER_BATCH_SIZE
Definition: stats.c:79
ip4_route_t * ip4routes
Definition: stats.h:85
void unix_shared_memory_queue_lock(unix_shared_memory_queue_t *q)
#define COMBINED_COUNTER_BATCH_SIZE
Definition: stats.c:80
vl_api_ip6_nbr_counter_t * counters
A vector of ip6 nbr counters.
Definition: stats.c:1280
vlib_combined_counter_main_t adjacency_counters
Adjacency packet counters.
Definition: adj.c:25
static void do_simple_interface_counters(stats_main_t *sm)
Definition: stats.c:440
u32 index
Definition: stats.h:79
word fformat(FILE *f, char *fmt,...)
Definition: format.c:453
The context passed when collecting adjacency counters.
Definition: stats.c:1118
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:182
int clear_client_for_stat(u32 reg, u32 item, u32 client_index)
Definition: stats.c:315
union ip_adjacency_t_::@38 sub_type
void clib_bihash_foreach_key_value_pair(clib_bihash *h, void *callback, void *arg)
Visit active (key,value) pairs in a bi-hash table.
The IPv4 FIB.
Definition: ip4_fib.h:39
u8 * format_vnet_interface_combined_counters(u8 *s, va_list *args)
Definition: stats.c:89
u32 sw_if_index
The SW IF index all these adjs belong to.
Definition: stats.c:1123
fib_node_index_t ft_index
Index into FIB vector.
Definition: fib_table.h:55
static void add_routes_in_fib(BVT(clib_bihash_kv)*kvp, void *arg)
Definition: stats.c:1608
stats_main_t * sm
Definition: stats.c:1604
static vpe_client_registration_t * get_client_for_stat(u32 reg, u32 item, u32 client_index)
Definition: stats.c:254
api_main_t api_main
Definition: api_shared.c:35
svmdb_client_t * c
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
u32 ft_table_id
Table ID (hash key) for this FIB.
Definition: fib_table.h:50
static void vlib_get_combined_counter(const vlib_combined_counter_main_t *cm, u32 index, vlib_counter_t *result)
Get the value of a combined counter, never called in the speed path Scrapes the entire set of per-thr...
Definition: counter.h:250
vlib_main_t * vm
Definition: buffer.c:283
vec_header_t h
Definition: buffer.c:282
uword * results
Definition: stats.h:89
clib_longjmp_t jmp_buf
Definition: stats.h:168
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
#define IP4_FIB_COUNTER_BATCH_SIZE
Definition: stats.c:81
static void * clib_mem_set_heap(void *heap)
Definition: mem.h:226
Want Interface Combined Stats, register for continuous stats.
Definition: stats.api:80
#define clib_warning(format, args...)
Definition: error.h:59
This table stores the routes that are used to forward traffic.
Definition: ip6.h:125
#define clib_memcpy(a, b, c)
Definition: string.h:69
unix_shared_memory_queue_t * vl_api_client_index_to_input_queue(u32 index)
static void vnet_interface_counter_unlock(vnet_interface_main_t *im)
Definition: interface.h:693
static void vl_api_vnet_ip6_fib_counters_t_handler(vl_api_vnet_ip6_fib_counters_t *mp)
Definition: stats.c:1989
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:267
Want IP6 FIB Stats, register for continuous stats.
Definition: stats.api:127
api_main_t * api_main
Definition: stats.h:184
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
#define ARRAY_LEN(x)
Definition: clib.h:59
vl_api_ip6_fib_counter_t c[count]
Definition: stats.api:215
Simple per interface stats counters structure.
Definition: interface.api:315
static void vnet_interface_counter_lock(vnet_interface_main_t *im)
Definition: interface.h:685
struct ip6_nbr_stats_ctx_t_ ip6_nbr_stats_ctx_t
The context passed when collecting adjacency counters.
void vl_msg_api_send_shmem(unix_shared_memory_queue_t *q, u8 *elem)
#define ASSERT(truth)
void stats_dslock_with_hint(int hint, int tag)
Definition: stats.c:219
u64 tx_packets
packet counter
Definition: stats.h:71
unsigned int u32
Definition: types.h:88
ip6_main_t ip6_main
Definition: ip6_forward.c:3043
static void ip6_nbr_ship(stats_main_t *sm, ip6_nbr_stats_ctx_t *ctx)
Definition: stats.c:1312
long ctx[MAX_CONNS]
Definition: main.c:95
#define STATS_RELEASE_DELAY_NS
Definition: stats.c:85
The context passed when collecting adjacency counters.
Definition: stats.c:1270
static void setup_message_id_table(api_main_t *am)
Definition: stats.c:70
uword ** stats_registration_hash
Definition: stats.h:161
IPv4 main type.
Definition: ip4.h:95
int stats_memclnt_delete_callback(u32 client_index)
Definition: stats.c:2309
static void do_combined_interface_counters(stats_main_t *sm)
Definition: stats.c:619
u64 size
Definition: vhost-user.h:76
vpe_client_stats_registration_t ** stats_registrations
Definition: stats.h:162
fib_table_t ** fibs
Definition: stats.h:87
size_t count
Definition: vapi.c:40
u64 counter_t
64bit counters
Definition: counter.h:54
Simple stats counters structure.
Definition: interface.api:283
Want IP6 NBR Stats, register for continuous stats.
Definition: stats.api:155
u32 stats_poll_interval_in_seconds
Definition: stats.h:125
ip6_fib_table_instance_t ip6_table[IP6_FIB_NUM_TABLES]
The two FIB tables; fwding and non-fwding.
Definition: ip6.h:156
u64 uword
Definition: types.h:112
void dslock(stats_main_t *sm, int release_hint, int tag)
Definition: stats.c:193
vl_api_ip4_fib_counter_t c[count]
Definition: stats.api:175
counter_t bytes
byte counter
Definition: counter.h:142
Want IP4 FIB Stats, register for continuous stats.
Definition: stats.api:113
data_structure_lock_t * data_structure_lock
Definition: stats.h:165
Definition: defs.h:47
u32 ** init_client_reg(u32 **registrations)
Definition: stats.c:398
Per-neighbour (i.e.
Definition: stats.api:195
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:166
void vl_msg_api_send_shmem_nolock(unix_shared_memory_queue_t *q, u8 *elem)
struct ip4_fib_t_ * v4_fibs
Vector of MTries.
Definition: ip4.h:103
u8 * format_vnet_interface_simple_counters(u8 *s, va_list *args)
Definition: stats.c:136
void unix_shared_memory_queue_unlock(unix_shared_memory_queue_t *q)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
vpe_client_registration_t * get_clients_for_stat(u32 reg, u32 item)
Definition: stats.c:359
vnet_interface_main_t * interface_main
Definition: stats.h:183
unsigned char u8
Definition: types.h:56
static void vl_api_want_stats_t_handler(vl_api_want_stats_t *mp)
Definition: stats.c:2087
#define hash_foreach_pair(p, v, body)
Iterate over hash pairs.
Definition: hash.h:349
static void clear_client_reg(u32 **registrations)
Definition: stats.c:385
vnet_sw_interface_t * sw_interfaces
Definition: interface.h:659
#define clib_unix_warning(format, args...)
Definition: error.h:68
u32 address_length
Definition: stats.h:78
A collection of combined counters.
Definition: counter.h:180
Want Per Interface Combined Stats, register for continuous stats.
Definition: stats.api:96
uword * fib_entry_by_dst_address[33]
Definition: ip4_fib.h:48
#define clib_mem_unaligned(pointer, type)
Definition: types.h:155
static void vl_api_vnet_ip6_nbr_counters_t_handler(vl_api_vnet_ip6_nbr_counters_t *mp)
Definition: stats.c:2038
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:120
static void do_ip6_fib_counters(stats_main_t *sm)
Definition: stats.c:1629
static void do_simple_per_interface_counters(stats_main_t *sm)
Definition: stats.c:937
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1175
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
Reply for vnet_get_summary_stats request.
Definition: stats.api:252
ip6_route_t ** routep
Definition: stats.c:1603
struct fib_table_t_ * fibs
Vector of FIBs.
Definition: ip4.h:100
#define vec_foreach(var, vec)
Vector iterator.
Want IP4 NBR Stats, register for continuous stats.
Definition: stats.api:141
static void vl_api_want_interface_combined_stats_t_handler(vl_api_want_interface_combined_stats_t *mp)
Definition: stats.c:535
void * vlib_worker_thread_bootstrap_fn(void *arg)
Definition: threads.c:670
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:101
static void do_combined_per_interface_counters(stats_main_t *sm)
Definition: stats.c:740
static void vl_api_vnet_interface_combined_counters_t_handler(vl_api_vnet_interface_combined_counters_t *mp)
Definition: stats.c:573
vhost_vring_addr_t addr
Definition: vhost-user.h:83
void stats_dsunlock(int hint, int tag)
Definition: stats.c:247
u64 tx_bytes
byte counter
Definition: stats.h:72
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
vnet_main_t * vnet_main
Definition: stats.h:182
struct fib_table_t_ * fibs
Definition: ip6.h:161
static void vl_api_want_per_interface_simple_stats_t_handler(vl_api_want_per_interface_simple_stats_t *mp)
Definition: stats.c:872
static void do_ip4_nbr_counters(stats_main_t *sm)
Definition: stats.c:1216
uword key
Definition: hash.h:161
vl_api_ip6_nbr_counter_t c[count]
Definition: stats.api:231
Definition: defs.h:46
A protocol Independent FIB table.
Definition: fib_table.h:35
struct _unix_shared_memory_queue unix_shared_memory_queue_t
ip6_address_t address
Definition: stats.h:77
u64 rx_packets
packet counter
Definition: stats.h:69
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128