From ec995e056d985f9ef54f92adbcbe626967912592 Mon Sep 17 00:00:00 2001 From: YohanPipereau Date: Wed, 5 Jun 2019 11:21:14 +0200 Subject: Support for ietf-interfaces statistics -Add connection to VPP STAT API -Support a few statistic counters from ietf-interfaces Change-Id: I77372ea562e73311effd5b08fd36b0d90ababdac Signed-off-by: YohanPipereau --- src/plugins/ietf/ietf_interface.c | 180 +++++++++++++++++++++++++++++++++++++- src/plugins/sc_plugins.c | 18 +++- 2 files changed, 195 insertions(+), 3 deletions(-) diff --git a/src/plugins/ietf/ietf_interface.c b/src/plugins/ietf/ietf_interface.c index 4d13d13..b4a2bc7 100644 --- a/src/plugins/ietf/ietf_interface.c +++ b/src/plugins/ietf/ietf_interface.c @@ -21,6 +21,8 @@ #include #include +#include + /** * @brief Callback to be called by any config change of * "/ietf-interfaces:interfaces/interface/enabled" leaf. @@ -259,6 +261,8 @@ ietf_interface_change_cb(sr_session_ctx_t *session, const char *xpath, /** * @brief Callback to be called by any request for state data under "/ietf-interfaces:interfaces-state/interface" path. + * Here we reply systematically with all interfaces, it the responsability of + * sysrepo apply a filter not to answer undesired interfaces. */ static int ietf_interface_state_cb(const char *xpath, sr_val_t **values, @@ -292,7 +296,7 @@ ietf_interface_state_cb(const char *xpath, sr_val_t **values, foreach_stack_elt(stack) { dump = (sw_interface_dump_t *) data; - SRP_LOG_DBG("State of interface %s", dump->interface_name); + SRP_LOG_DBG("State of interface %s, xpath %s", dump->interface_name, xpath); //TODO need support for type propvirtual sr_val_build_xpath(&val[cnt], "%s[name='%s']/type", xpath, dump->interface_name); sr_val_set_str_data(&val[cnt], SR_IDENTITYREF_T, "iana-if-type:ethernetCsmacd"); @@ -338,6 +342,174 @@ nothing_todo: return rc; } +static inline stat_segment_data_t* fetch_stat_index(const char *path) { + stat_segment_data_t *r; + u32 *stats = NULL; + u8 **patterns = NULL; + + patterns = stat_segment_string_vector(patterns, path); + if (!patterns) + return NULL; + + do { + stats = stat_segment_ls(patterns); + if (!stats) + return NULL; + + r = stat_segment_dump(stats); + } while (r == NULL); /* Memory layout has changed */ + + return r; +} + +static inline uint64_t get_counter(stat_segment_data_t *r, int itf_idx) +{ + if (r == NULL) { + SRP_LOG_ERR_MSG("stat segment can not be NULL"); + return 0; + } + + if (r->type != STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE) { + SRP_LOG_ERR_MSG("Only simple counter"); + return 0; + } + + return r->simple_counter_vec[0][itf_idx]; +} + +static inline uint64_t get_bytes(stat_segment_data_t *r, int itf_idx) +{ + if (r->type != STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED) { + SRP_LOG_ERR_MSG("Only combined counter"); + return 0; + } + + return r->combined_counter_vec[0][itf_idx].bytes; +} + +static inline uint64_t get_packets(stat_segment_data_t *r, int itf_idx) +{ + if (r->type != STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED) { + SRP_LOG_ERR_MSG("Only combined counter"); + return 0; + } + + return r->combined_counter_vec[0][itf_idx].packets; +} + +/** + * @brief Callback to be called by any request for state data under + * "/ietf-interfaces:interfaces-state/interface/statistics" path. + */ +static int +interface_statistics_cb(const char *xpath, sr_val_t **values, + size_t *values_cnt, uint64_t request_id, + const char *original_xpath, void *private_ctx) +{ + UNUSED(request_id); UNUSED(original_xpath); UNUSED(private_ctx); + sr_val_t *val = NULL; + int vc = 10; + int cnt = 0; //value counter + int rc = SR_ERR_OK; + sr_xpath_ctx_t state = {0}; + char *tmp; + char interface_name[VPP_INTFC_NAME_LEN] = {0}; + uint32_t itf_idx; + stat_segment_data_t *r; + + SRP_LOG_INF("In %s", __FUNCTION__); + + /* Retrieve the interface asked */ + tmp = sr_xpath_key_value((char*) xpath, "interface", "name", &state); + if (!tmp) { + SRP_LOG_ERR_MSG("XPATH interface name not found"); + return SR_ERR_INVAL_ARG; + } + strncpy(interface_name, tmp, VPP_INTFC_NAME_LEN); + sr_xpath_recover(&state); + + /* allocate array of values to be returned */ + rc = sr_new_values(vc, &val); + if (0 != rc) + goto nothing_todo; + + rc = get_interface_id(interface_name, &itf_idx); + if (rc != 0) + goto nothing_todo; + + SRP_LOG_DBG("name:%s index:%d", interface_name, itf_idx); + + r = fetch_stat_index("/if"); + if (!r) + goto nothing_todo; + + for (int i = 0; i < stat_segment_vec_len(r); i++) { + if (strcmp(r[i].name, "/if/rx") == 0) { + sr_val_build_xpath(&val[cnt], "%s/in-octets", xpath, 5); + val[cnt].type = SR_UINT64_T; + val[cnt].data.uint64_val = get_bytes(&r[i], itf_idx); + cnt++; + } else if (strcmp(r[i].name, "/if/rx-unicast") == 0) { + sr_val_build_xpath(&val[cnt], "%s/in-unicast-pkts", xpath, 5); + val[cnt].type = SR_UINT64_T; + val[cnt].data.uint64_val = get_packets(&r[i], itf_idx); + cnt++; + } else if (strcmp(r[i].name, "/if/rx-broadcast") == 0) { + sr_val_build_xpath(&val[cnt], "%s/in-broadcast-pkts", xpath, 5); + val[cnt].type = SR_UINT64_T; + val[cnt].data.uint64_val = get_packets(&r[i], itf_idx); + cnt++; + } else if (strcmp(r[i].name, "/if/rx-multicast") == 0) { + sr_val_build_xpath(&val[cnt], "%s/in-multicast-pkts", xpath, 5); + val[cnt].type = SR_UINT64_T; + val[cnt].data.uint64_val = get_packets(&r[i], itf_idx); + cnt++; + } else if (strcmp(r[i].name, "/if/rx-error") == 0) { + sr_val_build_xpath(&val[cnt], "%s/in-errors", xpath, 5); + val[cnt].type = SR_UINT32_T; + //Be carefeul cast uint64 to uint32 + val[cnt].data.uint32_val = get_counter(&r[i], itf_idx); + cnt++; + } else if (strcmp(r[i].name, "/if/tx") == 0) { + sr_val_build_xpath(&val[cnt], "%s/out-octets", xpath, 5); + val[cnt].type = SR_UINT64_T; + val[cnt].data.uint64_val = get_bytes(&r[i], itf_idx); + cnt++; + } else if (strcmp(r[i].name, "/if/tx-unicast") == 0) { + sr_val_build_xpath(&val[cnt], "%s/out-unicast-pkts", xpath, 5); + val[cnt].type = SR_UINT64_T; + val[cnt].data.uint64_val = get_packets(&r[i], itf_idx); + cnt++; + } else if (strcmp(r[i].name, "/if/tx-broadcast") == 0) { + sr_val_build_xpath(&val[cnt], "%s/out-broadcast-pkts", xpath, 5); + val[cnt].type = SR_UINT64_T; + val[cnt].data.uint64_val = get_packets(&r[i], itf_idx); + cnt++; + } else if (strcmp(r[i].name, "/if/tx-multicast") == 0) { + sr_val_build_xpath(&val[cnt], "%s/out-multicast-pkts", xpath, 5); + val[cnt].type = SR_UINT64_T; + val[cnt].data.uint64_val = get_packets(&r[i], itf_idx); + cnt++; + } else if (strcmp(r[i].name, "/if/tx-error") == 0) { + sr_val_build_xpath(&val[cnt], "%s/out-errors", xpath, 5); + val[cnt].type = SR_UINT32_T; + //Be carefeul cast uint64 to uint32 + val[cnt].data.uint32_val = get_counter(&r[i], itf_idx); + cnt++; + } + } + + *values = val; + *values_cnt = cnt; + + return SR_ERR_OK; + +nothing_todo: + *values = NULL; + *values_cnt = 0; + return rc; +} + int ietf_interface_init(sc_plugin_main_t *pm) @@ -375,6 +547,12 @@ ietf_interface_init(sc_plugin_main_t *pm) goto error; } + rc = sr_dp_get_items_subscribe(pm->session, "/ietf-interfaces:interfaces-state/interface/statistics", + interface_statistics_cb, NULL, SR_SUBSCR_CTX_REUSE, &pm->subscription); + if (SR_ERR_OK != rc) { + goto error; + } + SRP_LOG_DBG_MSG("ietf-interface plugin initialized successfully."); return SR_ERR_OK; diff --git a/src/plugins/sc_plugins.c b/src/plugins/sc_plugins.c index e0de0f6..7fc5975 100644 --- a/src/plugins/sc_plugins.c +++ b/src/plugins/sc_plugins.c @@ -17,6 +17,8 @@ #include +#include + sc_plugin_main_t sc_plugin_main; static int vpp_pid_start; @@ -73,9 +75,17 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx) sc_plugin_main.session = session; + /* Connect to VAPI */ rc = sc_connect_vpp(); if (0 != rc) { - SRP_LOG_ERR("vpp connect error , with return %d.", rc); + SRP_LOG_ERR("vpp vapi connect error , with return %d.", rc); + return SR_ERR_INTERNAL; + } + + /* Connect to STAT API */ + rc = stat_segment_connect(STAT_SEGMENT_SOCKET_FILE); + if (rc != 0) { + SRP_LOG_ERR("vpp stat connect error , with return %d.", rc); return SR_ERR_INTERNAL; } @@ -94,13 +104,17 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx) void sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *private_ctx) { - sc_call_all_exit_function(&sc_plugin_main); + sc_call_all_exit_function(&sc_plugin_main); /* subscription was set as our private context */ if (private_ctx != NULL) sr_unsubscribe(session, private_ctx); SRP_LOG_DBG_MSG("unload plugin ok."); + /* Disconnect from STAT API */ + stat_segment_disconnect(); + + /* Disconnect from VAPI */ sc_disconnect_vpp(); SRP_LOG_DBG_MSG("plugin disconnect vpp ok."); } -- cgit 1.2.3-korg