From: Ciara Power <ciara.po...@intel.com>

This patch adds functionality to create a JSON message in
order to send it to a client socket.

When stats are requested by a client, they are retrieved from
the metrics library and encoded in JSON format.

Signed-off-by: Ciara Power <ciara.po...@intel.com>
Signed-off-by: Brian Archbold <brian.archb...@intel.com>
Signed-off-by: Kevin Laatz <kevin.la...@intel.com>
---
 lib/librte_telemetry/rte_telemetry.c | 310 ++++++++++++++++++++++++++++++++++-
 1 file changed, 308 insertions(+), 2 deletions(-)

diff --git a/lib/librte_telemetry/rte_telemetry.c 
b/lib/librte_telemetry/rte_telemetry.c
index 596c611..5b1d2ef 100644
--- a/lib/librte_telemetry/rte_telemetry.c
+++ b/lib/librte_telemetry/rte_telemetry.c
@@ -186,7 +186,7 @@ rte_telemetry_send_error_response(struct telemetry_impl 
*telemetry,
                return -EPERM;
        }
 
-       json_buffer = json_dumps(root, JSON_INDENT(2));
+       json_buffer = json_dumps(root, 0);
        json_decref(root);
 
        ret = rte_telemetry_write_to_socket(telemetry, json_buffer);
@@ -198,6 +198,304 @@ rte_telemetry_send_error_response(struct telemetry_impl 
*telemetry,
        return 0;
 }
 
