Arrays and Dicts now support uint64_t, int and string array values. Only one level of recursion supported.
Signed-off-by: Ciara Power <ciara.po...@intel.com> --- v2: - Added support for arrays to have container values. - Added support for int and string arrays within dict/array. - Added APIs for internal container memory management. --- lib/librte_telemetry/rte_telemetry.h | 67 +++++++++++++++++++ .../rte_telemetry_version.map | 4 ++ lib/librte_telemetry/telemetry.c | 56 ++++++++++++++++ lib/librte_telemetry/telemetry_data.c | 51 ++++++++++++++ lib/librte_telemetry/telemetry_data.h | 7 ++ lib/librte_telemetry/telemetry_json.h | 33 +++++++++ 6 files changed, 218 insertions(+) diff --git a/lib/librte_telemetry/rte_telemetry.h b/lib/librte_telemetry/rte_telemetry.h index eb7f2c917..89aff3429 100644 --- a/lib/librte_telemetry/rte_telemetry.h +++ b/lib/librte_telemetry/rte_telemetry.h @@ -44,6 +44,7 @@ enum rte_tel_value_type { RTE_TEL_STRING_VAL, /** a string value */ RTE_TEL_INT_VAL, /** a signed 32-bit int value */ RTE_TEL_U64_VAL, /** an unsigned 64-bit int value */ + RTE_TEL_CONTAINER, /** a container struct */ }; /** @@ -134,6 +135,28 @@ __rte_experimental int rte_tel_data_add_array_u64(struct rte_tel_data *d, uint64_t x); +/** + * Add a container to an array. + * The array must have been started by rte_tel_data_start_array() with + * RTE_TEL_CONTAINER as the type parameter. The rte_tel_data type + * must be an array of type u64/int/string. + * + * @param d + * The data structure passed to the callback + * @param val + * The rte_tel_data pointer to be returned in the container. + * @param keep + * Integer value to represent if rte_tel_data memory should be freed + * after use. + * 1 = keep, 0 = free. + * @return + * 0 on success, negative errno on error + */ +__rte_experimental +int +rte_tel_data_add_array_container(struct rte_tel_data *d, + struct rte_tel_data *val, int keep); + /** * Add a string value to a dictionary. * The dict must have been started by rte_tel_data_start_dict(). @@ -188,6 +211,27 @@ int rte_tel_data_add_dict_u64(struct rte_tel_data *d, const char *name, uint64_t val); +/** + * Add a container to a dictionary. + * The dict must have been started by rte_tel_data_start_dict(). + * The rte_tel_data type must be an array of type u64/int/string. + * + * @param d + * The data structure passed to the callback + * @param val + * The rte_tel_data pointer to be returned in the container. + * @param keep + * Integer value to represent if rte_tel_data memory should be freed + * after use. + * 1 = keep, 0 = free. + * @return + * 0 on success, negative errno on error + */ +__rte_experimental +int +rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name, + struct rte_tel_data *val, int keep); + /** * This telemetry callback is used when registering a telemetry command. * It handles getting and formatting information to be returned to telemetry @@ -262,4 +306,27 @@ int rte_telemetry_init(const char *runtime_dir, rte_cpuset_t *cpuset, const char **err_str); +/** + * @internal + * Get a data object with memory allocated. + * + * @return + * Pointer to rte_tel_data. + */ +__rte_experimental +struct rte_tel_data * +rte_tel_data_alloc(void); + +/** + * @internal + * Free a data object that has memory allocated. + * + * @param data + * Pointer to rte_tel_data. + *. + */ +__rte_experimental +void +rte_tel_data_free(struct rte_tel_data *data); + #endif diff --git a/lib/librte_telemetry/rte_telemetry_version.map b/lib/librte_telemetry/rte_telemetry_version.map index 86433c21d..d1dbf8d58 100644 --- a/lib/librte_telemetry/rte_telemetry_version.map +++ b/lib/librte_telemetry/rte_telemetry_version.map @@ -1,12 +1,16 @@ EXPERIMENTAL { global: + rte_tel_data_add_array_container; rte_tel_data_add_array_int; rte_tel_data_add_array_string; rte_tel_data_add_array_u64; + rte_tel_data_add_dict_container; rte_tel_data_add_dict_int; rte_tel_data_add_dict_string; rte_tel_data_add_dict_u64; + rte_tel_data_alloc; + rte_tel_data_free; rte_tel_data_start_array; rte_tel_data_start_dict; rte_tel_data_string; diff --git a/lib/librte_telemetry/telemetry.c b/lib/librte_telemetry/telemetry.c index e7e3d861d..a36f60a6c 100644 --- a/lib/librte_telemetry/telemetry.c +++ b/lib/librte_telemetry/telemetry.c @@ -120,6 +120,35 @@ command_help(const char *cmd __rte_unused, const char *params, return 0; } +static int +recursive_data_json(const struct rte_tel_data *d, char *out_buf, size_t buf_len) +{ + size_t used = 0; + unsigned int i; + + if (d->type != RTE_TEL_ARRAY_U64 && d->type != RTE_TEL_ARRAY_INT + && d->type != RTE_TEL_ARRAY_STRING) + return snprintf(out_buf, buf_len, "null"); + + used = rte_tel_json_empty_array(out_buf, buf_len, 0); + if (d->type == RTE_TEL_ARRAY_U64) + for (i = 0; i < d->data_len; i++) + used = rte_tel_json_add_array_u64(out_buf, + buf_len, used, + d->data.array[i].u64val); + if (d->type == RTE_TEL_ARRAY_INT) + for (i = 0; i < d->data_len; i++) + used = rte_tel_json_add_array_int(out_buf, + buf_len, used, + d->data.array[i].ival); + if (d->type == RTE_TEL_ARRAY_STRING) + for (i = 0; i < d->data_len; i++) + used = rte_tel_json_add_array_string(out_buf, + buf_len, used, + d->data.array[i].sval); + return used; +} + static void output_json(const char *cmd, const struct rte_tel_data *d, int s) { @@ -166,6 +195,20 @@ output_json(const char *cmd, const struct rte_tel_data *d, int s) buf_len, used, v->name, v->value.u64val); break; + case RTE_TEL_CONTAINER: + { + char temp[buf_len]; + const struct container *cont = + &v->value.container; + if (recursive_data_json(cont->data, + temp, buf_len) != 0) + used = rte_tel_json_add_obj_json( + cb_data_buf, + buf_len, used, + v->name, temp); + if (!cont->keep) + rte_tel_data_free(cont->data); + } } } used += prefix_used; @@ -174,6 +217,7 @@ output_json(const char *cmd, const struct rte_tel_data *d, int s) case RTE_TEL_ARRAY_STRING: case RTE_TEL_ARRAY_INT: case RTE_TEL_ARRAY_U64: + case RTE_TEL_ARRAY_CONTAINER: prefix_used = snprintf(out_buf, sizeof(out_buf), "{\"%.*s\":", MAX_CMD_LEN, cmd); cb_data_buf = &out_buf[prefix_used]; @@ -194,6 +238,18 @@ output_json(const char *cmd, const struct rte_tel_data *d, int s) used = rte_tel_json_add_array_u64(cb_data_buf, buf_len, used, d->data.array[i].u64val); + else if (d->type == RTE_TEL_ARRAY_CONTAINER) { + char temp[buf_len]; + const struct container *rec_data = + &d->data.array[i].container; + if (recursive_data_json(rec_data->data, + temp, buf_len) != 0) + used = rte_tel_json_add_array_json( + cb_data_buf, + buf_len, used, temp); + if (!rec_data->keep) + rte_tel_data_free(rec_data->data); + } used += prefix_used; used += strlcat(out_buf + used, "}", sizeof(out_buf) - used); break; diff --git a/lib/librte_telemetry/telemetry_data.c b/lib/librte_telemetry/telemetry_data.c index f424bbd48..77b0fe09a 100644 --- a/lib/librte_telemetry/telemetry_data.c +++ b/lib/librte_telemetry/telemetry_data.c @@ -14,6 +14,7 @@ rte_tel_data_start_array(struct rte_tel_data *d, enum rte_tel_value_type type) RTE_TEL_ARRAY_STRING, /* RTE_TEL_STRING_VAL = 0 */ RTE_TEL_ARRAY_INT, /* RTE_TEL_INT_VAL = 1 */ RTE_TEL_ARRAY_U64, /* RTE_TEL_u64_VAL = 2 */ + RTE_TEL_ARRAY_CONTAINER, /* RTE_TEL_CONTAINER = 3 */ }; d->type = array_types[type]; d->data_len = 0; @@ -74,6 +75,23 @@ rte_tel_data_add_array_u64(struct rte_tel_data *d, uint64_t x) return 0; } +int +rte_tel_data_add_array_container(struct rte_tel_data *d, + struct rte_tel_data *val, int keep) +{ + if (d->type != RTE_TEL_ARRAY_CONTAINER || + (val->type != RTE_TEL_ARRAY_U64 + && val->type != RTE_TEL_ARRAY_INT + && val->type != RTE_TEL_ARRAY_STRING)) + return -EINVAL; + if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES) + return -ENOSPC; + + d->data.array[d->data_len].container.data = val; + d->data.array[d->data_len++].container.keep = !!keep; + return 0; +} + int rte_tel_data_add_dict_string(struct rte_tel_data *d, const char *name, const char *val) @@ -128,3 +146,36 @@ rte_tel_data_add_dict_u64(struct rte_tel_data *d, const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN); return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG; } + +int +rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name, + struct rte_tel_data *val, int keep) +{ + struct tel_dict_entry *e = &d->data.dict[d->data_len]; + + if (d->type != RTE_TEL_DICT || (val->type != RTE_TEL_ARRAY_U64 + && val->type != RTE_TEL_ARRAY_INT + && val->type != RTE_TEL_ARRAY_STRING)) + return -EINVAL; + if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES) + return -ENOSPC; + + d->data_len++; + e->type = RTE_TEL_CONTAINER; + e->value.container.data = val; + e->value.container.keep = !!keep; + const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN); + return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG; +} + +struct rte_tel_data * +rte_tel_data_alloc(void) +{ + return malloc(sizeof(struct rte_tel_data)); +} + +void +rte_tel_data_free(struct rte_tel_data *data) +{ + free(data); +} diff --git a/lib/librte_telemetry/telemetry_data.h b/lib/librte_telemetry/telemetry_data.h index ff3a371a3..adb84a09f 100644 --- a/lib/librte_telemetry/telemetry_data.h +++ b/lib/librte_telemetry/telemetry_data.h @@ -15,6 +15,12 @@ enum tel_container_types { RTE_TEL_ARRAY_STRING, /** array of string values only */ RTE_TEL_ARRAY_INT, /** array of signed, 32-bit int values */ RTE_TEL_ARRAY_U64, /** array of unsigned 64-bit int values */ + RTE_TEL_ARRAY_CONTAINER, /** array of container structs */ +}; + +struct container { + struct rte_tel_data *data; + int keep; }; /* each type here must have an equivalent enum in the value types enum in @@ -25,6 +31,7 @@ union tel_value { char sval[RTE_TEL_MAX_STRING_LEN]; int ival; uint64_t u64val; + struct container container; }; struct tel_dict_entry { diff --git a/lib/librte_telemetry/telemetry_json.h b/lib/librte_telemetry/telemetry_json.h index a2ce4899e..ad270b9b3 100644 --- a/lib/librte_telemetry/telemetry_json.h +++ b/lib/librte_telemetry/telemetry_json.h @@ -102,6 +102,22 @@ rte_tel_json_add_array_u64(char *buf, const int len, const int used, return ret == 0 ? used : end + ret; } +/* + * Add a new element with raw JSON value to the JSON array stored in the + * provided buffer. + */ +static inline int +rte_tel_json_add_array_json(char *buf, const int len, const int used, + const char *str) +{ + int ret, end = used - 1; /* strip off final delimiter */ + if (used <= 2) /* assume empty, since minimum is '[]' */ + return __json_snprintf(buf, len, "[%s]", str); + + ret = __json_snprintf(buf + end, len - end, ",%s]", str); + return ret == 0 ? used : end + ret; +} + /** * Add a new element with uint64_t value to the JSON object stored in the * provided buffer. @@ -155,4 +171,21 @@ rte_tel_json_add_obj_str(char *buf, const int len, const int used, return ret == 0 ? used : end + ret; } +/** + * Add a new element with raw JSON value to the JSON object stored in the + * provided buffer. + */ +static inline int +rte_tel_json_add_obj_json(char *buf, const int len, const int used, + const char *name, const char *val) +{ + int ret, end = used - 1; + if (used <= 2) /* assume empty, since minimum is '{}' */ + return __json_snprintf(buf, len, "{\"%s\":%s}", name, val); + + ret = __json_snprintf(buf + end, len - end, ",\"%s\":%s}", + name, val); + return ret == 0 ? used : end + ret; +} + #endif /*_RTE_TELEMETRY_JSON_H_*/ -- 2.17.1