telemetry: update metrics before sending stats
[dpdk.git] / lib / librte_telemetry / rte_telemetry.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <pthread.h>
8 #include <sys/socket.h>
9 #include <sys/un.h>
10 #include <jansson.h>
11
12 #include <rte_eal.h>
13 #include <rte_ethdev.h>
14 #include <rte_metrics.h>
15 #include <rte_option.h>
16 #include <rte_string_fns.h>
17
18 #include "rte_telemetry.h"
19 #include "rte_telemetry_internal.h"
20 #include "rte_telemetry_parser.h"
21
22 #define BUF_SIZE 1024
23 #define ACTION_POST 1
24 #define SLEEP_TIME 10
25
26 static telemetry_impl *static_telemetry;
27
28 static void
29 rte_telemetry_get_runtime_dir(char *socket_path, size_t size)
30 {
31         snprintf(socket_path, size, "%s/telemetry", rte_eal_get_runtime_dir());
32 }
33
34 int32_t
35 rte_telemetry_is_port_active(int port_id)
36 {
37         int ret;
38
39         ret = rte_eth_find_next(port_id);
40         if (ret == port_id)
41                 return 1;
42
43         TELEMETRY_LOG_ERR("port_id: %d is invalid, not active",
44                 port_id);
45
46         return 0;
47 }
48
49 static int32_t
50 rte_telemetry_update_metrics_ethdev(struct telemetry_impl *telemetry,
51         uint16_t port_id, int reg_start_index)
52 {
53         int ret, num_xstats, i;
54         struct rte_eth_xstat *eth_xstats;
55
56         if (!rte_eth_dev_is_valid_port(port_id)) {
57                 TELEMETRY_LOG_ERR("port_id: %d is invalid", port_id);
58                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
59                 if (ret < 0)
60                         TELEMETRY_LOG_ERR("Could not send error");
61                 return -1;
62         }
63
64         ret = rte_telemetry_is_port_active(port_id);
65         if (ret < 1) {
66                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
67                 if (ret < 0)
68                         TELEMETRY_LOG_ERR("Could not send error");
69                 return -1;
70         }
71
72         num_xstats = rte_eth_xstats_get(port_id, NULL, 0);
73         if (num_xstats < 0) {
74                 TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) failed: %d", port_id,
75                                 num_xstats);
76                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
77                 if (ret < 0)
78                         TELEMETRY_LOG_ERR("Could not send error");
79                 return -1;
80         }
81
82         eth_xstats = malloc(sizeof(struct rte_eth_xstat) * num_xstats);
83         if (eth_xstats == NULL) {
84                 TELEMETRY_LOG_ERR("Failed to malloc memory for xstats");
85                 ret = rte_telemetry_send_error_response(telemetry, -ENOMEM);
86                 if (ret < 0)
87                         TELEMETRY_LOG_ERR("Could not send error");
88                 return -1;
89         }
90
91         ret = rte_eth_xstats_get(port_id, eth_xstats, num_xstats);
92         if (ret < 0 || ret > num_xstats) {
93                 free(eth_xstats);
94                 TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) len%i failed: %d",
95                                 port_id, num_xstats, ret);
96                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
97                 if (ret < 0)
98                         TELEMETRY_LOG_ERR("Could not send error");
99                 return -1;
100         }
101
102         uint64_t xstats_values[num_xstats];
103         for (i = 0; i < num_xstats; i++)
104                 xstats_values[i] = eth_xstats[i].value;
105
106         ret = rte_metrics_update_values(port_id, reg_start_index, xstats_values,
107                         num_xstats);
108         if (ret < 0) {
109                 TELEMETRY_LOG_ERR("Could not update metrics values");
110                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
111                 if (ret < 0)
112                         TELEMETRY_LOG_ERR("Could not send error");
113                 free(eth_xstats);
114                 return -1;
115         }
116
117         free(eth_xstats);
118         return 0;
119 }
120
121 int32_t
122 rte_telemetry_write_to_socket(struct telemetry_impl *telemetry,
123         const char *json_string)
124 {
125         int ret;
126
127         if (telemetry == NULL) {
128                 TELEMETRY_LOG_ERR("Could not initialise TELEMETRY_API");
129                 return -1;
130         }
131
132         if (telemetry->request_client == NULL) {
133                 TELEMETRY_LOG_ERR("No client has been chosen to write to");
134                 return -1;
135         }
136
137         if (json_string == NULL) {
138                 TELEMETRY_LOG_ERR("Invalid JSON string!");
139                 return -1;
140         }
141
142         ret = send(telemetry->request_client->fd,
143                         json_string, strlen(json_string), 0);
144         if (ret < 0) {
145                 TELEMETRY_LOG_ERR("Failed to write to socket for client: %s",
146                                 telemetry->request_client->file_path);
147                 return -1;
148         }
149
150         return 0;
151 }
152
153 int32_t
154 rte_telemetry_send_error_response(struct telemetry_impl *telemetry,
155         int error_type)
156 {
157         int ret;
158         const char *status_code, *json_buffer;
159         json_t *root;
160
161         if (error_type == -EPERM)
162                 status_code = "Status Error: Unknown";
163         else if (error_type == -EINVAL)
164                 status_code = "Status Error: Invalid Argument 404";
165         else if (error_type == -ENOMEM)
166                 status_code = "Status Error: Memory Allocation Error";
167         else {
168                 TELEMETRY_LOG_ERR("Invalid error type");
169                 return -EINVAL;
170         }
171
172         root = json_object();
173
174         if (root == NULL) {
175                 TELEMETRY_LOG_ERR("Could not create root JSON object");
176                 return -EPERM;
177         }
178
179         ret = json_object_set_new(root, "status_code", json_string(status_code));
180         if (ret < 0) {
181                 TELEMETRY_LOG_ERR("Status code field cannot be set");
182                 json_decref(root);
183                 return -EPERM;
184         }
185
186         ret = json_object_set_new(root, "data", json_null());
187         if (ret < 0) {
188                 TELEMETRY_LOG_ERR("Data field cannot be set");
189                 json_decref(root);
190                 return -EPERM;
191         }
192
193         json_buffer = json_dumps(root, JSON_INDENT(2));
194         json_decref(root);
195
196         ret = rte_telemetry_write_to_socket(telemetry, json_buffer);
197         if (ret < 0) {
198                 TELEMETRY_LOG_ERR("Could not write to socket");
199                 return -EPERM;
200         }
201
202         return 0;
203 }
204
205 int32_t
206 rte_telemetry_send_ports_stats_values(uint32_t *metric_ids, int num_metric_ids,
207         uint32_t *port_ids, int num_port_ids, struct telemetry_impl *telemetry)
208 {
209         int ret, i;
210         char *json_buffer = NULL;
211
212         if (telemetry == NULL) {
213                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
214                 return -1;
215         }
216
217         if (metric_ids == NULL) {
218                 TELEMETRY_LOG_ERR("Invalid metric_ids array");
219                 goto einval_fail;
220         }
221
222         if (num_metric_ids < 0) {
223                 TELEMETRY_LOG_ERR("Invalid num_metric_ids, must be positive");
224                 goto einval_fail;
225         }
226
227         if (port_ids == NULL) {
228                 TELEMETRY_LOG_ERR("Invalid port_ids array");
229                 goto einval_fail;
230         }
231
232         if (num_port_ids < 0) {
233                 TELEMETRY_LOG_ERR("Invalid num_port_ids, must be positive");
234                 goto einval_fail;
235         }
236
237         for (i = 0; i < num_port_ids; i++) {
238                 if (!rte_eth_dev_is_valid_port(port_ids[i])) {
239                         TELEMETRY_LOG_ERR("Port: %d invalid", port_ids[i]);
240                         goto einval_fail;
241                 }
242
243                 ret = rte_telemetry_update_metrics_ethdev(telemetry,
244                         port_ids[i], telemetry->reg_index);
245                 if (ret < 0) {
246                         TELEMETRY_LOG_ERR("Failed to update ethdev metrics");
247                         return -1;
248                 }
249         }
250
251         ret = rte_telemetry_write_to_socket(telemetry, json_buffer);
252         if (ret < 0) {
253                 TELEMETRY_LOG_ERR("Could not write to socket");
254                 return -1;
255         }
256
257         return 0;
258
259 einval_fail:
260         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
261         if (ret < 0)
262                 TELEMETRY_LOG_ERR("Could not send error");
263         return -1;
264 }
265
266
267 static int32_t
268 rte_telemetry_reg_ethdev_to_metrics(uint16_t port_id)
269 {
270         int ret, num_xstats, ret_val, i;
271         struct rte_eth_xstat *eth_xstats = NULL;
272         struct rte_eth_xstat_name *eth_xstats_names = NULL;
273
274         if (!rte_eth_dev_is_valid_port(port_id)) {
275                 TELEMETRY_LOG_ERR("port_id: %d is invalid", port_id);
276                 return -EINVAL;
277         }
278
279         num_xstats = rte_eth_xstats_get(port_id, NULL, 0);
280         if (num_xstats < 0) {
281                 TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) failed: %d",
282                                 port_id, num_xstats);
283                 return -EPERM;
284         }
285
286         eth_xstats = malloc(sizeof(struct rte_eth_xstat) * num_xstats);
287         if (eth_xstats == NULL) {
288                 TELEMETRY_LOG_ERR("Failed to malloc memory for xstats");
289                 return -ENOMEM;
290         }
291
292         ret = rte_eth_xstats_get(port_id, eth_xstats, num_xstats);
293         const char *xstats_names[num_xstats];
294         eth_xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * num_xstats);
295         if (ret < 0 || ret > num_xstats) {
296                 TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) len%i failed: %d",
297                                 port_id, num_xstats, ret);
298                 ret_val = -EPERM;
299                 goto free_xstats;
300         }
301
302         if (eth_xstats_names == NULL) {
303                 TELEMETRY_LOG_ERR("Failed to malloc memory for xstats_names");
304                 ret_val = -ENOMEM;
305                 goto free_xstats;
306         }
307
308         ret = rte_eth_xstats_get_names(port_id, eth_xstats_names, num_xstats);
309         if (ret < 0 || ret > num_xstats) {
310                 TELEMETRY_LOG_ERR("rte_eth_xstats_get_names(%u) len%i failed: %d",
311                                 port_id, num_xstats, ret);
312                 ret_val = -EPERM;
313                 goto free_xstats;
314         }
315
316         for (i = 0; i < num_xstats; i++)
317                 xstats_names[i] = eth_xstats_names[eth_xstats[i].id].name;
318
319         ret_val = rte_metrics_reg_names(xstats_names, num_xstats);
320         if (ret_val < 0) {
321                 TELEMETRY_LOG_ERR("rte_metrics_reg_names failed - metrics may already be registered");
322                 ret_val = -1;
323                 goto free_xstats;
324         }
325
326         goto free_xstats;
327
328 free_xstats:
329         free(eth_xstats);
330         free(eth_xstats_names);
331         return ret_val;
332 }
333
334 static int32_t
335 rte_telemetry_initial_accept(struct telemetry_impl *telemetry)
336 {
337         uint16_t pid;
338
339         RTE_ETH_FOREACH_DEV(pid) {
340                 telemetry->reg_index = rte_telemetry_reg_ethdev_to_metrics(pid);
341                 break;
342         }
343
344         if (telemetry->reg_index < 0) {
345                 TELEMETRY_LOG_ERR("Failed to register ethdev metrics");
346                 return -1;
347         }
348
349         telemetry->metrics_register_done = 1;
350
351         return 0;
352 }
353
354 static int32_t
355 rte_telemetry_read_client(struct telemetry_impl *telemetry)
356 {
357         char buf[BUF_SIZE];
358         int ret, buffer_read;
359
360         buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
361
362         if (buffer_read == -1) {
363                 TELEMETRY_LOG_ERR("Read error");
364                 return -1;
365         } else if (buffer_read == 0) {
366                 goto close_socket;
367         } else {
368                 buf[buffer_read] = '\0';
369                 ret = rte_telemetry_parse_client_message(telemetry, buf);
370                 if (ret < 0)
371                         TELEMETRY_LOG_WARN("Parse message failed");
372                 goto close_socket;
373         }
374
375 close_socket:
376         if (close(telemetry->accept_fd) < 0) {
377                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
378                 free(telemetry);
379                 return -EPERM;
380         }
381         telemetry->accept_fd = 0;
382
383         return 0;
384 }
385
386 static int32_t
387 rte_telemetry_accept_new_client(struct telemetry_impl *telemetry)
388 {
389         int ret;
390
391         if (telemetry->accept_fd <= 0) {
392                 ret = listen(telemetry->server_fd, 1);
393                 if (ret < 0) {
394                         TELEMETRY_LOG_ERR("Listening error with server fd");
395                         return -1;
396                 }
397
398                 telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL);
399                 if (telemetry->accept_fd >= 0 &&
400                         telemetry->metrics_register_done == 0) {
401                         ret = rte_telemetry_initial_accept(telemetry);
402                         if (ret < 0) {
403                                 TELEMETRY_LOG_ERR("Failed to run initial configurations/tests");
404                                 return -1;
405                         }
406                 }
407         } else {
408                 ret = rte_telemetry_read_client(telemetry);
409                 if (ret < 0) {
410                         TELEMETRY_LOG_ERR("Failed to read socket buffer");
411                         return -1;
412                 }
413         }
414
415         return 0;
416 }
417
418 static int32_t
419 rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)
420 {
421         int ret;
422         telemetry_client *client;
423         char client_buf[BUF_SIZE];
424         int bytes;
425
426         TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
427                 bytes = read(client->fd, client_buf, BUF_SIZE-1);
428
429                 if (bytes > 0) {
430                         client_buf[bytes] = '\0';
431                         telemetry->request_client = client;
432                         ret = rte_telemetry_parse(telemetry, client_buf);
433                         if (ret < 0) {
434                                 TELEMETRY_LOG_WARN("Parse socket input failed: %i",
435                                                 ret);
436                                 return -1;
437                         }
438                 }
439         }
440
441         return 0;
442 }
443
444 static int32_t
445 rte_telemetry_run(void *userdata)
446 {
447         int ret;
448         struct telemetry_impl *telemetry = userdata;
449
450         if (telemetry == NULL) {
451                 TELEMETRY_LOG_WARN("TELEMETRY could not be initialised");
452                 return -1;
453         }
454
455         ret = rte_telemetry_accept_new_client(telemetry);
456         if (ret < 0) {
457                 TELEMETRY_LOG_ERR("Accept and read new client failed");
458                 return -1;
459         }
460
461         ret = rte_telemetry_read_client_sockets(telemetry);
462         if (ret < 0) {
463                 TELEMETRY_LOG_ERR("Client socket read failed");
464                 return -1;
465         }
466
467         return 0;
468 }
469
470 static void
471 *rte_telemetry_run_thread_func(void *userdata)
472 {
473         int ret;
474         struct telemetry_impl *telemetry = userdata;
475
476         if (telemetry == NULL) {
477                 TELEMETRY_LOG_ERR("%s passed a NULL instance", __func__);
478                 pthread_exit(0);
479         }
480
481         while (telemetry->thread_status) {
482                 rte_telemetry_run(telemetry);
483                 ret = usleep(SLEEP_TIME);
484                 if (ret < 0)
485                         TELEMETRY_LOG_ERR("Calling thread could not be put to sleep");
486         }
487         pthread_exit(0);
488 }
489
490 static int32_t
491 rte_telemetry_set_socket_nonblock(int fd)
492 {
493         int flags;
494
495         if (fd < 0) {
496                 TELEMETRY_LOG_ERR("Invalid fd provided");
497                 return -1;
498         }
499
500         flags = fcntl(fd, F_GETFL, 0);
501         if (flags < 0)
502                 flags = 0;
503
504         return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
505 }
506
507 static int32_t
508 rte_telemetry_create_socket(struct telemetry_impl *telemetry)
509 {
510         int ret;
511         struct sockaddr_un addr;
512         char socket_path[BUF_SIZE];
513
514         if (telemetry == NULL)
515                 return -1;
516
517         telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
518         if (telemetry->server_fd == -1) {
519                 TELEMETRY_LOG_ERR("Failed to open socket");
520                 return -1;
521         }
522
523         ret  = rte_telemetry_set_socket_nonblock(telemetry->server_fd);
524         if (ret < 0) {
525                 TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK");
526                 goto close_socket;
527         }
528
529         addr.sun_family = AF_UNIX;
530         rte_telemetry_get_runtime_dir(socket_path, sizeof(socket_path));
531         strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
532         unlink(socket_path);
533
534         if (bind(telemetry->server_fd, (struct sockaddr *)&addr,
535                 sizeof(addr)) < 0) {
536                 TELEMETRY_LOG_ERR("Socket binding error");
537                 goto close_socket;
538         }
539
540         return 0;
541
542 close_socket:
543         if (close(telemetry->server_fd) < 0) {
544                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
545                 return -EPERM;
546         }
547
548         return -1;
549 }
550
551 int32_t __rte_experimental
552 rte_telemetry_init()
553 {
554         int ret;
555         pthread_attr_t attr;
556         const char *telemetry_ctrl_thread = "telemetry";
557
558         if (static_telemetry) {
559                 TELEMETRY_LOG_WARN("TELEMETRY structure already initialised");
560                 return -EALREADY;
561         }
562
563         static_telemetry = calloc(1, sizeof(struct telemetry_impl));
564         if (static_telemetry == NULL) {
565                 TELEMETRY_LOG_ERR("Memory could not be allocated");
566                 return -ENOMEM;
567         }
568
569         static_telemetry->socket_id = rte_socket_id();
570         rte_metrics_init(static_telemetry->socket_id);
571
572         ret = pthread_attr_init(&attr);
573         if (ret != 0) {
574                 TELEMETRY_LOG_ERR("Pthread attribute init failed");
575                 return -EPERM;
576         }
577
578         ret = rte_telemetry_create_socket(static_telemetry);
579         if (ret < 0) {
580                 ret = rte_telemetry_cleanup();
581                 if (ret < 0)
582                         TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
583                 return -EPERM;
584         }
585         TAILQ_INIT(&static_telemetry->client_list_head);
586
587         ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
588                 telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
589                 (void *)static_telemetry);
590         static_telemetry->thread_status = 1;
591
592         if (ret < 0) {
593                 ret = rte_telemetry_cleanup();
594                 if (ret < 0)
595                         TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
596                 return -EPERM;
597         }
598
599         return 0;
600 }
601
602 static int32_t
603 rte_telemetry_client_cleanup(struct telemetry_client *client)
604 {
605         int ret;
606
607         ret = close(client->fd);
608         free(client->file_path);
609         free(client);
610
611         if (ret < 0) {
612                 TELEMETRY_LOG_ERR("Close client socket failed");
613                 return -EPERM;
614         }
615
616         return 0;
617 }
618
619 int32_t __rte_experimental
620 rte_telemetry_cleanup(void)
621 {
622         int ret;
623         struct telemetry_impl *telemetry = static_telemetry;
624         telemetry_client *client, *temp_client;
625
626         TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
627                 temp_client) {
628                 TAILQ_REMOVE(&telemetry->client_list_head, client, client_list);
629                 ret = rte_telemetry_client_cleanup(client);
630                 if (ret < 0) {
631                         TELEMETRY_LOG_ERR("Client cleanup failed");
632                         return -EPERM;
633                 }
634         }
635
636         ret = close(telemetry->server_fd);
637         if (ret < 0) {
638                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
639                 free(telemetry);
640                 return -EPERM;
641         }
642
643         telemetry->thread_status = 0;
644         pthread_join(telemetry->thread_id, NULL);
645         free(telemetry);
646         static_telemetry = NULL;
647
648         return 0;
649 }
650
651 int32_t
652 rte_telemetry_unregister_client(struct telemetry_impl *telemetry,
653         const char *client_path)
654 {
655         int ret;
656         telemetry_client *client, *temp_client;
657
658         if (telemetry == NULL) {
659                 TELEMETRY_LOG_WARN("TELEMETRY is not initialised");
660                 return -ENODEV;
661         }
662
663         if (client_path == NULL) {
664                 TELEMETRY_LOG_ERR("Invalid client path");
665                 goto einval_fail;
666         }
667
668         if (TAILQ_EMPTY(&telemetry->client_list_head)) {
669                 TELEMETRY_LOG_ERR("There are no clients currently registered");
670                 return -EPERM;
671         }
672
673         TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
674                         temp_client) {
675                 if (strcmp(client_path, client->file_path) == 0) {
676                         TAILQ_REMOVE(&telemetry->client_list_head, client,
677                                 client_list);
678                         ret = rte_telemetry_client_cleanup(client);
679
680                         if (ret < 0) {
681                                 TELEMETRY_LOG_ERR("Client cleanup failed");
682                                 return -EPERM;
683                         }
684
685                         return 0;
686                 }
687         }
688
689         TELEMETRY_LOG_WARN("Couldn't find client, possibly not registered yet.");
690         return -1;
691
692 einval_fail:
693         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
694         if (ret < 0)
695                 TELEMETRY_LOG_ERR("Could not send error");
696         return -EINVAL;
697 }
698
699 int32_t
700 rte_telemetry_register_client(struct telemetry_impl *telemetry,
701         const char *client_path)
702 {
703         int ret, fd;
704         struct sockaddr_un addrs;
705
706         if (telemetry == NULL) {
707                 TELEMETRY_LOG_ERR("Could not initialize TELEMETRY API");
708                 return -ENODEV;
709         }
710
711         if (client_path == NULL) {
712                 TELEMETRY_LOG_ERR("Invalid client path");
713                 return -EINVAL;
714         }
715
716         telemetry_client *client;
717         TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
718                 if (strcmp(client_path, client->file_path) == 0) {
719                         TELEMETRY_LOG_WARN("'%s' already registered",
720                                         client_path);
721                         return -EINVAL;
722                 }
723         }
724
725         fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
726         if (fd == -1) {
727                 TELEMETRY_LOG_ERR("Client socket error");
728                 return -EACCES;
729         }
730
731         ret = rte_telemetry_set_socket_nonblock(fd);
732         if (ret < 0) {
733                 TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK");
734                 return -EPERM;
735         }
736
737         addrs.sun_family = AF_UNIX;
738         strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path));
739         telemetry_client *new_client = malloc(sizeof(telemetry_client));
740         new_client->file_path = strdup(client_path);
741         new_client->fd = fd;
742
743         if (connect(fd, (struct sockaddr *)&addrs, sizeof(addrs)) == -1) {
744                 TELEMETRY_LOG_ERR("TELEMETRY client connect to %s didn't work",
745                                 client_path);
746                 ret = rte_telemetry_client_cleanup(new_client);
747                 if (ret < 0) {
748                         TELEMETRY_LOG_ERR("Client cleanup failed");
749                         return -EPERM;
750                 }
751                 return -EINVAL;
752         }
753
754         TAILQ_INSERT_HEAD(&telemetry->client_list_head, new_client, client_list);
755
756         return 0;
757 }
758
759 int32_t
760 rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf)
761 {
762         int ret, action_int;
763         json_error_t error;
764         json_t *root = json_loads(buf, 0, &error);
765
766         if (root == NULL) {
767                 TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s",
768                                 error.text);
769                 goto fail;
770         } else if (!json_is_object(root)) {
771                 TELEMETRY_LOG_WARN("JSON Request is not a JSON object");
772                 goto fail;
773         }
774
775         json_t *action = json_object_get(root, "action");
776         if (action == NULL) {
777                 TELEMETRY_LOG_WARN("Request does not have action field");
778                 goto fail;
779         } else if (!json_is_integer(action)) {
780                 TELEMETRY_LOG_WARN("Action value is not an integer");
781                 goto fail;
782         }
783
784         json_t *command = json_object_get(root, "command");
785         if (command == NULL) {
786                 TELEMETRY_LOG_WARN("Request does not have command field");
787                 goto fail;
788         } else if (!json_is_string(command)) {
789                 TELEMETRY_LOG_WARN("Command value is not a string");
790                 goto fail;
791         }
792
793         action_int = json_integer_value(action);
794         if (action_int != ACTION_POST) {
795                 TELEMETRY_LOG_WARN("Invalid action code");
796                 goto fail;
797         }
798
799         if (strcmp(json_string_value(command), "clients") != 0) {
800                 TELEMETRY_LOG_WARN("Invalid command");
801                 goto fail;
802         }
803
804         json_t *data = json_object_get(root, "data");
805         if (data == NULL) {
806                 TELEMETRY_LOG_WARN("Request does not have data field");
807                 goto fail;
808         }
809
810         json_t *client_path = json_object_get(data, "client_path");
811         if (client_path == NULL) {
812                 TELEMETRY_LOG_WARN("Request does not have client_path field");
813                 goto fail;
814         }
815
816         if (!json_is_string(client_path)) {
817                 TELEMETRY_LOG_WARN("Client_path value is not a string");
818                 goto fail;
819         }
820
821         ret = rte_telemetry_register_client(telemetry,
822                         json_string_value(client_path));
823         if (ret < 0) {
824                 TELEMETRY_LOG_ERR("Could not register client");
825                 telemetry->register_fail_count++;
826                 goto fail;
827         }
828
829         return 0;
830
831 fail:
832         TELEMETRY_LOG_WARN("Client attempted to register with invalid message");
833         json_decref(root);
834         return -1;
835 }
836
837 int telemetry_log_level;
838
839 static struct rte_option option = {
840         .opt_str = "--telemetry",
841         .cb = &rte_telemetry_init,
842         .enabled = 0
843 };
844
845 RTE_INIT(rte_telemetry_register)
846 {
847         telemetry_log_level = rte_log_register("lib.telemetry");
848         if (telemetry_log_level >= 0)
849                 rte_log_set_level(telemetry_log_level, RTE_LOG_ERR);
850
851         rte_option_register(&option);
852 }