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