xref: /dpdk/lib/telemetry/telemetry_data.c (revision 665b49c51639a10c553433bc2bcd85c7331c631e)
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 static int
123 rte_tel_uint_to_hex_encoded_str(char *buf, size_t buf_len, uint64_t val,
124 				uint8_t display_bitwidth)
125 {
126 	int spec_hex_width = (display_bitwidth + 3) / 4;
127 	int len;
128 
129 	if (display_bitwidth != 0)
130 		len = snprintf(buf, buf_len, "0x%0*" PRIx64, spec_hex_width, val);
131 	else
132 		len = snprintf(buf, buf_len, "0x%" PRIx64, val);
133 
134 	return len < (int)buf_len ? 0 : -EINVAL;
135 }
136 
137 int
138 rte_tel_data_add_array_uint_hex(struct rte_tel_data *d, uint64_t val,
139 				uint8_t display_bitwidth)
140 {
141 	char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
142 	int ret;
143 
144 	ret = rte_tel_uint_to_hex_encoded_str(hex_str,
145 			RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
146 	if (ret != 0)
147 		return ret;
148 
149 	return rte_tel_data_add_array_string(d, hex_str);
150 }
151 
152 static bool
153 valid_name(const char *name)
154 {
155 	char allowed[128] = {
156 			['0' ... '9'] = 1,
157 			['A' ... 'Z'] = 1,
158 			['a' ... 'z'] = 1,
159 			['_'] = 1,
160 			['/'] = 1,
161 	};
162 	while (*name != '\0') {
163 		if ((size_t)*name >= RTE_DIM(allowed) || allowed[(int)*name] == 0)
164 			return false;
165 		name++;
166 	}
167 	return true;
168 }
169 
170 int
171 rte_tel_data_add_dict_string(struct rte_tel_data *d, const char *name,
172 		const char *val)
173 {
174 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
175 	size_t nbytes, vbytes;
176 
177 	if (d->type != TEL_DICT)
178 		return -EINVAL;
179 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
180 		return -ENOSPC;
181 
182 	if (!valid_name(name))
183 		return -EINVAL;
184 
185 	d->data_len++;
186 	e->type = RTE_TEL_STRING_VAL;
187 	vbytes = strlcpy(e->value.sval, val, RTE_TEL_MAX_STRING_LEN);
188 	nbytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
189 	if (vbytes >= RTE_TEL_MAX_STRING_LEN ||
190 			nbytes >= RTE_TEL_MAX_STRING_LEN)
191 		return E2BIG;
192 	return 0;
193 }
194 
195 int __vsym
196 rte_tel_data_add_dict_int_v24(struct rte_tel_data *d, const char *name, int64_t val)
197 {
198 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
199 	if (d->type != TEL_DICT)
200 		return -EINVAL;
201 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
202 		return -ENOSPC;
203 
204 	if (!valid_name(name))
205 		return -EINVAL;
206 
207 	d->data_len++;
208 	e->type = RTE_TEL_INT_VAL;
209 	e->value.ival = val;
210 	const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
211 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
212 }
213 
214 int __vsym
215 rte_tel_data_add_dict_int_v23(struct rte_tel_data *d, const char *name, int val)
216 {
217 	return rte_tel_data_add_dict_int_v24(d, name, val);
218 }
219 
220 /* mark the v23 function as the older version, and v24 as the default version */
221 VERSION_SYMBOL(rte_tel_data_add_dict_int, _v23, 23);
222 BIND_DEFAULT_SYMBOL(rte_tel_data_add_dict_int, _v24, 24);
223 MAP_STATIC_SYMBOL(int rte_tel_data_add_dict_int(struct rte_tel_data *d,
224 		const char *name, int64_t val), rte_tel_data_add_dict_int_v24);
225 
226 int
227 rte_tel_data_add_dict_uint(struct rte_tel_data *d,
228 		const char *name, uint64_t val)
229 {
230 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
231 	if (d->type != TEL_DICT)
232 		return -EINVAL;
233 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
234 		return -ENOSPC;
235 
236 	if (!valid_name(name))
237 		return -EINVAL;
238 
239 	d->data_len++;
240 	e->type = RTE_TEL_UINT_VAL;
241 	e->value.uval = val;
242 	const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
243 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
244 }
245 
246 int
247 rte_tel_data_add_dict_u64(struct rte_tel_data *d, const char *name, uint64_t val)
248 {
249 	return rte_tel_data_add_dict_uint(d, name, val);
250 }
251 
252 int
253 rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name,
254 		struct rte_tel_data *val, int keep)
255 {
256 	struct tel_dict_entry *e = &d->data.dict[d->data_len];
257 
258 	if (d->type != TEL_DICT || (val->type != TEL_ARRAY_UINT
259 			&& val->type != TEL_ARRAY_INT
260 			&& val->type != TEL_ARRAY_STRING
261 			&& val->type != TEL_DICT))
262 		return -EINVAL;
263 	if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES)
264 		return -ENOSPC;
265 
266 	if (!valid_name(name))
267 		return -EINVAL;
268 
269 	d->data_len++;
270 	e->type = RTE_TEL_CONTAINER;
271 	e->value.container.data = val;
272 	e->value.container.keep = !!keep;
273 	const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN);
274 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
275 }
276 
277 int
278 rte_tel_data_add_dict_uint_hex(struct rte_tel_data *d, const char *name,
279 			       uint64_t val, uint8_t display_bitwidth)
280 {
281 	char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
282 	int ret;
283 
284 	ret = rte_tel_uint_to_hex_encoded_str(hex_str,
285 			RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
286 	if (ret != 0)
287 		return ret;
288 
289 
290 	return rte_tel_data_add_dict_string(d, name, hex_str);
291 }
292 
293 struct rte_tel_data *
294 rte_tel_data_alloc(void)
295 {
296 	return malloc(sizeof(struct rte_tel_data));
297 }
298 
299 void
300 rte_tel_data_free(struct rte_tel_data *data)
301 {
302 	free(data);
303 }
304