xref: /dpdk/lib/telemetry/telemetry_data.c (revision 51cbeedeaf1f6e591e43f65b7ec97c80e4e1b952)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 
5 #include <ctype.h>
6 #include <errno.h>
7 #include <stdlib.h>
8 #include <inttypes.h>
9 
10 #undef RTE_USE_LIBBSD
11 #include <stdbool.h>
12 
13 #include <rte_string_fns.h>
14 
15 #include "telemetry_data.h"
16 
17 #define RTE_TEL_UINT_HEX_STR_BUF_LEN 64
18 
19 int
rte_tel_data_start_array(struct rte_tel_data * d,enum rte_tel_value_type type)20 rte_tel_data_start_array(struct rte_tel_data *d, enum rte_tel_value_type type)
21 {
22 	enum tel_container_types array_types[] = {
23 			[RTE_TEL_STRING_VAL] = TEL_ARRAY_STRING,
24 			[RTE_TEL_INT_VAL] = TEL_ARRAY_INT,
25 			[RTE_TEL_UINT_VAL] = TEL_ARRAY_UINT,
26 			[RTE_TEL_CONTAINER] = TEL_ARRAY_CONTAINER,
27 	};
28 	d->type = array_types[type];
29 	d->data_len = 0;
30 	return 0;
31 }
32 
33 int
rte_tel_data_start_dict(struct rte_tel_data * d)34 rte_tel_data_start_dict(struct rte_tel_data *d)
35 {
36 	d->type = TEL_DICT;
37 	d->data_len = 0;
38 	return 0;
39 }
40 
41 int
rte_tel_data_string(struct rte_tel_data * d,const char * str)42 rte_tel_data_string(struct rte_tel_data *d, const char *str)
43 {
44 	d->type = TEL_STRING;
45 	d->data_len = strlcpy(d->data.str, str, sizeof(d->data.str));
46 	if (d->data_len >= RTE_TEL_MAX_SINGLE_STRING_LEN) {
47 		d->data_len = RTE_TEL_MAX_SINGLE_STRING_LEN - 1;
48 		return E2BIG; /* not necessarily and error, just truncation */
49 	}
50 	return 0;
51 }
52 
53 int
rte_tel_data_add_array_string(struct rte_tel_data * d,const char * str)54 rte_tel_data_add_array_string(struct rte_tel_data *d, const char *str)
55 {
56 	if (d->type != TEL_ARRAY_STRING)
57 		return -EINVAL;
58 	if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
59 		return -ENOSPC;
60 	const size_t bytes = strlcpy(d->data.array[d->data_len++].sval,
61 			str, RTE_TEL_MAX_STRING_LEN);
62 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
63 }
64 
65 int
rte_tel_data_add_array_int(struct rte_tel_data * d,int64_t x)66 rte_tel_data_add_array_int(struct rte_tel_data *d, int64_t x)
67 {
68 	if (d->type != TEL_ARRAY_INT)
69 		return -EINVAL;
70 	if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
71 		return -ENOSPC;
72 	d->data.array[d->data_len++].ival = x;
73 	return 0;
74 }
75 
76 int
rte_tel_data_add_array_uint(struct rte_tel_data * d,uint64_t x)77 rte_tel_data_add_array_uint(struct rte_tel_data *d, uint64_t x)
78 {
79 	if (d->type != TEL_ARRAY_UINT)
80 		return -EINVAL;
81 	if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
82 		return -ENOSPC;
83 	d->data.array[d->data_len++].uval = x;
84 	return 0;
85 }
86 
87 int
rte_tel_data_add_array_u64(struct rte_tel_data * d,uint64_t x)88 rte_tel_data_add_array_u64(struct rte_tel_data *d, uint64_t x)
89 {
90 	return rte_tel_data_add_array_uint(d, x);
91 }
92 
93 int
rte_tel_data_add_array_container(struct rte_tel_data * d,struct rte_tel_data * val,int keep)94 rte_tel_data_add_array_container(struct rte_tel_data *d,
95 		struct rte_tel_data *val, int keep)
96 {
97 	if (d->type != TEL_ARRAY_CONTAINER ||
98 			(val->type != TEL_ARRAY_UINT
99 			&& val->type != TEL_ARRAY_INT
100 			&& val->type != TEL_ARRAY_STRING))
101 		return -EINVAL;
102 	if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
103 		return -ENOSPC;
104 
105 	d->data.array[d->data_len].container.data = val;
106 	d->data.array[d->data_len++].container.keep = !!keep;
107 	return 0;
108 }
109 
110 static int
rte_tel_uint_to_hex_encoded_str(char * buf,size_t buf_len,uint64_t val,uint8_t display_bitwidth)111 rte_tel_uint_to_hex_encoded_str(char *buf, size_t buf_len, uint64_t val,
112 				uint8_t display_bitwidth)
113 {
114 	int spec_hex_width = (display_bitwidth + 3) / 4;
115 	int len;
116 
117 	if (display_bitwidth != 0)
118 		len = snprintf(buf, buf_len, "0x%0*" PRIx64, spec_hex_width, val);
119 	else
120 		len = snprintf(buf, buf_len, "0x%" PRIx64, val);
121 
122 	return len < (int)buf_len ? 0 : -EINVAL;
123 }
124 
125 int
rte_tel_data_add_array_uint_hex(struct rte_tel_data * d,uint64_t val,uint8_t display_bitwidth)126 rte_tel_data_add_array_uint_hex(struct rte_tel_data *d, uint64_t val,
127 				uint8_t display_bitwidth)
128 {
129 	char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
130 	int ret;
131 
132 	ret = rte_tel_uint_to_hex_encoded_str(hex_str,
133 			RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
134 	if (ret != 0)
135 		return ret;
136 
137 	return rte_tel_data_add_array_string(d, hex_str);
138 }
139 
140 static bool
valid_name(const char * name)141 valid_name(const char *name)
142 {
143 	/* non-alphanumeric characters allowed in names */
144 	static const char allowed[128] = { ['_'] = 1, ['/'] = 1 };
145 
146 	for (; *name != '\0'; name++) {
147 		if (isalnum(*name))
148 			continue;
149 		if ((size_t)*name >= RTE_DIM(allowed) || allowed[(int)*name] == 0)
150 			return false;
151 	}
152 	return true;
153 }
154 
155 int
rte_tel_data_add_dict_string(struct rte_tel_data * d,const char * name,const char * val)156 rte_tel_data_add_dict_string(struct rte_tel_data *d, const char *name,
157 		const char *val)
158 {
159 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
160 	size_t nbytes, vbytes;
161 
162 	if (d->type != TEL_DICT)
163 		return -EINVAL;
164 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
165 		return -ENOSPC;
166 
167 	if (!valid_name(name))
168 		return -EINVAL;
169 
170 	d->data_len++;
171 	e->type = RTE_TEL_STRING_VAL;
172 	vbytes = strlcpy(e->value.sval, val, RTE_TEL_MAX_STRING_LEN);
173 	nbytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
174 	if (vbytes >= RTE_TEL_MAX_STRING_LEN ||
175 			nbytes >= RTE_TEL_MAX_STRING_LEN)
176 		return E2BIG;
177 	return 0;
178 }
179 
180 int
rte_tel_data_add_dict_int(struct rte_tel_data * d,const char * name,int64_t val)181 rte_tel_data_add_dict_int(struct rte_tel_data *d, const char *name, int64_t val)
182 {
183 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
184 	if (d->type != TEL_DICT)
185 		return -EINVAL;
186 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
187 		return -ENOSPC;
188 
189 	if (!valid_name(name))
190 		return -EINVAL;
191 
192 	d->data_len++;
193 	e->type = RTE_TEL_INT_VAL;
194 	e->value.ival = val;
195 	const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
196 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
197 }
198 
199 int
rte_tel_data_add_dict_uint(struct rte_tel_data * d,const char * name,uint64_t val)200 rte_tel_data_add_dict_uint(struct rte_tel_data *d,
201 		const char *name, uint64_t val)
202 {
203 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
204 	if (d->type != TEL_DICT)
205 		return -EINVAL;
206 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
207 		return -ENOSPC;
208 
209 	if (!valid_name(name))
210 		return -EINVAL;
211 
212 	d->data_len++;
213 	e->type = RTE_TEL_UINT_VAL;
214 	e->value.uval = val;
215 	const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
216 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
217 }
218 
219 int
rte_tel_data_add_dict_u64(struct rte_tel_data * d,const char * name,uint64_t val)220 rte_tel_data_add_dict_u64(struct rte_tel_data *d, const char *name, uint64_t val)
221 {
222 	return rte_tel_data_add_dict_uint(d, name, val);
223 }
224 
225 int
rte_tel_data_add_dict_container(struct rte_tel_data * d,const char * name,struct rte_tel_data * val,int keep)226 rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name,
227 		struct rte_tel_data *val, int keep)
228 {
229 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
230 
231 	if (d->type != TEL_DICT || (val->type != TEL_ARRAY_UINT
232 			&& val->type != TEL_ARRAY_INT
233 			&& val->type != TEL_ARRAY_STRING
234 			&& val->type != TEL_DICT))
235 		return -EINVAL;
236 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
237 		return -ENOSPC;
238 
239 	if (!valid_name(name))
240 		return -EINVAL;
241 
242 	d->data_len++;
243 	e->type = RTE_TEL_CONTAINER;
244 	e->value.container.data = val;
245 	e->value.container.keep = !!keep;
246 	const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
247 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
248 }
249 
250 int
rte_tel_data_add_dict_uint_hex(struct rte_tel_data * d,const char * name,uint64_t val,uint8_t display_bitwidth)251 rte_tel_data_add_dict_uint_hex(struct rte_tel_data *d, const char *name,
252 			       uint64_t val, uint8_t display_bitwidth)
253 {
254 	char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
255 	int ret;
256 
257 	ret = rte_tel_uint_to_hex_encoded_str(hex_str,
258 			RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
259 	if (ret != 0)
260 		return ret;
261 
262 
263 	return rte_tel_data_add_dict_string(d, name, hex_str);
264 }
265 
266 struct rte_tel_data *
rte_tel_data_alloc(void)267 rte_tel_data_alloc(void)
268 {
269 	return malloc(sizeof(struct rte_tel_data));
270 }
271 
272 void
rte_tel_data_free(struct rte_tel_data * data)273 rte_tel_data_free(struct rte_tel_data *data)
274 {
275 	free(data);
276 }
277