+static int
+rte_telemetry_get_metrics(struct telemetry_impl *telemetry, uint32_t port_id,
+       struct rte_metric_value *metrics, struct rte_metric_name *names,
+       int num_metrics)
+{
+       int ret, num_values;
+
+       if (num_metrics < 0) {
+               TELEMETRY_LOG_ERR("Invalid metrics count");
+               goto einval_fail;
+       } else if (num_metrics == 0) {
+               TELEMETRY_LOG_ERR("No metrics to display (none have been 
registered)");
+               goto eperm_fail;
+       }
+
+       if (!metrics) {
+               TELEMETRY_LOG_ERR("Metrics must be initialised.");
+               goto einval_fail;
+       }
+
+       if (!names) {
+               TELEMETRY_LOG_ERR("Names must be initialised.");
+               goto einval_fail;
+       }
+
+       ret = rte_metrics_get_names(names, num_metrics);
+       if (ret < 0 || ret > num_metrics) {
+               TELEMETRY_LOG_ERR("Cannot get metrics names");
+               goto eperm_fail;
+       }
+
+       num_values = rte_metrics_get_values(port_id, NULL, 0);
+       ret = rte_metrics_get_values(port_id, metrics, num_values);
+       if (ret < 0 || ret > num_values) {
+               TELEMETRY_LOG_ERR("Cannot get metrics values");
+               goto eperm_fail;
+       }
+
+       return 0;
+
+eperm_fail:
+       ret = rte_telemetry_send_error_response(telemetry, -EPERM);
+       if (ret < 0)
+               TELEMETRY_LOG_ERR("Could not send error");
+       return -1;
+
+einval_fail:
+       ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
+       if (ret < 0)
+               TELEMETRY_LOG_ERR("Could not send error");
+       return -1;
+
+}
+
+static int32_t
+rte_telemetry_json_format_stat(struct telemetry_impl *telemetry, json_t *stats,
+       const char *metric_name, uint64_t metric_value)
+{
+       int ret;
+       json_t *stat = json_object();
+
+       if (!stat) {
+               TELEMETRY_LOG_ERR("Could not create stat JSON object");
+               goto eperm_fail;
+       }
+
+       ret = json_object_set_new(stat, "name", json_string(metric_name));
+       if (ret < 0) {
+               TELEMETRY_LOG_ERR("Stat Name field cannot be set");
+               goto eperm_fail;
+       }
+
+       ret = json_object_set_new(stat, "value", json_integer(metric_value));
+       if (ret < 0) {
+               TELEMETRY_LOG_ERR("Stat Value field cannot be set");
+               goto eperm_fail;
+       }
+
+       ret = json_array_append_new(stats, stat);
+       if (ret < 0) {
+               TELEMETRY_LOG_ERR("Stat cannot be added to stats json array");
+               goto eperm_fail;
+       }
+
+       return 0;
+
+eperm_fail:
+       ret = rte_telemetry_send_error_response(telemetry, -EPERM);
+       if (ret < 0)
+               TELEMETRY_LOG_ERR("Could not send error");
+       return -1;
+
+}
+
+static int32_t
+rte_telemetry_json_format_port(struct telemetry_impl *telemetry,
+       uint32_t port_id, json_t *ports, uint32_t *metric_ids,
+       uint32_t num_metric_ids)
+{
+       struct rte_metric_value *metrics = 0;
+       struct rte_metric_name *names = 0;
+       int num_metrics, ret, err_ret;
+       json_t *port, *stats;
+       uint32_t i;
+
+       num_metrics = rte_metrics_get_names(NULL, 0);
+       if (num_metrics < 0) {
+               TELEMETRY_LOG_ERR("Cannot get metrics count");
+               goto einval_fail;
+       } else if (num_metrics == 0) {
+               TELEMETRY_LOG_ERR("No metrics to display (none have been 
registered)");
+               goto eperm_fail;
+       }
+
+       metrics = malloc(sizeof(struct rte_metric_value) * num_metrics);
+       names = malloc(sizeof(struct rte_metric_name) * num_metrics);
+       if (!metrics || !names) {
+               TELEMETRY_LOG_ERR("Cannot allocate memory");
+               free(metrics);
+               free(names);
+
+               err_ret = rte_telemetry_send_error_response(telemetry, -ENOMEM);
+               if (err_ret < 0)
+                       TELEMETRY_LOG_ERR("Could not send error");
+               return -1;
+       }
+
+       ret  = rte_telemetry_get_metrics(telemetry, port_id, metrics, names,
+               num_metrics);
+       if (ret < 0) {
+               free(metrics);
+               free(names);
+               TELEMETRY_LOG_ERR("rte_telemetry_get_metrics failed");
+               return -1;
+       }
+
+       port = json_object();
+       stats = json_array();
+       if (!port || !stats) {
+               TELEMETRY_LOG_ERR("Could not create port/stats JSON objects");
+               goto eperm_fail;
+       }
+
+       ret = json_object_set_new(port, "port", json_integer(port_id));
+       if (ret < 0) {
+               TELEMETRY_LOG_ERR("Port field cannot be set");
+               goto eperm_fail;
+       }
+
+       for (i = 0; i < num_metric_ids; i++) {
+               int metric_id = metric_ids[i];
+               int metric_index = -1;
+               int metric_name_key = -1;
+               int32_t j;
+               uint64_t metric_value;
+
+               if (metric_id >= num_metrics) {
+                       TELEMETRY_LOG_ERR("Metric_id: %d is not valid",
+                                       metric_id);
+                       goto einval_fail;
+               }
+
+               for (j = 0; j < num_metrics; j++) {
+                       if (metrics[j].key == metric_id) {
+                               metric_name_key = metrics[j].key;
+                               metric_index = j;
+                               break;
+                       }
+               }
+
+               const char *metric_name = names[metric_name_key].name;
+               metric_value = metrics[metric_index].value;
+
+               if (metric_name_key < 0 || metric_index < 0) {
+                       TELEMETRY_LOG_ERR("Could not get metric name/index");
+                       goto eperm_fail;
+               }
+
+               ret = rte_telemetry_json_format_stat(telemetry, stats,
+                       metric_name, metric_value);
+               if (ret < 0) {
+                       TELEMETRY_LOG_ERR("Format stat with id: %u failed",
+                                       metric_id);
+                       free(metrics);
+                       free(names);
+                       return -1;
+               }
+       }
+
+       if (json_array_size(stats) == 0)
+               ret = json_object_set_new(port, "stats", json_null());
+       else
+               ret = json_object_set_new(port, "stats", stats);
+
+       if (ret < 0) {
+               TELEMETRY_LOG_ERR("Stats object cannot be set");
+               goto eperm_fail;
+       }
+
+       ret = json_array_append_new(ports, port);
+       if (ret < 0) {
+               TELEMETRY_LOG_ERR("Port object cannot be added to ports array");
+               goto eperm_fail;
+       }
+
+       free(metrics);
+       free(names);
+       return 0;
+
+eperm_fail:
+       free(metrics);
+       free(names);
+       ret = rte_telemetry_send_error_response(telemetry, -EPERM);
+       if (ret < 0)
+               TELEMETRY_LOG_ERR("Could not send error");
+       return -1;
+
+einval_fail:
+       free(metrics);
+       free(names);
+       ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
+       if (ret < 0)
+               TELEMETRY_LOG_ERR("Could not send error");
+       return -1;
+}
+
+static int32_t
+rte_telemetry_encode_json_format(struct telemetry_impl *telemetry,
+       uint32_t *port_ids, uint32_t num_port_ids, uint32_t *metric_ids,
+       uint32_t num_metric_ids, char **json_buffer)
+{
+       int ret;
+       json_t *root, *ports;
+       uint32_t i;
+
+       if (num_port_ids <= 0 || num_metric_ids <= 0) {
+               TELEMETRY_LOG_ERR("Please provide port and metric ids to 
query");
+               goto einval_fail;
+       }
+
+       ports = json_array();
+       if (!ports) {
+               TELEMETRY_LOG_ERR("Could not create ports JSON array");
+               goto eperm_fail;
+       }
+
+       for (i = 0; i < num_port_ids; i++) {
+               if (!rte_eth_dev_is_valid_port(port_ids[i])) {
+                       TELEMETRY_LOG_ERR("Port: %d invalid", port_ids[i]);
+                       goto einval_fail;
+               }
+       }
+
+       for (i = 0; i < num_port_ids; i++) {
+               ret = rte_telemetry_json_format_port(telemetry, port_ids[i],
+                       ports, metric_ids, num_metric_ids);
+               if (ret < 0) {
+                       TELEMETRY_LOG_ERR("Format port in JSON failed");
+                       return -1;
+               }
+       }
+
+       root = json_object();
+       if (!root) {
+               TELEMETRY_LOG_ERR("Could not create root JSON object");
+               goto eperm_fail;
+       }
+
+       ret = json_object_set_new(root, "status_code",
+               json_string("Status OK: 200"));
+       if (ret < 0) {
+               TELEMETRY_LOG_ERR("Status code field cannot be set");
+               goto eperm_fail;
+       }
+
+       ret = json_object_set_new(root, "data", ports);
+       if (ret < 0) {
+               TELEMETRY_LOG_ERR("Data field cannot be set");
+               goto eperm_fail;
+       }
+
+       *json_buffer = json_dumps(root, JSON_INDENT(2));
+       json_decref(root);
+       return 0;
+
+eperm_fail:
+       ret = rte_telemetry_send_error_response(telemetry, -EPERM);
+       if (ret < 0)
+               TELEMETRY_LOG_ERR("Could not send error");
+       return -1;
+
+einval_fail:
+       ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
+       if (ret < 0)
+               TELEMETRY_LOG_ERR("Could not send error");
+       return -1;
+}
+
 int32_t
 rte_telemetry_send_ports_stats_values(uint32_t *metric_ids, int num_metric_ids,
        uint32_t *port_ids, int num_port_ids, struct telemetry_impl *telemetry)
@@ -237,13 +535,20 @@ rte_telemetry_send_ports_stats_values(uint32_t 
*metric_ids, int num_metric_ids,
                }
 
                ret = rte_telemetry_update_metrics_ethdev(telemetry,
-                       port_ids[i], telemetry->reg_index);
+                               port_ids[i], telemetry->reg_index);
                if (ret < 0) {
                        TELEMETRY_LOG_ERR("Failed to update ethdev metrics");
                        return -1;
                }
        }
 
+       ret = rte_telemetry_encode_json_format(telemetry, port_ids,
+               num_port_ids, metric_ids, num_metric_ids, &json_buffer);
+       if (ret < 0) {
+               TELEMETRY_LOG_ERR("JSON encode function failed");
+               return -1;
+       }
+
        ret = rte_telemetry_write_to_socket(telemetry, json_buffer);
        if (ret < 0) {
                TELEMETRY_LOG_ERR("Could not write to socket");
@@ -367,6 +672,7 @@ rte_telemetry_read_client(struct telemetry_impl *telemetry)
                ret = rte_telemetry_parse_client_message(telemetry, buf);
                if (ret < 0)
                        TELEMETRY_LOG_WARN("Parse message failed");
+
                close(telemetry->accept_fd);
                telemetry->accept_fd = 0;
        }
-- 
2.9.5

Reply via email to