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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vpp/stats/stats.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>
24 stats_main_t stats_main;
26 #include <vnet/ip/ip.h>
28 #include <vpp/api/vpe_msg_enum.h>
31 #define f64_print(a,b)
33 #define vl_typedefs /* define message structures */
34 #include <vpp/api/vpe_all_api_h.h>
37 #define vl_endianfun /* define message structures */
38 #include <vpp/api/vpe_all_api_h.h>
41 /* instantiate all the print functions we know about */
42 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
44 #include <vpp/api/vpe_all_api_h.h>
47 #define foreach_stats_msg \
48 _(WANT_STATS, want_stats) \
49 _(VNET_INTERFACE_SIMPLE_COUNTERS, vnet_interface_simple_counters) \
50 _(WANT_INTERFACE_SIMPLE_STATS, want_interface_simple_stats) \
51 _(VNET_INTERFACE_COMBINED_COUNTERS, vnet_interface_combined_counters) \
52 _(WANT_INTERFACE_COMBINED_STATS, want_interface_combined_stats) \
53 _(WANT_PER_INTERFACE_COMBINED_STATS, want_per_interface_combined_stats) \
54 _(WANT_PER_INTERFACE_SIMPLE_STATS, want_per_interface_simple_stats) \
55 _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \
56 _(WANT_IP4_FIB_STATS, want_ip4_fib_stats) \
57 _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \
58 _(WANT_IP6_FIB_STATS, want_ip6_fib_stats) \
59 _(WANT_IP4_MFIB_STATS, want_ip4_mfib_stats) \
60 _(WANT_IP6_MFIB_STATS, want_ip6_mfib_stats) \
61 _(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \
62 _(WANT_IP4_NBR_STATS, want_ip4_nbr_stats) \
63 _(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \
64 _(WANT_IP6_NBR_STATS, want_ip6_nbr_stats) \
65 _(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats) \
66 _(STATS_GET_POLLER_DELAY, stats_get_poller_delay)
69 #define vl_msg_name_crc_list
70 #include <vpp/stats/stats.api.h>
71 #undef vl_msg_name_crc_list
74 setup_message_id_table (api_main_t * am)
77 vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
78 foreach_vl_msg_name_crc_stats;
82 /* These constants ensure msg sizes <= 1024, aka ring allocation */
83 #define SIMPLE_COUNTER_BATCH_SIZE 126
84 #define COMBINED_COUNTER_BATCH_SIZE 63
85 #define IP4_FIB_COUNTER_BATCH_SIZE 48
86 #define IP6_FIB_COUNTER_BATCH_SIZE 30
87 #define IP4_MFIB_COUNTER_BATCH_SIZE 24
88 #define IP6_MFIB_COUNTER_BATCH_SIZE 15
91 #define STATS_RELEASE_DELAY_NS (1000 * 1000 * 5)
95 format_vnet_interface_combined_counters (u8 * s, va_list * args)
97 stats_main_t *sm = &stats_main;
98 vl_api_vnet_interface_combined_counters_t *mp =
99 va_arg (*args, vl_api_vnet_interface_combined_counters_t *);
102 u32 count, sw_if_index;
104 count = ntohl (mp->count);
105 sw_if_index = ntohl (mp->first_sw_if_index);
109 vp = (vlib_counter_t *) mp->data;
111 switch (mp->vnet_counter_type)
113 case VNET_INTERFACE_COUNTER_RX:
116 case VNET_INTERFACE_COUNTER_TX:
120 counter_name = "bogus";
123 for (i = 0; i < count; i++)
125 packets = clib_mem_unaligned (&vp->packets, u64);
126 packets = clib_net_to_host_u64 (packets);
127 bytes = clib_mem_unaligned (&vp->bytes, u64);
128 bytes = clib_net_to_host_u64 (bytes);
130 s = format (s, "%U.%s.packets %lld\n",
131 format_vnet_sw_if_index_name,
132 sm->vnet_main, sw_if_index, counter_name, packets);
133 s = format (s, "%U.%s.bytes %lld\n",
134 format_vnet_sw_if_index_name,
135 sm->vnet_main, sw_if_index, counter_name, bytes);
142 format_vnet_interface_simple_counters (u8 * s, va_list * args)
144 stats_main_t *sm = &stats_main;
145 vl_api_vnet_interface_simple_counters_t *mp =
146 va_arg (*args, vl_api_vnet_interface_simple_counters_t *);
148 u32 count, sw_if_index;
149 count = ntohl (mp->count);
150 sw_if_index = ntohl (mp->first_sw_if_index);
152 vp = (u64 *) mp->data;
155 switch (mp->vnet_counter_type)
157 case VNET_INTERFACE_COUNTER_DROP:
158 counter_name = "drop";
160 case VNET_INTERFACE_COUNTER_PUNT:
161 counter_name = "punt";
163 case VNET_INTERFACE_COUNTER_IP4:
164 counter_name = "ip4";
166 case VNET_INTERFACE_COUNTER_IP6:
167 counter_name = "ip6";
169 case VNET_INTERFACE_COUNTER_RX_NO_BUF:
170 counter_name = "rx-no-buff";
172 case VNET_INTERFACE_COUNTER_RX_MISS:
173 counter_name = "rx-miss";
175 case VNET_INTERFACE_COUNTER_RX_ERROR:
176 counter_name = "rx-error (fifo-full)";
178 case VNET_INTERFACE_COUNTER_TX_ERROR:
179 counter_name = "tx-error (fifo-full)";
182 counter_name = "bogus";
185 for (i = 0; i < count; i++)
187 v = clib_mem_unaligned (vp, u64);
188 v = clib_net_to_host_u64 (v);
190 s = format (s, "%U.%s %lld\n", format_vnet_sw_if_index_name,
191 sm->vnet_main, sw_if_index, counter_name, v);
199 dslock (stats_main_t * sm, int release_hint, int tag)
202 data_structure_lock_t *l = sm->data_structure_lock;
204 if (PREDICT_FALSE (l == 0))
207 thread_index = vlib_get_thread_index ();
208 if (l->lock && l->thread_index == thread_index)
217 while (__sync_lock_test_and_set (&l->lock, 1))
220 l->thread_index = thread_index;
225 stats_dslock_with_hint (int hint, int tag)
227 stats_main_t *sm = &stats_main;
228 dslock (sm, hint, tag);
232 dsunlock (stats_main_t * sm)
235 data_structure_lock_t *l = sm->data_structure_lock;
237 if (PREDICT_FALSE (l == 0))
240 thread_index = vlib_get_thread_index ();
241 ASSERT (l->lock && l->thread_index == thread_index);
247 CLIB_MEMORY_BARRIER ();
253 stats_dsunlock (int hint, int tag)
255 stats_main_t *sm = &stats_main;
259 static vpe_client_registration_t *
260 get_client_for_stat (u32 reg, u32 item, u32 client_index)
262 stats_main_t *sm = &stats_main;
263 vpe_client_stats_registration_t *registration;
266 /* Is there anything listening for item in that reg */
267 p = hash_get (sm->stats_registration_hash[reg], item);
272 /* If there is, is our client_index one of them */
273 registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
274 p = hash_get (registration->client_hash, client_index);
279 return pool_elt_at_index (registration->clients, p[0]);
284 set_client_for_stat (u32 reg, u32 item, vpe_client_registration_t * client)
286 stats_main_t *sm = &stats_main;
287 vpe_client_stats_registration_t *registration;
288 vpe_client_registration_t *cr;
291 /* Is there anything listening for item in that reg */
292 p = hash_get (sm->stats_registration_hash[reg], item);
296 pool_get (sm->stats_registrations[reg], registration);
297 registration->item = item;
298 hash_set (sm->stats_registration_hash[reg], item,
299 registration - sm->stats_registrations[reg]);
303 registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
306 p = hash_get (registration->client_hash, client->client_index);
310 pool_get (registration->clients, cr);
311 cr->client_index = client->client_index;
312 cr->client_pid = client->client_pid;
313 hash_set (registration->client_hash, cr->client_index,
314 cr - registration->clients);
317 return 1; //At least one client is doing something ... poll
321 clear_client_for_stat (u32 reg, u32 item, u32 client_index)
323 stats_main_t *sm = &stats_main;
324 vpe_client_stats_registration_t *registration;
325 vpe_client_registration_t *client;
329 /* Clear the client first */
330 /* Is there anything listening for item in that reg */
331 p = hash_get (sm->stats_registration_hash[reg], item);
336 /* If there is, is our client_index one of them */
337 registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
338 p = hash_get (registration->client_hash, client_index);
343 client = pool_elt_at_index (registration->clients, p[0]);
344 hash_unset (registration->client_hash, client->client_index);
345 pool_put (registration->clients, client);
347 /* Now check if that was the last client for that item */
348 if (0 == pool_elts (registration->clients))
350 hash_unset (sm->stats_registration_hash[reg], item);
351 pool_put (sm->stats_registrations[reg], registration);
356 /* Now check if that was the last item in any of the listened to stats */
357 for (i = 0; i < STATS_REG_N_IDX; i++)
359 elts += pool_elts (sm->stats_registrations[i]);
364 vpe_client_registration_t *
365 get_clients_for_stat (u32 reg, u32 item)
367 stats_main_t *sm = &stats_main;
368 vpe_client_registration_t *client, *clients = 0;
369 vpe_client_stats_registration_t *registration;
372 /* Is there anything listening for item in that reg */
373 p = hash_get (sm->stats_registration_hash[reg], item);
378 /* If there is, is our client_index one of them */
379 registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
381 vec_reset_length (clients);
382 pool_foreach (client, registration->clients, (
384 vec_add1 (clients, *client);}
391 clear_client_reg (u32 ** registrations)
393 /* When registrations[x] is a vector of pool indices
394 here is a good place to clean up the pools
396 #define stats_reg(n) vec_free(registrations[IDX_##n]);
397 #include <vpp/stats/stats.reg>
400 vec_free (registrations);
404 init_client_reg (u32 ** registrations)
408 Initialise the stats registrations for each
409 type of stat a client can register for as well as
410 a vector of "interested" indexes.
411 Initially this is a u32 of either sw_if_index or fib_index
412 but eventually this should migrate to a pool_index (u32)
413 with a type specific pool that can include more complex things
414 such as timing and structured events.
416 vec_validate (registrations, STATS_REG_N_IDX);
417 #define stats_reg(n) \
418 vec_reset_length(registrations[IDX_##n]);
419 #include <vpp/stats/stats.reg>
423 When registrations[x] is a vector of pool indices, here
424 is a good place to init the pools.
426 return registrations;
430 enable_all_client_reg (u32 ** registrations)
434 Enable all stats known by adding
435 ~0 to the index vector. Eventually this
436 should be deprecated.
438 #define stats_reg(n) \
439 vec_add1(registrations[IDX_##n], ~0);
440 #include <vpp/stats/stats.reg>
442 return registrations;
446 do_simple_interface_counters (stats_main_t * sm)
448 vl_api_vnet_interface_simple_counters_t *mp = 0;
449 vnet_interface_main_t *im = sm->interface_main;
450 api_main_t *am = sm->api_main;
451 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
452 svm_queue_t *q = shmem_hdr->vl_input_queue;
453 vlib_simple_counter_main_t *cm;
454 u32 items_this_message = 0;
459 * Prevent interface registration from expanding / moving the vectors...
460 * That tends never to happen, so we can hold this lock for a while.
462 vnet_interface_counter_lock (im);
464 vec_foreach (cm, im->sw_if_counters)
466 n_counts = vlib_simple_counter_n_counters (cm);
467 for (i = 0; i < n_counts; i++)
471 items_this_message = clib_min (SIMPLE_COUNTER_BATCH_SIZE,
474 mp = vl_msg_api_alloc_as_if_client
475 (sizeof (*mp) + items_this_message * sizeof (v));
476 mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_SIMPLE_COUNTERS);
477 mp->vnet_counter_type = cm - im->sw_if_counters;
478 mp->first_sw_if_index = htonl (i);
480 vp = (u64 *) mp->data;
482 v = vlib_get_simple_counter (cm, i);
483 clib_mem_unaligned (vp, u64) = clib_host_to_net_u64 (v);
486 if (mp->count == items_this_message)
488 mp->count = htonl (items_this_message);
489 /* Send to the main thread... */
490 vl_msg_api_send_shmem (q, (u8 *) & mp);
496 vnet_interface_counter_unlock (im);
500 handle_client_registration (vpe_client_registration_t * client, u32 stat,
501 u32 item, int enable_disable)
503 stats_main_t *sm = &stats_main;
504 vpe_client_registration_t *rp, _rp;
506 rp = get_client_for_stat (stat, item, client->client_index);
509 if (enable_disable == 0)
511 if (!rp) // No client to disable
513 clib_warning ("pid %d: already disabled for stats...",
518 clear_client_for_stat (stat, item, client->client_index);
525 rp->client_index = client->client_index;
526 rp->client_pid = client->client_pid;
527 sm->enable_poller = set_client_for_stat (stat, item, rp);
532 /**********************************
533 * ALL Interface Combined stats - to be deprecated
534 **********************************/
537 * This API should be deprecated as _per_interface_ works with ~0 as sw_if_index.
540 vl_api_want_interface_combined_stats_t_handler
541 (vl_api_want_interface_combined_stats_t * mp)
543 stats_main_t *sm = &stats_main;
544 vpe_client_registration_t rp;
545 vl_api_want_interface_combined_stats_reply_t *rmp;
548 vl_api_registration_t *reg;
551 swif = ~0; //Using same mechanism as _per_interface_
552 rp.client_index = mp->client_index;
553 rp.client_pid = mp->pid;
555 handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
559 reg = vl_api_client_index_to_registration (mp->client_index);
563 clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
568 rmp = vl_msg_api_alloc (sizeof (*rmp));
569 rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_COMBINED_STATS_REPLY);
570 rmp->context = mp->context;
571 rmp->retval = retval;
573 vl_api_send_msg (reg, (u8 *) rmp);
577 vl_api_vnet_interface_combined_counters_t_handler
578 (vl_api_vnet_interface_combined_counters_t * mp)
580 vpe_client_registration_t *clients, client;
581 stats_main_t *sm = &stats_main;
582 vl_api_registration_t *reg, *reg_prev = NULL;
583 vl_api_vnet_interface_combined_counters_t *mp_copy = NULL;
587 mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (vlib_counter_t));
590 get_clients_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
591 ~0 /*flag for all */ );
593 for (i = 0; i < vec_len (clients); i++)
596 reg = vl_api_client_index_to_registration (client.client_index);
599 if (reg_prev && vl_api_can_send_msg (reg_prev))
601 mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
602 clib_memcpy (mp_copy, mp, mp_size);
603 vl_api_send_msg (reg_prev, (u8 *) mp);
610 fformat (stdout, "%U\n", format_vnet_combined_counters, mp);
613 if (reg_prev && vl_api_can_send_msg (reg_prev))
615 vl_api_send_msg (reg_prev, (u8 *) mp);
619 vl_msg_api_free (mp);
624 do_combined_interface_counters (stats_main_t * sm)
626 vl_api_vnet_interface_combined_counters_t *mp = 0;
627 vnet_interface_main_t *im = sm->interface_main;
628 api_main_t *am = sm->api_main;
629 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
630 svm_queue_t *q = shmem_hdr->vl_input_queue;
631 vlib_combined_counter_main_t *cm;
632 u32 items_this_message = 0;
633 vlib_counter_t v, *vp = 0;
636 vnet_interface_counter_lock (im);
638 vec_foreach (cm, im->combined_sw_if_counters)
640 n_counts = vlib_combined_counter_n_counters (cm);
641 for (i = 0; i < n_counts; i++)
645 items_this_message = clib_min (COMBINED_COUNTER_BATCH_SIZE,
648 mp = vl_msg_api_alloc_as_if_client
649 (sizeof (*mp) + items_this_message * sizeof (v));
650 mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_COMBINED_COUNTERS);
651 mp->vnet_counter_type = cm - im->combined_sw_if_counters;
652 mp->first_sw_if_index = htonl (i);
654 vp = (vlib_counter_t *) mp->data;
656 vlib_get_combined_counter (cm, i, &v);
657 clib_mem_unaligned (&vp->packets, u64)
658 = clib_host_to_net_u64 (v.packets);
659 clib_mem_unaligned (&vp->bytes, u64) = clib_host_to_net_u64 (v.bytes);
662 if (mp->count == items_this_message)
664 mp->count = htonl (items_this_message);
665 /* Send to the main thread... */
666 vl_msg_api_send_shmem (q, (u8 *) & mp);
672 vnet_interface_counter_unlock (im);
675 /**********************************
676 * Per Interface Combined stats
677 **********************************/
679 /* Request from client registering interfaces it wants */
681 vl_api_want_per_interface_combined_stats_t_handler
682 (vl_api_want_per_interface_combined_stats_t * mp)
684 stats_main_t *sm = &stats_main;
685 vpe_client_registration_t rp;
686 vl_api_want_per_interface_combined_stats_reply_t *rmp;
687 vlib_combined_counter_main_t *cm;
690 vl_api_registration_t *reg;
691 u32 i, swif, num = 0;
693 num = ntohl (mp->num);
696 * Validate sw_if_indexes before registering
698 for (i = 0; i < num; i++)
700 swif = ntohl (mp->sw_ifs[i]);
703 * Check its a real sw_if_index that the client is allowed to see
707 if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
709 retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
715 for (i = 0; i < num; i++)
717 swif = ntohl (mp->sw_ifs[i]);
719 rp.client_index = mp->client_index;
720 rp.client_pid = mp->pid;
721 handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
722 swif, ntohl (mp->enable_disable));
726 reg = vl_api_client_index_to_registration (mp->client_index);
729 for (i = 0; i < num; i++)
731 swif = ntohl (mp->sw_ifs[i]);
734 clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
740 rmp = vl_msg_api_alloc (sizeof (*rmp));
741 rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_COMBINED_STATS_REPLY);
742 rmp->context = mp->context;
743 rmp->retval = retval;
745 vl_api_send_msg (reg, (u8 *) rmp);
748 /* Per Interface Combined distribution to client */
750 do_combined_per_interface_counters (stats_main_t * sm)
752 vl_api_vnet_per_interface_combined_counters_t *mp = 0;
753 vnet_interface_main_t *im = sm->interface_main;
754 api_main_t *am = sm->api_main;
755 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
756 vl_api_registration_t *vl_reg;
757 vlib_combined_counter_main_t *cm;
758 vl_api_vnet_combined_counter_t *vp = 0;
761 vpe_client_stats_registration_t *reg;
762 vpe_client_registration_t *client;
763 u32 *sw_if_index = 0;
765 vnet_interface_counter_lock (im);
767 vec_reset_length (sm->regs_tmp);
771 sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS],
772 ({ vec_add1 (sm->regs_tmp, reg); }));
775 for (i = 0; i < vec_len (sm->regs_tmp); i++)
777 reg = sm->regs_tmp[i];
780 vnet_interface_counter_unlock (im);
781 do_combined_interface_counters (sm);
782 vnet_interface_counter_lock (im);
785 vec_reset_length (sm->clients_tmp);
788 pool_foreach (client, reg->clients, ({ vec_add1 (sm->clients_tmp,
792 for (j = 0; j < vec_len (sm->clients_tmp); j++)
794 client = sm->clients_tmp[j];
796 vl_reg = vl_api_client_index_to_registration (client->client_index);
798 //Client may have disconnected abrubtly, clean up so we don't poll nothing.
802 clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
803 reg->item, client->client_index);
806 mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + sizeof (*vp));
807 memset (mp, 0, sizeof (*mp));
810 ntohs (VL_API_VNET_PER_INTERFACE_COMBINED_COUNTERS);
813 * count will eventually be used to optimise the batching
814 * of per client messages for each stat. For now setting this to 1 then
815 * iterate. This will not affect API.
817 * FIXME instead of enqueueing here, this should be sent to a batch
818 * storer for per-client transmission. Each "mp" sent would be a single entry
819 * and if a client is listening to other sw_if_indexes for same, it would be
820 * appended to that *mp
824 * - capturing the timestamp of the counters "when VPP knew them" is important.
825 * Less so is that the timing of the delivery to the control plane be in the same
828 * i.e. As long as the control plane can delta messages from VPP and work out
829 * velocity etc based on the timestamp, it can do so in a more "batch mode".
831 * It would be beneficial to keep a "per-client" message queue, and then
832 * batch all the stat messages for a client into one message, with
833 * discrete timestamps.
835 * Given this particular API is for "per interface" one assumes that the scale
836 * is less than the ~0 case, which the prior API is suited for.
840 * 1 message per api call for now
842 mp->count = htonl (1);
843 mp->timestamp = htonl (vlib_time_now (sm->vlib_main));
845 vp = (vl_api_vnet_combined_counter_t *) mp->data;
846 vp->sw_if_index = htonl (reg->item);
848 im = &vnet_get_main ()->interface_main;
849 cm = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX;
850 vlib_get_combined_counter (cm, reg->item, &v);
851 clib_mem_unaligned (&vp->rx_packets, u64) =
852 clib_host_to_net_u64 (v.packets);
853 clib_mem_unaligned (&vp->rx_bytes, u64) =
854 clib_host_to_net_u64 (v.bytes);
855 cm = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX;
856 vlib_get_combined_counter (cm, reg->item, &v);
857 clib_mem_unaligned (&vp->tx_packets, u64) =
858 clib_host_to_net_u64 (v.packets);
859 clib_mem_unaligned (&vp->tx_bytes, u64) =
860 clib_host_to_net_u64 (v.bytes);
862 vl_api_send_msg (vl_reg, (u8 *) mp);
866 vnet_interface_counter_unlock (im);
869 /**********************************
870 * Per Interface simple stats
871 **********************************/
873 /* Request from client registering interfaces it wants */
875 vl_api_want_per_interface_simple_stats_t_handler
876 (vl_api_want_per_interface_simple_stats_t * mp)
878 stats_main_t *sm = &stats_main;
879 vpe_client_registration_t rp;
880 vl_api_want_per_interface_simple_stats_reply_t *rmp;
881 vlib_simple_counter_main_t *cm;
884 vl_api_registration_t *reg;
885 u32 i, swif, num = 0;
887 num = ntohl (mp->num);
889 for (i = 0; i < num; i++)
891 swif = ntohl (mp->sw_ifs[i]);
893 /* Check its a real sw_if_index that the client is allowed to see */
896 if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
898 retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
904 for (i = 0; i < num; i++)
906 swif = ntohl (mp->sw_ifs[i]);
908 rp.client_index = mp->client_index;
909 rp.client_pid = mp->pid;
910 handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
911 swif, ntohl (mp->enable_disable));
915 reg = vl_api_client_index_to_registration (mp->client_index);
917 /* Client may have disconnected abruptly, clean up */
920 for (i = 0; i < num; i++)
922 swif = ntohl (mp->sw_ifs[i]);
924 clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
932 rmp = vl_msg_api_alloc (sizeof (*rmp));
933 rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
934 rmp->context = mp->context;
935 rmp->retval = retval;
937 vl_api_send_msg (reg, (u8 *) rmp);
940 /* Per Interface Simple distribution to client */
942 do_simple_per_interface_counters (stats_main_t * sm)
944 vl_api_vnet_per_interface_simple_counters_t *mp = 0;
945 vnet_interface_main_t *im = sm->interface_main;
946 api_main_t *am = sm->api_main;
947 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
948 vl_api_registration_t *vl_reg;
949 vlib_simple_counter_main_t *cm;
951 vpe_client_stats_registration_t *reg;
952 vpe_client_registration_t *client;
953 u32 timestamp, count;
954 vl_api_vnet_simple_counter_t *vp = 0;
957 vnet_interface_counter_lock (im);
959 vec_reset_length (sm->regs_tmp);
963 sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS],
964 ({ vec_add1 (sm->regs_tmp, reg); }));
967 for (i = 0; i < vec_len (sm->regs_tmp); i++)
969 reg = sm->regs_tmp[i];
972 vnet_interface_counter_unlock (im);
973 do_simple_interface_counters (sm);
974 vnet_interface_counter_lock (im);
977 vec_reset_length (sm->clients_tmp);
980 pool_foreach (client, reg->clients, ({ vec_add1 (sm->clients_tmp,
984 for (j = 0; j < vec_len (sm->clients_tmp); j++)
986 client = sm->clients_tmp[j];
987 vl_reg = vl_api_client_index_to_registration (client->client_index);
989 /* Client may have disconnected abrubtly, clean up */
993 clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
994 reg->item, client->client_index);
998 mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + sizeof (*vp));
999 memset (mp, 0, sizeof (*mp));
1000 mp->_vl_msg_id = ntohs (VL_API_VNET_PER_INTERFACE_SIMPLE_COUNTERS);
1003 * count will eventually be used to optimise the batching
1004 * of per client messages for each stat. For now setting this to 1 then
1005 * iterate. This will not affect API.
1007 * FIXME instead of enqueueing here, this should be sent to a batch
1008 * storer for per-client transmission. Each "mp" sent would be a single entry
1009 * and if a client is listening to other sw_if_indexes for same, it would be
1010 * appended to that *mp
1014 * - capturing the timestamp of the counters "when VPP knew them" is important.
1015 * Less so is that the timing of the delivery to the control plane be in the same
1018 * i.e. As long as the control plane can delta messages from VPP and work out
1019 * velocity etc based on the timestamp, it can do so in a more "batch mode".
1021 * It would be beneficial to keep a "per-client" message queue, and then
1022 * batch all the stat messages for a client into one message, with
1023 * discrete timestamps.
1025 * Given this particular API is for "per interface" one assumes that the scale
1026 * is less than the ~0 case, which the prior API is suited for.
1030 * 1 message per api call for now
1032 mp->count = htonl (1);
1033 mp->timestamp = htonl (vlib_time_now (sm->vlib_main));
1034 vp = (vl_api_vnet_simple_counter_t *) mp->data;
1036 vp->sw_if_index = htonl (reg->item);
1038 // VNET_INTERFACE_COUNTER_DROP
1039 cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
1040 v = vlib_get_simple_counter (cm, reg->item);
1041 clib_mem_unaligned (&vp->drop, u64) = clib_host_to_net_u64 (v);
1043 // VNET_INTERFACE_COUNTER_PUNT
1044 cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_PUNT;
1045 v = vlib_get_simple_counter (cm, reg->item);
1046 clib_mem_unaligned (&vp->punt, u64) = clib_host_to_net_u64 (v);
1048 // VNET_INTERFACE_COUNTER_IP4
1049 cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP4;
1050 v = vlib_get_simple_counter (cm, reg->item);
1051 clib_mem_unaligned (&vp->rx_ip4, u64) = clib_host_to_net_u64 (v);
1053 //VNET_INTERFACE_COUNTER_IP6
1054 cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP6;
1055 v = vlib_get_simple_counter (cm, reg->item);
1056 clib_mem_unaligned (&vp->rx_ip6, u64) = clib_host_to_net_u64 (v);
1058 //VNET_INTERFACE_COUNTER_RX_NO_BUF
1059 cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_NO_BUF;
1060 v = vlib_get_simple_counter (cm, reg->item);
1061 clib_mem_unaligned (&vp->rx_no_buffer, u64) =
1062 clib_host_to_net_u64 (v);
1064 //VNET_INTERFACE_COUNTER_RX_MISS
1065 cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_MISS;
1066 v = vlib_get_simple_counter (cm, reg->item);
1067 clib_mem_unaligned (&vp->rx_miss, u64) = clib_host_to_net_u64 (v);
1069 //VNET_INTERFACE_COUNTER_RX_ERROR
1070 cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_ERROR;
1071 v = vlib_get_simple_counter (cm, reg->item);
1072 clib_mem_unaligned (&vp->rx_error, u64) = clib_host_to_net_u64 (v);
1074 //VNET_INTERFACE_COUNTER_TX_ERROR
1075 cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_TX_ERROR;
1076 v = vlib_get_simple_counter (cm, reg->item);
1077 clib_mem_unaligned (&vp->tx_error, u64) = clib_host_to_net_u64 (v);
1079 //VNET_INTERFACE_COUNTER_MPLS
1080 cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_MPLS;
1081 v = vlib_get_simple_counter (cm, reg->item);
1082 clib_mem_unaligned (&vp->rx_mpls, u64) = clib_host_to_net_u64 (v);
1084 vl_api_send_msg (vl_reg, (u8 *) mp);
1088 vnet_interface_counter_unlock (im);
1091 /**********************************
1093 **********************************/
1096 ip46_fib_stats_delay (stats_main_t * sm, u32 sec, u32 nsec)
1098 struct timespec _req, *req = &_req;
1099 struct timespec _rem, *rem = &_rem;
1102 req->tv_nsec = nsec;
1105 if (nanosleep (req, rem) == 0)
1110 clib_unix_warning ("nanosleep");
1116 * @brief The context passed when collecting adjacency counters
1118 typedef struct ip4_nbr_stats_ctx_t_
1121 * The SW IF index all these adjs belong to
1126 * A vector of ip4 nbr counters
1128 vl_api_ip4_nbr_counter_t *counters;
1129 } ip4_nbr_stats_ctx_t;
1131 static adj_walk_rc_t
1132 ip4_nbr_stats_cb (adj_index_t ai, void *arg)
1134 vl_api_ip4_nbr_counter_t *vl_counter;
1135 vlib_counter_t adj_counter;
1136 ip4_nbr_stats_ctx_t *ctx;
1137 ip_adjacency_t *adj;
1140 vlib_get_combined_counter (&adjacency_counters, ai, &adj_counter);
1142 if (0 != adj_counter.packets)
1144 vec_add2 (ctx->counters, vl_counter, 1);
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;
1152 return (ADJ_WALK_RC_CONTINUE);
1155 #define MIN(x,y) (((x)<(y))?(x):(y))
1158 ip4_nbr_ship (stats_main_t * sm, ip4_nbr_stats_ctx_t * ctx)
1160 api_main_t *am = sm->api_main;
1161 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1162 svm_queue_t *q = shmem_hdr->vl_input_queue;
1163 vl_api_vnet_ip4_nbr_counters_t *mp = 0;
1167 * If the walk context has counters, which may be left over from the last
1168 * suspend, then we continue from there.
1170 while (0 != vec_len (ctx->counters))
1172 u32 n_items = MIN (vec_len (ctx->counters),
1173 IP4_FIB_COUNTER_BATCH_SIZE);
1176 dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1178 mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
1181 (vl_api_ip4_nbr_counter_t)));
1182 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_NBR_COUNTERS);
1183 mp->count = ntohl (n_items);
1184 mp->sw_if_index = ntohl (ctx->sw_if_index);
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.
1194 &ctx->counters[vec_len (ctx->counters) - n_items],
1195 n_items * sizeof (*ctx->counters));
1197 _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
1203 pause = svm_queue_is_full (q);
1205 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1206 svm_queue_unlock (q);
1210 ip46_fib_stats_delay (sm, 0 /* sec */ ,
1211 STATS_RELEASE_DELAY_NS);
1216 do_ip4_nbr_counters (stats_main_t * sm)
1218 vnet_main_t *vnm = vnet_get_main ();
1219 vnet_interface_main_t *im = &vnm->interface_main;
1220 vnet_sw_interface_t *si;
1222 ip4_nbr_stats_ctx_t ctx = {
1228 pool_foreach (si, im->sw_interfaces,
1231 * update the interface we are now concerned with
1233 ctx.sw_if_index = si->sw_if_index;
1236 * we are about to walk another interface, so we shouldn't have any pending
1239 ASSERT(ctx.counters == NULL);
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.
1248 dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1249 adj_nbr_walk (si->sw_if_index,
1256 * if this interface has some adjacencies with counters then ship them,
1257 * else continue to the next interface.
1259 if (NULL != ctx.counters)
1261 ip4_nbr_ship(sm, &ctx);
1268 * @brief The context passed when collecting adjacency counters
1270 typedef struct ip6_nbr_stats_ctx_t_
1273 * The SW IF index all these adjs belong to
1278 * A vector of ip6 nbr counters
1280 vl_api_ip6_nbr_counter_t *counters;
1281 } ip6_nbr_stats_ctx_t;
1283 static adj_walk_rc_t
1284 ip6_nbr_stats_cb (adj_index_t ai,
1287 vl_api_ip6_nbr_counter_t *vl_counter;
1288 vlib_counter_t adj_counter;
1289 ip6_nbr_stats_ctx_t *ctx;
1290 ip_adjacency_t *adj;
1293 vlib_get_combined_counter(&adjacency_counters, ai, &adj_counter);
1295 if (0 != adj_counter.packets)
1297 vec_add2(ctx->counters, vl_counter, 1);
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;
1306 return (ADJ_WALK_RC_CONTINUE);
1309 #define MIN(x,y) (((x)<(y))?(x):(y))
1312 ip6_nbr_ship (stats_main_t * sm,
1313 ip6_nbr_stats_ctx_t *ctx)
1315 api_main_t *am = sm->api_main;
1316 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1317 svm_queue_t *q = shmem_hdr->vl_input_queue;
1318 vl_api_vnet_ip6_nbr_counters_t *mp = 0;
1322 * If the walk context has counters, which may be left over from the last
1323 * suspend, then we continue from there.
1325 while (0 != vec_len(ctx->counters))
1327 u32 n_items = MIN (vec_len (ctx->counters),
1328 IP6_FIB_COUNTER_BATCH_SIZE);
1331 dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1333 mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
1336 (vl_api_ip6_nbr_counter_t)));
1337 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_NBR_COUNTERS);
1338 mp->count = ntohl (n_items);
1339 mp->sw_if_index = ntohl (ctx->sw_if_index);
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.
1349 &ctx->counters[vec_len (ctx->counters) - n_items],
1350 n_items * sizeof (*ctx->counters));
1352 _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
1358 pause = svm_queue_is_full (q);
1360 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1361 svm_queue_unlock (q);
1365 ip46_fib_stats_delay (sm, 0 /* sec */ ,
1366 STATS_RELEASE_DELAY_NS);
1371 do_ip6_nbr_counters (stats_main_t * sm)
1373 vnet_main_t *vnm = vnet_get_main ();
1374 vnet_interface_main_t *im = &vnm->interface_main;
1375 vnet_sw_interface_t *si;
1377 ip6_nbr_stats_ctx_t ctx = {
1383 pool_foreach (si, im->sw_interfaces,
1386 * update the interface we are now concerned with
1388 ctx.sw_if_index = si->sw_if_index;
1391 * we are about to walk another interface, so we shouldn't have any pending
1394 ASSERT(ctx.counters == NULL);
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.
1403 dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1404 adj_nbr_walk (si->sw_if_index,
1411 * if this interface has some adjacencies with counters then ship them,
1412 * else continue to the next interface.
1414 if (NULL != ctx.counters)
1416 ip6_nbr_ship(sm, &ctx);
1423 do_ip4_fib_counters (stats_main_t * sm)
1425 ip4_main_t *im4 = &ip4_main;
1426 api_main_t *am = sm->api_main;
1427 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1428 svm_queue_t *q = shmem_hdr->vl_input_queue;
1432 do_ip46_fibs_t *do_fibs;
1433 vl_api_vnet_ip4_fib_counters_t *mp = 0;
1434 u32 items_this_message;
1435 vl_api_ip4_fib_counter_t *ctrp = 0;
1436 u32 start_at_fib_index = 0;
1439 do_fibs = &sm->do_ip46_fibs;
1442 vec_reset_length (do_fibs->fibs);
1444 pool_foreach (fib, im4->fibs,
1445 ({vec_add1(do_fibs->fibs,fib);}));
1449 for (j = 0; j < vec_len (do_fibs->fibs); j++)
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)
1456 v4_fib = pool_elt_at_index (im4->v4_fibs, fib->ft_index);
1460 items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
1461 mp = vl_msg_api_alloc_as_if_client
1463 items_this_message * sizeof (vl_api_ip4_fib_counter_t));
1464 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
1466 mp->vrf_id = ntohl (fib->ft_table_id);
1467 ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1471 /* happens if the last FIB was empty... */
1472 ASSERT (mp->count == 0);
1473 mp->vrf_id = ntohl (fib->ft_table_id);
1476 dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1478 vec_reset_length (do_fibs->ip4routes);
1479 vec_reset_length (do_fibs->results);
1481 for (i = 0; i < ARRAY_LEN (v4_fib->fib_entry_by_dst_address); i++)
1483 uword *hash = v4_fib->fib_entry_by_dst_address[i];
1487 vec_reset_length (do_fibs->pvec);
1489 x.address_length = i;
1491 hash_foreach_pair (p, hash, (
1493 vec_add1 (do_fibs->pvec, p);}
1495 for (k = 0; k < vec_len (do_fibs->pvec); k++)
1497 p = do_fibs->pvec[k];
1498 x.address.data_u32 = p->key;
1499 x.index = p->value[0];
1501 vec_add1 (do_fibs->ip4routes, x);
1502 if (sm->data_structure_lock->release_hint)
1504 start_at_fib_index = fib - im4->fibs;
1506 ip46_fib_stats_delay (sm, 0 /* sec */ ,
1507 STATS_RELEASE_DELAY_NS);
1509 ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1515 vec_foreach (r, do_fibs->ip4routes)
1518 const dpo_id_t *dpo_id;
1521 dpo_id = fib_entry_contribute_ip_forwarding (r->index);
1522 index = (u32) dpo_id->dpoi_index;
1524 vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
1527 * If it has actually
1528 * seen at least one packet, send it.
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);
1541 if (mp->count == items_this_message)
1543 mp->count = htonl (items_this_message);
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.
1550 if (svm_queue_is_full (q))
1553 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1554 svm_queue_unlock (q);
1556 ip46_fib_stats_delay (sm, 0 /* sec */ ,
1557 STATS_RELEASE_DELAY_NS);
1560 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1561 svm_queue_unlock (q);
1563 items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
1564 mp = vl_msg_api_alloc_as_if_client
1566 items_this_message * sizeof (vl_api_ip4_fib_counter_t));
1567 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
1569 mp->vrf_id = ntohl (fib->ft_table_id);
1570 ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1572 } /* for each (mp or single) adj */
1573 if (sm->data_structure_lock->release_hint)
1575 start_at_fib_index = fib - im4->fibs;
1577 ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
1579 ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
1582 } /* vec_foreach (routes) */
1586 /* Flush any data from this fib */
1589 mp->count = htonl (mp->count);
1590 vl_msg_api_send_shmem (q, (u8 *) & mp);
1595 /* If e.g. the last FIB had no reportable routes, free the buffer */
1597 vl_msg_api_free (mp);
1601 mfib_table_stats_walk_cb (fib_node_index_t fei, void *ctx)
1603 stats_main_t *sm = ctx;
1604 do_ip46_fibs_t *do_fibs;
1605 mfib_entry_t *entry;
1607 do_fibs = &sm->do_ip46_fibs;
1608 entry = mfib_entry_get (fei);
1610 vec_add1 (do_fibs->mroutes, entry->mfe_prefix);
1616 do_ip4_mfib_counters (stats_main_t * sm)
1618 ip4_main_t *im4 = &ip4_main;
1619 api_main_t *am = sm->api_main;
1620 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1621 svm_queue_t *q = shmem_hdr->vl_input_queue;
1624 do_ip46_fibs_t *do_fibs;
1625 vl_api_vnet_ip4_mfib_counters_t *mp = 0;
1626 u32 items_this_message;
1627 vl_api_ip4_mfib_counter_t *ctrp = 0;
1628 u32 start_at_mfib_index = 0;
1631 do_fibs = &sm->do_ip46_fibs;
1633 vec_reset_length (do_fibs->mfibs);
1635 pool_foreach (mfib, im4->mfibs, ({vec_add1(do_fibs->mfibs, mfib);}));
1638 for (j = 0; j < vec_len (do_fibs->mfibs); j++)
1640 mfib = do_fibs->mfibs[j];
1641 /* We may have bailed out due to control-plane activity */
1642 while ((mfib - im4->mfibs) < start_at_mfib_index)
1647 items_this_message = IP4_MFIB_COUNTER_BATCH_SIZE;
1648 mp = vl_msg_api_alloc_as_if_client
1650 items_this_message * sizeof (vl_api_ip4_mfib_counter_t));
1651 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_MFIB_COUNTERS);
1653 mp->vrf_id = ntohl (mfib->mft_table_id);
1654 ctrp = (vl_api_ip4_mfib_counter_t *) mp->c;
1658 /* happens if the last MFIB was empty... */
1659 ASSERT (mp->count == 0);
1660 mp->vrf_id = ntohl (mfib->mft_table_id);
1663 vec_reset_length (do_fibs->mroutes);
1666 * walk the table with table updates blocked
1668 dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1670 mfib_table_walk (mfib->mft_index,
1671 FIB_PROTOCOL_IP4, mfib_table_stats_walk_cb, sm);
1674 vec_foreach (pfx, do_fibs->mroutes)
1676 const dpo_id_t *dpo_id;
1677 fib_node_index_t mfei;
1682 * re-lookup the entry, since we suspend during the collection
1684 mfei = mfib_table_lookup (mfib->mft_index, pfx);
1686 if (FIB_NODE_INDEX_INVALID == mfei)
1689 dpo_id = mfib_entry_contribute_ip_forwarding (mfei);
1690 index = (u32) dpo_id->dpoi_index;
1692 vlib_get_combined_counter (&replicate_main.repm_counters,
1693 dpo_id->dpoi_index, &c);
1695 * If it has seen at least one packet, send it.
1699 /* already in net byte order */
1700 memcpy (ctrp->group, &pfx->fp_grp_addr.ip4, 4);
1701 memcpy (ctrp->source, &pfx->fp_src_addr.ip4, 4);
1702 ctrp->group_length = pfx->fp_len;
1703 ctrp->packets = clib_host_to_net_u64 (c.packets);
1704 ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1708 if (mp->count == items_this_message)
1710 mp->count = htonl (items_this_message);
1712 * If the main thread's input queue is stuffed,
1713 * drop the data structure lock (which the main thread
1714 * may want), and take a pause.
1718 while (svm_queue_is_full (q))
1720 svm_queue_unlock (q);
1721 ip46_fib_stats_delay (sm, 0 /* sec */ ,
1722 STATS_RELEASE_DELAY_NS);
1725 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1726 svm_queue_unlock (q);
1728 items_this_message = IP4_MFIB_COUNTER_BATCH_SIZE;
1729 mp = vl_msg_api_alloc_as_if_client
1731 items_this_message * sizeof (vl_api_ip4_mfib_counter_t));
1732 mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_MFIB_COUNTERS);
1734 mp->vrf_id = ntohl (mfib->mft_table_id);
1735 ctrp = (vl_api_ip4_mfib_counter_t *) mp->c;
1740 /* Flush any data from this mfib */
1743 mp->count = htonl (mp->count);
1744 vl_msg_api_send_shmem (q, (u8 *) & mp);
1749 /* If e.g. the last FIB had no reportable routes, free the buffer */
1751 vl_msg_api_free (mp);
1755 do_ip6_mfib_counters (stats_main_t * sm)
1757 ip6_main_t *im6 = &ip6_main;
1758 api_main_t *am = sm->api_main;
1759 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1760 svm_queue_t *q = shmem_hdr->vl_input_queue;
1763 do_ip46_fibs_t *do_fibs;
1764 vl_api_vnet_ip6_mfib_counters_t *mp = 0;
1765 u32 items_this_message;
1766 vl_api_ip6_mfib_counter_t *ctrp = 0;
1767 u32 start_at_mfib_index = 0;
1770 do_fibs = &sm->do_ip46_fibs;
1772 vec_reset_length (do_fibs->mfibs);
1774 pool_foreach (mfib, im6->mfibs, ({vec_add1(do_fibs->mfibs, mfib);}));
1777 for (j = 0; j < vec_len (do_fibs->mfibs); j++)
1779 mfib = do_fibs->mfibs[j];
1780 /* We may have bailed out due to control-plane activity */
1781 while ((mfib - im6->mfibs) < start_at_mfib_index)
1786 items_this_message = IP6_MFIB_COUNTER_BATCH_SIZE;
1787 mp = vl_msg_api_alloc_as_if_client
1789 items_this_message * sizeof (vl_api_ip6_mfib_counter_t));
1790 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_MFIB_COUNTERS);
1792 mp->vrf_id = ntohl (mfib->mft_table_id);
1793 ctrp = (vl_api_ip6_mfib_counter_t *) mp->c;
1797 /* happens if the last MFIB was empty... */
1798 ASSERT (mp->count == 0);
1799 mp->vrf_id = ntohl (mfib->mft_table_id);
1802 vec_reset_length (do_fibs->mroutes);
1805 * walk the table with table updates blocked
1807 dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1809 mfib_table_walk (mfib->mft_index,
1810 FIB_PROTOCOL_IP6, mfib_table_stats_walk_cb, sm);
1813 vec_foreach (pfx, do_fibs->mroutes)
1815 const dpo_id_t *dpo_id;
1816 fib_node_index_t mfei;
1821 * re-lookup the entry, since we suspend during the collection
1823 mfei = mfib_table_lookup (mfib->mft_index, pfx);
1825 if (FIB_NODE_INDEX_INVALID == mfei)
1828 dpo_id = mfib_entry_contribute_ip_forwarding (mfei);
1829 index = (u32) dpo_id->dpoi_index;
1831 vlib_get_combined_counter (&replicate_main.repm_counters,
1832 dpo_id->dpoi_index, &c);
1834 * If it has seen at least one packet, send it.
1838 /* already in net byte order */
1839 memcpy (ctrp->group, &pfx->fp_grp_addr.ip6, 16);
1840 memcpy (ctrp->source, &pfx->fp_src_addr.ip6, 16);
1841 ctrp->group_length = pfx->fp_len;
1842 ctrp->packets = clib_host_to_net_u64 (c.packets);
1843 ctrp->bytes = clib_host_to_net_u64 (c.bytes);
1847 if (mp->count == items_this_message)
1849 mp->count = htonl (items_this_message);
1851 * If the main thread's input queue is stuffed,
1852 * drop the data structure lock (which the main thread
1853 * may want), and take a pause.
1857 while (svm_queue_is_full (q))
1859 svm_queue_unlock (q);
1860 ip46_fib_stats_delay (sm, 0 /* sec */ ,
1861 STATS_RELEASE_DELAY_NS);
1864 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1865 svm_queue_unlock (q);
1867 items_this_message = IP6_MFIB_COUNTER_BATCH_SIZE;
1868 mp = vl_msg_api_alloc_as_if_client
1870 items_this_message * sizeof (vl_api_ip6_mfib_counter_t));
1871 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_MFIB_COUNTERS);
1873 mp->vrf_id = ntohl (mfib->mft_table_id);
1874 ctrp = (vl_api_ip6_mfib_counter_t *) mp->c;
1879 /* Flush any data from this mfib */
1882 mp->count = htonl (mp->count);
1883 vl_msg_api_send_shmem (q, (u8 *) & mp);
1888 /* If e.g. the last FIB had no reportable routes, free the buffer */
1890 vl_msg_api_free (mp);
1896 ip6_route_t **routep;
1898 } add_routes_in_fib_arg_t;
1901 add_routes_in_fib (BVT (clib_bihash_kv) * kvp, void *arg)
1903 add_routes_in_fib_arg_t *ap = arg;
1904 stats_main_t *sm = ap->sm;
1906 if (sm->data_structure_lock->release_hint)
1907 clib_longjmp (&sm->jmp_buf, 1);
1909 if (kvp->key[2] >> 32 == ap->fib_index)
1911 ip6_address_t *addr;
1913 addr = (ip6_address_t *) kvp;
1914 vec_add2 (*ap->routep, r, 1);
1915 r->address = addr[0];
1916 r->address_length = kvp->key[2] & 0xFF;
1917 r->index = kvp->value;
1922 do_ip6_fib_counters (stats_main_t * sm)
1924 ip6_main_t *im6 = &ip6_main;
1925 api_main_t *am = sm->api_main;
1926 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
1927 svm_queue_t *q = shmem_hdr->vl_input_queue;
1930 do_ip46_fibs_t *do_fibs;
1931 vl_api_vnet_ip6_fib_counters_t *mp = 0;
1932 u32 items_this_message;
1933 vl_api_ip6_fib_counter_t *ctrp = 0;
1934 u32 start_at_fib_index = 0;
1935 BVT (clib_bihash) * h = &im6->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash;
1936 add_routes_in_fib_arg_t _a, *a = &_a;
1939 do_fibs = &sm->do_ip46_fibs;
1941 vec_reset_length (do_fibs->fibs);
1943 pool_foreach (fib, im6->fibs,
1944 ({vec_add1(do_fibs->fibs,fib);}));
1948 for (i = 0; i < vec_len (do_fibs->fibs); i++)
1950 fib = do_fibs->fibs[i];
1951 /* We may have bailed out due to control-plane activity */
1952 while ((fib - im6->fibs) < start_at_fib_index)
1957 items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
1958 mp = vl_msg_api_alloc_as_if_client
1960 items_this_message * sizeof (vl_api_ip6_fib_counter_t));
1961 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
1963 mp->vrf_id = ntohl (fib->ft_table_id);
1964 ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
1967 dslock (sm, 0 /* release hint */ , 1 /* tag */ );
1969 vec_reset_length (do_fibs->ip6routes);
1970 vec_reset_length (do_fibs->results);
1972 a->fib_index = fib - im6->fibs;
1973 a->routep = &do_fibs->ip6routes;
1976 if (clib_setjmp (&sm->jmp_buf, 0) == 0)
1978 start_at_fib_index = fib - im6->fibs;
1979 BV (clib_bihash_foreach_key_value_pair) (h, add_routes_in_fib, a);
1984 ip46_fib_stats_delay (sm, 0 /* sec */ ,
1985 STATS_RELEASE_DELAY_NS);
1987 ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
1991 vec_foreach (r, do_fibs->ip6routes)
1995 vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
1998 * If it has actually
1999 * seen at least one packet, send it.
2003 /* already in net byte order */
2004 ctrp->address[0] = r->address.as_u64[0];
2005 ctrp->address[1] = r->address.as_u64[1];
2006 ctrp->address_length = (u8) r->address_length;
2007 ctrp->packets = clib_host_to_net_u64 (c.packets);
2008 ctrp->bytes = clib_host_to_net_u64 (c.bytes);
2012 if (mp->count == items_this_message)
2014 mp->count = htonl (items_this_message);
2016 * If the main thread's input queue is stuffed,
2017 * drop the data structure lock (which the main thread
2018 * may want), and take a pause.
2021 if (svm_queue_is_full (q))
2024 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
2025 svm_queue_unlock (q);
2027 ip46_fib_stats_delay (sm, 0 /* sec */ ,
2028 STATS_RELEASE_DELAY_NS);
2031 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
2032 svm_queue_unlock (q);
2034 items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
2035 mp = vl_msg_api_alloc_as_if_client
2037 items_this_message * sizeof (vl_api_ip6_fib_counter_t));
2038 mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
2040 mp->vrf_id = ntohl (fib->ft_table_id);
2041 ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
2045 if (sm->data_structure_lock->release_hint)
2047 start_at_fib_index = fib - im6->fibs;
2049 ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
2051 ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
2054 } /* vec_foreach (routes) */
2058 /* Flush any data from this fib */
2061 mp->count = htonl (mp->count);
2062 vl_msg_api_send_shmem (q, (u8 *) & mp);
2067 /* If e.g. the last FIB had no reportable routes, free the buffer */
2069 vl_msg_api_free (mp);
2073 stats_set_poller_delay (u32 poller_delay_sec)
2075 stats_main_t *sm = &stats_main;
2076 if (!poller_delay_sec)
2078 return VNET_API_ERROR_INVALID_ARGUMENT;
2082 sm->stats_poll_interval_in_seconds = poller_delay_sec;
2087 static clib_error_t *
2088 stats_config (vlib_main_t * vm, unformat_input_t * input)
2092 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2094 if (unformat (input, "interval %u", &sec))
2096 int rv = stats_set_poller_delay (sec);
2099 return clib_error_return (0,
2100 "`stats_set_poller_delay' API call failed, rv=%d:%U",
2101 (int) rv, format_vnet_api_errno, rv);
2107 return clib_error_return (0, "unknown input '%U'",
2108 format_unformat_error, input);
2114 /* stats { ... } configuration. */
2117 * @cfgcmd{interval, <seconds>}
2118 * Configure stats poller delay to be @c seconds.
2121 VLIB_CONFIG_FUNCTION (stats_config, "stats");
2124 vl_api_stats_get_poller_delay_t_handler
2125 (vl_api_stats_get_poller_delay_t * mp)
2127 stats_main_t *sm = &stats_main;
2128 vl_api_registration_t *reg;
2129 reg = vl_api_client_index_to_registration (mp->client_index);
2132 vl_api_stats_get_poller_delay_reply_t *rmp;
2134 rmp = vl_msg_api_alloc (sizeof (*rmp));
2135 rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
2136 rmp->context = mp->context;
2138 rmp->delay = clib_host_to_net_u32 (sm->stats_poll_interval_in_seconds);
2140 vl_api_send_msg (reg, (u8 *) rmp);
2145 stats_thread_fn (void *arg)
2147 stats_main_t *sm = &stats_main;
2148 vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
2149 vlib_thread_main_t *tm = vlib_get_thread_main ();
2151 /* stats thread wants no signals. */
2155 pthread_sigmask (SIG_SETMASK, &s, 0);
2158 if (vec_len (tm->thread_prefix))
2159 vlib_set_thread_name ((char *)
2160 format (0, "%v_stats%c", tm->thread_prefix, '\0'));
2162 clib_mem_set_heap (w->thread_mheap);
2166 ip46_fib_stats_delay (sm, sm->stats_poll_interval_in_seconds,
2169 if (!(sm->enable_poller))
2174 (sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS]))
2175 do_combined_per_interface_counters (sm);
2178 (sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS]))
2179 do_simple_per_interface_counters (sm);
2181 if (pool_elts (sm->stats_registrations[IDX_IP4_FIB_COUNTERS]))
2182 do_ip4_fib_counters (sm);
2184 if (pool_elts (sm->stats_registrations[IDX_IP6_FIB_COUNTERS]))
2185 do_ip6_fib_counters (sm);
2187 if (pool_elts (sm->stats_registrations[IDX_IP4_MFIB_COUNTERS]))
2188 do_ip4_mfib_counters (sm);
2190 if (pool_elts (sm->stats_registrations[IDX_IP6_MFIB_COUNTERS]))
2191 do_ip6_mfib_counters (sm);
2193 if (pool_elts (sm->stats_registrations[IDX_IP4_NBR_COUNTERS]))
2194 do_ip4_nbr_counters (sm);
2196 if (pool_elts (sm->stats_registrations[IDX_IP6_NBR_COUNTERS]))
2197 do_ip6_nbr_counters (sm);
2202 vl_api_vnet_interface_simple_counters_t_handler
2203 (vl_api_vnet_interface_simple_counters_t * mp)
2205 vpe_client_registration_t *clients, client;
2206 stats_main_t *sm = &stats_main;
2207 vl_api_registration_t *reg, *reg_prev = NULL;
2208 vl_api_vnet_interface_simple_counters_t *mp_copy = NULL;
2212 mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (u64));
2215 get_clients_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
2216 ~0 /*flag for all */ );
2218 for (i = 0; i < vec_len (clients); i++)
2220 client = clients[i];
2221 reg = vl_api_client_index_to_registration (client.client_index);
2224 if (reg_prev && vl_api_can_send_msg (reg_prev))
2226 mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2227 clib_memcpy (mp_copy, mp, mp_size);
2228 vl_api_send_msg (reg_prev, (u8 *) mp);
2236 clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, ~0,
2237 client.client_index);
2243 fformat (stdout, "%U\n", format_vnet_simple_counters, mp);
2246 if (reg_prev && vl_api_can_send_msg (reg_prev))
2248 vl_api_send_msg (reg_prev, (u8 *) mp);
2252 vl_msg_api_free (mp);
2257 vl_api_vnet_ip4_fib_counters_t_handler (vl_api_vnet_ip4_fib_counters_t * mp)
2259 stats_main_t *sm = &stats_main;
2260 vl_api_registration_t *reg, *reg_prev = NULL;
2261 vl_api_vnet_ip4_fib_counters_t *mp_copy = NULL;
2263 vpe_client_registration_t *clients, client;
2266 mp_size = sizeof (*mp_copy) +
2267 ntohl (mp->count) * sizeof (vl_api_ip4_fib_counter_t);
2270 get_clients_for_stat (IDX_IP4_FIB_COUNTERS, ~0 /*flag for all */ );
2272 for (i = 0; i < vec_len (clients); i++)
2274 client = clients[i];
2275 reg = vl_api_client_index_to_registration (client.client_index);
2278 if (reg_prev && vl_api_can_send_msg (reg_prev))
2280 mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2281 clib_memcpy (mp_copy, mp, mp_size);
2282 vl_api_send_msg (reg_prev, (u8 *) mp);
2289 sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
2290 ~0, client.client_index);
2295 if (reg_prev && vl_api_can_send_msg (reg_prev))
2297 vl_api_send_msg (reg_prev, (u8 *) mp);
2301 vl_msg_api_free (mp);
2306 vl_api_vnet_ip4_nbr_counters_t_handler (vl_api_vnet_ip4_nbr_counters_t * mp)
2308 stats_main_t *sm = &stats_main;
2309 vl_api_registration_t *reg, *reg_prev = NULL;
2310 vl_api_vnet_ip4_nbr_counters_t *mp_copy = NULL;
2312 vpe_client_registration_t *clients, client;
2315 mp_size = sizeof (*mp_copy) +
2316 ntohl (mp->count) * sizeof (vl_api_ip4_nbr_counter_t);
2319 get_clients_for_stat (IDX_IP4_NBR_COUNTERS, ~0 /*flag for all */ );
2321 for (i = 0; i < vec_len (clients); i++)
2323 client = clients[i];
2324 reg = vl_api_client_index_to_registration (client.client_index);
2327 if (reg_prev && vl_api_can_send_msg (reg_prev))
2329 mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2330 clib_memcpy (mp_copy, mp, mp_size);
2331 vl_api_send_msg (reg_prev, (u8 *) mp);
2338 sm->enable_poller = clear_client_for_stat (IDX_IP4_NBR_COUNTERS,
2339 ~0, client.client_index);
2345 if (reg_prev && vl_api_can_send_msg (reg_prev))
2347 vl_api_send_msg (reg_prev, (u8 *) mp);
2351 vl_msg_api_free (mp);
2356 vl_api_vnet_ip6_fib_counters_t_handler (vl_api_vnet_ip6_fib_counters_t * mp)
2358 stats_main_t *sm = &stats_main;
2359 vl_api_registration_t *reg, *reg_prev = NULL;
2360 vl_api_vnet_ip6_fib_counters_t *mp_copy = NULL;
2362 vpe_client_registration_t *clients, client;
2365 mp_size = sizeof (*mp_copy) +
2366 ntohl (mp->count) * sizeof (vl_api_ip6_fib_counter_t);
2369 get_clients_for_stat (IDX_IP6_FIB_COUNTERS, ~0 /*flag for all */ );
2371 for (i = 0; i < vec_len (clients); i++)
2373 client = clients[i];
2374 reg = vl_api_client_index_to_registration (client.client_index);
2377 if (reg_prev && vl_api_can_send_msg (reg_prev))
2379 mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2380 clib_memcpy (mp_copy, mp, mp_size);
2381 vl_api_send_msg (reg_prev, (u8 *) mp);
2388 sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2389 ~0, client.client_index);
2394 if (reg_prev && vl_api_can_send_msg (reg_prev))
2396 vl_api_send_msg (reg_prev, (u8 *) mp);
2400 vl_msg_api_free (mp);
2405 vl_api_vnet_ip6_nbr_counters_t_handler (vl_api_vnet_ip6_nbr_counters_t * mp)
2407 stats_main_t *sm = &stats_main;
2408 vl_api_registration_t *reg, *reg_prev = NULL;
2409 vl_api_vnet_ip6_nbr_counters_t *mp_copy = NULL;
2411 vpe_client_registration_t *clients, client;
2414 mp_size = sizeof (*mp_copy) +
2415 ntohl (mp->count) * sizeof (vl_api_ip6_nbr_counter_t);
2418 get_clients_for_stat (IDX_IP6_NBR_COUNTERS, ~0 /*flag for all */ );
2420 for (i = 0; i < vec_len (clients); i++)
2422 client = clients[i];
2423 reg = vl_api_client_index_to_registration (client.client_index);
2426 if (reg_prev && vl_api_can_send_msg (reg_prev))
2428 mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
2429 clib_memcpy (mp_copy, mp, mp_size);
2430 vl_api_send_msg (reg_prev, (u8 *) mp);
2437 sm->enable_poller = clear_client_for_stat (IDX_IP6_NBR_COUNTERS,
2438 ~0, client.client_index);
2443 if (reg_prev && vl_api_can_send_msg (reg_prev))
2445 vl_api_send_msg (reg_prev, (u8 *) mp);
2449 vl_msg_api_free (mp);
2454 vl_api_want_stats_t_handler (vl_api_want_stats_t * mp)
2456 stats_main_t *sm = &stats_main;
2457 vpe_client_registration_t rp;
2458 vl_api_want_stats_reply_t *rmp;
2462 vl_api_registration_t *reg;
2464 item = ~0; //"ALL THE THINGS IN THE THINGS
2465 rp.client_index = mp->client_index;
2466 rp.client_pid = mp->pid;
2468 handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
2469 item, mp->enable_disable);
2471 handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
2472 item, mp->enable_disable);
2474 handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS,
2475 item, mp->enable_disable);
2477 handle_client_registration (&rp, IDX_IP4_NBR_COUNTERS,
2478 item, mp->enable_disable);
2480 handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS,
2481 item, mp->enable_disable);
2483 handle_client_registration (&rp, IDX_IP6_NBR_COUNTERS,
2484 item, mp->enable_disable);
2487 reg = vl_api_client_index_to_registration (mp->client_index);
2491 rmp = vl_msg_api_alloc (sizeof (*rmp));
2492 rmp->_vl_msg_id = ntohs (VL_API_WANT_STATS_REPLY);
2493 rmp->context = mp->context;
2494 rmp->retval = retval;
2496 vl_api_send_msg (reg, (u8 *) rmp);
2500 vl_api_want_interface_simple_stats_t_handler
2501 (vl_api_want_interface_simple_stats_t * mp)
2503 stats_main_t *sm = &stats_main;
2504 vpe_client_registration_t rp;
2505 vl_api_want_interface_simple_stats_reply_t *rmp;
2509 vl_api_registration_t *reg;
2511 swif = ~0; //Using same mechanism as _per_interface_
2512 rp.client_index = mp->client_index;
2513 rp.client_pid = mp->pid;
2515 handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2516 mp->enable_disable);
2519 reg = vl_api_client_index_to_registration (mp->client_index);
2524 clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
2529 rmp = vl_msg_api_alloc (sizeof (*rmp));
2530 rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_SIMPLE_STATS_REPLY);
2531 rmp->context = mp->context;
2532 rmp->retval = retval;
2534 vl_api_send_msg (reg, (u8 *) rmp);
2539 vl_api_want_ip4_fib_stats_t_handler (vl_api_want_ip4_fib_stats_t * mp)
2541 stats_main_t *sm = &stats_main;
2542 vpe_client_registration_t rp;
2543 vl_api_want_ip4_fib_stats_reply_t *rmp;
2546 vl_api_registration_t *reg;
2549 fib = ~0; //Using same mechanism as _per_interface_
2550 rp.client_index = mp->client_index;
2551 rp.client_pid = mp->pid;
2553 handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS, fib,
2554 mp->enable_disable);
2557 reg = vl_api_client_index_to_registration (mp->client_index);
2561 sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
2562 fib, mp->client_index);
2566 rmp = vl_msg_api_alloc (sizeof (*rmp));
2567 rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_FIB_STATS_REPLY);
2568 rmp->context = mp->context;
2569 rmp->retval = retval;
2571 vl_api_send_msg (reg, (u8 *) rmp);
2575 vl_api_want_ip4_mfib_stats_t_handler (vl_api_want_ip4_mfib_stats_t * mp)
2577 stats_main_t *sm = &stats_main;
2578 vpe_client_registration_t rp;
2579 vl_api_want_ip4_mfib_stats_reply_t *rmp;
2582 vl_api_registration_t *reg;
2585 mfib = ~0; //Using same mechanism as _per_interface_
2586 rp.client_index = mp->client_index;
2587 rp.client_pid = mp->pid;
2589 handle_client_registration (&rp, IDX_IP4_MFIB_COUNTERS, mfib,
2590 mp->enable_disable);
2593 reg = vl_api_client_index_to_registration (mp->client_index);
2596 sm->enable_poller = clear_client_for_stat (IDX_IP4_MFIB_COUNTERS,
2597 mfib, mp->client_index);
2601 rmp = vl_msg_api_alloc (sizeof (*rmp));
2602 rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_MFIB_STATS_REPLY);
2603 rmp->context = mp->context;
2604 rmp->retval = retval;
2606 vl_api_send_msg (reg, (u8 *) rmp);
2610 vl_api_want_ip6_fib_stats_t_handler (vl_api_want_ip6_fib_stats_t * mp)
2612 stats_main_t *sm = &stats_main;
2613 vpe_client_registration_t rp;
2614 vl_api_want_ip4_fib_stats_reply_t *rmp;
2617 vl_api_registration_t *reg;
2620 fib = ~0; //Using same mechanism as _per_interface_
2621 rp.client_index = mp->client_index;
2622 rp.client_pid = mp->pid;
2624 handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS, fib,
2625 mp->enable_disable);
2628 reg = vl_api_client_index_to_registration (mp->client_index);
2631 sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
2632 fib, mp->client_index);
2636 rmp = vl_msg_api_alloc (sizeof (*rmp));
2637 rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_FIB_STATS_REPLY);
2638 rmp->context = mp->context;
2639 rmp->retval = retval;
2641 vl_api_send_msg (reg, (u8 *) rmp);
2645 vl_api_want_ip6_mfib_stats_t_handler (vl_api_want_ip6_mfib_stats_t * mp)
2647 stats_main_t *sm = &stats_main;
2648 vpe_client_registration_t rp;
2649 vl_api_want_ip4_mfib_stats_reply_t *rmp;
2652 vl_api_registration_t *reg;
2655 mfib = ~0; //Using same mechanism as _per_interface_
2656 rp.client_index = mp->client_index;
2657 rp.client_pid = mp->pid;
2659 handle_client_registration (&rp, IDX_IP6_MFIB_COUNTERS, mfib,
2660 mp->enable_disable);
2663 reg = vl_api_client_index_to_registration (mp->client_index);
2666 sm->enable_poller = clear_client_for_stat (IDX_IP6_MFIB_COUNTERS,
2667 mfib, mp->client_index);
2671 rmp = vl_msg_api_alloc (sizeof (*rmp));
2672 rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_MFIB_STATS_REPLY);
2673 rmp->context = mp->context;
2674 rmp->retval = retval;
2676 vl_api_send_msg (reg, (u8 *) rmp);
2679 /* FIXME - NBR stats broken - this will be fixed in subsequent patch */
2681 vl_api_want_ip4_nbr_stats_t_handler (vl_api_want_ip4_nbr_stats_t * mp)
2686 vl_api_want_ip6_nbr_stats_t_handler (vl_api_want_ip6_nbr_stats_t * mp)
2691 vl_api_vnet_get_summary_stats_t_handler (vl_api_vnet_get_summary_stats_t * mp)
2693 stats_main_t *sm = &stats_main;
2694 vnet_interface_main_t *im = sm->interface_main;
2695 vl_api_vnet_get_summary_stats_reply_t *rmp;
2696 vlib_combined_counter_main_t *cm;
2699 u64 total_pkts[VLIB_N_RX_TX];
2700 u64 total_bytes[VLIB_N_RX_TX];
2701 vl_api_registration_t *reg;
2703 reg = vl_api_client_index_to_registration (mp->client_index);
2707 rmp = vl_msg_api_alloc (sizeof (*rmp));
2708 rmp->_vl_msg_id = ntohs (VL_API_VNET_GET_SUMMARY_STATS_REPLY);
2709 rmp->context = mp->context;
2712 memset (total_pkts, 0, sizeof (total_pkts));
2713 memset (total_bytes, 0, sizeof (total_bytes));
2715 vnet_interface_counter_lock (im);
2717 vec_foreach (cm, im->combined_sw_if_counters)
2719 which = cm - im->combined_sw_if_counters;
2721 for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
2723 vlib_get_combined_counter (cm, i, &v);
2724 total_pkts[which] += v.packets;
2725 total_bytes[which] += v.bytes;
2728 vnet_interface_counter_unlock (im);
2730 rmp->total_pkts[VLIB_RX] = clib_host_to_net_u64 (total_pkts[VLIB_RX]);
2731 rmp->total_bytes[VLIB_RX] = clib_host_to_net_u64 (total_bytes[VLIB_RX]);
2732 rmp->total_pkts[VLIB_TX] = clib_host_to_net_u64 (total_pkts[VLIB_TX]);
2733 rmp->total_bytes[VLIB_TX] = clib_host_to_net_u64 (total_bytes[VLIB_TX]);
2735 clib_host_to_net_u64 (vlib_last_vector_length_per_node (sm->vlib_main));
2737 vl_api_send_msg (reg, (u8 *) rmp);
2741 stats_memclnt_delete_callback (u32 client_index)
2743 vpe_client_stats_registration_t *rp;
2744 stats_main_t *sm = &stats_main;
2748 /* p = hash_get (sm->stats_registration_hash, client_index); */
2751 /* rp = pool_elt_at_index (sm->stats_registrations, p[0]); */
2752 /* pool_put (sm->stats_registrations, rp); */
2753 /* hash_unset (sm->stats_registration_hash, client_index); */
2759 #define vl_api_vnet_interface_simple_counters_t_endian vl_noop_handler
2760 #define vl_api_vnet_interface_simple_counters_t_print vl_noop_handler
2761 #define vl_api_vnet_interface_combined_counters_t_endian vl_noop_handler
2762 #define vl_api_vnet_interface_combined_counters_t_print vl_noop_handler
2763 #define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
2764 #define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
2765 #define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
2766 #define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler
2767 #define vl_api_vnet_ip4_nbr_counters_t_endian vl_noop_handler
2768 #define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
2769 #define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
2770 #define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
2772 static clib_error_t *
2773 stats_init (vlib_main_t * vm)
2775 stats_main_t *sm = &stats_main;
2776 api_main_t *am = &api_main;
2777 void *vlib_worker_thread_bootstrap_fn (void *arg);
2780 sm->vnet_main = vnet_get_main ();
2781 sm->interface_main = &vnet_get_main ()->interface_main;
2783 sm->stats_poll_interval_in_seconds = 10;
2784 sm->data_structure_lock =
2785 clib_mem_alloc_aligned (sizeof (data_structure_lock_t),
2786 CLIB_CACHE_LINE_BYTES);
2787 memset (sm->data_structure_lock, 0, sizeof (*sm->data_structure_lock));
2790 vl_msg_api_set_handlers(VL_API_##N, #n, \
2791 vl_api_##n##_t_handler, \
2793 vl_api_##n##_t_endian, \
2794 vl_api_##n##_t_print, \
2795 sizeof(vl_api_##n##_t), 0 /* do NOT trace! */);
2799 /* tell the msg infra not to free these messages... */
2800 am->message_bounce[VL_API_VNET_INTERFACE_SIMPLE_COUNTERS] = 1;
2801 am->message_bounce[VL_API_VNET_INTERFACE_COMBINED_COUNTERS] = 1;
2802 am->message_bounce[VL_API_VNET_IP4_FIB_COUNTERS] = 1;
2803 am->message_bounce[VL_API_VNET_IP6_FIB_COUNTERS] = 1;
2804 am->message_bounce[VL_API_VNET_IP4_NBR_COUNTERS] = 1;
2805 am->message_bounce[VL_API_VNET_IP6_NBR_COUNTERS] = 1;
2808 * Set up the (msg_name, crc, message-id) table
2810 setup_message_id_table (am);
2812 vec_validate (sm->stats_registrations, STATS_REG_N_IDX);
2813 vec_validate (sm->stats_registration_hash, STATS_REG_N_IDX);
2814 #define stats_reg(n) \
2815 sm->stats_registrations[IDX_##n] = 0; \
2816 sm->stats_registration_hash[IDX_##n] = 0;
2817 #include <vpp/stats/stats.reg>
2823 VLIB_INIT_FUNCTION (stats_init);
2826 VLIB_REGISTER_THREAD (stats_thread_reg, static) = {
2828 .function = stats_thread_fn,
2831 .no_data_structure_clone = 1,
2837 * fd.io coding-style-patch-verification: ON
2840 * eval: (c-set-style "gnu")