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