@@ -5,3 +5,5 @@ sources = files('rte_telemetry.c')
headers = files('rte_telemetry.h', 'rte_telemetry_internal.h')
deps += ['metrics', 'ethdev']
cflags += '-DALLOW_EXPERIMENTAL_API'
+jansson = cc.find_library('jansson', required: true)
+ext_deps += jansson
@@ -6,6 +6,7 @@
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <jansson.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
@@ -15,6 +16,8 @@
#include "rte_telemetry.h"
#include "rte_telemetry_internal.h"
+#define BUF_SIZE 1024
+#define ACTION_POST 1
#define SLEEP_TIME 10
#define DEFAULT_DPDK_PATH "/var/run/.rte_telemetry"
@@ -36,6 +39,88 @@ rte_telemetry_check_port_activity(int port_id)
return 0;
}
+int32_t
+rte_telemetry_write_to_socket(struct telemetry_impl *telemetry,
+ const char *json_string)
+{
+ int ret;
+
+ if (!telemetry) {
+ TELEMETRY_LOG_ERR("Error, could not initialise "
+ "TELEMETRY_API\n");
+ return -1;
+ }
+ if (!telemetry->request_client) {
+ TELEMETRY_LOG_ERR("Error - No client has been chosen to"
+ " write to\n");
+ return -1;
+ }
+ if (!json_string) {
+ TELEMETRY_LOG_ERR("Error - Invalid JSON string!\n");
+ return -1;
+ }
+ ret = send(telemetry->request_client->fd,
+ json_string, strlen(json_string), 0);
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - Failed to write to socket for "
+ "client: %s\n", telemetry->request_client->file_path);
+ return -1;
+ }
+ return 0;
+}
+
+int32_t
+rte_telemetry_send_error_response(struct telemetry_impl *telemetry,
+ int error_type)
+{
+ int ret;
+ const char *status_code, *json_buffer;
+ json_t *root;
+
+ if (error_type == -EPERM)
+ status_code = "Status Error: Unknown";
+ else if (error_type == -EINVAL)
+ status_code = "Status Error: Invalid Argument 404";
+ else if (error_type == -ENOMEM)
+ status_code = "Status Error: Memory Allocation Error";
+ else {
+ TELEMETRY_LOG_ERR("Error - invalid error type\n");
+ return -EINVAL;
+ }
+
+ root = json_object();
+
+ if (!root) {
+ TELEMETRY_LOG_ERR("Error - Could not create root JSON "
+ "object\n");
+ return -EPERM;
+ }
+
+ ret = json_object_set_new(root, "status_code",
+ json_string(status_code));
+
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - Status code field cannot be set\n");
+ return -EPERM;
+ }
+
+ ret = json_object_set_new(root, "data", json_null());
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - Data field cannot be set\n");
+ return -EPERM;
+ }
+
+ json_buffer = json_dumps(root, JSON_INDENT(2));
+ json_decref(root);
+
+ ret = rte_telemetry_write_to_socket(telemetry, json_buffer);
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - Could not write to socket\n");
+ return -EPERM;
+ }
+ return 0;
+}
+
static int32_t
rte_telemetry_reg_ethdev_to_metrics(uint16_t port_id)
{
@@ -127,6 +212,31 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry)
}
static int32_t
+rte_telemetry_read_client(struct telemetry_impl *telemetry)
+{
+ char buf[BUF_SIZE];
+ int buffer_read = 0;
+ errno = 0;
+
+ buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
+ buf[buffer_read] = '\0';
+ if (buffer_read == -1) {
+ TELEMETRY_LOG_ERR("Error - Read error\n");
+ return -1;
+ } else if (buffer_read == 0) {
+ close(telemetry->accept_fd);
+ telemetry->accept_fd = 0;
+ } else {
+ int ret = rte_telemetry_parse_client_message(telemetry, buf);
+ if (ret < 0)
+ TELEMETRY_LOG_WARN("Warning - parse message failed\n");
+ close(telemetry->accept_fd);
+ telemetry->accept_fd = 0;
+ }
+ return 0;
+}
+
+static int32_t
rte_telemetry_accept_new_client(struct telemetry_impl *telemetry)
{
int ret;
@@ -148,6 +258,28 @@ rte_telemetry_accept_new_client(struct telemetry_impl *telemetry)
return -1;
}
}
+ } else {
+ ret = rte_telemetry_read_client(telemetry);
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - failed to read socket "
+ "buffer\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int32_t
+rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)
+{
+ telemetry_client *client;
+ TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
+ char client_buf[BUF_SIZE];
+ int bytes = read(client->fd, client_buf, BUF_SIZE-1);
+ client_buf[bytes] = '\0';
+ if (bytes > 0) {
+ telemetry->request_client = client;
+ }
}
return 0;
}
@@ -169,6 +301,12 @@ rte_telemetry_run(void *userdata)
"failed\n");
return -1;
}
+
+ ret = rte_telemetry_read_client_sockets(telemetry);
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - client socket read failed\n");
+ return -1;
+ }
return 0;
}
@@ -267,6 +405,7 @@ rte_telemetry_init(uint32_t socket_id)
TELEMETRY_LOG_ERR("Error - TELEMETRY cleanup failed\n");
return -EPERM;
}
+ TAILQ_INIT(&static_telemetry->client_list_head);
pthread_attr_init(&attr);
ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
@@ -282,12 +421,38 @@ rte_telemetry_init(uint32_t socket_id)
return 0;
}
+static int32_t
+rte_telemetry_client_cleanup(struct telemetry_client *client)
+{
+ int ret;
+
+ ret = close(client->fd);
+ free(client->file_path);
+ free(client);
+
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - Close client socket failed\n");
+ return -EPERM;
+ }
+ return 0;
+}
+
int32_t
rte_telemetry_cleanup(void)
{
int ret;
struct telemetry_impl *telemetry = static_telemetry;
+ telemetry_client *client, *temp_client;
+ TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
+ temp_client) {
+ TAILQ_REMOVE(&telemetry->client_list_head, client, client_list);
+ ret = rte_telemetry_client_cleanup(client);
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - Client cleanup failed\n");
+ return -EPERM;
+ }
+ }
ret = close(telemetry->server_fd);
if (ret < 0) {
TELEMETRY_LOG_ERR("Error - Close TELEMETRY socket failed\n");
@@ -301,6 +466,199 @@ rte_telemetry_cleanup(void)
return 0;
}
+int32_t
+rte_telemetry_unregister_client(struct telemetry_impl *telemetry,
+ const char *client_path)
+{
+ int ret;
+
+ if (!telemetry) {
+ TELEMETRY_LOG_WARN("Warning - TELEMETRY is not initialised\n");
+ return -ENODEV;
+ }
+
+ if (!client_path) {
+ TELEMETRY_LOG_ERR("Error - Invalid client path\n");
+ goto einval_fail;
+ }
+
+ if (TAILQ_EMPTY(&telemetry->client_list_head)) {
+ TELEMETRY_LOG_ERR("Error - there are no clients currently "
+ "registered\n");
+ return -EPERM;
+ }
+ telemetry_client *client, *temp_client;
+ TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
+ temp_client) {
+ if (strcmp(client_path, client->file_path) == 0) {
+ TAILQ_REMOVE(&telemetry->client_list_head, client,
+ client_list);
+ ret = rte_telemetry_client_cleanup(client);
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - Client cleanup "
+ "failed\n");
+ return -EPERM;
+ }
+ return 0;
+ }
+ }
+ TELEMETRY_LOG_WARN("Warning - couldn't find client, possibly not "
+ "registered yet.\n");
+ return -1;
+
+einval_fail:
+ ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
+ if (ret < 0)
+ TELEMETRY_LOG_ERR("Error - Could not send error\n");
+ return -EINVAL;
+}
+
+int32_t
+rte_telemetry_register_client(struct telemetry_impl *telemetry,
+ const char *client_path)
+{
+ int ret, fd;
+ if (!telemetry) {
+ TELEMETRY_LOG_ERR("Error - could not initialize "
+ "TELEMETRY API\n");
+ return -ENODEV;
+ }
+
+ if (!client_path) {
+ TELEMETRY_LOG_ERR("Error - Invalid client path\n");
+ return -EINVAL;
+ }
+
+ telemetry_client *client;
+ TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
+ if (strcmp(client_path, client->file_path) == 0) {
+ TELEMETRY_LOG_WARN("Warning - '%s' already "
+ "registered\n", client_path);
+ return -EINVAL;
+ }
+ }
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ TELEMETRY_LOG_ERR("Error - Client socket error\n");
+ return -EACCES;
+ }
+ ret = rte_telemetry_set_socket_nonblock(fd);
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - Could not set socket to NONBLOCK\n");
+ return -EPERM;
+ }
+
+ struct sockaddr_un addrs = {0};
+ addrs.sun_family = AF_UNIX;
+ strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path));
+ telemetry_client *new_client =
+ (telemetry_client *)malloc(sizeof(telemetry_client));
+ new_client->file_path = strdup(client_path);
+ new_client->fd = fd;
+
+ if (connect(fd, (struct sockaddr *)&addrs, sizeof(addrs)) == -1) {
+ TELEMETRY_LOG_ERR("Error - TELEMETRY client connect to %s "
+ "didn't work\n", client_path);
+ ret = rte_telemetry_client_cleanup(new_client);
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - Client cleanup failed\n");
+ return -EPERM;
+ }
+ return -EINVAL;
+ }
+ TAILQ_INSERT_HEAD(&telemetry->client_list_head, new_client,
+ client_list);
+
+ return 0;
+}
+
+int32_t
+rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf)
+{
+ int ret;
+ json_error_t error;
+ json_t *root = json_loads(buf, 0, &error);
+
+ if (!root) {
+ TELEMETRY_LOG_WARN("Warning - Could not load JSON object from "
+ "data passed in : %s\n", error.text);
+ goto fail;
+ } else if (!json_is_object(root)) {
+ TELEMETRY_LOG_WARN("Warning - JSON Request is not a JSON "
+ "object\n");
+ json_decref(root);
+ goto fail;
+ }
+
+ json_t *action = json_object_get(root, "action");
+ if (!action) {
+ TELEMETRY_LOG_WARN("Warning - Request does not have action "
+ "field\n");
+ goto fail;
+ } else if (!json_is_integer(action)) {
+ TELEMETRY_LOG_WARN("Warning - Action value is not an "
+ "integer\n");
+ goto fail;
+ }
+
+ json_t *command = json_object_get(root, "command");
+ if (!command) {
+ TELEMETRY_LOG_WARN("Warning - Request does not have command "
+ "field\n");
+ goto fail;
+ } else if (!json_is_string(command)) {
+ TELEMETRY_LOG_WARN("Warning - Command value is not a string\n");
+ goto fail;
+ }
+
+ int action_int = json_integer_value(action);
+ if (action_int != ACTION_POST) {
+ TELEMETRY_LOG_WARN("Warning - Invalid action code\n");
+ goto fail;
+ }
+
+ const char *command_string = json_string_value(command);
+ if (strcmp(command_string, "clients") != 0) {
+ TELEMETRY_LOG_WARN("Warning - Invalid command\n");
+ goto fail;
+ }
+
+ json_t *data = json_object_get(root, "data");
+ if (!data) {
+ TELEMETRY_LOG_WARN("Warning - Request does not have data "
+ "field\n");
+ goto fail;
+ }
+
+ json_t *client_path = json_object_get(data, "client_path");
+ if (!client_path) {
+ TELEMETRY_LOG_WARN("Warning - Request does not have "
+ "client_path field\n");
+ goto fail;
+ }
+ if (!json_is_string(client_path)) {
+ TELEMETRY_LOG_WARN("Warning - client_path value is not a "
+ "string\n");
+ goto fail;
+ }
+
+ const char *client_path_string = json_string_value(client_path);
+
+ ret = rte_telemetry_register_client(telemetry, client_path_string);
+ if (ret < 0) {
+ TELEMETRY_LOG_ERR("Error - could not register client\n");
+ telemetry->register_fail_count++;
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ TELEMETRY_LOG_WARN("Warning - Client attempted to register with "
+ "invalid message\n");
+ return -1;
+}
+
int telemetry_log_level;
RTE_INIT(rte_telemetry_log_init);
@@ -3,6 +3,7 @@
*/
#include <rte_log.h>
+#include <rte_tailq.h>
#ifndef _RTE_TELEMETRY_INTERNAL_H_
#define _RTE_TELEMETRY_INTERNAL_H_
@@ -23,6 +24,12 @@ extern int telemetry_log_level;
#define TELEMETRY_LOG_INFO(fmt, args...) \
TELEMETRY_LOG(INFO, fmt, ## args)
+typedef struct telemetry_client {
+ char *file_path;
+ int fd;
+ TAILQ_ENTRY(telemetry_client) client_list;
+} telemetry_client;
+
typedef struct telemetry_impl {
int accept_fd;
int server_fd;
@@ -31,6 +38,24 @@ typedef struct telemetry_impl {
uint32_t socket_id;
int reg_index;
int metrics_register_done;
+ TAILQ_HEAD(, telemetry_client) client_list_head;
+ struct telemetry_client *request_client;
+ int register_fail_count;
} telemetry_impl;
+int32_t
+rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf);
+
+int32_t
+rte_telemetry_send_error_response(struct telemetry_impl *telemetry,
+ int error_type);
+
+int32_t
+rte_telemetry_register_client(struct telemetry_impl *telemetry,
+ const char *client_path);
+
+int32_t
+rte_telemetry_unregister_client(struct telemetry_impl *telemetry,
+ const char *client_path);
+
#endif
@@ -80,7 +80,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY) += -lrte_security
_LDLIBS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV) += -lrte_compressdev
_LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += -lrte_eventdev
_LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV) += -lrte_rawdev
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -lrte_metrics -lrte_telemetry
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += -lrte_metrics -lrte_telemetry -ljansson
_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER) += -lrte_timer
_LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += -lrte_mempool
_LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING) += -lrte_mempool_ring