xref: /dpdk/lib/telemetry/telemetry_data.c (revision 33b84a2efca7ac188def108ba8b981daa7572b9a)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 
5 #include <errno.h>
6 #include <stdlib.h>
7 #include <inttypes.h>
8 
9 #undef RTE_USE_LIBBSD
10 #include <stdbool.h>
11 
12 #include <rte_function_versioning.h>
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
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
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
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
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 __vsym
66 rte_tel_data_add_array_int_v24(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 __vsym
77 rte_tel_data_add_array_int_v23(struct rte_tel_data *d, int x)
78 {
79 	return rte_tel_data_add_array_int_v24(d, x);
80 }
81 
82 /* mark the v23 function as the older version, and v24 as the default version */
83 VERSION_SYMBOL(rte_tel_data_add_array_int, _v23, 23);
84 BIND_DEFAULT_SYMBOL(rte_tel_data_add_array_int, _v24, 24);
85 MAP_STATIC_SYMBOL(int rte_tel_data_add_array_int(struct rte_tel_data *d,
86 		int64_t x), rte_tel_data_add_array_int_v24);
87 
88 int
89 rte_tel_data_add_array_uint(struct rte_tel_data *d, uint64_t x)
90 {
91 	if (d->type != TEL_ARRAY_UINT)
92 		return -EINVAL;
93 	if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
94 		return -ENOSPC;
95 	d->data.array[d->data_len++].uval = x;
96 	return 0;
97 }
98 
99 int
100 rte_tel_data_add_array_u64(struct rte_tel_data *d, uint64_t x)
101 {
102 	return rte_tel_data_add_array_uint(d, x);
103 }
104 
105 int
106 rte_tel_data_add_array_container(struct rte_tel_data *d,
107 		struct rte_tel_data *val, int keep)
108 {
109 	if (d->type != TEL_ARRAY_CONTAINER ||
110 			(val->type != TEL_ARRAY_UINT
111 			&& val->type != TEL_ARRAY_INT
112 			&& val->type != TEL_ARRAY_STRING))
113 		return -EINVAL;
114 	if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES)
115 		return -ENOSPC;
116 
117 	d->data.array[d->data_len].container.data = val;
118 	d->data.array[d->data_len++].container.keep = !!keep;
119 	return 0;
120 }
121 
122 /* To suppress compiler warning about format string. */
123 #if defined(RTE_TOOLCHAIN_GCC)
124 #pragma GCC diagnostic push
125 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
126 #elif defined(RTE_TOOLCHAIN_CLANG)
127 #pragma clang diagnostic push
128 #pragma clang diagnostic ignored "-Wformat-nonliteral"
129 #endif
130 
131 static int
132 rte_tel_uint_to_hex_encoded_str(char *buf, size_t buf_len, uint64_t val,
133 				uint8_t display_bitwidth)
134 {
135 #define RTE_TEL_HEX_FORMAT_LEN 16
136 
137 	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
138 	char format[RTE_TEL_HEX_FORMAT_LEN];
139 
140 	if (display_bitwidth != 0) {
141 		if (snprintf(format, RTE_TEL_HEX_FORMAT_LEN, "0x%%0%u" PRIx64,
142 				spec_hex_width) >= RTE_TEL_HEX_FORMAT_LEN)
143 			return -EINVAL;
144 
145 		if (snprintf(buf, buf_len, format, val) >= (int)buf_len)
146 			return -EINVAL;
147 	} else {
148 		if (snprintf(buf, buf_len, "0x%" PRIx64, val) >= (int)buf_len)
149 			return -EINVAL;
150 	}
151 
152 	return 0;
153 }
154 
155 #if defined(RTE_TOOLCHAIN_GCC)
156 #pragma GCC diagnostic pop
157 #elif defined(RTE_TOOLCHAIN_CLANG)
158 #pragma clang diagnostic pop
159 #endif
160 
161 int
162 rte_tel_data_add_array_uint_hex(struct rte_tel_data *d, uint64_t val,
163 				uint8_t display_bitwidth)
164 {
165 	char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
166 	int ret;
167 
168 	ret = rte_tel_uint_to_hex_encoded_str(hex_str,
169 			RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
170 	if (ret != 0)
171 		return ret;
172 
173 	return rte_tel_data_add_array_string(d, hex_str);
174 }
175 
176 static bool
177 valid_name(const char *name)
178 {
179 	char allowed[128] = {
180 			['0' ... '9'] = 1,
181 			['A' ... 'Z'] = 1,
182 			['a' ... 'z'] = 1,
183 			['_'] = 1,
184 			['/'] = 1,
185 	};
186 	while (*name != '\0') {
187 		if ((size_t)*name >= RTE_DIM(allowed) || allowed[(int)*name] == 0)
188 			return false;
189 		name++;
190 	}
191 	return true;
192 }
193 
194 int
195 rte_tel_data_add_dict_string(struct rte_tel_data *d, const char *name,
196 		const char *val)
197 {
198 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
199 	size_t nbytes, vbytes;
200 
201 	if (d->type != TEL_DICT)
202 		return -EINVAL;
203 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
204 		return -ENOSPC;
205 
206 	if (!valid_name(name))
207 		return -EINVAL;
208 
209 	d->data_len++;
210 	e->type = RTE_TEL_STRING_VAL;
211 	vbytes = strlcpy(e->value.sval, val, RTE_TEL_MAX_STRING_LEN);
212 	nbytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
213 	if (vbytes >= RTE_TEL_MAX_STRING_LEN ||
214 			nbytes >= RTE_TEL_MAX_STRING_LEN)
215 		return E2BIG;
216 	return 0;
217 }
218 
219 int __vsym
220 rte_tel_data_add_dict_int_v24(struct rte_tel_data *d, const char *name, int64_t val)
221 {
222 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
223 	if (d->type != TEL_DICT)
224 		return -EINVAL;
225 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
226 		return -ENOSPC;
227 
228 	if (!valid_name(name))
229 		return -EINVAL;
230 
231 	d->data_len++;
232 	e->type = RTE_TEL_INT_VAL;
233 	e->value.ival = val;
234 	const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
235 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
236 }
237 
238 int __vsym
239 rte_tel_data_add_dict_int_v23(struct rte_tel_data *d, const char *name, int val)
240 {
241 	return rte_tel_data_add_dict_int_v24(d, name, val);
242 }
243 
244 /* mark the v23 function as the older version, and v24 as the default version */
245 VERSION_SYMBOL(rte_tel_data_add_dict_int, _v23, 23);
246 BIND_DEFAULT_SYMBOL(rte_tel_data_add_dict_int, _v24, 24);
247 MAP_STATIC_SYMBOL(int rte_tel_data_add_dict_int(struct rte_tel_data *d,
248 		const char *name, int64_t val), rte_tel_data_add_dict_int_v24);
249 
250 int
251 rte_tel_data_add_dict_uint(struct rte_tel_data *d,
252 		const char *name, uint64_t val)
253 {
254 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
255 	if (d->type != TEL_DICT)
256 		return -EINVAL;
257 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
258 		return -ENOSPC;
259 
260 	if (!valid_name(name))
261 		return -EINVAL;
262 
263 	d->data_len++;
264 	e->type = RTE_TEL_UINT_VAL;
265 	e->value.uval = val;
266 	const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
267 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
268 }
269 
270 int
271 rte_tel_data_add_dict_u64(struct rte_tel_data *d, const char *name, uint64_t val)
272 {
273 	return rte_tel_data_add_dict_uint(d, name, val);
274 }
275 
276 int
277 rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name,
278 		struct rte_tel_data *val, int keep)
279 {
280 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
281 
282 	if (d->type != TEL_DICT || (val->type != TEL_ARRAY_UINT
283 			&& val->type != TEL_ARRAY_INT
284 			&& val->type != TEL_ARRAY_STRING
285 			&& val->type != TEL_DICT))
286 		return -EINVAL;
287 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
288 		return -ENOSPC;
289 
290 	if (!valid_name(name))
291 		return -EINVAL;
292 
293 	d->data_len++;
294 	e->type = RTE_TEL_CONTAINER;
295 	e->value.container.data = val;
296 	e->value.container.keep = !!keep;
297 	const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
298 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
299 }
300 
301 int
302 rte_tel_data_add_dict_uint_hex(struct rte_tel_data *d, const char *name,
303 			       uint64_t val, uint8_t display_bitwidth)
304 {
305 	char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
306 	int ret;
307 
308 	ret = rte_tel_uint_to_hex_encoded_str(hex_str,
309 			RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
310 	if (ret != 0)
311 		return ret;
312 
313 
314 	return rte_tel_data_add_dict_string(d, name, hex_str);
315 }
316 
317 struct rte_tel_data *
318 rte_tel_data_alloc(void)
319 {
320 	return malloc(sizeof(struct rte_tel_data));
321 }
322 
323 void
324 rte_tel_data_free(struct rte_tel_data *data)
325 {
326 	free(data);
327 }
328