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