telemetry: move some functions to metrics library
[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 #include "rte_telemetry_socket_tests.h"
22
23 #define BUF_SIZE 1024
24 #define ACTION_POST 1
25 #define SLEEP_TIME 10
26
27 #define SELFTEST_VALID_CLIENT "/var/run/dpdk/valid_client"
28 #define SELFTEST_INVALID_CLIENT "/var/run/dpdk/invalid_client"
29 #define SOCKET_TEST_CLIENT_PATH "/var/run/dpdk/client"
30
31 static telemetry_impl *static_telemetry;
32
33 struct telemetry_message_test {
34         const char *test_name;
35         int (*test_func_ptr)(struct telemetry_impl *telemetry, int fd);
36 };
37
38 struct json_data {
39         char *status_code;
40         const char *data;
41         int port;
42         char *stat_name;
43         int stat_value;
44 };
45
46 static void
47 rte_telemetry_get_runtime_dir(char *socket_path, size_t size)
48 {
49         snprintf(socket_path, size, "%s/telemetry", rte_eal_get_runtime_dir());
50 }
51
52 static int32_t
53 rte_telemetry_write_to_socket(struct telemetry_impl *telemetry,
54         const char *json_string)
55 {
56         int ret;
57
58         if (telemetry == NULL) {
59                 TELEMETRY_LOG_ERR("Could not initialise TELEMETRY_API");
60                 return -1;
61         }
62
63         if (telemetry->request_client == NULL) {
64                 TELEMETRY_LOG_ERR("No client has been chosen to write to");
65                 return -1;
66         }
67
68         if (json_string == NULL) {
69                 TELEMETRY_LOG_ERR("Invalid JSON string!");
70                 return -1;
71         }
72
73         ret = send(telemetry->request_client->fd,
74                         json_string, strlen(json_string), 0);
75         if (ret < 0) {
76                 TELEMETRY_LOG_ERR("Failed to write to socket for client: %s",
77                                 telemetry->request_client->file_path);
78                 return -1;
79         }
80
81         return 0;
82 }
83
84 int32_t
85 rte_telemetry_send_error_response(struct telemetry_impl *telemetry,
86         int error_type)
87 {
88         int ret;
89         const char *status_code, *json_buffer;
90         json_t *root;
91
92         if (error_type == -EPERM)
93                 status_code = "Status Error: Unknown";
94         else if (error_type == -EINVAL)
95                 status_code = "Status Error: Invalid Argument 404";
96         else if (error_type == -ENOMEM)
97                 status_code = "Status Error: Memory Allocation Error";
98         else {
99                 TELEMETRY_LOG_ERR("Invalid error type");
100                 return -EINVAL;
101         }
102
103         root = json_object();
104
105         if (root == NULL) {
106                 TELEMETRY_LOG_ERR("Could not create root JSON object");
107                 return -EPERM;
108         }
109
110         ret = json_object_set_new(root, "status_code", json_string(status_code));
111         if (ret < 0) {
112                 TELEMETRY_LOG_ERR("Status code field cannot be set");
113                 json_decref(root);
114                 return -EPERM;
115         }
116
117         ret = json_object_set_new(root, "data", json_null());
118         if (ret < 0) {
119                 TELEMETRY_LOG_ERR("Data field cannot be set");
120                 json_decref(root);
121                 return -EPERM;
122         }
123
124         json_buffer = json_dumps(root, 0);
125         json_decref(root);
126
127         ret = rte_telemetry_write_to_socket(telemetry, json_buffer);
128         if (ret < 0) {
129                 TELEMETRY_LOG_ERR("Could not write to socket");
130                 return -EPERM;
131         }
132
133         return 0;
134 }
135
136 int32_t
137 rte_telemetry_send_global_stats_values(struct telemetry_encode_param *ep,
138         struct telemetry_impl *telemetry)
139 {
140         int ret;
141         char *json_buffer = NULL;
142
143         if (telemetry == NULL) {
144                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
145                 return -1;
146         }
147
148         if (ep->gp.num_metric_ids < 0) {
149                 TELEMETRY_LOG_ERR("Invalid num_metric_ids, must be positive");
150                 goto einval_fail;
151         }
152
153         ret = rte_metrics_tel_encode_json_format(ep, &json_buffer);
154         if (ret < 0) {
155                 TELEMETRY_LOG_ERR("JSON encode function failed");
156                 ret = rte_telemetry_send_error_response(telemetry, ret);
157                 if (ret < 0)
158                         TELEMETRY_LOG_ERR("Could not send error");
159                 return -1;
160         }
161
162         ret = rte_telemetry_write_to_socket(telemetry, json_buffer);
163         if (ret < 0) {
164                 TELEMETRY_LOG_ERR("Could not write to socket");
165                 return -1;
166         }
167
168         return 0;
169
170 einval_fail:
171         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
172         if (ret < 0)
173                 TELEMETRY_LOG_ERR("Could not send error");
174         return -1;
175 }
176
177 int32_t
178 rte_telemetry_send_ports_stats_values(struct telemetry_encode_param *ep,
179         struct telemetry_impl *telemetry)
180 {
181         int ret;
182         char *json_buffer = NULL;
183
184         if (telemetry == NULL) {
185                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
186                 return -1;
187         }
188
189         if (ep == NULL) {
190                 TELEMETRY_LOG_ERR("Invalid encode param argument");
191                 goto einval_fail;
192         }
193
194         if (ep->pp.num_metric_ids < 0) {
195                 TELEMETRY_LOG_ERR("Invalid num_metric_ids, must be positive");
196                 goto einval_fail;
197         }
198
199         if (ep->pp.num_port_ids < 0) {
200                 TELEMETRY_LOG_ERR("Invalid num_port_ids, must be positive");
201                 goto einval_fail;
202         }
203
204         ret = rte_metrics_tel_get_ports_stats_json(ep, telemetry->reg_index,
205                         &json_buffer);
206         if (ret < 0) {
207                 TELEMETRY_LOG_ERR("Function for get_ports_stats_json"
208                                 " failed");
209                 ret = rte_telemetry_send_error_response(telemetry, ret);
210                 if (ret < 0)
211                         TELEMETRY_LOG_ERR("Could not send error");
212                 return -1;
213         }
214
215         ret = rte_telemetry_write_to_socket(telemetry, json_buffer);
216         if (ret < 0) {
217                 TELEMETRY_LOG_ERR("Could not write to socket");
218                 return -1;
219         }
220
221         return 0;
222
223 einval_fail:
224         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
225         if (ret < 0)
226                 TELEMETRY_LOG_ERR("Could not send error");
227         return -1;
228 }
229
230 static int32_t
231 rte_telemetry_initial_accept(struct telemetry_impl *telemetry)
232 {
233         int ret;
234         int selftest = 0;
235
236         ret = rte_metrics_tel_reg_all_ethdev(
237                         &telemetry->metrics_register_done,
238                         telemetry->reg_index);
239         if (ret < 0) {
240                 TELEMETRY_LOG_ERR("Failed to register ethdev metrics");
241                 ret = rte_telemetry_send_error_response(telemetry, ret);
242                 if (ret < 0)
243                         TELEMETRY_LOG_ERR("Could not send error");
244                 return -1;
245         }
246
247         if (selftest) {
248                 ret = rte_telemetry_socket_messaging_testing(telemetry->reg_index[0],
249                                 telemetry->server_fd);
250                 if (ret < 0)
251                         return -1;
252
253                 ret = rte_telemetry_parser_test(telemetry);
254                 if (ret < 0) {
255                         TELEMETRY_LOG_ERR("Parser Tests Failed");
256                         return -1;
257                 }
258
259                 TELEMETRY_LOG_INFO("Success - All Parser Tests Passed");
260         }
261
262         return 0;
263 }
264
265 static int32_t
266 rte_telemetry_read_client(struct telemetry_impl *telemetry)
267 {
268         char buf[BUF_SIZE];
269         int ret, buffer_read;
270
271         buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
272
273         if (buffer_read == -1) {
274                 TELEMETRY_LOG_ERR("Read error");
275                 return -1;
276         } else if (buffer_read == 0) {
277                 goto close_socket;
278         } else {
279                 buf[buffer_read] = '\0';
280                 ret = rte_telemetry_parse_client_message(telemetry, buf);
281                 if (ret < 0)
282                         TELEMETRY_LOG_WARN("Parse message failed");
283                 goto close_socket;
284         }
285
286 close_socket:
287         if (close(telemetry->accept_fd) < 0) {
288                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
289                 free(telemetry);
290                 return -EPERM;
291         }
292         telemetry->accept_fd = 0;
293
294         return 0;
295 }
296
297 static int32_t
298 rte_telemetry_accept_new_client(struct telemetry_impl *telemetry)
299 {
300         int ret;
301
302         if (telemetry->accept_fd <= 0) {
303                 ret = listen(telemetry->server_fd, 1);
304                 if (ret < 0) {
305                         TELEMETRY_LOG_ERR("Listening error with server fd");
306                         return -1;
307                 }
308
309                 telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL);
310                 if (telemetry->accept_fd >= 0 &&
311                         telemetry->metrics_register_done == 0) {
312                         ret = rte_telemetry_initial_accept(telemetry);
313                         if (ret < 0) {
314                                 TELEMETRY_LOG_ERR("Failed to run initial configurations/tests");
315                                 return -1;
316                         }
317                 }
318         } else {
319                 ret = rte_telemetry_read_client(telemetry);
320                 if (ret < 0) {
321                         TELEMETRY_LOG_ERR("Failed to read socket buffer");
322                         return -1;
323                 }
324         }
325
326         return 0;
327 }
328
329 static int32_t
330 rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)
331 {
332         int ret;
333         telemetry_client *client;
334         char client_buf[BUF_SIZE];
335         int bytes;
336
337         TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
338                 bytes = read(client->fd, client_buf, BUF_SIZE-1);
339
340                 if (bytes > 0) {
341                         client_buf[bytes] = '\0';
342                         telemetry->request_client = client;
343                         ret = rte_telemetry_parse(telemetry, client_buf);
344                         if (ret < 0) {
345                                 TELEMETRY_LOG_WARN("Parse socket input failed: %i",
346                                                 ret);
347                                 return -1;
348                         }
349                 }
350         }
351
352         return 0;
353 }
354
355 static int32_t
356 rte_telemetry_run(void *userdata)
357 {
358         int ret;
359         struct telemetry_impl *telemetry = userdata;
360
361         if (telemetry == NULL) {
362                 TELEMETRY_LOG_WARN("TELEMETRY could not be initialised");
363                 return -1;
364         }
365
366         ret = rte_telemetry_accept_new_client(telemetry);
367         if (ret < 0) {
368                 TELEMETRY_LOG_ERR("Accept and read new client failed");
369                 return -1;
370         }
371
372         ret = rte_telemetry_read_client_sockets(telemetry);
373         if (ret < 0) {
374                 TELEMETRY_LOG_ERR("Client socket read failed");
375                 return -1;
376         }
377
378         return 0;
379 }
380
381 static void
382 *rte_telemetry_run_thread_func(void *userdata)
383 {
384         int ret;
385         struct telemetry_impl *telemetry = userdata;
386
387         if (telemetry == NULL) {
388                 TELEMETRY_LOG_ERR("%s passed a NULL instance", __func__);
389                 pthread_exit(0);
390         }
391
392         while (telemetry->thread_status) {
393                 rte_telemetry_run(telemetry);
394                 ret = usleep(SLEEP_TIME);
395                 if (ret < 0)
396                         TELEMETRY_LOG_ERR("Calling thread could not be put to sleep");
397         }
398         pthread_exit(0);
399 }
400
401 static int32_t
402 rte_telemetry_set_socket_nonblock(int fd)
403 {
404         int flags;
405
406         if (fd < 0) {
407                 TELEMETRY_LOG_ERR("Invalid fd provided");
408                 return -1;
409         }
410
411         flags = fcntl(fd, F_GETFL, 0);
412         if (flags < 0)
413                 flags = 0;
414
415         return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
416 }
417
418 static int32_t
419 rte_telemetry_create_socket(struct telemetry_impl *telemetry)
420 {
421         int ret;
422         struct sockaddr_un addr;
423         char socket_path[BUF_SIZE];
424
425         if (telemetry == NULL)
426                 return -1;
427
428         telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
429         if (telemetry->server_fd == -1) {
430                 TELEMETRY_LOG_ERR("Failed to open socket");
431                 return -1;
432         }
433
434         ret  = rte_telemetry_set_socket_nonblock(telemetry->server_fd);
435         if (ret < 0) {
436                 TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK");
437                 goto close_socket;
438         }
439
440         addr.sun_family = AF_UNIX;
441         rte_telemetry_get_runtime_dir(socket_path, sizeof(socket_path));
442         strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
443         unlink(socket_path);
444
445         if (bind(telemetry->server_fd, (struct sockaddr *)&addr,
446                 sizeof(addr)) < 0) {
447                 TELEMETRY_LOG_ERR("Socket binding error");
448                 goto close_socket;
449         }
450
451         return 0;
452
453 close_socket:
454         if (close(telemetry->server_fd) < 0) {
455                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
456                 return -EPERM;
457         }
458
459         return -1;
460 }
461
462 int32_t
463 rte_telemetry_init(void)
464 {
465         int ret;
466         pthread_attr_t attr;
467         const char *telemetry_ctrl_thread = "telemetry";
468
469         if (static_telemetry) {
470                 TELEMETRY_LOG_WARN("TELEMETRY structure already initialised");
471                 return -EALREADY;
472         }
473
474         static_telemetry = calloc(1, sizeof(struct telemetry_impl));
475         if (static_telemetry == NULL) {
476                 TELEMETRY_LOG_ERR("Memory could not be allocated");
477                 return -ENOMEM;
478         }
479
480         static_telemetry->socket_id = rte_socket_id();
481         rte_metrics_init(static_telemetry->socket_id);
482
483         ret = pthread_attr_init(&attr);
484         if (ret != 0) {
485                 TELEMETRY_LOG_ERR("Pthread attribute init failed");
486                 return -EPERM;
487         }
488
489         ret = rte_telemetry_create_socket(static_telemetry);
490         if (ret < 0) {
491                 ret = rte_telemetry_cleanup();
492                 if (ret < 0)
493                         TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
494                 return -EPERM;
495         }
496         TAILQ_INIT(&static_telemetry->client_list_head);
497
498         ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
499                 telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
500                 (void *)static_telemetry);
501         static_telemetry->thread_status = 1;
502
503         if (ret < 0) {
504                 ret = rte_telemetry_cleanup();
505                 if (ret < 0)
506                         TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
507                 return -EPERM;
508         }
509
510         return 0;
511 }
512
513 static int32_t
514 rte_telemetry_client_cleanup(struct telemetry_client *client)
515 {
516         int ret;
517
518         ret = close(client->fd);
519         free(client->file_path);
520         free(client);
521
522         if (ret < 0) {
523                 TELEMETRY_LOG_ERR("Close client socket failed");
524                 return -EPERM;
525         }
526
527         return 0;
528 }
529
530 int32_t
531 rte_telemetry_cleanup(void)
532 {
533         int ret;
534         struct telemetry_impl *telemetry = static_telemetry;
535         telemetry_client *client, *temp_client;
536
537         TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
538                 temp_client) {
539                 TAILQ_REMOVE(&telemetry->client_list_head, client, client_list);
540                 ret = rte_telemetry_client_cleanup(client);
541                 if (ret < 0) {
542                         TELEMETRY_LOG_ERR("Client cleanup failed");
543                         return -EPERM;
544                 }
545         }
546
547         ret = close(telemetry->server_fd);
548         if (ret < 0) {
549                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
550                 free(telemetry);
551                 return -EPERM;
552         }
553
554         telemetry->thread_status = 0;
555         pthread_join(telemetry->thread_id, NULL);
556         free(telemetry);
557         static_telemetry = NULL;
558
559         return 0;
560 }
561
562 int32_t
563 rte_telemetry_unregister_client(struct telemetry_impl *telemetry,
564         const char *client_path)
565 {
566         int ret;
567         telemetry_client *client, *temp_client;
568
569         if (telemetry == NULL) {
570                 TELEMETRY_LOG_WARN("TELEMETRY is not initialised");
571                 return -ENODEV;
572         }
573
574         if (client_path == NULL) {
575                 TELEMETRY_LOG_ERR("Invalid client path");
576                 goto einval_fail;
577         }
578
579         if (TAILQ_EMPTY(&telemetry->client_list_head)) {
580                 TELEMETRY_LOG_ERR("There are no clients currently registered");
581                 return -EPERM;
582         }
583
584         TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
585                         temp_client) {
586                 if (strcmp(client_path, client->file_path) == 0) {
587                         TAILQ_REMOVE(&telemetry->client_list_head, client,
588                                 client_list);
589                         ret = rte_telemetry_client_cleanup(client);
590
591                         if (ret < 0) {
592                                 TELEMETRY_LOG_ERR("Client cleanup failed");
593                                 return -EPERM;
594                         }
595
596                         return 0;
597                 }
598         }
599
600         TELEMETRY_LOG_WARN("Couldn't find client, possibly not registered yet.");
601         return -1;
602
603 einval_fail:
604         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
605         if (ret < 0)
606                 TELEMETRY_LOG_ERR("Could not send error");
607         return -EINVAL;
608 }
609
610 int32_t
611 rte_telemetry_register_client(struct telemetry_impl *telemetry,
612         const char *client_path)
613 {
614         int ret, fd;
615         struct sockaddr_un addrs;
616
617         if (telemetry == NULL) {
618                 TELEMETRY_LOG_ERR("Could not initialize TELEMETRY API");
619                 return -ENODEV;
620         }
621
622         if (client_path == NULL) {
623                 TELEMETRY_LOG_ERR("Invalid client path");
624                 return -EINVAL;
625         }
626
627         telemetry_client *client;
628         TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
629                 if (strcmp(client_path, client->file_path) == 0) {
630                         TELEMETRY_LOG_WARN("'%s' already registered",
631                                         client_path);
632                         return -EINVAL;
633                 }
634         }
635
636         fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
637         if (fd == -1) {
638                 TELEMETRY_LOG_ERR("Client socket error");
639                 return -EACCES;
640         }
641
642         ret = rte_telemetry_set_socket_nonblock(fd);
643         if (ret < 0) {
644                 TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK");
645                 return -EPERM;
646         }
647
648         addrs.sun_family = AF_UNIX;
649         strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path));
650         telemetry_client *new_client = malloc(sizeof(telemetry_client));
651         new_client->file_path = strdup(client_path);
652         new_client->fd = fd;
653
654         if (connect(fd, (struct sockaddr *)&addrs, sizeof(addrs)) == -1) {
655                 TELEMETRY_LOG_ERR("TELEMETRY client connect to %s didn't work",
656                                 client_path);
657                 ret = rte_telemetry_client_cleanup(new_client);
658                 if (ret < 0) {
659                         TELEMETRY_LOG_ERR("Client cleanup failed");
660                         return -EPERM;
661                 }
662                 return -EINVAL;
663         }
664
665         TAILQ_INSERT_HEAD(&telemetry->client_list_head, new_client, client_list);
666
667         return 0;
668 }
669
670 int32_t
671 rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf)
672 {
673         int ret, action_int;
674         json_error_t error;
675         json_t *root = json_loads(buf, 0, &error);
676
677         if (root == NULL) {
678                 TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s",
679                                 error.text);
680                 goto fail;
681         } else if (!json_is_object(root)) {
682                 TELEMETRY_LOG_WARN("JSON Request is not a JSON object");
683                 goto fail;
684         }
685
686         json_t *action = json_object_get(root, "action");
687         if (action == NULL) {
688                 TELEMETRY_LOG_WARN("Request does not have action field");
689                 goto fail;
690         } else if (!json_is_integer(action)) {
691                 TELEMETRY_LOG_WARN("Action value is not an integer");
692                 goto fail;
693         }
694
695         json_t *command = json_object_get(root, "command");
696         if (command == NULL) {
697                 TELEMETRY_LOG_WARN("Request does not have command field");
698                 goto fail;
699         } else if (!json_is_string(command)) {
700                 TELEMETRY_LOG_WARN("Command value is not a string");
701                 goto fail;
702         }
703
704         action_int = json_integer_value(action);
705         if (action_int != ACTION_POST) {
706                 TELEMETRY_LOG_WARN("Invalid action code");
707                 goto fail;
708         }
709
710         if (strcmp(json_string_value(command), "clients") != 0) {
711                 TELEMETRY_LOG_WARN("Invalid command");
712                 goto fail;
713         }
714
715         json_t *data = json_object_get(root, "data");
716         if (data == NULL) {
717                 TELEMETRY_LOG_WARN("Request does not have data field");
718                 goto fail;
719         }
720
721         json_t *client_path = json_object_get(data, "client_path");
722         if (client_path == NULL) {
723                 TELEMETRY_LOG_WARN("Request does not have client_path field");
724                 goto fail;
725         }
726
727         if (!json_is_string(client_path)) {
728                 TELEMETRY_LOG_WARN("Client_path value is not a string");
729                 goto fail;
730         }
731
732         ret = rte_telemetry_register_client(telemetry,
733                         json_string_value(client_path));
734         if (ret < 0) {
735                 TELEMETRY_LOG_ERR("Could not register client");
736                 telemetry->register_fail_count++;
737                 goto fail;
738         }
739
740         return 0;
741
742 fail:
743         TELEMETRY_LOG_WARN("Client attempted to register with invalid message");
744         json_decref(root);
745         return -1;
746 }
747
748 static int32_t
749 rte_telemetry_dummy_client_socket(const char *valid_client_path)
750 {
751         int sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
752         struct sockaddr_un addr = {0};
753
754         if (sockfd < 0) {
755                 TELEMETRY_LOG_ERR("Test socket creation failure");
756                 return -1;
757         }
758
759         addr.sun_family = AF_UNIX;
760         strlcpy(addr.sun_path, valid_client_path, sizeof(addr.sun_path));
761         unlink(valid_client_path);
762
763         if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
764                 TELEMETRY_LOG_ERR("Test socket binding failure");
765                 return -1;
766         }
767
768         if (listen(sockfd, 1) < 0) {
769                 TELEMETRY_LOG_ERR("Listen failure");
770                 return -1;
771         }
772
773         return sockfd;
774 }
775
776 int32_t
777 rte_telemetry_selftest(void)
778 {
779         const char *invalid_client_path = SELFTEST_INVALID_CLIENT;
780         const char *valid_client_path = SELFTEST_VALID_CLIENT;
781         int ret, sockfd;
782
783         TELEMETRY_LOG_INFO("Selftest");
784
785         ret = rte_telemetry_init();
786         if (ret < 0) {
787                 TELEMETRY_LOG_ERR("Valid initialisation test failed");
788                 return -1;
789         }
790
791         TELEMETRY_LOG_INFO("Success - Valid initialisation test passed");
792
793         ret = rte_telemetry_init();
794         if (ret != -EALREADY) {
795                 TELEMETRY_LOG_ERR("Invalid initialisation test failed");
796                 return -1;
797         }
798
799         TELEMETRY_LOG_INFO("Success - Invalid initialisation test passed");
800
801         ret = rte_telemetry_unregister_client(static_telemetry,
802                         invalid_client_path);
803         if (ret != -EPERM) {
804                 TELEMETRY_LOG_ERR("Invalid unregister test failed");
805                 return -1;
806         }
807
808         TELEMETRY_LOG_INFO("Success - Invalid unregister test passed");
809
810         sockfd = rte_telemetry_dummy_client_socket(valid_client_path);
811         if (sockfd < 0) {
812                 TELEMETRY_LOG_ERR("Test socket creation failed");
813                 return -1;
814         }
815
816         ret = rte_telemetry_register_client(static_telemetry, valid_client_path);
817         if (ret != 0) {
818                 TELEMETRY_LOG_ERR("Valid register test failed: %i", ret);
819                 return -1;
820         }
821
822         accept(sockfd, NULL, NULL);
823         TELEMETRY_LOG_INFO("Success - Valid register test passed");
824
825         ret = rte_telemetry_register_client(static_telemetry, valid_client_path);
826         if (ret != -EINVAL) {
827                 TELEMETRY_LOG_ERR("Invalid register test failed: %i", ret);
828                 return -1;
829         }
830
831         TELEMETRY_LOG_INFO("Success - Invalid register test passed");
832
833         ret = rte_telemetry_unregister_client(static_telemetry,
834                 invalid_client_path);
835         if (ret != -1) {
836                 TELEMETRY_LOG_ERR("Invalid unregister test failed: %i", ret);
837                 return -1;
838         }
839
840         TELEMETRY_LOG_INFO("Success - Invalid unregister test passed");
841
842         ret = rte_telemetry_unregister_client(static_telemetry, valid_client_path);
843         if (ret != 0) {
844                 TELEMETRY_LOG_ERR("Valid unregister test failed: %i", ret);
845                 return -1;
846         }
847
848         TELEMETRY_LOG_INFO("Success - Valid unregister test passed");
849
850         ret = rte_telemetry_cleanup();
851         if (ret < 0) {
852                 TELEMETRY_LOG_ERR("Cleanup test failed");
853                 return -1;
854         }
855
856         TELEMETRY_LOG_INFO("Success - Valid cleanup test passed");
857
858         return 0;
859 }
860
861 int32_t
862 rte_telemetry_socket_messaging_testing(int index, int socket)
863 {
864         struct telemetry_impl *telemetry = calloc(1, sizeof(telemetry_impl));
865         int fd, bad_send_fd, send_fd, bad_fd, bad_recv_fd, recv_fd, ret;
866
867         if (telemetry == NULL) {
868                 TELEMETRY_LOG_ERR("Could not initialize Telemetry API");
869                 return -1;
870         }
871
872         telemetry->server_fd = socket;
873         telemetry->reg_index[0] = index;
874         TELEMETRY_LOG_INFO("Beginning Telemetry socket message Selftest");
875         rte_telemetry_socket_test_setup(telemetry, &send_fd, &recv_fd);
876         TELEMETRY_LOG_INFO("Register valid client test");
877
878         ret = rte_telemetry_socket_register_test(telemetry, &fd, send_fd,
879                 recv_fd);
880         if (ret < 0) {
881                 TELEMETRY_LOG_ERR("Register valid client test failed!");
882                 free(telemetry);
883                 return -1;
884         }
885
886         TELEMETRY_LOG_INFO("Success - Register valid client test passed!");
887
888         TELEMETRY_LOG_INFO("Register invalid/same client test");
889         ret = rte_telemetry_socket_test_setup(telemetry, &bad_send_fd,
890                 &bad_recv_fd);
891         ret = rte_telemetry_socket_register_test(telemetry, &bad_fd,
892                 bad_send_fd, bad_recv_fd);
893         if (!ret) {
894                 TELEMETRY_LOG_ERR("Register invalid/same client test failed!");
895                 free(telemetry);
896                 return -1;
897         }
898
899         TELEMETRY_LOG_INFO("Success - Register invalid/same client test passed!");
900
901         ret = rte_telemetry_json_socket_message_test(telemetry, fd);
902         if (ret < 0) {
903                 free(telemetry);
904                 return -1;
905         }
906
907         free(telemetry);
908         return 0;
909 }
910
911 int32_t
912 rte_telemetry_socket_register_test(struct telemetry_impl *telemetry, int *fd,
913         int send_fd, int recv_fd)
914 {
915         int ret;
916         char good_req_string[BUF_SIZE];
917
918         snprintf(good_req_string, sizeof(good_req_string),
919         "{\"action\":1,\"command\":\"clients\",\"data\":{\"client_path\""
920                 ":\"%s\"}}", SOCKET_TEST_CLIENT_PATH);
921
922         listen(recv_fd, 1);
923
924         ret = send(send_fd, good_req_string, strlen(good_req_string), 0);
925         if (ret < 0) {
926                 TELEMETRY_LOG_ERR("Could not send message over socket");
927                 return -1;
928         }
929
930         rte_telemetry_run(telemetry);
931
932         if (telemetry->register_fail_count != 0)
933                 return -1;
934
935         *fd = accept(recv_fd, NULL, NULL);
936
937         return 0;
938 }
939
940 int32_t
941 rte_telemetry_socket_test_setup(struct telemetry_impl *telemetry, int *send_fd,
942         int *recv_fd)
943 {
944         int ret;
945         const char *client_path = SOCKET_TEST_CLIENT_PATH;
946         char socket_path[BUF_SIZE];
947         struct sockaddr_un addr = {0};
948         struct sockaddr_un addrs = {0};
949         *send_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
950         *recv_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
951
952         listen(telemetry->server_fd, 5);
953         addr.sun_family = AF_UNIX;
954         rte_telemetry_get_runtime_dir(socket_path, sizeof(socket_path));
955         strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
956
957         ret = connect(*send_fd, (struct sockaddr *) &addr, sizeof(addr));
958         if (ret < 0) {
959                 TELEMETRY_LOG_ERR("Could not connect socket");
960                 return -1;
961         }
962
963         telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL);
964
965         addrs.sun_family = AF_UNIX;
966         strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path));
967         unlink(client_path);
968
969         ret = bind(*recv_fd, (struct sockaddr *)&addrs, sizeof(addrs));
970         if (ret < 0) {
971                 TELEMETRY_LOG_ERR("Could not bind socket");
972                 return -1;
973         }
974
975         return 0;
976 }
977
978 static int32_t
979 rte_telemetry_stat_parse(char *buf, struct json_data *json_data_struct)
980 {
981         json_error_t error;
982         json_t *root = json_loads(buf, 0, &error);
983         int arraylen, i;
984         json_t *status, *dataArray, *port, *stats, *name, *value, *dataArrayObj,
985                *statsArrayObj;
986
987         stats = NULL;
988         port = NULL;
989         name = NULL;
990
991         if (buf == NULL) {
992                 TELEMETRY_LOG_ERR("JSON message is NULL");
993                 return -EINVAL;
994         }
995
996         if (root == NULL) {
997                 TELEMETRY_LOG_ERR("Could not load JSON object from data passed in : %s",
998                                 error.text);
999                 return -EPERM;
1000         } else if (!json_is_object(root)) {
1001                 TELEMETRY_LOG_ERR("JSON Request is not a JSON object");
1002                 json_decref(root);
1003                 return -EINVAL;
1004         }
1005
1006         status = json_object_get(root, "status_code");
1007         if (!status) {
1008                 TELEMETRY_LOG_ERR("Request does not have status field");
1009                 return -EINVAL;
1010         } else if (!json_is_string(status)) {
1011                 TELEMETRY_LOG_ERR("Status value is not a string");
1012                 return -EINVAL;
1013         }
1014
1015         json_data_struct->status_code = strdup(json_string_value(status));
1016
1017         dataArray = json_object_get(root, "data");
1018         if (dataArray == NULL) {
1019                 TELEMETRY_LOG_ERR("Request does not have data field");
1020                 return -EINVAL;
1021         }
1022
1023         arraylen = json_array_size(dataArray);
1024         if (arraylen == 0) {
1025                 json_data_struct->data = "null";
1026                 return -EINVAL;
1027         }
1028
1029         for (i = 0; i < arraylen; i++) {
1030                 dataArrayObj = json_array_get(dataArray, i);
1031                 port = json_object_get(dataArrayObj, "port");
1032                 stats = json_object_get(dataArrayObj, "stats");
1033         }
1034
1035         if (port == NULL) {
1036                 TELEMETRY_LOG_ERR("Request does not have port field");
1037                 return -EINVAL;
1038         }
1039
1040         if (!json_is_integer(port)) {
1041                 TELEMETRY_LOG_ERR("Port value is not an integer");
1042                 return -EINVAL;
1043         }
1044
1045         json_data_struct->port = json_integer_value(port);
1046
1047         if (stats == NULL) {
1048                 TELEMETRY_LOG_ERR("Request does not have stats field");
1049                 return -EINVAL;
1050         }
1051
1052         arraylen = json_array_size(stats);
1053         for (i = 0; i < arraylen; i++) {
1054                 statsArrayObj = json_array_get(stats, i);
1055                 name = json_object_get(statsArrayObj, "name");
1056                 value = json_object_get(statsArrayObj, "value");
1057         }
1058
1059         if (name == NULL) {
1060                 TELEMETRY_LOG_ERR("Request does not have name field");
1061                 return -EINVAL;
1062         }
1063
1064         if (!json_is_string(name)) {
1065                 TELEMETRY_LOG_ERR("Stat name value is not a string");
1066                 return -EINVAL;
1067         }
1068
1069         json_data_struct->stat_name = strdup(json_string_value(name));
1070
1071         if (value == NULL) {
1072                 TELEMETRY_LOG_ERR("Request does not have value field");
1073                 return -EINVAL;
1074         }
1075
1076         if (!json_is_integer(value)) {
1077                 TELEMETRY_LOG_ERR("Stat value is not an integer");
1078                 return -EINVAL;
1079         }
1080
1081         json_data_struct->stat_value = json_integer_value(value);
1082
1083         return 0;
1084 }
1085
1086 static void
1087 rte_telemetry_free_test_data(struct json_data *data)
1088 {
1089         free(data->status_code);
1090         free(data->stat_name);
1091         free(data);
1092 }
1093
1094 int32_t
1095 rte_telemetry_valid_json_test(struct telemetry_impl *telemetry, int fd)
1096 {
1097         int ret;
1098         int port = 0;
1099         int value = 0;
1100         int fail_count = 0;
1101         int buffer_read = 0;
1102         char buf[BUF_SIZE];
1103         struct json_data *data_struct;
1104         errno = 0;
1105         const char *status = "Status OK: 200";
1106         const char *name = "rx_good_packets";
1107         const char *valid_json_message = "{\"action\":0,\"command\":"
1108         "\"ports_stats_values_by_name\",\"data\":{\"ports\""
1109         ":[0],\"stats\":[\"rx_good_packets\"]}}";
1110
1111         ret = send(fd, valid_json_message, strlen(valid_json_message), 0);
1112         if (ret < 0) {
1113                 TELEMETRY_LOG_ERR("Could not send message over socket");
1114                 return -1;
1115         }
1116
1117         rte_telemetry_run(telemetry);
1118         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1119
1120         if (buffer_read == -1) {
1121                 TELEMETRY_LOG_ERR("Read error");
1122                 return -1;
1123         }
1124
1125         buf[buffer_read] = '\0';
1126         data_struct = calloc(1, sizeof(struct json_data));
1127         ret = rte_telemetry_stat_parse(buf, data_struct);
1128
1129         if (ret < 0) {
1130                 TELEMETRY_LOG_ERR("Could not parse stats");
1131                 fail_count++;
1132         }
1133
1134         if (strcmp(data_struct->status_code, status) != 0) {
1135                 TELEMETRY_LOG_ERR("Status code is invalid");
1136                 fail_count++;
1137         }
1138
1139         if (data_struct->port != port) {
1140                 TELEMETRY_LOG_ERR("Port is invalid");
1141                 fail_count++;
1142         }
1143
1144         if (strcmp(data_struct->stat_name, name) != 0) {
1145                 TELEMETRY_LOG_ERR("Stat name is invalid");
1146                 fail_count++;
1147         }
1148
1149         if (data_struct->stat_value != value) {
1150                 TELEMETRY_LOG_ERR("Stat value is invalid");
1151                 fail_count++;
1152         }
1153
1154         rte_telemetry_free_test_data(data_struct);
1155         if (fail_count > 0)
1156                 return -1;
1157
1158         TELEMETRY_LOG_INFO("Success - Passed valid JSON message test passed");
1159
1160         return 0;
1161 }
1162
1163 int32_t
1164 rte_telemetry_invalid_json_test(struct telemetry_impl *telemetry, int fd)
1165 {
1166         int ret;
1167         char buf[BUF_SIZE];
1168         int fail_count = 0;
1169         const char *invalid_json = "{]";
1170         const char *status = "Status Error: Unknown";
1171         const char *data = "null";
1172         struct json_data *data_struct;
1173         int buffer_read = 0;
1174         errno = 0;
1175
1176         ret = send(fd, invalid_json, strlen(invalid_json), 0);
1177         if (ret < 0) {
1178                 TELEMETRY_LOG_ERR("Could not send message over socket");
1179                 return -1;
1180         }
1181
1182         rte_telemetry_run(telemetry);
1183         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1184
1185         if (buffer_read == -1) {
1186                 TELEMETRY_LOG_ERR("Read error");
1187                 return -1;
1188         }
1189
1190         buf[buffer_read] = '\0';
1191
1192         data_struct = calloc(1, sizeof(struct json_data));
1193         ret = rte_telemetry_stat_parse(buf, data_struct);
1194
1195         if (ret < 0)
1196                 TELEMETRY_LOG_ERR("Could not parse stats");
1197
1198         if (strcmp(data_struct->status_code, status) != 0) {
1199                 TELEMETRY_LOG_ERR("Status code is invalid");
1200                 fail_count++;
1201         }
1202
1203         if (strcmp(data_struct->data, data) != 0) {
1204                 TELEMETRY_LOG_ERR("Data status is invalid");
1205                 fail_count++;
1206         }
1207
1208         rte_telemetry_free_test_data(data_struct);
1209         if (fail_count > 0)
1210                 return -1;
1211
1212         TELEMETRY_LOG_INFO("Success - Passed invalid JSON message test");
1213
1214         return 0;
1215 }
1216
1217 int32_t
1218 rte_telemetry_json_contents_test(struct telemetry_impl *telemetry, int fd)
1219 {
1220         int ret;
1221         char buf[BUF_SIZE];
1222         int fail_count = 0;
1223         const char *status = "Status Error: Invalid Argument 404";
1224         const char *data = "null";
1225         struct json_data *data_struct;
1226         const char *invalid_contents = "{\"action\":0,\"command\":"
1227         "\"ports_stats_values_by_name\",\"data\":{\"ports\""
1228         ":[0],\"stats\":[\"some_invalid_param\","
1229         "\"another_invalid_param\"]}}";
1230         int buffer_read = 0;
1231         errno = 0;
1232
1233         ret = send(fd, invalid_contents, strlen(invalid_contents), 0);
1234         if (ret < 0) {
1235                 TELEMETRY_LOG_ERR("Could not send message over socket");
1236                 return -1;
1237         }
1238
1239         rte_telemetry_run(telemetry);
1240         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1241
1242         if (buffer_read == -1) {
1243                 TELEMETRY_LOG_ERR("Read error");
1244                 return -1;
1245         }
1246
1247         buf[buffer_read] = '\0';
1248         data_struct = calloc(1, sizeof(struct json_data));
1249         ret = rte_telemetry_stat_parse(buf, data_struct);
1250
1251         if (ret < 0)
1252                 TELEMETRY_LOG_ERR("Could not parse stats");
1253
1254         if (strcmp(data_struct->status_code, status) != 0) {
1255                 TELEMETRY_LOG_ERR("Status code is invalid");
1256                 fail_count++;
1257         }
1258
1259         if (strcmp(data_struct->data, data) != 0) {
1260                 TELEMETRY_LOG_ERR("Data status is invalid");
1261                 fail_count++;
1262         }
1263
1264         rte_telemetry_free_test_data(data_struct);
1265         if (fail_count > 0)
1266                 return -1;
1267
1268         TELEMETRY_LOG_INFO("Success - Passed invalid JSON content test");
1269
1270         return 0;
1271 }
1272
1273 int32_t
1274 rte_telemetry_json_empty_test(struct telemetry_impl *telemetry, int fd)
1275 {
1276         int ret;
1277         char buf[BUF_SIZE];
1278         int fail_count = 0;
1279         const char *status = "Status Error: Invalid Argument 404";
1280         const char *data = "null";
1281         struct json_data *data_struct;
1282         const char *empty_json  = "{}";
1283         int buffer_read = 0;
1284         errno = 0;
1285
1286         ret = (send(fd, empty_json, strlen(empty_json), 0));
1287         if (ret < 0) {
1288                 TELEMETRY_LOG_ERR("Could not send message over socket");
1289                 return -1;
1290         }
1291
1292         rte_telemetry_run(telemetry);
1293         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1294
1295         if (buffer_read == -1) {
1296                 TELEMETRY_LOG_ERR("Read error");
1297                 return -1;
1298         }
1299
1300         buf[buffer_read] = '\0';
1301         data_struct = calloc(1, sizeof(struct json_data));
1302         ret = rte_telemetry_stat_parse(buf, data_struct);
1303
1304         if (ret < 0)
1305                 TELEMETRY_LOG_ERR("Could not parse stats");
1306
1307         if (strcmp(data_struct->status_code, status) != 0) {
1308                 TELEMETRY_LOG_ERR("Status code is invalid");
1309                 fail_count++;
1310         }
1311
1312         if (strcmp(data_struct->data, data) != 0) {
1313                 TELEMETRY_LOG_ERR("Data status is invalid");
1314                 fail_count++;
1315         }
1316
1317         rte_telemetry_free_test_data(data_struct);
1318
1319         if (fail_count > 0)
1320                 return -1;
1321
1322         TELEMETRY_LOG_INFO("Success - Passed JSON empty message test");
1323
1324         return 0;
1325 }
1326
1327 int32_t
1328 rte_telemetry_json_socket_message_test(struct telemetry_impl *telemetry, int fd)
1329 {
1330         uint16_t i;
1331         int ret, fail_count;
1332
1333         fail_count = 0;
1334         struct telemetry_message_test socket_json_tests[] = {
1335                 {.test_name = "Invalid JSON test",
1336                         .test_func_ptr = rte_telemetry_invalid_json_test},
1337                 {.test_name = "Valid JSON test",
1338                         .test_func_ptr = rte_telemetry_valid_json_test},
1339                 {.test_name = "JSON contents test",
1340                         .test_func_ptr = rte_telemetry_json_contents_test},
1341                 {.test_name = "JSON empty tests",
1342                         .test_func_ptr = rte_telemetry_json_empty_test}
1343                 };
1344
1345 #define NUM_TESTS RTE_DIM(socket_json_tests)
1346
1347         for (i = 0; i < NUM_TESTS; i++) {
1348                 TELEMETRY_LOG_INFO("%s", socket_json_tests[i].test_name);
1349                 ret = (socket_json_tests[i].test_func_ptr)
1350                         (telemetry, fd);
1351                 if (ret < 0) {
1352                         TELEMETRY_LOG_ERR("%s failed",
1353                                         socket_json_tests[i].test_name);
1354                         fail_count++;
1355                 }
1356         }
1357
1358         if (fail_count > 0) {
1359                 TELEMETRY_LOG_ERR("Failed %i JSON socket message test(s)",
1360                                 fail_count);
1361                 return -1;
1362         }
1363
1364         TELEMETRY_LOG_INFO("Success - All JSON tests passed");
1365
1366         return 0;
1367 }
1368
1369 int telemetry_log_level;
1370
1371 static struct rte_option option = {
1372         .name = "telemetry",
1373         .usage = "Enable telemetry backend",
1374         .cb = &rte_telemetry_init,
1375         .enabled = 0
1376 };
1377
1378 RTE_INIT(rte_telemetry_register)
1379 {
1380         telemetry_log_level = rte_log_register("lib.telemetry");
1381         if (telemetry_log_level >= 0)
1382                 rte_log_set_level(telemetry_log_level, RTE_LOG_ERR);
1383
1384         rte_option_register(&option);
1385 }