* [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-17 9:41 ` Thomas Monjalon
2018-10-17 15:56 ` Gaëtan Rivet
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 02/13] eal: make get runtime dir function public Kevin Laatz
` (13 subsequent siblings)
14 siblings, 2 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
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 <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 <rte_devargs.h>
#include <rte_version.h>
#include <rte_vfio.h>
+#include <rte_param.h>
#include <rte_atomic.h>
#include <malloc_heap.h>
@@ -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 <unistd.h>
+#include <string.h>
+
+#include <rte_eal.h>
+#include <rte_param.h>
+
+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 <rte_atomic.h>
#include <malloc_heap.h>
#include <rte_vfio.h>
+#include <rte_param.h>
#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;
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure Kevin Laatz
@ 2018-10-17 9:41 ` Thomas Monjalon
2018-10-17 11:45 ` Gaëtan Rivet
2018-10-17 15:56 ` Gaëtan Rivet
1 sibling, 1 reply; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-17 9:41 UTC (permalink / raw)
To: Kevin Laatz
Cc: dev, harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, bruce.richardson
I still think all the wording is incorrect.
Please start by describing what is "param", "flag" and "option" in your mind.
They are all mentioned in this file.
Are you sure rte_param is the right name?
16/10/2018 17:57, Kevin Laatz:
> --- /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
[...]
> --- /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 <unistd.h>
> +#include <string.h>
> +
> +#include <rte_eal.h>
> +#include <rte_param.h>
> +
> +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;
> +}
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure
2018-10-17 9:41 ` Thomas Monjalon
@ 2018-10-17 11:45 ` Gaëtan Rivet
2018-10-17 13:46 ` Thomas Monjalon
2018-10-17 13:55 ` Laatz, Kevin
0 siblings, 2 replies; 219+ messages in thread
From: Gaëtan Rivet @ 2018-10-17 11:45 UTC (permalink / raw)
To: Thomas Monjalon
Cc: Kevin Laatz, dev, harry.van.haaren, stephen, shreyansh.jain,
mattias.ronnblom, bruce.richardson
Hi Thomas,
On Wed, Oct 17, 2018 at 11:41:53AM +0200, Thomas Monjalon wrote:
> I still think all the wording is incorrect.
> Please start by describing what is "param", "flag" and "option" in your mind.
> They are all mentioned in this file.
> Are you sure rte_param is the right name?
>
I suggested the name rte_param, I think the original proposal was
rte_lib_init, which to me unduly diminished the intent of these structures.
I think rte_param seems proper, this is a generic parameter object
description. The integer "enabled" is described as a flag in the
structure, as it is used to flag the init routine down the road to
trigger the init callback associated with this parameter.
eal_option is reminiscent of optarg / optind of getopt() family,
which seems fitting.
I don't mean to overstep Kevin's role defending his work, but given
that I proposed some of this naming and pushed for this direction to be
taken in the first place, I feel I should help explain my propositions.
rte_param could become rte_parameter or rte_option instead, eal_option
could become opt_string or opt_str, and so on, do you have specific
ideas about proper names?
>
> 16/10/2018 17:57, Kevin Laatz:
> > --- /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.
> > + *
Citing --telemetry here is a bad idea, this file is lib-agnostic,
--telemetry is not assured to be relevant.
> > + * 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.
> > + */
--
Gaëtan Rivet
6WIND
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure
2018-10-17 11:45 ` Gaëtan Rivet
@ 2018-10-17 13:46 ` Thomas Monjalon
2018-10-17 14:09 ` Laatz, Kevin
2018-10-17 13:55 ` Laatz, Kevin
1 sibling, 1 reply; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-17 13:46 UTC (permalink / raw)
To: Gaëtan Rivet
Cc: Kevin Laatz, dev, harry.van.haaren, stephen, shreyansh.jain,
mattias.ronnblom, bruce.richardson
17/10/2018 13:45, Gaëtan Rivet:
> Hi Thomas,
>
> On Wed, Oct 17, 2018 at 11:41:53AM +0200, Thomas Monjalon wrote:
> > I still think all the wording is incorrect.
> > Please start by describing what is "param", "flag" and "option" in your mind.
> > They are all mentioned in this file.
> > Are you sure rte_param is the right name?
> >
>
> I suggested the name rte_param, I think the original proposal was
> rte_lib_init, which to me unduly diminished the intent of these structures.
I think the right word is "run-time option".
An option can have a parameter.
If this API is not supporting options with parameters, the name is
really misleading.
> I think rte_param seems proper, this is a generic parameter object
> description. The integer "enabled" is described as a flag in the
> structure, as it is used to flag the init routine down the road to
> trigger the init callback associated with this parameter.
"enabled" can be documented as the result of the option parsing.
If the option is given to rte_eal_init, it becomes enabled.
> eal_option is reminiscent of optarg / optind of getopt() family,
> which seems fitting.
>
> I don't mean to overstep Kevin's role defending his work, but given
> that I proposed some of this naming and pushed for this direction to be
> taken in the first place, I feel I should help explain my propositions.
>
> rte_param could become rte_parameter or rte_option instead, eal_option
> could become opt_string or opt_str, and so on, do you have specific
> ideas about proper names?
rte_option looks OK.
The global picture may be better explained I think.
Any help with wording and documentation is appreciated, thanks.
> > 16/10/2018 17:57, Kevin Laatz:
> > > --- /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.
> > > + *
>
> Citing --telemetry here is a bad idea, this file is lib-agnostic,
> --telemetry is not assured to be relevant.
>
> > > + * 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.
> > > + */
>
>
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure
2018-10-17 13:46 ` Thomas Monjalon
@ 2018-10-17 14:09 ` Laatz, Kevin
2018-10-17 14:20 ` Thomas Monjalon
0 siblings, 1 reply; 219+ messages in thread
From: Laatz, Kevin @ 2018-10-17 14:09 UTC (permalink / raw)
To: Thomas Monjalon, Gaëtan Rivet
Cc: dev, harry.van.haaren, stephen, shreyansh.jain, mattias.ronnblom,
bruce.richardson
Hi Thomas,
On 17/10/2018 14:46, Thomas Monjalon wrote:
> 17/10/2018 13:45, Gaëtan Rivet:
>> Hi Thomas,
>>
>> On Wed, Oct 17, 2018 at 11:41:53AM +0200, Thomas Monjalon wrote:
>>> I still think all the wording is incorrect.
>>> Please start by describing what is "param", "flag" and "option" in your mind.
>>> They are all mentioned in this file.
>>> Are you sure rte_param is the right name?
>>>
>> I suggested the name rte_param, I think the original proposal was
>> rte_lib_init, which to me unduly diminished the intent of these structures.
> I think the right word is "run-time option".
> An option can have a parameter.
> If this API is not supporting options with parameters, the name is
> really misleading.
The option will be passed like any other EAL option. Right now it
doesn't support any parameters but in future we could add functionality
like we had with the --vdev solution where we can pass selftest=1 with
the telemetry option.
>
>> I think rte_param seems proper, this is a generic parameter object
>> description. The integer "enabled" is described as a flag in the
>> structure, as it is used to flag the init routine down the road to
>> trigger the init callback associated with this parameter.
> "enabled" can be documented as the result of the option parsing.
> If the option is given to rte_eal_init, it becomes enabled.
The Doxygen comments mention that the flag should initially be set to 0
and will be set to 1 if the option for the relevant callback is passed
to EAL when running your application.
>
>> eal_option is reminiscent of optarg / optind of getopt() family,
>> which seems fitting.
>>
>> I don't mean to overstep Kevin's role defending his work, but given
>> that I proposed some of this naming and pushed for this direction to be
>> taken in the first place, I feel I should help explain my propositions.
>>
>> rte_param could become rte_parameter or rte_option instead, eal_option
>> could become opt_string or opt_str, and so on, do you have specific
>> ideas about proper names?
> rte_option looks OK.
I'm happy to change it to rte_option if we have consensus on it :)
>
> The global picture may be better explained I think.
> Any help with wording and documentation is appreciated, thanks.
Thanks,
Kevin
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure
2018-10-17 14:09 ` Laatz, Kevin
@ 2018-10-17 14:20 ` Thomas Monjalon
0 siblings, 0 replies; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-17 14:20 UTC (permalink / raw)
To: Laatz, Kevin
Cc: Gaëtan Rivet, dev, harry.van.haaren, stephen,
shreyansh.jain, mattias.ronnblom, bruce.richardson
17/10/2018 16:09, Laatz, Kevin:
> Hi Thomas,
>
>
> On 17/10/2018 14:46, Thomas Monjalon wrote:
> > 17/10/2018 13:45, Gaëtan Rivet:
> >> Hi Thomas,
> >>
> >> On Wed, Oct 17, 2018 at 11:41:53AM +0200, Thomas Monjalon wrote:
> >>> I still think all the wording is incorrect.
> >>> Please start by describing what is "param", "flag" and "option" in your mind.
> >>> They are all mentioned in this file.
> >>> Are you sure rte_param is the right name?
> >>>
> >> I suggested the name rte_param, I think the original proposal was
> >> rte_lib_init, which to me unduly diminished the intent of these structures.
> > I think the right word is "run-time option".
> > An option can have a parameter.
> > If this API is not supporting options with parameters, the name is
> > really misleading.
> The option will be passed like any other EAL option. Right now it
> doesn't support any parameters but in future we could add functionality
> like we had with the --vdev solution where we can pass selftest=1 with
> the telemetry option.
> >
> >> I think rte_param seems proper, this is a generic parameter object
> >> description. The integer "enabled" is described as a flag in the
> >> structure, as it is used to flag the init routine down the road to
> >> trigger the init callback associated with this parameter.
> > "enabled" can be documented as the result of the option parsing.
> > If the option is given to rte_eal_init, it becomes enabled.
> The Doxygen comments mention that the flag should initially be set to 0
> and will be set to 1 if the option for the relevant callback is passed
> to EAL when running your application.
Saying "passed to EAL" is too vague.
You need to differentiate the option parsing and the init.
Both are done in EAL, that's why you need to be more specific.
> >> eal_option is reminiscent of optarg / optind of getopt() family,
> >> which seems fitting.
> >>
> >> I don't mean to overstep Kevin's role defending his work, but given
> >> that I proposed some of this naming and pushed for this direction to be
> >> taken in the first place, I feel I should help explain my propositions.
> >>
> >> rte_param could become rte_parameter or rte_option instead, eal_option
> >> could become opt_string or opt_str, and so on, do you have specific
> >> ideas about proper names?
> > rte_option looks OK.
> I'm happy to change it to rte_option if we have consensus on it :)
OK, thanks
> > The global picture may be better explained I think.
> > Any help with wording and documentation is appreciated, thanks.
>
> Thanks,
> Kevin
>
>
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure
2018-10-17 11:45 ` Gaëtan Rivet
2018-10-17 13:46 ` Thomas Monjalon
@ 2018-10-17 13:55 ` Laatz, Kevin
1 sibling, 0 replies; 219+ messages in thread
From: Laatz, Kevin @ 2018-10-17 13:55 UTC (permalink / raw)
To: Gaëtan Rivet, Thomas Monjalon
Cc: dev, harry.van.haaren, stephen, shreyansh.jain, mattias.ronnblom,
bruce.richardson
Hi Thomas,
On 17/10/2018 12:45, Gaëtan Rivet wrote:
> Hi Thomas,
>
> On Wed, Oct 17, 2018 at 11:41:53AM +0200, Thomas Monjalon wrote:
>> I still think all the wording is incorrect.
>> Please start by describing what is "param", "flag" and "option" in your mind.
>> They are all mentioned in this file.
>> Are you sure rte_param is the right name?
> I suggested the name rte_param, I think the original proposal was
> rte_lib_init, which to me unduly diminished the intent of these structures.
>
> I think rte_param seems proper, this is a generic parameter object
> description. The integer "enabled" is described as a flag in the
> structure, as it is used to flag the init routine down the road to
> trigger the init callback associated with this parameter.
The purpose of "enabled" is to avoid redundantly calling all of the
callbacks in rte_param_list. Enabled should always be initialized to 0
by the library (as described in the Doxygen comment) and it will be set
if the 'option' for the callback is passed to EAL when running the
application (this is done in rte_param_parse).
To avoid confusion, I have renamed eal_flag to eal_option in the param
struct and reworded the Doxygen comments accordingly. The only place
flag is mentioned now is for "enabled".
>
> eal_option is reminiscent of optarg / optind of getopt() family,
> which seems fitting.
>
> I don't mean to overstep Kevin's role defending his work, but given
> that I proposed some of this naming and pushed for this direction to be
> taken in the first place, I feel I should help explain my propositions.
>
> rte_param could become rte_parameter or rte_option instead, eal_option
> could become opt_string or opt_str, and so on, do you have specific
> ideas about proper names?
I think rte_param was an improvement on rte_lib_init, for reasons
mentioned by Gaetan.
I am open to renaming it if you have any better, more descriptive name
in mind?
<snip>
Thanks,
Kevin
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure Kevin Laatz
2018-10-17 9:41 ` Thomas Monjalon
@ 2018-10-17 15:56 ` Gaëtan Rivet
2018-10-18 15:58 ` Laatz, Kevin
1 sibling, 1 reply; 219+ messages in thread
From: Gaëtan Rivet @ 2018-10-17 15:56 UTC (permalink / raw)
To: Kevin Laatz
Cc: dev, harry.van.haaren, stephen, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson
Some suggestions,
On Tue, Oct 16, 2018 at 04:57:50PM +0100, Kevin Laatz wrote:
> 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 <kevin.laatz@intel.com>
> Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
> ---
> 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 <rte_devargs.h>
> #include <rte_version.h>
> #include <rte_vfio.h>
> +#include <rte_param.h>
> #include <rte_atomic.h>
> #include <malloc_heap.h>
>
> @@ -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.
This API offers the ability to register options to the EAL command line
and map those options to functions, that will be executed at the end of
EAL initialization. These options will be available as part of the EAL
command line of applications and are dynamically managed.
This is used primarily by DPDK libraries offering command line options.
Currently, this API is limited to registering options without argument.
> + */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +typedef int (*rte_param_cb)(void);
> +
> +/*
/**
> + * Structure containing parameters relating to the function being registered
> + * with EAL.
Structure describing the EAL command line option being registered.
> + */
> +struct rte_param {
As said earlier, rte_option instead.
> + TAILQ_ENTRY(rte_param) next; /** The next entry in the TAILQ*/
^ missing a '<' here for doxygen,
and a space after TAILQ.
/**< Next entry. */
or
/**< Next entry in the list. */
Also reads better, TAILQ is
implementation detail, not too useful
in API doc.
Also missing a period.
> + char *eal_option; /** The EAL option */
*opt_str; /**< The option name. */
> + rte_param_cb cb; /** Function pointer of the callback */
cb; /**< Function called when the option is used. */
> +
> + /**
> + * 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;
/**< Set when the option is used. */
> +};
> +
> +/**
> + * @internal Check if the passed option is valid
Check if option is registered.
> + *
> + * @param option
> + * The option to be parsed
> + *
> + * @return
> + * 0 on success
> + * @return
> + * -1 on fail
> + */
> +int
> +rte_param_parse(char *option);
This should probably be a const char *.
Also, internal functions must not be part of public headers.
Move the prototype to eal_private.h instead.
> +
> +/**
> + * @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.
> + */
Register an option to the EAL command line.
When recognized, the associated function will
be executed at the end of EAL initialization.
The associated structure must be available the whole time
this option is registered (i.e. not stack memory)
@param option
Structure describing the option to parse.
> +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.
Iterate through registered options and execute the associated callback
if enabled.
> + *
> + * @return
> + * 0 on success
> + * @return
> + * -1 on fail
> + */
> +int
> +rte_param_init(void);
This function prototype should be added to eal_private.h instead.
Maybe missing: rte_option_unregister, to be executed in .FINI, if a
plugin is unloaded.
> +
> +#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 <unistd.h>
> +#include <string.h>
> +
> +#include <rte_eal.h>
> +#include <rte_param.h>
> +
> +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);
What happens when an option already exists in the list?
> +}
> +
> +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 <rte_atomic.h>
> #include <malloc_heap.h>
> #include <rte_vfio.h>
> +#include <rte_param.h>
>
> #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");
It would be better to be able to know which function failed
and why. "Callback failed" is not helpful to the user.
Maybe rte_option_init() return value should be expanded to allow
for error string, error value to be passed, that could come from the
library itself, or simply printing the option name that is the source of
the error.
> + 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;
> --
> 2.9.5
>
Best regards,
--
Gaëtan Rivet
6WIND
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure
2018-10-17 15:56 ` Gaëtan Rivet
@ 2018-10-18 15:58 ` Laatz, Kevin
0 siblings, 0 replies; 219+ messages in thread
From: Laatz, Kevin @ 2018-10-18 15:58 UTC (permalink / raw)
To: Gaëtan Rivet
Cc: dev, harry.van.haaren, stephen, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson
Hi Gaetan,
Thanks for reviewing and providing suggestions.
On 17/10/2018 16:56, Gaëtan Rivet wrote:
>> +
>> +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);
> What happens when an option already exists in the list?
Will add a check to avoid option duplication, good spot. Thanks
>> @@ -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");
> It would be better to be able to know which function failed
> and why. "Callback failed" is not helpful to the user.
> Maybe rte_option_init() return value should be expanded to allow
> for error string, error value to be passed, that could come from the
> library itself, or simply printing the option name that is the source of
> the error.
I agree that the error message is not helpful. Expanding the return
value to pass the option name or more would be difficult however as we
would need to check for success/fail of the execution of the callback in
rte_option_init(). Since the we don't know what the return type of a
given registered callback is, it is difficult to do the error checking here.
With that in mind, I think it might be best to leave the library's
function do the error checking itself, and changing the return type of
rte_option_init() to void. This way we could get library specific errors
using RTE_LOG, for example. Thoughts?
Best regards,
Kevin
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 02/13] eal: make get runtime dir function public
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 03/13] telemetry: initial telemetry infrastructure Kevin Laatz
` (12 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
This patch makes the eal_get_runtime_dir() API public so it can be used
from outside EAL.
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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;
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 03/13] telemetry: initial telemetry infrastructure
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 01/13] eal: add param register infrastructure Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 02/13] eal: make get runtime dir function public Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 04/13] telemetry: add initial connection socket Kevin Laatz
` (11 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 <unistd.h>
+#include <pthread.h>
+
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_metrics.h>
+#include <rte_param.h>
+
+#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 <stdint.h>
+
+#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 <rte_log.h>
+
+#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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 04/13] telemetry: add initial connection socket
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (2 preceding siblings ...)
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 03/13] telemetry: initial telemetry infrastructure Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 05/13] telemetry: add client feature and sockets Kevin Laatz
` (10 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 <unistd.h>
+#include <fcntl.h>
#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_metrics.h>
#include <rte_param.h>
+#include <rte_string_fns.h>
#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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 05/13] telemetry: add client feature and sockets
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (3 preceding siblings ...)
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 04/13] telemetry: add initial connection socket Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 06/13] telemetry: add parser for client socket messages Kevin Laatz
` (9 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <jansson.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
@@ -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 <rte_log.h>
+#include <rte_tailq.h>
#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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 06/13] telemetry: add parser for client socket messages
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (4 preceding siblings ...)
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 05/13] telemetry: add client feature and sockets Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 07/13] telemetry: update metrics before sending stats Kevin Laatz
` (8 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+
+#include <rte_metrics.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+
+#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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 07/13] telemetry: update metrics before sending stats
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (5 preceding siblings ...)
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 06/13] telemetry: add parser for client socket messages Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 08/13] telemetry: format json response when " Kevin Laatz
` (7 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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;
}
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 08/13] telemetry: format json response when sending stats
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (6 preceding siblings ...)
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 07/13] telemetry: update metrics before sending stats Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 09/13] telemetry: add tests for telemetry api Kevin Laatz
` (6 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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");
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 09/13] telemetry: add tests for telemetry api
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (7 preceding siblings ...)
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 08/13] telemetry: format json response when " Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 10/13] telemetry: add ability to disable selftest Kevin Laatz
` (5 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_tailq.h>
+#include <rte_string_fns.h>
+
+#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 <stdbool.h>
+
+#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: *;
};
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 10/13] telemetry: add ability to disable selftest
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (8 preceding siblings ...)
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 09/13] telemetry: add tests for telemetry api Kevin Laatz
@ 2018-10-16 15:57 ` Kevin Laatz
2018-10-16 15:58 ` [dpdk-dev] [PATCH v5 11/13] doc: add telemetry documentation Kevin Laatz
` (4 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:57 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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;
}
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 11/13] doc: add telemetry documentation
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (9 preceding siblings ...)
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 10/13] telemetry: add ability to disable selftest Kevin Laatz
@ 2018-10-16 15:58 ` Kevin Laatz
2018-10-16 15:58 ` [dpdk-dev] [PATCH v5 12/13] usertools: add client python script for telemetry Kevin Laatz
` (3 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:58 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 <kevin.laatz@intel.com>
+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.
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 12/13] usertools: add client python script for telemetry
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (10 preceding siblings ...)
2018-10-16 15:58 ` [dpdk-dev] [PATCH v5 11/13] doc: add telemetry documentation Kevin Laatz
@ 2018-10-16 15:58 ` Kevin Laatz
2018-10-16 15:58 ` [dpdk-dev] [PATCH v5 13/13] build: add dependency on telemetry to apps in meson Kevin Laatz
` (2 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:58 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <file_path>".
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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)
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v5 13/13] build: add dependency on telemetry to apps in meson
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (11 preceding siblings ...)
2018-10-16 15:58 ` [dpdk-dev] [PATCH v5 12/13] usertools: add client python script for telemetry Kevin Laatz
@ 2018-10-16 15:58 ` Kevin Laatz
2018-10-18 8:07 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Mattias Rönnblom
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-16 15:58 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
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 <bruce.richardson@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 = []
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 00/13] introduce telemetry library
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (12 preceding siblings ...)
2018-10-16 15:58 ` [dpdk-dev] [PATCH v5 13/13] build: add dependency on telemetry to apps in meson Kevin Laatz
@ 2018-10-18 8:07 ` Mattias Rönnblom
2018-10-19 10:16 ` Laatz, Kevin
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
14 siblings, 1 reply; 219+ messages in thread
From: Mattias Rönnblom @ 2018-10-18 8:07 UTC (permalink / raw)
To: Kevin Laatz, dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
bruce.richardson
Most of the issues I pointed out in v2 of this patchset is still here.
On 2018-10-16 17:57, Kevin Laatz wrote:
> This patchset introduces a Telemetry library for DPDK Service Assurance.
> This library provides an easy way to query DPDK Ethdev metrics.
>
> The telemetry library provides a method for a service assurance component
> to retrieve metrics from a DPDK packet forwarding application.
> Communicating from the service assurance component to DPDK is done using a
> UNIX domain socket, passing a JSON formatted string. A reply is sent (again
> a JSON formatted string) of the current DPDK metrics.
>
> The telemetry component makes use of the existing rte_metrics library to
> query values. The values to be transmitted via the telemetry infrastructure
> must be present in the Metrics library. Currently the ethdev values are
> pushed to the metrics library, and the queried from there there is an open
> question on how applications would like this to occur. Currently only
> ethdev to metrics functionality is implemented, however other subsystems
> like crypto, eventdev, keepalive etc can use similar mechanisms.
>
> Exposing DPDK Telemetry via a socket interface enables service assurance
> agents like collectd to consume data from DPDK. This is vital for
> monitoring, fault-detection, and error reporting. A collectd plugin has
> been created to interact with the DPDK Telemetry component, showing how it
> can be used in practice. The collectd plugin will be upstreamed to collectd
> at a later stage. A small python script is provided in
> ./usertools/telemetry_client.py to quick-start using DPDK Telemetry.
>
> Note: Despite opterr being set to 0, --telemetry said to be 'unrecognized'
> as a startup print. This is a cosmetic issue and will be addressed in the
> future.
>
> ---
> v2:
> - Reworked telemetry as part of EAL instead of using vdev (Gaetan)
> - Refactored rte_telemetry_command (Gaetan)
> - Added MAINTAINERS file entry (Stephen)
> - Updated docs to reflect vdev to eal rework
> - Removed collectd patch from patchset (Thomas)
> - General code clean up from v1 feedback
>
> v3:
> - Reworked registering with eal and moved to rte_param (Gaetan)
> - Added BSD implementation for rte_param (Gaetan)
> - Updated the paths to align with the new runtime file location (Mattias)
> - Fixed pointer checks to align with the coding style 1.8.1 (Mattias)
> - Added missing decref's and close's (Mattias)
> - Fixed runtime issue in Meson (was not recognising flag due to linking)
> - More general clean up
>
> v4:
> - Added Doxygen comments for rte_param.h (Thomas)
> - Made eal_get_runtime_dir a public function to use outside of EAL (Thomas)
> - Reworked telemetry to get path using rte_eal_get_runtime_dir (Thomas)
> - Fixed checkpatch coding style error
>
> v5:
> - Moved the BUF_SIZE define to fix build (Harry)
> - Set default config for telemetry to 'n' (Harry)
> - Improved Doxygen comments (Thomas)
> - Cleaned up rte_param struct (Thomas)
>
> Ciara Power, Brian Archbold and Kevin Laatz (10):
> telemetry: initial telemetry infrastructure
> telemetry: add initial connection socket
> telemetry: add client feature and sockets
> telemetry: add parser for client socket messages
> telemetry: update metrics before sending stats
> telemetry: format json response when sending stats
> telemetry: add tests for telemetry api
> telemetry: add ability to disable selftest
> doc: add telemetry documentation
> usertools: add client python script for telemetry
>
> Kevin Laatz (3):
> eal: add param register infrastructure
> eal: make get runtime dir function public
> build: add dependency on telemetry to apps in meson
>
> MAINTAINERS | 5 +
> 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/common_base | 5 +
> config/meson.build | 3 +
> doc/guides/howto/index.rst | 1 +
> doc/guides/howto/telemetry.rst | 85 +
> lib/Makefile | 2 +
> lib/librte_eal/bsdapp/eal/Makefile | 1 +
> lib/librte_eal/bsdapp/eal/eal.c | 20 +-
> lib/librte_eal/common/Makefile | 1 +
> lib/librte_eal/common/eal_filesystem.h | 14 +-
> lib/librte_eal/common/include/rte_eal.h | 9 +
> 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 | 20 +-
> lib/librte_eal/rte_eal_version.map | 2 +
> lib/librte_telemetry/Makefile | 30 +
> lib/librte_telemetry/meson.build | 9 +
> lib/librte_telemetry/rte_telemetry.c | 1810 +++++++++++++++++++++
> lib/librte_telemetry/rte_telemetry.h | 48 +
> lib/librte_telemetry/rte_telemetry_internal.h | 81 +
> lib/librte_telemetry/rte_telemetry_parser.c | 586 +++++++
> lib/librte_telemetry/rte_telemetry_parser.h | 13 +
> 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 | 7 +
> lib/meson.build | 3 +-
> meson.build | 1 +
> mk/rte.app.mk | 1 +
> usertools/dpdk-telemetry-client.py | 116 ++
> 38 files changed, 3618 insertions(+), 19 deletions(-)
> create mode 100644 doc/guides/howto/telemetry.rst
> create mode 100644 lib/librte_eal/common/include/rte_param.h
> create mode 100644 lib/librte_eal/common/rte_param.c
> 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_parser.c
> create mode 100644 lib/librte_telemetry/rte_telemetry_parser.h
> 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
> create mode 100644 lib/librte_telemetry/rte_telemetry_version.map
> create mode 100644 usertools/dpdk-telemetry-client.py
>
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 00/13] introduce telemetry library
2018-10-18 8:07 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Mattias Rönnblom
@ 2018-10-19 10:16 ` Laatz, Kevin
2018-10-22 7:11 ` Mattias Rönnblom
0 siblings, 1 reply; 219+ messages in thread
From: Laatz, Kevin @ 2018-10-19 10:16 UTC (permalink / raw)
To: Mattias Rönnblom, dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
bruce.richardson
Hi Mattias,
On 18/10/2018 09:07, Mattias Rönnblom wrote:
> Most of the issues I pointed out in v2 of this patchset is still here.
Will recheck feedback for the next version.
With regards to comments on v2, 3/10, could you please help provide
clarification on the below?
<Copy from the v2 feedback>
On 03/10/2018 20:06, Mattias Rönnblom wrote:
> On 2018-10-03 19:36, Kevin Laatz wrote:
>> From: Ciara Power <ciara.power@intel.com>
>> +
>> + if (!telemetry->request_client) {
>> + TELEMETRY_LOG_ERR("No client has been chosen to write to");
>> + return -1;
>> + } > +
>> + if (!json_string) {
>> + TELEMETRY_LOG_ERR("Invalid JSON string!");
>> + return -1;
>> + }
>> +
>> + ret = send(telemetry->request_client->fd,
>> + json_string, strlen(json_string), 0);
>
> How would this code handle a partial success (as in, for example, half
> of the string fits the socket buffer)? In not, maybe switching over to
> a SOCK_SEQPACKET AF_UNIX socket would be the best way around it.
>
Is the suggestion here simply to use socket(AF_UNIX, SOCK_SEQPACKET)
instead of (AF_UNIX, SOCK_STREAM) ?
>
>> +
>> + buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
>
> This and the below code seem to assume that read() returns one and
> only one message, but on a SOCK_STREAM, there is no such thing as a
> message. It's a byte stream, and you need to provide your own framing,
> or have an application protocol which allows only have one outstanding
> request. If you do the latter, you still need to allow for "short"
> (partial) read()s (i.e. re-read() until done).
>
Will the above solve this part of the problem too?
Best regards,
Kevin
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 00/13] introduce telemetry library
2018-10-19 10:16 ` Laatz, Kevin
@ 2018-10-22 7:11 ` Mattias Rönnblom
2018-10-22 9:03 ` Laatz, Kevin
0 siblings, 1 reply; 219+ messages in thread
From: Mattias Rönnblom @ 2018-10-22 7:11 UTC (permalink / raw)
To: Laatz, Kevin, dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
bruce.richardson
On 2018-10-19 12:16, Laatz, Kevin wrote:
> On 03/10/2018 20:06, Mattias Rönnblom wrote:
>> On 2018-10-03 19:36, Kevin Laatz wrote:
>>> From: Ciara Power <ciara.power@intel.com>
>>> +
>>> + if (!telemetry->request_client) {
>>> + TELEMETRY_LOG_ERR("No client has been chosen to write to");
>>> + return -1;
>>> + } > +
>>> + if (!json_string) {
>>> + TELEMETRY_LOG_ERR("Invalid JSON string!");
>>> + return -1;
>>> + }
>>> +
>>> + ret = send(telemetry->request_client->fd,
>>> + json_string, strlen(json_string), 0);
>>
>> How would this code handle a partial success (as in, for example, half
>> of the string fits the socket buffer)? In not, maybe switching over to
>> a SOCK_SEQPACKET AF_UNIX socket would be the best way around it.
>>
> Is the suggestion here simply to use socket(AF_UNIX, SOCK_SEQPACKET)
> instead of (AF_UNIX, SOCK_STREAM) ?
That would be the most straight-forward to the problem, I think. Linux'
SOCK_SEQPACKET implementation has problems with really large messages
(since a per-message linear buffer is allocated), but I'm guessing these
messages are not in the hundreds-of-kb range.
>>
>>> +
>>> + buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
>>
>> This and the below code seem to assume that read() returns one and
>> only one message, but on a SOCK_STREAM, there is no such thing as a
>> message. It's a byte stream, and you need to provide your own framing,
>> or have an application protocol which allows only have one outstanding
>> request. If you do the latter, you still need to allow for "short"
>> (partial) read()s (i.e. re-read() until done).
>>
> Will the above solve this part of the problem too?
>
Yes. The kernel will delivered the application (at most) one message, in
its entirety.
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v5 00/13] introduce telemetry library
2018-10-22 7:11 ` Mattias Rönnblom
@ 2018-10-22 9:03 ` Laatz, Kevin
0 siblings, 0 replies; 219+ messages in thread
From: Laatz, Kevin @ 2018-10-22 9:03 UTC (permalink / raw)
To: Mattias Rönnblom, dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
bruce.richardson
Hi Mattias,
Thanks for the input and clarification. I will include these changes in
the v6.
Regards,
Kevin
On 22/10/2018 08:11, Mattias Rönnblom wrote:
> On 2018-10-19 12:16, Laatz, Kevin wrote:
>> On 03/10/2018 20:06, Mattias Rönnblom wrote:
>>> On 2018-10-03 19:36, Kevin Laatz wrote:
>>>> From: Ciara Power <ciara.power@intel.com>
>>>> +
>>>> + if (!telemetry->request_client) {
>>>> + TELEMETRY_LOG_ERR("No client has been chosen to write to");
>>>> + return -1;
>>>> + } > +
>>>> + if (!json_string) {
>>>> + TELEMETRY_LOG_ERR("Invalid JSON string!");
>>>> + return -1;
>>>> + }
>>>> +
>>>> + ret = send(telemetry->request_client->fd,
>>>> + json_string, strlen(json_string), 0);
>>>
>>> How would this code handle a partial success (as in, for example,
>>> half of the string fits the socket buffer)? In not, maybe switching
>>> over to a SOCK_SEQPACKET AF_UNIX socket would be the best way around
>>> it.
>>>
>> Is the suggestion here simply to use socket(AF_UNIX, SOCK_SEQPACKET)
>> instead of (AF_UNIX, SOCK_STREAM) ?
>
> That would be the most straight-forward to the problem, I think.
> Linux' SOCK_SEQPACKET implementation has problems with really large
> messages (since a per-message linear buffer is allocated), but I'm
> guessing these messages are not in the hundreds-of-kb range.
>
>>>
>>>> +
>>>> + buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
>>>
>>> This and the below code seem to assume that read() returns one and
>>> only one message, but on a SOCK_STREAM, there is no such thing as a
>>> message. It's a byte stream, and you need to provide your own
>>> framing, or have an application protocol which allows only have one
>>> outstanding request. If you do the latter, you still need to allow
>>> for "short" (partial) read()s (i.e. re-read() until done).
>>>
>> Will the above solve this part of the problem too?
>>
>
> Yes. The kernel will delivered the application (at most) one message,
> in its entirety.
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 00/13] introduce telemetry library
2018-10-16 15:57 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Kevin Laatz
` (13 preceding siblings ...)
2018-10-18 8:07 ` [dpdk-dev] [PATCH v5 00/13] introduce telemetry library Mattias Rönnblom
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 01/13] eal: add option register infrastructure Kevin Laatz
` (13 more replies)
14 siblings, 14 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
This patchset introduces a Telemetry library for DPDK Service Assurance.
This library provides an easy way to query DPDK Ethdev metrics.
The telemetry library provides a method for a service assurance component
to retrieve metrics from a DPDK packet forwarding application.
Communicating from the service assurance component to DPDK is done using a
UNIX domain socket, passing a JSON formatted string. A reply is sent (again
a JSON formatted string) of the current DPDK metrics.
The telemetry component makes use of the existing rte_metrics library to
query values. The values to be transmitted via the telemetry infrastructure
must be present in the Metrics library. Currently the ethdev values are
pushed to the metrics library, and the queried from there there is an open
question on how applications would like this to occur. Currently only
ethdev to metrics functionality is implemented, however other subsystems
like crypto, eventdev, keepalive etc can use similar mechanisms.
Exposing DPDK Telemetry via a socket interface enables service assurance
agents like collectd to consume data from DPDK. This is vital for
monitoring, fault-detection, and error reporting. A collectd plugin has
been created to interact with the DPDK Telemetry component, showing how it
can be used in practice. The collectd plugin will be upstreamed to collectd
at a later stage. A small python script is provided in
./usertools/telemetry_client.py to quick-start using DPDK Telemetry.
Note: Despite opterr being set to 0, --telemetry said to be 'unrecognized'
as a startup print. This is a cosmetic issue and will be addressed in the
future.
---
v2:
- Reworked telemetry as part of EAL instead of using vdev (Gaetan)
- Refactored rte_telemetry_command (Gaetan)
- Added MAINTAINERS file entry (Stephen)
- Updated docs to reflect vdev to eal rework
- Removed collectd patch from patchset (Thomas)
- General code clean up from v1 feedback
v3:
- Reworked registering with eal and moved to rte_param (Gaetan)
- Added BSD implementation for rte_param (Gaetan)
- Updated the paths to align with the new runtime file location (Mattias)
- Fixed pointer checks to align with the coding style 1.8.1 (Mattias)
- Added missing decref's and close's (Mattias)
- Fixed runtime issue in Meson (was not recognising flag due to linking)
- More general clean up
v4:
- Added Doxygen comments for rte_param.h (Thomas)
- Made eal_get_runtime_dir a public function to use outside of EAL (Thomas)
- Reworked telemetry to get path using rte_eal_get_runtime_dir (Thomas)
- Fixed checkpatch coding style error
v5:
- Moved the BUF_SIZE define to fix build (Harry)
- Set default config for telemetry to 'n' (Harry)
- Improved Doxygen comments (Thomas)
- Cleaned up rte_param struct (Thomas)
v6:
- Renamed rte_param to rte_option (Thomas)
- Moved internal functions to eal_private.h (Gaetan)
- Added fail check for pthread_attr_init() (Mattias)
- Changed socket implementation to SOCK_SEQPACKET (Mattias)
- Added check to avoid option duplicates (Gaetan)
- Removed telemetry specifics from Doxygen comment (Gaetan)
- General Doxygen clean-up (Thomas)
- General code clean-up
Ciara Power, Brian Archbold and Kevin Laatz (10):
telemetry: initial telemetry infrastructure
telemetry: add initial connection socket
telemetry: add client feature and sockets
telemetry: add parser for client socket messages
telemetry: update metrics before sending stats
telemetry: format json response when sending stats
telemetry: add tests for telemetry api
telemetry: add ability to disable selftest
doc: add telemetry documentation
usertools: add client python script for telemetry
Kevin Laatz (3):
eal: add option register infrastructure
eal: make get runtime dir function public
build: add dependency on telemetry to apps in meson
MAINTAINERS | 5 +
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/common_base | 5 +
config/meson.build | 3 +
doc/guides/howto/index.rst | 1 +
doc/guides/howto/telemetry.rst | 85 +
lib/Makefile | 2 +
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 16 +-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_filesystem.h | 15 +-
lib/librte_eal/common/eal_private.h | 21 +
lib/librte_eal/common/include/rte_eal.h | 9 +
lib/librte_eal/common/include/rte_option.h | 63 +
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 16 +-
lib/librte_eal/rte_eal_version.map | 2 +
lib/librte_telemetry/Makefile | 30 +
lib/librte_telemetry/meson.build | 9 +
lib/librte_telemetry/rte_telemetry.c | 1816 +++++++++++++++++++++
lib/librte_telemetry/rte_telemetry.h | 48 +
lib/librte_telemetry/rte_telemetry_internal.h | 81 +
lib/librte_telemetry/rte_telemetry_parser.c | 586 +++++++
lib/librte_telemetry/rte_telemetry_parser.h | 13 +
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 | 7 +
lib/meson.build | 3 +-
meson.build | 1 +
mk/rte.app.mk | 1 +
usertools/dpdk-telemetry-client.py | 116 ++
39 files changed, 3617 insertions(+), 19 deletions(-)
create mode 100644 doc/guides/howto/telemetry.rst
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
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_parser.c
create mode 100644 lib/librte_telemetry/rte_telemetry_parser.h
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
create mode 100644 lib/librte_telemetry/rte_telemetry_version.map
create mode 100644 usertools/dpdk-telemetry-client.py
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 01/13] eal: add option register infrastructure
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 02/13] eal: make get runtime dir function public Kevin Laatz
` (12 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
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 <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 14 ++++++-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_private.h | 21 ++++++++++
lib/librte_eal/common/include/rte_option.h | 63 ++++++++++++++++++++++++++++++
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +++++++++++++++++++++++++
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 14 ++++++-
lib/librte_eal/rte_eal_version.map | 1 +
10 files changed, 170 insertions(+), 2 deletions(-)
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index d27da3d..03ead51 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_option.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..8904fe3 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -42,6 +42,7 @@
#include <rte_devargs.h>
#include <rte_version.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#include <rte_atomic.h>
#include <malloc_heap.h>
@@ -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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -788,6 +797,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index cca6882..87d8c45 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_option.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/eal_private.h b/lib/librte_eal/common/eal_private.h
index 4f809a8..e633d7d 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -304,4 +304,25 @@ int
rte_devargs_layers_parse(struct rte_devargs *devargs,
const char *devstr);
+/**
+ * Check if the option is registered.
+ *
+ * @param option
+ * The option to be parsed.
+ *
+ * @return
+ * 0 on success
+ * @return
+ * -1 on fail
+ */
+int
+rte_option_parse(const char *opt);
+
+/**
+ * Iterate through the registered options and execute the associated
+ * callback if enabled.
+ */
+void
+rte_option_init(void);
+
#endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_option.h b/lib/librte_eal/common/include/rte_option.h
new file mode 100644
index 0000000..ae7c2d1
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_option.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#ifndef __INCLUDE_RTE_PARAM_H__
+#define __INCLUDE_RTE_PARAM_H__
+
+/**
+ * @file
+ *
+ * This API offers the ability to register options to the EAL command line and
+ * map those options to functions that will be executed at the end of EAL
+ * initialization. These options will be available as part of the EAL command
+ * line of applications and are dynamically managed.
+ *
+ * This is used primarily by DPDK libraries offering command line options.
+ * Currently, this API is limited to registering options without argument.
+ *
+ * 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_option 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_option_cb)(void);
+
+/*
+ * Structure describing the EAL command line option being registered.
+ */
+struct rte_option {
+ TAILQ_ENTRY(rte_option) next; /**< Next entry in the list. */
+ char *opt_str; /**< The option name. */
+ rte_option_cb cb; /**< Function called when option is used. */
+ int enabled; /**< Set when the option is used. */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Register an option to the EAL command line.
+ * When recognized, the associated function will be executed at the end of EAL
+ * initialization.
+ *
+ * The associated structure must be available the whole time this option is
+ * registered (i.e. not stack memory).
+ *
+ * @param opt
+ * Structure describing the option to parse.
+ */
+void __rte_experimental
+rte_option_register(struct rte_option *opt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build
index b7fc984..f879e65 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_option.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_option.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_option.c b/lib/librte_eal/common/rte_option.c
new file mode 100644
index 0000000..02d59a8
--- /dev/null
+++ b/lib/librte_eal/common/rte_option.c
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_eal.h>
+#include <rte_option.h>
+
+#include "eal_private.h"
+
+TAILQ_HEAD(rte_option_list, rte_option);
+
+struct rte_option_list rte_option_list =
+ TAILQ_HEAD_INITIALIZER(rte_option_list);
+
+static struct rte_option *option;
+
+int
+rte_option_parse(const char *opt)
+{
+ /* Check if the option is registered */
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt, option->opt_str) == 0) {
+ option->enabled = 1;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void __rte_experimental
+rte_option_register(struct rte_option *opt)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt->opt_str, option->opt_str) == 0)
+ RTE_LOG(INFO, EAL, "Option %s has already been registered.",
+ opt->opt_str);
+ return;
+ }
+
+ TAILQ_INSERT_HEAD(&rte_option_list, opt, next);
+}
+
+void
+rte_option_init(void)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (option->enabled)
+ option->cb();
+ }
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 5c16bc4..d4df958 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_option.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..f0ad3aa 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -48,6 +48,7 @@
#include <rte_atomic.h>
#include <malloc_heap.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -1071,6 +1080,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 73282bb..09e0816 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_option_register;
rte_service_lcore_attr_get;
rte_service_lcore_attr_reset_all;
rte_service_may_be_active;
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 02/13] eal: make get runtime dir function public
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 01/13] eal: add option register infrastructure Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 03/13] telemetry: initial telemetry infrastructure Kevin Laatz
` (11 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
This patch makes the eal_get_runtime_dir() API public so it can be used
from outside EAL.
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 | 15 ++++++++-------
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, 20 insertions(+), 9 deletions(-)
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 8904fe3..6101fdc 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..b3e8ae5 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,8 @@ 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 +67,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 +79,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 +100,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 f0ad3aa..1f6522c 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 09e0816..64f60ec 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;
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 03/13] telemetry: initial telemetry infrastructure
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 01/13] eal: add option register infrastructure Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 02/13] eal: make get runtime dir function public Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 04/13] telemetry: add initial connection socket Kevin Laatz
` (10 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
config/common_base | 5 +
lib/Makefile | 2 +
lib/librte_telemetry/Makefile | 28 ++++++
lib/librte_telemetry/meson.build | 7 ++
lib/librte_telemetry/rte_telemetry.c | 123 +++++++++++++++++++++++++
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, 241 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..ee9c90f
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_metrics.h>
+#include <rte_option.h>
+
+#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);
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0) {
+ TELEMETRY_LOG_ERR("Pthread attribute init failed");
+ return -EPERM;
+ }
+
+ 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_option option = {
+ .opt_str = "--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_option_register(&option);
+}
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 <stdint.h>
+
+#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 <rte_log.h>
+
+#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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 04/13] telemetry: add initial connection socket
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (2 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 03/13] telemetry: initial telemetry infrastructure Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 13:50 ` Mattias Rönnblom
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 05/13] telemetry: add client feature and sockets Kevin Laatz
` (9 subsequent siblings)
13 siblings, 1 reply; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 ee9c90f..10311be 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -3,23 +3,163 @@
*/
#include <unistd.h>
+#include <fcntl.h>
#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_metrics.h>
#include <rte_option.h>
+#include <rte_string_fns.h>
#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;
+ char socket_path[BUF_SIZE];
+
+ if (telemetry == NULL)
+ return -1;
+
+ telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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()
{
@@ -77,6 +285,14 @@ rte_telemetry_init()
return -EPERM;
}
+ 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;
+ }
+
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
(void *)static_telemetry);
@@ -95,11 +311,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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v6 04/13] telemetry: add initial connection socket
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 04/13] telemetry: add initial connection socket Kevin Laatz
@ 2018-10-22 13:50 ` Mattias Rönnblom
0 siblings, 0 replies; 219+ messages in thread
From: Mattias Rönnblom @ 2018-10-22 13:50 UTC (permalink / raw)
To: Kevin Laatz, dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
bruce.richardson, Ciara Power, Brian Archbold
On 2018-10-22 13:00, Kevin Laatz wrote:
> From: Ciara Power <ciara.power@intel.com>
>
> 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 <ciara.power@intel.com>
> Signed-off-by: Brian Archbold <brian.archbold@intel.com>
> Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
> Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
> ---
> 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 ee9c90f..10311be 100644
> --- a/lib/librte_telemetry/rte_telemetry.c
> +++ b/lib/librte_telemetry/rte_telemetry.c
> @@ -3,23 +3,163 @@
> */
>
> #include <unistd.h>
> +#include <fcntl.h>
> #include <pthread.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
>
> #include <rte_eal.h>
> #include <rte_ethdev.h>
> #include <rte_metrics.h>
> #include <rte_option.h>
> +#include <rte_string_fns.h>
>
> #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) {
Is this intentional? If so, what's the meaning of "accept_fd == 0", as
oppose to when accept_fd is -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;
> + char socket_path[BUF_SIZE];
> +
> + if (telemetry == NULL)
> + return -1;
> +
> + telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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);
This free() needs to go away, or use-after-free and a double-free() will
occur in rte_telemetry_init().
> + return -EPERM;
> + }
> +
> + return -1;
> +}
> +
> int32_t
> rte_telemetry_init()
> {
> @@ -77,6 +285,14 @@ rte_telemetry_init()
> return -EPERM;
> }
>
> + 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;
> + }
> +
> ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
> telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
> (void *)static_telemetry);
> @@ -95,11 +311,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
>
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 05/13] telemetry: add client feature and sockets
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (3 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 04/13] telemetry: add initial connection socket Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 14:05 ` Mattias Rönnblom
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 06/13] telemetry: add parser for client socket messages Kevin Laatz
` (8 subsequent siblings)
13 siblings, 1 reply; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 10311be..a3ab3e9 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -7,6 +7,7 @@
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <jansson.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
@@ -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,38 @@ 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);
+
+ if (buffer_read == -1) {
+ TELEMETRY_LOG_ERR("Read error");
+ return -1;
+ } else if (buffer_read == 0) {
+ goto close_socket;
+ } else {
+ buf[buffer_read] = '\0';
+ ret = rte_telemetry_parse_client_message(telemetry, buf);
+ if (ret < 0)
+ TELEMETRY_LOG_WARN("Parse message failed");
+ goto close_socket;
+ }
+
+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 +259,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 +269,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 +315,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;
}
@@ -292,6 +440,7 @@ rte_telemetry_init()
TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
return -EPERM;
}
+ TAILQ_INIT(&static_telemetry->client_list_head);
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
@@ -308,11 +457,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) {
@@ -329,6 +506,192 @@ 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;
+
+ 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_SEQPACKET, 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 <rte_log.h>
+#include <rte_tailq.h>
#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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v6 05/13] telemetry: add client feature and sockets
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 05/13] telemetry: add client feature and sockets Kevin Laatz
@ 2018-10-22 14:05 ` Mattias Rönnblom
2018-10-23 8:42 ` Laatz, Kevin
0 siblings, 1 reply; 219+ messages in thread
From: Mattias Rönnblom @ 2018-10-22 14:05 UTC (permalink / raw)
To: Kevin Laatz, dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
bruce.richardson, Ciara Power, Brian Archbold
On 2018-10-22 13:00, Kevin Laatz wrote:
> From: Ciara Power <ciara.power@intel.com>
>
> 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 <ciara.power@intel.com>
> Signed-off-by: Brian Archbold <brian.archbold@intel.com>
> Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
> Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
> ---
> 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 10311be..a3ab3e9 100644
> --- a/lib/librte_telemetry/rte_telemetry.c
> +++ b/lib/librte_telemetry/rte_telemetry.c
> @@ -7,6 +7,7 @@
> #include <pthread.h>
> #include <sys/socket.h>
> #include <sys/un.h>
> +#include <jansson.h>
>
> #include <rte_eal.h>
> #include <rte_ethdev.h>
> @@ -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,38 @@ 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;
No need to set it to zero.
> +
> + buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
> +
> + if (buffer_read == -1) {
> + TELEMETRY_LOG_ERR("Read error");
> + return -1;
> + } else if (buffer_read == 0) {
> + goto close_socket;
> + } else {
I would have moved the 'ret' variable to this scope.
> + buf[buffer_read] = '\0';
> + ret = rte_telemetry_parse_client_message(telemetry, buf);
> + if (ret < 0)
> + TELEMETRY_LOG_WARN("Parse message failed");
> + goto close_socket;
> + }
> +
> +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 +259,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 +269,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';
read() might return -1, and you'll be writing out-of-bounds.
> +
> + if (bytes > 0)
> + telemetry->request_client = client;
> }
>
> return 0;
> @@ -173,6 +315,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;
> }
>
> @@ -292,6 +440,7 @@ rte_telemetry_init()
> TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
> return -EPERM;
> }
> + TAILQ_INIT(&static_telemetry->client_list_head);
>
> ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
> telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
> @@ -308,11 +457,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) {
> @@ -329,6 +506,192 @@ 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;
> +
> + 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_SEQPACKET, 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;
> + }
> +
You're leaking the root object here, but maybe that's fixed in
subsequent patches.
> + 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 <rte_log.h>
> +#include <rte_tailq.h>
>
> #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
>
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v6 05/13] telemetry: add client feature and sockets
2018-10-22 14:05 ` Mattias Rönnblom
@ 2018-10-23 8:42 ` Laatz, Kevin
0 siblings, 0 replies; 219+ messages in thread
From: Laatz, Kevin @ 2018-10-23 8:42 UTC (permalink / raw)
To: Mattias Rönnblom, dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
bruce.richardson, Ciara Power, Brian Archbold
Thanks for the review Mattias.
Will address the comments both here and in the 4/13 review.
Best regards,
Kevin
On 22/10/2018 15:05, Mattias Rönnblom wrote:
> On 2018-10-22 13:00, Kevin Laatz wrote:
>>
>> @@ -131,6 +217,38 @@ 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;
>
> No need to set it to zero.
>
>> +
>> + buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
>> +
>> + if (buffer_read == -1) {
>> + TELEMETRY_LOG_ERR("Read error");
>> + return -1;
>> + } else if (buffer_read == 0) {
>> + goto close_socket;
>> + } else {
>
> I would have moved the 'ret' variable to this scope.
>
>>
>> +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';
>
> read() might return -1, and you'll be writing out-of-bounds.
>
>>
>> +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;
>> + }
>> +
>
> You're leaking the root object here, but maybe that's fixed in
> subsequent patches.
>
>> + return 0;
>> +
>> +fail:
>> + TELEMETRY_LOG_WARN("Client attempted to register with invalid
>> message");
>> + return -1;
>> +}
>> +
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 06/13] telemetry: add parser for client socket messages
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (4 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 05/13] telemetry: add client feature and sockets Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 07/13] telemetry: update metrics before sending stats Kevin Laatz
` (7 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 a3ab3e9..76d92e9 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
@@ -283,6 +284,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;
@@ -291,8 +293,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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+
+#include <rte_metrics.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+
+#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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 07/13] telemetry: update metrics before sending stats
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (5 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 06/13] telemetry: add parser for client socket messages Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 08/13] telemetry: format json response when " Kevin Laatz
` (6 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 76d92e9..cd97a6e 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;
}
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 08/13] telemetry: format json response when sending stats
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (6 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 07/13] telemetry: update metrics before sending stats Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 09/13] telemetry: add tests for telemetry api Kevin Laatz
` (5 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 cd97a6e..f5c1bad 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");
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 09/13] telemetry: add tests for telemetry api
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (7 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 08/13] telemetry: format json response when " Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 10/13] telemetry: add ability to disable selftest Kevin Laatz
` (4 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 f5c1bad..717416e 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;
}
@@ -1140,6 +1172,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_SEQPACKET, 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_SEQPACKET, 0);
+ *recv_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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..5fe93fa
--- /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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_tailq.h>
+#include <rte_string_fns.h>
+
+#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_SEQPACKET, 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 <stdbool.h>
+
+#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: *;
};
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 10/13] telemetry: add ability to disable selftest
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (8 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 09/13] telemetry: add tests for telemetry api Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 11/13] doc: add telemetry documentation Kevin Laatz
` (3 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 717416e..c43b657 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;
}
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 11/13] doc: add telemetry documentation
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (9 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 10/13] telemetry: add ability to disable selftest Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 12:25 ` Kovacevic, Marko
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 12/13] usertools: add client python script for telemetry Kevin Laatz
` (2 subsequent siblings)
13 siblings, 1 reply; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 <kevin.laatz@intel.com>
+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.
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v6 11/13] doc: add telemetry documentation
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 11/13] doc: add telemetry documentation Kevin Laatz
@ 2018-10-22 12:25 ` Kovacevic, Marko
0 siblings, 0 replies; 219+ messages in thread
From: Kovacevic, Marko @ 2018-10-22 12:25 UTC (permalink / raw)
To: Laatz, Kevin, dev
Cc: Van Haaren, Harry, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, Richardson, Bruce, Ciara Power, Brian Archbold,
Laatz, Kevin
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Kevin Laatz
> Sent: Monday, October 22, 2018 12:00 PM
> To: dev@dpdk.org
> Cc: Van Haaren, Harry <harry.van.haaren@intel.com>;
> stephen@networkplumber.org; gaetan.rivet@6wind.com;
> shreyansh.jain@nxp.com; thomas@monjalon.net;
> mattias.ronnblom@ericsson.com; Richardson, Bruce
> <bruce.richardson@intel.com>; Ciara Power <ciara.power@intel.com>; Brian
> Archbold <brian.archbold@intel.com>; Laatz, Kevin <kevin.laatz@intel.com>
> Subject: [dpdk-dev] [PATCH v6 11/13] doc: add telemetry documentation
>
> From: Ciara Power <ciara.power@intel.com>
>
> 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 <ciara.power@intel.com>
> Signed-off-by: Brian Archbold <brian.archbold@intel.com>
> Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
> Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
> ---
> MAINTAINERS | 5 +++
> doc/guides/howto/index.rst | 1 +
> doc/guides/howto/telemetry.rst | 85
> ++++++++++++++++++++++++++++++++++++++++++
Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 12/13] usertools: add client python script for telemetry
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (10 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 11/13] doc: add telemetry documentation Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 13/13] build: add dependency on telemetry to apps in meson Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <file_path>".
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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..6dcf62b
--- /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_SEQPACKET)
+ self.recv_fd = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ 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)
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v6 13/13] build: add dependency on telemetry to apps in meson
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (11 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 12/13] usertools: add client python script for telemetry Kevin Laatz
@ 2018-10-22 11:00 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-22 11:00 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
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 <bruce.richardson@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 = []
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 00/13] introduce telemetry library
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 " Kevin Laatz
` (12 preceding siblings ...)
2018-10-22 11:00 ` [dpdk-dev] [PATCH v6 13/13] build: add dependency on telemetry to apps in meson Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 01/13] eal: add option register infrastructure Kevin Laatz
` (14 more replies)
13 siblings, 15 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
This patchset introduces a Telemetry library for DPDK Service Assurance.
This library provides an easy way to query DPDK Ethdev metrics.
The telemetry library provides a method for a service assurance component
to retrieve metrics from a DPDK packet forwarding application.
Communicating from the service assurance component to DPDK is done using a
UNIX domain socket, passing a JSON formatted string. A reply is sent (again
a JSON formatted string) of the current DPDK metrics.
The telemetry component makes use of the existing rte_metrics library to
query values. The values to be transmitted via the telemetry infrastructure
must be present in the Metrics library. Currently the ethdev values are
pushed to the metrics library, and the queried from there there is an open
question on how applications would like this to occur. Currently only
ethdev to metrics functionality is implemented, however other subsystems
like crypto, eventdev, keepalive etc can use similar mechanisms.
Exposing DPDK Telemetry via a socket interface enables service assurance
agents like collectd to consume data from DPDK. This is vital for
monitoring, fault-detection, and error reporting. A collectd plugin has
been created to interact with the DPDK Telemetry component, showing how it
can be used in practice. The collectd plugin will be upstreamed to collectd
at a later stage. A small python script is provided in
./usertools/telemetry_client.py to quick-start using DPDK Telemetry.
Note: Despite opterr being set to 0, --telemetry said to be 'unrecognized'
as a startup print. This is a cosmetic issue and will be addressed in the
future.
---
v2:
- Reworked telemetry as part of EAL instead of using vdev (Gaetan)
- Refactored rte_telemetry_command (Gaetan)
- Added MAINTAINERS file entry (Stephen)
- Updated docs to reflect vdev to eal rework
- Removed collectd patch from patchset (Thomas)
- General code clean up from v1 feedback
v3:
- Reworked registering with eal and moved to rte_param (Gaetan)
- Added BSD implementation for rte_param (Gaetan)
- Updated the paths to align with the new runtime file location (Mattias)
- Fixed pointer checks to align with the coding style 1.8.1 (Mattias)
- Added missing decref's and close's (Mattias)
- Fixed runtime issue in Meson (was not recognising flag due to linking)
- More general clean up
v4:
- Added Doxygen comments for rte_param.h (Thomas)
- Made eal_get_runtime_dir a public function to use outside of EAL (Thomas)
- Reworked telemetry to get path using rte_eal_get_runtime_dir (Thomas)
- Fixed checkpatch coding style error
v5:
- Moved the BUF_SIZE define to fix build (Harry)
- Set default config for telemetry to 'n' (Harry)
- Improved Doxygen comments (Thomas)
- Cleaned up rte_param struct (Thomas)
v6:
- Renamed rte_param to rte_option (Thomas)
- Moved internal functions to eal_private.h (Gaetan)
- Added fail check for pthread_attr_init() (Mattias)
- Changed socket implementation to SOCK_SEQPACKET (Mattias)
- Added check to avoid option duplicates (Gaetan)
- Removed telemetry example from Doxygen comment (Gaetan)
- General Doxygen clean-up (Thomas)
- General code clean-up (Mattias)
v7:
- Fix object leak (Mattias)
- General clean-up (Mattias)
- Fix rte_option header define
- Added release note update
- Rebased
Ciara Power, Brian Archbold and Kevin Laatz (10):
telemetry: initial telemetry infrastructure
telemetry: add initial connection socket
telemetry: add client feature and sockets
telemetry: add parser for client socket messages
telemetry: update metrics before sending stats
telemetry: format json response when sending stats
telemetry: add tests for telemetry api
telemetry: add ability to disable selftest
doc: add telemetry documentation
usertools: add client python script for telemetry
Kevin Laatz (3):
eal: add option register infrastructure
eal: make get runtime dir function public
build: add dependency on telemetry to apps in meson
MAINTAINERS | 5 +
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/common_base | 5 +
config/meson.build | 3 +
doc/guides/howto/index.rst | 1 +
doc/guides/howto/telemetry.rst | 85 +
doc/guides/rel_notes/release_18_11.rst | 6 +
lib/Makefile | 2 +
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 16 +-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_filesystem.h | 15 +-
lib/librte_eal/common/eal_private.h | 21 +
lib/librte_eal/common/include/rte_eal.h | 9 +
lib/librte_eal/common/include/rte_option.h | 63 +
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 16 +-
lib/librte_eal/rte_eal_version.map | 2 +
lib/librte_telemetry/Makefile | 30 +
lib/librte_telemetry/meson.build | 9 +
lib/librte_telemetry/rte_telemetry.c | 1815 +++++++++++++++++++++
lib/librte_telemetry/rte_telemetry.h | 48 +
lib/librte_telemetry/rte_telemetry_internal.h | 81 +
lib/librte_telemetry/rte_telemetry_parser.c | 586 +++++++
lib/librte_telemetry/rte_telemetry_parser.h | 13 +
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 | 7 +
lib/meson.build | 3 +-
meson.build | 1 +
mk/rte.app.mk | 1 +
usertools/dpdk-telemetry-client.py | 116 ++
40 files changed, 3622 insertions(+), 19 deletions(-)
create mode 100644 doc/guides/howto/telemetry.rst
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
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_parser.c
create mode 100644 lib/librte_telemetry/rte_telemetry_parser.h
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
create mode 100644 lib/librte_telemetry/rte_telemetry_version.map
create mode 100644 usertools/dpdk-telemetry-client.py
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 01/13] eal: add option register infrastructure
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 14:01 ` Gaëtan Rivet
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 02/13] eal: make get runtime dir function public Kevin Laatz
` (13 subsequent siblings)
14 siblings, 1 reply; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
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 <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 14 ++++++-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_private.h | 21 ++++++++++
lib/librte_eal/common/include/rte_option.h | 63 ++++++++++++++++++++++++++++++
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +++++++++++++++++++++++++
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 14 ++++++-
lib/librte_eal/rte_eal_version.map | 1 +
10 files changed, 170 insertions(+), 2 deletions(-)
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index d19f53c..bfeddaa 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -67,6 +67,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_option.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 7735194..178cfd6 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -42,6 +42,7 @@
#include <rte_devargs.h>
#include <rte_version.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#include <rte_atomic.h>
#include <malloc_heap.h>
@@ -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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -791,6 +800,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index cca6882..87d8c45 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_option.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/eal_private.h b/lib/librte_eal/common/eal_private.h
index b189d67..442c6dc 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -349,4 +349,25 @@ dev_sigbus_handler_register(void);
int
dev_sigbus_handler_unregister(void);
+/**
+ * Check if the option is registered.
+ *
+ * @param option
+ * The option to be parsed.
+ *
+ * @return
+ * 0 on success
+ * @return
+ * -1 on fail
+ */
+int
+rte_option_parse(const char *opt);
+
+/**
+ * Iterate through the registered options and execute the associated
+ * callback if enabled.
+ */
+void
+rte_option_init(void);
+
#endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_option.h b/lib/librte_eal/common/include/rte_option.h
new file mode 100644
index 0000000..8957b97
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_option.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#ifndef __INCLUDE_RTE_OPTION_H__
+#define __INCLUDE_RTE_OPTION_H__
+
+/**
+ * @file
+ *
+ * This API offers the ability to register options to the EAL command line and
+ * map those options to functions that will be executed at the end of EAL
+ * initialization. These options will be available as part of the EAL command
+ * line of applications and are dynamically managed.
+ *
+ * This is used primarily by DPDK libraries offering command line options.
+ * Currently, this API is limited to registering options without argument.
+ *
+ * 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_option 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_option_cb)(void);
+
+/*
+ * Structure describing the EAL command line option being registered.
+ */
+struct rte_option {
+ TAILQ_ENTRY(rte_option) next; /**< Next entry in the list. */
+ char *opt_str; /**< The option name. */
+ rte_option_cb cb; /**< Function called when option is used. */
+ int enabled; /**< Set when the option is used. */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Register an option to the EAL command line.
+ * When recognized, the associated function will be executed at the end of EAL
+ * initialization.
+ *
+ * The associated structure must be available the whole time this option is
+ * registered (i.e. not stack memory).
+ *
+ * @param opt
+ * Structure describing the option to parse.
+ */
+void __rte_experimental
+rte_option_register(struct rte_option *opt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build
index 04c4143..2a10d57 100644
--- a/lib/librte_eal/common/meson.build
+++ b/lib/librte_eal/common/meson.build
@@ -34,6 +34,7 @@ common_sources = files(
'malloc_mp.c',
'rte_keepalive.c',
'rte_malloc.c',
+ 'rte_option.c',
'rte_reciprocal.c',
'rte_service.c'
)
@@ -71,6 +72,7 @@ common_headers = files(
'include/rte_malloc_heap.h',
'include/rte_memory.h',
'include/rte_memzone.h',
+ 'include/rte_option.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_option.c b/lib/librte_eal/common/rte_option.c
new file mode 100644
index 0000000..02d59a8
--- /dev/null
+++ b/lib/librte_eal/common/rte_option.c
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_eal.h>
+#include <rte_option.h>
+
+#include "eal_private.h"
+
+TAILQ_HEAD(rte_option_list, rte_option);
+
+struct rte_option_list rte_option_list =
+ TAILQ_HEAD_INITIALIZER(rte_option_list);
+
+static struct rte_option *option;
+
+int
+rte_option_parse(const char *opt)
+{
+ /* Check if the option is registered */
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt, option->opt_str) == 0) {
+ option->enabled = 1;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void __rte_experimental
+rte_option_register(struct rte_option *opt)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt->opt_str, option->opt_str) == 0)
+ RTE_LOG(INFO, EAL, "Option %s has already been registered.",
+ opt->opt_str);
+ return;
+ }
+
+ TAILQ_INSERT_HEAD(&rte_option_list, opt, next);
+}
+
+void
+rte_option_init(void)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (option->enabled)
+ option->cb();
+ }
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 7280885..51deb57 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -75,6 +75,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_option.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 a00cebf..70ab032 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -48,6 +48,7 @@
#include <rte_atomic.h>
#include <malloc_heap.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -1080,6 +1089,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 08e3bc2..12ace18 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -351,6 +351,7 @@ EXPERIMENTAL {
rte_mp_request_sync;
rte_mp_request_async;
rte_mp_sendmsg;
+ rte_option_register;
rte_service_lcore_attr_get;
rte_service_lcore_attr_reset_all;
rte_service_may_be_active;
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v7 01/13] eal: add option register infrastructure
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 01/13] eal: add option register infrastructure Kevin Laatz
@ 2018-10-24 14:01 ` Gaëtan Rivet
2018-10-24 14:33 ` Thomas Monjalon
0 siblings, 1 reply; 219+ messages in thread
From: Gaëtan Rivet @ 2018-10-24 14:01 UTC (permalink / raw)
To: Kevin Laatz
Cc: dev, harry.van.haaren, stephen, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson
Hi Kevin,
On Wed, Oct 24, 2018 at 02:27:13PM +0100, Kevin Laatz wrote:
> 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 <kevin.laatz@intel.com>
> Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
I think this is good enough,
Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com>
The only remaining issue is rte_option_init().
Sorry I missed your previous message and did not respond in time, I
would have opted for leaving a return value to at least be able to stop
the init on error. It is possible to force the callback type to return
an error value along with a string / hint describing the error. It
should not be hard to add it later, so not blocking IMO.
--
Gaëtan Rivet
6WIND
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v7 01/13] eal: add option register infrastructure
2018-10-24 14:01 ` Gaëtan Rivet
@ 2018-10-24 14:33 ` Thomas Monjalon
2018-10-24 14:52 ` Laatz, Kevin
0 siblings, 1 reply; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-24 14:33 UTC (permalink / raw)
To: Kevin Laatz
Cc: Gaëtan Rivet, dev, harry.van.haaren, stephen,
shreyansh.jain, mattias.ronnblom, bruce.richardson
24/10/2018 16:01, Gaëtan Rivet:
> Hi Kevin,
>
> On Wed, Oct 24, 2018 at 02:27:13PM +0100, Kevin Laatz wrote:
> > 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 <kevin.laatz@intel.com>
> > Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
>
> I think this is good enough,
>
> Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Yes it looks good enough.
And it compiles fine in my test.
> The only remaining issue is rte_option_init().
> Sorry I missed your previous message and did not respond in time, I
> would have opted for leaving a return value to at least be able to stop
> the init on error. It is possible to force the callback type to return
> an error value along with a string / hint describing the error. It
> should not be hard to add it later, so not blocking IMO.
I think you need to set this API as experimental.
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v7 01/13] eal: add option register infrastructure
2018-10-24 14:33 ` Thomas Monjalon
@ 2018-10-24 14:52 ` Laatz, Kevin
2018-10-24 15:05 ` Laatz, Kevin
0 siblings, 1 reply; 219+ messages in thread
From: Laatz, Kevin @ 2018-10-24 14:52 UTC (permalink / raw)
To: Thomas Monjalon
Cc: Gaëtan Rivet, dev, harry.van.haaren, stephen,
shreyansh.jain, mattias.ronnblom, bruce.richardson
On 24/10/2018 15:33, Thomas Monjalon wrote:
> 24/10/2018 16:01, Gaëtan Rivet:
>> Hi Kevin,
>>
>> On Wed, Oct 24, 2018 at 02:27:13PM +0100, Kevin Laatz wrote:
>>> 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 <kevin.laatz@intel.com>
>>> Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
>> I think this is good enough,
>>
>> Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> Yes it looks good enough.
> And it compiles fine in my test.
>
>> The only remaining issue is rte_option_init().
>> Sorry I missed your previous message and did not respond in time, I
>> would have opted for leaving a return value to at least be able to stop
>> the init on error. It is possible to force the callback type to return
>> an error value along with a string / hint describing the error. It
>> should not be hard to add it later, so not blocking IMO.
Agree this can be added in the future.
> I think you need to set this API as experimental.
Will do, thanks.
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v7 01/13] eal: add option register infrastructure
2018-10-24 14:52 ` Laatz, Kevin
@ 2018-10-24 15:05 ` Laatz, Kevin
0 siblings, 0 replies; 219+ messages in thread
From: Laatz, Kevin @ 2018-10-24 15:05 UTC (permalink / raw)
To: Thomas Monjalon
Cc: Gaëtan Rivet, dev, harry.van.haaren, stephen,
shreyansh.jain, mattias.ronnblom, bruce.richardson
On 24/10/2018 15:52, Laatz, Kevin wrote:
> On 24/10/2018 15:33, Thomas Monjalon wrote:
>> 24/10/2018 16:01, Gaëtan Rivet:
>>> Hi Kevin,
>>>
>>> On Wed, Oct 24, 2018 at 02:27:13PM +0100, Kevin Laatz wrote:
>>>> 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 <kevin.laatz@intel.com>
>>>> Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
>>> I think this is good enough,
>>>
>>> Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com>
>> Yes it looks good enough.
>> And it compiles fine in my test.
>>
>>> The only remaining issue is rte_option_init().
>>> Sorry I missed your previous message and did not respond in time, I
>>> would have opted for leaving a return value to at least be able to stop
>>> the init on error. It is possible to force the callback type to return
>>> an error value along with a string / hint describing the error. It
>>> should not be hard to add it later, so not blocking IMO.
> Agree this can be added in the future.
>> I think you need to set this API as experimental.
> Will do, thanks.
Correction: This is an internal function (eal_private.h), so no need to
mark as experimental. rte_option_register() is marked as experimental.
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 02/13] eal: make get runtime dir function public
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 01/13] eal: add option register infrastructure Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 03/13] telemetry: initial telemetry infrastructure Kevin Laatz
` (12 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
This patch makes the eal_get_runtime_dir() API public so it can be used
from outside EAL.
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_eal/bsdapp/eal/eal.c | 2 +-
lib/librte_eal/common/eal_filesystem.h | 15 ++++++++-------
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, 20 insertions(+), 9 deletions(-)
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 178cfd6..52c1dea 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..b3e8ae5 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,8 @@ 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 +67,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 +79,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 +100,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 3ee897c..150ced7 100644
--- a/lib/librte_eal/common/include/rte_eal.h
+++ b/lib/librte_eal/common/include/rte_eal.h
@@ -507,6 +507,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 70ab032..b75dd01 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 12ace18..42bd367 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -261,6 +261,7 @@ DPDK_18.08 {
DPDK_18.11 {
global:
+ rte_eal_get_runtime_dir;
rte_eal_hotplug_add;
rte_eal_hotplug_remove;
rte_strscpy;
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 03/13] telemetry: initial telemetry infrastructure
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 01/13] eal: add option register infrastructure Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 02/13] eal: make get runtime dir function public Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 04/13] telemetry: add initial connection socket Kevin Laatz
` (11 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
config/common_base | 5 +
lib/Makefile | 2 +
lib/librte_telemetry/Makefile | 28 ++++++
lib/librte_telemetry/meson.build | 7 ++
lib/librte_telemetry/rte_telemetry.c | 123 +++++++++++++++++++++++++
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, 241 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 be7365e..d59141b 100644
--- a/config/common_base
+++ b/config/common_base
@@ -753,6 +753,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..ee9c90f
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_metrics.h>
+#include <rte_option.h>
+
+#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);
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0) {
+ TELEMETRY_LOG_ERR("Pthread attribute init failed");
+ return -EPERM;
+ }
+
+ 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_option option = {
+ .opt_str = "--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_option_register(&option);
+}
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 <stdint.h>
+
+#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 <rte_log.h>
+
+#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 24351cc..90a4227 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 3203cf0..a5ce715 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_telemetry
_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER) += -lrte_timer
_LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += -lrte_mempool
_LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING) += -lrte_mempool_ring
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 04/13] telemetry: add initial connection socket
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (2 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 03/13] telemetry: initial telemetry infrastructure Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 05/13] telemetry: add client feature and sockets Kevin Laatz
` (10 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/rte_telemetry.c | 225 ++++++++++++++++++++++++++
lib/librte_telemetry/rte_telemetry_internal.h | 4 +
2 files changed, 229 insertions(+)
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index ee9c90f..816296b 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -3,23 +3,163 @@
*/
#include <unistd.h>
+#include <fcntl.h>
#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_metrics.h>
#include <rte_option.h>
+#include <rte_string_fns.h>
#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) {
+ 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,67 @@ 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;
+ char socket_path[BUF_SIZE];
+
+ if (telemetry == NULL)
+ return -1;
+
+ telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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");
+ return -EPERM;
+ }
+
+ return -1;
+}
+
int32_t
rte_telemetry_init()
{
@@ -77,6 +284,14 @@ rte_telemetry_init()
return -EPERM;
}
+ 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;
+ }
+
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
(void *)static_telemetry);
@@ -95,11 +310,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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 05/13] telemetry: add client feature and sockets
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (3 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 04/13] telemetry: add initial connection socket Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 06/13] telemetry: add parser for client socket messages Kevin Laatz
` (9 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/meson.build | 2 +
lib/librte_telemetry/rte_telemetry.c | 370 +++++++++++++++++++++++++-
lib/librte_telemetry/rte_telemetry_internal.h | 25 ++
mk/rte.app.mk | 2 +-
4 files changed, 395 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 816296b..15292de 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -7,6 +7,7 @@
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <jansson.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
@@ -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,38 @@ 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;
+
+ buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
+
+ if (buffer_read == -1) {
+ TELEMETRY_LOG_ERR("Read error");
+ return -1;
+ } else if (buffer_read == 0) {
+ goto close_socket;
+ } else {
+ buf[buffer_read] = '\0';
+ ret = rte_telemetry_parse_client_message(telemetry, buf);
+ if (ret < 0)
+ TELEMETRY_LOG_WARN("Parse message failed");
+ goto close_socket;
+ }
+
+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 +259,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 +269,31 @@ 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);
+
+ if (bytes > 0) {
+ client_buf[bytes] = '\0';
+ telemetry->request_client = client;
+ }
}
return 0;
@@ -173,6 +316,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;
}
@@ -291,6 +440,7 @@ rte_telemetry_init()
TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
return -EPERM;
}
+ TAILQ_INIT(&static_telemetry->client_list_head);
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
@@ -307,11 +457,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) {
@@ -328,6 +506,192 @@ 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;
+
+ 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_SEQPACKET, 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");
+ 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");
+ json_decref(root);
+ 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 <rte_log.h>
+#include <rte_tailq.h>
#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 a5ce715..620059c 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_telemetry
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 06/13] telemetry: add parser for client socket messages
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (4 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 05/13] telemetry: add client feature and sockets Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 07/13] telemetry: update metrics before sending stats Kevin Laatz
` (8 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/Makefile | 1 +
lib/librte_telemetry/meson.build | 4 +-
lib/librte_telemetry/rte_telemetry.c | 8 +
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, 606 insertions(+), 2 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 15292de..d9b67d4 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
@@ -283,6 +284,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,6 +295,12 @@ rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)
if (bytes > 0) {
client_buf[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;
+ }
}
}
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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+
+#include <rte_metrics.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+
+#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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 07/13] telemetry: update metrics before sending stats
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (5 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 06/13] telemetry: add parser for client socket messages Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 08/13] telemetry: format json response when " Kevin Laatz
` (7 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 d9b67d4..556e53d 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;
}
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 08/13] telemetry: format json response when sending stats
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (6 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 07/13] telemetry: update metrics before sending stats Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 09/13] telemetry: add tests for telemetry api Kevin Laatz
` (6 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 556e53d..3e76108 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");
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 09/13] telemetry: add tests for telemetry api
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (7 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 08/13] telemetry: format json response when " Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 10/13] telemetry: add ability to disable selftest Kevin Laatz
` (5 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 3e76108..324185f 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;
}
@@ -1139,6 +1171,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_SEQPACKET, 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_SEQPACKET, 0);
+ *recv_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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..5fe93fa
--- /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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_tailq.h>
+#include <rte_string_fns.h>
+
+#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_SEQPACKET, 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 <stdbool.h>
+
+#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: *;
};
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 10/13] telemetry: add ability to disable selftest
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (8 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 09/13] telemetry: add tests for telemetry api Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 11/13] doc: add telemetry documentation Kevin Laatz
` (4 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 324185f..a169832 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;
}
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 11/13] doc: add telemetry documentation
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (9 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 10/13] telemetry: add ability to disable selftest Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 12/13] usertools: add client python script for telemetry Kevin Laatz
` (3 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 and a release notes update for
telemetry.
Signed-off-by: Ciara Power <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>
---
MAINTAINERS | 5 ++
doc/guides/howto/index.rst | 1 +
doc/guides/howto/telemetry.rst | 85 ++++++++++++++++++++++++++++++++++
doc/guides/rel_notes/release_18_11.rst | 6 +++
4 files changed, 97 insertions(+)
create mode 100644 doc/guides/howto/telemetry.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index b220479..7612a5b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1208,6 +1208,11 @@ F: test/bpf/
F: test/test/test_bpf.c
F: doc/guides/prog_guide/bpf_lib.rst
+Telemetry
+M: Kevin Laatz <kevin.laatz@intel.com>
+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.
diff --git a/doc/guides/rel_notes/release_18_11.rst b/doc/guides/rel_notes/release_18_11.rst
index 04f3745..e82c790 100644
--- a/doc/guides/rel_notes/release_18_11.rst
+++ b/doc/guides/rel_notes/release_18_11.rst
@@ -189,6 +189,12 @@ New Features
the specified port. The port must be stopped before the command call in order
to reconfigure queues.
+* **Added Telemetry API.**
+
+ Added the telemetry API which allows applications to transparently expose
+ their telemetry via a UNIX socket in JSON. The JSON can be consumed by any
+ Service Assurance agent, such as CollectD.
+
* **Add a new sample for vDPA**
The vdpa sample application creates vhost-user sockets by using the
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 12/13] usertools: add client python script for telemetry
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (10 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 11/13] doc: add telemetry documentation Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 13/13] build: add dependency on telemetry to apps in meson Kevin Laatz
` (2 subsequent siblings)
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <file_path>".
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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..6dcf62b
--- /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_SEQPACKET)
+ self.recv_fd = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ 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)
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v7 13/13] build: add dependency on telemetry to apps in meson
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (11 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 12/13] usertools: add client python script for telemetry Kevin Laatz
@ 2018-10-24 13:27 ` Kevin Laatz
2018-10-24 14:13 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Thomas Monjalon
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
14 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 13:27 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
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 <bruce.richardson@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 e68d949..78bc3af 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -29,7 +29,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)
@@ -43,7 +43,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 cd66618..6006c60 100644
--- a/app/test-pmd/meson.build
+++ b/app/test-pmd/meson.build
@@ -24,7 +24,7 @@ sources = files('cmdline.c',
'txonly.c',
'util.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 90a4227..ae99ab0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -131,6 +131,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 = []
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v7 00/13] introduce telemetry library
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (12 preceding siblings ...)
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 13/13] build: add dependency on telemetry to apps in meson Kevin Laatz
@ 2018-10-24 14:13 ` Thomas Monjalon
2018-10-24 14:49 ` Laatz, Kevin
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
14 siblings, 1 reply; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-24 14:13 UTC (permalink / raw)
To: Kevin Laatz
Cc: dev, harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, bruce.richardson
24/10/2018 15:27, Kevin Laatz:
> This patchset introduces a Telemetry library for DPDK Service Assurance.
> This library provides an easy way to query DPDK Ethdev metrics.
This new library is not defined as experimental.
Is it on purpose?
We are supposed to give an experimental period to new APIs:
http://doc.dpdk.org/guides/contributing/versioning.html#general-guidelines
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v7 00/13] introduce telemetry library
2018-10-24 14:13 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Thomas Monjalon
@ 2018-10-24 14:49 ` Laatz, Kevin
0 siblings, 0 replies; 219+ messages in thread
From: Laatz, Kevin @ 2018-10-24 14:49 UTC (permalink / raw)
To: Thomas Monjalon
Cc: dev, harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, bruce.richardson
On 24/10/2018 15:13, Thomas Monjalon wrote:
> 24/10/2018 15:27, Kevin Laatz:
>> This patchset introduces a Telemetry library for DPDK Service Assurance.
>> This library provides an easy way to query DPDK Ethdev metrics.
> This new library is not defined as experimental.
> Is it on purpose?
>
> We are supposed to give an experimental period to new APIs:
> http://doc.dpdk.org/guides/contributing/versioning.html#general-guidelines
Will do, Thanks.
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 00/13] introduce telemetry library
2018-10-24 13:27 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Kevin Laatz
` (13 preceding siblings ...)
2018-10-24 14:13 ` [dpdk-dev] [PATCH v7 00/13] introduce telemetry library Thomas Monjalon
@ 2018-10-24 16:02 ` Kevin Laatz
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 01/13] eal: add option register infrastructure Kevin Laatz
` (13 more replies)
14 siblings, 14 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:02 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
This patchset introduces a Telemetry library for DPDK Service Assurance.
This library provides an easy way to query DPDK Ethdev metrics.
The telemetry library provides a method for a service assurance component
to retrieve metrics from a DPDK packet forwarding application.
Communicating from the service assurance component to DPDK is done using a
UNIX domain socket, passing a JSON formatted string. A reply is sent (again
a JSON formatted string) of the current DPDK metrics.
The telemetry component makes use of the existing rte_metrics library to
query values. The values to be transmitted via the telemetry infrastructure
must be present in the Metrics library. Currently the ethdev values are
pushed to the metrics library, and the queried from there there is an open
question on how applications would like this to occur. Currently only
ethdev to metrics functionality is implemented, however other subsystems
like crypto, eventdev, keepalive etc can use similar mechanisms.
Exposing DPDK Telemetry via a socket interface enables service assurance
agents like collectd to consume data from DPDK. This is vital for
monitoring, fault-detection, and error reporting. A collectd plugin has
been created to interact with the DPDK Telemetry component, showing how it
can be used in practice. The collectd plugin will be upstreamed to collectd
at a later stage. A small python script is provided in
./usertools/telemetry_client.py to quick-start using DPDK Telemetry.
Note: Despite opterr being set to 0, --telemetry said to be 'unrecognized'
as a startup print. This is a cosmetic issue and will be addressed in the
future.
---
v2:
- Reworked telemetry as part of EAL instead of using vdev (Gaetan)
- Refactored rte_telemetry_command (Gaetan)
- Added MAINTAINERS file entry (Stephen)
- Updated docs to reflect vdev to eal rework
- Removed collectd patch from patchset (Thomas)
- General code clean up from v1 feedback
v3:
- Reworked registering with eal and moved to rte_param (Gaetan)
- Added BSD implementation for rte_param (Gaetan)
- Updated the paths to align with the new runtime file location (Mattias)
- Fixed pointer checks to align with the coding style 1.8.1 (Mattias)
- Added missing decref's and close's (Mattias)
- Fixed runtime issue in Meson (was not recognising flag due to linking)
- More general clean up
v4:
- Added Doxygen comments for rte_param.h (Thomas)
- Made eal_get_runtime_dir a public function to use outside of EAL (Thomas)
- Reworked telemetry to get path using rte_eal_get_runtime_dir (Thomas)
- Fixed checkpatch coding style error
v5:
- Moved the BUF_SIZE define to fix build (Harry)
- Set default config for telemetry to 'n' (Harry)
- Improved Doxygen comments (Thomas)
- Cleaned up rte_param struct (Thomas)
v6:
- Renamed rte_param to rte_option (Thomas)
- Moved internal functions to eal_private.h (Gaetan)
- Added fail check for pthread_attr_init() (Mattias)
- Changed socket implementation to SOCK_SEQPACKET (Mattias)
- Added check to avoid option duplicates (Gaetan)
- Removed telemetry example from Doxygen comment (Gaetan)
- General Doxygen clean-up (Thomas)
- General code clean-up (Mattias)
v7:
- Fix object leak (Mattias)
- General clean-up (Mattias)
- Fix rte_option header define
- Added release note update
- Rebased
v8:
- Added missing experimental tags
- Added Gaetan's Ack from ML
Ciara Power, Brian Archbold and Kevin Laatz (10):
telemetry: initial telemetry infrastructure
telemetry: add initial connection socket
telemetry: add client feature and sockets
telemetry: add parser for client socket messages
telemetry: update metrics before sending stats
telemetry: format json response when sending stats
telemetry: add tests for telemetry api
telemetry: add ability to disable selftest
doc: add telemetry documentation
usertools: add client python script for telemetry
Kevin Laatz (3):
eal: add option register infrastructure
eal: make get runtime dir function public
build: add dependency on telemetry to apps in meson
MAINTAINERS | 5 +
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/common_base | 5 +
config/meson.build | 3 +
doc/guides/howto/index.rst | 1 +
doc/guides/howto/telemetry.rst | 85 +
doc/guides/rel_notes/release_18_11.rst | 6 +
lib/Makefile | 2 +
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 16 +-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_filesystem.h | 15 +-
lib/librte_eal/common/eal_private.h | 21 +
lib/librte_eal/common/include/rte_eal.h | 9 +
lib/librte_eal/common/include/rte_option.h | 63 +
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 16 +-
lib/librte_eal/rte_eal_version.map | 2 +
lib/librte_telemetry/Makefile | 30 +
lib/librte_telemetry/meson.build | 9 +
lib/librte_telemetry/rte_telemetry.c | 1815 +++++++++++++++++++++
lib/librte_telemetry/rte_telemetry.h | 57 +
lib/librte_telemetry/rte_telemetry_internal.h | 81 +
lib/librte_telemetry/rte_telemetry_parser.c | 586 +++++++
lib/librte_telemetry/rte_telemetry_parser.h | 13 +
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 | 9 +
lib/meson.build | 3 +-
meson.build | 1 +
mk/rte.app.mk | 1 +
usertools/dpdk-telemetry-client.py | 116 ++
40 files changed, 3633 insertions(+), 19 deletions(-)
create mode 100644 doc/guides/howto/telemetry.rst
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
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_parser.c
create mode 100644 lib/librte_telemetry/rte_telemetry_parser.h
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
create mode 100644 lib/librte_telemetry/rte_telemetry_version.map
create mode 100644 usertools/dpdk-telemetry-client.py
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 01/13] eal: add option register infrastructure
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
@ 2018-10-24 16:02 ` Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 02/13] eal: make get runtime dir function public Kevin Laatz
` (12 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:02 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
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 <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 14 ++++++-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_private.h | 21 ++++++++++
lib/librte_eal/common/include/rte_option.h | 63 ++++++++++++++++++++++++++++++
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +++++++++++++++++++++++++
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 14 ++++++-
lib/librte_eal/rte_eal_version.map | 1 +
10 files changed, 170 insertions(+), 2 deletions(-)
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index d19f53c..bfeddaa 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -67,6 +67,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_option.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 7735194..178cfd6 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -42,6 +42,7 @@
#include <rte_devargs.h>
#include <rte_version.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#include <rte_atomic.h>
#include <malloc_heap.h>
@@ -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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -791,6 +800,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index cca6882..87d8c45 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_option.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/eal_private.h b/lib/librte_eal/common/eal_private.h
index b189d67..442c6dc 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -349,4 +349,25 @@ dev_sigbus_handler_register(void);
int
dev_sigbus_handler_unregister(void);
+/**
+ * Check if the option is registered.
+ *
+ * @param option
+ * The option to be parsed.
+ *
+ * @return
+ * 0 on success
+ * @return
+ * -1 on fail
+ */
+int
+rte_option_parse(const char *opt);
+
+/**
+ * Iterate through the registered options and execute the associated
+ * callback if enabled.
+ */
+void
+rte_option_init(void);
+
#endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_option.h b/lib/librte_eal/common/include/rte_option.h
new file mode 100644
index 0000000..8957b97
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_option.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#ifndef __INCLUDE_RTE_OPTION_H__
+#define __INCLUDE_RTE_OPTION_H__
+
+/**
+ * @file
+ *
+ * This API offers the ability to register options to the EAL command line and
+ * map those options to functions that will be executed at the end of EAL
+ * initialization. These options will be available as part of the EAL command
+ * line of applications and are dynamically managed.
+ *
+ * This is used primarily by DPDK libraries offering command line options.
+ * Currently, this API is limited to registering options without argument.
+ *
+ * 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_option 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_option_cb)(void);
+
+/*
+ * Structure describing the EAL command line option being registered.
+ */
+struct rte_option {
+ TAILQ_ENTRY(rte_option) next; /**< Next entry in the list. */
+ char *opt_str; /**< The option name. */
+ rte_option_cb cb; /**< Function called when option is used. */
+ int enabled; /**< Set when the option is used. */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Register an option to the EAL command line.
+ * When recognized, the associated function will be executed at the end of EAL
+ * initialization.
+ *
+ * The associated structure must be available the whole time this option is
+ * registered (i.e. not stack memory).
+ *
+ * @param opt
+ * Structure describing the option to parse.
+ */
+void __rte_experimental
+rte_option_register(struct rte_option *opt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build
index 04c4143..2a10d57 100644
--- a/lib/librte_eal/common/meson.build
+++ b/lib/librte_eal/common/meson.build
@@ -34,6 +34,7 @@ common_sources = files(
'malloc_mp.c',
'rte_keepalive.c',
'rte_malloc.c',
+ 'rte_option.c',
'rte_reciprocal.c',
'rte_service.c'
)
@@ -71,6 +72,7 @@ common_headers = files(
'include/rte_malloc_heap.h',
'include/rte_memory.h',
'include/rte_memzone.h',
+ 'include/rte_option.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_option.c b/lib/librte_eal/common/rte_option.c
new file mode 100644
index 0000000..02d59a8
--- /dev/null
+++ b/lib/librte_eal/common/rte_option.c
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_eal.h>
+#include <rte_option.h>
+
+#include "eal_private.h"
+
+TAILQ_HEAD(rte_option_list, rte_option);
+
+struct rte_option_list rte_option_list =
+ TAILQ_HEAD_INITIALIZER(rte_option_list);
+
+static struct rte_option *option;
+
+int
+rte_option_parse(const char *opt)
+{
+ /* Check if the option is registered */
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt, option->opt_str) == 0) {
+ option->enabled = 1;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void __rte_experimental
+rte_option_register(struct rte_option *opt)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt->opt_str, option->opt_str) == 0)
+ RTE_LOG(INFO, EAL, "Option %s has already been registered.",
+ opt->opt_str);
+ return;
+ }
+
+ TAILQ_INSERT_HEAD(&rte_option_list, opt, next);
+}
+
+void
+rte_option_init(void)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (option->enabled)
+ option->cb();
+ }
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 7280885..51deb57 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -75,6 +75,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_option.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 a00cebf..70ab032 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -48,6 +48,7 @@
#include <rte_atomic.h>
#include <malloc_heap.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -1080,6 +1089,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 08e3bc2..12ace18 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -351,6 +351,7 @@ EXPERIMENTAL {
rte_mp_request_sync;
rte_mp_request_async;
rte_mp_sendmsg;
+ rte_option_register;
rte_service_lcore_attr_get;
rte_service_lcore_attr_reset_all;
rte_service_may_be_active;
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 02/13] eal: make get runtime dir function public
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 01/13] eal: add option register infrastructure Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 03/13] telemetry: initial telemetry infrastructure Kevin Laatz
` (11 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
This patch makes the eal_get_runtime_dir() API public so it can be used
from outside EAL.
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_eal/bsdapp/eal/eal.c | 2 +-
lib/librte_eal/common/eal_filesystem.h | 15 ++++++++-------
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, 20 insertions(+), 9 deletions(-)
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 178cfd6..52c1dea 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..b3e8ae5 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,8 @@ 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 +67,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 +79,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 +100,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 3ee897c..150ced7 100644
--- a/lib/librte_eal/common/include/rte_eal.h
+++ b/lib/librte_eal/common/include/rte_eal.h
@@ -507,6 +507,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 70ab032..b75dd01 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 12ace18..42bd367 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -261,6 +261,7 @@ DPDK_18.08 {
DPDK_18.11 {
global:
+ rte_eal_get_runtime_dir;
rte_eal_hotplug_add;
rte_eal_hotplug_remove;
rte_strscpy;
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 03/13] telemetry: initial telemetry infrastructure
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 01/13] eal: add option register infrastructure Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 02/13] eal: make get runtime dir function public Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-25 20:33 ` Thomas Monjalon
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 04/13] telemetry: add initial connection socket Kevin Laatz
` (10 subsequent siblings)
13 siblings, 1 reply; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
config/common_base | 5 +
lib/Makefile | 2 +
lib/librte_telemetry/Makefile | 28 ++++++
lib/librte_telemetry/meson.build | 7 ++
lib/librte_telemetry/rte_telemetry.c | 123 +++++++++++++++++++++++++
lib/librte_telemetry/rte_telemetry.h | 42 +++++++++
lib/librte_telemetry/rte_telemetry_internal.h | 32 +++++++
lib/librte_telemetry/rte_telemetry_version.map | 8 ++
lib/meson.build | 2 +-
mk/rte.app.mk | 1 +
10 files changed, 249 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 be7365e..d59141b 100644
--- a/config/common_base
+++ b/config/common_base
@@ -753,6 +753,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..7f4ad03
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_metrics.h>
+#include <rte_option.h>
+
+#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_experimental
+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);
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0) {
+ TELEMETRY_LOG_ERR("Pthread attribute init failed");
+ return -EPERM;
+ }
+
+ 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_experimental
+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_option option = {
+ .opt_str = "--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_option_register(&option);
+}
diff --git a/lib/librte_telemetry/rte_telemetry.h b/lib/librte_telemetry/rte_telemetry.h
new file mode 100644
index 0000000..1e8dce6
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <stdint.h>
+
+#ifndef _RTE_TELEMETRY_H_
+#define _RTE_TELEMETRY_H_
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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_experimental
+rte_telemetry_init(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Clean up and free memory.
+ *
+ * @return
+ * 0 on success
+ * @return
+ * -EPERM on failure
+ */
+int32_t __rte_experimental
+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 <rte_log.h>
+
+#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..bbcd9a7
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry_version.map
@@ -0,0 +1,8 @@
+EXPERIMENTAL {
+ global:
+
+ rte_telemetry_cleanup;
+ rte_telemetry_init;
+
+ local: *;
+};
diff --git a/lib/meson.build b/lib/meson.build
index 24351cc..90a4227 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 3203cf0..a5ce715 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_telemetry
_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER) += -lrte_timer
_LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += -lrte_mempool
_LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING) += -lrte_mempool_ring
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v8 03/13] telemetry: initial telemetry infrastructure
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 03/13] telemetry: initial telemetry infrastructure Kevin Laatz
@ 2018-10-25 20:33 ` Thomas Monjalon
0 siblings, 0 replies; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-25 20:33 UTC (permalink / raw)
To: Kevin Laatz
Cc: dev, harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold
We forgot to add rte_telemetry.h in doxygen:
doc/api/doxy-api-index.md
doc/api/doxy-api.conf.in
We need a section @file at the top of the header file
to make it appear in doxygen.
24/10/2018 18:03, Kevin Laatz:
> --- /dev/null
> +++ b/lib/librte_telemetry/rte_telemetry.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Intel Corporation
> + */
> +
> +#include <stdint.h>
> +
> +#ifndef _RTE_TELEMETRY_H_
> +#define _RTE_TELEMETRY_H_
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * 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_experimental
> +rte_telemetry_init(void);
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * Clean up and free memory.
> + *
> + * @return
> + * 0 on success
> + * @return
> + * -EPERM on failure
> + */
> +int32_t __rte_experimental
> +rte_telemetry_cleanup(void);
> +
> +#endif
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 04/13] telemetry: add initial connection socket
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (2 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 03/13] telemetry: initial telemetry infrastructure Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets Kevin Laatz
` (9 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/rte_telemetry.c | 225 ++++++++++++++++++++++++++
lib/librte_telemetry/rte_telemetry_internal.h | 4 +
2 files changed, 229 insertions(+)
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index 7f4ad03..e9b3330 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -3,23 +3,163 @@
*/
#include <unistd.h>
+#include <fcntl.h>
#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_metrics.h>
#include <rte_option.h>
+#include <rte_string_fns.h>
#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) {
+ 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,67 @@ 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;
+ char socket_path[BUF_SIZE];
+
+ if (telemetry == NULL)
+ return -1;
+
+ telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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");
+ return -EPERM;
+ }
+
+ return -1;
+}
+
int32_t __rte_experimental
rte_telemetry_init()
{
@@ -77,6 +284,14 @@ rte_telemetry_init()
return -EPERM;
}
+ 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;
+ }
+
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
(void *)static_telemetry);
@@ -95,11 +310,21 @@ rte_telemetry_init()
int32_t __rte_experimental
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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (3 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 04/13] telemetry: add initial connection socket Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-25 20:29 ` Thomas Monjalon
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 06/13] telemetry: add parser for client socket messages Kevin Laatz
` (8 subsequent siblings)
13 siblings, 1 reply; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/meson.build | 2 +
lib/librte_telemetry/rte_telemetry.c | 370 +++++++++++++++++++++++++-
lib/librte_telemetry/rte_telemetry_internal.h | 25 ++
mk/rte.app.mk | 2 +-
4 files changed, 395 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 e9b3330..3c8b922 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -7,6 +7,7 @@
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <jansson.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
@@ -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,38 @@ 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;
+
+ buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
+
+ if (buffer_read == -1) {
+ TELEMETRY_LOG_ERR("Read error");
+ return -1;
+ } else if (buffer_read == 0) {
+ goto close_socket;
+ } else {
+ buf[buffer_read] = '\0';
+ ret = rte_telemetry_parse_client_message(telemetry, buf);
+ if (ret < 0)
+ TELEMETRY_LOG_WARN("Parse message failed");
+ goto close_socket;
+ }
+
+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 +259,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 +269,31 @@ 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);
+
+ if (bytes > 0) {
+ client_buf[bytes] = '\0';
+ telemetry->request_client = client;
+ }
}
return 0;
@@ -173,6 +316,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;
}
@@ -291,6 +440,7 @@ rte_telemetry_init()
TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
return -EPERM;
}
+ TAILQ_INIT(&static_telemetry->client_list_head);
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
@@ -307,11 +457,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_experimental
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) {
@@ -328,6 +506,192 @@ 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;
+
+ 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_SEQPACKET, 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");
+ 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");
+ json_decref(root);
+ 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 <rte_log.h>
+#include <rte_tailq.h>
#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 a5ce715..620059c 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_telemetry
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets Kevin Laatz
@ 2018-10-25 20:29 ` Thomas Monjalon
2018-10-25 20:41 ` Thomas Monjalon
0 siblings, 1 reply; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-25 20:29 UTC (permalink / raw)
To: Kevin Laatz
Cc: dev, harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold
24/10/2018 18:03, Kevin Laatz:
> --- 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
I just discovered an issue when trying to compile for arm64
(with devtools/test-meson-builds.sh):
/usr/lib/gcc/aarch64-linux-gnu/8.2.0/../../../../aarch64-linux-gnu/bin/ld:
cannot find -ljansson
I am worried because it is a real blocker.
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets
2018-10-25 20:29 ` Thomas Monjalon
@ 2018-10-25 20:41 ` Thomas Monjalon
2018-10-25 20:44 ` Bruce Richardson
0 siblings, 1 reply; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-25 20:41 UTC (permalink / raw)
To: Kevin Laatz
Cc: dev, harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold
25/10/2018 22:29, Thomas Monjalon:
> 24/10/2018 18:03, Kevin Laatz:
> > --- 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
>
> I just discovered an issue when trying to compile for arm64
> (with devtools/test-meson-builds.sh):
>
> /usr/lib/gcc/aarch64-linux-gnu/8.2.0/../../../../aarch64-linux-gnu/bin/ld:
> cannot find -ljansson
>
> I am worried because it is a real blocker.
The dependency must be optional.
Should we disable the library if jansson is not found?
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets
2018-10-25 20:41 ` Thomas Monjalon
@ 2018-10-25 20:44 ` Bruce Richardson
2018-10-25 20:49 ` Thomas Monjalon
0 siblings, 1 reply; 219+ messages in thread
From: Bruce Richardson @ 2018-10-25 20:44 UTC (permalink / raw)
To: Thomas Monjalon
Cc: Kevin Laatz, dev, harry.van.haaren, stephen, gaetan.rivet,
shreyansh.jain, mattias.ronnblom, Ciara Power, Brian Archbold
On Thu, Oct 25, 2018 at 10:41:53PM +0200, Thomas Monjalon wrote:
> 25/10/2018 22:29, Thomas Monjalon:
> > 24/10/2018 18:03, Kevin Laatz:
> > > --- 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
> >
> > I just discovered an issue when trying to compile for arm64
> > (with devtools/test-meson-builds.sh):
> >
> > /usr/lib/gcc/aarch64-linux-gnu/8.2.0/../../../../aarch64-linux-gnu/bin/ld:
> > cannot find -ljansson
> >
> > I am worried because it is a real blocker.
>
> The dependency must be optional.
> Should we disable the library if jansson is not found?
>
Yes, it should be.
Needs:
jansson = cc.find_library('jansson', required: false)
build = jansson.found()
/Bruce
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets
2018-10-25 20:44 ` Bruce Richardson
@ 2018-10-25 20:49 ` Thomas Monjalon
2018-10-25 21:16 ` Richardson, Bruce
0 siblings, 1 reply; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-25 20:49 UTC (permalink / raw)
To: Bruce Richardson
Cc: Kevin Laatz, dev, harry.van.haaren, stephen, gaetan.rivet,
shreyansh.jain, mattias.ronnblom, Ciara Power, Brian Archbold
25/10/2018 22:44, Bruce Richardson:
> On Thu, Oct 25, 2018 at 10:41:53PM +0200, Thomas Monjalon wrote:
> > 25/10/2018 22:29, Thomas Monjalon:
> > > 24/10/2018 18:03, Kevin Laatz:
> > > > --- 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
> > >
> > > I just discovered an issue when trying to compile for arm64
> > > (with devtools/test-meson-builds.sh):
> > >
> > > /usr/lib/gcc/aarch64-linux-gnu/8.2.0/../../../../aarch64-linux-gnu/bin/ld:
> > > cannot find -ljansson
> > >
> > > I am worried because it is a real blocker.
> >
> > The dependency must be optional.
> > Should we disable the library if jansson is not found?
> >
> Yes, it should be.
>
> Needs:
>
> jansson = cc.find_library('jansson', required: false)
> build = jansson.found()
And for the makefile?
It has been introduced (too early) in patch 3:
LDLIBS += -ljansson
I think we must use pkg-config to check if jansson is found.
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets
2018-10-25 20:49 ` Thomas Monjalon
@ 2018-10-25 21:16 ` Richardson, Bruce
2018-10-25 23:58 ` Thomas Monjalon
0 siblings, 1 reply; 219+ messages in thread
From: Richardson, Bruce @ 2018-10-25 21:16 UTC (permalink / raw)
To: Thomas Monjalon
Cc: Laatz, Kevin, dev, Van Haaren, Harry, stephen, gaetan.rivet,
shreyansh.jain, mattias.ronnblom, Ciara Power, Brian Archbold
> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> Sent: Thursday, October 25, 2018 9:50 PM
> To: Richardson, Bruce <bruce.richardson@intel.com>
> Cc: Laatz, Kevin <kevin.laatz@intel.com>; dev@dpdk.org; Van Haaren, Harry
> <harry.van.haaren@intel.com>; stephen@networkplumber.org;
> gaetan.rivet@6wind.com; shreyansh.jain@nxp.com;
> mattias.ronnblom@ericsson.com; Ciara Power <ciara.power@intel.com>; Brian
> Archbold <brian.archbold@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and
> sockets
>
> 25/10/2018 22:44, Bruce Richardson:
> > On Thu, Oct 25, 2018 at 10:41:53PM +0200, Thomas Monjalon wrote:
> > > 25/10/2018 22:29, Thomas Monjalon:
> > > > 24/10/2018 18:03, Kevin Laatz:
> > > > > --- 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
> > > >
> > > > I just discovered an issue when trying to compile for arm64 (with
> > > > devtools/test-meson-builds.sh):
> > > >
> > > > /usr/lib/gcc/aarch64-linux-gnu/8.2.0/../../../../aarch64-linux-
> gnu/bin/ld:
> > > > cannot find -ljansson
> > > >
> > > > I am worried because it is a real blocker.
> > >
> > > The dependency must be optional.
> > > Should we disable the library if jansson is not found?
> > >
> > Yes, it should be.
> >
> > Needs:
> >
> > jansson = cc.find_library('jansson', required: false)
> > build = jansson.found()
>
> And for the makefile?
>
> It has been introduced (too early) in patch 3:
> LDLIBS += -ljansson
> I think we must use pkg-config to check if jansson is found.
>
I didn't look at the makefile, because you never asked! :-)
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets
2018-10-25 21:16 ` Richardson, Bruce
@ 2018-10-25 23:58 ` Thomas Monjalon
0 siblings, 0 replies; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-25 23:58 UTC (permalink / raw)
To: Richardson, Bruce, Laatz, Kevin
Cc: dev, Van Haaren, Harry, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold
25/10/2018 23:16, Richardson, Bruce:
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > 25/10/2018 22:44, Bruce Richardson:
> > > On Thu, Oct 25, 2018 at 10:41:53PM +0200, Thomas Monjalon wrote:
> > > > 25/10/2018 22:29, Thomas Monjalon:
> > > > > 24/10/2018 18:03, Kevin Laatz:
> > > > > > --- 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
> > > > >
> > > > > I just discovered an issue when trying to compile for arm64 (with
> > > > > devtools/test-meson-builds.sh):
> > > > >
> > > > > /usr/lib/gcc/aarch64-linux-gnu/8.2.0/../../../../aarch64-linux-
> > gnu/bin/ld:
> > > > > cannot find -ljansson
> > > > >
> > > > > I am worried because it is a real blocker.
> > > >
> > > > The dependency must be optional.
> > > > Should we disable the library if jansson is not found?
> > > >
> > > Yes, it should be.
> > >
> > > Needs:
> > >
> > > jansson = cc.find_library('jansson', required: false)
> > > build = jansson.found()
> >
> > And for the makefile?
> >
> > It has been introduced (too early) in patch 3:
> > LDLIBS += -ljansson
> > I think we must use pkg-config to check if jansson is found.
>
> I didn't look at the makefile, because you never asked! :-)
The code is already written in examples/power:
https://patches.dpdk.org/patch/46984/
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 06/13] telemetry: add parser for client socket messages
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (4 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 05/13] telemetry: add client feature and sockets Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 07/13] telemetry: update metrics before sending stats Kevin Laatz
` (7 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/Makefile | 1 +
lib/librte_telemetry/meson.build | 4 +-
lib/librte_telemetry/rte_telemetry.c | 8 +
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, 606 insertions(+), 2 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 3c8b922..cac7884 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
@@ -283,6 +284,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,6 +295,12 @@ rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)
if (bytes > 0) {
client_buf[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;
+ }
}
}
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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+
+#include <rte_metrics.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+
+#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
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 07/13] telemetry: update metrics before sending stats
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (5 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 06/13] telemetry: add parser for client socket messages Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 08/13] telemetry: format json response when " Kevin Laatz
` (6 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 cac7884..7616e7c 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;
}
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 08/13] telemetry: format json response when sending stats
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (6 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 07/13] telemetry: update metrics before sending stats Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 09/13] telemetry: add tests for telemetry api Kevin Laatz
` (5 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 7616e7c..36cd748 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");
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 09/13] telemetry: add tests for telemetry api
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (7 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 08/13] telemetry: format json response when " Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 10/13] telemetry: add ability to disable selftest Kevin Laatz
` (4 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/Makefile | 1 +
lib/librte_telemetry/meson.build | 4 +-
lib/librte_telemetry/rte_telemetry.c | 653 ++++++++++++++++++++++
lib/librte_telemetry/rte_telemetry.h | 15 +
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, 1284 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 36cd748..5b66b71 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;
}
@@ -1139,6 +1171,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_SEQPACKET, 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_experimental
+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_SEQPACKET, 0);
+ *recv_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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 1e8dce6..807bd9f 100644
--- a/lib/librte_telemetry/rte_telemetry.h
+++ b/lib/librte_telemetry/rte_telemetry.h
@@ -39,4 +39,19 @@ rte_telemetry_init(void);
int32_t __rte_experimental
rte_telemetry_cleanup(void);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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_experimental
+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..5fe93fa
--- /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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_tailq.h>
+#include <rte_string_fns.h>
+
+#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_SEQPACKET, 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 <stdbool.h>
+
+#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 bbcd9a7..b5a8265 100644
--- a/lib/librte_telemetry/rte_telemetry_version.map
+++ b/lib/librte_telemetry/rte_telemetry_version.map
@@ -3,6 +3,7 @@ EXPERIMENTAL {
rte_telemetry_cleanup;
rte_telemetry_init;
+ rte_telemetry_selftest;
local: *;
};
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 10/13] telemetry: add ability to disable selftest
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (8 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 09/13] telemetry: add tests for telemetry api Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 11/13] doc: add telemetry documentation Kevin Laatz
` (3 subsequent siblings)
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 5b66b71..2e27491 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;
}
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 11/13] doc: add telemetry documentation
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (9 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 10/13] telemetry: add ability to disable selftest Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-25 20:31 ` Thomas Monjalon
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 12/13] usertools: add client python script for telemetry Kevin Laatz
` (2 subsequent siblings)
13 siblings, 1 reply; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 and a release notes update for
telemetry.
Signed-off-by: Ciara Power <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>
---
MAINTAINERS | 5 ++
doc/guides/howto/index.rst | 1 +
doc/guides/howto/telemetry.rst | 85 ++++++++++++++++++++++++++++++++++
doc/guides/rel_notes/release_18_11.rst | 6 +++
4 files changed, 97 insertions(+)
create mode 100644 doc/guides/howto/telemetry.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index b220479..6b64c15 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1208,6 +1208,11 @@ F: test/bpf/
F: test/test/test_bpf.c
F: doc/guides/prog_guide/bpf_lib.rst
+Telemetry - EXPERIMENTAL
+M: Kevin Laatz <kevin.laatz@intel.com>
+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.
diff --git a/doc/guides/rel_notes/release_18_11.rst b/doc/guides/rel_notes/release_18_11.rst
index 04f3745..e82c790 100644
--- a/doc/guides/rel_notes/release_18_11.rst
+++ b/doc/guides/rel_notes/release_18_11.rst
@@ -189,6 +189,12 @@ New Features
the specified port. The port must be stopped before the command call in order
to reconfigure queues.
+* **Added Telemetry API.**
+
+ Added the telemetry API which allows applications to transparently expose
+ their telemetry via a UNIX socket in JSON. The JSON can be consumed by any
+ Service Assurance agent, such as CollectD.
+
* **Add a new sample for vDPA**
The vdpa sample application creates vhost-user sockets by using the
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v8 11/13] doc: add telemetry documentation
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 11/13] doc: add telemetry documentation Kevin Laatz
@ 2018-10-25 20:31 ` Thomas Monjalon
0 siblings, 0 replies; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-25 20:31 UTC (permalink / raw)
To: Kevin Laatz
Cc: dev, harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold
24/10/2018 18:03, Kevin Laatz:
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> +Telemetry - EXPERIMENTAL
> +M: Kevin Laatz <kevin.laatz@intel.com>
> +F: lib/librte_telemetry/
> +F: usertools/dpdk-telemetry-client.py
> +F: doc/guides/howto/telemetry.rst
It would be a bit better to introduce it in previous patches when files
are created. I wanted to spread it in other patches myself,
but I stopped when encountering a build issue (patch 5).
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 12/13] usertools: add client python script for telemetry
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (10 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 11/13] doc: add telemetry documentation Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 13/13] build: add dependency on telemetry to apps in meson Kevin Laatz
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Ciara Power, Brian Archbold,
Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <file_path>".
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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..6dcf62b
--- /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_SEQPACKET)
+ self.recv_fd = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ 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)
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v8 13/13] build: add dependency on telemetry to apps in meson
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (11 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 12/13] usertools: add client python script for telemetry Kevin Laatz
@ 2018-10-24 16:03 ` Kevin Laatz
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
13 siblings, 0 replies; 219+ messages in thread
From: Kevin Laatz @ 2018-10-24 16:03 UTC (permalink / raw)
To: dev
Cc: harry.van.haaren, stephen, gaetan.rivet, shreyansh.jain, thomas,
mattias.ronnblom, bruce.richardson, Kevin Laatz
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 <bruce.richardson@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 e68d949..78bc3af 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -29,7 +29,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)
@@ -43,7 +43,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 cd66618..6006c60 100644
--- a/app/test-pmd/meson.build
+++ b/app/test-pmd/meson.build
@@ -24,7 +24,7 @@ sources = files('cmdline.c',
'txonly.c',
'util.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 90a4227..ae99ab0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -131,6 +131,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 = []
--
2.9.5
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library
2018-10-24 16:02 ` [dpdk-dev] [PATCH v8 " Kevin Laatz
` (12 preceding siblings ...)
2018-10-24 16:03 ` [dpdk-dev] [PATCH v8 13/13] build: add dependency on telemetry to apps in meson Kevin Laatz
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 01/12] eal: add option register infrastructure Harry van Haaren
` (12 more replies)
13 siblings, 13 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Harry van Haaren
This patchset introduces a Telemetry library for DPDK Service Assurance.
This library provides an easy way to query DPDK Ethdev metrics.
The telemetry library provides a method for a service assurance component
to retrieve metrics from a DPDK packet forwarding application.
Communicating from the service assurance component to DPDK is done using a
UNIX domain socket, passing a JSON formatted string. A reply is sent (again
a JSON formatted string) of the current DPDK metrics.
The telemetry component makes use of the existing rte_metrics library to
query values. The values to be transmitted via the telemetry infrastructure
must be present in the Metrics library. Currently the ethdev values are
pushed to the metrics library, and the queried from there there is an open
question on how applications would like this to occur. Currently only
ethdev to metrics functionality is implemented, however other subsystems
like crypto, eventdev, keepalive etc can use similar mechanisms.
Exposing DPDK Telemetry via a socket interface enables service assurance
agents like collectd to consume data from DPDK. This is vital for
monitoring, fault-detection, and error reporting. A collectd plugin has
been created to interact with the DPDK Telemetry component, showing how it
can be used in practice. The collectd plugin will be upstreamed to collectd
at a later stage. A small python script is provided in
./usertools/telemetry_client.py to quick-start using DPDK Telemetry.
Note: Despite opterr being set to 0, --telemetry said to be 'unrecognized'
as a startup print. This is a cosmetic issue and will be addressed in the
future.
---
v2:
- Reworked telemetry as part of EAL instead of using vdev (Gaetan)
- Refactored rte_telemetry_command (Gaetan)
- Added MAINTAINERS file entry (Stephen)
- Updated docs to reflect vdev to eal rework
- Removed collectd patch from patchset (Thomas)
- General code clean up from v1 feedback
v3:
- Reworked registering with eal and moved to rte_param (Gaetan)
- Added BSD implementation for rte_param (Gaetan)
- Updated the paths to align with the new runtime file location (Mattias)
- Fixed pointer checks to align with the coding style 1.8.1 (Mattias)
- Added missing decref's and close's (Mattias)
- Fixed runtime issue in Meson (was not recognising flag due to linking)
- More general clean up
v4:
- Added Doxygen comments for rte_param.h (Thomas)
- Made eal_get_runtime_dir a public function to use outside of EAL (Thomas)
- Reworked telemetry to get path using rte_eal_get_runtime_dir (Thomas)
- Fixed checkpatch coding style error
v5:
- Moved the BUF_SIZE define to fix build (Harry)
- Set default config for telemetry to 'n' (Harry)
- Improved Doxygen comments (Thomas)
- Cleaned up rte_param struct (Thomas)
v6:
- Renamed rte_param to rte_option (Thomas)
- Moved internal functions to eal_private.h (Gaetan)
- Added fail check for pthread_attr_init() (Mattias)
- Changed socket implementation to SOCK_SEQPACKET (Mattias)
- Added check to avoid option duplicates (Gaetan)
- Removed telemetry example from Doxygen comment (Gaetan)
- General Doxygen clean-up (Thomas)
- General code clean-up (Mattias)
v7:
- Fix object leak (Mattias)
- General clean-up (Mattias)
- Fix rte_option header define
- Added release note update
- Rebased
v8:
- Added missing experimental tags
- Added Gaetan's Ack from ML
v9:
- Added doxygen to build (Thomas)
- Added doxygen @file tag (Thomas)
- Detect jansson library dynamically with Make/pkg-config (Thomas)
- Make jansson optional build-dep for Meson (Thomas/Bruce)
Ciara Power (9):
telemetry: initial telemetry infrastructure
telemetry: add initial connection socket
telemetry: add client feature and sockets
telemetry: add parser for client socket messages
telemetry: update metrics before sending stats
telemetry: format json response when sending stats
telemetry: add ability to disable selftest
doc: add telemetry documentation
usertools: add client python script for telemetry
Kevin Laatz (3):
eal: add option register infrastructure
eal: make get runtime dir function public
build: add dependency on telemetry to apps in meson
MAINTAINERS | 5 +
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/common_base | 5 +
config/meson.build | 3 +
doc/api/doxy-api-index.md | 3 +-
doc/api/doxy-api.conf.in | 1 +
doc/guides/howto/index.rst | 1 +
doc/guides/howto/telemetry.rst | 85 +
doc/guides/rel_notes/release_18_11.rst | 6 +
lib/Makefile | 2 +
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 16 +-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_filesystem.h | 15 +-
lib/librte_eal/common/eal_private.h | 21 +
lib/librte_eal/common/include/rte_eal.h | 9 +
lib/librte_eal/common/include/rte_option.h | 63 +
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 16 +-
lib/librte_eal/rte_eal_version.map | 2 +
lib/librte_telemetry/Makefile | 30 +
lib/librte_telemetry/meson.build | 15 +
lib/librte_telemetry/rte_telemetry.c | 1815 +++++++++++++++++
lib/librte_telemetry/rte_telemetry.h | 66 +
lib/librte_telemetry/rte_telemetry_internal.h | 81 +
lib/librte_telemetry/rte_telemetry_parser.c | 586 ++++++
lib/librte_telemetry/rte_telemetry_parser.h | 14 +
.../rte_telemetry_parser_test.c | 534 +++++
.../rte_telemetry_parser_test.h | 39 +
.../rte_telemetry_socket_tests.h | 36 +
.../rte_telemetry_version.map | 10 +
lib/meson.build | 3 +-
meson.build | 2 +
mk/rte.app.mk | 3 +-
mk/rte.vars.mk | 6 +
usertools/dpdk-telemetry-client.py | 116 ++
43 files changed, 3661 insertions(+), 21 deletions(-)
create mode 100644 doc/guides/howto/telemetry.rst
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
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_parser.c
create mode 100644 lib/librte_telemetry/rte_telemetry_parser.h
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
create mode 100644 lib/librte_telemetry/rte_telemetry_version.map
create mode 100644 usertools/dpdk-telemetry-client.py
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 01/12] eal: add option register infrastructure
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 02/12] eal: make get runtime dir function public Harry van Haaren
` (11 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Kevin Laatz
From: Kevin Laatz <kevin.laatz@intel.com>
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 <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 14 ++++-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_private.h | 21 ++++++++
lib/librte_eal/common/include/rte_option.h | 63 ++++++++++++++++++++++
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +++++++++++++++++++
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 14 ++++-
lib/librte_eal/rte_eal_version.map | 1 +
10 files changed, 170 insertions(+), 2 deletions(-)
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index d19f53c1e..bfeddaadc 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -67,6 +67,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_option.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 f94c5c5f4..11cbda964 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -42,6 +42,7 @@
#include <rte_devargs.h>
#include <rte_version.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#include <rte_atomic.h>
#include <malloc_heap.h>
@@ -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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -791,6 +800,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index cca68826f..87d8c455d 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_option.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/eal_private.h b/lib/librte_eal/common/eal_private.h
index b189d675d..442c6dc48 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -349,4 +349,25 @@ dev_sigbus_handler_register(void);
int
dev_sigbus_handler_unregister(void);
+/**
+ * Check if the option is registered.
+ *
+ * @param option
+ * The option to be parsed.
+ *
+ * @return
+ * 0 on success
+ * @return
+ * -1 on fail
+ */
+int
+rte_option_parse(const char *opt);
+
+/**
+ * Iterate through the registered options and execute the associated
+ * callback if enabled.
+ */
+void
+rte_option_init(void);
+
#endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_option.h b/lib/librte_eal/common/include/rte_option.h
new file mode 100644
index 000000000..8957b970c
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_option.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#ifndef __INCLUDE_RTE_OPTION_H__
+#define __INCLUDE_RTE_OPTION_H__
+
+/**
+ * @file
+ *
+ * This API offers the ability to register options to the EAL command line and
+ * map those options to functions that will be executed at the end of EAL
+ * initialization. These options will be available as part of the EAL command
+ * line of applications and are dynamically managed.
+ *
+ * This is used primarily by DPDK libraries offering command line options.
+ * Currently, this API is limited to registering options without argument.
+ *
+ * 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_option 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_option_cb)(void);
+
+/*
+ * Structure describing the EAL command line option being registered.
+ */
+struct rte_option {
+ TAILQ_ENTRY(rte_option) next; /**< Next entry in the list. */
+ char *opt_str; /**< The option name. */
+ rte_option_cb cb; /**< Function called when option is used. */
+ int enabled; /**< Set when the option is used. */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Register an option to the EAL command line.
+ * When recognized, the associated function will be executed at the end of EAL
+ * initialization.
+ *
+ * The associated structure must be available the whole time this option is
+ * registered (i.e. not stack memory).
+ *
+ * @param opt
+ * Structure describing the option to parse.
+ */
+void __rte_experimental
+rte_option_register(struct rte_option *opt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build
index 04c414356..2a10d57d8 100644
--- a/lib/librte_eal/common/meson.build
+++ b/lib/librte_eal/common/meson.build
@@ -34,6 +34,7 @@ common_sources = files(
'malloc_mp.c',
'rte_keepalive.c',
'rte_malloc.c',
+ 'rte_option.c',
'rte_reciprocal.c',
'rte_service.c'
)
@@ -71,6 +72,7 @@ common_headers = files(
'include/rte_malloc_heap.h',
'include/rte_memory.h',
'include/rte_memzone.h',
+ 'include/rte_option.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_option.c b/lib/librte_eal/common/rte_option.c
new file mode 100644
index 000000000..02d59a869
--- /dev/null
+++ b/lib/librte_eal/common/rte_option.c
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_eal.h>
+#include <rte_option.h>
+
+#include "eal_private.h"
+
+TAILQ_HEAD(rte_option_list, rte_option);
+
+struct rte_option_list rte_option_list =
+ TAILQ_HEAD_INITIALIZER(rte_option_list);
+
+static struct rte_option *option;
+
+int
+rte_option_parse(const char *opt)
+{
+ /* Check if the option is registered */
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt, option->opt_str) == 0) {
+ option->enabled = 1;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void __rte_experimental
+rte_option_register(struct rte_option *opt)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt->opt_str, option->opt_str) == 0)
+ RTE_LOG(INFO, EAL, "Option %s has already been registered.",
+ opt->opt_str);
+ return;
+ }
+
+ TAILQ_INSERT_HEAD(&rte_option_list, opt, next);
+}
+
+void
+rte_option_init(void)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (option->enabled)
+ option->cb();
+ }
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 728088594..51deb5797 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -75,6 +75,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_option.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 76536bae2..930070e43 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -48,6 +48,7 @@
#include <rte_atomic.h>
#include <malloc_heap.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -1080,6 +1089,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index f4a2b38fd..5b6d91ffd 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -350,6 +350,7 @@ EXPERIMENTAL {
rte_mp_request_sync;
rte_mp_request_async;
rte_mp_sendmsg;
+ rte_option_register;
rte_service_lcore_attr_get;
rte_service_lcore_attr_reset_all;
rte_service_may_be_active;
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 02/12] eal: make get runtime dir function public
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 01/12] eal: add option register infrastructure Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 03/12] telemetry: initial telemetry infrastructure Harry van Haaren
` (10 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Kevin Laatz
From: Kevin Laatz <kevin.laatz@intel.com>
This patch makes the eal_get_runtime_dir() API public so it can be used
from outside EAL.
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_eal/bsdapp/eal/eal.c | 2 +-
lib/librte_eal/common/eal_filesystem.h | 15 ++++++++-------
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, 20 insertions(+), 9 deletions(-)
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 11cbda964..21997ced8 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 de05febf4..b3e8ae5ea 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,8 @@ 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 +67,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 +79,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 +100,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 6514a9fe6..a0cedd573 100644
--- a/lib/librte_eal/common/include/rte_eal.h
+++ b/lib/librte_eal/common/include/rte_eal.h
@@ -507,6 +507,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 930070e43..7b11375f4 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 5b6d91ffd..28bfa4950 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -259,6 +259,7 @@ DPDK_18.08 {
DPDK_18.11 {
global:
+ rte_eal_get_runtime_dir;
rte_eal_hotplug_add;
rte_eal_hotplug_remove;
rte_strscpy;
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 03/12] telemetry: initial telemetry infrastructure
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 01/12] eal: add option register infrastructure Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 02/12] eal: make get runtime dir function public Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-27 1:56 ` Thomas Monjalon
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 04/12] telemetry: add initial connection socket Harry van Haaren
` (9 subsequent siblings)
12 siblings, 1 reply; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz,
Radu Nicolau
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
v9:
- Add telemetry.h to doxygen index/conf (Thomas)
- Add @file section to telemetry.h for Doxygen (Thomas)
- Move -ljansson to patch that introduces json_* calls (Thomas)
---
config/common_base | 5 +
doc/api/doxy-api-index.md | 3 +-
doc/api/doxy-api.conf.in | 1 +
lib/Makefile | 2 +
lib/librte_telemetry/Makefile | 27 ++++
lib/librte_telemetry/meson.build | 7 +
lib/librte_telemetry/rte_telemetry.c | 123 ++++++++++++++++++
lib/librte_telemetry/rte_telemetry.h | 51 ++++++++
lib/librte_telemetry/rte_telemetry_internal.h | 32 +++++
.../rte_telemetry_version.map | 8 ++
lib/meson.build | 2 +-
mk/rte.app.mk | 3 +-
mk/rte.vars.mk | 6 +
13 files changed, 267 insertions(+), 3 deletions(-)
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 38beaabb3..4236b7f46 100644
--- a/config/common_base
+++ b/config/common_base
@@ -756,6 +756,11 @@ CONFIG_RTE_LIBRTE_CMDLINE_DEBUG=n
CONFIG_RTE_LIBRTE_HASH=y
CONFIG_RTE_LIBRTE_HASH_DEBUG=n
+#
+# Compile librte_telemetry
+#
+CONFIG_RTE_LIBRTE_TELEMETRY=y
+
#
# Compile librte_efd
#
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index a3039d168..0d0b9bd6c 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -159,7 +159,8 @@ The public API headers are grouped by topics:
[hexdump] (@ref rte_hexdump.h),
[debug] (@ref rte_debug.h),
[log] (@ref rte_log.h),
- [errno] (@ref rte_errno.h)
+ [errno] (@ref rte_errno.h),
+ [telemetry] (@ref rte_telemetry.h)
- **misc**:
[EAL config] (@ref rte_eal.h),
diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in
index 3b652ac9c..77ba327a8 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -56,6 +56,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \
@TOPDIR@/lib/librte_sched \
@TOPDIR@/lib/librte_security \
@TOPDIR@/lib/librte_table \
+ @TOPDIR@/lib/librte_telemetry \
@TOPDIR@/lib/librte_timer \
@TOPDIR@/lib/librte_vhost
INPUT += @API_EXAMPLES@
diff --git a/lib/Makefile b/lib/Makefile
index 062cbdfd7..b7370ef97 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -106,6 +106,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 000000000..a2d4ff166
--- /dev/null
+++ b/lib/librte_telemetry/Makefile
@@ -0,0 +1,27 @@
+# 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
+
+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 000000000..7716076a9
--- /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 000000000..7f4ad0342
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_metrics.h>
+#include <rte_option.h>
+
+#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_experimental
+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);
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0) {
+ TELEMETRY_LOG_ERR("Pthread attribute init failed");
+ return -EPERM;
+ }
+
+ 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_experimental
+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_option option = {
+ .opt_str = "--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_option_register(&option);
+}
diff --git a/lib/librte_telemetry/rte_telemetry.h b/lib/librte_telemetry/rte_telemetry.h
new file mode 100644
index 000000000..97674ae2d
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <stdint.h>
+
+#ifndef _RTE_TELEMETRY_H_
+#define _RTE_TELEMETRY_H_
+
+/**
+ * @file
+ * RTE Telemetry
+ *
+ * The telemetry library provides a method to retrieve statistics from
+ * DPDK by sending a JSON encoded message over a socket. DPDK will send
+ * a JSON encoded response containing telemetry data.
+ ***/
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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_experimental
+rte_telemetry_init(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Clean up and free memory.
+ *
+ * @return
+ * 0 on success
+ * @return
+ * -EPERM on failure
+ */
+int32_t __rte_experimental
+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 000000000..4e810a84c
--- /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 <rte_log.h>
+
+#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 000000000..bbcd9a796
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry_version.map
@@ -0,0 +1,8 @@
+EXPERIMENTAL {
+ global:
+
+ rte_telemetry_cleanup;
+ rte_telemetry_init;
+
+ local: *;
+};
diff --git a/lib/meson.build b/lib/meson.build
index 2b903fa37..9d1f353d2 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -25,7 +25,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 c0036daf8..c5aaa9da5 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -51,7 +51,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_ACL) += --whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_ACL) += -lrte_acl
_LDLIBS-$(CONFIG_RTE_LIBRTE_ACL) += --no-whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += -lrte_jobstats
-_LDLIBS-$(CONFIG_RTE_LIBRTE_METRICS) += -lrte_metrics
_LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE) += -lrte_bitratestats
_LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS) += -lrte_latencystats
_LDLIBS-$(CONFIG_RTE_LIBRTE_POWER) += -lrte_power
@@ -80,6 +79,8 @@ _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_METRICS) += -lrte_metrics
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -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
diff --git a/mk/rte.vars.mk b/mk/rte.vars.mk
index 07b0db127..603972c3c 100644
--- a/mk/rte.vars.mk
+++ b/mk/rte.vars.mk
@@ -52,6 +52,12 @@ ifneq ($(CONFIG_RTE_LIBRTE_E1000_PMD),y)
CONFIG_RTE_LIBRTE_E1000_PMD = $(CONFIG_RTE_LIBRTE_EM_PMD)
endif
+JANSSON := $(shell pkg-config --exists jansson; echo $$?)
+ifneq ($(JANSSON),0)
+$(warning Jansson not found, disabling RTE_LIBRTE_TELEMETRY)
+CONFIG_RTE_LIBRTE_TELEMETRY = n
+endif
+
ifeq ($(RTE_ARCH),)
$(error RTE_ARCH is not defined)
endif
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v9 03/12] telemetry: initial telemetry infrastructure
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 03/12] telemetry: initial telemetry infrastructure Harry van Haaren
@ 2018-10-27 1:56 ` Thomas Monjalon
2018-10-27 2:19 ` Van Haaren, Harry
0 siblings, 1 reply; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-27 1:56 UTC (permalink / raw)
To: Harry van Haaren, Kevin Laatz, Radu Nicolau, david.hunt
Cc: dev, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold
27/10/2018 01:59, Harry van Haaren:
> --- a/mk/rte.vars.mk
> +++ b/mk/rte.vars.mk
> +JANSSON := $(shell pkg-config --exists jansson; echo $$?)
> +ifneq ($(JANSSON),0)
> +$(warning Jansson not found, disabling RTE_LIBRTE_TELEMETRY)
> +CONFIG_RTE_LIBRTE_TELEMETRY = n
> +endif
It fails for cross-compilation.
Example:
When compiling i686 on x86_64 host, no error with
pkg-config --exists jansson
but fails when linking:
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../libjansson.so when searching for -ljansson
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../libjansson.a when searching for -ljansson
/usr/bin/ld: skipping incompatible /usr/lib/libjansson.so when searching for -ljansson
/usr/bin/ld: skipping incompatible /usr/lib/libjansson.a when searching for -ljansson
/usr/bin/ld: cannot find -ljansson
Note: there is the same issue with examples/vm_power_manager/Makefile
I start thinking it is not reasonnable to enable an optional dependency
in our Makefiles. Perhaps the only solution is to use meson...
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v9 03/12] telemetry: initial telemetry infrastructure
2018-10-27 1:56 ` Thomas Monjalon
@ 2018-10-27 2:19 ` Van Haaren, Harry
2018-10-27 2:33 ` Thomas Monjalon
0 siblings, 1 reply; 219+ messages in thread
From: Van Haaren, Harry @ 2018-10-27 2:19 UTC (permalink / raw)
To: Thomas Monjalon, Richardson, Bruce
Cc: dev, stephen, gaetan.rivet, shreyansh.jain, mattias.ronnblom,
Laatz, Kevin, Nicolau, Radu, Hunt, David
> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> Sent: Friday, October 26, 2018 6:56 PM
> To: Van Haaren, Harry <harry.van.haaren@intel.com>; Laatz, Kevin
> <kevin.laatz@intel.com>; Nicolau, Radu <radu.nicolau@intel.com>; Hunt, David
> <david.hunt@intel.com>
> Cc: dev@dpdk.org; Richardson, Bruce <bruce.richardson@intel.com>;
> stephen@networkplumber.org; gaetan.rivet@6wind.com; shreyansh.jain@nxp.com;
> mattias.ronnblom@ericsson.com; Ciara Power <ciara.power@intel.com>; Brian
> Archbold <brian.archbold@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v9 03/12] telemetry: initial telemetry
> infrastructure
>
> 27/10/2018 01:59, Harry van Haaren:
> > --- a/mk/rte.vars.mk
> > +++ b/mk/rte.vars.mk
> > +JANSSON := $(shell pkg-config --exists jansson; echo $$?)
> > +ifneq ($(JANSSON),0)
> > +$(warning Jansson not found, disabling RTE_LIBRTE_TELEMETRY)
> > +CONFIG_RTE_LIBRTE_TELEMETRY = n
> > +endif
>
> It fails for cross-compilation.
> Example:
> When compiling i686 on x86_64 host, no error with
> pkg-config --exists jansson
> but fails when linking:
> /usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-
> gnu/8.2.1/../../../libjansson.so when searching for -ljansson
> /usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-
> gnu/8.2.1/../../../libjansson.a when searching for -ljansson
> /usr/bin/ld: skipping incompatible /usr/lib/libjansson.so when searching
> for -ljansson
> /usr/bin/ld: skipping incompatible /usr/lib/libjansson.a when searching
> for -ljansson
> /usr/bin/ld: cannot find -ljansson
>
> Note: there is the same issue with examples/vm_power_manager/Makefile
>
> I start thinking it is not reasonnable to enable an optional dependency
> in our Makefiles. Perhaps the only solution is to use meson...
Ouch, yes if x86_64 pkg-config finds the available library, and it is not available in its i686 form, or other combinations thereof, things become another-level of complex.
Indeed Meson is (good | getting better) at detecting these things, Bruce knows more IIRC :)
@Thomas, for this release I propose to rework to use CONFIG=N as default for Make, and allow packagers to enable if they wish. Is that a good next-step?
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v9 03/12] telemetry: initial telemetry infrastructure
2018-10-27 2:19 ` Van Haaren, Harry
@ 2018-10-27 2:33 ` Thomas Monjalon
0 siblings, 0 replies; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-27 2:33 UTC (permalink / raw)
To: Van Haaren, Harry
Cc: Richardson, Bruce, dev, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Laatz, Kevin, Nicolau, Radu, Hunt, David
27/10/2018 04:19, Van Haaren, Harry:
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > 27/10/2018 01:59, Harry van Haaren:
> > > --- a/mk/rte.vars.mk
> > > +++ b/mk/rte.vars.mk
> > > +JANSSON := $(shell pkg-config --exists jansson; echo $$?)
> > > +ifneq ($(JANSSON),0)
> > > +$(warning Jansson not found, disabling RTE_LIBRTE_TELEMETRY)
> > > +CONFIG_RTE_LIBRTE_TELEMETRY = n
> > > +endif
> >
> > It fails for cross-compilation.
> > Example:
> > When compiling i686 on x86_64 host, no error with
> > pkg-config --exists jansson
> > but fails when linking:
> > /usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-
> > gnu/8.2.1/../../../libjansson.so when searching for -ljansson
> > /usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-
> > gnu/8.2.1/../../../libjansson.a when searching for -ljansson
> > /usr/bin/ld: skipping incompatible /usr/lib/libjansson.so when searching
> > for -ljansson
> > /usr/bin/ld: skipping incompatible /usr/lib/libjansson.a when searching
> > for -ljansson
> > /usr/bin/ld: cannot find -ljansson
> >
> > Note: there is the same issue with examples/vm_power_manager/Makefile
> >
> > I start thinking it is not reasonnable to enable an optional dependency
> > in our Makefiles. Perhaps the only solution is to use meson...
>
> Ouch, yes if x86_64 pkg-config finds the available library, and it is not available in its i686 form, or other combinations thereof, things become another-level of complex.
On ArchLinux, I have pkg-config-32 for i686 libs.
And for true cross-compilation with sysroot, some environment variables
are required. See this doc:
https://autotools.io/pkgconfig/cross-compiling.html
> Indeed Meson is (good | getting better) at detecting these things, Bruce knows more IIRC :)
>
> @Thomas, for this release I propose to rework to use CONFIG=N as default for Make, and allow packagers to enable if they wish. Is that a good next-step?
Yes it looks reasonnable disabling telemetry by default in make case.
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 04/12] telemetry: add initial connection socket
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (2 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 03/12] telemetry: initial telemetry infrastructure Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 05/12] telemetry: add client feature and sockets Harry van Haaren
` (8 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/rte_telemetry.c | 225 ++++++++++++++++++
lib/librte_telemetry/rte_telemetry_internal.h | 4 +
2 files changed, 229 insertions(+)
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index 7f4ad0342..e9b3330ca 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -3,23 +3,163 @@
*/
#include <unistd.h>
+#include <fcntl.h>
#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_metrics.h>
#include <rte_option.h>
+#include <rte_string_fns.h>
#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) {
+ 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,67 @@ 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;
+ char socket_path[BUF_SIZE];
+
+ if (telemetry == NULL)
+ return -1;
+
+ telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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");
+ return -EPERM;
+ }
+
+ return -1;
+}
+
int32_t __rte_experimental
rte_telemetry_init()
{
@@ -77,6 +284,14 @@ rte_telemetry_init()
return -EPERM;
}
+ 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;
+ }
+
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
(void *)static_telemetry);
@@ -95,11 +310,21 @@ rte_telemetry_init()
int32_t __rte_experimental
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 4e810a84c..569d56ab8 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
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 05/12] telemetry: add client feature and sockets
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (3 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 04/12] telemetry: add initial connection socket Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 06/12] telemetry: add parser for client socket messages Harry van Haaren
` (7 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
v9:
- Meson build disables if jansson not available (Thomas/Bruce)
- Add link to Jansson library (was in patch 3) (Thomas)
- Use pkg-config to get link flag (was -ljansson directly)
---
lib/librte_telemetry/Makefile | 1 +
lib/librte_telemetry/meson.build | 7 +
lib/librte_telemetry/rte_telemetry.c | 370 +++++++++++++++++-
lib/librte_telemetry/rte_telemetry_internal.h | 25 ++
4 files changed, 400 insertions(+), 3 deletions(-)
diff --git a/lib/librte_telemetry/Makefile b/lib/librte_telemetry/Makefile
index a2d4ff166..5ce1ad40c 100644
--- a/lib/librte_telemetry/Makefile
+++ b/lib/librte_telemetry/Makefile
@@ -13,6 +13,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
LDLIBS += -lrte_eal -lrte_ethdev
LDLIBS += -lrte_metrics
LDLIBS += -lpthread
+LDLIBS += $(shell pkg-config --libs jansson)
EXPORT_MAP := rte_telemetry_version.map
diff --git a/lib/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build
index 7716076a9..7b939805e 100644
--- a/lib/librte_telemetry/meson.build
+++ b/lib/librte_telemetry/meson.build
@@ -5,3 +5,10 @@ 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: false)
+if jansson.found()
+ ext_deps += jansson
+else
+ build = false
+endif
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index e9b3330ca..3c8b922f5 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -7,6 +7,7 @@
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <jansson.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
@@ -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;
}
@@ -130,6 +216,38 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry)
return 0;
}
+static int32_t
+rte_telemetry_read_client(struct telemetry_impl *telemetry)
+{
+ char buf[BUF_SIZE];
+ int ret, buffer_read;
+
+ buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
+
+ if (buffer_read == -1) {
+ TELEMETRY_LOG_ERR("Read error");
+ return -1;
+ } else if (buffer_read == 0) {
+ goto close_socket;
+ } else {
+ buf[buffer_read] = '\0';
+ ret = rte_telemetry_parse_client_message(telemetry, buf);
+ if (ret < 0)
+ TELEMETRY_LOG_WARN("Parse message failed");
+ goto close_socket;
+ }
+
+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)
{
@@ -141,8 +259,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 +269,31 @@ 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);
+
+ if (bytes > 0) {
+ client_buf[bytes] = '\0';
+ telemetry->request_client = client;
+ }
}
return 0;
@@ -173,6 +316,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;
}
@@ -291,6 +440,7 @@ rte_telemetry_init()
TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
return -EPERM;
}
+ TAILQ_INIT(&static_telemetry->client_list_head);
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
@@ -307,11 +457,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_experimental
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) {
@@ -328,6 +506,192 @@ 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;
+
+ 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_SEQPACKET, 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");
+ 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");
+ json_decref(root);
+ 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 569d56ab8..e3292cf40 100644
--- a/lib/librte_telemetry/rte_telemetry_internal.h
+++ b/lib/librte_telemetry/rte_telemetry_internal.h
@@ -3,6 +3,7 @@
*/
#include <rte_log.h>
+#include <rte_tailq.h>
#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
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 06/12] telemetry: add parser for client socket messages
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (4 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 05/12] telemetry: add client feature and sockets Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 07/12] telemetry: update metrics before sending stats Harry van Haaren
` (6 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
v9:
- Add rte_telemetry_parse() to version map file for shared builds
---
lib/librte_telemetry/Makefile | 1 +
lib/librte_telemetry/meson.build | 4 +-
lib/librte_telemetry/rte_telemetry.c | 8 +
lib/librte_telemetry/rte_telemetry_internal.h | 13 +
lib/librte_telemetry/rte_telemetry_parser.c | 569 ++++++++++++++++++
lib/librte_telemetry/rte_telemetry_parser.h | 14 +
.../rte_telemetry_version.map | 1 +
7 files changed, 608 insertions(+), 2 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 5ce1ad40c..562bbf94b 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 7b939805e..e459d0b80 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'
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index 3c8b922f5..cac788438 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
@@ -283,6 +284,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,6 +295,12 @@ rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)
if (bytes > 0) {
client_buf[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;
+ }
}
}
diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h
index e3292cf40..86a5ba15e 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 000000000..556abbe4a
--- /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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+
+#include <rte_metrics.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+
+#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_experimental
+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 000000000..b7051945b
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry_parser.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include "rte_telemetry_internal.h"
+#include "rte_compat.h"
+
+#ifndef _RTE_TELEMETRY_PARSER_H_
+#define _RTE_TELEMETRY_PARSER_H_
+
+int32_t __rte_experimental
+rte_telemetry_parse(struct telemetry_impl *telemetry, char *socket_rx_data);
+
+#endif
diff --git a/lib/librte_telemetry/rte_telemetry_version.map b/lib/librte_telemetry/rte_telemetry_version.map
index bbcd9a796..fb0b5be62 100644
--- a/lib/librte_telemetry/rte_telemetry_version.map
+++ b/lib/librte_telemetry/rte_telemetry_version.map
@@ -3,6 +3,7 @@ EXPERIMENTAL {
rte_telemetry_cleanup;
rte_telemetry_init;
+ rte_telemetry_parse;
local: *;
};
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 07/12] telemetry: update metrics before sending stats
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (5 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 06/12] telemetry: add parser for client socket messages Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 08/12] telemetry: format json response when " Harry van Haaren
` (5 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 cac788438..7616e7c91 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 86a5ba15e..0082cb2ca 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 556abbe4a..03a58a2fd 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;
}
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 08/12] telemetry: format json response when sending stats
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (6 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 07/12] telemetry: update metrics before sending stats Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 09/12] telemetry: add ability to disable selftest Harry van Haaren
` (4 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/Makefile | 1 +
lib/librte_telemetry/meson.build | 4 +-
lib/librte_telemetry/rte_telemetry.c | 962 +++++++++++++++++-
lib/librte_telemetry/rte_telemetry.h | 15 +
lib/librte_telemetry/rte_telemetry_internal.h | 3 +
.../rte_telemetry_parser_test.c | 534 ++++++++++
.../rte_telemetry_parser_test.h | 39 +
.../rte_telemetry_socket_tests.h | 36 +
.../rte_telemetry_version.map | 1 +
9 files changed, 1591 insertions(+), 4 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 562bbf94b..9feff6832 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 e459d0b80..b3bbf5bd0 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'
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index 7616e7c91..5b66b71c4 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)
{
@@ -190,7 +209,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 +221,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 +558,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");
@@ -335,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);
@@ -347,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;
}
@@ -834,6 +1171,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_SEQPACKET, 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_experimental
+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_SEQPACKET, 0);
+ *recv_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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 97674ae2d..119db16fe 100644
--- a/lib/librte_telemetry/rte_telemetry.h
+++ b/lib/librte_telemetry/rte_telemetry.h
@@ -48,4 +48,19 @@ rte_telemetry_init(void);
int32_t __rte_experimental
rte_telemetry_cleanup(void);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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_experimental
+rte_telemetry_selftest(void);
+
#endif
diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h
index 0082cb2ca..de7afda30 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 000000000..5fe93fa6e
--- /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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_tailq.h>
+#include <rte_string_fns.h>
+
+#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_SEQPACKET, 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 000000000..6ada85276
--- /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 000000000..db9167c5d
--- /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 <stdbool.h>
+
+#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 fb0b5be62..fa62d7718 100644
--- a/lib/librte_telemetry/rte_telemetry_version.map
+++ b/lib/librte_telemetry/rte_telemetry_version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
rte_telemetry_cleanup;
rte_telemetry_init;
rte_telemetry_parse;
+ rte_telemetry_selftest;
local: *;
};
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 09/12] telemetry: add ability to disable selftest
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (7 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 08/12] telemetry: format json response when " Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 10/12] doc: add telemetry documentation Harry van Haaren
` (3 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 5b66b71c4..2e27491b5 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;
}
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 10/12] doc: add telemetry documentation
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (8 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 09/12] telemetry: add ability to disable selftest Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 11/12] usertools: add client python script for telemetry Harry van Haaren
` (2 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 and a release notes update for
telemetry.
Signed-off-by: Ciara Power <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>
---
MAINTAINERS | 5 ++
doc/guides/howto/index.rst | 1 +
doc/guides/howto/telemetry.rst | 85 ++++++++++++++++++++++++++
doc/guides/rel_notes/release_18_11.rst | 6 ++
4 files changed, 97 insertions(+)
create mode 100644 doc/guides/howto/telemetry.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index 17ee5b9d3..be4ceb9b8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1208,6 +1208,11 @@ F: test/bpf/
F: test/test/test_bpf.c
F: doc/guides/prog_guide/bpf_lib.rst
+Telemetry - EXPERIMENTAL
+M: Kevin Laatz <kevin.laatz@intel.com>
+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 e13a090c3..a642a2be1 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 000000000..3fcb0619e
--- /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.
diff --git a/doc/guides/rel_notes/release_18_11.rst b/doc/guides/rel_notes/release_18_11.rst
index c6256939b..ed7994241 100644
--- a/doc/guides/rel_notes/release_18_11.rst
+++ b/doc/guides/rel_notes/release_18_11.rst
@@ -256,6 +256,12 @@ New Features
the specified port. The port must be stopped before the command call in order
to reconfigure queues.
+* **Added Telemetry API.**
+
+ Added the telemetry API which allows applications to transparently expose
+ their telemetry via a UNIX socket in JSON. The JSON can be consumed by any
+ Service Assurance agent, such as CollectD.
+
* **Add a new sample for vDPA**
The vdpa sample application creates vhost-user sockets by using the
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 11/12] usertools: add client python script for telemetry
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (9 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 10/12] doc: add telemetry documentation Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 12/12] build: add dependency on telemetry to apps in meson Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <file_path>".
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 000000000..6dcf62bac
--- /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_SEQPACKET)
+ self.recv_fd = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ 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)
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v9 12/12] build: add dependency on telemetry to apps in meson
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (10 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 11/12] usertools: add client python script for telemetry Harry van Haaren
@ 2018-10-26 23:59 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-26 23:59 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Kevin Laatz, Radu Nicolau
From: Kevin Laatz <kevin.laatz@intel.com>
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 <bruce.richardson@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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/librte_telemetry/meson.build | 1 +
lib/meson.build | 1 +
meson.build | 2 ++
10 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/app/meson.build b/app/meson.build
index e68d949e9..a9a026bbf 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -29,7 +29,7 @@ foreach app:apps
# use "deps" for internal DPDK dependencies, and "ext_deps" for
# external package/library requirements
ext_deps = []
- deps = []
+ deps = dpdk_app_link_libraries
subdir(name)
@@ -43,7 +43,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 988cb4eb2..116c27f02 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 9c148e36e..a52b2ee4a 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 653907ded..eb8cc0499 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 eacd7a0f5..d735b186f 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 cd66618e9..6006c60f9 100644
--- a/app/test-pmd/meson.build
+++ b/app/test-pmd/meson.build
@@ -24,7 +24,7 @@ sources = files('cmdline.c',
'txonly.c',
'util.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 6f9228c87..275f00b60 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/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build
index b3bbf5bd0..9492f544e 100644
--- a/lib/librte_telemetry/meson.build
+++ b/lib/librte_telemetry/meson.build
@@ -9,6 +9,7 @@ cflags += '-DALLOW_EXPERIMENTAL_API'
jansson = cc.find_library('jansson', required: false)
if jansson.found()
ext_deps += jansson
+ dpdk_app_link_libraries += ['telemetry']
else
build = false
endif
diff --git a/lib/meson.build b/lib/meson.build
index 9d1f353d2..c0cc2d86e 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -132,6 +132,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 c9af33532..b1e6eab6a 100644
--- a/meson.build
+++ b/meson.build
@@ -12,8 +12,10 @@ project('DPDK', 'C',
cc = meson.get_compiler('c')
dpdk_conf = configuration_data()
dpdk_libraries = []
+dpdk_static_libraries = []
dpdk_drivers = []
dpdk_extra_ldflags = []
+dpdk_app_link_libraries = []
driver_install_path = join_paths(get_option('libdir'), 'dpdk/drivers')
eal_pmd_path = join_paths(get_option('prefix'), driver_install_path)
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 00/12] Introduce Telemetry Library Harry van Haaren
` (11 preceding siblings ...)
2018-10-26 23:59 ` [dpdk-dev] [PATCH v9 12/12] build: add dependency on telemetry to apps in meson Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 01/12] eal: add option register infrastructure Harry van Haaren
` (12 more replies)
12 siblings, 13 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Harry van Haaren
This patchset introduces a Telemetry library for DPDK Service Assurance.
This library provides an easy way to query DPDK Ethdev metrics.
The telemetry library provides a method for a service assurance component
to retrieve metrics from a DPDK packet forwarding application.
Communicating from the service assurance component to DPDK is done using a
UNIX domain socket, passing a JSON formatted string. A reply is sent (again
a JSON formatted string) of the current DPDK metrics.
The telemetry component makes use of the existing rte_metrics library to
query values. The values to be transmitted via the telemetry infrastructure
must be present in the Metrics library. Currently the ethdev values are
pushed to the metrics library, and the queried from there there is an open
question on how applications would like this to occur. Currently only
ethdev to metrics functionality is implemented, however other subsystems
like crypto, eventdev, keepalive etc can use similar mechanisms.
Exposing DPDK Telemetry via a socket interface enables service assurance
agents like collectd to consume data from DPDK. This is vital for
monitoring, fault-detection, and error reporting. A collectd plugin has
been created to interact with the DPDK Telemetry component, showing how it
can be used in practice. The collectd plugin will be upstreamed to collectd
at a later stage. A small python script is provided in
./usertools/telemetry_client.py to quick-start using DPDK Telemetry.
Note: Despite opterr being set to 0, --telemetry said to be 'unrecognized'
as a startup print. This is a cosmetic issue and will be addressed in the
future.
---
v2:
- Reworked telemetry as part of EAL instead of using vdev (Gaetan)
- Refactored rte_telemetry_command (Gaetan)
- Added MAINTAINERS file entry (Stephen)
- Updated docs to reflect vdev to eal rework
- Removed collectd patch from patchset (Thomas)
- General code clean up from v1 feedback
v3:
- Reworked registering with eal and moved to rte_param (Gaetan)
- Added BSD implementation for rte_param (Gaetan)
- Updated the paths to align with the new runtime file location (Mattias)
- Fixed pointer checks to align with the coding style 1.8.1 (Mattias)
- Added missing decref's and close's (Mattias)
- Fixed runtime issue in Meson (was not recognising flag due to linking)
- More general clean up
v4:
- Added Doxygen comments for rte_param.h (Thomas)
- Made eal_get_runtime_dir a public function to use outside of EAL (Thomas)
- Reworked telemetry to get path using rte_eal_get_runtime_dir (Thomas)
- Fixed checkpatch coding style error
v5:
- Moved the BUF_SIZE define to fix build (Harry)
- Set default config for telemetry to 'n' (Harry)
- Improved Doxygen comments (Thomas)
- Cleaned up rte_param struct (Thomas)
v6:
- Renamed rte_param to rte_option (Thomas)
- Moved internal functions to eal_private.h (Gaetan)
- Added fail check for pthread_attr_init() (Mattias)
- Changed socket implementation to SOCK_SEQPACKET (Mattias)
- Added check to avoid option duplicates (Gaetan)
- Removed telemetry example from Doxygen comment (Gaetan)
- General Doxygen clean-up (Thomas)
- General code clean-up (Mattias)
v7:
- Fix object leak (Mattias)
- General clean-up (Mattias)
- Fix rte_option header define
- Added release note update
- Rebased
v8:
- Added missing experimental tags
- Added Gaetan's Ack from ML
v9:
- Added doxygen to build (Thomas)
- Added doxygen @file tag (Thomas)
- Detect jansson library dynamically with Make/pkg-config (Thomas)
- Make jansson optional build-dep for Meson (Thomas/Bruce)
v10:
- Location of Telemetry in doxygen (Thomas)
- Linking jansson in patch of first usage (Thomas)
- Meson detection in patch of first usage (Thomas)
- Removed pkg-config check in Make due to issues with 32/64 bit (Thomas)
- MAINTAINERS file entires introduced earlier and split (Thomas)
- Disable Telemetry library in Make by default due to jansson dep (Thomas)
Ciara Power (9):
telemetry: initial telemetry infrastructure
telemetry: add initial connection socket
telemetry: add client feature and sockets
telemetry: add parser for client socket messages
telemetry: update metrics before sending stats
telemetry: format json response when sending stats
telemetry: add ability to disable selftest
doc: add telemetry documentation
usertools: add client python script for telemetry
Kevin Laatz (3):
eal: add option register infrastructure
eal: make get runtime dir function public
build: add dependency on telemetry to apps in meson
MAINTAINERS | 5 +
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/common_base | 5 +
config/meson.build | 3 +
doc/api/doxy-api-index.md | 1 +
doc/api/doxy-api.conf.in | 1 +
doc/guides/howto/index.rst | 1 +
doc/guides/howto/telemetry.rst | 85 +
doc/guides/rel_notes/release_18_11.rst | 6 +
lib/Makefile | 2 +
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 16 +-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_filesystem.h | 15 +-
lib/librte_eal/common/eal_private.h | 21 +
lib/librte_eal/common/include/rte_eal.h | 9 +
lib/librte_eal/common/include/rte_option.h | 63 +
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 16 +-
lib/librte_eal/rte_eal_version.map | 2 +
lib/librte_telemetry/Makefile | 30 +
lib/librte_telemetry/meson.build | 15 +
lib/librte_telemetry/rte_telemetry.c | 1815 +++++++++++++++++
lib/librte_telemetry/rte_telemetry.h | 66 +
lib/librte_telemetry/rte_telemetry_internal.h | 81 +
lib/librte_telemetry/rte_telemetry_parser.c | 586 ++++++
lib/librte_telemetry/rte_telemetry_parser.h | 14 +
.../rte_telemetry_parser_test.c | 534 +++++
.../rte_telemetry_parser_test.h | 39 +
.../rte_telemetry_socket_tests.h | 36 +
.../rte_telemetry_version.map | 10 +
lib/meson.build | 3 +-
meson.build | 2 +
mk/rte.app.mk | 3 +-
usertools/dpdk-telemetry-client.py | 116 ++
42 files changed, 3654 insertions(+), 20 deletions(-)
create mode 100644 doc/guides/howto/telemetry.rst
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
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_parser.c
create mode 100644 lib/librte_telemetry/rte_telemetry_parser.h
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
create mode 100644 lib/librte_telemetry/rte_telemetry_version.map
create mode 100644 usertools/dpdk-telemetry-client.py
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 01/12] eal: add option register infrastructure
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 02/12] eal: make get runtime dir function public Harry van Haaren
` (11 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Kevin Laatz
From: Kevin Laatz <kevin.laatz@intel.com>
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 <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
lib/librte_eal/bsdapp/eal/Makefile | 1 +
lib/librte_eal/bsdapp/eal/eal.c | 14 ++++-
lib/librte_eal/common/Makefile | 1 +
lib/librte_eal/common/eal_private.h | 21 ++++++++
lib/librte_eal/common/include/rte_option.h | 63 ++++++++++++++++++++++
lib/librte_eal/common/meson.build | 2 +
lib/librte_eal/common/rte_option.c | 54 +++++++++++++++++++
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal.c | 14 ++++-
lib/librte_eal/rte_eal_version.map | 1 +
10 files changed, 170 insertions(+), 2 deletions(-)
create mode 100644 lib/librte_eal/common/include/rte_option.h
create mode 100644 lib/librte_eal/common/rte_option.c
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index d19f53c1e..bfeddaadc 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -67,6 +67,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_option.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 f94c5c5f4..11cbda964 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -42,6 +42,7 @@
#include <rte_devargs.h>
#include <rte_version.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#include <rte_atomic.h>
#include <malloc_heap.h>
@@ -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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -791,6 +800,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index cca68826f..87d8c455d 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_option.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/eal_private.h b/lib/librte_eal/common/eal_private.h
index b189d675d..442c6dc48 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -349,4 +349,25 @@ dev_sigbus_handler_register(void);
int
dev_sigbus_handler_unregister(void);
+/**
+ * Check if the option is registered.
+ *
+ * @param option
+ * The option to be parsed.
+ *
+ * @return
+ * 0 on success
+ * @return
+ * -1 on fail
+ */
+int
+rte_option_parse(const char *opt);
+
+/**
+ * Iterate through the registered options and execute the associated
+ * callback if enabled.
+ */
+void
+rte_option_init(void);
+
#endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_option.h b/lib/librte_eal/common/include/rte_option.h
new file mode 100644
index 000000000..8957b970c
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_option.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#ifndef __INCLUDE_RTE_OPTION_H__
+#define __INCLUDE_RTE_OPTION_H__
+
+/**
+ * @file
+ *
+ * This API offers the ability to register options to the EAL command line and
+ * map those options to functions that will be executed at the end of EAL
+ * initialization. These options will be available as part of the EAL command
+ * line of applications and are dynamically managed.
+ *
+ * This is used primarily by DPDK libraries offering command line options.
+ * Currently, this API is limited to registering options without argument.
+ *
+ * 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_option 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_option_cb)(void);
+
+/*
+ * Structure describing the EAL command line option being registered.
+ */
+struct rte_option {
+ TAILQ_ENTRY(rte_option) next; /**< Next entry in the list. */
+ char *opt_str; /**< The option name. */
+ rte_option_cb cb; /**< Function called when option is used. */
+ int enabled; /**< Set when the option is used. */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Register an option to the EAL command line.
+ * When recognized, the associated function will be executed at the end of EAL
+ * initialization.
+ *
+ * The associated structure must be available the whole time this option is
+ * registered (i.e. not stack memory).
+ *
+ * @param opt
+ * Structure describing the option to parse.
+ */
+void __rte_experimental
+rte_option_register(struct rte_option *opt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build
index 04c414356..2a10d57d8 100644
--- a/lib/librte_eal/common/meson.build
+++ b/lib/librte_eal/common/meson.build
@@ -34,6 +34,7 @@ common_sources = files(
'malloc_mp.c',
'rte_keepalive.c',
'rte_malloc.c',
+ 'rte_option.c',
'rte_reciprocal.c',
'rte_service.c'
)
@@ -71,6 +72,7 @@ common_headers = files(
'include/rte_malloc_heap.h',
'include/rte_memory.h',
'include/rte_memzone.h',
+ 'include/rte_option.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_option.c b/lib/librte_eal/common/rte_option.c
new file mode 100644
index 000000000..02d59a869
--- /dev/null
+++ b/lib/librte_eal/common/rte_option.c
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_eal.h>
+#include <rte_option.h>
+
+#include "eal_private.h"
+
+TAILQ_HEAD(rte_option_list, rte_option);
+
+struct rte_option_list rte_option_list =
+ TAILQ_HEAD_INITIALIZER(rte_option_list);
+
+static struct rte_option *option;
+
+int
+rte_option_parse(const char *opt)
+{
+ /* Check if the option is registered */
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt, option->opt_str) == 0) {
+ option->enabled = 1;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void __rte_experimental
+rte_option_register(struct rte_option *opt)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (strcmp(opt->opt_str, option->opt_str) == 0)
+ RTE_LOG(INFO, EAL, "Option %s has already been registered.",
+ opt->opt_str);
+ return;
+ }
+
+ TAILQ_INSERT_HEAD(&rte_option_list, opt, next);
+}
+
+void
+rte_option_init(void)
+{
+ TAILQ_FOREACH(option, &rte_option_list, next) {
+ if (option->enabled)
+ option->cb();
+ }
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 728088594..51deb5797 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -75,6 +75,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_option.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 76536bae2..930070e43 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -48,6 +48,7 @@
#include <rte_atomic.h>
#include <malloc_heap.h>
#include <rte_vfio.h>
+#include <rte_option.h>
#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_option_parse(argv[optind-1]);
+ if (ret == 0)
+ continue;
+
eal_usage(prgname);
ret = -1;
goto out;
@@ -1080,6 +1089,9 @@ rte_eal_init(int argc, char **argv)
rte_eal_mcfg_complete();
+ /* Call each registered callback, if enabled */
+ rte_option_init();
+
return fctret;
}
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index f4a2b38fd..5b6d91ffd 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -350,6 +350,7 @@ EXPERIMENTAL {
rte_mp_request_sync;
rte_mp_request_async;
rte_mp_sendmsg;
+ rte_option_register;
rte_service_lcore_attr_get;
rte_service_lcore_attr_reset_all;
rte_service_may_be_active;
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 02/12] eal: make get runtime dir function public
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 01/12] eal: add option register infrastructure Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 03/12] telemetry: initial telemetry infrastructure Harry van Haaren
` (10 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Kevin Laatz
From: Kevin Laatz <kevin.laatz@intel.com>
This patch makes the eal_get_runtime_dir() API public so it can be used
from outside EAL.
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_eal/bsdapp/eal/eal.c | 2 +-
lib/librte_eal/common/eal_filesystem.h | 15 ++++++++-------
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, 20 insertions(+), 9 deletions(-)
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 11cbda964..21997ced8 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 de05febf4..b3e8ae5ea 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,8 @@ 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 +67,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 +79,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 +100,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 6514a9fe6..a0cedd573 100644
--- a/lib/librte_eal/common/include/rte_eal.h
+++ b/lib/librte_eal/common/include/rte_eal.h
@@ -507,6 +507,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 930070e43..7b11375f4 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 5b6d91ffd..28bfa4950 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -259,6 +259,7 @@ DPDK_18.08 {
DPDK_18.11 {
global:
+ rte_eal_get_runtime_dir;
rte_eal_hotplug_add;
rte_eal_hotplug_remove;
rte_strscpy;
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 03/12] telemetry: initial telemetry infrastructure
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 01/12] eal: add option register infrastructure Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 02/12] eal: make get runtime dir function public Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 04/12] telemetry: add initial connection socket Harry van Haaren
` (9 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz,
Radu Nicolau
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
v10:
- change position of Telemetry in index Doxygen index (Thomas)
- Add MAINTAINER file entry for lib/telemetry files (Thomas)
- Removed -ljansson from mk/rte.app.mk (Thomas)
- Removed pkg-config jansson check in mk/rte.vars.mk (Thomas)
- Set CONFIG_TELEMETRY=N by default (Thomas)
---
MAINTAINERS | 3 +
config/common_base | 5 +
doc/api/doxy-api-index.md | 1 +
doc/api/doxy-api.conf.in | 1 +
lib/Makefile | 2 +
lib/librte_telemetry/Makefile | 27 ++++
lib/librte_telemetry/meson.build | 7 +
lib/librte_telemetry/rte_telemetry.c | 123 ++++++++++++++++++
lib/librte_telemetry/rte_telemetry.h | 51 ++++++++
lib/librte_telemetry/rte_telemetry_internal.h | 32 +++++
.../rte_telemetry_version.map | 8 ++
lib/meson.build | 2 +-
mk/rte.app.mk | 3 +-
13 files changed, 263 insertions(+), 2 deletions(-)
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/MAINTAINERS b/MAINTAINERS
index 17ee5b9d3..a50214d7a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1208,6 +1208,9 @@ F: test/bpf/
F: test/test/test_bpf.c
F: doc/guides/prog_guide/bpf_lib.rst
+Telemetry - EXPERIMENTAL
+M: Kevin Laatz <kevin.laatz@intel.com>
+F: lib/librte_telemetry/
Test Applications
-----------------
diff --git a/config/common_base b/config/common_base
index 38beaabb3..4ba8f651d 100644
--- a/config/common_base
+++ b/config/common_base
@@ -756,6 +756,11 @@ CONFIG_RTE_LIBRTE_CMDLINE_DEBUG=n
CONFIG_RTE_LIBRTE_HASH=y
CONFIG_RTE_LIBRTE_HASH_DEBUG=n
+#
+# Compile librte_telemetry
+#
+CONFIG_RTE_LIBRTE_TELEMETRY=n
+
#
# Compile librte_efd
#
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index a3039d168..cd2b7e413 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -29,6 +29,7 @@ The public API headers are grouped by topics:
[metrics] (@ref rte_metrics.h),
[bitrate] (@ref rte_bitrate.h),
[latency] (@ref rte_latencystats.h),
+ [telemetry] (@ref rte_telemetry.h),
[devargs] (@ref rte_devargs.h),
[PCI] (@ref rte_pci.h),
[vfio] (@ref rte_vfio.h)
diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in
index 3b652ac9c..77ba327a8 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -56,6 +56,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \
@TOPDIR@/lib/librte_sched \
@TOPDIR@/lib/librte_security \
@TOPDIR@/lib/librte_table \
+ @TOPDIR@/lib/librte_telemetry \
@TOPDIR@/lib/librte_timer \
@TOPDIR@/lib/librte_vhost
INPUT += @API_EXAMPLES@
diff --git a/lib/Makefile b/lib/Makefile
index 062cbdfd7..b7370ef97 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -106,6 +106,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 000000000..a2d4ff166
--- /dev/null
+++ b/lib/librte_telemetry/Makefile
@@ -0,0 +1,27 @@
+# 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
+
+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 000000000..7716076a9
--- /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 000000000..7f4ad0342
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_metrics.h>
+#include <rte_option.h>
+
+#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_experimental
+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);
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0) {
+ TELEMETRY_LOG_ERR("Pthread attribute init failed");
+ return -EPERM;
+ }
+
+ 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_experimental
+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_option option = {
+ .opt_str = "--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_option_register(&option);
+}
diff --git a/lib/librte_telemetry/rte_telemetry.h b/lib/librte_telemetry/rte_telemetry.h
new file mode 100644
index 000000000..97674ae2d
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <stdint.h>
+
+#ifndef _RTE_TELEMETRY_H_
+#define _RTE_TELEMETRY_H_
+
+/**
+ * @file
+ * RTE Telemetry
+ *
+ * The telemetry library provides a method to retrieve statistics from
+ * DPDK by sending a JSON encoded message over a socket. DPDK will send
+ * a JSON encoded response containing telemetry data.
+ ***/
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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_experimental
+rte_telemetry_init(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Clean up and free memory.
+ *
+ * @return
+ * 0 on success
+ * @return
+ * -EPERM on failure
+ */
+int32_t __rte_experimental
+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 000000000..4e810a84c
--- /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 <rte_log.h>
+
+#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 000000000..bbcd9a796
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry_version.map
@@ -0,0 +1,8 @@
+EXPERIMENTAL {
+ global:
+
+ rte_telemetry_cleanup;
+ rte_telemetry_init;
+
+ local: *;
+};
diff --git a/lib/meson.build b/lib/meson.build
index 2b903fa37..9d1f353d2 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -25,7 +25,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 c0036daf8..a14e83c71 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -51,7 +51,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_ACL) += --whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_ACL) += -lrte_acl
_LDLIBS-$(CONFIG_RTE_LIBRTE_ACL) += --no-whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += -lrte_jobstats
-_LDLIBS-$(CONFIG_RTE_LIBRTE_METRICS) += -lrte_metrics
_LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE) += -lrte_bitratestats
_LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS) += -lrte_latencystats
_LDLIBS-$(CONFIG_RTE_LIBRTE_POWER) += -lrte_power
@@ -80,6 +79,8 @@ _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_METRICS) += -lrte_metrics
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -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
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 04/12] telemetry: add initial connection socket
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (2 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 03/12] telemetry: initial telemetry infrastructure Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 05/12] telemetry: add client feature and sockets Harry van Haaren
` (8 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/rte_telemetry.c | 225 ++++++++++++++++++
lib/librte_telemetry/rte_telemetry_internal.h | 4 +
2 files changed, 229 insertions(+)
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index 7f4ad0342..e9b3330ca 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -3,23 +3,163 @@
*/
#include <unistd.h>
+#include <fcntl.h>
#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_metrics.h>
#include <rte_option.h>
+#include <rte_string_fns.h>
#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) {
+ 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,67 @@ 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;
+ char socket_path[BUF_SIZE];
+
+ if (telemetry == NULL)
+ return -1;
+
+ telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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");
+ return -EPERM;
+ }
+
+ return -1;
+}
+
int32_t __rte_experimental
rte_telemetry_init()
{
@@ -77,6 +284,14 @@ rte_telemetry_init()
return -EPERM;
}
+ 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;
+ }
+
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
(void *)static_telemetry);
@@ -95,11 +310,21 @@ rte_telemetry_init()
int32_t __rte_experimental
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 4e810a84c..569d56ab8 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
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 05/12] telemetry: add client feature and sockets
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (3 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 04/12] telemetry: add initial connection socket Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 06/12] telemetry: add parser for client socket messages Harry van Haaren
` (7 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
v10:
- remove error prone pkg-config detection (Thomas)
- Re-add -ljansson to mk/rte.app.mk, was in patch 1 (Thomas)
---
lib/librte_telemetry/Makefile | 1 +
lib/librte_telemetry/meson.build | 7 +
lib/librte_telemetry/rte_telemetry.c | 370 +++++++++++++++++-
lib/librte_telemetry/rte_telemetry_internal.h | 25 ++
mk/rte.app.mk | 2 +-
5 files changed, 401 insertions(+), 4 deletions(-)
diff --git a/lib/librte_telemetry/Makefile b/lib/librte_telemetry/Makefile
index a2d4ff166..0d61361f4 100644
--- a/lib/librte_telemetry/Makefile
+++ b/lib/librte_telemetry/Makefile
@@ -13,6 +13,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
LDLIBS += -lrte_eal -lrte_ethdev
LDLIBS += -lrte_metrics
LDLIBS += -lpthread
+LDLIBS += -ljansson
EXPORT_MAP := rte_telemetry_version.map
diff --git a/lib/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build
index 7716076a9..7b939805e 100644
--- a/lib/librte_telemetry/meson.build
+++ b/lib/librte_telemetry/meson.build
@@ -5,3 +5,10 @@ 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: false)
+if jansson.found()
+ ext_deps += jansson
+else
+ build = false
+endif
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index e9b3330ca..3c8b922f5 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -7,6 +7,7 @@
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <jansson.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
@@ -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;
}
@@ -130,6 +216,38 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry)
return 0;
}
+static int32_t
+rte_telemetry_read_client(struct telemetry_impl *telemetry)
+{
+ char buf[BUF_SIZE];
+ int ret, buffer_read;
+
+ buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
+
+ if (buffer_read == -1) {
+ TELEMETRY_LOG_ERR("Read error");
+ return -1;
+ } else if (buffer_read == 0) {
+ goto close_socket;
+ } else {
+ buf[buffer_read] = '\0';
+ ret = rte_telemetry_parse_client_message(telemetry, buf);
+ if (ret < 0)
+ TELEMETRY_LOG_WARN("Parse message failed");
+ goto close_socket;
+ }
+
+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)
{
@@ -141,8 +259,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 +269,31 @@ 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);
+
+ if (bytes > 0) {
+ client_buf[bytes] = '\0';
+ telemetry->request_client = client;
+ }
}
return 0;
@@ -173,6 +316,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;
}
@@ -291,6 +440,7 @@ rte_telemetry_init()
TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
return -EPERM;
}
+ TAILQ_INIT(&static_telemetry->client_list_head);
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
@@ -307,11 +457,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_experimental
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) {
@@ -328,6 +506,192 @@ 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;
+
+ 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_SEQPACKET, 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");
+ 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");
+ json_decref(root);
+ 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 569d56ab8..e3292cf40 100644
--- a/lib/librte_telemetry/rte_telemetry_internal.h
+++ b/lib/librte_telemetry/rte_telemetry_internal.h
@@ -3,6 +3,7 @@
*/
#include <rte_log.h>
+#include <rte_tailq.h>
#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 a14e83c71..c5aaa9da5 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,7 @@ _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_METRICS) += -lrte_metrics
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -lrte_telemetry
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -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
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 06/12] telemetry: add parser for client socket messages
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (4 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 05/12] telemetry: add client feature and sockets Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 07/12] telemetry: update metrics before sending stats Harry van Haaren
` (6 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/Makefile | 1 +
lib/librte_telemetry/meson.build | 4 +-
lib/librte_telemetry/rte_telemetry.c | 8 +
lib/librte_telemetry/rte_telemetry_internal.h | 13 +
lib/librte_telemetry/rte_telemetry_parser.c | 569 ++++++++++++++++++
lib/librte_telemetry/rte_telemetry_parser.h | 14 +
.../rte_telemetry_version.map | 1 +
7 files changed, 608 insertions(+), 2 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 0d61361f4..95c72963a 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 7b939805e..e459d0b80 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'
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index 3c8b922f5..cac788438 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
@@ -283,6 +284,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,6 +295,12 @@ rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)
if (bytes > 0) {
client_buf[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;
+ }
}
}
diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h
index e3292cf40..86a5ba15e 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 000000000..556abbe4a
--- /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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+
+#include <rte_metrics.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+
+#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_experimental
+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 000000000..b7051945b
--- /dev/null
+++ b/lib/librte_telemetry/rte_telemetry_parser.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include "rte_telemetry_internal.h"
+#include "rte_compat.h"
+
+#ifndef _RTE_TELEMETRY_PARSER_H_
+#define _RTE_TELEMETRY_PARSER_H_
+
+int32_t __rte_experimental
+rte_telemetry_parse(struct telemetry_impl *telemetry, char *socket_rx_data);
+
+#endif
diff --git a/lib/librte_telemetry/rte_telemetry_version.map b/lib/librte_telemetry/rte_telemetry_version.map
index bbcd9a796..fb0b5be62 100644
--- a/lib/librte_telemetry/rte_telemetry_version.map
+++ b/lib/librte_telemetry/rte_telemetry_version.map
@@ -3,6 +3,7 @@ EXPERIMENTAL {
rte_telemetry_cleanup;
rte_telemetry_init;
+ rte_telemetry_parse;
local: *;
};
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 07/12] telemetry: update metrics before sending stats
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (5 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 06/12] telemetry: add parser for client socket messages Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 08/12] telemetry: format json response when " Harry van Haaren
` (5 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 cac788438..7616e7c91 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 86a5ba15e..0082cb2ca 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 556abbe4a..03a58a2fd 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;
}
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 08/12] telemetry: format json response when sending stats
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (6 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 07/12] telemetry: update metrics before sending stats Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 09/12] telemetry: add ability to disable selftest Harry van Haaren
` (4 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
lib/librte_telemetry/Makefile | 1 +
lib/librte_telemetry/meson.build | 4 +-
lib/librte_telemetry/rte_telemetry.c | 962 +++++++++++++++++-
lib/librte_telemetry/rte_telemetry.h | 15 +
lib/librte_telemetry/rte_telemetry_internal.h | 3 +
.../rte_telemetry_parser_test.c | 534 ++++++++++
.../rte_telemetry_parser_test.h | 39 +
.../rte_telemetry_socket_tests.h | 36 +
.../rte_telemetry_version.map | 1 +
9 files changed, 1591 insertions(+), 4 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 95c72963a..1a0506913 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 e459d0b80..b3bbf5bd0 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'
diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c
index 7616e7c91..5b66b71c4 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)
{
@@ -190,7 +209,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 +221,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 +558,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");
@@ -335,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);
@@ -347,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;
}
@@ -834,6 +1171,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_SEQPACKET, 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_experimental
+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_SEQPACKET, 0);
+ *recv_fd = socket(AF_UNIX, SOCK_SEQPACKET, 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 97674ae2d..119db16fe 100644
--- a/lib/librte_telemetry/rte_telemetry.h
+++ b/lib/librte_telemetry/rte_telemetry.h
@@ -48,4 +48,19 @@ rte_telemetry_init(void);
int32_t __rte_experimental
rte_telemetry_cleanup(void);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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_experimental
+rte_telemetry_selftest(void);
+
#endif
diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h
index 0082cb2ca..de7afda30 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 000000000..5fe93fa6e
--- /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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <jansson.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_tailq.h>
+#include <rte_string_fns.h>
+
+#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_SEQPACKET, 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 000000000..6ada85276
--- /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 000000000..db9167c5d
--- /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 <stdbool.h>
+
+#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 fb0b5be62..fa62d7718 100644
--- a/lib/librte_telemetry/rte_telemetry_version.map
+++ b/lib/librte_telemetry/rte_telemetry_version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
rte_telemetry_cleanup;
rte_telemetry_init;
rte_telemetry_parse;
+ rte_telemetry_selftest;
local: *;
};
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 09/12] telemetry: add ability to disable selftest
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (7 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 08/12] telemetry: format json response when " Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 10/12] doc: add telemetry documentation Harry van Haaren
` (3 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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 5b66b71c4..2e27491b5 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;
}
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 10/12] doc: add telemetry documentation
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (8 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 09/12] telemetry: add ability to disable selftest Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 11/12] usertools: add client python script for telemetry Harry van Haaren
` (2 subsequent siblings)
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 and a release notes update for
telemetry.
Signed-off-by: Ciara Power <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>
---
v10:
- Add MAINTAINERS entry for documentation (Thomas)
---
MAINTAINERS | 1 +
doc/guides/howto/index.rst | 1 +
doc/guides/howto/telemetry.rst | 85 ++++++++++++++++++++++++++
doc/guides/rel_notes/release_18_11.rst | 6 ++
4 files changed, 93 insertions(+)
create mode 100644 doc/guides/howto/telemetry.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index a50214d7a..86712b139 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1211,6 +1211,7 @@ F: doc/guides/prog_guide/bpf_lib.rst
Telemetry - EXPERIMENTAL
M: Kevin Laatz <kevin.laatz@intel.com>
F: lib/librte_telemetry/
+F: doc/guides/howto/telemetry.rst
Test Applications
-----------------
diff --git a/doc/guides/howto/index.rst b/doc/guides/howto/index.rst
index e13a090c3..a642a2be1 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 000000000..3fcb0619e
--- /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.
diff --git a/doc/guides/rel_notes/release_18_11.rst b/doc/guides/rel_notes/release_18_11.rst
index c6256939b..ed7994241 100644
--- a/doc/guides/rel_notes/release_18_11.rst
+++ b/doc/guides/rel_notes/release_18_11.rst
@@ -256,6 +256,12 @@ New Features
the specified port. The port must be stopped before the command call in order
to reconfigure queues.
+* **Added Telemetry API.**
+
+ Added the telemetry API which allows applications to transparently expose
+ their telemetry via a UNIX socket in JSON. The JSON can be consumed by any
+ Service Assurance agent, such as CollectD.
+
* **Add a new sample for vDPA**
The vdpa sample application creates vhost-user sockets by using the
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 11/12] usertools: add client python script for telemetry
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (9 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 10/12] doc: add telemetry documentation Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 12/12] build: add dependency on telemetry to apps in meson Harry van Haaren
2018-10-27 13:24 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Thomas Monjalon
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Ciara Power, Brian Archbold, Kevin Laatz
From: Ciara Power <ciara.power@intel.com>
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 <file_path>".
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 <ciara.power@intel.com>
Signed-off-by: Brian Archbold <brian.archbold@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
v10:
- Add MAINTAINER entry for client script (Thomas)
---
MAINTAINERS | 1 +
usertools/dpdk-telemetry-client.py | 116 +++++++++++++++++++++++++++++
2 files changed, 117 insertions(+)
create mode 100644 usertools/dpdk-telemetry-client.py
diff --git a/MAINTAINERS b/MAINTAINERS
index 86712b139..a919ffd45 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1212,6 +1212,7 @@ Telemetry - EXPERIMENTAL
M: Kevin Laatz <kevin.laatz@intel.com>
F: lib/librte_telemetry/
F: doc/guides/howto/telemetry.rst
+F: usertools/dpdk-telemetry-client.py
Test Applications
-----------------
diff --git a/usertools/dpdk-telemetry-client.py b/usertools/dpdk-telemetry-client.py
new file mode 100644
index 000000000..6dcf62bac
--- /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_SEQPACKET)
+ self.recv_fd = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ 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)
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* [dpdk-dev] [PATCH v10 12/12] build: add dependency on telemetry to apps in meson
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (10 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 11/12] usertools: add client python script for telemetry Harry van Haaren
@ 2018-10-27 9:17 ` Harry van Haaren
2018-10-27 13:24 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Thomas Monjalon
12 siblings, 0 replies; 219+ messages in thread
From: Harry van Haaren @ 2018-10-27 9:17 UTC (permalink / raw)
To: dev
Cc: thomas, bruce.richardson, stephen, gaetan.rivet, shreyansh.jain,
mattias.ronnblom, Kevin Laatz, Radu Nicolau
From: Kevin Laatz <kevin.laatz@intel.com>
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 <bruce.richardson@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
---
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/librte_telemetry/meson.build | 1 +
lib/meson.build | 1 +
meson.build | 2 ++
10 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/app/meson.build b/app/meson.build
index e68d949e9..a9a026bbf 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -29,7 +29,7 @@ foreach app:apps
# use "deps" for internal DPDK dependencies, and "ext_deps" for
# external package/library requirements
ext_deps = []
- deps = []
+ deps = dpdk_app_link_libraries
subdir(name)
@@ -43,7 +43,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 988cb4eb2..116c27f02 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 9c148e36e..a52b2ee4a 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 653907ded..eb8cc0499 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 eacd7a0f5..d735b186f 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 cd66618e9..6006c60f9 100644
--- a/app/test-pmd/meson.build
+++ b/app/test-pmd/meson.build
@@ -24,7 +24,7 @@ sources = files('cmdline.c',
'txonly.c',
'util.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 6f9228c87..275f00b60 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/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build
index b3bbf5bd0..9492f544e 100644
--- a/lib/librte_telemetry/meson.build
+++ b/lib/librte_telemetry/meson.build
@@ -9,6 +9,7 @@ cflags += '-DALLOW_EXPERIMENTAL_API'
jansson = cc.find_library('jansson', required: false)
if jansson.found()
ext_deps += jansson
+ dpdk_app_link_libraries += ['telemetry']
else
build = false
endif
diff --git a/lib/meson.build b/lib/meson.build
index 9d1f353d2..c0cc2d86e 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -132,6 +132,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 c9af33532..b1e6eab6a 100644
--- a/meson.build
+++ b/meson.build
@@ -12,8 +12,10 @@ project('DPDK', 'C',
cc = meson.get_compiler('c')
dpdk_conf = configuration_data()
dpdk_libraries = []
+dpdk_static_libraries = []
dpdk_drivers = []
dpdk_extra_ldflags = []
+dpdk_app_link_libraries = []
driver_install_path = join_paths(get_option('libdir'), 'dpdk/drivers')
eal_pmd_path = join_paths(get_option('prefix'), driver_install_path)
--
2.17.1
^ permalink raw reply [flat|nested] 219+ messages in thread
* Re: [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 00/12] Introduce Telemetry Library Harry van Haaren
` (11 preceding siblings ...)
2018-10-27 9:17 ` [dpdk-dev] [PATCH v10 12/12] build: add dependency on telemetry to apps in meson Harry van Haaren
@ 2018-10-27 13:24 ` Thomas Monjalon
12 siblings, 0 replies; 219+ messages in thread
From: Thomas Monjalon @ 2018-10-27 13:24 UTC (permalink / raw)
To: Harry van Haaren, bruce.richardson, kevin.laatz
Cc: dev, stephen, gaetan.rivet, shreyansh.jain, mattias.ronnblom,
radu.nicolau
27/10/2018 11:17, Harry van Haaren:
> Ciara Power (9):
> telemetry: initial telemetry infrastructure
> telemetry: add initial connection socket
> telemetry: add client feature and sockets
> telemetry: add parser for client socket messages
> telemetry: update metrics before sending stats
> telemetry: format json response when sending stats
> telemetry: add ability to disable selftest
> doc: add telemetry documentation
> usertools: add client python script for telemetry
>
> Kevin Laatz (3):
> eal: add option register infrastructure
> eal: make get runtime dir function public
> build: add dependency on telemetry to apps in meson
Applied with some changes as discussed on IRC with Harry.
Everybody spent so many time on this feature, I guess nobody wants to
hear about it for some time :) Let's hope all will work as expected!
^ permalink raw reply [flat|nested] 219+ messages in thread