1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 5 #include <ctype.h> 6 #include <errno.h> 7 #include <stdlib.h> 8 #include <inttypes.h> 9 10 #undef RTE_USE_LIBBSD 11 #include <stdbool.h> 12 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 66 rte_tel_data_add_array_int(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 77 rte_tel_data_add_array_uint(struct rte_tel_data *d, uint64_t x) 78 { 79 if (d->type != TEL_ARRAY_UINT) 80 return -EINVAL; 81 if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES) 82 return -ENOSPC; 83 d->data.array[d->data_len++].uval = x; 84 return 0; 85 } 86 87 int 88 rte_tel_data_add_array_u64(struct rte_tel_data *d, uint64_t x) 89 { 90 return rte_tel_data_add_array_uint(d, x); 91 } 92 93 int 94 rte_tel_data_add_array_container(struct rte_tel_data *d, 95 struct rte_tel_data *val, int keep) 96 { 97 if (d->type != TEL_ARRAY_CONTAINER || 98 (val->type != TEL_ARRAY_UINT 99 && val->type != TEL_ARRAY_INT 100 && val->type != TEL_ARRAY_STRING)) 101 return -EINVAL; 102 if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES) 103 return -ENOSPC; 104 105 d->data.array[d->data_len].container.data = val; 106 d->data.array[d->data_len++].container.keep = !!keep; 107 return 0; 108 } 109 110 static int 111 rte_tel_uint_to_hex_encoded_str(char *buf, size_t buf_len, uint64_t val, 112 uint8_t display_bitwidth) 113 { 114 int spec_hex_width = (display_bitwidth + 3) / 4; 115 int len; 116 117 if (display_bitwidth != 0) 118 len = snprintf(buf, buf_len, "0x%0*" PRIx64, spec_hex_width, val); 119 else 120 len = snprintf(buf, buf_len, "0x%" PRIx64, val); 121 122 return len < (int)buf_len ? 0 : -EINVAL; 123 } 124 125 int 126 rte_tel_data_add_array_uint_hex(struct rte_tel_data *d, uint64_t val, 127 uint8_t display_bitwidth) 128 { 129 char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN]; 130 int ret; 131 132 ret = rte_tel_uint_to_hex_encoded_str(hex_str, 133 RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth); 134 if (ret != 0) 135 return ret; 136 137 return rte_tel_data_add_array_string(d, hex_str); 138 } 139 140 static bool 141 valid_name(const char *name) 142 { 143 /* non-alphanumeric characters allowed in names */ 144 static const char allowed[128] = { ['_'] = 1, ['/'] = 1 }; 145 146 for (; *name != '\0'; name++) { 147 if (isalnum(*name)) 148 continue; 149 if ((size_t)*name >= RTE_DIM(allowed) || allowed[(int)*name] == 0) 150 return false; 151 } 152 return true; 153 } 154 155 int 156 rte_tel_data_add_dict_string(struct rte_tel_data *d, const char *name, 157 const char *val) 158 { 159 struct tel_dict_entry *e = &d->data.dict[d->data_len]; 160 size_t nbytes, vbytes; 161 162 if (d->type != TEL_DICT) 163 return -EINVAL; 164 if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES) 165 return -ENOSPC; 166 167 if (!valid_name(name)) 168 return -EINVAL; 169 170 d->data_len++; 171 e->type = RTE_TEL_STRING_VAL; 172 vbytes = strlcpy(e->value.sval, val, RTE_TEL_MAX_STRING_LEN); 173 nbytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN); 174 if (vbytes >= RTE_TEL_MAX_STRING_LEN || 175 nbytes >= RTE_TEL_MAX_STRING_LEN) 176 return E2BIG; 177 return 0; 178 } 179 180 int 181 rte_tel_data_add_dict_int(struct rte_tel_data *d, const char *name, int64_t val) 182 { 183 struct tel_dict_entry *e = &d->data.dict[d->data_len]; 184 if (d->type != TEL_DICT) 185 return -EINVAL; 186 if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES) 187 return -ENOSPC; 188 189 if (!valid_name(name)) 190 return -EINVAL; 191 192 d->data_len++; 193 e->type = RTE_TEL_INT_VAL; 194 e->value.ival = val; 195 const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN); 196 return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG; 197 } 198 199 int 200 rte_tel_data_add_dict_uint(struct rte_tel_data *d, 201 const char *name, uint64_t val) 202 { 203 struct tel_dict_entry *e = &d->data.dict[d->data_len]; 204 if (d->type != TEL_DICT) 205 return -EINVAL; 206 if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES) 207 return -ENOSPC; 208 209 if (!valid_name(name)) 210 return -EINVAL; 211 212 d->data_len++; 213 e->type = RTE_TEL_UINT_VAL; 214 e->value.uval = val; 215 const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN); 216 return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG; 217 } 218 219 int 220 rte_tel_data_add_dict_u64(struct rte_tel_data *d, const char *name, uint64_t val) 221 { 222 return rte_tel_data_add_dict_uint(d, name, val); 223 } 224 225 int 226 rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name, 227 struct rte_tel_data *val, int keep) 228 { 229 struct tel_dict_entry *e = &d->data.dict[d->data_len]; 230 231 if (d->type != TEL_DICT || (val->type != TEL_ARRAY_UINT 232 && val->type != TEL_ARRAY_INT 233 && val->type != TEL_ARRAY_STRING 234 && val->type != TEL_DICT)) 235 return -EINVAL; 236 if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES) 237 return -ENOSPC; 238 239 if (!valid_name(name)) 240 return -EINVAL; 241 242 d->data_len++; 243 e->type = RTE_TEL_CONTAINER; 244 e->value.container.data = val; 245 e->value.container.keep = !!keep; 246 const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN); 247 return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG; 248 } 249 250 int 251 rte_tel_data_add_dict_uint_hex(struct rte_tel_data *d, const char *name, 252 uint64_t val, uint8_t display_bitwidth) 253 { 254 char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN]; 255 int ret; 256 257 ret = rte_tel_uint_to_hex_encoded_str(hex_str, 258 RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth); 259 if (ret != 0) 260 return ret; 261 262 263 return rte_tel_data_add_dict_string(d, name, hex_str); 264 } 265 266 struct rte_tel_data * 267 rte_tel_data_alloc(void) 268 { 269 return malloc(sizeof(struct rte_tel_data)); 270 } 271 272 void 273 rte_tel_data_free(struct rte_tel_data *data) 274 { 275 free(data); 276 } 277