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