numam-dpdk/lib/librte_telemetry/telemetry_data.c
Ciara Power c933bb5177 telemetry: support array values in data object
Arrays of type uint64_t/int/string can now be included within an array
or dict. One level of embedded containers is supported. This is
necessary to allow for instances such as the ethdev queue stats to be
reported as a list of uint64_t values, rather than having multiple dict
entries with one uint64_t value for each queue stat.

The memory management APIs provided by telemetry simplify the memory
allocation/free aspect of the embedded container. The rte_tel_data_alloc
function is called in the library/app callback to return a pointer to a
container that has been allocated memory. When adding this container
to an array/dict, a parameter is passed to indicate if the memory
should be freed by telemetry after use. This will allow reuse of the
allocated memory if the library/app wishes to do so.

Signed-off-by: Ciara Power <ciara.power@intel.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
2020-10-06 22:55:00 +02:00

182 lines
4.5 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2020 Intel Corporation
*/
#undef RTE_USE_LIBBSD
#include <rte_string_fns.h>
#include "telemetry_data.h"
int
rte_tel_data_start_array(struct rte_tel_data *d, enum rte_tel_value_type type)
{
enum tel_container_types array_types[] = {
RTE_TEL_ARRAY_STRING, /* RTE_TEL_STRING_VAL = 0 */
RTE_TEL_ARRAY_INT, /* RTE_TEL_INT_VAL = 1 */
RTE_TEL_ARRAY_U64, /* RTE_TEL_u64_VAL = 2 */
RTE_TEL_ARRAY_CONTAINER, /* RTE_TEL_CONTAINER = 3 */
};
d->type = array_types[type];
d->data_len = 0;
return 0;
}
int
rte_tel_data_start_dict(struct rte_tel_data *d)
{
d->type = RTE_TEL_DICT;
d->data_len = 0;
return 0;
}
int
rte_tel_data_string(struct rte_tel_data *d, const char *str)
{
d->type = RTE_TEL_STRING;
d->data_len = strlcpy(d->data.str, str, sizeof(d->data.str));
if (d->data_len >= RTE_TEL_MAX_SINGLE_STRING_LEN) {
d->data_len = RTE_TEL_MAX_SINGLE_STRING_LEN - 1;
return E2BIG; /* not necessarily and error, just truncation */
}
return 0;
}
int
rte_tel_data_add_array_string(struct rte_tel_data *d, const char *str)
{
if (d->type != RTE_TEL_ARRAY_STRING)
return -EINVAL;
if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
return -ENOSPC;
const size_t bytes = strlcpy(d->data.array[d->data_len++].sval,
str, RTE_TEL_MAX_STRING_LEN);
return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
}
int
rte_tel_data_add_array_int(struct rte_tel_data *d, int x)
{
if (d->type != RTE_TEL_ARRAY_INT)
return -EINVAL;
if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
return -ENOSPC;
d->data.array[d->data_len++].ival = x;
return 0;
}
int
rte_tel_data_add_array_u64(struct rte_tel_data *d, uint64_t x)
{
if (d->type != RTE_TEL_ARRAY_U64)
return -EINVAL;
if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
return -ENOSPC;
d->data.array[d->data_len++].u64val = x;
return 0;
}
int
rte_tel_data_add_array_container(struct rte_tel_data *d,
struct rte_tel_data *val, int keep)
{
if (d->type != RTE_TEL_ARRAY_CONTAINER ||
(val->type != RTE_TEL_ARRAY_U64
&& val->type != RTE_TEL_ARRAY_INT
&& val->type != RTE_TEL_ARRAY_STRING))
return -EINVAL;
if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
return -ENOSPC;
d->data.array[d->data_len].container.data = val;
d->data.array[d->data_len++].container.keep = !!keep;
return 0;
}
int
rte_tel_data_add_dict_string(struct rte_tel_data *d, const char *name,
const char *val)
{
struct tel_dict_entry *e = &d->data.dict[d->data_len];
size_t nbytes, vbytes;
if (d->type != RTE_TEL_DICT)
return -EINVAL;
if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
return -ENOSPC;
d->data_len++;
e->type = RTE_TEL_STRING_VAL;
vbytes = strlcpy(e->value.sval, val, RTE_TEL_MAX_STRING_LEN);
nbytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
if (vbytes >= RTE_TEL_MAX_STRING_LEN ||
nbytes >= RTE_TEL_MAX_STRING_LEN)
return E2BIG;
return 0;
}
int
rte_tel_data_add_dict_int(struct rte_tel_data *d, const char *name, int val)
{
struct tel_dict_entry *e = &d->data.dict[d->data_len];
if (d->type != RTE_TEL_DICT)
return -EINVAL;
if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
return -ENOSPC;
d->data_len++;
e->type = RTE_TEL_INT_VAL;
e->value.ival = val;
const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
}
int
rte_tel_data_add_dict_u64(struct rte_tel_data *d,
const char *name, uint64_t val)
{
struct tel_dict_entry *e = &d->data.dict[d->data_len];
if (d->type != RTE_TEL_DICT)
return -EINVAL;
if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
return -ENOSPC;
d->data_len++;
e->type = RTE_TEL_U64_VAL;
e->value.u64val = val;
const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
}
int
rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name,
struct rte_tel_data *val, int keep)
{
struct tel_dict_entry *e = &d->data.dict[d->data_len];
if (d->type != RTE_TEL_DICT || (val->type != RTE_TEL_ARRAY_U64
&& val->type != RTE_TEL_ARRAY_INT
&& val->type != RTE_TEL_ARRAY_STRING))
return -EINVAL;
if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
return -ENOSPC;
d->data_len++;
e->type = RTE_TEL_CONTAINER;
e->value.container.data = val;
e->value.container.keep = !!keep;
const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
}
struct rte_tel_data *
rte_tel_data_alloc(void)
{
return malloc(sizeof(struct rte_tel_data));
}
void
rte_tel_data_free(struct rte_tel_data *data)
{
free(data);
}