get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/47514/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 47514,
    "url": "https://patches.dpdk.org/api/patches/47514/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20181027091750.17254-6-harry.van.haaren@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20181027091750.17254-6-harry.van.haaren@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20181027091750.17254-6-harry.van.haaren@intel.com",
    "date": "2018-10-27T09:17:43",
    "name": "[v10,05/12] telemetry: add client feature and sockets",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "0092a2990d8352a7a851012b95d9031ba73fc548",
    "submitter": {
        "id": 317,
        "url": "https://patches.dpdk.org/api/people/317/?format=api",
        "name": "Van Haaren, Harry",
        "email": "harry.van.haaren@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20181027091750.17254-6-harry.van.haaren@intel.com/mbox/",
    "series": [
        {
            "id": 2132,
            "url": "https://patches.dpdk.org/api/series/2132/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=2132",
            "date": "2018-10-27T09:17:38",
            "name": "Introduce Telemetry Library",
            "version": 10,
            "mbox": "https://patches.dpdk.org/series/2132/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/47514/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/47514/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id D5FFD56A3;\n\tSat, 27 Oct 2018 11:19:50 +0200 (CEST)",
            "from mga18.intel.com (mga18.intel.com [134.134.136.126])\n\tby dpdk.org (Postfix) with ESMTP id 1037A4C8C\n\tfor <dev@dpdk.org>; Sat, 27 Oct 2018 11:19:35 +0200 (CEST)",
            "from orsmga008.jf.intel.com ([10.7.209.65])\n\tby orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t27 Oct 2018 02:19:35 -0700",
            "from silpixa00399779.ir.intel.com (HELO\n\tsilpixa00399779.ger.corp.intel.com) ([10.237.223.188])\n\tby orsmga008.jf.intel.com with ESMTP; 27 Oct 2018 02:19:33 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.54,431,1534834800\"; d=\"scan'208\";a=\"84903885\"",
        "From": "Harry van Haaren <harry.van.haaren@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "thomas@monjalon.net, bruce.richardson@intel.com,\n\tstephen@networkplumber.org, gaetan.rivet@6wind.com,\n\tshreyansh.jain@nxp.com, \n\tmattias.ronnblom@ericsson.com, Ciara Power <ciara.power@intel.com>,\n\tBrian Archbold <brian.archbold@intel.com>,\n\tKevin Laatz <kevin.laatz@intel.com>",
        "Date": "Sat, 27 Oct 2018 10:17:43 +0100",
        "Message-Id": "<20181027091750.17254-6-harry.van.haaren@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20181027091750.17254-1-harry.van.haaren@intel.com>",
        "References": "<20181026235933.79779-1-harry.van.haaren@intel.com>\n\t<20181027091750.17254-1-harry.van.haaren@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v10 05/12] telemetry: add client feature and\n\tsockets",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Ciara Power <ciara.power@intel.com>\n\nThis patch introduces clients to the telemetry API.\n\nWhen a client makes a connection through the initial telemetry\nsocket, they can send a message through the socket to be\nparsed. Register messages are expected through this socket, to\nenable clients to register and have a client socket setup for\nfuture communications.\n\nA TAILQ is used to store all clients information. Using this, the\nclient sockets are polled for messages, which will later be parsed\nand dealt with accordingly.\n\nFunctionality that make use of the client sockets were introduced\nin this patch also, such as writing to client sockets, and sending\nerror responses.\n\nSigned-off-by: Ciara Power <ciara.power@intel.com>\nSigned-off-by: Brian Archbold <brian.archbold@intel.com>\nSigned-off-by: Kevin Laatz <kevin.laatz@intel.com>\nAcked-by: Harry van Haaren <harry.van.haaren@intel.com>\n\n---\n\nv10:\n - remove error prone pkg-config detection (Thomas)\n - Re-add -ljansson to mk/rte.app.mk, was in patch 1 (Thomas)\n---\n lib/librte_telemetry/Makefile                 |   1 +\n lib/librte_telemetry/meson.build              |   7 +\n lib/librte_telemetry/rte_telemetry.c          | 370 +++++++++++++++++-\n lib/librte_telemetry/rte_telemetry_internal.h |  25 ++\n mk/rte.app.mk                                 |   2 +-\n 5 files changed, 401 insertions(+), 4 deletions(-)",
    "diff": "diff --git a/lib/librte_telemetry/Makefile b/lib/librte_telemetry/Makefile\nindex a2d4ff166..0d61361f4 100644\n--- a/lib/librte_telemetry/Makefile\n+++ b/lib/librte_telemetry/Makefile\n@@ -13,6 +13,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API\n LDLIBS += -lrte_eal -lrte_ethdev\n LDLIBS += -lrte_metrics\n LDLIBS += -lpthread\n+LDLIBS += -ljansson\n \n EXPORT_MAP := rte_telemetry_version.map\n \ndiff --git a/lib/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build\nindex 7716076a9..7b939805e 100644\n--- a/lib/librte_telemetry/meson.build\n+++ b/lib/librte_telemetry/meson.build\n@@ -5,3 +5,10 @@ sources = files('rte_telemetry.c')\n headers = files('rte_telemetry.h', 'rte_telemetry_internal.h')\n deps += ['metrics', 'ethdev']\n cflags += '-DALLOW_EXPERIMENTAL_API'\n+\n+jansson = cc.find_library('jansson', required: false)\n+if jansson.found()\n+\text_deps += jansson\n+else\n+\tbuild = false\n+endif\ndiff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c\nindex e9b3330ca..3c8b922f5 100644\n--- a/lib/librte_telemetry/rte_telemetry.c\n+++ b/lib/librte_telemetry/rte_telemetry.c\n@@ -7,6 +7,7 @@\n #include <pthread.h>\n #include <sys/socket.h>\n #include <sys/un.h>\n+#include <jansson.h>\n \n #include <rte_eal.h>\n #include <rte_ethdev.h>\n@@ -18,6 +19,7 @@\n #include \"rte_telemetry_internal.h\"\n \n #define BUF_SIZE 1024\n+#define ACTION_POST 1\n #define SLEEP_TIME 10\n \n static telemetry_impl *static_telemetry;\n@@ -39,6 +41,91 @@ rte_telemetry_is_port_active(int port_id)\n \n \tTELEMETRY_LOG_ERR(\"port_id: %d is invalid, not active\",\n \t\tport_id);\n+\n+\treturn 0;\n+}\n+\n+int32_t\n+rte_telemetry_write_to_socket(struct telemetry_impl *telemetry,\n+\tconst char *json_string)\n+{\n+\tint ret;\n+\n+\tif (telemetry == NULL) {\n+\t\tTELEMETRY_LOG_ERR(\"Could not initialise TELEMETRY_API\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (telemetry->request_client == NULL) {\n+\t\tTELEMETRY_LOG_ERR(\"No client has been chosen to write to\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (json_string == NULL) {\n+\t\tTELEMETRY_LOG_ERR(\"Invalid JSON string!\");\n+\t\treturn -1;\n+\t}\n+\n+\tret = send(telemetry->request_client->fd,\n+\t\t\tjson_string, strlen(json_string), 0);\n+\tif (ret < 0) {\n+\t\tTELEMETRY_LOG_ERR(\"Failed to write to socket for client: %s\",\n+\t\t\t\ttelemetry->request_client->file_path);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int32_t\n+rte_telemetry_send_error_response(struct telemetry_impl *telemetry,\n+\tint error_type)\n+{\n+\tint ret;\n+\tconst char *status_code, *json_buffer;\n+\tjson_t *root;\n+\n+\tif (error_type == -EPERM)\n+\t\tstatus_code = \"Status Error: Unknown\";\n+\telse if (error_type == -EINVAL)\n+\t\tstatus_code = \"Status Error: Invalid Argument 404\";\n+\telse if (error_type == -ENOMEM)\n+\t\tstatus_code = \"Status Error: Memory Allocation Error\";\n+\telse {\n+\t\tTELEMETRY_LOG_ERR(\"Invalid error type\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\troot = json_object();\n+\n+\tif (root == NULL) {\n+\t\tTELEMETRY_LOG_ERR(\"Could not create root JSON object\");\n+\t\treturn -EPERM;\n+\t}\n+\n+\tret = json_object_set_new(root, \"status_code\", json_string(status_code));\n+\tif (ret < 0) {\n+\t\tTELEMETRY_LOG_ERR(\"Status code field cannot be set\");\n+\t\tjson_decref(root);\n+\t\treturn -EPERM;\n+\t}\n+\n+\tret = json_object_set_new(root, \"data\", json_null());\n+\tif (ret < 0) {\n+\t\tTELEMETRY_LOG_ERR(\"Data field cannot be set\");\n+\t\tjson_decref(root);\n+\t\treturn -EPERM;\n+\t}\n+\n+\tjson_buffer = json_dumps(root, JSON_INDENT(2));\n+\tjson_decref(root);\n+\n+\tret = rte_telemetry_write_to_socket(telemetry, json_buffer);\n+\tif (ret < 0) {\n+\t\tTELEMETRY_LOG_ERR(\"Could not write to socket\");\n+\t\treturn -EPERM;\n+\t}\n+\n \treturn 0;\n }\n \n@@ -115,8 +202,7 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry)\n \tuint16_t pid;\n \n \tRTE_ETH_FOREACH_DEV(pid) {\n-\t\ttelemetry->reg_index =\n-\t\t\trte_telemetry_reg_ethdev_to_metrics(pid);\n+\t\ttelemetry->reg_index = rte_telemetry_reg_ethdev_to_metrics(pid);\n \t\tbreak;\n \t}\n \n@@ -130,6 +216,38 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry)\n \treturn 0;\n }\n \n+static int32_t\n+rte_telemetry_read_client(struct telemetry_impl *telemetry)\n+{\n+\tchar buf[BUF_SIZE];\n+\tint ret, buffer_read;\n+\n+\tbuffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);\n+\n+\tif (buffer_read == -1) {\n+\t\tTELEMETRY_LOG_ERR(\"Read error\");\n+\t\treturn -1;\n+\t} else if (buffer_read == 0) {\n+\t\tgoto close_socket;\n+\t} else {\n+\t\tbuf[buffer_read] = '\\0';\n+\t\tret = rte_telemetry_parse_client_message(telemetry, buf);\n+\t\tif (ret < 0)\n+\t\t\tTELEMETRY_LOG_WARN(\"Parse message failed\");\n+\t\tgoto close_socket;\n+\t}\n+\n+close_socket:\n+\tif (close(telemetry->accept_fd) < 0) {\n+\t\tTELEMETRY_LOG_ERR(\"Close TELEMETRY socket failed\");\n+\t\tfree(telemetry);\n+\t\treturn -EPERM;\n+\t}\n+\ttelemetry->accept_fd = 0;\n+\n+\treturn 0;\n+}\n+\n static int32_t\n rte_telemetry_accept_new_client(struct telemetry_impl *telemetry)\n {\n@@ -141,8 +259,8 @@ rte_telemetry_accept_new_client(struct telemetry_impl *telemetry)\n \t\t\tTELEMETRY_LOG_ERR(\"Listening error with server fd\");\n \t\t\treturn -1;\n \t\t}\n-\t\ttelemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL);\n \n+\t\ttelemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL);\n \t\tif (telemetry->accept_fd >= 0 &&\n \t\t\ttelemetry->metrics_register_done == 0) {\n \t\t\tret = rte_telemetry_initial_accept(telemetry);\n@@ -151,6 +269,31 @@ rte_telemetry_accept_new_client(struct telemetry_impl *telemetry)\n \t\t\t\treturn -1;\n \t\t\t}\n \t\t}\n+\t} else {\n+\t\tret = rte_telemetry_read_client(telemetry);\n+\t\tif (ret < 0) {\n+\t\t\tTELEMETRY_LOG_ERR(\"Failed to read socket buffer\");\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int32_t\n+rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)\n+{\n+\ttelemetry_client *client;\n+\tchar client_buf[BUF_SIZE];\n+\tint bytes;\n+\n+\tTAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {\n+\t\tbytes = read(client->fd, client_buf, BUF_SIZE-1);\n+\n+\t\tif (bytes > 0) {\n+\t\t\tclient_buf[bytes] = '\\0';\n+\t\t\ttelemetry->request_client = client;\n+\t\t}\n \t}\n \n \treturn 0;\n@@ -173,6 +316,12 @@ rte_telemetry_run(void *userdata)\n \t\treturn -1;\n \t}\n \n+\tret = rte_telemetry_read_client_sockets(telemetry);\n+\tif (ret < 0) {\n+\t\tTELEMETRY_LOG_ERR(\"Client socket read failed\");\n+\t\treturn -1;\n+\t}\n+\n \treturn 0;\n }\n \n@@ -291,6 +440,7 @@ rte_telemetry_init()\n \t\t\tTELEMETRY_LOG_ERR(\"TELEMETRY cleanup failed\");\n \t\treturn -EPERM;\n \t}\n+\tTAILQ_INIT(&static_telemetry->client_list_head);\n \n \tret = rte_ctrl_thread_create(&static_telemetry->thread_id,\n \t\ttelemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,\n@@ -307,11 +457,39 @@ rte_telemetry_init()\n \treturn 0;\n }\n \n+static int32_t\n+rte_telemetry_client_cleanup(struct telemetry_client *client)\n+{\n+\tint ret;\n+\n+\tret = close(client->fd);\n+\tfree(client->file_path);\n+\tfree(client);\n+\n+\tif (ret < 0) {\n+\t\tTELEMETRY_LOG_ERR(\"Close client socket failed\");\n+\t\treturn -EPERM;\n+\t}\n+\n+\treturn 0;\n+}\n+\n int32_t __rte_experimental\n rte_telemetry_cleanup(void)\n {\n \tint ret;\n \tstruct telemetry_impl *telemetry = static_telemetry;\n+\ttelemetry_client *client, *temp_client;\n+\n+\tTAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,\n+\t\ttemp_client) {\n+\t\tTAILQ_REMOVE(&telemetry->client_list_head, client, client_list);\n+\t\tret = rte_telemetry_client_cleanup(client);\n+\t\tif (ret < 0) {\n+\t\t\tTELEMETRY_LOG_ERR(\"Client cleanup failed\");\n+\t\t\treturn -EPERM;\n+\t\t}\n+\t}\n \n \tret = close(telemetry->server_fd);\n \tif (ret < 0) {\n@@ -328,6 +506,192 @@ rte_telemetry_cleanup(void)\n \treturn 0;\n }\n \n+int32_t\n+rte_telemetry_unregister_client(struct telemetry_impl *telemetry,\n+\tconst char *client_path)\n+{\n+\tint ret;\n+\ttelemetry_client *client, *temp_client;\n+\n+\tif (telemetry == NULL) {\n+\t\tTELEMETRY_LOG_WARN(\"TELEMETRY is not initialised\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tif (client_path == NULL) {\n+\t\tTELEMETRY_LOG_ERR(\"Invalid client path\");\n+\t\tgoto einval_fail;\n+\t}\n+\n+\tif (TAILQ_EMPTY(&telemetry->client_list_head)) {\n+\t\tTELEMETRY_LOG_ERR(\"There are no clients currently registered\");\n+\t\treturn -EPERM;\n+\t}\n+\n+\tTAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,\n+\t\t\ttemp_client) {\n+\t\tif (strcmp(client_path, client->file_path) == 0) {\n+\t\t\tTAILQ_REMOVE(&telemetry->client_list_head, client,\n+\t\t\t\tclient_list);\n+\t\t\tret = rte_telemetry_client_cleanup(client);\n+\n+\t\t\tif (ret < 0) {\n+\t\t\t\tTELEMETRY_LOG_ERR(\"Client cleanup failed\");\n+\t\t\t\treturn -EPERM;\n+\t\t\t}\n+\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\tTELEMETRY_LOG_WARN(\"Couldn't find client, possibly not registered yet.\");\n+\treturn -1;\n+\n+einval_fail:\n+\tret = rte_telemetry_send_error_response(telemetry, -EINVAL);\n+\tif (ret < 0)\n+\t\tTELEMETRY_LOG_ERR(\"Could not send error\");\n+\treturn -EINVAL;\n+}\n+\n+int32_t\n+rte_telemetry_register_client(struct telemetry_impl *telemetry,\n+\tconst char *client_path)\n+{\n+\tint ret, fd;\n+\tstruct sockaddr_un addrs;\n+\n+\tif (telemetry == NULL) {\n+\t\tTELEMETRY_LOG_ERR(\"Could not initialize TELEMETRY API\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tif (client_path == NULL) {\n+\t\tTELEMETRY_LOG_ERR(\"Invalid client path\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\ttelemetry_client *client;\n+\tTAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {\n+\t\tif (strcmp(client_path, client->file_path) == 0) {\n+\t\t\tTELEMETRY_LOG_WARN(\"'%s' already registered\",\n+\t\t\t\t\tclient_path);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\tfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);\n+\tif (fd == -1) {\n+\t\tTELEMETRY_LOG_ERR(\"Client socket error\");\n+\t\treturn -EACCES;\n+\t}\n+\n+\tret = rte_telemetry_set_socket_nonblock(fd);\n+\tif (ret < 0) {\n+\t\tTELEMETRY_LOG_ERR(\"Could not set socket to NONBLOCK\");\n+\t\treturn -EPERM;\n+\t}\n+\n+\taddrs.sun_family = AF_UNIX;\n+\tstrlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path));\n+\ttelemetry_client *new_client = malloc(sizeof(telemetry_client));\n+\tnew_client->file_path = strdup(client_path);\n+\tnew_client->fd = fd;\n+\n+\tif (connect(fd, (struct sockaddr *)&addrs, sizeof(addrs)) == -1) {\n+\t\tTELEMETRY_LOG_ERR(\"TELEMETRY client connect to %s didn't work\",\n+\t\t\t\tclient_path);\n+\t\tret = rte_telemetry_client_cleanup(new_client);\n+\t\tif (ret < 0) {\n+\t\t\tTELEMETRY_LOG_ERR(\"Client cleanup failed\");\n+\t\t\treturn -EPERM;\n+\t\t}\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tTAILQ_INSERT_HEAD(&telemetry->client_list_head, new_client, client_list);\n+\n+\treturn 0;\n+}\n+\n+int32_t\n+rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf)\n+{\n+\tint ret, action_int;\n+\tjson_error_t error;\n+\tjson_t *root = json_loads(buf, 0, &error);\n+\n+\tif (root == NULL) {\n+\t\tTELEMETRY_LOG_WARN(\"Could not load JSON object from data passed in : %s\",\n+\t\t\t\terror.text);\n+\t\tgoto fail;\n+\t} else if (!json_is_object(root)) {\n+\t\tTELEMETRY_LOG_WARN(\"JSON Request is not a JSON object\");\n+\t\tgoto fail;\n+\t}\n+\n+\tjson_t *action = json_object_get(root, \"action\");\n+\tif (action == NULL) {\n+\t\tTELEMETRY_LOG_WARN(\"Request does not have action field\");\n+\t\tgoto fail;\n+\t} else if (!json_is_integer(action)) {\n+\t\tTELEMETRY_LOG_WARN(\"Action value is not an integer\");\n+\t\tgoto fail;\n+\t}\n+\n+\tjson_t *command = json_object_get(root, \"command\");\n+\tif (command == NULL) {\n+\t\tTELEMETRY_LOG_WARN(\"Request does not have command field\");\n+\t\tgoto fail;\n+\t} else if (!json_is_string(command)) {\n+\t\tTELEMETRY_LOG_WARN(\"Command value is not a string\");\n+\t\tgoto fail;\n+\t}\n+\n+\taction_int = json_integer_value(action);\n+\tif (action_int != ACTION_POST) {\n+\t\tTELEMETRY_LOG_WARN(\"Invalid action code\");\n+\t\tgoto fail;\n+\t}\n+\n+\tif (strcmp(json_string_value(command), \"clients\") != 0) {\n+\t\tTELEMETRY_LOG_WARN(\"Invalid command\");\n+\t\tgoto fail;\n+\t}\n+\n+\tjson_t *data = json_object_get(root, \"data\");\n+\tif (data == NULL) {\n+\t\tTELEMETRY_LOG_WARN(\"Request does not have data field\");\n+\t\tgoto fail;\n+\t}\n+\n+\tjson_t *client_path = json_object_get(data, \"client_path\");\n+\tif (client_path == NULL) {\n+\t\tTELEMETRY_LOG_WARN(\"Request does not have client_path field\");\n+\t\tgoto fail;\n+\t}\n+\n+\tif (!json_is_string(client_path)) {\n+\t\tTELEMETRY_LOG_WARN(\"Client_path value is not a string\");\n+\t\tgoto fail;\n+\t}\n+\n+\tret = rte_telemetry_register_client(telemetry,\n+\t\t\tjson_string_value(client_path));\n+\tif (ret < 0) {\n+\t\tTELEMETRY_LOG_ERR(\"Could not register client\");\n+\t\ttelemetry->register_fail_count++;\n+\t\tgoto fail;\n+\t}\n+\n+\treturn 0;\n+\n+fail:\n+\tTELEMETRY_LOG_WARN(\"Client attempted to register with invalid message\");\n+\tjson_decref(root);\n+\treturn -1;\n+}\n+\n int telemetry_log_level;\n RTE_INIT(rte_telemetry_register);\n \ndiff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h\nindex 569d56ab8..e3292cf40 100644\n--- a/lib/librte_telemetry/rte_telemetry_internal.h\n+++ b/lib/librte_telemetry/rte_telemetry_internal.h\n@@ -3,6 +3,7 @@\n  */\n \n #include <rte_log.h>\n+#include <rte_tailq.h>\n \n #ifndef _RTE_TELEMETRY_INTERNAL_H_\n #define _RTE_TELEMETRY_INTERNAL_H_\n@@ -23,6 +24,12 @@ extern int telemetry_log_level;\n #define TELEMETRY_LOG_INFO(fmt, args...) \\\n \tTELEMETRY_LOG(INFO, fmt, ## args)\n \n+typedef struct telemetry_client {\n+\tchar *file_path;\n+\tint fd;\n+\tTAILQ_ENTRY(telemetry_client) client_list;\n+} telemetry_client;\n+\n typedef struct telemetry_impl {\n \tint accept_fd;\n \tint server_fd;\n@@ -31,6 +38,24 @@ typedef struct telemetry_impl {\n \tuint32_t socket_id;\n \tint reg_index;\n \tint metrics_register_done;\n+\tTAILQ_HEAD(, telemetry_client) client_list_head;\n+\tstruct telemetry_client *request_client;\n+\tint register_fail_count;\n } telemetry_impl;\n \n+int32_t\n+rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf);\n+\n+int32_t\n+rte_telemetry_send_error_response(struct telemetry_impl *telemetry,\n+\tint error_type);\n+\n+int32_t\n+rte_telemetry_register_client(struct telemetry_impl *telemetry,\n+\tconst char *client_path);\n+\n+int32_t\n+rte_telemetry_unregister_client(struct telemetry_impl *telemetry,\n+\tconst char *client_path);\n+\n #endif\ndiff --git a/mk/rte.app.mk b/mk/rte.app.mk\nindex a14e83c71..c5aaa9da5 100644\n--- a/mk/rte.app.mk\n+++ b/mk/rte.app.mk\n@@ -80,7 +80,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV)    += -lrte_compressdev\n _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev\n _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV)         += -lrte_rawdev\n _LDLIBS-$(CONFIG_RTE_LIBRTE_METRICS)        += -lrte_metrics\n-_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY)      += -lrte_telemetry\n+_LDLIBS-$(CONFIG_RTE_LIBRTE_TELEMETRY)      += -lrte_telemetry -ljansson\n _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer\n _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool\n _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring\n",
    "prefixes": [
        "v10",
        "05/12"
    ]
}