From patchwork Tue Oct 16 15:57:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46898 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5D4831B13B; Tue, 16 Oct 2018 17:57:49 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id CBF961B126 for ; Tue, 16 Oct 2018 17:57:43 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:57:43 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465329" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:57:41 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Kevin Laatz Date: Tue, 16 Oct 2018 16:57:50 +0100 Message-Id: <20181016155802.2067-2-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This commit adds infrastructure to EAL that allows an application to register it's init function with EAL. This allows libraries to be initialized at the end of EAL init. This infrastructure allows libraries that depend on EAL to be initialized as part of EAL init, removing circular dependency issues. Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/bsdapp/eal/eal.c | 18 +++++- lib/librte_eal/common/Makefile | 1 + lib/librte_eal/common/include/rte_param.h | 91 +++++++++++++++++++++++++++++++ lib/librte_eal/common/meson.build | 2 + lib/librte_eal/common/rte_param.c | 47 ++++++++++++++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/linuxapp/eal/eal.c | 18 +++++- lib/librte_eal/rte_eal_version.map | 1 + 9 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 lib/librte_eal/common/include/rte_param.h create mode 100644 lib/librte_eal/common/rte_param.c diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile index d27da3d..7f4fa7e 100644 --- a/lib/librte_eal/bsdapp/eal/Makefile +++ b/lib/librte_eal/bsdapp/eal/Makefile @@ -66,6 +66,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_elem.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_heap.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_mp.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_keepalive.c +SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_param.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_service.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_reciprocal.c diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c index d7ae9d6..27b7afc 100644 --- a/lib/librte_eal/bsdapp/eal/eal.c +++ b/lib/librte_eal/bsdapp/eal/eal.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -414,12 +415,20 @@ eal_parse_args(int argc, char **argv) argvopt = argv; optind = 1; optreset = 1; + opterr = 0; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { - /* getopt is not happy, stop right now */ + /* + * getopt didn't recognise the option, lets parse the + * registered options to see if the flag is valid + */ if (opt == '?') { + ret = rte_param_parse(argv[optind-1]); + if (ret == 0) + continue; + eal_usage(prgname); ret = -1; goto out; @@ -788,6 +797,13 @@ rte_eal_init(int argc, char **argv) rte_eal_mcfg_complete(); + /* Call each registered callback, if enabled */ + ret = rte_param_init(); + if (ret < 0) { + rte_eal_init_alert("Callback failed\n"); + return -1; + } + return fctret; } diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile index cca6882..8def95a 100644 --- a/lib/librte_eal/common/Makefile +++ b/lib/librte_eal/common/Makefile @@ -12,6 +12,7 @@ INC += rte_tailq.h rte_interrupts.h rte_alarm.h INC += rte_string_fns.h rte_version.h INC += rte_eal_memconfig.h rte_malloc_heap.h INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h +INC += rte_param.h INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h INC += rte_malloc.h rte_keepalive.h rte_time.h INC += rte_service.h rte_service_component.h diff --git a/lib/librte_eal/common/include/rte_param.h b/lib/librte_eal/common/include/rte_param.h new file mode 100644 index 0000000..a0635f7 --- /dev/null +++ b/lib/librte_eal/common/include/rte_param.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation. + */ + +#ifndef __INCLUDE_RTE_PARAM_H__ +#define __INCLUDE_RTE_PARAM_H__ + +/** + * @file + * + * This API introduces the ability to register callbacks with EAL. When + * registering a callback, the application also provides an option as part + * of the struct used to register. If the option is passed to EAL when + * running a DPDK application, the relevant callback will be called at the + * end of EAL init. For example, passing --telemetry will make the + * telemetry init be called at the end of EAL init. + * + * The register API can be used to resolve circular dependency issues + * between EAL and the library. The library uses EAL but is also initialized by + * EAL. Hence, EAL depends on the init function of the library. The API + * introduced in rte_param allows us to register the library init with EAL + * (passing a function pointer) and avoid the circular dependency. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*rte_param_cb)(void); + +/* + * Structure containing parameters relating to the function being registered + * with EAL. + */ +struct rte_param { + TAILQ_ENTRY(rte_param) next; /** The next entry in the TAILQ*/ + char *eal_option; /** The EAL option */ + rte_param_cb cb; /** Function pointer of the callback */ + + /** + * Enabled flag, should be 0 by default. This is set when the option + * for the callback is passed to EAL and determines if the callback is + * called or not. + */ + int enabled; +}; + +/** + * @internal Check if the passed option is valid + * + * @param option + * The option to be parsed + * + * @return + * 0 on success + * @return + * -1 on fail + */ +int +rte_param_parse(char *option); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Register a function with EAL. Registering the function will enable the + * function to be called at the end of EAL init. + * + * @param reg_param + * Structure containing various params used to register the function. + */ +void __rte_experimental +rte_param_register(struct rte_param *reg_param); + +/** + * @internal Iterate through the registered params and call the callback for + * the enabled ones. + * + * @return + * 0 on success + * @return + * -1 on fail + */ +int +rte_param_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build index b7fc984..4069e49 100644 --- a/lib/librte_eal/common/meson.build +++ b/lib/librte_eal/common/meson.build @@ -33,6 +33,7 @@ common_sources = files( 'malloc_mp.c', 'rte_keepalive.c', 'rte_malloc.c', + 'rte_param.c', 'rte_reciprocal.c', 'rte_service.c' ) @@ -70,6 +71,7 @@ common_headers = files( 'include/rte_malloc_heap.h', 'include/rte_memory.h', 'include/rte_memzone.h', + 'include/rte_param.h', 'include/rte_pci_dev_feature_defs.h', 'include/rte_pci_dev_features.h', 'include/rte_per_lcore.h', diff --git a/lib/librte_eal/common/rte_param.c b/lib/librte_eal/common/rte_param.c new file mode 100644 index 0000000..317e371 --- /dev/null +++ b/lib/librte_eal/common/rte_param.c @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation. + */ + +#include +#include + +#include +#include + +TAILQ_HEAD(rte_param_list, rte_param); + +struct rte_param_list rte_param_list = + TAILQ_HEAD_INITIALIZER(rte_param_list); + +static struct rte_param *param; + +int +rte_param_parse(char *option) +{ + /* Check if the option is in the registered inits */ + TAILQ_FOREACH(param, &rte_param_list, next) { + if (strcmp(option, param->eal_option) == 0) { + param->enabled = 1; + return 0; + } + } + + return -1; +} + +void __rte_experimental +rte_param_register(struct rte_param *reg_param) +{ + TAILQ_INSERT_HEAD(&rte_param_list, reg_param, next); +} + +int +rte_param_init(void) +{ + TAILQ_FOREACH(param, &rte_param_list, next) { + if (param->enabled) + param->cb(); + } + + return 0; +} diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile index 5c16bc4..2bf8b24 100644 --- a/lib/librte_eal/linuxapp/eal/Makefile +++ b/lib/librte_eal/linuxapp/eal/Makefile @@ -74,6 +74,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_elem.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_heap.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_mp.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_keepalive.c +SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_param.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_service.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_reciprocal.c diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c index 4a55d3b..e28562b 100644 --- a/lib/librte_eal/linuxapp/eal/eal.c +++ b/lib/librte_eal/linuxapp/eal/eal.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "eal_private.h" #include "eal_thread.h" @@ -600,12 +601,20 @@ eal_parse_args(int argc, char **argv) argvopt = argv; optind = 1; + opterr = 0; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { - /* getopt is not happy, stop right now */ + /* + * getopt didn't recognise the option, lets parse the + * registered options to see if the flag is valid + */ if (opt == '?') { + ret = rte_param_parse(argv[optind-1]); + if (ret == 0) + continue; + eal_usage(prgname); ret = -1; goto out; @@ -1071,6 +1080,13 @@ rte_eal_init(int argc, char **argv) rte_eal_mcfg_complete(); + /* Call each registered callback, if enabled */ + ret = rte_param_init(); + if (ret < 0) { + rte_eal_init_alert("Callback failed\n"); + return -1; + } + return fctret; } diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map index 73282bb..ccfb8a2 100644 --- a/lib/librte_eal/rte_eal_version.map +++ b/lib/librte_eal/rte_eal_version.map @@ -341,6 +341,7 @@ EXPERIMENTAL { rte_mp_request_sync; rte_mp_request_async; rte_mp_sendmsg; + rte_param_register; rte_service_lcore_attr_get; rte_service_lcore_attr_reset_all; rte_service_may_be_active; From patchwork Tue Oct 16 15:57:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46899 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 8F2B71B144; Tue, 16 Oct 2018 17:57:51 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 2BF5F1B13E for ; Tue, 16 Oct 2018 17:57:46 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:57:45 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465337" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:57:43 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Kevin Laatz Date: Tue, 16 Oct 2018 16:57:51 +0100 Message-Id: <20181016155802.2067-3-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 02/13] eal: make get runtime dir function public X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch makes the eal_get_runtime_dir() API public so it can be used from outside EAL. Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- Note: I have added rte_eal_get_runtime_dir() to the 18.11 version in the .map file instead of the EXPERIMENTAL section as the function already existed, we just renamed it and made it public. --- lib/librte_eal/bsdapp/eal/eal.c | 2 +- lib/librte_eal/common/eal_filesystem.h | 14 +++++++------- lib/librte_eal/common/include/rte_eal.h | 9 +++++++++ lib/librte_eal/linuxapp/eal/eal.c | 2 +- lib/librte_eal/rte_eal_version.map | 1 + 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c index 27b7afc..ee94bc1 100644 --- a/lib/librte_eal/bsdapp/eal/eal.c +++ b/lib/librte_eal/bsdapp/eal/eal.c @@ -142,7 +142,7 @@ eal_create_runtime_dir(void) } const char * -eal_get_runtime_dir(void) +rte_eal_get_runtime_dir(void) { return runtime_dir; } diff --git a/lib/librte_eal/common/eal_filesystem.h b/lib/librte_eal/common/eal_filesystem.h index de05feb..f82b4fe 100644 --- a/lib/librte_eal/common/eal_filesystem.h +++ b/lib/librte_eal/common/eal_filesystem.h @@ -27,7 +27,7 @@ eal_create_runtime_dir(void); /* returns runtime dir */ const char * -eal_get_runtime_dir(void); +rte_eal_get_runtime_dir(void); #define RUNTIME_CONFIG_FNAME "config" static inline const char * @@ -35,7 +35,7 @@ eal_runtime_config_path(void) { static char buffer[PATH_MAX]; /* static so auto-zeroed */ - snprintf(buffer, sizeof(buffer) - 1, "%s/%s", eal_get_runtime_dir(), + snprintf(buffer, sizeof(buffer) - 1, "%s/%s", rte_eal_get_runtime_dir(), RUNTIME_CONFIG_FNAME); return buffer; } @@ -47,7 +47,7 @@ eal_mp_socket_path(void) { static char buffer[PATH_MAX]; /* static so auto-zeroed */ - snprintf(buffer, sizeof(buffer) - 1, "%s/%s", eal_get_runtime_dir(), + snprintf(buffer, sizeof(buffer) - 1, "%s/%s", rte_eal_get_runtime_dir(), MP_SOCKET_FNAME); return buffer; } @@ -55,7 +55,7 @@ eal_mp_socket_path(void) #define FBARRAY_NAME_FMT "%s/fbarray_%s" static inline const char * eal_get_fbarray_path(char *buffer, size_t buflen, const char *name) { - snprintf(buffer, buflen, FBARRAY_NAME_FMT, eal_get_runtime_dir(), name); + snprintf(buffer, buflen, FBARRAY_NAME_FMT, rte_eal_get_runtime_dir(), name); return buffer; } @@ -66,7 +66,7 @@ eal_hugepage_info_path(void) { static char buffer[PATH_MAX]; /* static so auto-zeroed */ - snprintf(buffer, sizeof(buffer) - 1, "%s/%s", eal_get_runtime_dir(), + snprintf(buffer, sizeof(buffer) - 1, "%s/%s", rte_eal_get_runtime_dir(), HUGEPAGE_INFO_FNAME); return buffer; } @@ -78,7 +78,7 @@ eal_hugepage_data_path(void) { static char buffer[PATH_MAX]; /* static so auto-zeroed */ - snprintf(buffer, sizeof(buffer) - 1, "%s/%s", eal_get_runtime_dir(), + snprintf(buffer, sizeof(buffer) - 1, "%s/%s", rte_eal_get_runtime_dir(), HUGEPAGE_DATA_FNAME); return buffer; } @@ -99,7 +99,7 @@ eal_get_hugefile_path(char *buffer, size_t buflen, const char *hugedir, int f_id static inline const char * eal_get_hugefile_lock_path(char *buffer, size_t buflen, int f_id) { - snprintf(buffer, buflen, HUGEFILE_LOCK_FMT, eal_get_runtime_dir(), + snprintf(buffer, buflen, HUGEFILE_LOCK_FMT, rte_eal_get_runtime_dir(), f_id); buffer[buflen - 1] = '\0'; return buffer; diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h index e114dcb..e19f74e 100644 --- a/lib/librte_eal/common/include/rte_eal.h +++ b/lib/librte_eal/common/include/rte_eal.h @@ -498,6 +498,15 @@ enum rte_iova_mode rte_eal_iova_mode(void); const char * rte_eal_mbuf_user_pool_ops(void); +/** + * Get the runtime directory of DPDK + * + * @return + * The runtime directory path of DPDK + */ +const char * +rte_eal_get_runtime_dir(void); + #ifdef __cplusplus } #endif diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c index e28562b..e926f67 100644 --- a/lib/librte_eal/linuxapp/eal/eal.c +++ b/lib/librte_eal/linuxapp/eal/eal.c @@ -150,7 +150,7 @@ eal_create_runtime_dir(void) } const char * -eal_get_runtime_dir(void) +rte_eal_get_runtime_dir(void) { return runtime_dir; } diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map index ccfb8a2..2de7197 100644 --- a/lib/librte_eal/rte_eal_version.map +++ b/lib/librte_eal/rte_eal_version.map @@ -265,6 +265,7 @@ DPDK_18.08 { DPDK_18.11 { global: + rte_eal_get_runtime_dir; rte_strscpy; } DPDK_18.08; From patchwork Tue Oct 16 15:57:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46900 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id CD51F1B14D; Tue, 16 Oct 2018 17:57:57 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id E823A1B12E for ; Tue, 16 Oct 2018 17:57:48 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:57:48 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465342" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:57:46 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:57:52 +0100 Message-Id: <20181016155802.2067-4-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 03/13] telemetry: initial telemetry infrastructure X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch adds the infrastructure and initial code for the telemetry library. The telemetry init is registered with eal_init(). We can then check to see if --telemetry was passed as an eal option. If --telemetry was parsed, then we call telemetry init at the end of eal init. Control threads are used to get CPU cycles for telemetry, which are configured in this patch also. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- config/common_base | 5 ++ lib/Makefile | 2 + lib/librte_telemetry/Makefile | 28 ++++++ lib/librte_telemetry/meson.build | 7 ++ lib/librte_telemetry/rte_telemetry.c | 117 +++++++++++++++++++++++++ lib/librte_telemetry/rte_telemetry.h | 36 ++++++++ lib/librte_telemetry/rte_telemetry_internal.h | 32 +++++++ lib/librte_telemetry/rte_telemetry_version.map | 6 ++ lib/meson.build | 2 +- mk/rte.app.mk | 1 + 10 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 lib/librte_telemetry/Makefile create mode 100644 lib/librte_telemetry/meson.build create mode 100644 lib/librte_telemetry/rte_telemetry.c create mode 100644 lib/librte_telemetry/rte_telemetry.h create mode 100644 lib/librte_telemetry/rte_telemetry_internal.h create mode 100644 lib/librte_telemetry/rte_telemetry_version.map diff --git a/config/common_base b/config/common_base index acc5211..f561eb4 100644 --- a/config/common_base +++ b/config/common_base @@ -722,6 +722,11 @@ CONFIG_RTE_LIBRTE_HASH=y CONFIG_RTE_LIBRTE_HASH_DEBUG=n # +# Compile librte_telemetry +# +CONFIG_RTE_LIBRTE_TELEMETRY=n + +# # Compile librte_efd # CONFIG_RTE_LIBRTE_EFD=y diff --git a/lib/Makefile b/lib/Makefile index 8c83942..2b446c6 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -105,6 +105,8 @@ DEPDIRS-librte_gso := librte_eal librte_mbuf librte_ethdev librte_net DEPDIRS-librte_gso += librte_mempool DIRS-$(CONFIG_RTE_LIBRTE_BPF) += librte_bpf DEPDIRS-librte_bpf := librte_eal librte_mempool librte_mbuf librte_ethdev +DIRS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += librte_telemetry +DEPDIRS-librte_telemetry := librte_eal librte_metrics librte_ethdev ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni diff --git a/lib/librte_telemetry/Makefile b/lib/librte_telemetry/Makefile new file mode 100644 index 0000000..0d61361 --- /dev/null +++ b/lib/librte_telemetry/Makefile @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# library name +LIB = librte_telemetry.a + +CFLAGS += -O3 +CFLAGS += -I$(SRCDIR) +CFLAGS += -DALLOW_EXPERIMENTAL_API + +LDLIBS += -lrte_eal -lrte_ethdev +LDLIBS += -lrte_metrics +LDLIBS += -lpthread +LDLIBS += -ljansson + +EXPORT_MAP := rte_telemetry_version.map + +LIBABIVER := 1 + +# library source files +SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) := rte_telemetry.c + +# export include files +SYMLINK-$(CONFIG_RTE_LIBRTE_TELEMETRY)-include := rte_telemetry.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build new file mode 100644 index 0000000..7716076 --- /dev/null +++ b/lib/librte_telemetry/meson.build @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +sources = files('rte_telemetry.c') +headers = files('rte_telemetry.h', 'rte_telemetry_internal.h') +deps += ['metrics', 'ethdev'] +cflags += '-DALLOW_EXPERIMENTAL_API' diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c new file mode 100644 index 0000000..b31b57d --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry.c @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include +#include + +#include +#include +#include +#include + +#include "rte_telemetry.h" +#include "rte_telemetry_internal.h" + +#define SLEEP_TIME 10 + +static telemetry_impl *static_telemetry; + +static int32_t +rte_telemetry_run(void *userdata) +{ + struct telemetry_impl *telemetry = userdata; + + if (telemetry == NULL) { + TELEMETRY_LOG_WARN("TELEMETRY could not be initialised"); + return -1; + } + + return 0; +} + +static void +*rte_telemetry_run_thread_func(void *userdata) +{ + int ret; + struct telemetry_impl *telemetry = userdata; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("%s passed a NULL instance", __func__); + pthread_exit(0); + } + + while (telemetry->thread_status) { + rte_telemetry_run(telemetry); + ret = usleep(SLEEP_TIME); + if (ret < 0) + TELEMETRY_LOG_ERR("Calling thread could not be put to sleep"); + } + pthread_exit(0); +} + +int32_t +rte_telemetry_init() +{ + int ret; + pthread_attr_t attr; + const char *telemetry_ctrl_thread = "telemetry"; + + if (static_telemetry) { + TELEMETRY_LOG_WARN("TELEMETRY structure already initialised"); + return -EALREADY; + } + + static_telemetry = calloc(1, sizeof(struct telemetry_impl)); + if (static_telemetry == NULL) { + TELEMETRY_LOG_ERR("Memory could not be allocated"); + return -ENOMEM; + } + + static_telemetry->socket_id = rte_socket_id(); + rte_metrics_init(static_telemetry->socket_id); + pthread_attr_init(&attr); + ret = rte_ctrl_thread_create(&static_telemetry->thread_id, + telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func, + (void *)static_telemetry); + static_telemetry->thread_status = 1; + + if (ret < 0) { + ret = rte_telemetry_cleanup(); + if (ret < 0) + TELEMETRY_LOG_ERR("TELEMETRY cleanup failed"); + return -EPERM; + } + + return 0; +} + +int32_t +rte_telemetry_cleanup(void) +{ + struct telemetry_impl *telemetry = static_telemetry; + telemetry->thread_status = 0; + pthread_join(telemetry->thread_id, NULL); + free(telemetry); + static_telemetry = NULL; + return 0; +} + +int telemetry_log_level; +RTE_INIT(rte_telemetry_register); + +static struct rte_param param = { + .eal_option = "--telemetry", + .cb = &rte_telemetry_init, + .enabled = 0 +}; + +static void +rte_telemetry_register(void) +{ + telemetry_log_level = rte_log_register("lib.telemetry"); + if (telemetry_log_level >= 0) + rte_log_set_level(telemetry_log_level, RTE_LOG_ERR); + + rte_param_register(¶m); +} diff --git a/lib/librte_telemetry/rte_telemetry.h b/lib/librte_telemetry/rte_telemetry.h new file mode 100644 index 0000000..d3b0d8d --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include + +#ifndef _RTE_TELEMETRY_H_ +#define _RTE_TELEMETRY_H_ + +/** + * Initialize Telemetry + * + * @return + * 0 on successful initialisation. + * @return + * -ENOMEM on memory allocation error + * @return + * -EPERM on unknown error failure + * @return + * -EALREADY if Telemetry is already initialised. + */ +int32_t +rte_telemetry_init(void); + +/** + * Clean up and free memory. + * + * @return + * 0 on success + * @return + * -EPERM on failure + */ +int32_t +rte_telemetry_cleanup(void); + +#endif diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h new file mode 100644 index 0000000..4e810a8 --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_internal.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include + +#ifndef _RTE_TELEMETRY_INTERNAL_H_ +#define _RTE_TELEMETRY_INTERNAL_H_ + +/* Logging Macros */ +extern int telemetry_log_level; + +#define TELEMETRY_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ##level, telemetry_log_level, "%s(): "fmt "\n", \ + __func__, ##args) + +#define TELEMETRY_LOG_ERR(fmt, args...) \ + TELEMETRY_LOG(ERR, fmt, ## args) + +#define TELEMETRY_LOG_WARN(fmt, args...) \ + TELEMETRY_LOG(WARNING, fmt, ## args) + +#define TELEMETRY_LOG_INFO(fmt, args...) \ + TELEMETRY_LOG(INFO, fmt, ## args) + +typedef struct telemetry_impl { + pthread_t thread_id; + int thread_status; + uint32_t socket_id; +} telemetry_impl; + +#endif diff --git a/lib/librte_telemetry/rte_telemetry_version.map b/lib/librte_telemetry/rte_telemetry_version.map new file mode 100644 index 0000000..992d227 --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_version.map @@ -0,0 +1,6 @@ +DPDK_18.11 { + global: + + rte_telemetry_init; + local: *; +}; diff --git a/lib/meson.build b/lib/meson.build index 3acc67e..b5612ad 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -24,7 +24,7 @@ libraries = [ 'compat', # just a header, used for versioning # add pkt framework libs which use other libs from above 'port', 'table', 'pipeline', # flow_classify lib depends on pkt framework table lib - 'flow_classify', 'bpf'] + 'flow_classify', 'bpf', 'telemetry'] default_cflags = machine_args if cc.has_argument('-Wno-format-truncation') diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 32579e4..35594b9 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -80,6 +80,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY) += -lrte_security _LDLIBS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV) += -lrte_compressdev _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += -lrte_eventdev _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV) += -lrte_rawdev +_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -lrte_metrics -lrte_telemetry _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER) += -lrte_timer _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += -lrte_mempool _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING) += -lrte_mempool_ring From patchwork Tue Oct 16 15:57:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46901 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B410C1B150; Tue, 16 Oct 2018 17:57:59 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id BFCF21B148 for ; Tue, 16 Oct 2018 17:57:51 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:57:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465356" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:57:48 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:57:53 +0100 Message-Id: <20181016155802.2067-5-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 04/13] telemetry: add initial connection socket X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch adds the telemetry UNIX socket. It is used to allow connections from external clients. On the initial connection from a client, ethdev stats are registered in the metrics library, to allow for their retrieval at a later stage. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- lib/librte_telemetry/rte_telemetry.c | 226 ++++++++++++++++++++++++++ lib/librte_telemetry/rte_telemetry_internal.h | 4 + 2 files changed, 230 insertions(+) diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c index b31b57d..8d5754e 100644 --- a/lib/librte_telemetry/rte_telemetry.c +++ b/lib/librte_telemetry/rte_telemetry.c @@ -3,23 +3,163 @@ */ #include +#include #include +#include +#include #include #include #include #include +#include #include "rte_telemetry.h" #include "rte_telemetry_internal.h" +#define BUF_SIZE 1024 #define SLEEP_TIME 10 static telemetry_impl *static_telemetry; +static void +rte_telemetry_get_runtime_dir(char *socket_path, size_t size) +{ + snprintf(socket_path, size, "%s/telemetry", rte_eal_get_runtime_dir()); +} + +int32_t +rte_telemetry_is_port_active(int port_id) +{ + int ret; + + ret = rte_eth_find_next(port_id); + if (ret == port_id) + return 1; + + TELEMETRY_LOG_ERR("port_id: %d is invalid, not active", + port_id); + return 0; +} + +static int32_t +rte_telemetry_reg_ethdev_to_metrics(uint16_t port_id) +{ + int ret, num_xstats, ret_val, i; + struct rte_eth_xstat *eth_xstats = NULL; + struct rte_eth_xstat_name *eth_xstats_names = NULL; + + if (!rte_eth_dev_is_valid_port(port_id)) { + TELEMETRY_LOG_ERR("port_id: %d is invalid", port_id); + return -EINVAL; + } + + num_xstats = rte_eth_xstats_get(port_id, NULL, 0); + if (num_xstats < 0) { + TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) failed: %d", + port_id, num_xstats); + return -EPERM; + } + + eth_xstats = malloc(sizeof(struct rte_eth_xstat) * num_xstats); + if (eth_xstats == NULL) { + TELEMETRY_LOG_ERR("Failed to malloc memory for xstats"); + return -ENOMEM; + } + + ret = rte_eth_xstats_get(port_id, eth_xstats, num_xstats); + const char *xstats_names[num_xstats]; + eth_xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * num_xstats); + if (ret < 0 || ret > num_xstats) { + TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) len%i failed: %d", + port_id, num_xstats, ret); + ret_val = -EPERM; + goto free_xstats; + } + + if (eth_xstats_names == NULL) { + TELEMETRY_LOG_ERR("Failed to malloc memory for xstats_names"); + ret_val = -ENOMEM; + goto free_xstats; + } + + ret = rte_eth_xstats_get_names(port_id, eth_xstats_names, num_xstats); + if (ret < 0 || ret > num_xstats) { + TELEMETRY_LOG_ERR("rte_eth_xstats_get_names(%u) len%i failed: %d", + port_id, num_xstats, ret); + ret_val = -EPERM; + goto free_xstats; + } + + for (i = 0; i < num_xstats; i++) + xstats_names[i] = eth_xstats_names[eth_xstats[i].id].name; + + ret_val = rte_metrics_reg_names(xstats_names, num_xstats); + if (ret_val < 0) { + TELEMETRY_LOG_ERR("rte_metrics_reg_names failed - metrics may already be registered"); + ret_val = -1; + goto free_xstats; + } + + goto free_xstats; + +free_xstats: + free(eth_xstats); + free(eth_xstats_names); + return ret_val; +} + +static int32_t +rte_telemetry_initial_accept(struct telemetry_impl *telemetry) +{ + uint16_t pid; + + RTE_ETH_FOREACH_DEV(pid) { + telemetry->reg_index = + rte_telemetry_reg_ethdev_to_metrics(pid); + break; + } + + if (telemetry->reg_index < 0) { + TELEMETRY_LOG_ERR("Failed to register ethdev metrics"); + return -1; + } + + telemetry->metrics_register_done = 1; + + return 0; +} + +static int32_t +rte_telemetry_accept_new_client(struct telemetry_impl *telemetry) +{ + int ret; + + if (telemetry->accept_fd == 0 || telemetry->accept_fd == -1) { + ret = listen(telemetry->server_fd, 1); + if (ret < 0) { + TELEMETRY_LOG_ERR("Listening error with server fd"); + return -1; + } + telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL); + + if (telemetry->accept_fd > 0 && + telemetry->metrics_register_done == 0) { + ret = rte_telemetry_initial_accept(telemetry); + if (ret < 0) { + TELEMETRY_LOG_ERR("Failed to run initial configurations/tests"); + return -1; + } + } + } + + return 0; +} + static int32_t rte_telemetry_run(void *userdata) { + int ret; struct telemetry_impl *telemetry = userdata; if (telemetry == NULL) { @@ -27,6 +167,12 @@ rte_telemetry_run(void *userdata) return -1; } + ret = rte_telemetry_accept_new_client(telemetry); + if (ret < 0) { + TELEMETRY_LOG_ERR("Accept and read new client failed"); + return -1; + } + return 0; } @@ -50,6 +196,68 @@ static void pthread_exit(0); } +static int32_t +rte_telemetry_set_socket_nonblock(int fd) +{ + int flags; + + if (fd < 0) { + TELEMETRY_LOG_ERR("Invalid fd provided"); + return -1; + } + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) + flags = 0; + + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} + +static int32_t +rte_telemetry_create_socket(struct telemetry_impl *telemetry) +{ + int ret; + struct sockaddr_un addr = {0}; + char socket_path[BUF_SIZE]; + + if (telemetry == NULL) + return -1; + + telemetry->server_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (telemetry->server_fd == -1) { + TELEMETRY_LOG_ERR("Failed to open socket"); + return -1; + } + + ret = rte_telemetry_set_socket_nonblock(telemetry->server_fd); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK"); + goto close_socket; + } + + addr.sun_family = AF_UNIX; + rte_telemetry_get_runtime_dir(socket_path, sizeof(socket_path)); + strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path)); + unlink(socket_path); + + if (bind(telemetry->server_fd, (struct sockaddr *)&addr, + sizeof(addr)) < 0) { + TELEMETRY_LOG_ERR("Socket binding error"); + goto close_socket; + } + + return 0; + +close_socket: + if (close(telemetry->server_fd) < 0) { + TELEMETRY_LOG_ERR("Close TELEMETRY socket failed"); + free(telemetry); + return -EPERM; + } + + return -1; +} + int32_t rte_telemetry_init() { @@ -70,6 +278,14 @@ rte_telemetry_init() static_telemetry->socket_id = rte_socket_id(); rte_metrics_init(static_telemetry->socket_id); + ret = rte_telemetry_create_socket(static_telemetry); + if (ret < 0) { + ret = rte_telemetry_cleanup(); + if (ret < 0) + TELEMETRY_LOG_ERR("TELEMETRY cleanup failed"); + return -EPERM; + } + pthread_attr_init(&attr); ret = rte_ctrl_thread_create(&static_telemetry->thread_id, telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func, @@ -89,11 +305,21 @@ rte_telemetry_init() int32_t rte_telemetry_cleanup(void) { + int ret; struct telemetry_impl *telemetry = static_telemetry; + + ret = close(telemetry->server_fd); + if (ret < 0) { + TELEMETRY_LOG_ERR("Close TELEMETRY socket failed"); + free(telemetry); + return -EPERM; + } + telemetry->thread_status = 0; pthread_join(telemetry->thread_id, NULL); free(telemetry); static_telemetry = NULL; + return 0; } diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h index 4e810a8..569d56a 100644 --- a/lib/librte_telemetry/rte_telemetry_internal.h +++ b/lib/librte_telemetry/rte_telemetry_internal.h @@ -24,9 +24,13 @@ extern int telemetry_log_level; TELEMETRY_LOG(INFO, fmt, ## args) typedef struct telemetry_impl { + int accept_fd; + int server_fd; pthread_t thread_id; int thread_status; uint32_t socket_id; + int reg_index; + int metrics_register_done; } telemetry_impl; #endif From patchwork Tue Oct 16 15:57:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46902 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 10E861B157; Tue, 16 Oct 2018 17:58:02 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 8755F1B14B for ; Tue, 16 Oct 2018 17:57:54 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:57:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465366" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:57:51 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:57:54 +0100 Message-Id: <20181016155802.2067-6-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 05/13] telemetry: add client feature and sockets X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch introduces clients to the telemetry API. When a client makes a connection through the initial telemetry socket, they can send a message through the socket to be parsed. Register messages are expected through this socket, to enable clients to register and have a client socket setup for future communications. A TAILQ is used to store all clients information. Using this, the client sockets are polled for messages, which will later be parsed and dealt with accordingly. Functionality that make use of the client sockets were introduced in this patch also, such as writing to client sockets, and sending error responses. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- lib/librte_telemetry/meson.build | 2 + lib/librte_telemetry/rte_telemetry.c | 369 +++++++++++++++++++++++++- lib/librte_telemetry/rte_telemetry_internal.h | 25 ++ mk/rte.app.mk | 2 +- 4 files changed, 394 insertions(+), 4 deletions(-) diff --git a/lib/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build index 7716076..0ccfa36 100644 --- a/lib/librte_telemetry/meson.build +++ b/lib/librte_telemetry/meson.build @@ -5,3 +5,5 @@ sources = files('rte_telemetry.c') headers = files('rte_telemetry.h', 'rte_telemetry_internal.h') deps += ['metrics', 'ethdev'] cflags += '-DALLOW_EXPERIMENTAL_API' +jansson = cc.find_library('jansson', required: true) +ext_deps += jansson diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c index 8d5754e..9ed8ea6 100644 --- a/lib/librte_telemetry/rte_telemetry.c +++ b/lib/librte_telemetry/rte_telemetry.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,7 @@ #include "rte_telemetry_internal.h" #define BUF_SIZE 1024 +#define ACTION_POST 1 #define SLEEP_TIME 10 static telemetry_impl *static_telemetry; @@ -39,6 +41,91 @@ rte_telemetry_is_port_active(int port_id) TELEMETRY_LOG_ERR("port_id: %d is invalid, not active", port_id); + + return 0; +} + +int32_t +rte_telemetry_write_to_socket(struct telemetry_impl *telemetry, + const char *json_string) +{ + int ret; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Could not initialise TELEMETRY_API"); + return -1; + } + + if (telemetry->request_client == NULL) { + TELEMETRY_LOG_ERR("No client has been chosen to write to"); + return -1; + } + + if (json_string == NULL) { + TELEMETRY_LOG_ERR("Invalid JSON string!"); + return -1; + } + + ret = send(telemetry->request_client->fd, + json_string, strlen(json_string), 0); + if (ret < 0) { + TELEMETRY_LOG_ERR("Failed to write to socket for client: %s", + telemetry->request_client->file_path); + return -1; + } + + return 0; +} + +int32_t +rte_telemetry_send_error_response(struct telemetry_impl *telemetry, + int error_type) +{ + int ret; + const char *status_code, *json_buffer; + json_t *root; + + if (error_type == -EPERM) + status_code = "Status Error: Unknown"; + else if (error_type == -EINVAL) + status_code = "Status Error: Invalid Argument 404"; + else if (error_type == -ENOMEM) + status_code = "Status Error: Memory Allocation Error"; + else { + TELEMETRY_LOG_ERR("Invalid error type"); + return -EINVAL; + } + + root = json_object(); + + if (root == NULL) { + TELEMETRY_LOG_ERR("Could not create root JSON object"); + return -EPERM; + } + + ret = json_object_set_new(root, "status_code", json_string(status_code)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Status code field cannot be set"); + json_decref(root); + return -EPERM; + } + + ret = json_object_set_new(root, "data", json_null()); + if (ret < 0) { + TELEMETRY_LOG_ERR("Data field cannot be set"); + json_decref(root); + return -EPERM; + } + + json_buffer = json_dumps(root, JSON_INDENT(2)); + json_decref(root); + + ret = rte_telemetry_write_to_socket(telemetry, json_buffer); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not write to socket"); + return -EPERM; + } + return 0; } @@ -115,8 +202,7 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry) uint16_t pid; RTE_ETH_FOREACH_DEV(pid) { - telemetry->reg_index = - rte_telemetry_reg_ethdev_to_metrics(pid); + telemetry->reg_index = rte_telemetry_reg_ethdev_to_metrics(pid); break; } @@ -131,6 +217,40 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry) } static int32_t +rte_telemetry_read_client(struct telemetry_impl *telemetry) +{ + char buf[BUF_SIZE]; + int ret, buffer_read = 0; + + buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1); + buf[buffer_read] = '\0'; + + if (buffer_read == -1) { + TELEMETRY_LOG_ERR("Read error"); + return -1; + } else if (buffer_read == 0) { + goto close_socket; + } else { + ret = rte_telemetry_parse_client_message(telemetry, buf); + if (ret < 0) + TELEMETRY_LOG_WARN("Parse message failed"); + goto close_socket; + } + + return 0; + +close_socket: + if (close(telemetry->accept_fd) < 0) { + TELEMETRY_LOG_ERR("Close TELEMETRY socket failed"); + free(telemetry); + return -EPERM; + } + telemetry->accept_fd = 0; + + return 0; +} + +static int32_t rte_telemetry_accept_new_client(struct telemetry_impl *telemetry) { int ret; @@ -141,8 +261,8 @@ rte_telemetry_accept_new_client(struct telemetry_impl *telemetry) TELEMETRY_LOG_ERR("Listening error with server fd"); return -1; } - telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL); + telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL); if (telemetry->accept_fd > 0 && telemetry->metrics_register_done == 0) { ret = rte_telemetry_initial_accept(telemetry); @@ -151,6 +271,30 @@ rte_telemetry_accept_new_client(struct telemetry_impl *telemetry) return -1; } } + } else { + ret = rte_telemetry_read_client(telemetry); + if (ret < 0) { + TELEMETRY_LOG_ERR("Failed to read socket buffer"); + return -1; + } + } + + return 0; +} + +static int32_t +rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry) +{ + telemetry_client *client; + char client_buf[BUF_SIZE]; + int bytes; + + TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) { + bytes = read(client->fd, client_buf, BUF_SIZE-1); + client_buf[bytes] = '\0'; + + if (bytes > 0) + telemetry->request_client = client; } return 0; @@ -173,6 +317,12 @@ rte_telemetry_run(void *userdata) return -1; } + ret = rte_telemetry_read_client_sockets(telemetry); + if (ret < 0) { + TELEMETRY_LOG_ERR("Client socket read failed"); + return -1; + } + return 0; } @@ -285,6 +435,7 @@ rte_telemetry_init() TELEMETRY_LOG_ERR("TELEMETRY cleanup failed"); return -EPERM; } + TAILQ_INIT(&static_telemetry->client_list_head); pthread_attr_init(&attr); ret = rte_ctrl_thread_create(&static_telemetry->thread_id, @@ -302,11 +453,39 @@ rte_telemetry_init() return 0; } +static int32_t +rte_telemetry_client_cleanup(struct telemetry_client *client) +{ + int ret; + + ret = close(client->fd); + free(client->file_path); + free(client); + + if (ret < 0) { + TELEMETRY_LOG_ERR("Close client socket failed"); + return -EPERM; + } + + return 0; +} + int32_t rte_telemetry_cleanup(void) { int ret; struct telemetry_impl *telemetry = static_telemetry; + telemetry_client *client, *temp_client; + + TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list, + temp_client) { + TAILQ_REMOVE(&telemetry->client_list_head, client, client_list); + ret = rte_telemetry_client_cleanup(client); + if (ret < 0) { + TELEMETRY_LOG_ERR("Client cleanup failed"); + return -EPERM; + } + } ret = close(telemetry->server_fd); if (ret < 0) { @@ -323,6 +502,190 @@ rte_telemetry_cleanup(void) return 0; } +int32_t +rte_telemetry_unregister_client(struct telemetry_impl *telemetry, + const char *client_path) +{ + int ret; + telemetry_client *client, *temp_client; + + if (telemetry == NULL) { + TELEMETRY_LOG_WARN("TELEMETRY is not initialised"); + return -ENODEV; + } + + if (client_path == NULL) { + TELEMETRY_LOG_ERR("Invalid client path"); + goto einval_fail; + } + + if (TAILQ_EMPTY(&telemetry->client_list_head)) { + TELEMETRY_LOG_ERR("There are no clients currently registered"); + return -EPERM; + } + + TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list, + temp_client) { + if (strcmp(client_path, client->file_path) == 0) { + TAILQ_REMOVE(&telemetry->client_list_head, client, + client_list); + ret = rte_telemetry_client_cleanup(client); + + if (ret < 0) { + TELEMETRY_LOG_ERR("Client cleanup failed"); + return -EPERM; + } + + return 0; + } + } + + TELEMETRY_LOG_WARN("Couldn't find client, possibly not registered yet."); + return -1; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -EINVAL; +} + +int32_t +rte_telemetry_register_client(struct telemetry_impl *telemetry, + const char *client_path) +{ + int ret, fd; + struct sockaddr_un addrs = {0}; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Could not initialize TELEMETRY API"); + return -ENODEV; + } + + if (client_path == NULL) { + TELEMETRY_LOG_ERR("Invalid client path"); + return -EINVAL; + } + + telemetry_client *client; + TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) { + if (strcmp(client_path, client->file_path) == 0) { + TELEMETRY_LOG_WARN("'%s' already registered", + client_path); + return -EINVAL; + } + } + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + TELEMETRY_LOG_ERR("Client socket error"); + return -EACCES; + } + ret = rte_telemetry_set_socket_nonblock(fd); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK"); + return -EPERM; + } + + addrs.sun_family = AF_UNIX; + strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path)); + telemetry_client *new_client = malloc(sizeof(telemetry_client)); + new_client->file_path = strdup(client_path); + new_client->fd = fd; + + if (connect(fd, (struct sockaddr *)&addrs, sizeof(addrs)) == -1) { + TELEMETRY_LOG_ERR("TELEMETRY client connect to %s didn't work", + client_path); + ret = rte_telemetry_client_cleanup(new_client); + if (ret < 0) { + TELEMETRY_LOG_ERR("Client cleanup failed"); + return -EPERM; + } + return -EINVAL; + } + + TAILQ_INSERT_HEAD(&telemetry->client_list_head, new_client, client_list); + + return 0; +} + +int32_t +rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf) +{ + int ret, action_int; + json_error_t error; + json_t *root = json_loads(buf, 0, &error); + + if (root == NULL) { + TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s", + error.text); + goto fail; + } else if (!json_is_object(root)) { + TELEMETRY_LOG_WARN("JSON Request is not a JSON object"); + json_decref(root); + goto fail; + } + + json_t *action = json_object_get(root, "action"); + if (action == NULL) { + TELEMETRY_LOG_WARN("Request does not have action field"); + goto fail; + } else if (!json_is_integer(action)) { + TELEMETRY_LOG_WARN("Action value is not an integer"); + goto fail; + } + + json_t *command = json_object_get(root, "command"); + if (command == NULL) { + TELEMETRY_LOG_WARN("Request does not have command field"); + goto fail; + } else if (!json_is_string(command)) { + TELEMETRY_LOG_WARN("Command value is not a string"); + goto fail; + } + + action_int = json_integer_value(action); + if (action_int != ACTION_POST) { + TELEMETRY_LOG_WARN("Invalid action code"); + goto fail; + } + + if (strcmp(json_string_value(command), "clients") != 0) { + TELEMETRY_LOG_WARN("Invalid command"); + goto fail; + } + + json_t *data = json_object_get(root, "data"); + if (data == NULL) { + TELEMETRY_LOG_WARN("Request does not have data field"); + goto fail; + } + + json_t *client_path = json_object_get(data, "client_path"); + if (client_path == NULL) { + TELEMETRY_LOG_WARN("Request does not have client_path field"); + goto fail; + } + + if (!json_is_string(client_path)) { + TELEMETRY_LOG_WARN("Client_path value is not a string"); + goto fail; + } + + ret = rte_telemetry_register_client(telemetry, + json_string_value(client_path)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not register client"); + telemetry->register_fail_count++; + goto fail; + } + + return 0; + +fail: + TELEMETRY_LOG_WARN("Client attempted to register with invalid message"); + return -1; +} + int telemetry_log_level; RTE_INIT(rte_telemetry_register); diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h index 569d56a..e3292cf 100644 --- a/lib/librte_telemetry/rte_telemetry_internal.h +++ b/lib/librte_telemetry/rte_telemetry_internal.h @@ -3,6 +3,7 @@ */ #include +#include #ifndef _RTE_TELEMETRY_INTERNAL_H_ #define _RTE_TELEMETRY_INTERNAL_H_ @@ -23,6 +24,12 @@ extern int telemetry_log_level; #define TELEMETRY_LOG_INFO(fmt, args...) \ TELEMETRY_LOG(INFO, fmt, ## args) +typedef struct telemetry_client { + char *file_path; + int fd; + TAILQ_ENTRY(telemetry_client) client_list; +} telemetry_client; + typedef struct telemetry_impl { int accept_fd; int server_fd; @@ -31,6 +38,24 @@ typedef struct telemetry_impl { uint32_t socket_id; int reg_index; int metrics_register_done; + TAILQ_HEAD(, telemetry_client) client_list_head; + struct telemetry_client *request_client; + int register_fail_count; } telemetry_impl; +int32_t +rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf); + +int32_t +rte_telemetry_send_error_response(struct telemetry_impl *telemetry, + int error_type); + +int32_t +rte_telemetry_register_client(struct telemetry_impl *telemetry, + const char *client_path); + +int32_t +rte_telemetry_unregister_client(struct telemetry_impl *telemetry, + const char *client_path); + #endif diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 35594b9..b740691 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -80,7 +80,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY) += -lrte_security _LDLIBS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV) += -lrte_compressdev _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += -lrte_eventdev _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV) += -lrte_rawdev -_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -lrte_metrics -lrte_telemetry +_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -lrte_metrics -lrte_telemetry -ljansson _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER) += -lrte_timer _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += -lrte_mempool _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING) += -lrte_mempool_ring From patchwork Tue Oct 16 15:57:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46903 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 9C6E11B16A; Tue, 16 Oct 2018 17:58:10 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id A55081B140 for ; Tue, 16 Oct 2018 17:57:57 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:57:57 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465374" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:57:54 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:57:55 +0100 Message-Id: <20181016155802.2067-7-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 06/13] telemetry: add parser for client socket messages X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch adds the parser file. This is used to parse any messages that are received on any of the client sockets. Currently, the unregister functionality works using the parser. Functionality relating to getting statistic values for certain ports will be added in a subsequent patch, however the parsing involved for that command is added in this patch. Some of the parser code included is in preparation for future functionality, that is not implemented yet in this patchset. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- lib/librte_telemetry/Makefile | 1 + lib/librte_telemetry/meson.build | 4 +- lib/librte_telemetry/rte_telemetry.c | 11 +- lib/librte_telemetry/rte_telemetry_internal.h | 13 + lib/librte_telemetry/rte_telemetry_parser.c | 569 ++++++++++++++++++++++++++ lib/librte_telemetry/rte_telemetry_parser.h | 13 + 6 files changed, 608 insertions(+), 3 deletions(-) create mode 100644 lib/librte_telemetry/rte_telemetry_parser.c create mode 100644 lib/librte_telemetry/rte_telemetry_parser.h diff --git a/lib/librte_telemetry/Makefile b/lib/librte_telemetry/Makefile index 0d61361..95c7296 100644 --- a/lib/librte_telemetry/Makefile +++ b/lib/librte_telemetry/Makefile @@ -21,6 +21,7 @@ LIBABIVER := 1 # library source files SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) := rte_telemetry.c +SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += rte_telemetry_parser.c # export include files SYMLINK-$(CONFIG_RTE_LIBRTE_TELEMETRY)-include := rte_telemetry.h diff --git a/lib/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build index 0ccfa36..7450f96 100644 --- a/lib/librte_telemetry/meson.build +++ b/lib/librte_telemetry/meson.build @@ -1,8 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel Corporation -sources = files('rte_telemetry.c') -headers = files('rte_telemetry.h', 'rte_telemetry_internal.h') +sources = files('rte_telemetry.c', 'rte_telemetry_parser.c') +headers = files('rte_telemetry.h', 'rte_telemetry_internal.h', 'rte_telemetry_parser.h') deps += ['metrics', 'ethdev'] cflags += '-DALLOW_EXPERIMENTAL_API' jansson = cc.find_library('jansson', required: true) diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c index 9ed8ea6..9af855a 100644 --- a/lib/librte_telemetry/rte_telemetry.c +++ b/lib/librte_telemetry/rte_telemetry.c @@ -17,6 +17,7 @@ #include "rte_telemetry.h" #include "rte_telemetry_internal.h" +#include "rte_telemetry_parser.h" #define BUF_SIZE 1024 #define ACTION_POST 1 @@ -285,6 +286,7 @@ rte_telemetry_accept_new_client(struct telemetry_impl *telemetry) static int32_t rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry) { + int ret; telemetry_client *client; char client_buf[BUF_SIZE]; int bytes; @@ -293,8 +295,15 @@ rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry) bytes = read(client->fd, client_buf, BUF_SIZE-1); client_buf[bytes] = '\0'; - if (bytes > 0) + if (bytes > 0) { telemetry->request_client = client; + ret = rte_telemetry_parse(telemetry, client_buf); + if (ret < 0) { + TELEMETRY_LOG_WARN("Parse socket input failed: %i", + ret); + return -1; + } + } } return 0; diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h index e3292cf..86a5ba1 100644 --- a/lib/librte_telemetry/rte_telemetry_internal.h +++ b/lib/librte_telemetry/rte_telemetry_internal.h @@ -43,6 +43,11 @@ typedef struct telemetry_impl { int register_fail_count; } telemetry_impl; +enum rte_telemetry_parser_actions { + ACTION_GET = 0, + ACTION_DELETE = 2 +}; + int32_t rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf); @@ -58,4 +63,12 @@ int32_t rte_telemetry_unregister_client(struct telemetry_impl *telemetry, const char *client_path); +/** + * This is a wrapper for the ethdev api rte_eth_find_next(). + * If rte_eth_find_next() returns the same port id that we passed it, + * then we know that that port is active. + */ +int32_t +rte_telemetry_is_port_active(int port_id); + #endif diff --git a/lib/librte_telemetry/rte_telemetry_parser.c b/lib/librte_telemetry/rte_telemetry_parser.c new file mode 100644 index 0000000..6bc4c6d --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_parser.c @@ -0,0 +1,569 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rte_telemetry_internal.h" + +typedef int (*command_func)(struct telemetry_impl *, int, json_t *); + +struct rte_telemetry_command { + char *text; + command_func fn; +} command; + +static int32_t +rte_telemetry_command_clients(struct telemetry_impl *telemetry, int action, + json_t *data) +{ + int ret; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Invalid telemetry argument"); + return -1; + } + + if (action != ACTION_DELETE) { + TELEMETRY_LOG_WARN("Invalid action for this command"); + goto einval_fail; + } + + if (!json_is_object(data)) { + TELEMETRY_LOG_WARN("Invalid data provided for this command"); + goto einval_fail; + } + + json_t *client_path = json_object_get(data, "client_path"); + if (!json_is_string(client_path)) { + TELEMETRY_LOG_WARN("Command value is not a string"); + goto einval_fail; + } + + ret = rte_telemetry_unregister_client(telemetry, + json_string_value(client_path)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not unregister client"); + goto einval_fail; + } + + return 0; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; +} + +static int32_t +rte_telemetry_command_ports(struct telemetry_impl *telemetry, int action, + json_t *data) +{ + int ret; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Invalid telemetry argument"); + return -1; + } + + if (!json_is_null(data)) { + TELEMETRY_LOG_WARN("Data should be NULL JSON object for 'ports' command"); + goto einval_fail; + } + + if (action != ACTION_GET) { + TELEMETRY_LOG_WARN("Invalid action for this command"); + goto einval_fail; + } + + return 0; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; +} + +static int32_t +rte_telemetry_command_ports_details(struct telemetry_impl *telemetry, + int action, json_t *data) +{ + json_t *value, *port_ids_json = json_object_get(data, "ports"); + uint64_t num_port_ids = json_array_size(port_ids_json); + int ret, port_ids[num_port_ids]; + RTE_SET_USED(port_ids); + size_t index; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Invalid telemetry argument"); + return -1; + } + + if (action != ACTION_GET) { + TELEMETRY_LOG_WARN("Invalid action for this command"); + goto einval_fail; + } + + if (!json_is_object(data)) { + TELEMETRY_LOG_WARN("Invalid data provided for this command"); + goto einval_fail; + } + + if (!json_is_array(port_ids_json)) { + TELEMETRY_LOG_WARN("Invalid Port ID array"); + goto einval_fail; + } + + json_array_foreach(port_ids_json, index, value) { + if (!json_is_integer(value)) { + TELEMETRY_LOG_WARN("Port ID given is invalid"); + goto einval_fail; + } + port_ids[index] = json_integer_value(value); + } + + return 0; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; +} + +static int32_t +rte_telemetry_command_port_stats(struct telemetry_impl *telemetry, int action, + json_t *data) +{ + int ret; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Invalid telemetry argument"); + return -1; + } + + if (!json_is_null(data)) { + TELEMETRY_LOG_WARN("Data should be NULL JSON object for 'port_stats' command"); + goto einval_fail; + } + + if (action != ACTION_GET) { + TELEMETRY_LOG_WARN("Invalid action for this command"); + goto einval_fail; + } + + return 0; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; +} + +static int32_t +rte_telemetry_stat_names_to_ids(struct telemetry_impl *telemetry, + const char * const *stat_names, uint32_t *stat_ids, + uint64_t num_stat_names) +{ + struct rte_metric_name *names; + int ret, num_metrics; + uint32_t i, k; + + if (stat_names == NULL) { + TELEMETRY_LOG_WARN("Invalid stat_names argument"); + goto einval_fail; + } + + if (num_stat_names <= 0) { + TELEMETRY_LOG_WARN("Invalid num_stat_names argument"); + goto einval_fail; + } + + num_metrics = rte_metrics_get_names(NULL, 0); + if (num_metrics < 0) { + TELEMETRY_LOG_ERR("Cannot get metrics count"); + goto eperm_fail; + } else if (num_metrics == 0) { + TELEMETRY_LOG_WARN("No metrics have been registered"); + goto eperm_fail; + } + + names = malloc(sizeof(struct rte_metric_name) * num_metrics); + if (names == NULL) { + TELEMETRY_LOG_ERR("Cannot allocate memory for names"); + + ret = rte_telemetry_send_error_response(telemetry, -ENOMEM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + + return -1; + } + + ret = rte_metrics_get_names(names, num_metrics); + if (ret < 0 || ret > num_metrics) { + TELEMETRY_LOG_ERR("Cannot get metrics names"); + free(names); + goto eperm_fail; + } + + k = 0; + for (i = 0; i < (uint32_t)num_stat_names; i++) { + uint32_t j; + for (j = 0; j < (uint32_t)num_metrics; j++) { + if (strcmp(stat_names[i], names[j].name) == 0) { + stat_ids[k] = j; + k++; + break; + } + } + } + + if (k != num_stat_names) { + TELEMETRY_LOG_WARN("Invalid stat names provided"); + free(names); + goto einval_fail; + } + + free(names); + return 0; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + +eperm_fail: + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; +} + +int32_t +rte_telemetry_command_ports_all_stat_values(struct telemetry_impl *telemetry, + int action, json_t *data) +{ + int ret, num_metrics, i, p; + struct rte_metric_name *names; + uint64_t num_port_ids = 0; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Invalid telemetry argument"); + return -1; + } + + if (action != ACTION_GET) { + TELEMETRY_LOG_WARN("Invalid action for this command"); + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + if (json_is_object(data)) { + TELEMETRY_LOG_WARN("Invalid data provided for this command"); + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + num_metrics = rte_metrics_get_names(NULL, 0); + if (num_metrics < 0) { + TELEMETRY_LOG_ERR("Cannot get metrics count"); + + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + + return -1; + } else if (num_metrics == 0) { + TELEMETRY_LOG_ERR("No metrics to display (none have been registered)"); + + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + + return -1; + } + + names = malloc(sizeof(struct rte_metric_name) * num_metrics); + if (names == NULL) { + TELEMETRY_LOG_ERR("Cannot allocate memory"); + ret = rte_telemetry_send_error_response(telemetry, + -ENOMEM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + const char *stat_names[num_metrics]; + uint32_t stat_ids[num_metrics]; + + RTE_ETH_FOREACH_DEV(p) { + num_port_ids++; + } + + if (!num_port_ids) { + TELEMETRY_LOG_WARN("No active ports"); + + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + + goto fail; + } + + ret = rte_metrics_get_names(names, num_metrics); + for (i = 0; i < num_metrics; i++) + stat_names[i] = names[i].name; + + ret = rte_telemetry_stat_names_to_ids(telemetry, stat_names, stat_ids, + num_metrics); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not convert stat names to IDs"); + goto fail; + } + + return 0; + +fail: + free(names); + return -1; +} + +int32_t +rte_telemetry_command_ports_stats_values_by_name(struct telemetry_impl + *telemetry, int action, json_t *data) +{ + int ret; + json_t *port_ids_json = json_object_get(data, "ports"); + json_t *stat_names_json = json_object_get(data, "stats"); + uint64_t num_port_ids = json_array_size(port_ids_json); + uint64_t num_stat_names = json_array_size(stat_names_json); + const char *stat_names[num_stat_names]; + uint32_t port_ids[num_port_ids], stat_ids[num_stat_names]; + size_t index; + json_t *value; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Invalid telemetry argument"); + return -1; + } + + if (action != ACTION_GET) { + TELEMETRY_LOG_WARN("Invalid action for this command"); + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + if (!json_is_object(data)) { + TELEMETRY_LOG_WARN("Invalid data provided for this command"); + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + if (!json_is_array(port_ids_json) || + !json_is_array(stat_names_json)) { + TELEMETRY_LOG_WARN("Invalid input data array(s)"); + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + json_array_foreach(port_ids_json, index, value) { + if (!json_is_integer(value)) { + TELEMETRY_LOG_WARN("Port ID given is not valid"); + ret = rte_telemetry_send_error_response(telemetry, + -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + port_ids[index] = json_integer_value(value); + ret = rte_telemetry_is_port_active(port_ids[index]); + if (ret < 1) { + ret = rte_telemetry_send_error_response(telemetry, + -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + } + + json_array_foreach(stat_names_json, index, value) { + if (!json_is_string(value)) { + TELEMETRY_LOG_WARN("Stat Name given is not a string"); + + ret = rte_telemetry_send_error_response(telemetry, + -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + + return -1; + } + stat_names[index] = json_string_value(value); + } + + ret = rte_telemetry_stat_names_to_ids(telemetry, stat_names, stat_ids, + num_stat_names); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not convert stat names to IDs"); + return -1; + } + return 0; +} + +static int32_t +rte_telemetry_parse_command(struct telemetry_impl *telemetry, int action, + const char *command, json_t *data) +{ + int ret; + uint32_t i; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Invalid telemetry argument"); + return -1; + } + + struct rte_telemetry_command commands[] = { + { + .text = "clients", + .fn = &rte_telemetry_command_clients + }, + { + .text = "ports", + .fn = &rte_telemetry_command_ports + }, + { + .text = "ports_details", + .fn = &rte_telemetry_command_ports_details + }, + { + .text = "port_stats", + .fn = &rte_telemetry_command_port_stats + }, + { + .text = "ports_stats_values_by_name", + .fn = &rte_telemetry_command_ports_stats_values_by_name + }, + { + .text = "ports_all_stat_values", + .fn = &rte_telemetry_command_ports_all_stat_values + } + }; + + const uint32_t num_commands = RTE_DIM(commands); + + for (i = 0; i < num_commands; i++) { + if (strcmp(command, commands[i].text) == 0) { + ret = commands[i].fn(telemetry, action, data); + if (ret < 0) { + TELEMETRY_LOG_ERR("Command Function for %s failed", + commands[i].text); + return -1; + } + return 0; + } + } + + TELEMETRY_LOG_WARN("\"%s\" command not found", command); + + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + + return -1; +} + +int32_t +rte_telemetry_parse(struct telemetry_impl *telemetry, char *socket_rx_data) +{ + int ret, action_int; + json_error_t error; + json_t *root, *action, *command, *data; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Invalid telemetry argument"); + return -1; + } + + root = json_loads(socket_rx_data, 0, &error); + if (root == NULL) { + TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s", + error.text); + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -EPERM; + } else if (!json_is_object(root)) { + TELEMETRY_LOG_WARN("JSON Request is not a JSON object"); + json_decref(root); + goto einval_fail; + } + + action = json_object_get(root, "action"); + if (action == NULL) { + TELEMETRY_LOG_WARN("Request does not have action field"); + goto einval_fail; + } else if (!json_is_integer(action)) { + TELEMETRY_LOG_WARN("Action value is not an integer"); + goto einval_fail; + } + + command = json_object_get(root, "command"); + if (command == NULL) { + TELEMETRY_LOG_WARN("Request does not have command field"); + goto einval_fail; + } else if (!json_is_string(command)) { + TELEMETRY_LOG_WARN("Command value is not a string"); + goto einval_fail; + } + + action_int = json_integer_value(action); + if (action_int != ACTION_GET && action_int != ACTION_DELETE) { + TELEMETRY_LOG_WARN("Invalid action code"); + goto einval_fail; + } + + const char *command_string = json_string_value(command); + data = json_object_get(root, "data"); + if (data == NULL) { + TELEMETRY_LOG_WARN("Request does not have data field"); + goto einval_fail; + } + + ret = rte_telemetry_parse_command(telemetry, action_int, command_string, + data); + if (ret < 0) { + TELEMETRY_LOG_WARN("Could not parse command"); + return -EINVAL; + } + + return 0; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not send error"); + return -EPERM; + } + return -EINVAL; +} diff --git a/lib/librte_telemetry/rte_telemetry_parser.h b/lib/librte_telemetry/rte_telemetry_parser.h new file mode 100644 index 0000000..63e633d --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_parser.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include "rte_telemetry_internal.h" + +#ifndef _RTE_TELEMETRY_PARSER_H_ +#define _RTE_TELEMETRY_PARSER_H_ + +int32_t +rte_telemetry_parse(struct telemetry_impl *telemetry, char *socket_rx_data); + +#endif From patchwork Tue Oct 16 15:57:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46904 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 48CD81B179; Tue, 16 Oct 2018 17:58:12 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id ACBBE1B152 for ; Tue, 16 Oct 2018 17:58:00 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:58:00 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465388" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:57:57 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:57:56 +0100 Message-Id: <20181016155802.2067-8-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 07/13] telemetry: update metrics before sending stats X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch adds functionality to update the statistics in the metrics library with values from the ethdev stats. Values need to be updated before they are encoded into a JSON message and sent to the client that requested them. The JSON encoding will be added in a subsequent patch. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- lib/librte_telemetry/rte_telemetry.c | 134 ++++++++++++++++++++++++++ lib/librte_telemetry/rte_telemetry_internal.h | 4 + lib/librte_telemetry/rte_telemetry_parser.c | 17 ++++ 3 files changed, 155 insertions(+) diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c index 9af855a..cd2bd12 100644 --- a/lib/librte_telemetry/rte_telemetry.c +++ b/lib/librte_telemetry/rte_telemetry.c @@ -46,6 +46,78 @@ rte_telemetry_is_port_active(int port_id) return 0; } +static int32_t +rte_telemetry_update_metrics_ethdev(struct telemetry_impl *telemetry, + uint16_t port_id, int reg_start_index) +{ + int ret, num_xstats, i; + struct rte_eth_xstat *eth_xstats; + + if (!rte_eth_dev_is_valid_port(port_id)) { + TELEMETRY_LOG_ERR("port_id: %d is invalid", port_id); + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + ret = rte_telemetry_is_port_active(port_id); + if (ret < 1) { + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + num_xstats = rte_eth_xstats_get(port_id, NULL, 0); + if (num_xstats < 0) { + TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) failed: %d", port_id, + num_xstats); + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + eth_xstats = malloc(sizeof(struct rte_eth_xstat) * num_xstats); + if (eth_xstats == NULL) { + TELEMETRY_LOG_ERR("Failed to malloc memory for xstats"); + ret = rte_telemetry_send_error_response(telemetry, -ENOMEM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + ret = rte_eth_xstats_get(port_id, eth_xstats, num_xstats); + if (ret < 0 || ret > num_xstats) { + free(eth_xstats); + TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) len%i failed: %d", + port_id, num_xstats, ret); + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + uint64_t xstats_values[num_xstats]; + for (i = 0; i < num_xstats; i++) + xstats_values[i] = eth_xstats[i].value; + + ret = rte_metrics_update_values(port_id, reg_start_index, xstats_values, + num_xstats); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not update metrics values"); + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + free(eth_xstats); + return -1; + } + + free(eth_xstats); + return 0; +} + int32_t rte_telemetry_write_to_socket(struct telemetry_impl *telemetry, const char *json_string) @@ -130,6 +202,68 @@ rte_telemetry_send_error_response(struct telemetry_impl *telemetry, return 0; } +int32_t +rte_telemetry_send_ports_stats_values(uint32_t *metric_ids, int num_metric_ids, + uint32_t *port_ids, int num_port_ids, struct telemetry_impl *telemetry) +{ + int ret, i; + char *json_buffer = NULL; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Invalid telemetry argument"); + return -1; + } + + if (metric_ids == NULL) { + TELEMETRY_LOG_ERR("Invalid metric_ids array"); + goto einval_fail; + } + + if (num_metric_ids < 0) { + TELEMETRY_LOG_ERR("Invalid num_metric_ids, must be positive"); + goto einval_fail; + } + + if (port_ids == NULL) { + TELEMETRY_LOG_ERR("Invalid port_ids array"); + goto einval_fail; + } + + if (num_port_ids < 0) { + TELEMETRY_LOG_ERR("Invalid num_port_ids, must be positive"); + goto einval_fail; + } + + for (i = 0; i < num_port_ids; i++) { + if (!rte_eth_dev_is_valid_port(port_ids[i])) { + TELEMETRY_LOG_ERR("Port: %d invalid", port_ids[i]); + goto einval_fail; + } + + ret = rte_telemetry_update_metrics_ethdev(telemetry, + port_ids[i], telemetry->reg_index); + if (ret < 0) { + TELEMETRY_LOG_ERR("Failed to update ethdev metrics"); + return -1; + } + } + + ret = rte_telemetry_write_to_socket(telemetry, json_buffer); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not write to socket"); + return -1; + } + + return 0; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; +} + + static int32_t rte_telemetry_reg_ethdev_to_metrics(uint16_t port_id) { diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h index 86a5ba1..0082cb2 100644 --- a/lib/librte_telemetry/rte_telemetry_internal.h +++ b/lib/librte_telemetry/rte_telemetry_internal.h @@ -71,4 +71,8 @@ rte_telemetry_unregister_client(struct telemetry_impl *telemetry, int32_t rte_telemetry_is_port_active(int port_id); +int32_t +rte_telemetry_send_ports_stats_values(uint32_t *metric_ids, int num_metric_ids, + uint32_t *port_ids, int num_port_ids, struct telemetry_impl *telemetry); + #endif diff --git a/lib/librte_telemetry/rte_telemetry_parser.c b/lib/librte_telemetry/rte_telemetry_parser.c index 6bc4c6d..084c160 100644 --- a/lib/librte_telemetry/rte_telemetry_parser.c +++ b/lib/librte_telemetry/rte_telemetry_parser.c @@ -258,6 +258,7 @@ rte_telemetry_command_ports_all_stat_values(struct telemetry_impl *telemetry, int ret, num_metrics, i, p; struct rte_metric_name *names; uint64_t num_port_ids = 0; + uint32_t port_ids[RTE_MAX_ETHPORTS]; if (telemetry == NULL) { TELEMETRY_LOG_ERR("Invalid telemetry argument"); @@ -313,6 +314,7 @@ rte_telemetry_command_ports_all_stat_values(struct telemetry_impl *telemetry, uint32_t stat_ids[num_metrics]; RTE_ETH_FOREACH_DEV(p) { + port_ids[num_port_ids] = p; num_port_ids++; } @@ -337,6 +339,13 @@ rte_telemetry_command_ports_all_stat_values(struct telemetry_impl *telemetry, goto fail; } + ret = rte_telemetry_send_ports_stats_values(stat_ids, num_metrics, + port_ids, num_port_ids, telemetry); + if (ret < 0) { + TELEMETRY_LOG_ERR("Sending ports stats values failed"); + goto fail; + } + return 0; fail: @@ -428,6 +437,14 @@ rte_telemetry_command_ports_stats_values_by_name(struct telemetry_impl TELEMETRY_LOG_ERR("Could not convert stat names to IDs"); return -1; } + + ret = rte_telemetry_send_ports_stats_values(stat_ids, num_stat_names, + port_ids, num_port_ids, telemetry); + if (ret < 0) { + TELEMETRY_LOG_ERR("Sending ports stats values failed"); + return -1; + } + return 0; } From patchwork Tue Oct 16 15:57:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46905 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 4D3F21B181; Tue, 16 Oct 2018 17:58:14 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 9A68A1B16F for ; Tue, 16 Oct 2018 17:58:03 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:58:03 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465404" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:58:00 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:57:57 +0100 Message-Id: <20181016155802.2067-9-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 08/13] telemetry: format json response when sending stats X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch adds functionality to create a JSON message in order to send it to a client socket. When stats are requested by a client, they are retrieved from the metrics library and encoded in JSON format. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- lib/librte_telemetry/rte_telemetry.c | 309 ++++++++++++++++++++++++++++++++++- 1 file changed, 307 insertions(+), 2 deletions(-) diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c index cd2bd12..122640a 100644 --- a/lib/librte_telemetry/rte_telemetry.c +++ b/lib/librte_telemetry/rte_telemetry.c @@ -190,7 +190,7 @@ rte_telemetry_send_error_response(struct telemetry_impl *telemetry, return -EPERM; } - json_buffer = json_dumps(root, JSON_INDENT(2)); + json_buffer = json_dumps(root, 0); json_decref(root); ret = rte_telemetry_write_to_socket(telemetry, json_buffer); @@ -202,6 +202,304 @@ rte_telemetry_send_error_response(struct telemetry_impl *telemetry, return 0; } +static int +rte_telemetry_get_metrics(struct telemetry_impl *telemetry, uint32_t port_id, + struct rte_metric_value *metrics, struct rte_metric_name *names, + int num_metrics) +{ + int ret, num_values; + + if (num_metrics < 0) { + TELEMETRY_LOG_ERR("Invalid metrics count"); + goto einval_fail; + } else if (num_metrics == 0) { + TELEMETRY_LOG_ERR("No metrics to display (none have been registered)"); + goto eperm_fail; + } + + if (metrics == NULL) { + TELEMETRY_LOG_ERR("Metrics must be initialised."); + goto einval_fail; + } + + if (names == NULL) { + TELEMETRY_LOG_ERR("Names must be initialised."); + goto einval_fail; + } + + ret = rte_metrics_get_names(names, num_metrics); + if (ret < 0 || ret > num_metrics) { + TELEMETRY_LOG_ERR("Cannot get metrics names"); + goto eperm_fail; + } + + num_values = rte_metrics_get_values(port_id, NULL, 0); + ret = rte_metrics_get_values(port_id, metrics, num_values); + if (ret < 0 || ret > num_values) { + TELEMETRY_LOG_ERR("Cannot get metrics values"); + goto eperm_fail; + } + + return 0; + +eperm_fail: + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + +} + +static int32_t +rte_telemetry_json_format_stat(struct telemetry_impl *telemetry, json_t *stats, + const char *metric_name, uint64_t metric_value) +{ + int ret; + json_t *stat = json_object(); + + if (stat == NULL) { + TELEMETRY_LOG_ERR("Could not create stat JSON object"); + goto eperm_fail; + } + + ret = json_object_set_new(stat, "name", json_string(metric_name)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Stat Name field cannot be set"); + goto eperm_fail; + } + + ret = json_object_set_new(stat, "value", json_integer(metric_value)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Stat Value field cannot be set"); + goto eperm_fail; + } + + ret = json_array_append_new(stats, stat); + if (ret < 0) { + TELEMETRY_LOG_ERR("Stat cannot be added to stats json array"); + goto eperm_fail; + } + + return 0; + +eperm_fail: + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + +} + +static int32_t +rte_telemetry_json_format_port(struct telemetry_impl *telemetry, + uint32_t port_id, json_t *ports, uint32_t *metric_ids, + uint32_t num_metric_ids) +{ + struct rte_metric_value *metrics = 0; + struct rte_metric_name *names = 0; + int num_metrics, ret, err_ret; + json_t *port, *stats; + uint32_t i; + + num_metrics = rte_metrics_get_names(NULL, 0); + if (num_metrics < 0) { + TELEMETRY_LOG_ERR("Cannot get metrics count"); + goto einval_fail; + } else if (num_metrics == 0) { + TELEMETRY_LOG_ERR("No metrics to display (none have been registered)"); + goto eperm_fail; + } + + metrics = malloc(sizeof(struct rte_metric_value) * num_metrics); + names = malloc(sizeof(struct rte_metric_name) * num_metrics); + if (metrics == NULL || names == NULL) { + TELEMETRY_LOG_ERR("Cannot allocate memory"); + free(metrics); + free(names); + + err_ret = rte_telemetry_send_error_response(telemetry, -ENOMEM); + if (err_ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + } + + ret = rte_telemetry_get_metrics(telemetry, port_id, metrics, names, + num_metrics); + if (ret < 0) { + free(metrics); + free(names); + TELEMETRY_LOG_ERR("rte_telemetry_get_metrics failed"); + return -1; + } + + port = json_object(); + stats = json_array(); + if (port == NULL || stats == NULL) { + TELEMETRY_LOG_ERR("Could not create port/stats JSON objects"); + goto eperm_fail; + } + + ret = json_object_set_new(port, "port", json_integer(port_id)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Port field cannot be set"); + goto eperm_fail; + } + + for (i = 0; i < num_metric_ids; i++) { + int metric_id = metric_ids[i]; + int metric_index = -1; + int metric_name_key = -1; + int32_t j; + uint64_t metric_value; + + if (metric_id >= num_metrics) { + TELEMETRY_LOG_ERR("Metric_id: %d is not valid", + metric_id); + goto einval_fail; + } + + for (j = 0; j < num_metrics; j++) { + if (metrics[j].key == metric_id) { + metric_name_key = metrics[j].key; + metric_index = j; + break; + } + } + + const char *metric_name = names[metric_name_key].name; + metric_value = metrics[metric_index].value; + + if (metric_name_key < 0 || metric_index < 0) { + TELEMETRY_LOG_ERR("Could not get metric name/index"); + goto eperm_fail; + } + + ret = rte_telemetry_json_format_stat(telemetry, stats, + metric_name, metric_value); + if (ret < 0) { + TELEMETRY_LOG_ERR("Format stat with id: %u failed", + metric_id); + free(metrics); + free(names); + return -1; + } + } + + if (json_array_size(stats) == 0) + ret = json_object_set_new(port, "stats", json_null()); + else + ret = json_object_set_new(port, "stats", stats); + + if (ret < 0) { + TELEMETRY_LOG_ERR("Stats object cannot be set"); + goto eperm_fail; + } + + ret = json_array_append_new(ports, port); + if (ret < 0) { + TELEMETRY_LOG_ERR("Port object cannot be added to ports array"); + goto eperm_fail; + } + + free(metrics); + free(names); + return 0; + +eperm_fail: + free(metrics); + free(names); + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + +einval_fail: + free(metrics); + free(names); + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; +} + +static int32_t +rte_telemetry_encode_json_format(struct telemetry_impl *telemetry, + uint32_t *port_ids, uint32_t num_port_ids, uint32_t *metric_ids, + uint32_t num_metric_ids, char **json_buffer) +{ + int ret; + json_t *root, *ports; + uint32_t i; + + if (num_port_ids <= 0 || num_metric_ids <= 0) { + TELEMETRY_LOG_ERR("Please provide port and metric ids to query"); + goto einval_fail; + } + + ports = json_array(); + if (ports == NULL) { + TELEMETRY_LOG_ERR("Could not create ports JSON array"); + goto eperm_fail; + } + + for (i = 0; i < num_port_ids; i++) { + if (!rte_eth_dev_is_valid_port(port_ids[i])) { + TELEMETRY_LOG_ERR("Port: %d invalid", port_ids[i]); + goto einval_fail; + } + } + + for (i = 0; i < num_port_ids; i++) { + ret = rte_telemetry_json_format_port(telemetry, port_ids[i], + ports, metric_ids, num_metric_ids); + if (ret < 0) { + TELEMETRY_LOG_ERR("Format port in JSON failed"); + return -1; + } + } + + root = json_object(); + if (root == NULL) { + TELEMETRY_LOG_ERR("Could not create root JSON object"); + goto eperm_fail; + } + + ret = json_object_set_new(root, "status_code", + json_string("Status OK: 200")); + if (ret < 0) { + TELEMETRY_LOG_ERR("Status code field cannot be set"); + goto eperm_fail; + } + + ret = json_object_set_new(root, "data", ports); + if (ret < 0) { + TELEMETRY_LOG_ERR("Data field cannot be set"); + goto eperm_fail; + } + + *json_buffer = json_dumps(root, JSON_INDENT(2)); + json_decref(root); + return 0; + +eperm_fail: + ret = rte_telemetry_send_error_response(telemetry, -EPERM); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; + +einval_fail: + ret = rte_telemetry_send_error_response(telemetry, -EINVAL); + if (ret < 0) + TELEMETRY_LOG_ERR("Could not send error"); + return -1; +} + int32_t rte_telemetry_send_ports_stats_values(uint32_t *metric_ids, int num_metric_ids, uint32_t *port_ids, int num_port_ids, struct telemetry_impl *telemetry) @@ -241,13 +539,20 @@ rte_telemetry_send_ports_stats_values(uint32_t *metric_ids, int num_metric_ids, } ret = rte_telemetry_update_metrics_ethdev(telemetry, - port_ids[i], telemetry->reg_index); + port_ids[i], telemetry->reg_index); if (ret < 0) { TELEMETRY_LOG_ERR("Failed to update ethdev metrics"); return -1; } } + ret = rte_telemetry_encode_json_format(telemetry, port_ids, + num_port_ids, metric_ids, num_metric_ids, &json_buffer); + if (ret < 0) { + TELEMETRY_LOG_ERR("JSON encode function failed"); + return -1; + } + ret = rte_telemetry_write_to_socket(telemetry, json_buffer); if (ret < 0) { TELEMETRY_LOG_ERR("Could not write to socket"); From patchwork Tue Oct 16 15:57:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46906 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id DF8FC1B18A; Tue, 16 Oct 2018 17:58:16 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 6C1861B16A for ; Tue, 16 Oct 2018 17:58:08 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:58:08 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465416" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:58:03 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:57:58 +0100 Message-Id: <20181016155802.2067-10-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 09/13] telemetry: add tests for telemetry api X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch adds all tests for the Telemetry API. The tests added include a parser test, selftest, and socket messaging tests. The parser tests pass valid and invalid messages to the parser to ensure the correct return values are received. The selftest tests basic functions in the Telemetry API such as registering, unregistering, and initialisation. The socket messaging tests pass messages through the socket and validates the return message, to ensure the Telemetry API is responding correctly. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- lib/librte_telemetry/Makefile | 1 + lib/librte_telemetry/meson.build | 4 +- lib/librte_telemetry/rte_telemetry.c | 653 ++++++++++++++++++++++ lib/librte_telemetry/rte_telemetry.h | 12 + lib/librte_telemetry/rte_telemetry_internal.h | 3 + lib/librte_telemetry/rte_telemetry_parser_test.c | 534 ++++++++++++++++++ lib/librte_telemetry/rte_telemetry_parser_test.h | 39 ++ lib/librte_telemetry/rte_telemetry_socket_tests.h | 36 ++ lib/librte_telemetry/rte_telemetry_version.map | 1 + 9 files changed, 1281 insertions(+), 2 deletions(-) create mode 100644 lib/librte_telemetry/rte_telemetry_parser_test.c create mode 100644 lib/librte_telemetry/rte_telemetry_parser_test.h create mode 100644 lib/librte_telemetry/rte_telemetry_socket_tests.h diff --git a/lib/librte_telemetry/Makefile b/lib/librte_telemetry/Makefile index 95c7296..1a05069 100644 --- a/lib/librte_telemetry/Makefile +++ b/lib/librte_telemetry/Makefile @@ -22,6 +22,7 @@ LIBABIVER := 1 # library source files SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) := rte_telemetry.c SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += rte_telemetry_parser.c +SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += rte_telemetry_parser_test.c # export include files SYMLINK-$(CONFIG_RTE_LIBRTE_TELEMETRY)-include := rte_telemetry.h diff --git a/lib/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build index 7450f96..57dd83d 100644 --- a/lib/librte_telemetry/meson.build +++ b/lib/librte_telemetry/meson.build @@ -1,8 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel Corporation -sources = files('rte_telemetry.c', 'rte_telemetry_parser.c') -headers = files('rte_telemetry.h', 'rte_telemetry_internal.h', 'rte_telemetry_parser.h') +sources = files('rte_telemetry.c', 'rte_telemetry_parser.c', 'rte_telemetry_parser_test.c') +headers = files('rte_telemetry.h', 'rte_telemetry_internal.h', 'rte_telemetry_parser.h', 'rte_telemetry_parser_test.h') deps += ['metrics', 'ethdev'] cflags += '-DALLOW_EXPERIMENTAL_API' jansson = cc.find_library('jansson', required: true) diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c index 122640a..82b46a5 100644 --- a/lib/librte_telemetry/rte_telemetry.c +++ b/lib/librte_telemetry/rte_telemetry.c @@ -18,13 +18,32 @@ #include "rte_telemetry.h" #include "rte_telemetry_internal.h" #include "rte_telemetry_parser.h" +#include "rte_telemetry_parser_test.h" +#include "rte_telemetry_socket_tests.h" #define BUF_SIZE 1024 #define ACTION_POST 1 #define SLEEP_TIME 10 +#define SELFTEST_VALID_CLIENT "/var/run/dpdk/valid_client" +#define SELFTEST_INVALID_CLIENT "/var/run/dpdk/invalid_client" +#define SOCKET_TEST_CLIENT_PATH "/var/run/dpdk/client" + static telemetry_impl *static_telemetry; +struct telemetry_message_test { + char *test_name; + int (*test_func_ptr)(struct telemetry_impl *telemetry, int fd); +}; + +struct json_data { + char *status_code; + char *data; + int port; + char *stat_name; + int stat_value; +}; + static void rte_telemetry_get_runtime_dir(char *socket_path, size_t size) { @@ -640,6 +659,7 @@ static int32_t rte_telemetry_initial_accept(struct telemetry_impl *telemetry) { uint16_t pid; + int ret; RTE_ETH_FOREACH_DEV(pid) { telemetry->reg_index = rte_telemetry_reg_ethdev_to_metrics(pid); @@ -652,6 +672,18 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry) } telemetry->metrics_register_done = 1; + ret = rte_telemetry_socket_messaging_testing(telemetry->reg_index, + telemetry->server_fd); + if (ret < 0) + return -1; + + ret = rte_telemetry_parser_test(telemetry); + if (ret < 0) { + TELEMETRY_LOG_ERR("Parser Tests Failed"); + return -1; + } + + TELEMETRY_LOG_INFO("Success - All Parser Tests Passed"); return 0; } @@ -1134,6 +1166,627 @@ rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf) return -1; } +int32_t +rte_telemetry_dummy_client_socket(const char *valid_client_path) +{ + int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + struct sockaddr_un addr = {0}; + + if (sockfd < 0) { + TELEMETRY_LOG_ERR("Test socket creation failure"); + return -1; + } + + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, valid_client_path, sizeof(addr.sun_path)); + unlink(valid_client_path); + + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + TELEMETRY_LOG_ERR("Test socket binding failure"); + return -1; + } + + if (listen(sockfd, 1) < 0) { + TELEMETRY_LOG_ERR("Listen failure"); + return -1; + } + + return sockfd; +} + +int32_t +rte_telemetry_selftest(void) +{ + const char *invalid_client_path = SELFTEST_INVALID_CLIENT; + const char *valid_client_path = SELFTEST_VALID_CLIENT; + int ret, sockfd; + + TELEMETRY_LOG_INFO("Selftest"); + + ret = rte_telemetry_init(); + if (ret < 0) { + TELEMETRY_LOG_ERR("Valid initialisation test failed"); + return -1; + } + + TELEMETRY_LOG_INFO("Success - Valid initialisation test passed"); + + ret = rte_telemetry_init(); + if (ret != -EALREADY) { + TELEMETRY_LOG_ERR("Invalid initialisation test failed"); + return -1; + } + + TELEMETRY_LOG_INFO("Success - Invalid initialisation test passed"); + + ret = rte_telemetry_unregister_client(static_telemetry, + invalid_client_path); + if (ret != -EPERM) { + TELEMETRY_LOG_ERR("Invalid unregister test failed"); + return -1; + } + + TELEMETRY_LOG_INFO("Success - Invalid unregister test passed"); + + sockfd = rte_telemetry_dummy_client_socket(valid_client_path); + if (sockfd < 0) { + TELEMETRY_LOG_ERR("Test socket creation failed"); + return -1; + } + + ret = rte_telemetry_register_client(static_telemetry, valid_client_path); + if (ret != 0) { + TELEMETRY_LOG_ERR("Valid register test failed: %i", ret); + return -1; + } + + accept(sockfd, NULL, NULL); + TELEMETRY_LOG_INFO("Success - Valid register test passed"); + + ret = rte_telemetry_register_client(static_telemetry, valid_client_path); + if (ret != -EINVAL) { + TELEMETRY_LOG_ERR("Invalid register test failed: %i", ret); + return -1; + } + + TELEMETRY_LOG_INFO("Success - Invalid register test passed"); + + ret = rte_telemetry_unregister_client(static_telemetry, + invalid_client_path); + if (ret != -1) { + TELEMETRY_LOG_ERR("Invalid unregister test failed: %i", ret); + return -1; + } + + TELEMETRY_LOG_INFO("Success - Invalid unregister test passed"); + + ret = rte_telemetry_unregister_client(static_telemetry, valid_client_path); + if (ret != 0) { + TELEMETRY_LOG_ERR("Valid unregister test failed: %i", ret); + return -1; + } + + TELEMETRY_LOG_INFO("Success - Valid unregister test passed"); + + ret = rte_telemetry_cleanup(); + if (ret < 0) { + TELEMETRY_LOG_ERR("Cleanup test failed"); + return -1; + } + + TELEMETRY_LOG_INFO("Success - Valid cleanup test passed"); + + return 0; +} + +int32_t +rte_telemetry_socket_messaging_testing(int index, int socket) +{ + struct telemetry_impl *telemetry = calloc(1, sizeof(telemetry_impl)); + int fd, bad_send_fd, send_fd, bad_fd, bad_recv_fd, recv_fd, ret; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Could not initialize Telemetry API"); + return -1; + } + + telemetry->server_fd = socket; + telemetry->reg_index = index; + TELEMETRY_LOG_INFO("Beginning Telemetry socket message Selftest"); + rte_telemetry_socket_test_setup(telemetry, &send_fd, &recv_fd); + TELEMETRY_LOG_INFO("Register valid client test"); + + ret = rte_telemetry_socket_register_test(telemetry, &fd, send_fd, + recv_fd); + if (ret < 0) { + TELEMETRY_LOG_ERR("Register valid client test failed!"); + free(telemetry); + return -1; + } + + TELEMETRY_LOG_INFO("Success - Register valid client test passed!"); + + TELEMETRY_LOG_INFO("Register invalid/same client test"); + ret = rte_telemetry_socket_test_setup(telemetry, &bad_send_fd, + &bad_recv_fd); + ret = rte_telemetry_socket_register_test(telemetry, &bad_fd, + bad_send_fd, bad_recv_fd); + if (!ret) { + TELEMETRY_LOG_ERR("Register invalid/same client test failed!"); + free(telemetry); + return -1; + } + + TELEMETRY_LOG_INFO("Success - Register invalid/same client test passed!"); + + ret = rte_telemetry_json_socket_message_test(telemetry, fd); + if (ret < 0) { + free(telemetry); + return -1; + } + + free(telemetry); + return 0; +} + +int32_t +rte_telemetry_socket_register_test(struct telemetry_impl *telemetry, int *fd, + int send_fd, int recv_fd) +{ + int ret; + char good_req_string[BUF_SIZE]; + + snprintf(good_req_string, sizeof(good_req_string), + "{\"action\":1,\"command\":\"clients\",\"data\":{\"client_path\"" + ":\"%s\"}}", SOCKET_TEST_CLIENT_PATH); + + listen(recv_fd, 1); + + ret = send(send_fd, good_req_string, strlen(good_req_string), 0); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not send message over socket"); + return -1; + } + + rte_telemetry_run(telemetry); + + if (telemetry->register_fail_count != 0) + return -1; + + *fd = accept(recv_fd, NULL, NULL); + + return 0; +} + +int32_t +rte_telemetry_socket_test_setup(struct telemetry_impl *telemetry, int *send_fd, + int *recv_fd) +{ + int ret; + const char *client_path = SOCKET_TEST_CLIENT_PATH; + char socket_path[BUF_SIZE]; + struct sockaddr_un addr = {0}; + struct sockaddr_un addrs = {0}; + *send_fd = socket(AF_UNIX, SOCK_STREAM, 0); + *recv_fd = socket(AF_UNIX, SOCK_STREAM, 0); + + listen(telemetry->server_fd, 5); + addr.sun_family = AF_UNIX; + rte_telemetry_get_runtime_dir(socket_path, sizeof(socket_path)); + strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path)); + + ret = connect(*send_fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not connect socket"); + return -1; + } + + telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL); + + addrs.sun_family = AF_UNIX; + strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path)); + unlink(client_path); + + ret = bind(*recv_fd, (struct sockaddr *)&addrs, sizeof(addrs)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not bind socket"); + return -1; + } + + return 0; +} + +static int32_t +rte_telemetry_stat_parse(char *buf, struct json_data *json_data_struct) +{ + json_error_t error; + json_t *root = json_loads(buf, 0, &error); + int arraylen, i; + json_t *status, *dataArray, *port, *stats, *name, *value, *dataArrayObj, + *statsArrayObj; + + stats = NULL; + port = NULL; + name = NULL; + + if (buf == NULL) { + TELEMETRY_LOG_ERR("JSON message is NULL"); + return -EINVAL; + } + + if (root == NULL) { + TELEMETRY_LOG_ERR("Could not load JSON object from data passed in : %s", + error.text); + return -EPERM; + } else if (!json_is_object(root)) { + TELEMETRY_LOG_ERR("JSON Request is not a JSON object"); + json_decref(root); + return -EINVAL; + } + + status = json_object_get(root, "status_code"); + if (!status) { + TELEMETRY_LOG_ERR("Request does not have status field"); + return -EINVAL; + } else if (!json_is_string(status)) { + TELEMETRY_LOG_ERR("Status value is not a string"); + return -EINVAL; + } + + json_data_struct->status_code = strdup(json_string_value(status)); + + dataArray = json_object_get(root, "data"); + if (dataArray == NULL) { + TELEMETRY_LOG_ERR("Request does not have data field"); + return -EINVAL; + } + + arraylen = json_array_size(dataArray); + if (arraylen == 0) { + json_data_struct->data = "null"; + return -EINVAL; + } + + for (i = 0; i < arraylen; i++) { + dataArrayObj = json_array_get(dataArray, i); + port = json_object_get(dataArrayObj, "port"); + stats = json_object_get(dataArrayObj, "stats"); + } + + if (port == NULL) { + TELEMETRY_LOG_ERR("Request does not have port field"); + return -EINVAL; + } + + if (!json_is_integer(port)) { + TELEMETRY_LOG_ERR("Port value is not an integer"); + return -EINVAL; + } + + json_data_struct->port = json_integer_value(port); + + if (stats == NULL) { + TELEMETRY_LOG_ERR("Request does not have stats field"); + return -EINVAL; + } + + arraylen = json_array_size(stats); + for (i = 0; i < arraylen; i++) { + statsArrayObj = json_array_get(stats, i); + name = json_object_get(statsArrayObj, "name"); + value = json_object_get(statsArrayObj, "value"); + } + + if (name == NULL) { + TELEMETRY_LOG_ERR("Request does not have name field"); + return -EINVAL; + } + + if (!json_is_string(name)) { + TELEMETRY_LOG_ERR("Stat name value is not a string"); + return -EINVAL; + } + + json_data_struct->stat_name = strdup(json_string_value(name)); + + if (value == NULL) { + TELEMETRY_LOG_ERR("Request does not have value field"); + return -EINVAL; + } + + if (!json_is_integer(value)) { + TELEMETRY_LOG_ERR("Stat value is not an integer"); + return -EINVAL; + } + + json_data_struct->stat_value = json_integer_value(value); + + return 0; +} + +static void +rte_telemetry_free_test_data(struct json_data *data) +{ + free(data->status_code); + free(data->stat_name); + free(data); +} + +int32_t +rte_telemetry_valid_json_test(struct telemetry_impl *telemetry, int fd) +{ + int ret; + int port = 0; + int value = 0; + int fail_count = 0; + int buffer_read = 0; + char buf[BUF_SIZE]; + struct json_data *data_struct; + errno = 0; + const char *status = "Status OK: 200"; + const char *name = "rx_good_packets"; + const char *valid_json_message = "{\"action\":0,\"command\":" + "\"ports_stats_values_by_name\",\"data\":{\"ports\"" + ":[0],\"stats\":[\"rx_good_packets\"]}}"; + + ret = send(fd, valid_json_message, strlen(valid_json_message), 0); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not send message over socket"); + return -1; + } + + rte_telemetry_run(telemetry); + buffer_read = recv(fd, buf, BUF_SIZE-1, 0); + + if (buffer_read == -1) { + TELEMETRY_LOG_ERR("Read error"); + return -1; + } + + buf[buffer_read] = '\0'; + data_struct = calloc(1, sizeof(struct json_data)); + ret = rte_telemetry_stat_parse(buf, data_struct); + + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not parse stats"); + fail_count++; + } + + if (strcmp(data_struct->status_code, status) != 0) { + TELEMETRY_LOG_ERR("Status code is invalid"); + fail_count++; + } + + if (data_struct->port != port) { + TELEMETRY_LOG_ERR("Port is invalid"); + fail_count++; + } + + if (strcmp(data_struct->stat_name, name) != 0) { + TELEMETRY_LOG_ERR("Stat name is invalid"); + fail_count++; + } + + if (data_struct->stat_value != value) { + TELEMETRY_LOG_ERR("Stat value is invalid"); + fail_count++; + } + + rte_telemetry_free_test_data(data_struct); + if (fail_count > 0) + return -1; + + TELEMETRY_LOG_INFO("Success - Passed valid JSON message test passed"); + + return 0; +} + +int32_t +rte_telemetry_invalid_json_test(struct telemetry_impl *telemetry, int fd) +{ + int ret; + char buf[BUF_SIZE]; + int fail_count = 0; + const char *invalid_json = "{]"; + const char *status = "Status Error: Unknown"; + const char *data = "null"; + struct json_data *data_struct; + int buffer_read = 0; + errno = 0; + + ret = send(fd, invalid_json, strlen(invalid_json), 0); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not send message over socket"); + return -1; + } + + rte_telemetry_run(telemetry); + buffer_read = recv(fd, buf, BUF_SIZE-1, 0); + + if (buffer_read == -1) { + TELEMETRY_LOG_ERR("Read error"); + return -1; + } + + buf[buffer_read] = '\0'; + + data_struct = calloc(1, sizeof(struct json_data)); + ret = rte_telemetry_stat_parse(buf, data_struct); + + if (ret < 0) + TELEMETRY_LOG_ERR("Could not parse stats"); + + if (strcmp(data_struct->status_code, status) != 0) { + TELEMETRY_LOG_ERR("Status code is invalid"); + fail_count++; + } + + if (strcmp(data_struct->data, data) != 0) { + TELEMETRY_LOG_ERR("Data status is invalid"); + fail_count++; + } + + rte_telemetry_free_test_data(data_struct); + if (fail_count > 0) + return -1; + + TELEMETRY_LOG_INFO("Success - Passed invalid JSON message test"); + + return 0; +} + +int32_t +rte_telemetry_json_contents_test(struct telemetry_impl *telemetry, int fd) +{ + int ret; + char buf[BUF_SIZE]; + int fail_count = 0; + char *status = "Status Error: Invalid Argument 404"; + char *data = "null"; + struct json_data *data_struct; + const char *invalid_contents = "{\"action\":0,\"command\":" + "\"ports_stats_values_by_name\",\"data\":{\"ports\"" + ":[0],\"stats\":[\"some_invalid_param\"," + "\"another_invalid_param\"]}}"; + int buffer_read = 0; + errno = 0; + + ret = send(fd, invalid_contents, strlen(invalid_contents), 0); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not send message over socket"); + return -1; + } + + rte_telemetry_run(telemetry); + buffer_read = recv(fd, buf, BUF_SIZE-1, 0); + + if (buffer_read == -1) { + TELEMETRY_LOG_ERR("Read error"); + return -1; + } + + buf[buffer_read] = '\0'; + data_struct = calloc(1, sizeof(struct json_data)); + ret = rte_telemetry_stat_parse(buf, data_struct); + + if (ret < 0) + TELEMETRY_LOG_ERR("Could not parse stats"); + + if (strcmp(data_struct->status_code, status) != 0) { + TELEMETRY_LOG_ERR("Status code is invalid"); + fail_count++; + } + + if (strcmp(data_struct->data, data) != 0) { + TELEMETRY_LOG_ERR("Data status is invalid"); + fail_count++; + } + + rte_telemetry_free_test_data(data_struct); + if (fail_count > 0) + return -1; + + TELEMETRY_LOG_INFO("Success - Passed invalid JSON content test"); + + return 0; +} + +int32_t +rte_telemetry_json_empty_test(struct telemetry_impl *telemetry, int fd) +{ + int ret; + char buf[BUF_SIZE]; + int fail_count = 0; + const char *status = "Status Error: Invalid Argument 404"; + char *data = "null"; + struct json_data *data_struct; + const char *empty_json = "{}"; + int buffer_read = 0; + errno = 0; + + ret = (send(fd, empty_json, strlen(empty_json), 0)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not send message over socket"); + return -1; + } + + rte_telemetry_run(telemetry); + buffer_read = recv(fd, buf, BUF_SIZE-1, 0); + + if (buffer_read == -1) { + TELEMETRY_LOG_ERR("Read error"); + return -1; + } + + buf[buffer_read] = '\0'; + data_struct = calloc(1, sizeof(struct json_data)); + ret = rte_telemetry_stat_parse(buf, data_struct); + + if (ret < 0) + TELEMETRY_LOG_ERR("Could not parse stats"); + + if (strcmp(data_struct->status_code, status) != 0) { + TELEMETRY_LOG_ERR("Status code is invalid"); + fail_count++; + } + + if (strcmp(data_struct->data, data) != 0) { + TELEMETRY_LOG_ERR("Data status is invalid"); + fail_count++; + } + + rte_telemetry_free_test_data(data_struct); + + if (fail_count > 0) + return -1; + + TELEMETRY_LOG_INFO("Success - Passed JSON empty message test"); + + return 0; +} + +int32_t +rte_telemetry_json_socket_message_test(struct telemetry_impl *telemetry, int fd) +{ + uint16_t i; + int ret, fail_count; + + fail_count = 0; + struct telemetry_message_test socket_json_tests[] = { + {.test_name = "Invalid JSON test", + .test_func_ptr = rte_telemetry_invalid_json_test}, + {.test_name = "Valid JSON test", + .test_func_ptr = rte_telemetry_valid_json_test}, + {.test_name = "JSON contents test", + .test_func_ptr = rte_telemetry_json_contents_test}, + {.test_name = "JSON empty tests", + .test_func_ptr = rte_telemetry_json_empty_test} + }; + +#define NUM_TESTS RTE_DIM(socket_json_tests) + + for (i = 0; i < NUM_TESTS; i++) { + TELEMETRY_LOG_INFO("%s", socket_json_tests[i].test_name); + ret = (socket_json_tests[i].test_func_ptr) + (telemetry, fd); + if (ret < 0) { + TELEMETRY_LOG_ERR("%s failed", + socket_json_tests[i].test_name); + fail_count++; + } + } + + if (fail_count > 0) { + TELEMETRY_LOG_ERR("Failed %i JSON socket message test(s)", + fail_count); + return -1; + } + + TELEMETRY_LOG_INFO("Success - All JSON tests passed"); + + return 0; +} + int telemetry_log_level; RTE_INIT(rte_telemetry_register); diff --git a/lib/librte_telemetry/rte_telemetry.h b/lib/librte_telemetry/rte_telemetry.h index d3b0d8d..958723b 100644 --- a/lib/librte_telemetry/rte_telemetry.h +++ b/lib/librte_telemetry/rte_telemetry.h @@ -33,4 +33,16 @@ rte_telemetry_init(void); int32_t rte_telemetry_cleanup(void); +/** + * Runs various tests to ensure telemetry initialisation and register/unregister + * functions are working correctly. + * + * @return + * 0 on success when all tests have passed + * @return + * -1 on failure when the test has failed + */ +int32_t +rte_telemetry_selftest(void); + #endif diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h index 0082cb2..de7afda 100644 --- a/lib/librte_telemetry/rte_telemetry_internal.h +++ b/lib/librte_telemetry/rte_telemetry_internal.h @@ -75,4 +75,7 @@ int32_t rte_telemetry_send_ports_stats_values(uint32_t *metric_ids, int num_metric_ids, uint32_t *port_ids, int num_port_ids, struct telemetry_impl *telemetry); +int32_t +rte_telemetry_socket_messaging_testing(int index, int socket); + #endif diff --git a/lib/librte_telemetry/rte_telemetry_parser_test.c b/lib/librte_telemetry/rte_telemetry_parser_test.c new file mode 100644 index 0000000..9bf66a2 --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_parser_test.c @@ -0,0 +1,534 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rte_telemetry_parser.h" + +enum choices { + INV_ACTION_VAL, + INV_COMMAND_VAL, + INV_DATA_VAL, + INV_ACTION_FIELD, + INV_COMMAND_FIELD, + INV_DATA_FIELD, + INV_JSON_FORMAT, + VALID_REQ +}; + + +#define TEST_CLIENT "/var/run/dpdk/test_client" + +int32_t +rte_telemetry_create_test_socket(struct telemetry_impl *telemetry, + const char *test_client_path) +{ + int ret, sockfd; + struct sockaddr_un addr = {0}; + struct telemetry_client *client; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Telemetry argument has not been initialised"); + return -EINVAL; + } + + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) { + TELEMETRY_LOG_ERR("Test socket creation failure"); + return -1; + } + + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, test_client_path, sizeof(addr.sun_path)); + unlink(test_client_path); + + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + TELEMETRY_LOG_ERR("Test socket binding failure"); + return -1; + } + + if (listen(sockfd, 1) < 0) { + TELEMETRY_LOG_ERR("Listen failure"); + return -1; + } + + ret = rte_telemetry_register_client(telemetry, test_client_path); + if (ret < 0) { + TELEMETRY_LOG_ERR("Register dummy client failed: %i", ret); + return -1; + } + + ret = accept(sockfd, NULL, NULL); + if (ret < 0) { + TELEMETRY_LOG_ERR("Socket accept failed"); + return -1; + } + + TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) + telemetry->request_client = client; + + return 0; +} + +int32_t +rte_telemetry_format_port_stat_ids(int *port_ids, int num_port_ids, + const char * const *stat_names, int num_stat_names, json_t **data) +{ + + int ret; + json_t *stat_names_json_array = NULL; + json_t *port_ids_json_array = NULL; + uint32_t i; + + if (num_port_ids < 0) { + TELEMETRY_LOG_ERR("Port Ids Count invalid"); + goto fail; + } + + *data = json_object(); + if (*data == NULL) { + TELEMETRY_LOG_ERR("Data json object creation failed"); + goto fail; + } + + port_ids_json_array = json_array(); + if (port_ids_json_array == NULL) { + TELEMETRY_LOG_ERR("port_ids_json_array creation failed"); + goto fail; + } + + for (i = 0; i < (uint32_t)num_port_ids; i++) { + ret = json_array_append(port_ids_json_array, + json_integer(port_ids[i])); + if (ret < 0) { + TELEMETRY_LOG_ERR("JSON array creation failed"); + goto fail; + } + } + + ret = json_object_set_new(*data, "ports", port_ids_json_array); + if (ret < 0) { + TELEMETRY_LOG_ERR("Setting 'ports' value in data object failed"); + goto fail; + } + + if (stat_names) { + if (num_stat_names < 0) { + TELEMETRY_LOG_ERR("Stat Names Count invalid"); + goto fail; + } + + stat_names_json_array = json_array(); + if (stat_names_json_array == NULL) { + TELEMETRY_LOG_ERR("stat_names_json_array creation failed"); + goto fail; + } + + uint32_t i; + for (i = 0; i < (uint32_t)num_stat_names; i++) { + ret = json_array_append(stat_names_json_array, + json_string(stat_names[i])); + if (ret < 0) { + TELEMETRY_LOG_ERR("JSON array creation failed"); + goto fail; + } + } + + ret = json_object_set_new(*data, "stats", stat_names_json_array); + if (ret < 0) { + TELEMETRY_LOG_ERR("Setting 'stats' value in data object failed"); + goto fail; + } + } + + return 0; + +fail: + if (*data) + json_decref(*data); + if (stat_names_json_array) + json_decref(stat_names_json_array); + if (port_ids_json_array) + json_decref(port_ids_json_array); + return -1; +} + +int32_t +rte_telemetry_create_json_request(int action, char *command, + const char *client_path, int *port_ids, int num_port_ids, + const char * const *stat_names, int num_stat_names, char **request, + int inv_choice) +{ + int ret; + json_t *root = json_object(); + json_t *data; + + if (root == NULL) { + TELEMETRY_LOG_ERR("Could not create root json object"); + goto fail; + } + + if (inv_choice == INV_ACTION_FIELD) { + ret = json_object_set_new(root, "ac--on", json_integer(action)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Setting invalid action field in root object failed"); + goto fail; + } + } else { + ret = json_object_set_new(root, "action", json_integer(action)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Setting valid action field in root object failed"); + goto fail; + } + } + + if (inv_choice == INV_COMMAND_FIELD) { + ret = json_object_set_new(root, "co---nd", json_string(command)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Setting invalid command field in root object failed"); + goto fail; + } + } else { + ret = json_object_set_new(root, "command", json_string(command)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Setting valid command field in root object failed"); + goto fail; + } + } + + data = json_null(); + if (client_path) { + data = json_object(); + if (data == NULL) { + TELEMETRY_LOG_ERR("Data json object creation failed"); + goto fail; + } + + ret = json_object_set_new(data, "client_path", + json_string(client_path)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Setting valid client_path field in data object failed"); + goto fail; + } + + } else if (port_ids) { + ret = rte_telemetry_format_port_stat_ids(port_ids, num_port_ids, + stat_names, num_stat_names, &data); + if (ret < 0) { + TELEMETRY_LOG_ERR("Formatting Port/Stat arrays failed"); + goto fail; + } + + } + + if (inv_choice == INV_DATA_FIELD) { + ret = json_object_set_new(root, "d--a", data); + if (ret < 0) { + TELEMETRY_LOG_ERR("Setting invalid data field in data object failed"); + goto fail; + } + } else { + ret = json_object_set_new(root, "data", data); + if (ret < 0) { + TELEMETRY_LOG_ERR("Setting valid data field in data object failed"); + goto fail; + } + } + + *request = json_dumps(root, 0); + if (*request == NULL) { + TELEMETRY_LOG_ERR("Converting JSON root object to char* failed"); + goto fail; + } + + json_decref(root); + return 0; + +fail: + if (root) + json_decref(root); + return -1; +} + +int32_t +rte_telemetry_send_get_ports_and_stats_request(struct telemetry_impl *telemetry, + int action_choice, char *command_choice, int inv_choice) +{ + int ret; + char *request; + char *client_path_data = NULL; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Telemetry argument has not been initialised"); + return -EINVAL; + } + + + if (inv_choice == INV_ACTION_VAL) + action_choice = -1; + else if (inv_choice == INV_COMMAND_VAL) + command_choice = "INVALID_COMMAND"; + else if (inv_choice == INV_DATA_VAL) + client_path_data = "INVALID_DATA"; + + ret = rte_telemetry_create_json_request(action_choice, command_choice, + client_path_data, NULL, -1, NULL, -1, &request, inv_choice); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not create JSON Request"); + return -1; + } + + if (inv_choice == INV_JSON_FORMAT) + request++; + + ret = rte_telemetry_parse(telemetry, request); + if (ret < 0) { + TELEMETRY_LOG_WARN("Could not parse JSON Request"); + return -1; + } + + return 0; +} + +int32_t +rte_telemetry_send_get_ports_details_request(struct telemetry_impl *telemetry, + int action_choice, int *port_ids, int num_port_ids, int inv_choice) +{ + int ret; + char *request; + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Telemetry argument has not been initialised"); + return -EINVAL; + } + + char *command = "ports_details"; + + if (inv_choice == INV_ACTION_VAL) + action_choice = -1; + else if (inv_choice == INV_COMMAND_VAL) + command = "INVALID_COMMAND"; + else if (inv_choice == INV_DATA_VAL) + port_ids = NULL; + + + ret = rte_telemetry_create_json_request(action_choice, command, NULL, + port_ids, num_port_ids, NULL, -1, &request, inv_choice); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not create JSON Request"); + return -1; + } + + if (inv_choice == INV_JSON_FORMAT) + request++; + + ret = rte_telemetry_parse(telemetry, request); + if (ret < 0) { + TELEMETRY_LOG_WARN("Could not parse JSON Request"); + return -1; + } + + return 0; +} + +int32_t +rte_telemetry_send_stats_values_by_name_request(struct telemetry_impl + *telemetry, int action_choice, int *port_ids, int num_port_ids, + const char * const *stat_names, int num_stat_names, + int inv_choice) +{ + int ret; + char *request; + char *command = "ports_stats_values_by_name"; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Telemetry argument has not been initialised"); + return -EINVAL; + } + + if (inv_choice == INV_ACTION_VAL) + action_choice = -1; + else if (inv_choice == INV_COMMAND_VAL) + command = "INVALID_COMMAND"; + else if (inv_choice == INV_DATA_VAL) { + port_ids = NULL; + stat_names = NULL; + } + + ret = rte_telemetry_create_json_request(action_choice, command, NULL, + port_ids, num_port_ids, stat_names, num_stat_names, &request, + inv_choice); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not create JSON Request"); + return -1; + } + + if (inv_choice == INV_JSON_FORMAT) + request++; + + ret = rte_telemetry_parse(telemetry, request); + if (ret < 0) { + TELEMETRY_LOG_WARN("Could not parse JSON Request"); + return -1; + } + + return 0; +} + +int32_t +rte_telemetry_send_unreg_request(struct telemetry_impl *telemetry, + int action_choice, const char *client_path, int inv_choice) +{ + int ret; + char *request; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Telemetry argument has not been initialised"); + return -EINVAL; + } + + char *command = "clients"; + + if (inv_choice == INV_ACTION_VAL) + action_choice = -1; + else if (inv_choice == INV_COMMAND_VAL) + command = "INVALID_COMMAND"; + else if (inv_choice == INV_DATA_VAL) + client_path = NULL; + + ret = rte_telemetry_create_json_request(action_choice, command, + client_path, NULL, -1, NULL, -1, &request, inv_choice); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not create JSON Request"); + return -1; + } + + if (inv_choice == INV_JSON_FORMAT) + request++; + + ret = rte_telemetry_parse(telemetry, request); + if (ret < 0) { + TELEMETRY_LOG_WARN("Could not parse JSON Request"); + return -1; + } + + return 0; +} + +int32_t +rte_telemetry_parser_test(struct telemetry_impl *telemetry) +{ + int ret; + const char *client_path = TEST_CLIENT; + + if (telemetry == NULL) { + TELEMETRY_LOG_ERR("Telemetry argument has not been initialised"); + return -EINVAL; + } + + ret = rte_telemetry_create_test_socket(telemetry, client_path); + if (ret < 0) { + TELEMETRY_LOG_ERR("Could not create test request client socket"); + return -1; + } + + int port_ids[] = {0, 1}; + int num_port_ids = RTE_DIM(port_ids); + + static const char * const stat_names[] = {"tx_good_packets", + "rx_good_packets"}; + int num_stat_names = RTE_DIM(stat_names); + + static const char * const test_types[] = { + "INVALID ACTION VALUE TESTS", + "INVALID COMMAND VALUE TESTS", + "INVALID DATA VALUE TESTS", + "INVALID ACTION FIELD TESTS", + "INVALID COMMAND FIELD TESTS", + "INVALID DATA FIELD TESTS", + "INVALID JSON FORMAT TESTS", + "VALID TESTS" + }; + + +#define NUM_TEST_TYPES (sizeof(test_types)/sizeof(const char * const)) + + uint32_t i; + for (i = 0; i < NUM_TEST_TYPES; i++) { + TELEMETRY_LOG_INFO("%s", test_types[i]); + + ret = rte_telemetry_send_get_ports_and_stats_request(telemetry, + ACTION_GET, "ports", i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Get ports valid test failed"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Get ports invalid test failed"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Get ports test passed"); + + ret = rte_telemetry_send_get_ports_details_request(telemetry, + ACTION_GET, port_ids, num_port_ids, i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Get ports details valid"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Get ports details invalid"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Get ports details test passed"); + + ret = rte_telemetry_send_get_ports_and_stats_request(telemetry, + ACTION_GET, "port_stats", i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Get port stats valid test"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Get ports stats invalid test failed"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Get ports stats test passed"); + + ret = rte_telemetry_send_stats_values_by_name_request(telemetry, + ACTION_GET, port_ids, num_port_ids, stat_names, + num_stat_names, i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Get ports stats values by name valid test failed"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Get ports stats values by name invalid test failed"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Get ports stats values by name test passed"); + + ret = rte_telemetry_send_unreg_request(telemetry, ACTION_DELETE, + client_path, i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Deregister valid test failed"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Deregister invalid test failed"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Deregister test passed"); + } + + return 0; +} diff --git a/lib/librte_telemetry/rte_telemetry_parser_test.h b/lib/librte_telemetry/rte_telemetry_parser_test.h new file mode 100644 index 0000000..6ada852 --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_parser_test.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#ifndef _RTE_TELEMETRY_PARSER_TEST_H_ +#define _RTE_TELEMETRY_PARSER_TEST_H_ + +int32_t +rte_telemetry_parser_test(struct telemetry_impl *telemetry); + +int32_t +rte_telemetry_format_port_stat_ids(int *port_ids, int num_port_ids, + const char * const stat_names, int num_stat_names, json_t **data); + +int32_t +rte_telemetry_create_json_request(int action, char *command, + const char *client_path, int *port_ids, int num_port_ids, + const char * const stat_names, int num_stat_names, char **request, + int inv_choice); + +int32_t +rte_telemetry_send_get_ports_and_stats_request(struct telemetry_impl *telemetry, + int action_choice, char *command_choice, int inv_choice); + +int32_t +rte_telemetry_send_get_ports_details_request(struct telemetry_impl *telemetry, + int action_choice, int *port_ids, int num_port_ids, int inv_choice); + +int32_t +rte_telemetry_send_stats_values_by_name_request(struct telemetry_impl + *telemetry, int action_choice, int *port_ids, int num_port_ids, + const char * const stat_names, int num_stat_names, + int inv_choice); + +int32_t +rte_telemetry_send_unreg_request(int action_choice, const char *client_path, + int inv_choice); + +#endif diff --git a/lib/librte_telemetry/rte_telemetry_socket_tests.h b/lib/librte_telemetry/rte_telemetry_socket_tests.h new file mode 100644 index 0000000..db9167c --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_socket_tests.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include + +#include "rte_telemetry_internal.h" + +#ifndef _RTE_TELEMETRY_SOCKET_TESTING_H_ +#define _RTE_TELEMETRY_SOCKET_TESTING_H_ + +int32_t +rte_telemetry_json_socket_message_test(struct telemetry_impl *telemetry, + int fd); + +int32_t +rte_telemetry_invalid_json_test(struct telemetry_impl *telemetry, int fd); + +int32_t +rte_telemetry_valid_json_test(struct telemetry_impl *telemetry, int fd); + +int32_t +rte_telemetry_json_contents_test(struct telemetry_impl *telemetry, int fd); + +int32_t +rte_telemetry_json_empty_test(struct telemetry_impl *telemetry, int fd); + +int32_t +rte_telemetry_socket_register_test(struct telemetry_impl *telemetry, int *fd, + int send_fd, int recv_fd); + +int32_t +rte_telemetry_socket_test_setup(struct telemetry_impl *telemetry, int *send_fd, + int *recv_fd); + +#endif diff --git a/lib/librte_telemetry/rte_telemetry_version.map b/lib/librte_telemetry/rte_telemetry_version.map index 992d227..98459fc 100644 --- a/lib/librte_telemetry/rte_telemetry_version.map +++ b/lib/librte_telemetry/rte_telemetry_version.map @@ -2,5 +2,6 @@ DPDK_18.11 { global: rte_telemetry_init; + rte_telemetry_selftest; local: *; }; From patchwork Tue Oct 16 15:57:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46907 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 574611B156; Tue, 16 Oct 2018 17:58:28 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id E331F1B16A for ; Tue, 16 Oct 2018 17:58:09 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:58:09 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465429" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:58:07 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:57:59 +0100 Message-Id: <20181016155802.2067-11-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 10/13] telemetry: add ability to disable selftest X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch adds functionality to enable/disable the selftest. This functionality will be extended in future to make the enabling/disabling more dynamic and remove this 'hardcoded' approach. We are temporarily using this approach due to the design changes (vdev vs eal) made to the library. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- lib/librte_telemetry/rte_telemetry.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c index 82b46a5..7d97206 100644 --- a/lib/librte_telemetry/rte_telemetry.c +++ b/lib/librte_telemetry/rte_telemetry.c @@ -660,6 +660,7 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry) { uint16_t pid; int ret; + int selftest = 0; RTE_ETH_FOREACH_DEV(pid) { telemetry->reg_index = rte_telemetry_reg_ethdev_to_metrics(pid); @@ -672,18 +673,20 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry) } telemetry->metrics_register_done = 1; - ret = rte_telemetry_socket_messaging_testing(telemetry->reg_index, - telemetry->server_fd); - if (ret < 0) - return -1; + if (selftest) { + ret = rte_telemetry_socket_messaging_testing(telemetry->reg_index, + telemetry->server_fd); + if (ret < 0) + return -1; - ret = rte_telemetry_parser_test(telemetry); - if (ret < 0) { - TELEMETRY_LOG_ERR("Parser Tests Failed"); - return -1; - } + ret = rte_telemetry_parser_test(telemetry); + if (ret < 0) { + TELEMETRY_LOG_ERR("Parser Tests Failed"); + return -1; + } - TELEMETRY_LOG_INFO("Success - All Parser Tests Passed"); + TELEMETRY_LOG_INFO("Success - All Parser Tests Passed"); + } return 0; } From patchwork Tue Oct 16 15:58:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46908 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 415021B1AB; Tue, 16 Oct 2018 17:58:30 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id D4DB51B17E for ; Tue, 16 Oct 2018 17:58:12 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:58:12 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465452" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:58:09 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:58:00 +0100 Message-Id: <20181016155802.2067-12-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v5 11/13] doc: add telemetry documentation X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch adds all documentation for telemetry. A description on how to use the Telemetry API with a DPDK application is given in this document. It also adds the MAINTAINERS file entry for telemetry. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- MAINTAINERS | 5 +++ doc/guides/howto/index.rst | 1 + doc/guides/howto/telemetry.rst | 85 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 doc/guides/howto/telemetry.rst diff --git a/MAINTAINERS b/MAINTAINERS index 84b9ff7..e695a68 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1168,6 +1168,11 @@ F: test/bpf/ F: test/test/test_bpf.c F: doc/guides/prog_guide/bpf_lib.rst +Telemetry +M: Kevin Laatz +F: lib/librte_telemetry/ +F: usertools/dpdk-telemetry-client.py +F: doc/guides/howto/telemetry.rst Test Applications ----------------- diff --git a/doc/guides/howto/index.rst b/doc/guides/howto/index.rst index e13a090..a642a2b 100644 --- a/doc/guides/howto/index.rst +++ b/doc/guides/howto/index.rst @@ -17,3 +17,4 @@ HowTo Guides virtio_user_for_container_networking virtio_user_as_exceptional_path packet_capture_framework + telemetry diff --git a/doc/guides/howto/telemetry.rst b/doc/guides/howto/telemetry.rst new file mode 100644 index 0000000..3fcb061 --- /dev/null +++ b/doc/guides/howto/telemetry.rst @@ -0,0 +1,85 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation. + +DPDK Telemetry API User Guide +============================== + +This document describes how the Data Plane Development Kit(DPDK) Telemetry API +is used for querying port statistics from incoming traffic. + +Introduction +------------ + +The ``librte_telemetry`` provides the functionality so that users may query +metrics from incoming port traffic. The application which initializes packet +forwarding will act as the server, sending metrics to the requesting application +which acts as the client. + +In DPDK, applications are used to initialize the ``telemetry``. To view incoming +traffic on featured ports, the application should be run first (ie. after ports +are configured). Once the application is running, the service assurance agent +(for example the collectd plugin) should be run to begin querying the API. + +A client connects their Service Assurance application to the DPDK application +via a UNIX socket. Once a connection is established, a client can send JSON +messages to the DPDK application requesting metrics via another UNIX client. +This request is then handled and parsed if valid. The response is then +formatted in JSON and sent back to the requesting client. + +Pre-requisites +~~~~~~~~~~~~~~ + +* Python ≥ 2.5 + +* Jansson library for JSON serialization + +Test Environment +---------------- + +``telemetry`` offers a range of selftests that a client can run within +the DPDK application. + +Selftests are disabled by default. They can be enabled by setting the 'selftest' +variable to 1 in rte_telemetry_initial_accept(). + +Note: this 'hardcoded' value is temporary. + +Configuration +------------- + +Enable the telemetry API by modifying the following config option before +building DPDK:: + + CONFIG_RTE_LIBRTE_TELEMETRY=y + +Note: Meson will pick this up automatically if ``libjansson`` is available. + +Running the Application +----------------------- + +The following steps demonstrate how to run the ``telemetry`` API to query all +statistics on all active ports, using the ``telemetry_client`` python script +to query. +Note: This guide assumes packet generation is applicable and the user is +testing with testpmd as a DPDK primary application to forward packets, although +any DPDK application is applicable. + +#. Launch testpmd as the primary application with ``telemetry``.:: + + ./app/testpmd --telemetry + +#. Launch the ``telemetry`` python script with a client filepath.:: + + python usertools/telemetry_client.py /var/run/some_client + + The client filepath is going to be used to setup our UNIX connection with the + DPDK primary application, in this case ``testpmd`` + This will initialize a menu where a client can proceed to recursively query + statistics, request statistics once or unregister the file_path, thus exiting + the menu. + +#. Send traffic to any or all available ports from a traffic generator. + Select a query option(recursive or singular polling). + The metrics will then be displayed on the client terminal in JSON format. + +#. Once finished, unregister the client using the menu command. From patchwork Tue Oct 16 15:58:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46909 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5215A1B1CC; Tue, 16 Oct 2018 17:58:32 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id AC9121B14E for ; Tue, 16 Oct 2018 17:58:15 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:58:15 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465467" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:58:12 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Ciara Power , Brian Archbold , Kevin Laatz Date: Tue, 16 Oct 2018 16:58:01 +0100 Message-Id: <20181016155802.2067-13-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 12/13] usertools: add client python script for telemetry X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power This patch adds a python script which can be used as a demo client. The script is interactive and will allow the user to register, request statistics, and unregister. To run the script, an argument for the client file path must be passed in: "python telemetry_client.py ". This script is useful to see how the Telemetry API for DPDK is used, and how to make the initial connection. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- usertools/dpdk-telemetry-client.py | 116 +++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 usertools/dpdk-telemetry-client.py diff --git a/usertools/dpdk-telemetry-client.py b/usertools/dpdk-telemetry-client.py new file mode 100644 index 0000000..71c6be7 --- /dev/null +++ b/usertools/dpdk-telemetry-client.py @@ -0,0 +1,116 @@ +# SPDK-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +import socket +import os +import sys +import time + +BUFFER_SIZE = 200000 + +METRICS_REQ = "{\"action\":0,\"command\":\"ports_all_stat_values\",\"data\":null}" +API_REG = "{\"action\":1,\"command\":\"clients\",\"data\":{\"client_path\":\"" +API_UNREG = "{\"action\":2,\"command\":\"clients\",\"data\":{\"client_path\":\"" +DEFAULT_FP = "/var/run/dpdk/default_client" + +class Socket: + + def __init__(self): + self.send_fd = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.recv_fd = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.client_fd = None + + def __del__(self): + try: + self.send_fd.close() + self.recv_fd.close() + self.client_fd.close() + except: + print("Error - Sockets could not be closed") + +class Client: + + def __init__(self): # Creates a client instance + self.socket = Socket() + self.file_path = None + self.choice = None + self.unregistered = 0 + + def __del__(self): + try: + if self.unregistered == 0: + self.unregister(); + except: + print("Error - Client could not be destroyed") + + def getFilepath(self, file_path): # Gets arguments from Command-Line and assigns to instance of client + self.file_path = file_path + + def register(self): # Connects a client to DPDK-instance + if os.path.exists(self.file_path): + os.unlink(self.file_path) + try: + self.socket.recv_fd.bind(self.file_path) + except socket.error as msg: + print ("Error - Socket binding error: " + str(msg) + "\n") + self.socket.recv_fd.settimeout(2) + self.socket.send_fd.connect("/var/run/dpdk/rte/telemetry") + JSON = (API_REG + self.file_path + "\"}}") + self.socket.send_fd.sendall(JSON) + self.socket.recv_fd.listen(1) + self.socket.client_fd = self.socket.recv_fd.accept()[0] + + def unregister(self): # Unregister a given client + self.socket.client_fd.send(API_UNREG + self.file_path + "\"}}") + self.socket.client_fd.close() + + def requestMetrics(self): # Requests metrics for given client + self.socket.client_fd.send(METRICS_REQ) + data = self.socket.client_fd.recv(BUFFER_SIZE) + print "\nResponse: \n", str(data) + + def repeatedlyRequestMetrics(self, sleep_time): # Recursively requests metrics for given client + print("\nPlease enter the number of times you'd like to continuously request Metrics:") + n_requests = int(input("\n:")) + print("\033[F") #Removes the user input from screen, cleans it up + print("\033[K") + for i in range(n_requests): + self.requestMetrics() + time.sleep(sleep_time) + + def interactiveMenu(self, sleep_time): # Creates Interactive menu within the script + while self.choice != 3: + print("\nOptions Menu") + print("[1] Send for Metrics for all ports") + print("[2] Send for Metrics for all ports recursively") + print("[3] Unregister client") + + try: + self.choice = int(input("\n:")) + print("\033[F") #Removes the user input for screen, cleans it up + print("\033[K") + if self.choice == 1: + self.requestMetrics() + elif self.choice == 2: + self.repeatedlyRequestMetrics(sleep_time) + elif self.choice == 3: + self.unregister() + self.unregistered = 1 + else: + print("Error - Invalid request choice") + except: + pass + +if __name__ == "__main__": + + sleep_time = 1 + file_path = "" + if (len(sys.argv) == 2): + file_path = sys.argv[1] + else: + print("Warning - No filepath passed, using default (" + DEFAULT_FP + ").") + file_path = DEFAULT_FP + client = Client() + client.getFilepath(file_path) + client.register() + client.interactiveMenu(sleep_time) From patchwork Tue Oct 16 15:58:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Laatz X-Patchwork-Id: 46910 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 814D01B1D8; Tue, 16 Oct 2018 17:58:34 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 18DAC1B187 for ; Tue, 16 Oct 2018 17:58:17 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Oct 2018 08:58:17 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,389,1534834800"; d="scan'208";a="92465491" Received: from silpixa00397517.ir.intel.com (HELO silpixa00397517.ger.corp.intel.com) ([10.237.222.54]) by orsmga003.jf.intel.com with ESMTP; 16 Oct 2018 08:58:15 -0700 From: Kevin Laatz To: dev@dpdk.org Cc: harry.van.haaren@intel.com, stephen@networkplumber.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com, thomas@monjalon.net, mattias.ronnblom@ericsson.com, bruce.richardson@intel.com, Kevin Laatz Date: Tue, 16 Oct 2018 16:58:02 +0100 Message-Id: <20181016155802.2067-14-kevin.laatz@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20181016155802.2067-1-kevin.laatz@intel.com> References: <20181011165837.81030-1-kevin.laatz@intel.com> <20181016155802.2067-1-kevin.laatz@intel.com> Subject: [dpdk-dev] [PATCH v5 13/13] build: add dependency on telemetry to apps in meson X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch adds telemetry as a dependecy to all applications. Without these changes, the --telemetry flag will not be recognised and applications will fail to run if they want to enable telemetry. Signed-off-by: Bruce Richardson Signed-off-by: Kevin Laatz Acked-by: Harry van Haaren --- app/meson.build | 4 ++-- app/pdump/meson.build | 2 +- app/proc-info/meson.build | 2 +- app/test-bbdev/meson.build | 2 +- app/test-crypto-perf/meson.build | 2 +- app/test-pmd/meson.build | 2 +- config/meson.build | 3 +++ lib/meson.build | 1 + meson.build | 1 + 9 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/meson.build b/app/meson.build index 99e0b93..8e716bf 100644 --- a/app/meson.build +++ b/app/meson.build @@ -24,7 +24,7 @@ foreach app:apps # use "deps" for internal DPDK dependencies, and "ext_deps" for # external package/library requirements ext_deps = [] - deps = [] + deps = ['telemetry'] subdir(name) @@ -38,7 +38,7 @@ foreach app:apps link_libs = [] if get_option('default_library') == 'static' - link_libs = dpdk_drivers + link_libs = dpdk_static_libraries + dpdk_drivers endif if allow_experimental_apis diff --git a/app/pdump/meson.build b/app/pdump/meson.build index 988cb4e..116c27f 100644 --- a/app/pdump/meson.build +++ b/app/pdump/meson.build @@ -3,4 +3,4 @@ sources = files('main.c') allow_experimental_apis = true -deps = ['ethdev', 'kvargs', 'pdump'] +deps += ['ethdev', 'kvargs', 'pdump'] diff --git a/app/proc-info/meson.build b/app/proc-info/meson.build index 9c148e3..a52b2ee 100644 --- a/app/proc-info/meson.build +++ b/app/proc-info/meson.build @@ -3,4 +3,4 @@ sources = files('main.c') allow_experimental_apis = true -deps = ['ethdev', 'metrics'] +deps += ['ethdev', 'metrics'] diff --git a/app/test-bbdev/meson.build b/app/test-bbdev/meson.build index 653907d..eb8cc04 100644 --- a/app/test-bbdev/meson.build +++ b/app/test-bbdev/meson.build @@ -6,4 +6,4 @@ sources = files('main.c', 'test_bbdev_perf.c', 'test_bbdev_vector.c') allow_experimental_apis = true -deps = ['bbdev', 'bus_vdev'] +deps += ['bbdev', 'bus_vdev'] diff --git a/app/test-crypto-perf/meson.build b/app/test-crypto-perf/meson.build index eacd7a0..d735b18 100644 --- a/app/test-crypto-perf/meson.build +++ b/app/test-crypto-perf/meson.build @@ -12,4 +12,4 @@ sources = files('cperf_ops.c', 'cperf_test_vectors.c', 'cperf_test_verify.c', 'main.c') -deps = ['cryptodev'] +deps += ['cryptodev'] diff --git a/app/test-pmd/meson.build b/app/test-pmd/meson.build index a0b3be0..c24f75f 100644 --- a/app/test-pmd/meson.build +++ b/app/test-pmd/meson.build @@ -22,7 +22,7 @@ sources = files('cmdline.c', 'testpmd.c', 'txonly.c') -deps = ['ethdev', 'gro', 'gso', 'cmdline', 'metrics', 'meter', 'bus_pci'] +deps += ['ethdev', 'gro', 'gso', 'cmdline', 'metrics', 'meter', 'bus_pci'] if dpdk_conf.has('RTE_LIBRTE_PDUMP') deps += 'pdump' endif diff --git a/config/meson.build b/config/meson.build index 6f9228c..275f00b 100644 --- a/config/meson.build +++ b/config/meson.build @@ -21,6 +21,9 @@ toolchain = cc.get_id() dpdk_conf.set_quoted('RTE_TOOLCHAIN', toolchain) dpdk_conf.set('RTE_TOOLCHAIN_' + toolchain.to_upper(), 1) +add_project_link_arguments('-Wl,--no-as-needed', language: 'c') +dpdk_extra_ldflags += '-Wl,--no-as-needed' + # use pthreads add_project_link_arguments('-pthread', language: 'c') dpdk_extra_ldflags += '-pthread' diff --git a/lib/meson.build b/lib/meson.build index b5612ad..ef3f3a6 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -127,6 +127,7 @@ foreach l:libraries dependencies: shared_deps) dpdk_libraries = [shared_lib] + dpdk_libraries + dpdk_static_libraries = [static_lib] + dpdk_static_libraries endif # sources.length() > 0 set_variable('shared_' + libname, shared_dep) diff --git a/meson.build b/meson.build index c9af335..f3bddb2 100644 --- a/meson.build +++ b/meson.build @@ -12,6 +12,7 @@ project('DPDK', 'C', cc = meson.get_compiler('c') dpdk_conf = configuration_data() dpdk_libraries = [] +dpdk_static_libraries = [] dpdk_drivers = [] dpdk_extra_ldflags = []