aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlberto Compagno <acompagn+fdio@cisco.com>2020-02-11 08:54:33 +0100
committerAlberto Compagno <acompagn+fdio@cisco.com>2020-02-18 15:44:20 +0100
commit4590ae6202d7f3fbf932a57e4d9500ce5ac1e473 (patch)
tree57ec4de8d93fc899e45222d1f24f1d9b84c30d5f
parentfbe679d3c25a69ab6b238ebe896ba83e3c8ac6e4 (diff)
[HICN-510] Adding collectd plugins to get telemetry from vpp and hicn-plugin
Change-Id: Idb322dc712b52301c66c5256ad8d1a6a65b503b9 Signed-off-by: Alberto Compagno <acompagn+fdio@cisco.com>
-rw-r--r--CMakeLists.txt3
-rw-r--r--cmake/Modules/BuildMacros.cmake30
-rw-r--r--cmake/Modules/FindCollectd.cmake47
-rw-r--r--cmake/Modules/FindVapiSafe.cmake40
-rw-r--r--docs/source/index.rst3
-rw-r--r--docs/source/telemetry.md116
-rw-r--r--libtransport/src/hicn/transport/core/hicn_vapi.c2
-rw-r--r--scripts/build-packages.sh26
-rw-r--r--telemetry/CMakeLists.txt21
-rw-r--r--telemetry/vpp-collectd/CMakeLists.txt31
-rw-r--r--telemetry/vpp-collectd/cmake/Modules/Packaging.cmake31
-rw-r--r--telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt55
-rw-r--r--telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c416
-rw-r--r--telemetry/vpp-collectd/vpp/CMakeLists.txt42
-rw-r--r--telemetry/vpp-collectd/vpp/vpp.c398
15 files changed, 1249 insertions, 12 deletions
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
+
+<Plugin logfile>
+ LogLevel "info"
+ File "/var/log/collectd.log"
+ Timestamp true
+ PrintSeverity true
+</Plugin>
+
+######################################################################
+# Plugins #
+######################################################################
+LoadPlugin csv
+LoadPlugin rrdtool
+LoadPlugin vpp
+LoadPlugin vpp_hicn
+
+######################################################################
+# Plugin configuration #
+######################################################################
+<Plugin csv>
+ DataDir "/collectd/csv" # the folder under which statistics are written in csv
+ StoreRates true
+</Plugin>
+
+<Plugin rrdtool>
+ DataDir "/collectd/rrd" # the folder under which statistics are written in csv
+</Plugin>
+```
+
+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 <stdlib.h>
+#include <string.h>
+
+#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 <config.h>
+#include <collectd.h>
+#include <common.h>
+#include <plugin.h>
+
+#define counter_t vpp_counter_t
+#include <vapi/hicn.api.vapi.h>
+#include <vapi/vapi_safe.h>
+#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, &timestamp);
+ values[0] = (value_t){.gauge = reply->pkts_interest_count};
+ submit(node_name, pkts_interest_count_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->pkts_data_count};
+ submit(node_name, pkts_data_count_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->pkts_from_cache_count};
+ submit(node_name, pkts_from_cache_count_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->pkts_no_pit_count};
+ submit(node_name, pkts_no_pit_count_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->pit_expired_count};
+ submit(node_name, pit_expired_count_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->cs_expired_count};
+ submit(node_name, cs_expired_count_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->cs_lru_count};
+ submit(node_name, cs_lru_count_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->pkts_drop_no_buf};
+ submit(node_name, pkts_drop_no_buf_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->interests_aggregated};
+ submit(node_name, interests_aggregated_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->interests_retx};
+ submit(node_name, interests_retx_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->interests_hash_collision};
+ submit(node_name, interests_hash_collision_ds.type, NULL, values, 1,
+ &timestamp);
+ values[0] = (value_t){.gauge = reply->pit_entries_count};
+ submit(node_name, pit_entries_count_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->cs_entries_count};
+ submit(node_name, cs_entries_count_ds.type, NULL, values, 1, &timestamp);
+ values[0] = (value_t){.gauge = reply->cs_entries_ntw_count};
+ submit(node_name, cs_entries_ntw_count_ds.type, NULL, values, 1, &timestamp);
+
+ 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, &timestamp);
+ 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, &timestamp);
+ 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, &timestamp);
+ 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, &timestamp);
+
+ 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 <stdlib.h>
+#include <string.h>
+
+#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 <config.h>
+#include <collectd.h>
+#include <common.h>
+#include <plugin.h>
+
+#define counter_t vpp_counter_t
+#include <vpp-api/client/stat_client.h>
+#include <vppinfra/vec.h>
+#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, &timestamp);
+
+ 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, &timestamp);
+
+ 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;
+}