+/**********************************
+ * Per Interface Combined stats
+ **********************************/
+
+/* Request from client registering interfaces it wants */
+static void
+ vl_api_want_per_interface_combined_stats_t_handler
+ (vl_api_want_per_interface_combined_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t rp;
+ vl_api_want_per_interface_combined_stats_reply_t *rmp;
+ vlib_combined_counter_main_t *cm;
+ uword *p;
+ i32 retval = 0;
+ vl_api_registration_t *reg;
+ u32 i, swif, num = 0;
+
+ num = ntohl (mp->num);
+
+ /*
+ * Validate sw_if_indexes before registering
+ */
+ for (i = 0; i < num; i++)
+ {
+ swif = ntohl (mp->sw_ifs[i]);
+
+ /*
+ * Check its a real sw_if_index that the client is allowed to see
+ */
+ if (swif != ~0)
+ {
+ if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
+ {
+ retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
+ goto reply;
+ }
+ }
+ }
+
+ for (i = 0; i < num; i++)
+ {
+ swif = ntohl (mp->sw_ifs[i]);
+
+ rp.client_index = mp->client_index;
+ rp.client_pid = mp->pid;
+ handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
+ swif, ntohl (mp->enable_disable));
+ }
+
+reply:
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ {
+ for (i = 0; i < num; i++)
+ {
+ swif = ntohl (mp->sw_ifs[i]);
+
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
+ mp->client_index);
+ }
+ return;
+ }
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_COMBINED_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = retval;
+
+ vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+/* Per Interface Combined distribution to client */
+static void
+do_combined_per_interface_counters (stats_main_t * sm)
+{
+ vl_api_vnet_per_interface_combined_counters_t *mp = 0;
+ vnet_interface_main_t *im = sm->interface_main;
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ vl_api_registration_t *vl_reg;
+ vlib_combined_counter_main_t *cm;
+ vl_api_vnet_combined_counter_t *vp = 0;
+ vlib_counter_t v;
+ u32 i, j;
+ vpe_client_stats_registration_t *reg;
+ vpe_client_registration_t *client;
+ u32 *sw_if_index = 0;
+
+ vnet_interface_counter_lock (im);
+
+ vec_reset_length (sm->regs_tmp);
+
+ /* *INDENT-OFF* */
+ pool_foreach (reg,
+ sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS],
+ ({ vec_add1 (sm->regs_tmp, reg); }));
+ /* *INDENT-ON* */
+
+ for (i = 0; i < vec_len (sm->regs_tmp); i++)
+ {
+ reg = sm->regs_tmp[i];
+ if (reg->item == ~0)
+ {
+ vnet_interface_counter_unlock (im);
+ do_combined_interface_counters (sm);
+ vnet_interface_counter_lock (im);
+ continue;
+ }
+ vec_reset_length (sm->clients_tmp);
+
+ /* *INDENT-OFF* */
+ pool_foreach (client, reg->clients, ({ vec_add1 (sm->clients_tmp,
+ client);}));
+ /* *INDENT-ON* */
+
+ for (j = 0; j < vec_len (sm->clients_tmp); j++)
+ {
+ client = sm->clients_tmp[j];
+
+ vl_reg = vl_api_client_index_to_registration (client->client_index);
+
+ //Client may have disconnected abrubtly, clean up so we don't poll nothing.
+ if (!vl_reg)
+ {
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
+ reg->item, client->client_index);
+ continue;
+ }
+ mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + sizeof (*vp));
+ memset (mp, 0, sizeof (*mp));
+
+ mp->_vl_msg_id =
+ ntohs (VL_API_VNET_PER_INTERFACE_COMBINED_COUNTERS);
+
+ /*
+ * count will eventually be used to optimise the batching
+ * of per client messages for each stat. For now setting this to 1 then
+ * iterate. This will not affect API.
+ *
+ * FIXME instead of enqueueing here, this should be sent to a batch
+ * storer for per-client transmission. Each "mp" sent would be a single entry
+ * and if a client is listening to other sw_if_indexes for same, it would be
+ * appended to that *mp
+ *
+ *
+ * FIXME(s):
+ * - capturing the timestamp of the counters "when VPP knew them" is important.
+ * Less so is that the timing of the delivery to the control plane be in the same
+ * timescale.
+
+ * i.e. As long as the control plane can delta messages from VPP and work out
+ * velocity etc based on the timestamp, it can do so in a more "batch mode".
+
+ * It would be beneficial to keep a "per-client" message queue, and then
+ * batch all the stat messages for a client into one message, with
+ * discrete timestamps.
+
+ * Given this particular API is for "per interface" one assumes that the scale
+ * is less than the ~0 case, which the prior API is suited for.
+ */
+
+ /*
+ * 1 message per api call for now
+ */
+ mp->count = htonl (1);
+ mp->timestamp = htonl (vlib_time_now (sm->vlib_main));
+
+ vp = (vl_api_vnet_combined_counter_t *) mp->data;
+ vp->sw_if_index = htonl (reg->item);
+
+ im = &vnet_get_main ()->interface_main;
+
+#define _(X, x) \
+ cm = im->combined_sw_if_counters + X; \
+ vlib_get_combined_counter (cm, reg->item, &v); \
+ clib_mem_unaligned (&vp->x##_packets, u64) = \
+ clib_host_to_net_u64 (v.packets); \
+ clib_mem_unaligned (&vp->x##_bytes, u64) = \
+ clib_host_to_net_u64 (v.bytes);
+
+
+ _(VNET_INTERFACE_COUNTER_RX, rx);
+ _(VNET_INTERFACE_COUNTER_TX, tx);
+ _(VNET_INTERFACE_COUNTER_RX_UNICAST, rx_unicast);
+ _(VNET_INTERFACE_COUNTER_TX_UNICAST, tx_unicast);
+ _(VNET_INTERFACE_COUNTER_RX_MULTICAST, rx_multicast);
+ _(VNET_INTERFACE_COUNTER_TX_MULTICAST, tx_multicast);
+ _(VNET_INTERFACE_COUNTER_RX_BROADCAST, rx_broadcast);
+ _(VNET_INTERFACE_COUNTER_TX_BROADCAST, tx_broadcast);
+
+#undef _
+
+ vl_api_send_msg (vl_reg, (u8 *) mp);
+ }
+ }
+
+ vnet_interface_counter_unlock (im);
+}
+
+/**********************************
+ * Per Interface simple stats
+ **********************************/
+
+/* Request from client registering interfaces it wants */
+static void
+ vl_api_want_per_interface_simple_stats_t_handler
+ (vl_api_want_per_interface_simple_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t rp;
+ vl_api_want_per_interface_simple_stats_reply_t *rmp;
+ vlib_simple_counter_main_t *cm;
+ uword *p;
+ i32 retval = 0;
+ vl_api_registration_t *reg;
+ u32 i, swif, num = 0;
+
+ num = ntohl (mp->num);
+
+ for (i = 0; i < num; i++)
+ {
+ swif = ntohl (mp->sw_ifs[i]);
+
+ /* Check its a real sw_if_index that the client is allowed to see */
+ if (swif != ~0)
+ {
+ if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
+ {
+ retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
+ goto reply;
+ }
+ }
+ }
+
+ for (i = 0; i < num; i++)
+ {
+ swif = ntohl (mp->sw_ifs[i]);
+
+ rp.client_index = mp->client_index;
+ rp.client_pid = mp->pid;
+ handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
+ swif, ntohl (mp->enable_disable));
+ }
+
+reply:
+ reg = vl_api_client_index_to_registration (mp->client_index);
+
+ /* Client may have disconnected abruptly, clean up */
+ if (!reg)
+ {
+ for (i = 0; i < num; i++)
+ {
+ swif = ntohl (mp->sw_ifs[i]);
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
+ mp->client_index);
+ }
+
+ return;
+ }
+
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = retval;
+
+ vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+/* Per Interface Simple distribution to client */
+static void
+do_simple_per_interface_counters (stats_main_t * sm)
+{
+ vl_api_vnet_per_interface_simple_counters_t *mp = 0;
+ vnet_interface_main_t *im = sm->interface_main;
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ vl_api_registration_t *vl_reg;
+ vlib_simple_counter_main_t *cm;
+ u32 i, j, size;
+ vpe_client_stats_registration_t *reg;
+ vpe_client_registration_t *client;
+ u32 timestamp, count;
+ vl_api_vnet_simple_counter_t *vp = 0;
+ counter_t v;
+
+ vnet_interface_counter_lock (im);
+
+ vec_reset_length (sm->regs_tmp);
+
+ /* *INDENT-OFF* */
+ pool_foreach (reg,
+ sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS],
+ ({ vec_add1 (sm->regs_tmp, reg); }));
+ /* *INDENT-ON* */
+
+ for (i = 0; i < vec_len (sm->regs_tmp); i++)
+ {
+ reg = sm->regs_tmp[i];
+ if (reg->item == ~0)
+ {
+ vnet_interface_counter_unlock (im);
+ do_simple_interface_counters (sm);
+ vnet_interface_counter_lock (im);
+ continue;
+ }
+ vec_reset_length (sm->clients_tmp);
+
+ /* *INDENT-OFF* */
+ pool_foreach (client, reg->clients, ({ vec_add1 (sm->clients_tmp,
+ client);}));
+ /* *INDENT-ON* */
+
+ for (j = 0; j < vec_len (sm->clients_tmp); j++)
+ {
+ client = sm->clients_tmp[j];
+ vl_reg = vl_api_client_index_to_registration (client->client_index);
+
+ /* Client may have disconnected abrubtly, clean up */
+ if (!vl_reg)
+ {
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
+ reg->item, client->client_index);
+ continue;
+ }
+
+ mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + sizeof (*vp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_PER_INTERFACE_SIMPLE_COUNTERS);
+
+ /*
+ * count will eventually be used to optimise the batching
+ * of per client messages for each stat. For now setting this to 1 then
+ * iterate. This will not affect API.
+ *
+ * FIXME instead of enqueueing here, this should be sent to a batch
+ * storer for per-client transmission. Each "mp" sent would be a single entry
+ * and if a client is listening to other sw_if_indexes for same, it would be
+ * appended to that *mp
+ *
+ *
+ * FIXME(s):
+ * - capturing the timestamp of the counters "when VPP knew them" is important.
+ * Less so is that the timing of the delivery to the control plane be in the same
+ * timescale.
+
+ * i.e. As long as the control plane can delta messages from VPP and work out
+ * velocity etc based on the timestamp, it can do so in a more "batch mode".
+
+ * It would be beneficial to keep a "per-client" message queue, and then
+ * batch all the stat messages for a client into one message, with
+ * discrete timestamps.
+
+ * Given this particular API is for "per interface" one assumes that the scale
+ * is less than the ~0 case, which the prior API is suited for.
+ */
+
+ /*
+ * 1 message per api call for now
+ */
+ mp->count = htonl (1);
+ mp->timestamp = htonl (vlib_time_now (sm->vlib_main));
+ vp = (vl_api_vnet_simple_counter_t *) mp->data;
+
+ vp->sw_if_index = htonl (reg->item);
+
+ // VNET_INTERFACE_COUNTER_DROP
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->drop, u64) = clib_host_to_net_u64 (v);
+
+ // VNET_INTERFACE_COUNTER_PUNT
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_PUNT;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->punt, u64) = clib_host_to_net_u64 (v);
+
+ // VNET_INTERFACE_COUNTER_IP4
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP4;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_ip4, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_IP6
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP6;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_ip6, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_RX_NO_BUF
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_NO_BUF;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_no_buffer, u64) =
+ clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_RX_MISS
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_MISS;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_miss, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_RX_ERROR
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_ERROR;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_error, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_TX_ERROR
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_TX_ERROR;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->tx_error, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_MPLS
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_MPLS;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_mpls, u64) = clib_host_to_net_u64 (v);
+
+ vl_api_send_msg (vl_reg, (u8 *) mp);
+ }
+ }
+
+ vnet_interface_counter_unlock (im);
+}
+
+/**********************************
+ * Per FIB IP4 stats
+ **********************************/