From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 05D61A034F; Thu, 30 Apr 2020 18:03:13 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 0B47E1DBDC; Thu, 30 Apr 2020 18:02:10 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by dpdk.org (Postfix) with ESMTP id A49401DBCF for ; Thu, 30 Apr 2020 18:02:07 +0200 (CEST) IronPort-SDR: SAOz+GG/mYpJ7xLh02MpobsO6n6tdKKgJQSiueDaJWs15sAii1NQ4oKI3mxYk3KBABBeKtjGih y1ohHHrABsTg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 30 Apr 2020 09:02:07 -0700 IronPort-SDR: R4jDooB5uKNQ78+Cm2G+f2S61FwRO9yKmpUC0xI7NOqPFrAfALtS2ZiSeUNYL6msVtZIhcFk+9 gnxXw0zcNqag== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,336,1583222400"; d="scan'208";a="258345070" Received: from silpixa00399953.ir.intel.com (HELO silpixa00399953.ger.corp.intel.com) ([10.237.222.53]) by orsmga003.jf.intel.com with ESMTP; 30 Apr 2020 09:02:04 -0700 From: Ciara Power To: dev@dpdk.org, kevin.laatz@intel.com Cc: reshma.pattan@intel.com, jerinjacobk@gmail.com, david.marchand@redhat.com, keith.wiles@intel.com, mb@smartsharesystems.com, thomas@monjalon.net, stephen@networkplumber.org, bluca@debian.org, Bruce Richardson Date: Thu, 30 Apr 2020 17:01:24 +0100 Message-Id: <20200430160137.59135-6-ciara.power@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200430160137.59135-1-ciara.power@intel.com> References: <20200319171907.60891-1-ciara.power@intel.com> <20200430160137.59135-1-ciara.power@intel.com> Subject: [dpdk-dev] [PATCH v5 05/18] telemetry: add utility functions for creating json X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Bruce Richardson The functions added in this patch will make it easier for telemetry to convert data to correct JSON responses to telemetry requests. Tests are also added for these json utility functions. Signed-off-by: Bruce Richardson Reviewed-by: Keith Wiles --- v4: Tests included in patch with utility functions --- app/test/Makefile | 2 + app/test/meson.build | 4 + app/test/test_telemetry_json.c | 136 ++++++++++++++++++++++ lib/librte_telemetry/telemetry_json.h | 158 ++++++++++++++++++++++++++ 4 files changed, 300 insertions(+) create mode 100644 app/test/test_telemetry_json.c create mode 100644 lib/librte_telemetry/telemetry_json.h diff --git a/app/test/Makefile b/app/test/Makefile index 4582eca6cf..e5c07ddf18 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -141,6 +141,8 @@ SRCS-$(CONFIG_RTE_LIBRTE_LPM) += test_lpm_perf.c SRCS-$(CONFIG_RTE_LIBRTE_LPM) += test_lpm6.c SRCS-$(CONFIG_RTE_LIBRTE_LPM) += test_lpm6_perf.c +SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += test_telemetry_json.c + SRCS-y += test_debug.c SRCS-y += test_errno.c SRCS-y += test_tailq.c diff --git a/app/test/meson.build b/app/test/meson.build index fc60acbe72..61abcc201f 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -335,6 +335,10 @@ endif if dpdk_conf.has('RTE_LIBRTE_SKELETON_EVENTDEV_PMD') test_deps += 'pmd_skeleton_event' endif +if dpdk_conf.has('RTE_LIBRTE_TELEMETRY') + test_sources += 'test_telemetry_json.c' + fast_tests += [['telemetry_json_autotest', true]] +endif # The following linkages of drivers are required because # they are used via a driver-specific API. diff --git a/app/test/test_telemetry_json.c b/app/test/test_telemetry_json.c new file mode 100644 index 0000000000..90bbb3e8d9 --- /dev/null +++ b/app/test/test_telemetry_json.c @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2020 Intel Corporation + */ + +#include + +#include "../../lib/librte_telemetry/telemetry_json.h" +#include "test.h" + +static int +test_basic_array(void) +{ + const char *expected = "[\"meaning of life\",42]"; + char buf[1024]; + int used = 0; + + printf("%s: ", __func__); + used = rte_tel_json_empty_array(buf, sizeof(buf), used); + if (used != 2 || strcmp(buf, "[]")) + return -1; + + used = rte_tel_json_add_array_string(buf, sizeof(buf), used, + "meaning of life"); + used = rte_tel_json_add_array_int(buf, sizeof(buf), used, 42); + + printf("buf = '%s', expected = '%s'\n", buf, expected); + if (used != (int)strlen(expected)) + return -1; + return strncmp(expected, buf, sizeof(buf)); +} + +static int +test_basic_obj(void) +{ + const char *expected = "{\"weddings\":4,\"funerals\":1}"; + char buf[1024]; + int used = 0; + + used = rte_tel_json_add_obj_u64(buf, sizeof(buf), used, + "weddings", 4); + used = rte_tel_json_add_obj_u64(buf, sizeof(buf), used, + "funerals", 1); + + printf("%s: buf = '%s', expected = '%s'\n", __func__, buf, expected); + if (used != (int)strlen(expected)) + return -1; + return strncmp(expected, buf, sizeof(buf)); +} + +static int +test_overflow_array(void) +{ + static const char * const strs[] = {"Arsenal", "Chelsea", "Liverpool", + "Spurs"}; + const char *expected = "[\"Arsenal\",\"Chelsea\"]"; + char buf[25]; + int i, used = 0; + + for (i = 0; i < (int)RTE_DIM(strs); i++) + used = rte_tel_json_add_array_string(buf, sizeof(buf), used, + strs[i]); + + printf("%s: buf = '%s', expected = '%s'\n", __func__, buf, expected); + if (buf[used - 1] != ']') + return -1; + if (used != (int)strlen(expected)) + return -1; + return strncmp(expected, buf, sizeof(buf)); +} + +static int +test_overflow_obj(void) +{ + static const char * const names[] = {"Italy", "Wales", "Scotland", + "Ireland", "England", "France"}; + const int vals[RTE_DIM(names)] = {20, 61, 10, 40, 55, 35}; + const char *expected = "{\"Italy\":20,\"Wales\":61}"; + char buf[25]; + int i, used = 0; + + for (i = 0; i < (int)RTE_DIM(names); i++) + used = rte_tel_json_add_obj_u64(buf, sizeof(buf), used, + names[i], vals[i]); + + printf("%s: buf = '%s', expected = '%s'\n", __func__, buf, expected); + if (buf[used - 1] != '}') + return -1; + if (used != (int)strlen(expected)) + return -1; + return strncmp(expected, buf, sizeof(buf)); +} + +static int +test_large_array_element(void) +{ + static const char str[] = "A really long string to overflow buffer"; + /* buffer should be unmodified so initial value and expected are same */ + const char *expected = "ABC"; + char buf[sizeof(str) - 5] = "ABC"; + int used = 0; + + used = rte_tel_json_add_array_string(buf, sizeof(buf), used, str); + printf("%s: buf = '%s', expected = '%s'\n", __func__, buf, expected); + + return strlen(buf) != 0; +} + +static int +test_large_obj_element(void) +{ + static const char str[] = "A really long string to overflow buffer"; + /* buffer should be unmodified so initial value and expected are same */ + const char *expected = "XYZ"; + char buf[sizeof(str) - 5] = "XYZ"; + int used = 0; + + used = rte_tel_json_add_obj_u64(buf, sizeof(buf), used, str, 0); + printf("%s: buf = '%s', expected = '%s'\n", __func__, buf, expected); + + return strlen(buf) != 0; +} + +static int +test_telemetry_json(void) +{ + if (test_basic_array() < 0 || + test_basic_obj() < 0 || + test_overflow_array() < 0 || + test_overflow_obj() < 0 || + test_large_array_element() < 0 || ++ test_large_obj_element() < 0) + return -1; + return 0; +} + +REGISTER_TEST_COMMAND(telemetry_json_autotest, test_telemetry_json); diff --git a/lib/librte_telemetry/telemetry_json.h b/lib/librte_telemetry/telemetry_json.h new file mode 100644 index 0000000000..a2ce4899e0 --- /dev/null +++ b/lib/librte_telemetry/telemetry_json.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#ifndef _RTE_TELEMETRY_JSON_H_ +#define _RTE_TELEMETRY_JSON_H_ + +#include +#include +#include +#include + +/** + * @file + * Internal Telemetry Utility functions + * + * This file contains small inline functions to make it easier for applications + * to build up valid JSON responses to telemetry requests. + * + ***/ + +/** + * @internal + * Copies a value into a buffer if the buffer has enough available space. + * Nothing written to buffer if an overflow ocurs. + * This function is not for use for values larger than 1k. + */ +__rte_format_printf(3, 4) +static inline int +__json_snprintf(char *buf, const int len, const char *format, ...) +{ + char tmp[1024]; + va_list ap; + int ret; + + va_start(ap, format); + ret = vsnprintf(tmp, sizeof(tmp), format, ap); + va_end(ap); + if (ret > 0 && ret < (int)sizeof(tmp) && ret < len) { + strcpy(buf, tmp); + return ret; + } + return 0; /* nothing written or modified */ +} + +/* Copies an empty array into the provided buffer. */ +static inline int +rte_tel_json_empty_array(char *buf, const int len, const int used) +{ + return used + __json_snprintf(buf + used, len - used, "[]"); +} + +/* Copies an empty object into the provided buffer. */ +static inline int +rte_tel_json_empty_obj(char *buf, const int len, const int used) +{ + return used + __json_snprintf(buf + used, len - used, "{}"); +} + +/* Copies a string into the provided buffer, in JSON format. */ +static inline int +rte_tel_json_str(char *buf, const int len, const int used, const char *str) +{ + return used + __json_snprintf(buf + used, len - used, "\"%s\"", str); +} + +/* Appends a string into the JSON array in the provided buffer. */ +static inline int +rte_tel_json_add_array_string(char *buf, const int len, const int used, + const char *str) +{ + int ret, end = used - 1; /* strip off final delimiter */ + if (used <= 2) /* assume empty, since minimum is '[]' */ + return __json_snprintf(buf, len, "[\"%s\"]", str); + + ret = __json_snprintf(buf + end, len - end, ",\"%s\"]", str); + return ret == 0 ? used : end + ret; +} + +/* Appends an integer into the JSON array in the provided buffer. */ +static inline int +rte_tel_json_add_array_int(char *buf, const int len, const int used, int val) +{ + int ret, end = used - 1; /* strip off final delimiter */ + if (used <= 2) /* assume empty, since minimum is '[]' */ + return __json_snprintf(buf, len, "[%d]", val); + + ret = __json_snprintf(buf + end, len - end, ",%d]", val); + return ret == 0 ? used : end + ret; +} + +/* Appends a uint64_t into the JSON array in the provided buffer. */ +static inline int +rte_tel_json_add_array_u64(char *buf, const int len, const int used, + uint64_t val) +{ + int ret, end = used - 1; /* strip off final delimiter */ + if (used <= 2) /* assume empty, since minimum is '[]' */ + return __json_snprintf(buf, len, "[%"PRIu64"]", val); + + ret = __json_snprintf(buf + end, len - end, ",%"PRIu64"]", val); + return ret == 0 ? used : end + ret; +} + +/** + * Add a new element with uint64_t value to the JSON object stored in the + * provided buffer. + */ +static inline int +rte_tel_json_add_obj_u64(char *buf, const int len, const int used, + const char *name, uint64_t val) +{ + int ret, end = used - 1; + if (used <= 2) /* assume empty, since minimum is '{}' */ + return __json_snprintf(buf, len, "{\"%s\":%"PRIu64"}", name, + val); + + ret = __json_snprintf(buf + end, len - end, ",\"%s\":%"PRIu64"}", + name, val); + return ret == 0 ? used : end + ret; +} + +/** + * Add a new element with int value to the JSON object stored in the + * provided buffer. + */ +static inline int +rte_tel_json_add_obj_int(char *buf, const int len, const int used, + const char *name, int val) +{ + int ret, end = used - 1; + if (used <= 2) /* assume empty, since minimum is '{}' */ + return __json_snprintf(buf, len, "{\"%s\":%d}", name, + val); + + ret = __json_snprintf(buf + end, len - end, ",\"%s\":%d}", + name, val); + return ret == 0 ? used : end + ret; +} + +/** + * Add a new element with string value to the JSON object stored in the + * provided buffer. + */ +static inline int +rte_tel_json_add_obj_str(char *buf, const int len, const int used, + const char *name, const char *val) +{ + int ret, end = used - 1; + if (used <= 2) /* assume empty, since minimum is '{}' */ + return __json_snprintf(buf, len, "{\"%s\":\"%s\"}", name, val); + + ret = __json_snprintf(buf + end, len - end, ",\"%s\":\"%s\"}", + name, val); + return ret == 0 ? used : end + ret; +} + +#endif /*_RTE_TELEMETRY_JSON_H_*/ -- 2.17.1