199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2020 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
59f5c7170STyler Retzlaff #include <ctype.h>
672b452c5SDmitry Kozlyuk #include <errno.h>
772b452c5SDmitry Kozlyuk #include <stdlib.h>
882c33481SHuisong Li #include <inttypes.h>
972b452c5SDmitry Kozlyuk
1099a2dd95SBruce Richardson #undef RTE_USE_LIBBSD
112537fb0cSBruce Richardson #include <stdbool.h>
122537fb0cSBruce Richardson
1399a2dd95SBruce Richardson #include <rte_string_fns.h>
1499a2dd95SBruce Richardson
1599a2dd95SBruce Richardson #include "telemetry_data.h"
1699a2dd95SBruce Richardson
1782c33481SHuisong Li #define RTE_TEL_UINT_HEX_STR_BUF_LEN 64
1882c33481SHuisong Li
1999a2dd95SBruce Richardson int
rte_tel_data_start_array(struct rte_tel_data * d,enum rte_tel_value_type type)2099a2dd95SBruce Richardson rte_tel_data_start_array(struct rte_tel_data *d, enum rte_tel_value_type type)
2199a2dd95SBruce Richardson {
2299a2dd95SBruce Richardson enum tel_container_types array_types[] = {
235ebf6e0fSBruce Richardson [RTE_TEL_STRING_VAL] = TEL_ARRAY_STRING,
245ebf6e0fSBruce Richardson [RTE_TEL_INT_VAL] = TEL_ARRAY_INT,
25cc4f33d9SBruce Richardson [RTE_TEL_UINT_VAL] = TEL_ARRAY_UINT,
265ebf6e0fSBruce Richardson [RTE_TEL_CONTAINER] = TEL_ARRAY_CONTAINER,
2799a2dd95SBruce Richardson };
2899a2dd95SBruce Richardson d->type = array_types[type];
2999a2dd95SBruce Richardson d->data_len = 0;
3099a2dd95SBruce Richardson return 0;
3199a2dd95SBruce Richardson }
3299a2dd95SBruce Richardson
3399a2dd95SBruce Richardson int
rte_tel_data_start_dict(struct rte_tel_data * d)3499a2dd95SBruce Richardson rte_tel_data_start_dict(struct rte_tel_data *d)
3599a2dd95SBruce Richardson {
365a36d531SBruce Richardson d->type = TEL_DICT;
3799a2dd95SBruce Richardson d->data_len = 0;
3899a2dd95SBruce Richardson return 0;
3999a2dd95SBruce Richardson }
4099a2dd95SBruce Richardson
4199a2dd95SBruce Richardson int
rte_tel_data_string(struct rte_tel_data * d,const char * str)4299a2dd95SBruce Richardson rte_tel_data_string(struct rte_tel_data *d, const char *str)
4399a2dd95SBruce Richardson {
445a36d531SBruce Richardson d->type = TEL_STRING;
4599a2dd95SBruce Richardson d->data_len = strlcpy(d->data.str, str, sizeof(d->data.str));
4699a2dd95SBruce Richardson if (d->data_len >= RTE_TEL_MAX_SINGLE_STRING_LEN) {
4799a2dd95SBruce Richardson d->data_len = RTE_TEL_MAX_SINGLE_STRING_LEN - 1;
4899a2dd95SBruce Richardson return E2BIG; /* not necessarily and error, just truncation */
4999a2dd95SBruce Richardson }
5099a2dd95SBruce Richardson return 0;
5199a2dd95SBruce Richardson }
5299a2dd95SBruce Richardson
5399a2dd95SBruce Richardson int
rte_tel_data_add_array_string(struct rte_tel_data * d,const char * str)5499a2dd95SBruce Richardson rte_tel_data_add_array_string(struct rte_tel_data *d, const char *str)
5599a2dd95SBruce Richardson {
565a36d531SBruce Richardson if (d->type != TEL_ARRAY_STRING)
5799a2dd95SBruce Richardson return -EINVAL;
5899a2dd95SBruce Richardson if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
5999a2dd95SBruce Richardson return -ENOSPC;
6099a2dd95SBruce Richardson const size_t bytes = strlcpy(d->data.array[d->data_len++].sval,
6199a2dd95SBruce Richardson str, RTE_TEL_MAX_STRING_LEN);
6299a2dd95SBruce Richardson return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
6399a2dd95SBruce Richardson }
6499a2dd95SBruce Richardson
65*51cbeedeSDavid Marchand int
rte_tel_data_add_array_int(struct rte_tel_data * d,int64_t x)66*51cbeedeSDavid Marchand rte_tel_data_add_array_int(struct rte_tel_data *d, int64_t x)
6799a2dd95SBruce Richardson {
685a36d531SBruce Richardson if (d->type != TEL_ARRAY_INT)
6999a2dd95SBruce Richardson return -EINVAL;
7099a2dd95SBruce Richardson if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
7199a2dd95SBruce Richardson return -ENOSPC;
7299a2dd95SBruce Richardson d->data.array[d->data_len++].ival = x;
7399a2dd95SBruce Richardson return 0;
7499a2dd95SBruce Richardson }
7599a2dd95SBruce Richardson
7699a2dd95SBruce Richardson int
rte_tel_data_add_array_uint(struct rte_tel_data * d,uint64_t x)77cc4f33d9SBruce Richardson rte_tel_data_add_array_uint(struct rte_tel_data *d, uint64_t x)
7899a2dd95SBruce Richardson {
79cc4f33d9SBruce Richardson if (d->type != TEL_ARRAY_UINT)
8099a2dd95SBruce Richardson return -EINVAL;
8199a2dd95SBruce Richardson if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
8299a2dd95SBruce Richardson return -ENOSPC;
83cc4f33d9SBruce Richardson d->data.array[d->data_len++].uval = x;
8499a2dd95SBruce Richardson return 0;
8599a2dd95SBruce Richardson }
8699a2dd95SBruce Richardson
8799a2dd95SBruce Richardson int
rte_tel_data_add_array_u64(struct rte_tel_data * d,uint64_t x)88cc4f33d9SBruce Richardson rte_tel_data_add_array_u64(struct rte_tel_data *d, uint64_t x)
89cc4f33d9SBruce Richardson {
90cc4f33d9SBruce Richardson return rte_tel_data_add_array_uint(d, x);
91cc4f33d9SBruce Richardson }
92cc4f33d9SBruce Richardson
93cc4f33d9SBruce Richardson int
rte_tel_data_add_array_container(struct rte_tel_data * d,struct rte_tel_data * val,int keep)9499a2dd95SBruce Richardson rte_tel_data_add_array_container(struct rte_tel_data *d,
9599a2dd95SBruce Richardson struct rte_tel_data *val, int keep)
9699a2dd95SBruce Richardson {
975a36d531SBruce Richardson if (d->type != TEL_ARRAY_CONTAINER ||
98cc4f33d9SBruce Richardson (val->type != TEL_ARRAY_UINT
995a36d531SBruce Richardson && val->type != TEL_ARRAY_INT
1005a36d531SBruce Richardson && val->type != TEL_ARRAY_STRING))
10199a2dd95SBruce Richardson return -EINVAL;
10299a2dd95SBruce Richardson if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
10399a2dd95SBruce Richardson return -ENOSPC;
10499a2dd95SBruce Richardson
10599a2dd95SBruce Richardson d->data.array[d->data_len].container.data = val;
10699a2dd95SBruce Richardson d->data.array[d->data_len++].container.keep = !!keep;
10799a2dd95SBruce Richardson return 0;
10899a2dd95SBruce Richardson }
10999a2dd95SBruce Richardson
11082c33481SHuisong Li static int
rte_tel_uint_to_hex_encoded_str(char * buf,size_t buf_len,uint64_t val,uint8_t display_bitwidth)11182c33481SHuisong Li rte_tel_uint_to_hex_encoded_str(char *buf, size_t buf_len, uint64_t val,
11282c33481SHuisong Li uint8_t display_bitwidth)
11382c33481SHuisong Li {
1144dd4b432SBruce Richardson int spec_hex_width = (display_bitwidth + 3) / 4;
1154dd4b432SBruce Richardson int len;
11682c33481SHuisong Li
1174dd4b432SBruce Richardson if (display_bitwidth != 0)
1184dd4b432SBruce Richardson len = snprintf(buf, buf_len, "0x%0*" PRIx64, spec_hex_width, val);
1194dd4b432SBruce Richardson else
1204dd4b432SBruce Richardson len = snprintf(buf, buf_len, "0x%" PRIx64, val);
12182c33481SHuisong Li
1224dd4b432SBruce Richardson return len < (int)buf_len ? 0 : -EINVAL;
12382c33481SHuisong Li }
12482c33481SHuisong Li
12582c33481SHuisong Li int
rte_tel_data_add_array_uint_hex(struct rte_tel_data * d,uint64_t val,uint8_t display_bitwidth)12682c33481SHuisong Li rte_tel_data_add_array_uint_hex(struct rte_tel_data *d, uint64_t val,
12782c33481SHuisong Li uint8_t display_bitwidth)
12882c33481SHuisong Li {
12982c33481SHuisong Li char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
13082c33481SHuisong Li int ret;
13182c33481SHuisong Li
13282c33481SHuisong Li ret = rte_tel_uint_to_hex_encoded_str(hex_str,
13382c33481SHuisong Li RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
13482c33481SHuisong Li if (ret != 0)
13582c33481SHuisong Li return ret;
13682c33481SHuisong Li
13782c33481SHuisong Li return rte_tel_data_add_array_string(d, hex_str);
13882c33481SHuisong Li }
13982c33481SHuisong Li
1402537fb0cSBruce Richardson static bool
valid_name(const char * name)1412537fb0cSBruce Richardson valid_name(const char *name)
1422537fb0cSBruce Richardson {
1439f5c7170STyler Retzlaff /* non-alphanumeric characters allowed in names */
1449f5c7170STyler Retzlaff static const char allowed[128] = { ['_'] = 1, ['/'] = 1 };
1459f5c7170STyler Retzlaff
1469f5c7170STyler Retzlaff for (; *name != '\0'; name++) {
1479f5c7170STyler Retzlaff if (isalnum(*name))
1489f5c7170STyler Retzlaff continue;
1492537fb0cSBruce Richardson if ((size_t)*name >= RTE_DIM(allowed) || allowed[(int)*name] == 0)
1502537fb0cSBruce Richardson return false;
1512537fb0cSBruce Richardson }
1522537fb0cSBruce Richardson return true;
1532537fb0cSBruce Richardson }
1542537fb0cSBruce Richardson
15599a2dd95SBruce Richardson int
rte_tel_data_add_dict_string(struct rte_tel_data * d,const char * name,const char * val)15699a2dd95SBruce Richardson rte_tel_data_add_dict_string(struct rte_tel_data *d, const char *name,
15799a2dd95SBruce Richardson const char *val)
15899a2dd95SBruce Richardson {
15999a2dd95SBruce Richardson struct tel_dict_entry *e = &d->data.dict[d->data_len];
16099a2dd95SBruce Richardson size_t nbytes, vbytes;
16199a2dd95SBruce Richardson
1625a36d531SBruce Richardson if (d->type != TEL_DICT)
16399a2dd95SBruce Richardson return -EINVAL;
16499a2dd95SBruce Richardson if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
16599a2dd95SBruce Richardson return -ENOSPC;
16699a2dd95SBruce Richardson
1672537fb0cSBruce Richardson if (!valid_name(name))
1682537fb0cSBruce Richardson return -EINVAL;
1692537fb0cSBruce Richardson
17099a2dd95SBruce Richardson d->data_len++;
17199a2dd95SBruce Richardson e->type = RTE_TEL_STRING_VAL;
17299a2dd95SBruce Richardson vbytes = strlcpy(e->value.sval, val, RTE_TEL_MAX_STRING_LEN);
17399a2dd95SBruce Richardson nbytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
17499a2dd95SBruce Richardson if (vbytes >= RTE_TEL_MAX_STRING_LEN ||
17599a2dd95SBruce Richardson nbytes >= RTE_TEL_MAX_STRING_LEN)
17699a2dd95SBruce Richardson return E2BIG;
17799a2dd95SBruce Richardson return 0;
17899a2dd95SBruce Richardson }
17999a2dd95SBruce Richardson
180*51cbeedeSDavid Marchand int
rte_tel_data_add_dict_int(struct rte_tel_data * d,const char * name,int64_t val)181*51cbeedeSDavid Marchand rte_tel_data_add_dict_int(struct rte_tel_data *d, const char *name, int64_t val)
18299a2dd95SBruce Richardson {
18399a2dd95SBruce Richardson struct tel_dict_entry *e = &d->data.dict[d->data_len];
1845a36d531SBruce Richardson if (d->type != TEL_DICT)
18599a2dd95SBruce Richardson return -EINVAL;
18699a2dd95SBruce Richardson if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
18799a2dd95SBruce Richardson return -ENOSPC;
18899a2dd95SBruce Richardson
1892537fb0cSBruce Richardson if (!valid_name(name))
1902537fb0cSBruce Richardson return -EINVAL;
1912537fb0cSBruce Richardson
19299a2dd95SBruce Richardson d->data_len++;
19399a2dd95SBruce Richardson e->type = RTE_TEL_INT_VAL;
19499a2dd95SBruce Richardson e->value.ival = val;
19599a2dd95SBruce Richardson const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
19699a2dd95SBruce Richardson return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
19799a2dd95SBruce Richardson }
19899a2dd95SBruce Richardson
19999a2dd95SBruce Richardson int
rte_tel_data_add_dict_uint(struct rte_tel_data * d,const char * name,uint64_t val)200cc4f33d9SBruce Richardson rte_tel_data_add_dict_uint(struct rte_tel_data *d,
20199a2dd95SBruce Richardson const char *name, uint64_t val)
20299a2dd95SBruce Richardson {
20399a2dd95SBruce Richardson struct tel_dict_entry *e = &d->data.dict[d->data_len];
2045a36d531SBruce Richardson if (d->type != TEL_DICT)
20599a2dd95SBruce Richardson return -EINVAL;
20699a2dd95SBruce Richardson if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
20799a2dd95SBruce Richardson return -ENOSPC;
20899a2dd95SBruce Richardson
2092537fb0cSBruce Richardson if (!valid_name(name))
2102537fb0cSBruce Richardson return -EINVAL;
2112537fb0cSBruce Richardson
21299a2dd95SBruce Richardson d->data_len++;
2132d2c55e4SBruce Richardson e->type = RTE_TEL_UINT_VAL;
214cc4f33d9SBruce Richardson e->value.uval = val;
21599a2dd95SBruce Richardson const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
21699a2dd95SBruce Richardson return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
21799a2dd95SBruce Richardson }
21899a2dd95SBruce Richardson
21999a2dd95SBruce Richardson int
rte_tel_data_add_dict_u64(struct rte_tel_data * d,const char * name,uint64_t val)220cc4f33d9SBruce Richardson rte_tel_data_add_dict_u64(struct rte_tel_data *d, const char *name, uint64_t val)
221cc4f33d9SBruce Richardson {
222cc4f33d9SBruce Richardson return rte_tel_data_add_dict_uint(d, name, val);
223cc4f33d9SBruce Richardson }
224cc4f33d9SBruce Richardson
225cc4f33d9SBruce Richardson int
rte_tel_data_add_dict_container(struct rte_tel_data * d,const char * name,struct rte_tel_data * val,int keep)22699a2dd95SBruce Richardson rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name,
22799a2dd95SBruce Richardson struct rte_tel_data *val, int keep)
22899a2dd95SBruce Richardson {
22999a2dd95SBruce Richardson struct tel_dict_entry *e = &d->data.dict[d->data_len];
23099a2dd95SBruce Richardson
231cc4f33d9SBruce Richardson if (d->type != TEL_DICT || (val->type != TEL_ARRAY_UINT
2325a36d531SBruce Richardson && val->type != TEL_ARRAY_INT
2335a36d531SBruce Richardson && val->type != TEL_ARRAY_STRING
2345a36d531SBruce Richardson && val->type != TEL_DICT))
23599a2dd95SBruce Richardson return -EINVAL;
23699a2dd95SBruce Richardson if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
23799a2dd95SBruce Richardson return -ENOSPC;
23899a2dd95SBruce Richardson
2392537fb0cSBruce Richardson if (!valid_name(name))
2402537fb0cSBruce Richardson return -EINVAL;
2412537fb0cSBruce Richardson
24299a2dd95SBruce Richardson d->data_len++;
24399a2dd95SBruce Richardson e->type = RTE_TEL_CONTAINER;
24499a2dd95SBruce Richardson e->value.container.data = val;
24599a2dd95SBruce Richardson e->value.container.keep = !!keep;
24699a2dd95SBruce Richardson const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
24799a2dd95SBruce Richardson return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
24899a2dd95SBruce Richardson }
24999a2dd95SBruce Richardson
25082c33481SHuisong Li int
rte_tel_data_add_dict_uint_hex(struct rte_tel_data * d,const char * name,uint64_t val,uint8_t display_bitwidth)25182c33481SHuisong Li rte_tel_data_add_dict_uint_hex(struct rte_tel_data *d, const char *name,
25282c33481SHuisong Li uint64_t val, uint8_t display_bitwidth)
25382c33481SHuisong Li {
25482c33481SHuisong Li char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
25582c33481SHuisong Li int ret;
25682c33481SHuisong Li
25782c33481SHuisong Li ret = rte_tel_uint_to_hex_encoded_str(hex_str,
25882c33481SHuisong Li RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
25982c33481SHuisong Li if (ret != 0)
26082c33481SHuisong Li return ret;
26182c33481SHuisong Li
26282c33481SHuisong Li
26382c33481SHuisong Li return rte_tel_data_add_dict_string(d, name, hex_str);
26482c33481SHuisong Li }
26582c33481SHuisong Li
26699a2dd95SBruce Richardson struct rte_tel_data *
rte_tel_data_alloc(void)26799a2dd95SBruce Richardson rte_tel_data_alloc(void)
26899a2dd95SBruce Richardson {
26999a2dd95SBruce Richardson return malloc(sizeof(struct rte_tel_data));
27099a2dd95SBruce Richardson }
27199a2dd95SBruce Richardson
27299a2dd95SBruce Richardson void
rte_tel_data_free(struct rte_tel_data * data)27399a2dd95SBruce Richardson rte_tel_data_free(struct rte_tel_data *data)
27499a2dd95SBruce Richardson {
27599a2dd95SBruce Richardson free(data);
27699a2dd95SBruce Richardson }
277