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 --- CMakeLists.txt | 3 + cmake/Modules/BuildMacros.cmake | 30 +- cmake/Modules/FindCollectd.cmake | 47 +++ cmake/Modules/FindVapiSafe.cmake | 40 ++ docs/source/index.rst | 3 +- docs/source/telemetry.md | 116 ++++++ libtransport/src/hicn/transport/core/hicn_vapi.c | 2 - scripts/build-packages.sh | 26 ++ telemetry/CMakeLists.txt | 21 ++ telemetry/vpp-collectd/CMakeLists.txt | 31 ++ .../vpp-collectd/cmake/Modules/Packaging.cmake | 31 ++ telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt | 55 +++ telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c | 416 +++++++++++++++++++++ telemetry/vpp-collectd/vpp/CMakeLists.txt | 42 +++ telemetry/vpp-collectd/vpp/vpp.c | 398 ++++++++++++++++++++ 15 files changed, 1249 insertions(+), 12 deletions(-) create mode 100644 cmake/Modules/FindCollectd.cmake create mode 100644 cmake/Modules/FindVapiSafe.cmake create mode 100644 docs/source/telemetry.md create mode 100644 telemetry/CMakeLists.txt create mode 100644 telemetry/vpp-collectd/CMakeLists.txt create mode 100644 telemetry/vpp-collectd/cmake/Modules/Packaging.cmake create mode 100644 telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt create mode 100644 telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c create mode 100644 telemetry/vpp-collectd/vpp/CMakeLists.txt create mode 100644 telemetry/vpp-collectd/vpp/vpp.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ea6de33d..5551d5acd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ option(BUILD_CTRL "Build the hicn control tools" ON) option(BUILD_HICNPLUGIN "Build the hicn vpp plugin" OFF) option(BUILD_SYSREPOPLUGIN "Build the sysrepo plugin" OFF) option(BUILD_EXTRAS "Build external projects" OFF) +option(BUILD_TELEMETRY "Build telemetry projects" OFF) option(DISABLE_EXECUTABLES "Disable executables" OFF) option(DISABLE_SHARED_LIBRARIES "Disable shared libraries" OFF) @@ -64,6 +65,7 @@ list(APPEND dir_options BUILD_APPS BUILD_SYSREPOPLUGIN BUILD_EXTRAS + BUILD_TELEMETRY ) set(BUILD_LIBHICN_DIR lib) @@ -75,6 +77,7 @@ set(BUILD_CTRL_DIR ctrl) set(BUILD_HICNPLUGIN_DIR hicn-plugin) set(BUILD_SYSREPOPLUGIN_DIR ctrl/sysrepo-plugins) set(BUILD_EXTRAS_DIR extras/) +set(BUILD_TELEMETRY_DIR telemetry) ## Add enabled components foreach (opt ${dir_options}) diff --git a/cmake/Modules/BuildMacros.cmake b/cmake/Modules/BuildMacros.cmake index c4c6c9af1..d360d26af 100644 --- a/cmake/Modules/BuildMacros.cmake +++ b/cmake/Modules/BuildMacros.cmake @@ -73,7 +73,7 @@ macro(build_library lib) cmake_parse_arguments(ARG "SHARED;STATIC;NO_DEV" "COMPONENT;" - "SOURCES;LINK_LIBRARIES;INSTALL_HEADERS;DEPENDS;INCLUDE_DIRS;DEFINITIONS;INSTALL_ROOT_DIR;INSTALL_FULL_PATH_DIR" + "SOURCES;LINK_LIBRARIES;INSTALL_HEADERS;DEPENDS;INCLUDE_DIRS;DEFINITIONS;INSTALL_ROOT_DIR;INSTALL_FULL_PATH_DIR;EMPTY_PREFIX;" ${ARGN} ) @@ -106,14 +106,26 @@ macro(build_library lib) ) endif() - set_target_properties(${library} - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" - INSTALL_RPATH_USE_LINK_PATH TRUE - ARCHIVE_OUTPUT_DIRECTORY "${BUILD_ROOT}/lib" - LIBRARY_OUTPUT_DIRECTORY "${BUILD_ROOT}/lib" - RUNTIME_OUTPUT_DIRECTORY "${BUILD_ROOT}/bin" - ) + if (${ARG_EMPTY_PREFIX}) + set_target_properties(${library} + PROPERTIES + INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" + INSTALL_RPATH_USE_LINK_PATH TRUE + PREFIX "" + ARCHIVE_OUTPUT_DIRECTORY "${BUILD_ROOT}/lib" + LIBRARY_OUTPUT_DIRECTORY "${BUILD_ROOT}/lib" + RUNTIME_OUTPUT_DIRECTORY "${BUILD_ROOT}/bin" + ) + else () + set_target_properties(${library} + PROPERTIES + INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" + INSTALL_RPATH_USE_LINK_PATH TRUE + ARCHIVE_OUTPUT_DIRECTORY "${BUILD_ROOT}/lib" + LIBRARY_OUTPUT_DIRECTORY "${BUILD_ROOT}/lib" + RUNTIME_OUTPUT_DIRECTORY "${BUILD_ROOT}/bin" + ) + endif() if (WIN32) target_compile_options(${library} PRIVATE) diff --git a/cmake/Modules/FindCollectd.cmake b/cmake/Modules/FindCollectd.cmake new file mode 100644 index 000000000..76d2df43f --- /dev/null +++ b/cmake/Modules/FindCollectd.cmake @@ -0,0 +1,47 @@ +# 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. + +set(COLLECTD_SEARCH_PATH_LIST + ${COLLECTD_HOME} + $ENV{COLLECTD_HOME} + /usr/local + /opt + /usr + ) + +find_path(COLLECTD_INCLUDE_DIR collectd.h + HINTS ${COLLECTD_SEARCH_PATH_LIST} + PATH_SUFFIXES include/collectd/core/daemon/ daemon/ + DOC "Find the collectd includes" +) + +find_path(COLLECTD_COMMON_INCLUDE_DIR common.h + HINTS ${COLLECTD_SEARCH_PATH_LIST} + PATH_SUFFIXES include/collectd/core/daemon/ utils/common/ + DOC "Find the collectd includes" +) + +find_path(COLLECTD_CONFIG_INCLUDE_DIR config.h + HINTS ${COLLECTD_SEARCH_PATH_LIST} + PATH_SUFFIXES include/collectd/core/ + DOC "Find the collectd includes" +) + +message(STATUS ${COLLECTD_INCLUDE_DIR} ${COLLECTD_COMMON_INCLUDE_DIR} ${COLLECTD_CONFIG_INCLUDE_DIR}) + +set(COLLECTD_INCLUDE_DIRS ${COLLECTD_INCLUDE_DIR} ${COLLECTD_COMMON_INCLUDE_DIR} ${COLLECTD_CONFIG_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Collectd DEFAULT_MSG COLLECTD_INCLUDE_DIRS) + +mark_as_advanced(COLLECTD_INCLUDE_DIRS) diff --git a/cmake/Modules/FindVapiSafe.cmake b/cmake/Modules/FindVapiSafe.cmake new file mode 100644 index 000000000..c2c9fd762 --- /dev/null +++ b/cmake/Modules/FindVapiSafe.cmake @@ -0,0 +1,40 @@ +# 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. + +set(SAFE_VAPI_SEARCH_PATH_LIST + ${SAFE_VAPI_HOME} + $ENV{SAFE_VAPI_HOME} + /usr/local + /opt + /usr +) + +find_path(SAFE_VAPI_INCLUDE_DIR vapi/vapi_safe.h + HINTS ${SAFE_VAPI_SEARCH_PATH_LIST} + PATH_SUFFIXES include + DOC "Find the vapi_safe includes" +) + +find_library(SAFE_VAPI_LIBRARY NAMES libsafe_vapi.so + HINTS ${SAFE_VAPI_SEARCH_PATH_LIST} + PATH_SUFFIXES lib/x86_64-linux-gnu/ + DOC "Find the vapi safe lib" +) + +set(SAFE_VAPI_LIBRARIES ${SAFE_VAPI_LIBRARY}) +set(SAFE_VAPI_INCLUDE_DIRS ${SAFE_VAPI_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(VapiSafe DEFAULT_MSG SAFE_VAPI_LIBRARIES SAFE_VAPI_INCLUDE_DIRS) + +mark_as_advanced(SAFE_VAPI_LIBRARY SAFE_VAPI_INCLUDE_DIR) diff --git a/docs/source/index.rst b/docs/source/index.rst index af8818388..17aeb3a1c 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,7 +2,7 @@ Hybrid Information-Centric Networking ===================================== .. toctree:: - + started lib vpp-plugin @@ -10,6 +10,7 @@ Hybrid Information-Centric Networking hicn-light interface control + telemetry utils apps diff --git a/docs/source/telemetry.md b/docs/source/telemetry.md new file mode 100644 index 000000000..0af3b0e02 --- /dev/null +++ b/docs/source/telemetry.md @@ -0,0 +1,116 @@ +# Telemetry + +Tools to collect telemetry from hICN forwarders. + +## Introduction ## + +The project containes two plugins for [collectd](https://github.com/collectd/collectd): +* vpp: to collect statistics for VPP +* vpp-hicn: to collect statistics for [hICN](https://github.com/FDio/hicn) + + +Currently the two plugins provide the followign funtionalities: + +* VPP: statistics (rx/tx bytes and packets) for each available interface. +* HICN-VPP: statistics (rx/tx bytes and packets) for each available face. + +## Quick Start ## + +``` +From the code tree root + +$ cd telemetry +$ mkdir -p build +$ cd build +$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr +$ make +$ sudo make install +``` + +## Using hICN collectd plugins ## + +### Platforms ### + +hICN collectd plugins have been tested in: + +- Ubuntu 16.04 LTS (x86_64) +- Ubuntu 18.04 LTS (x86_64) +- Debian Stable/Testing +- Red Hat Enterprise Linux 7 +- CentOS 7 + + +### Dependencies ### + +Build dependencies: + +- VPP 20.01 + - DEB packages (can be found https://packagecloud.io/fdio/release/install): + - vpp + - libvppinfra-dev + - vpp-dev + - hicn-plugin-dev + +## Getting started ## + +Collectd needs to be configured in order to use the hICN collectd plugins. +The configuration can be achieved editing the file '/etc/collectd/collectd.conf' and adding the following lines: + +``` +LoadPlugin vpp +LoadPlugin vpp_hicn +``` + +Before running collectd, a vpp forwarder must be started. If the vpp-hicn plugin is used, the hicn-plugin must be available in the vpp forwarder + +### Example: use rrdtool and csv plugin to store statistics from vpp and vpp-hicn plugins + +Edit the configuration file as the following: + +``` +###################################################################### +# Global # +###################################################################### +FQDNLookup true +BaseDir "/collectd" +Interval 2 + +###################################################################### +# Logging # +###################################################################### +LoadPlugin logfile + + + LogLevel "info" + File "/var/log/collectd.log" + Timestamp true + PrintSeverity true + + +###################################################################### +# Plugins # +###################################################################### +LoadPlugin csv +LoadPlugin rrdtool +LoadPlugin vpp +LoadPlugin vpp_hicn + +###################################################################### +# Plugin configuration # +###################################################################### + + DataDir "/collectd/csv" # the folder under which statistics are written in csv + StoreRates true + + + + DataDir "/collectd/rrd" # the folder under which statistics are written in csv + +``` + +Run vpp and collectd + +``` +$ systemctl start vpp +$ systemctl start collectd +``` diff --git a/libtransport/src/hicn/transport/core/hicn_vapi.c b/libtransport/src/hicn/transport/core/hicn_vapi.c index af7fa5a03..aea08f31c 100644 --- a/libtransport/src/hicn/transport/core/hicn_vapi.c +++ b/libtransport/src/hicn/transport/core/hicn_vapi.c @@ -121,9 +121,7 @@ int hicn_vapi_face_prod_del( msg->payload.faceid = input_params->face_id; - printf("Deleting producer face %d\n", msg->payload.faceid); int ret = vapi_hicn_api_face_prod_del(ctx, msg, face_prod_del_cb, NULL); - printf("DONE Deleting producer face %d\n", input_params->face_id); vapi_unlock(); return ret; } diff --git a/scripts/build-packages.sh b/scripts/build-packages.sh index 216099f3c..35741495f 100644 --- a/scripts/build-packages.sh +++ b/scripts/build-packages.sh @@ -178,6 +178,29 @@ setup() { c++ --version } + +install_collectd_headers() { + if [ -f /etc/os-release ]; then + . /etc/os-release + else + echo "ERROR: System configuration not recognized. Build failed" + exit -1 + fi + + if [ "${DISTRIB_ID}" == "ubuntu" ]; then + sudo apt-get install collectd-dev -y --allow-unauthenticated + + if [ "${VERSION_CODENAME}" == "xenial" ]; then + awk '/config.h/ { print; print "#include \"collectd/liboconfig/oconfig.h\""; next }1' /usr/include/collectd/core/daemon/configfile.h | sudo tee /usr/include/collectd/core/daemon/configfile.h + fi + elif [ "${DISTRIB_ID}" == "centos" ]; then + wget https://storage.googleapis.com/collectd-tarballs/collectd-5.9.2.tar.bz2 + tar -xf collectd-5.9.2.tar.bz2 + cd collectd-5.9.2 && ./configure && make && cd - + export COLLECTD_HOME=${PWD}/collectd-5.9.2/src + fi +} + # Parameters: # $1 = Package name # @@ -197,12 +220,15 @@ build_package() { rm -rf libtransport ctrl/libhicnctrl + install_collectd_headers + cmake -DCMAKE_INSTALL_PREFIX=/usr \ -DBUILD_HICNPLUGIN=ON \ -DBUILD_LIBTRANSPORT=ON \ -DBUILD_APPS=ON \ -DBUILD_HICNLIGHT=OFF \ -DBUILD_SYSREPOPLUGIN=ON \ + -DBUILD_TELEMETRY=ON \ ${SCRIPT_PATH}/.. make VERBOSE=1 -j8 package diff --git a/telemetry/CMakeLists.txt b/telemetry/CMakeLists.txt new file mode 100644 index 000000000..53fd04f01 --- /dev/null +++ b/telemetry/CMakeLists.txt @@ -0,0 +1,21 @@ +# 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. + + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +if ((CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) OR + (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")) + add_subdirectory(vpp-collectd) +endif () + diff --git a/telemetry/vpp-collectd/CMakeLists.txt b/telemetry/vpp-collectd/CMakeLists.txt new file mode 100644 index 000000000..18926b1c5 --- /dev/null +++ b/telemetry/vpp-collectd/CMakeLists.txt @@ -0,0 +1,31 @@ +# 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. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +set (COLLECTD_PLUGINS hicn-collectd-plugins) +project(hicn-collectd-plugins) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/" "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules/") + +include(BuildMacros) + + +add_subdirectory(vpp) +add_subdirectory(vpp-hicn) + +include(Packaging) +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + include(Packager) + make_packages() +endif() diff --git a/telemetry/vpp-collectd/cmake/Modules/Packaging.cmake b/telemetry/vpp-collectd/cmake/Modules/Packaging.cmake new file mode 100644 index 000000000..dc4629a26 --- /dev/null +++ b/telemetry/vpp-collectd/cmake/Modules/Packaging.cmake @@ -0,0 +1,31 @@ +# 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. + +###################### +# Packages section +###################### + +set(${COLLECTD_PLUGINS}_DESCRIPTION + "A high-performance Hybrid ICN forwarder as a plugin to VPP." + CACHE STRING "Description for deb/rpm package." +) + +set(${COLLECTD_PLUGINS}_DEB_DEPENDENCIES + "collectd, hicn-plugin-dev" + CACHE STRING "Dependencies for deb/rpm package." +) + +set(${COLLECTD_PLUGINS}_RPM_DEPENDENCIES + "collectd, hicn-plugin-dev" + CACHE STRING "Dependencies for deb/rpm package." +) \ No newline at end of file diff --git a/telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt b/telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt new file mode 100644 index 000000000..ab048b730 --- /dev/null +++ b/telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt @@ -0,0 +1,55 @@ +# 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. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +# Dependencies +find_package(Collectd REQUIRED) +find_package(Vpp REQUIRED) + +if(${CMAKE_SOURCE_DIR}/vpp-collectd STREQUAL ${PROJECT_SOURCE_DIR}) + message (STATUS "not compiling in the same folder") + find_package(HicnPlugin REQUIRED) + find_package(VapiSafe REQUIRED) +else() + message (STATUS "compiling in the same folder") + list(APPEND DEPENDENCIES + hicn_plugin + ) +endif() + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/vpp_hicn.c +) + +list (APPEND INCLUDE_DIRS + ${COLLECTD_INCLUDE_DIRS} + ${HICNPLUGIN_INCLUDE_DIRS} + ${SAFE_VAPI_INCLUDE_DIRS} + ${VPP_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR}) + +list (APPEND LIBRARIES + ${VPP_LIBRARY_VAPICLIENT} + ${SAFE_VAPI_LIBRARIES}) + +build_library(vpp_hicn + SHARED + SOURCES ${SOURCE_FILES} + LINK_LIBRARIES ${LIBRARIES} + INCLUDE_DIRS ${INCLUDE_DIRS} + INSTALL_FULL_PATH_DIR ${CMAKE_INSTALL_PREFIX}/collectd + COMPONENT "${COLLECTD_PLUGINS}" + DEPENDS ${DEPENDENCIES} + EMPTY_PREFIX true + ) 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; +} diff --git a/telemetry/vpp-collectd/vpp/CMakeLists.txt b/telemetry/vpp-collectd/vpp/CMakeLists.txt new file mode 100644 index 000000000..71fb7fc3d --- /dev/null +++ b/telemetry/vpp-collectd/vpp/CMakeLists.txt @@ -0,0 +1,42 @@ +# 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. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +# Dependencies + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/vpp.c +) + +find_package(Vpp REQUIRED) +find_package(Collectd REQUIRED) + +list (APPEND INCLUDE_DIRS + ${COLLECTD_INCLUDE_DIRS} + ${VPP_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR}) + +list (APPEND LIBRARIES + ${VPP_LIBRARY_VPPAPICLIENT} + ${VPP_LIBRARY_INFRA}) + +build_library(vpp + SHARED + SOURCES ${SOURCE_FILES} + LINK_LIBRARIES ${LIBRARIES} + INCLUDE_DIRS ${INCLUDE_DIRS} + INSTALL_FULL_PATH_DIR ${CMAKE_INSTALL_PREFIX}/collectd + COMPONENT ${COLLECTD_PLUGINS} + EMPTY_PREFIX true + ) diff --git a/telemetry/vpp-collectd/vpp/vpp.c b/telemetry/vpp-collectd/vpp/vpp.c new file mode 100644 index 000000000..72c052212 --- /dev/null +++ b/telemetry/vpp-collectd/vpp/vpp.c @@ -0,0 +1,398 @@ +/* + * 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 + +/************** DATA SOURCES ******************************/ +static data_source_t combined_dsrc[2] = { + {"packets", DS_TYPE_DERIVE, 0, NAN}, + {"bytes", DS_TYPE_DERIVE, 0, NAN}, +}; + +static data_source_t simple_dsrc[1] = { + {"packets", DS_TYPE_DERIVE, 0, NAN}, +}; + +/************** DATA SETS *********************************/ +static data_set_t if_drops_ds = { + "if_drops", + STATIC_ARRAY_SIZE(simple_dsrc), + simple_dsrc, +}; + +static data_set_t if_punt_ds = { + "if_punt", + STATIC_ARRAY_SIZE(simple_dsrc), + simple_dsrc, +}; + +static data_set_t if_ip4_ds = { + "if_ip4", + STATIC_ARRAY_SIZE(simple_dsrc), + simple_dsrc, +}; + +static data_set_t if_ip6_ds = { + "if_ip6", + STATIC_ARRAY_SIZE(simple_dsrc), + simple_dsrc, +}; + +static data_set_t if_rx_no_buf_ds = { + "if_rx_no_buf", + STATIC_ARRAY_SIZE(simple_dsrc), + simple_dsrc, +}; + +static data_set_t if_rx_miss_ds = { + "if_rx_miss", + STATIC_ARRAY_SIZE(simple_dsrc), + simple_dsrc, +}; + +static data_set_t if_rx_error_ds = { + "if_rx_error", + STATIC_ARRAY_SIZE(simple_dsrc), + simple_dsrc, +}; + +static data_set_t if_tx_error_ds = { + "if_tx_error", + STATIC_ARRAY_SIZE(simple_dsrc), + simple_dsrc, +}; + +static data_set_t if_mpls_ds = { + "if_mpls", + STATIC_ARRAY_SIZE(simple_dsrc), + simple_dsrc, +}; + +static data_set_t if_rx_ds = { + "if_rx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t if_rx_unicast_ds = { + "if_rx_unicast", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t if_rx_multicast_ds = { + "if_rx_multicast", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t if_rx_broadcast_ds = { + "if_rx_broadcast", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t if_tx_ds = { + "if_tx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t if_tx_unicast_ds = { + "if_tx_unicast", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t if_tx_multicast_ds = { + "if_tx_multicast", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +static data_set_t if_tx_broadcast_ds = { + "if_tx_broadcast", + 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", 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); +} + +/* + * Utility function to fetch the data set corresponding to the stat name. + */ +static int get_data_set(const char *stat_name, data_set_t *data_set_ptr) { + if (data_set_ptr == NULL) { + return 1; + } + + if (strcmp(stat_name, "/if/drops") == 0) { + *data_set_ptr = if_drops_ds; + } else if (strcmp(stat_name, "/if/punt") == 0) { + *data_set_ptr = if_punt_ds; + } else if (strcmp(stat_name, "/if/ip4") == 0) { + *data_set_ptr = if_ip4_ds; + } else if (strcmp(stat_name, "/if/ip6") == 0) { + *data_set_ptr = if_ip6_ds; + } else if (strcmp(stat_name, "/if/rx-no-buf") == 0) { + *data_set_ptr = if_rx_no_buf_ds; + } else if (strcmp(stat_name, "/if/rx-miss") == 0) { + *data_set_ptr = if_rx_miss_ds; + } else if (strcmp(stat_name, "/if/rx-error") == 0) { + *data_set_ptr = if_rx_error_ds; + } else if (strcmp(stat_name, "/if/tx-error") == 0) { + *data_set_ptr = if_tx_error_ds; + } else if (strcmp(stat_name, "/if/mpls") == 0) { + *data_set_ptr = if_mpls_ds; + } else if (strcmp(stat_name, "/if/rx") == 0) { + *data_set_ptr = if_rx_ds; + } else if (strcmp(stat_name, "/if/rx-unicast") == 0) { + *data_set_ptr = if_rx_unicast_ds; + } else if (strcmp(stat_name, "/if/rx-multicast") == 0) { + *data_set_ptr = if_rx_multicast_ds; + } else if (strcmp(stat_name, "/if/rx-broadcast") == 0) { + *data_set_ptr = if_rx_broadcast_ds; + } else if (strcmp(stat_name, "/if/tx") == 0) { + *data_set_ptr = if_tx_ds; + } else if (strcmp(stat_name, "/if/tx-unicast") == 0) { + *data_set_ptr = if_tx_unicast_ds; + } else if (strcmp(stat_name, "/if/tx-multicast") == 0) { + *data_set_ptr = if_tx_multicast_ds; + } else if (strcmp(stat_name, "/if/tx-broadcast") == 0) { + *data_set_ptr = if_tx_broadcast_ds; + } else { + return 1; + } + + return 0; +} + +/**********************************************************/ +/********** CALLBACK FUNCTIONS ****************************/ +/**********************************************************/ + +/* + * This function is called once upon startup to initialize the plugin. + */ +static int my_init(void) { + u8 *stat_segment_name = (u8 *)STAT_SEGMENT_SOCKET_FILE; + int ret = stat_segment_connect((char *)stat_segment_name); + + if (ret) + plugin_log(LOG_ERR, "vpp plugin: connecting to segment failed"); + + return ret; +} + +/* + * This function is called in regular intervalls to collect the data. + */ +static int my_read(void) { + uint8_t **patterns = {0}; + char **interfaces = {0}; + + vec_add1(patterns, (uint8_t *)"^/if"); + vec_add1(patterns, (uint8_t *)"ip4-input"); + + uint32_t *dir = stat_segment_ls(patterns); + stat_segment_data_t *res = stat_segment_dump(dir); + plugin_log(LOG_INFO, "vpp plugin: performed ls and dump"); + + /* Read all available interfaces */ + for (int k = 0; k < vec_len(res); k++) { + if (res[k].type == STAT_DIR_TYPE_NAME_VECTOR) { + for (int i = 0; i < vec_len(res[k].name_vector); i++) { + if (res[k].name_vector[i]) { + vec_add1(interfaces, (char *)res[k].name_vector[i]); + } + } + break; + } + } + + cdtime_t timestamp = cdtime(); + data_set_t data_set; + int err = 0; + + /* Collect results for each interface and submit them */ + for (int i = 0; i < vec_len(res); i++) { + switch (res[i].type) { + case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE: + for (int k = 0; k < vec_len(res[i].simple_counter_vec); k++) { + for (int j = 0; j < vec_len(res[i].simple_counter_vec[k]); j++) { + value_t values[1] = { + (value_t){.derive = res[i].simple_counter_vec[k][j]}}; + + if (get_data_set(res[i].name, &data_set)) { + plugin_log(LOG_INFO, "vpp plugin: ignored stat name %s", + res[i].name); + continue; + } + + err = + submit(interfaces[j], data_set.type, NULL, values, 1, ×tamp); + + if (err) + goto END; + } + } + break; + + case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED: + for (int k = 0; k < vec_len(res[i].combined_counter_vec); k++) { + for (int j = 0; j < vec_len(res[i].combined_counter_vec[k]); j++) { + value_t values[2] = { + (value_t){.derive = res[i].combined_counter_vec[k][j].packets}, + (value_t){.derive = res[i].combined_counter_vec[k][j].bytes}, + }; + + if (get_data_set(res[i].name, &data_set)) { + plugin_log(LOG_INFO, "vpp plugin: ignored stat name %s", + res[i].name); + continue; + } + + err = + submit(interfaces[j], data_set.type, NULL, values, 2, ×tamp); + + if (err) + goto END; + } + } + break; + + case STAT_DIR_TYPE_SCALAR_INDEX: + plugin_log(LOG_INFO, "vpp plugin: %.2f %s", res[i].scalar_value, + res[i].name); + break; + + case STAT_DIR_TYPE_NAME_VECTOR: + break; + + case STAT_DIR_TYPE_ERROR_INDEX: + break; + + default: + plugin_log(LOG_WARNING, "vpp plugin: unknown stat type %d", res[i].type); + break; + } + } + +END: + if (err) + plugin_log(LOG_ERR, + "vpp plugin: dispatching of results failed with error code %d.", + err); + + stat_segment_data_free(res); + + 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 plugin: shutting down"); + stat_segment_disconnect(); + return 0; +} + +/* + * This function is called after loading the plugin to register it with + * collectd. + */ +void module_register(void) { + plugin_register_data_set(&if_drops_ds); + plugin_register_data_set(&if_punt_ds); + plugin_register_data_set(&if_ip4_ds); + plugin_register_data_set(&if_ip6_ds); + plugin_register_data_set(&if_rx_no_buf_ds); + plugin_register_data_set(&if_rx_miss_ds); + plugin_register_data_set(&if_rx_error_ds); + plugin_register_data_set(&if_tx_error_ds); + plugin_register_data_set(&if_mpls_ds); + plugin_register_data_set(&if_rx_ds); + plugin_register_data_set(&if_rx_unicast_ds); + plugin_register_data_set(&if_rx_multicast_ds); + plugin_register_data_set(&if_rx_broadcast_ds); + plugin_register_data_set(&if_tx_ds); + plugin_register_data_set(&if_tx_unicast_ds); + plugin_register_data_set(&if_tx_multicast_ds); + plugin_register_data_set(&if_tx_broadcast_ds); + plugin_register_log("vpp", my_log, /* user data */ NULL); + plugin_register_init("vpp", my_init); + plugin_register_read("vpp", my_read); + plugin_register_shutdown("vpp", my_shutdown); + return; +} -- cgit 1.2.3-korg