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