From 4590ae6202d7f3fbf932a57e4d9500ce5ac1e473 Mon Sep 17 00:00:00 2001 From: Alberto Compagno Date: Tue, 11 Feb 2020 08:54:33 +0100 Subject: [HICN-510] Adding collectd plugins to get telemetry from vpp and hicn-plugin Change-Id: Idb322dc712b52301c66c5256ad8d1a6a65b503b9 Signed-off-by: Alberto Compagno --- telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c | 416 +++++++++++++++++++++++++++++ 1 file changed, 416 insertions(+) create mode 100644 telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c (limited to 'telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c') diff --git a/telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c b/telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c new file mode 100644 index 000000000..b90646073 --- /dev/null +++ b/telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !HAVE_CONFIG_H +#include +#include + +#ifndef __USE_ISOC99 /* required for NAN */ +#define DISABLE_ISOC99 1 +#define __USE_ISOC99 1 +#endif /* !defined(__USE_ISOC99) */ + +#if DISABLE_ISOC99 +#undef DISABLE_ISOC99 +#undef __USE_ISOC99 +#endif /* DISABLE_ISOC99 */ +#endif /* ! HAVE_CONFIG */ + +#include +#include +#include +#include + +#define counter_t vpp_counter_t +#include +#include +#undef counter_t + +DEFINE_VAPI_MSG_IDS_HICN_API_JSON +vapi_ctx_t vapi_ctx; + +/************** DATA SOURCES ******************************/ +static data_source_t packets_dsrc[1] = { + {"packets", DS_TYPE_GAUGE, 0, NAN}, +}; + +static data_source_t interests_dsrc[1] = { + {"interests", DS_TYPE_GAUGE, 0, NAN}, +}; + +static data_source_t data_dsrc[1] = { + {"data", DS_TYPE_GAUGE, 0, NAN}, +}; + +static data_source_t combined_dsrc[2] = { + {"packets", DS_TYPE_DERIVE, 0, NAN}, + {"bytes", DS_TYPE_DERIVE, 0, NAN}, +}; + +/************** DATA SETS NODE ****************************/ +static data_set_t pkts_processed_ds = { + "pkts_processed", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +static data_set_t pkts_interest_count_ds = { + "pkts_interest_count", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +static data_set_t pkts_data_count_ds = { + "pkts_data_count", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +static data_set_t pkts_from_cache_count_ds = { + "pkts_from_cache_count", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +static data_set_t pkts_no_pit_count_ds = { + "pkts_no_pit_count", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +static data_set_t pit_expired_count_ds = { + "pit_expired_count", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +static data_set_t cs_expired_count_ds = { + "cs_expired_count", + STATIC_ARRAY_SIZE(data_dsrc), + data_dsrc, +}; + +static data_set_t cs_lru_count_ds = { + "cs_lru_count", + STATIC_ARRAY_SIZE(data_dsrc), + data_dsrc, +}; + +static data_set_t pkts_drop_no_buf_ds = { + "pkts_drop_no_buf", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +static data_set_t interests_aggregated_ds = { + "interests_aggregated", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +static data_set_t interests_retx_ds = { + "interests_retx", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +static data_set_t interests_hash_collision_ds = { + "interests_hash_collision", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +static data_set_t pit_entries_count_ds = { + "pit_entries_count", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +static data_set_t cs_entries_count_ds = { + "cs_entries_count", + STATIC_ARRAY_SIZE(data_dsrc), + data_dsrc, +}; + +static data_set_t cs_entries_ntw_count_ds = { + "cs_entries_ntw_count", + STATIC_ARRAY_SIZE(data_dsrc), + data_dsrc, +}; + +/************** DATA SETS FACE ****************************/ +static data_set_t irx_ds = { + "irx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t itx_ds = { + "itx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t drx_ds = { + "drx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t dtx_ds = { + "dtx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +/**********************************************************/ +/********** UTILITY FUNCTIONS *****************************/ +/**********************************************************/ + +/* + * Utility function used by the read callback to populate a + * value_list_t and pass it to plugin_dispatch_values. + */ +static int submit(const char *plugin_instance, const char *type, + const char *type_instance, value_t *values, size_t values_len, + cdtime_t *timestamp) { + value_list_t vl = VALUE_LIST_INIT; + vl.values = values; + vl.values_len = values_len; + + if (timestamp != NULL) { + vl.time = *timestamp; + } + + sstrncpy(vl.plugin, "vpp_hicn", sizeof(vl.plugin)); + sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance)); + sstrncpy(vl.type, type, sizeof(vl.type)); + + if (type_instance != NULL) + sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); + + return plugin_dispatch_values(&vl); +} + +/**********************************************************/ +/********** CALLBACK FUNCTIONS ****************************/ +/**********************************************************/ + +/* + * Callback called by the hICN plugin API when node stats are ready. + */ +static vapi_error_e +parse_node_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, + bool is_last, + vapi_payload_hicn_api_node_stats_get_reply *reply) { + if (reply == NULL || rv != VAPI_OK) + return rv; + + if (reply->retval != VAPI_OK) + return reply->retval; + + char *node_name = "node"; + value_t values[1]; + cdtime_t timestamp = cdtime(); + + values[0] = (value_t){.gauge = reply->pkts_processed}; + submit(node_name, pkts_processed_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->pkts_interest_count}; + submit(node_name, pkts_interest_count_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->pkts_data_count}; + submit(node_name, pkts_data_count_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->pkts_from_cache_count}; + submit(node_name, pkts_from_cache_count_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->pkts_no_pit_count}; + submit(node_name, pkts_no_pit_count_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->pit_expired_count}; + submit(node_name, pit_expired_count_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->cs_expired_count}; + submit(node_name, cs_expired_count_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->cs_lru_count}; + submit(node_name, cs_lru_count_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->pkts_drop_no_buf}; + submit(node_name, pkts_drop_no_buf_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->interests_aggregated}; + submit(node_name, interests_aggregated_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->interests_retx}; + submit(node_name, interests_retx_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->interests_hash_collision}; + submit(node_name, interests_hash_collision_ds.type, NULL, values, 1, + ×tamp); + values[0] = (value_t){.gauge = reply->pit_entries_count}; + submit(node_name, pit_entries_count_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->cs_entries_count}; + submit(node_name, cs_entries_count_ds.type, NULL, values, 1, ×tamp); + values[0] = (value_t){.gauge = reply->cs_entries_ntw_count}; + submit(node_name, cs_entries_ntw_count_ds.type, NULL, values, 1, ×tamp); + + return VAPI_OK; +} + +/* + * Callback called by the hICN plugin API when face stats are ready. + */ +static vapi_error_e +parse_face_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, + bool is_last, + vapi_payload_hicn_api_face_stats_details *reply) { + if (reply == NULL || rv != VAPI_OK) + return rv; + + if (reply->retval != VAPI_OK) + return reply->retval; + + char face_name[10]; + snprintf(face_name, 10, "face%u", reply->faceid); + value_t values[2]; + cdtime_t timestamp = cdtime(); + + values[0] = (value_t){.derive = reply->irx_packets}; + values[1] = (value_t){.derive = reply->irx_bytes}; + submit(face_name, irx_ds.type, NULL, values, 2, ×tamp); + values[0] = (value_t){.derive = reply->itx_packets}; + values[1] = (value_t){.derive = reply->itx_bytes}; + submit(face_name, itx_ds.type, NULL, values, 2, ×tamp); + values[0] = (value_t){.derive = reply->drx_packets}; + values[1] = (value_t){.derive = reply->drx_bytes}; + submit(face_name, drx_ds.type, NULL, values, 2, ×tamp); + values[0] = (value_t){.derive = reply->dtx_packets}; + values[1] = (value_t){.derive = reply->dtx_bytes}; + submit(face_name, dtx_ds.type, NULL, values, 2, ×tamp); + + return VAPI_OK; +} + +/* + * This function is called once upon startup to initialize the plugin. + */ +static int my_init(void) { + int ret = vapi_connect_safe(&vapi_ctx, 0); + + if (ret) + plugin_log(LOG_ERR, "vpp_hicn plugin: vapi_connect_safe failed"); + + return ret; +} + +/* + * This function is called in regular intervalls to collect the data. + */ +static int my_read(void) { + int err = VAPI_OK; + + vapi_lock(); + + // NODE + vapi_msg_hicn_api_node_stats_get *hicn_node_stats_msg; + hicn_node_stats_msg = vapi_alloc_hicn_api_node_stats_get(vapi_ctx); + + if (!hicn_node_stats_msg) { + plugin_log(LOG_ERR, + "vpp_hicn plugin: could not create hicn_node_stats message"); + err = VAPI_ENOMEM; + goto END; + } + + err = vapi_hicn_api_node_stats_get(vapi_ctx, hicn_node_stats_msg, + parse_node_stats, NULL); + + if (err) { + plugin_log(LOG_ERR, + "vpp_hicn plugin: query of node stats failed with error %d", + err); + goto END; + } + + // FACES + vapi_msg_hicn_api_face_stats_dump *hicn_face_stats_msg; + hicn_face_stats_msg = vapi_alloc_hicn_api_face_stats_dump(vapi_ctx); + + if (!hicn_face_stats_msg) { + plugin_log(LOG_ERR, + "vpp_hicn plugin: could not create hicn_face_stats message"); + err = VAPI_ENOMEM; + goto END; + } + + err = vapi_hicn_api_face_stats_dump(vapi_ctx, hicn_face_stats_msg, + parse_face_stats, NULL); + + if (err) { + plugin_log(LOG_ERR, + "vpp_hicn plugin: query of face stats failed with error %d", + err); + goto END; + } + +END: + vapi_unlock(); + + return err; +} + +/* + * This function is called when plugin_log () has been used. + */ +static void my_log(int severity, const char *msg, user_data_t *ud) { + printf("[LOG %i] %s\n", severity, msg); + return; +} + +/* + * This function is called before shutting down collectd. + */ +static int my_shutdown(void) { + plugin_log(LOG_INFO, "vpp_hicn plugin: shutting down"); + int ret = vapi_disconnect_safe(); + plugin_log(LOG_INFO, "vpp_hicn plugin: disconnect vapi %s", + ret == 0 ? "ok" : "error"); + return ret; +} + +/* + * This function is called after loading the plugin to register it with + * collectd. + */ +void module_register(void) { + // data sets face + plugin_register_data_set(&irx_ds); + plugin_register_data_set(&itx_ds); + plugin_register_data_set(&drx_ds); + plugin_register_data_set(&dtx_ds); + // data sets node + plugin_register_data_set(&pkts_processed_ds); + plugin_register_data_set(&pkts_interest_count_ds); + plugin_register_data_set(&pkts_data_count_ds); + plugin_register_data_set(&pkts_from_cache_count_ds); + plugin_register_data_set(&pkts_no_pit_count_ds); + plugin_register_data_set(&pit_expired_count_ds); + plugin_register_data_set(&cs_expired_count_ds); + plugin_register_data_set(&cs_lru_count_ds); + plugin_register_data_set(&pkts_drop_no_buf_ds); + plugin_register_data_set(&interests_aggregated_ds); + plugin_register_data_set(&interests_retx_ds); + plugin_register_data_set(&interests_hash_collision_ds); + plugin_register_data_set(&pit_entries_count_ds); + plugin_register_data_set(&cs_entries_count_ds); + plugin_register_data_set(&cs_entries_ntw_count_ds); + // callbacks + plugin_register_log("vpp_hicn", my_log, /* user data */ NULL); + plugin_register_init("vpp_hicn", my_init); + plugin_register_read("vpp_hicn", my_read); + plugin_register_shutdown("vpp_hicn", my_shutdown); + return; +} -- cgit 1.2.3-korg