telemetry: format json response when sending stats
[dpdk.git] / lib / librte_telemetry / rte_telemetry.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <pthread.h>
8 #include <sys/socket.h>
9 #include <sys/un.h>
10 #include <jansson.h>
11
12 #include <rte_eal.h>
13 #include <rte_ethdev.h>
14 #include <rte_metrics.h>
15 #include <rte_option.h>
16 #include <rte_string_fns.h>
17
18 #include "rte_telemetry.h"
19 #include "rte_telemetry_internal.h"
20 #include "rte_telemetry_parser.h"
21 #include "rte_telemetry_parser_test.h"
22 #include "rte_telemetry_socket_tests.h"
23
24 #define BUF_SIZE 1024
25 #define ACTION_POST 1
26 #define SLEEP_TIME 10
27
28 #define SELFTEST_VALID_CLIENT "/var/run/dpdk/valid_client"
29 #define SELFTEST_INVALID_CLIENT "/var/run/dpdk/invalid_client"
30 #define SOCKET_TEST_CLIENT_PATH "/var/run/dpdk/client"
31
32 static telemetry_impl *static_telemetry;
33
34 struct telemetry_message_test {
35         char *test_name;
36         int (*test_func_ptr)(struct telemetry_impl *telemetry, int fd);
37 };
38
39 struct json_data {
40         char *status_code;
41         char *data;
42         int port;
43         char *stat_name;
44         int stat_value;
45 };
46
47 static void
48 rte_telemetry_get_runtime_dir(char *socket_path, size_t size)
49 {
50         snprintf(socket_path, size, "%s/telemetry", rte_eal_get_runtime_dir());
51 }
52
53 int32_t
54 rte_telemetry_is_port_active(int port_id)
55 {
56         int ret;
57
58         ret = rte_eth_find_next(port_id);
59         if (ret == port_id)
60                 return 1;
61
62         TELEMETRY_LOG_ERR("port_id: %d is invalid, not active",
63                 port_id);
64
65         return 0;
66 }
67
68 static int32_t
69 rte_telemetry_update_metrics_ethdev(struct telemetry_impl *telemetry,
70         uint16_t port_id, int reg_start_index)
71 {
72         int ret, num_xstats, i;
73         struct rte_eth_xstat *eth_xstats;
74
75         if (!rte_eth_dev_is_valid_port(port_id)) {
76                 TELEMETRY_LOG_ERR("port_id: %d is invalid", port_id);
77                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
78                 if (ret < 0)
79                         TELEMETRY_LOG_ERR("Could not send error");
80                 return -1;
81         }
82
83         ret = rte_telemetry_is_port_active(port_id);
84         if (ret < 1) {
85                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
86                 if (ret < 0)
87                         TELEMETRY_LOG_ERR("Could not send error");
88                 return -1;
89         }
90
91         num_xstats = rte_eth_xstats_get(port_id, NULL, 0);
92         if (num_xstats < 0) {
93                 TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) failed: %d", port_id,
94                                 num_xstats);
95                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
96                 if (ret < 0)
97                         TELEMETRY_LOG_ERR("Could not send error");
98                 return -1;
99         }
100
101         eth_xstats = malloc(sizeof(struct rte_eth_xstat) * num_xstats);
102         if (eth_xstats == NULL) {
103                 TELEMETRY_LOG_ERR("Failed to malloc memory for xstats");
104                 ret = rte_telemetry_send_error_response(telemetry, -ENOMEM);
105                 if (ret < 0)
106                         TELEMETRY_LOG_ERR("Could not send error");
107                 return -1;
108         }
109
110         ret = rte_eth_xstats_get(port_id, eth_xstats, num_xstats);
111         if (ret < 0 || ret > num_xstats) {
112                 free(eth_xstats);
113                 TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) len%i failed: %d",
114                                 port_id, num_xstats, ret);
115                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
116                 if (ret < 0)
117                         TELEMETRY_LOG_ERR("Could not send error");
118                 return -1;
119         }
120
121         uint64_t xstats_values[num_xstats];
122         for (i = 0; i < num_xstats; i++)
123                 xstats_values[i] = eth_xstats[i].value;
124
125         ret = rte_metrics_update_values(port_id, reg_start_index, xstats_values,
126                         num_xstats);
127         if (ret < 0) {
128                 TELEMETRY_LOG_ERR("Could not update metrics values");
129                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
130                 if (ret < 0)
131                         TELEMETRY_LOG_ERR("Could not send error");
132                 free(eth_xstats);
133                 return -1;
134         }
135
136         free(eth_xstats);
137         return 0;
138 }
139
140 int32_t
141 rte_telemetry_write_to_socket(struct telemetry_impl *telemetry,
142         const char *json_string)
143 {
144         int ret;
145
146         if (telemetry == NULL) {
147                 TELEMETRY_LOG_ERR("Could not initialise TELEMETRY_API");
148                 return -1;
149         }
150
151         if (telemetry->request_client == NULL) {
152                 TELEMETRY_LOG_ERR("No client has been chosen to write to");
153                 return -1;
154         }
155
156         if (json_string == NULL) {
157                 TELEMETRY_LOG_ERR("Invalid JSON string!");
158                 return -1;
159         }
160
161         ret = send(telemetry->request_client->fd,
162                         json_string, strlen(json_string), 0);
163         if (ret < 0) {
164                 TELEMETRY_LOG_ERR("Failed to write to socket for client: %s",
165                                 telemetry->request_client->file_path);
166                 return -1;
167         }
168
169         return 0;
170 }
171
172 int32_t
173 rte_telemetry_send_error_response(struct telemetry_impl *telemetry,
174         int error_type)
175 {
176         int ret;
177         const char *status_code, *json_buffer;
178         json_t *root;
179
180         if (error_type == -EPERM)
181                 status_code = "Status Error: Unknown";
182         else if (error_type == -EINVAL)
183                 status_code = "Status Error: Invalid Argument 404";
184         else if (error_type == -ENOMEM)
185                 status_code = "Status Error: Memory Allocation Error";
186         else {
187                 TELEMETRY_LOG_ERR("Invalid error type");
188                 return -EINVAL;
189         }
190
191         root = json_object();
192
193         if (root == NULL) {
194                 TELEMETRY_LOG_ERR("Could not create root JSON object");
195                 return -EPERM;
196         }
197
198         ret = json_object_set_new(root, "status_code", json_string(status_code));
199         if (ret < 0) {
200                 TELEMETRY_LOG_ERR("Status code field cannot be set");
201                 json_decref(root);
202                 return -EPERM;
203         }
204
205         ret = json_object_set_new(root, "data", json_null());
206         if (ret < 0) {
207                 TELEMETRY_LOG_ERR("Data field cannot be set");
208                 json_decref(root);
209                 return -EPERM;
210         }
211
212         json_buffer = json_dumps(root, 0);
213         json_decref(root);
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 -EPERM;
219         }
220
221         return 0;
222 }
223
224 static int
225 rte_telemetry_get_metrics(struct telemetry_impl *telemetry, uint32_t port_id,
226         struct rte_metric_value *metrics, struct rte_metric_name *names,
227         int num_metrics)
228 {
229         int ret, num_values;
230
231         if (num_metrics < 0) {
232                 TELEMETRY_LOG_ERR("Invalid metrics count");
233                 goto einval_fail;
234         } else if (num_metrics == 0) {
235                 TELEMETRY_LOG_ERR("No metrics to display (none have been registered)");
236                 goto eperm_fail;
237         }
238
239         if (metrics == NULL) {
240                 TELEMETRY_LOG_ERR("Metrics must be initialised.");
241                 goto einval_fail;
242         }
243
244         if (names == NULL) {
245                 TELEMETRY_LOG_ERR("Names must be initialised.");
246                 goto einval_fail;
247         }
248
249         ret = rte_metrics_get_names(names, num_metrics);
250         if (ret < 0 || ret > num_metrics) {
251                 TELEMETRY_LOG_ERR("Cannot get metrics names");
252                 goto eperm_fail;
253         }
254
255         num_values = rte_metrics_get_values(port_id, NULL, 0);
256         ret = rte_metrics_get_values(port_id, metrics, num_values);
257         if (ret < 0 || ret > num_values) {
258                 TELEMETRY_LOG_ERR("Cannot get metrics values");
259                 goto eperm_fail;
260         }
261
262         return 0;
263
264 eperm_fail:
265         ret = rte_telemetry_send_error_response(telemetry, -EPERM);
266         if (ret < 0)
267                 TELEMETRY_LOG_ERR("Could not send error");
268         return -1;
269
270 einval_fail:
271         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
272         if (ret < 0)
273                 TELEMETRY_LOG_ERR("Could not send error");
274         return -1;
275
276 }
277
278 static int32_t
279 rte_telemetry_json_format_stat(struct telemetry_impl *telemetry, json_t *stats,
280         const char *metric_name, uint64_t metric_value)
281 {
282         int ret;
283         json_t *stat = json_object();
284
285         if (stat == NULL) {
286                 TELEMETRY_LOG_ERR("Could not create stat JSON object");
287                 goto eperm_fail;
288         }
289
290         ret = json_object_set_new(stat, "name", json_string(metric_name));
291         if (ret < 0) {
292                 TELEMETRY_LOG_ERR("Stat Name field cannot be set");
293                 goto eperm_fail;
294         }
295
296         ret = json_object_set_new(stat, "value", json_integer(metric_value));
297         if (ret < 0) {
298                 TELEMETRY_LOG_ERR("Stat Value field cannot be set");
299                 goto eperm_fail;
300         }
301
302         ret = json_array_append_new(stats, stat);
303         if (ret < 0) {
304                 TELEMETRY_LOG_ERR("Stat cannot be added to stats json array");
305                 goto eperm_fail;
306         }
307
308         return 0;
309
310 eperm_fail:
311         ret = rte_telemetry_send_error_response(telemetry, -EPERM);
312         if (ret < 0)
313                 TELEMETRY_LOG_ERR("Could not send error");
314         return -1;
315
316 }
317
318 static int32_t
319 rte_telemetry_json_format_port(struct telemetry_impl *telemetry,
320         uint32_t port_id, json_t *ports, uint32_t *metric_ids,
321         uint32_t num_metric_ids)
322 {
323         struct rte_metric_value *metrics = 0;
324         struct rte_metric_name *names = 0;
325         int num_metrics, ret, err_ret;
326         json_t *port, *stats;
327         uint32_t i;
328
329         num_metrics = rte_metrics_get_names(NULL, 0);
330         if (num_metrics < 0) {
331                 TELEMETRY_LOG_ERR("Cannot get metrics count");
332                 goto einval_fail;
333         } else if (num_metrics == 0) {
334                 TELEMETRY_LOG_ERR("No metrics to display (none have been registered)");
335                 goto eperm_fail;
336         }
337
338         metrics = malloc(sizeof(struct rte_metric_value) * num_metrics);
339         names = malloc(sizeof(struct rte_metric_name) * num_metrics);
340         if (metrics == NULL || names == NULL) {
341                 TELEMETRY_LOG_ERR("Cannot allocate memory");
342                 free(metrics);
343                 free(names);
344
345                 err_ret = rte_telemetry_send_error_response(telemetry, -ENOMEM);
346                 if (err_ret < 0)
347                         TELEMETRY_LOG_ERR("Could not send error");
348                 return -1;
349         }
350
351         ret  = rte_telemetry_get_metrics(telemetry, port_id, metrics, names,
352                 num_metrics);
353         if (ret < 0) {
354                 free(metrics);
355                 free(names);
356                 TELEMETRY_LOG_ERR("rte_telemetry_get_metrics failed");
357                 return -1;
358         }
359
360         port = json_object();
361         stats = json_array();
362         if (port == NULL || stats == NULL) {
363                 TELEMETRY_LOG_ERR("Could not create port/stats JSON objects");
364                 goto eperm_fail;
365         }
366
367         ret = json_object_set_new(port, "port", json_integer(port_id));
368         if (ret < 0) {
369                 TELEMETRY_LOG_ERR("Port field cannot be set");
370                 goto eperm_fail;
371         }
372
373         for (i = 0; i < num_metric_ids; i++) {
374                 int metric_id = metric_ids[i];
375                 int metric_index = -1;
376                 int metric_name_key = -1;
377                 int32_t j;
378                 uint64_t metric_value;
379
380                 if (metric_id >= num_metrics) {
381                         TELEMETRY_LOG_ERR("Metric_id: %d is not valid",
382                                         metric_id);
383                         goto einval_fail;
384                 }
385
386                 for (j = 0; j < num_metrics; j++) {
387                         if (metrics[j].key == metric_id) {
388                                 metric_name_key = metrics[j].key;
389                                 metric_index = j;
390                                 break;
391                         }
392                 }
393
394                 const char *metric_name = names[metric_name_key].name;
395                 metric_value = metrics[metric_index].value;
396
397                 if (metric_name_key < 0 || metric_index < 0) {
398                         TELEMETRY_LOG_ERR("Could not get metric name/index");
399                         goto eperm_fail;
400                 }
401
402                 ret = rte_telemetry_json_format_stat(telemetry, stats,
403                         metric_name, metric_value);
404                 if (ret < 0) {
405                         TELEMETRY_LOG_ERR("Format stat with id: %u failed",
406                                         metric_id);
407                         free(metrics);
408                         free(names);
409                         return -1;
410                 }
411         }
412
413         if (json_array_size(stats) == 0)
414                 ret = json_object_set_new(port, "stats", json_null());
415         else
416                 ret = json_object_set_new(port, "stats", stats);
417
418         if (ret < 0) {
419                 TELEMETRY_LOG_ERR("Stats object cannot be set");
420                 goto eperm_fail;
421         }
422
423         ret = json_array_append_new(ports, port);
424         if (ret < 0) {
425                 TELEMETRY_LOG_ERR("Port object cannot be added to ports array");
426                 goto eperm_fail;
427         }
428
429         free(metrics);
430         free(names);
431         return 0;
432
433 eperm_fail:
434         free(metrics);
435         free(names);
436         ret = rte_telemetry_send_error_response(telemetry, -EPERM);
437         if (ret < 0)
438                 TELEMETRY_LOG_ERR("Could not send error");
439         return -1;
440
441 einval_fail:
442         free(metrics);
443         free(names);
444         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
445         if (ret < 0)
446                 TELEMETRY_LOG_ERR("Could not send error");
447         return -1;
448 }
449
450 static int32_t
451 rte_telemetry_encode_json_format(struct telemetry_impl *telemetry,
452         uint32_t *port_ids, uint32_t num_port_ids, uint32_t *metric_ids,
453         uint32_t num_metric_ids, char **json_buffer)
454 {
455         int ret;
456         json_t *root, *ports;
457         uint32_t i;
458
459         if (num_port_ids <= 0 || num_metric_ids <= 0) {
460                 TELEMETRY_LOG_ERR("Please provide port and metric ids to query");
461                 goto einval_fail;
462         }
463
464         ports = json_array();
465         if (ports == NULL) {
466                 TELEMETRY_LOG_ERR("Could not create ports JSON array");
467                 goto eperm_fail;
468         }
469
470         for (i = 0; i < num_port_ids; i++) {
471                 if (!rte_eth_dev_is_valid_port(port_ids[i])) {
472                         TELEMETRY_LOG_ERR("Port: %d invalid", port_ids[i]);
473                         goto einval_fail;
474                 }
475         }
476
477         for (i = 0; i < num_port_ids; i++) {
478                 ret = rte_telemetry_json_format_port(telemetry, port_ids[i],
479                         ports, metric_ids, num_metric_ids);
480                 if (ret < 0) {
481                         TELEMETRY_LOG_ERR("Format port in JSON failed");
482                         return -1;
483                 }
484         }
485
486         root = json_object();
487         if (root == NULL) {
488                 TELEMETRY_LOG_ERR("Could not create root JSON object");
489                 goto eperm_fail;
490         }
491
492         ret = json_object_set_new(root, "status_code",
493                 json_string("Status OK: 200"));
494         if (ret < 0) {
495                 TELEMETRY_LOG_ERR("Status code field cannot be set");
496                 goto eperm_fail;
497         }
498
499         ret = json_object_set_new(root, "data", ports);
500         if (ret < 0) {
501                 TELEMETRY_LOG_ERR("Data field cannot be set");
502                 goto eperm_fail;
503         }
504
505         *json_buffer = json_dumps(root, JSON_INDENT(2));
506         json_decref(root);
507         return 0;
508
509 eperm_fail:
510         ret = rte_telemetry_send_error_response(telemetry, -EPERM);
511         if (ret < 0)
512                 TELEMETRY_LOG_ERR("Could not send error");
513         return -1;
514
515 einval_fail:
516         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
517         if (ret < 0)
518                 TELEMETRY_LOG_ERR("Could not send error");
519         return -1;
520 }
521
522 int32_t
523 rte_telemetry_send_ports_stats_values(uint32_t *metric_ids, int num_metric_ids,
524         uint32_t *port_ids, int num_port_ids, struct telemetry_impl *telemetry)
525 {
526         int ret, i;
527         char *json_buffer = NULL;
528
529         if (telemetry == NULL) {
530                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
531                 return -1;
532         }
533
534         if (metric_ids == NULL) {
535                 TELEMETRY_LOG_ERR("Invalid metric_ids array");
536                 goto einval_fail;
537         }
538
539         if (num_metric_ids < 0) {
540                 TELEMETRY_LOG_ERR("Invalid num_metric_ids, must be positive");
541                 goto einval_fail;
542         }
543
544         if (port_ids == NULL) {
545                 TELEMETRY_LOG_ERR("Invalid port_ids array");
546                 goto einval_fail;
547         }
548
549         if (num_port_ids < 0) {
550                 TELEMETRY_LOG_ERR("Invalid num_port_ids, must be positive");
551                 goto einval_fail;
552         }
553
554         for (i = 0; i < num_port_ids; i++) {
555                 if (!rte_eth_dev_is_valid_port(port_ids[i])) {
556                         TELEMETRY_LOG_ERR("Port: %d invalid", port_ids[i]);
557                         goto einval_fail;
558                 }
559
560                 ret = rte_telemetry_update_metrics_ethdev(telemetry,
561                                 port_ids[i], telemetry->reg_index);
562                 if (ret < 0) {
563                         TELEMETRY_LOG_ERR("Failed to update ethdev metrics");
564                         return -1;
565                 }
566         }
567
568         ret = rte_telemetry_encode_json_format(telemetry, port_ids,
569                 num_port_ids, metric_ids, num_metric_ids, &json_buffer);
570         if (ret < 0) {
571                 TELEMETRY_LOG_ERR("JSON encode function failed");
572                 return -1;
573         }
574
575         ret = rte_telemetry_write_to_socket(telemetry, json_buffer);
576         if (ret < 0) {
577                 TELEMETRY_LOG_ERR("Could not write to socket");
578                 return -1;
579         }
580
581         return 0;
582
583 einval_fail:
584         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
585         if (ret < 0)
586                 TELEMETRY_LOG_ERR("Could not send error");
587         return -1;
588 }
589
590
591 static int32_t
592 rte_telemetry_reg_ethdev_to_metrics(uint16_t port_id)
593 {
594         int ret, num_xstats, ret_val, i;
595         struct rte_eth_xstat *eth_xstats = NULL;
596         struct rte_eth_xstat_name *eth_xstats_names = NULL;
597
598         if (!rte_eth_dev_is_valid_port(port_id)) {
599                 TELEMETRY_LOG_ERR("port_id: %d is invalid", port_id);
600                 return -EINVAL;
601         }
602
603         num_xstats = rte_eth_xstats_get(port_id, NULL, 0);
604         if (num_xstats < 0) {
605                 TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) failed: %d",
606                                 port_id, num_xstats);
607                 return -EPERM;
608         }
609
610         eth_xstats = malloc(sizeof(struct rte_eth_xstat) * num_xstats);
611         if (eth_xstats == NULL) {
612                 TELEMETRY_LOG_ERR("Failed to malloc memory for xstats");
613                 return -ENOMEM;
614         }
615
616         ret = rte_eth_xstats_get(port_id, eth_xstats, num_xstats);
617         const char *xstats_names[num_xstats];
618         eth_xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * num_xstats);
619         if (ret < 0 || ret > num_xstats) {
620                 TELEMETRY_LOG_ERR("rte_eth_xstats_get(%u) len%i failed: %d",
621                                 port_id, num_xstats, ret);
622                 ret_val = -EPERM;
623                 goto free_xstats;
624         }
625
626         if (eth_xstats_names == NULL) {
627                 TELEMETRY_LOG_ERR("Failed to malloc memory for xstats_names");
628                 ret_val = -ENOMEM;
629                 goto free_xstats;
630         }
631
632         ret = rte_eth_xstats_get_names(port_id, eth_xstats_names, num_xstats);
633         if (ret < 0 || ret > num_xstats) {
634                 TELEMETRY_LOG_ERR("rte_eth_xstats_get_names(%u) len%i failed: %d",
635                                 port_id, num_xstats, ret);
636                 ret_val = -EPERM;
637                 goto free_xstats;
638         }
639
640         for (i = 0; i < num_xstats; i++)
641                 xstats_names[i] = eth_xstats_names[eth_xstats[i].id].name;
642
643         ret_val = rte_metrics_reg_names(xstats_names, num_xstats);
644         if (ret_val < 0) {
645                 TELEMETRY_LOG_ERR("rte_metrics_reg_names failed - metrics may already be registered");
646                 ret_val = -1;
647                 goto free_xstats;
648         }
649
650         goto free_xstats;
651
652 free_xstats:
653         free(eth_xstats);
654         free(eth_xstats_names);
655         return ret_val;
656 }
657
658 static int32_t
659 rte_telemetry_initial_accept(struct telemetry_impl *telemetry)
660 {
661         uint16_t pid;
662         int ret;
663
664         RTE_ETH_FOREACH_DEV(pid) {
665                 telemetry->reg_index = rte_telemetry_reg_ethdev_to_metrics(pid);
666                 break;
667         }
668
669         if (telemetry->reg_index < 0) {
670                 TELEMETRY_LOG_ERR("Failed to register ethdev metrics");
671                 return -1;
672         }
673
674         telemetry->metrics_register_done = 1;
675         ret = rte_telemetry_socket_messaging_testing(telemetry->reg_index,
676                 telemetry->server_fd);
677         if (ret < 0)
678                 return -1;
679
680         ret = rte_telemetry_parser_test(telemetry);
681         if (ret < 0) {
682                 TELEMETRY_LOG_ERR("Parser Tests Failed");
683                 return -1;
684         }
685
686         TELEMETRY_LOG_INFO("Success - All Parser Tests Passed");
687
688         return 0;
689 }
690
691 static int32_t
692 rte_telemetry_read_client(struct telemetry_impl *telemetry)
693 {
694         char buf[BUF_SIZE];
695         int ret, buffer_read;
696
697         buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
698
699         if (buffer_read == -1) {
700                 TELEMETRY_LOG_ERR("Read error");
701                 return -1;
702         } else if (buffer_read == 0) {
703                 goto close_socket;
704         } else {
705                 buf[buffer_read] = '\0';
706                 ret = rte_telemetry_parse_client_message(telemetry, buf);
707                 if (ret < 0)
708                         TELEMETRY_LOG_WARN("Parse message failed");
709                 goto close_socket;
710         }
711
712 close_socket:
713         if (close(telemetry->accept_fd) < 0) {
714                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
715                 free(telemetry);
716                 return -EPERM;
717         }
718         telemetry->accept_fd = 0;
719
720         return 0;
721 }
722
723 static int32_t
724 rte_telemetry_accept_new_client(struct telemetry_impl *telemetry)
725 {
726         int ret;
727
728         if (telemetry->accept_fd <= 0) {
729                 ret = listen(telemetry->server_fd, 1);
730                 if (ret < 0) {
731                         TELEMETRY_LOG_ERR("Listening error with server fd");
732                         return -1;
733                 }
734
735                 telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL);
736                 if (telemetry->accept_fd >= 0 &&
737                         telemetry->metrics_register_done == 0) {
738                         ret = rte_telemetry_initial_accept(telemetry);
739                         if (ret < 0) {
740                                 TELEMETRY_LOG_ERR("Failed to run initial configurations/tests");
741                                 return -1;
742                         }
743                 }
744         } else {
745                 ret = rte_telemetry_read_client(telemetry);
746                 if (ret < 0) {
747                         TELEMETRY_LOG_ERR("Failed to read socket buffer");
748                         return -1;
749                 }
750         }
751
752         return 0;
753 }
754
755 static int32_t
756 rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)
757 {
758         int ret;
759         telemetry_client *client;
760         char client_buf[BUF_SIZE];
761         int bytes;
762
763         TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
764                 bytes = read(client->fd, client_buf, BUF_SIZE-1);
765
766                 if (bytes > 0) {
767                         client_buf[bytes] = '\0';
768                         telemetry->request_client = client;
769                         ret = rte_telemetry_parse(telemetry, client_buf);
770                         if (ret < 0) {
771                                 TELEMETRY_LOG_WARN("Parse socket input failed: %i",
772                                                 ret);
773                                 return -1;
774                         }
775                 }
776         }
777
778         return 0;
779 }
780
781 static int32_t
782 rte_telemetry_run(void *userdata)
783 {
784         int ret;
785         struct telemetry_impl *telemetry = userdata;
786
787         if (telemetry == NULL) {
788                 TELEMETRY_LOG_WARN("TELEMETRY could not be initialised");
789                 return -1;
790         }
791
792         ret = rte_telemetry_accept_new_client(telemetry);
793         if (ret < 0) {
794                 TELEMETRY_LOG_ERR("Accept and read new client failed");
795                 return -1;
796         }
797
798         ret = rte_telemetry_read_client_sockets(telemetry);
799         if (ret < 0) {
800                 TELEMETRY_LOG_ERR("Client socket read failed");
801                 return -1;
802         }
803
804         return 0;
805 }
806
807 static void
808 *rte_telemetry_run_thread_func(void *userdata)
809 {
810         int ret;
811         struct telemetry_impl *telemetry = userdata;
812
813         if (telemetry == NULL) {
814                 TELEMETRY_LOG_ERR("%s passed a NULL instance", __func__);
815                 pthread_exit(0);
816         }
817
818         while (telemetry->thread_status) {
819                 rte_telemetry_run(telemetry);
820                 ret = usleep(SLEEP_TIME);
821                 if (ret < 0)
822                         TELEMETRY_LOG_ERR("Calling thread could not be put to sleep");
823         }
824         pthread_exit(0);
825 }
826
827 static int32_t
828 rte_telemetry_set_socket_nonblock(int fd)
829 {
830         int flags;
831
832         if (fd < 0) {
833                 TELEMETRY_LOG_ERR("Invalid fd provided");
834                 return -1;
835         }
836
837         flags = fcntl(fd, F_GETFL, 0);
838         if (flags < 0)
839                 flags = 0;
840
841         return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
842 }
843
844 static int32_t
845 rte_telemetry_create_socket(struct telemetry_impl *telemetry)
846 {
847         int ret;
848         struct sockaddr_un addr;
849         char socket_path[BUF_SIZE];
850
851         if (telemetry == NULL)
852                 return -1;
853
854         telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
855         if (telemetry->server_fd == -1) {
856                 TELEMETRY_LOG_ERR("Failed to open socket");
857                 return -1;
858         }
859
860         ret  = rte_telemetry_set_socket_nonblock(telemetry->server_fd);
861         if (ret < 0) {
862                 TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK");
863                 goto close_socket;
864         }
865
866         addr.sun_family = AF_UNIX;
867         rte_telemetry_get_runtime_dir(socket_path, sizeof(socket_path));
868         strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
869         unlink(socket_path);
870
871         if (bind(telemetry->server_fd, (struct sockaddr *)&addr,
872                 sizeof(addr)) < 0) {
873                 TELEMETRY_LOG_ERR("Socket binding error");
874                 goto close_socket;
875         }
876
877         return 0;
878
879 close_socket:
880         if (close(telemetry->server_fd) < 0) {
881                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
882                 return -EPERM;
883         }
884
885         return -1;
886 }
887
888 int32_t __rte_experimental
889 rte_telemetry_init()
890 {
891         int ret;
892         pthread_attr_t attr;
893         const char *telemetry_ctrl_thread = "telemetry";
894
895         if (static_telemetry) {
896                 TELEMETRY_LOG_WARN("TELEMETRY structure already initialised");
897                 return -EALREADY;
898         }
899
900         static_telemetry = calloc(1, sizeof(struct telemetry_impl));
901         if (static_telemetry == NULL) {
902                 TELEMETRY_LOG_ERR("Memory could not be allocated");
903                 return -ENOMEM;
904         }
905
906         static_telemetry->socket_id = rte_socket_id();
907         rte_metrics_init(static_telemetry->socket_id);
908
909         ret = pthread_attr_init(&attr);
910         if (ret != 0) {
911                 TELEMETRY_LOG_ERR("Pthread attribute init failed");
912                 return -EPERM;
913         }
914
915         ret = rte_telemetry_create_socket(static_telemetry);
916         if (ret < 0) {
917                 ret = rte_telemetry_cleanup();
918                 if (ret < 0)
919                         TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
920                 return -EPERM;
921         }
922         TAILQ_INIT(&static_telemetry->client_list_head);
923
924         ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
925                 telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
926                 (void *)static_telemetry);
927         static_telemetry->thread_status = 1;
928
929         if (ret < 0) {
930                 ret = rte_telemetry_cleanup();
931                 if (ret < 0)
932                         TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
933                 return -EPERM;
934         }
935
936         return 0;
937 }
938
939 static int32_t
940 rte_telemetry_client_cleanup(struct telemetry_client *client)
941 {
942         int ret;
943
944         ret = close(client->fd);
945         free(client->file_path);
946         free(client);
947
948         if (ret < 0) {
949                 TELEMETRY_LOG_ERR("Close client socket failed");
950                 return -EPERM;
951         }
952
953         return 0;
954 }
955
956 int32_t __rte_experimental
957 rte_telemetry_cleanup(void)
958 {
959         int ret;
960         struct telemetry_impl *telemetry = static_telemetry;
961         telemetry_client *client, *temp_client;
962
963         TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
964                 temp_client) {
965                 TAILQ_REMOVE(&telemetry->client_list_head, client, client_list);
966                 ret = rte_telemetry_client_cleanup(client);
967                 if (ret < 0) {
968                         TELEMETRY_LOG_ERR("Client cleanup failed");
969                         return -EPERM;
970                 }
971         }
972
973         ret = close(telemetry->server_fd);
974         if (ret < 0) {
975                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
976                 free(telemetry);
977                 return -EPERM;
978         }
979
980         telemetry->thread_status = 0;
981         pthread_join(telemetry->thread_id, NULL);
982         free(telemetry);
983         static_telemetry = NULL;
984
985         return 0;
986 }
987
988 int32_t
989 rte_telemetry_unregister_client(struct telemetry_impl *telemetry,
990         const char *client_path)
991 {
992         int ret;
993         telemetry_client *client, *temp_client;
994
995         if (telemetry == NULL) {
996                 TELEMETRY_LOG_WARN("TELEMETRY is not initialised");
997                 return -ENODEV;
998         }
999
1000         if (client_path == NULL) {
1001                 TELEMETRY_LOG_ERR("Invalid client path");
1002                 goto einval_fail;
1003         }
1004
1005         if (TAILQ_EMPTY(&telemetry->client_list_head)) {
1006                 TELEMETRY_LOG_ERR("There are no clients currently registered");
1007                 return -EPERM;
1008         }
1009
1010         TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
1011                         temp_client) {
1012                 if (strcmp(client_path, client->file_path) == 0) {
1013                         TAILQ_REMOVE(&telemetry->client_list_head, client,
1014                                 client_list);
1015                         ret = rte_telemetry_client_cleanup(client);
1016
1017                         if (ret < 0) {
1018                                 TELEMETRY_LOG_ERR("Client cleanup failed");
1019                                 return -EPERM;
1020                         }
1021
1022                         return 0;
1023                 }
1024         }
1025
1026         TELEMETRY_LOG_WARN("Couldn't find client, possibly not registered yet.");
1027         return -1;
1028
1029 einval_fail:
1030         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
1031         if (ret < 0)
1032                 TELEMETRY_LOG_ERR("Could not send error");
1033         return -EINVAL;
1034 }
1035
1036 int32_t
1037 rte_telemetry_register_client(struct telemetry_impl *telemetry,
1038         const char *client_path)
1039 {
1040         int ret, fd;
1041         struct sockaddr_un addrs;
1042
1043         if (telemetry == NULL) {
1044                 TELEMETRY_LOG_ERR("Could not initialize TELEMETRY API");
1045                 return -ENODEV;
1046         }
1047
1048         if (client_path == NULL) {
1049                 TELEMETRY_LOG_ERR("Invalid client path");
1050                 return -EINVAL;
1051         }
1052
1053         telemetry_client *client;
1054         TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
1055                 if (strcmp(client_path, client->file_path) == 0) {
1056                         TELEMETRY_LOG_WARN("'%s' already registered",
1057                                         client_path);
1058                         return -EINVAL;
1059                 }
1060         }
1061
1062         fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1063         if (fd == -1) {
1064                 TELEMETRY_LOG_ERR("Client socket error");
1065                 return -EACCES;
1066         }
1067
1068         ret = rte_telemetry_set_socket_nonblock(fd);
1069         if (ret < 0) {
1070                 TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK");
1071                 return -EPERM;
1072         }
1073
1074         addrs.sun_family = AF_UNIX;
1075         strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path));
1076         telemetry_client *new_client = malloc(sizeof(telemetry_client));
1077         new_client->file_path = strdup(client_path);
1078         new_client->fd = fd;
1079
1080         if (connect(fd, (struct sockaddr *)&addrs, sizeof(addrs)) == -1) {
1081                 TELEMETRY_LOG_ERR("TELEMETRY client connect to %s didn't work",
1082                                 client_path);
1083                 ret = rte_telemetry_client_cleanup(new_client);
1084                 if (ret < 0) {
1085                         TELEMETRY_LOG_ERR("Client cleanup failed");
1086                         return -EPERM;
1087                 }
1088                 return -EINVAL;
1089         }
1090
1091         TAILQ_INSERT_HEAD(&telemetry->client_list_head, new_client, client_list);
1092
1093         return 0;
1094 }
1095
1096 int32_t
1097 rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf)
1098 {
1099         int ret, action_int;
1100         json_error_t error;
1101         json_t *root = json_loads(buf, 0, &error);
1102
1103         if (root == NULL) {
1104                 TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s",
1105                                 error.text);
1106                 goto fail;
1107         } else if (!json_is_object(root)) {
1108                 TELEMETRY_LOG_WARN("JSON Request is not a JSON object");
1109                 goto fail;
1110         }
1111
1112         json_t *action = json_object_get(root, "action");
1113         if (action == NULL) {
1114                 TELEMETRY_LOG_WARN("Request does not have action field");
1115                 goto fail;
1116         } else if (!json_is_integer(action)) {
1117                 TELEMETRY_LOG_WARN("Action value is not an integer");
1118                 goto fail;
1119         }
1120
1121         json_t *command = json_object_get(root, "command");
1122         if (command == NULL) {
1123                 TELEMETRY_LOG_WARN("Request does not have command field");
1124                 goto fail;
1125         } else if (!json_is_string(command)) {
1126                 TELEMETRY_LOG_WARN("Command value is not a string");
1127                 goto fail;
1128         }
1129
1130         action_int = json_integer_value(action);
1131         if (action_int != ACTION_POST) {
1132                 TELEMETRY_LOG_WARN("Invalid action code");
1133                 goto fail;
1134         }
1135
1136         if (strcmp(json_string_value(command), "clients") != 0) {
1137                 TELEMETRY_LOG_WARN("Invalid command");
1138                 goto fail;
1139         }
1140
1141         json_t *data = json_object_get(root, "data");
1142         if (data == NULL) {
1143                 TELEMETRY_LOG_WARN("Request does not have data field");
1144                 goto fail;
1145         }
1146
1147         json_t *client_path = json_object_get(data, "client_path");
1148         if (client_path == NULL) {
1149                 TELEMETRY_LOG_WARN("Request does not have client_path field");
1150                 goto fail;
1151         }
1152
1153         if (!json_is_string(client_path)) {
1154                 TELEMETRY_LOG_WARN("Client_path value is not a string");
1155                 goto fail;
1156         }
1157
1158         ret = rte_telemetry_register_client(telemetry,
1159                         json_string_value(client_path));
1160         if (ret < 0) {
1161                 TELEMETRY_LOG_ERR("Could not register client");
1162                 telemetry->register_fail_count++;
1163                 goto fail;
1164         }
1165
1166         return 0;
1167
1168 fail:
1169         TELEMETRY_LOG_WARN("Client attempted to register with invalid message");
1170         json_decref(root);
1171         return -1;
1172 }
1173
1174 int32_t
1175 rte_telemetry_dummy_client_socket(const char *valid_client_path)
1176 {
1177         int sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1178         struct sockaddr_un addr = {0};
1179
1180         if (sockfd < 0) {
1181                 TELEMETRY_LOG_ERR("Test socket creation failure");
1182                 return -1;
1183         }
1184
1185         addr.sun_family = AF_UNIX;
1186         strlcpy(addr.sun_path, valid_client_path, sizeof(addr.sun_path));
1187         unlink(valid_client_path);
1188
1189         if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1190                 TELEMETRY_LOG_ERR("Test socket binding failure");
1191                 return -1;
1192         }
1193
1194         if (listen(sockfd, 1) < 0) {
1195                 TELEMETRY_LOG_ERR("Listen failure");
1196                 return -1;
1197         }
1198
1199         return sockfd;
1200 }
1201
1202 int32_t __rte_experimental
1203 rte_telemetry_selftest(void)
1204 {
1205         const char *invalid_client_path = SELFTEST_INVALID_CLIENT;
1206         const char *valid_client_path = SELFTEST_VALID_CLIENT;
1207         int ret, sockfd;
1208
1209         TELEMETRY_LOG_INFO("Selftest");
1210
1211         ret = rte_telemetry_init();
1212         if (ret < 0) {
1213                 TELEMETRY_LOG_ERR("Valid initialisation test failed");
1214                 return -1;
1215         }
1216
1217         TELEMETRY_LOG_INFO("Success - Valid initialisation test passed");
1218
1219         ret = rte_telemetry_init();
1220         if (ret != -EALREADY) {
1221                 TELEMETRY_LOG_ERR("Invalid initialisation test failed");
1222                 return -1;
1223         }
1224
1225         TELEMETRY_LOG_INFO("Success - Invalid initialisation test passed");
1226
1227         ret = rte_telemetry_unregister_client(static_telemetry,
1228                         invalid_client_path);
1229         if (ret != -EPERM) {
1230                 TELEMETRY_LOG_ERR("Invalid unregister test failed");
1231                 return -1;
1232         }
1233
1234         TELEMETRY_LOG_INFO("Success - Invalid unregister test passed");
1235
1236         sockfd = rte_telemetry_dummy_client_socket(valid_client_path);
1237         if (sockfd < 0) {
1238                 TELEMETRY_LOG_ERR("Test socket creation failed");
1239                 return -1;
1240         }
1241
1242         ret = rte_telemetry_register_client(static_telemetry, valid_client_path);
1243         if (ret != 0) {
1244                 TELEMETRY_LOG_ERR("Valid register test failed: %i", ret);
1245                 return -1;
1246         }
1247
1248         accept(sockfd, NULL, NULL);
1249         TELEMETRY_LOG_INFO("Success - Valid register test passed");
1250
1251         ret = rte_telemetry_register_client(static_telemetry, valid_client_path);
1252         if (ret != -EINVAL) {
1253                 TELEMETRY_LOG_ERR("Invalid register test failed: %i", ret);
1254                 return -1;
1255         }
1256
1257         TELEMETRY_LOG_INFO("Success - Invalid register test passed");
1258
1259         ret = rte_telemetry_unregister_client(static_telemetry,
1260                 invalid_client_path);
1261         if (ret != -1) {
1262                 TELEMETRY_LOG_ERR("Invalid unregister test failed: %i", ret);
1263                 return -1;
1264         }
1265
1266         TELEMETRY_LOG_INFO("Success - Invalid unregister test passed");
1267
1268         ret = rte_telemetry_unregister_client(static_telemetry, valid_client_path);
1269         if (ret != 0) {
1270                 TELEMETRY_LOG_ERR("Valid unregister test failed: %i", ret);
1271                 return -1;
1272         }
1273
1274         TELEMETRY_LOG_INFO("Success - Valid unregister test passed");
1275
1276         ret = rte_telemetry_cleanup();
1277         if (ret < 0) {
1278                 TELEMETRY_LOG_ERR("Cleanup test failed");
1279                 return -1;
1280         }
1281
1282         TELEMETRY_LOG_INFO("Success - Valid cleanup test passed");
1283
1284         return 0;
1285 }
1286
1287 int32_t
1288 rte_telemetry_socket_messaging_testing(int index, int socket)
1289 {
1290         struct telemetry_impl *telemetry = calloc(1, sizeof(telemetry_impl));
1291         int fd, bad_send_fd, send_fd, bad_fd, bad_recv_fd, recv_fd, ret;
1292
1293         if (telemetry == NULL) {
1294                 TELEMETRY_LOG_ERR("Could not initialize Telemetry API");
1295                 return -1;
1296         }
1297
1298         telemetry->server_fd = socket;
1299         telemetry->reg_index = index;
1300         TELEMETRY_LOG_INFO("Beginning Telemetry socket message Selftest");
1301         rte_telemetry_socket_test_setup(telemetry, &send_fd, &recv_fd);
1302         TELEMETRY_LOG_INFO("Register valid client test");
1303
1304         ret = rte_telemetry_socket_register_test(telemetry, &fd, send_fd,
1305                 recv_fd);
1306         if (ret < 0) {
1307                 TELEMETRY_LOG_ERR("Register valid client test failed!");
1308                 free(telemetry);
1309                 return -1;
1310         }
1311
1312         TELEMETRY_LOG_INFO("Success - Register valid client test passed!");
1313
1314         TELEMETRY_LOG_INFO("Register invalid/same client test");
1315         ret = rte_telemetry_socket_test_setup(telemetry, &bad_send_fd,
1316                 &bad_recv_fd);
1317         ret = rte_telemetry_socket_register_test(telemetry, &bad_fd,
1318                 bad_send_fd, bad_recv_fd);
1319         if (!ret) {
1320                 TELEMETRY_LOG_ERR("Register invalid/same client test failed!");
1321                 free(telemetry);
1322                 return -1;
1323         }
1324
1325         TELEMETRY_LOG_INFO("Success - Register invalid/same client test passed!");
1326
1327         ret = rte_telemetry_json_socket_message_test(telemetry, fd);
1328         if (ret < 0) {
1329                 free(telemetry);
1330                 return -1;
1331         }
1332
1333         free(telemetry);
1334         return 0;
1335 }
1336
1337 int32_t
1338 rte_telemetry_socket_register_test(struct telemetry_impl *telemetry, int *fd,
1339         int send_fd, int recv_fd)
1340 {
1341         int ret;
1342         char good_req_string[BUF_SIZE];
1343
1344         snprintf(good_req_string, sizeof(good_req_string),
1345         "{\"action\":1,\"command\":\"clients\",\"data\":{\"client_path\""
1346                 ":\"%s\"}}", SOCKET_TEST_CLIENT_PATH);
1347
1348         listen(recv_fd, 1);
1349
1350         ret = send(send_fd, good_req_string, strlen(good_req_string), 0);
1351         if (ret < 0) {
1352                 TELEMETRY_LOG_ERR("Could not send message over socket");
1353                 return -1;
1354         }
1355
1356         rte_telemetry_run(telemetry);
1357
1358         if (telemetry->register_fail_count != 0)
1359                 return -1;
1360
1361         *fd = accept(recv_fd, NULL, NULL);
1362
1363         return 0;
1364 }
1365
1366 int32_t
1367 rte_telemetry_socket_test_setup(struct telemetry_impl *telemetry, int *send_fd,
1368         int *recv_fd)
1369 {
1370         int ret;
1371         const char *client_path = SOCKET_TEST_CLIENT_PATH;
1372         char socket_path[BUF_SIZE];
1373         struct sockaddr_un addr = {0};
1374         struct sockaddr_un addrs = {0};
1375         *send_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1376         *recv_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1377
1378         listen(telemetry->server_fd, 5);
1379         addr.sun_family = AF_UNIX;
1380         rte_telemetry_get_runtime_dir(socket_path, sizeof(socket_path));
1381         strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
1382
1383         ret = connect(*send_fd, (struct sockaddr *) &addr, sizeof(addr));
1384         if (ret < 0) {
1385                 TELEMETRY_LOG_ERR("Could not connect socket");
1386                 return -1;
1387         }
1388
1389         telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL);
1390
1391         addrs.sun_family = AF_UNIX;
1392         strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path));
1393         unlink(client_path);
1394
1395         ret = bind(*recv_fd, (struct sockaddr *)&addrs, sizeof(addrs));
1396         if (ret < 0) {
1397                 TELEMETRY_LOG_ERR("Could not bind socket");
1398                 return -1;
1399         }
1400
1401         return 0;
1402 }
1403
1404 static int32_t
1405 rte_telemetry_stat_parse(char *buf, struct json_data *json_data_struct)
1406 {
1407         json_error_t error;
1408         json_t *root = json_loads(buf, 0, &error);
1409         int arraylen, i;
1410         json_t *status, *dataArray, *port, *stats, *name, *value, *dataArrayObj,
1411                *statsArrayObj;
1412
1413         stats = NULL;
1414         port = NULL;
1415         name = NULL;
1416
1417         if (buf == NULL) {
1418                 TELEMETRY_LOG_ERR("JSON message is NULL");
1419                 return -EINVAL;
1420         }
1421
1422         if (root == NULL) {
1423                 TELEMETRY_LOG_ERR("Could not load JSON object from data passed in : %s",
1424                                 error.text);
1425                 return -EPERM;
1426         } else if (!json_is_object(root)) {
1427                 TELEMETRY_LOG_ERR("JSON Request is not a JSON object");
1428                 json_decref(root);
1429                 return -EINVAL;
1430         }
1431
1432         status = json_object_get(root, "status_code");
1433         if (!status) {
1434                 TELEMETRY_LOG_ERR("Request does not have status field");
1435                 return -EINVAL;
1436         } else if (!json_is_string(status)) {
1437                 TELEMETRY_LOG_ERR("Status value is not a string");
1438                 return -EINVAL;
1439         }
1440
1441         json_data_struct->status_code = strdup(json_string_value(status));
1442
1443         dataArray = json_object_get(root, "data");
1444         if (dataArray == NULL) {
1445                 TELEMETRY_LOG_ERR("Request does not have data field");
1446                 return -EINVAL;
1447         }
1448
1449         arraylen = json_array_size(dataArray);
1450         if (arraylen == 0) {
1451                 json_data_struct->data = "null";
1452                 return -EINVAL;
1453         }
1454
1455         for (i = 0; i < arraylen; i++) {
1456                 dataArrayObj = json_array_get(dataArray, i);
1457                 port = json_object_get(dataArrayObj, "port");
1458                 stats = json_object_get(dataArrayObj, "stats");
1459         }
1460
1461         if (port == NULL) {
1462                 TELEMETRY_LOG_ERR("Request does not have port field");
1463                 return -EINVAL;
1464         }
1465
1466         if (!json_is_integer(port)) {
1467                 TELEMETRY_LOG_ERR("Port value is not an integer");
1468                 return -EINVAL;
1469         }
1470
1471         json_data_struct->port = json_integer_value(port);
1472
1473         if (stats == NULL) {
1474                 TELEMETRY_LOG_ERR("Request does not have stats field");
1475                 return -EINVAL;
1476         }
1477
1478         arraylen = json_array_size(stats);
1479         for (i = 0; i < arraylen; i++) {
1480                 statsArrayObj = json_array_get(stats, i);
1481                 name = json_object_get(statsArrayObj, "name");
1482                 value = json_object_get(statsArrayObj, "value");
1483         }
1484
1485         if (name == NULL) {
1486                 TELEMETRY_LOG_ERR("Request does not have name field");
1487                 return -EINVAL;
1488         }
1489
1490         if (!json_is_string(name)) {
1491                 TELEMETRY_LOG_ERR("Stat name value is not a string");
1492                 return -EINVAL;
1493         }
1494
1495         json_data_struct->stat_name = strdup(json_string_value(name));
1496
1497         if (value == NULL) {
1498                 TELEMETRY_LOG_ERR("Request does not have value field");
1499                 return -EINVAL;
1500         }
1501
1502         if (!json_is_integer(value)) {
1503                 TELEMETRY_LOG_ERR("Stat value is not an integer");
1504                 return -EINVAL;
1505         }
1506
1507         json_data_struct->stat_value = json_integer_value(value);
1508
1509         return 0;
1510 }
1511
1512 static void
1513 rte_telemetry_free_test_data(struct json_data *data)
1514 {
1515         free(data->status_code);
1516         free(data->stat_name);
1517         free(data);
1518 }
1519
1520 int32_t
1521 rte_telemetry_valid_json_test(struct telemetry_impl *telemetry, int fd)
1522 {
1523         int ret;
1524         int port = 0;
1525         int value = 0;
1526         int fail_count = 0;
1527         int buffer_read = 0;
1528         char buf[BUF_SIZE];
1529         struct json_data *data_struct;
1530         errno = 0;
1531         const char *status = "Status OK: 200";
1532         const char *name = "rx_good_packets";
1533         const char *valid_json_message = "{\"action\":0,\"command\":"
1534         "\"ports_stats_values_by_name\",\"data\":{\"ports\""
1535         ":[0],\"stats\":[\"rx_good_packets\"]}}";
1536
1537         ret = send(fd, valid_json_message, strlen(valid_json_message), 0);
1538         if (ret < 0) {
1539                 TELEMETRY_LOG_ERR("Could not send message over socket");
1540                 return -1;
1541         }
1542
1543         rte_telemetry_run(telemetry);
1544         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1545
1546         if (buffer_read == -1) {
1547                 TELEMETRY_LOG_ERR("Read error");
1548                 return -1;
1549         }
1550
1551         buf[buffer_read] = '\0';
1552         data_struct = calloc(1, sizeof(struct json_data));
1553         ret = rte_telemetry_stat_parse(buf, data_struct);
1554
1555         if (ret < 0) {
1556                 TELEMETRY_LOG_ERR("Could not parse stats");
1557                 fail_count++;
1558         }
1559
1560         if (strcmp(data_struct->status_code, status) != 0) {
1561                 TELEMETRY_LOG_ERR("Status code is invalid");
1562                 fail_count++;
1563         }
1564
1565         if (data_struct->port != port) {
1566                 TELEMETRY_LOG_ERR("Port is invalid");
1567                 fail_count++;
1568         }
1569
1570         if (strcmp(data_struct->stat_name, name) != 0) {
1571                 TELEMETRY_LOG_ERR("Stat name is invalid");
1572                 fail_count++;
1573         }
1574
1575         if (data_struct->stat_value != value) {
1576                 TELEMETRY_LOG_ERR("Stat value is invalid");
1577                 fail_count++;
1578         }
1579
1580         rte_telemetry_free_test_data(data_struct);
1581         if (fail_count > 0)
1582                 return -1;
1583
1584         TELEMETRY_LOG_INFO("Success - Passed valid JSON message test passed");
1585
1586         return 0;
1587 }
1588
1589 int32_t
1590 rte_telemetry_invalid_json_test(struct telemetry_impl *telemetry, int fd)
1591 {
1592         int ret;
1593         char buf[BUF_SIZE];
1594         int fail_count = 0;
1595         const char *invalid_json = "{]";
1596         const char *status = "Status Error: Unknown";
1597         const char *data = "null";
1598         struct json_data *data_struct;
1599         int buffer_read = 0;
1600         errno = 0;
1601
1602         ret = send(fd, invalid_json, strlen(invalid_json), 0);
1603         if (ret < 0) {
1604                 TELEMETRY_LOG_ERR("Could not send message over socket");
1605                 return -1;
1606         }
1607
1608         rte_telemetry_run(telemetry);
1609         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1610
1611         if (buffer_read == -1) {
1612                 TELEMETRY_LOG_ERR("Read error");
1613                 return -1;
1614         }
1615
1616         buf[buffer_read] = '\0';
1617
1618         data_struct = calloc(1, sizeof(struct json_data));
1619         ret = rte_telemetry_stat_parse(buf, data_struct);
1620
1621         if (ret < 0)
1622                 TELEMETRY_LOG_ERR("Could not parse stats");
1623
1624         if (strcmp(data_struct->status_code, status) != 0) {
1625                 TELEMETRY_LOG_ERR("Status code is invalid");
1626                 fail_count++;
1627         }
1628
1629         if (strcmp(data_struct->data, data) != 0) {
1630                 TELEMETRY_LOG_ERR("Data status is invalid");
1631                 fail_count++;
1632         }
1633
1634         rte_telemetry_free_test_data(data_struct);
1635         if (fail_count > 0)
1636                 return -1;
1637
1638         TELEMETRY_LOG_INFO("Success - Passed invalid JSON message test");
1639
1640         return 0;
1641 }
1642
1643 int32_t
1644 rte_telemetry_json_contents_test(struct telemetry_impl *telemetry, int fd)
1645 {
1646         int ret;
1647         char buf[BUF_SIZE];
1648         int fail_count = 0;
1649         char *status = "Status Error: Invalid Argument 404";
1650         char *data = "null";
1651         struct json_data *data_struct;
1652         const char *invalid_contents = "{\"action\":0,\"command\":"
1653         "\"ports_stats_values_by_name\",\"data\":{\"ports\""
1654         ":[0],\"stats\":[\"some_invalid_param\","
1655         "\"another_invalid_param\"]}}";
1656         int buffer_read = 0;
1657         errno = 0;
1658
1659         ret = send(fd, invalid_contents, strlen(invalid_contents), 0);
1660         if (ret < 0) {
1661                 TELEMETRY_LOG_ERR("Could not send message over socket");
1662                 return -1;
1663         }
1664
1665         rte_telemetry_run(telemetry);
1666         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1667
1668         if (buffer_read == -1) {
1669                 TELEMETRY_LOG_ERR("Read error");
1670                 return -1;
1671         }
1672
1673         buf[buffer_read] = '\0';
1674         data_struct = calloc(1, sizeof(struct json_data));
1675         ret = rte_telemetry_stat_parse(buf, data_struct);
1676
1677         if (ret < 0)
1678                 TELEMETRY_LOG_ERR("Could not parse stats");
1679
1680         if (strcmp(data_struct->status_code, status) != 0) {
1681                 TELEMETRY_LOG_ERR("Status code is invalid");
1682                 fail_count++;
1683         }
1684
1685         if (strcmp(data_struct->data, data) != 0) {
1686                 TELEMETRY_LOG_ERR("Data status is invalid");
1687                 fail_count++;
1688         }
1689
1690         rte_telemetry_free_test_data(data_struct);
1691         if (fail_count > 0)
1692                 return -1;
1693
1694         TELEMETRY_LOG_INFO("Success - Passed invalid JSON content test");
1695
1696         return 0;
1697 }
1698
1699 int32_t
1700 rte_telemetry_json_empty_test(struct telemetry_impl *telemetry, int fd)
1701 {
1702         int ret;
1703         char buf[BUF_SIZE];
1704         int fail_count = 0;
1705         const char *status = "Status Error: Invalid Argument 404";
1706         char *data = "null";
1707         struct json_data *data_struct;
1708         const char *empty_json  = "{}";
1709         int buffer_read = 0;
1710         errno = 0;
1711
1712         ret = (send(fd, empty_json, strlen(empty_json), 0));
1713         if (ret < 0) {
1714                 TELEMETRY_LOG_ERR("Could not send message over socket");
1715                 return -1;
1716         }
1717
1718         rte_telemetry_run(telemetry);
1719         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1720
1721         if (buffer_read == -1) {
1722                 TELEMETRY_LOG_ERR("Read error");
1723                 return -1;
1724         }
1725
1726         buf[buffer_read] = '\0';
1727         data_struct = calloc(1, sizeof(struct json_data));
1728         ret = rte_telemetry_stat_parse(buf, data_struct);
1729
1730         if (ret < 0)
1731                 TELEMETRY_LOG_ERR("Could not parse stats");
1732
1733         if (strcmp(data_struct->status_code, status) != 0) {
1734                 TELEMETRY_LOG_ERR("Status code is invalid");
1735                 fail_count++;
1736         }
1737
1738         if (strcmp(data_struct->data, data) != 0) {
1739                 TELEMETRY_LOG_ERR("Data status is invalid");
1740                 fail_count++;
1741         }
1742
1743         rte_telemetry_free_test_data(data_struct);
1744
1745         if (fail_count > 0)
1746                 return -1;
1747
1748         TELEMETRY_LOG_INFO("Success - Passed JSON empty message test");
1749
1750         return 0;
1751 }
1752
1753 int32_t
1754 rte_telemetry_json_socket_message_test(struct telemetry_impl *telemetry, int fd)
1755 {
1756         uint16_t i;
1757         int ret, fail_count;
1758
1759         fail_count = 0;
1760         struct telemetry_message_test socket_json_tests[] = {
1761                 {.test_name = "Invalid JSON test",
1762                         .test_func_ptr = rte_telemetry_invalid_json_test},
1763                 {.test_name = "Valid JSON test",
1764                         .test_func_ptr = rte_telemetry_valid_json_test},
1765                 {.test_name = "JSON contents test",
1766                         .test_func_ptr = rte_telemetry_json_contents_test},
1767                 {.test_name = "JSON empty tests",
1768                         .test_func_ptr = rte_telemetry_json_empty_test}
1769                 };
1770
1771 #define NUM_TESTS RTE_DIM(socket_json_tests)
1772
1773         for (i = 0; i < NUM_TESTS; i++) {
1774                 TELEMETRY_LOG_INFO("%s", socket_json_tests[i].test_name);
1775                 ret = (socket_json_tests[i].test_func_ptr)
1776                         (telemetry, fd);
1777                 if (ret < 0) {
1778                         TELEMETRY_LOG_ERR("%s failed",
1779                                         socket_json_tests[i].test_name);
1780                         fail_count++;
1781                 }
1782         }
1783
1784         if (fail_count > 0) {
1785                 TELEMETRY_LOG_ERR("Failed %i JSON socket message test(s)",
1786                                 fail_count);
1787                 return -1;
1788         }
1789
1790         TELEMETRY_LOG_INFO("Success - All JSON tests passed");
1791
1792         return 0;
1793 }
1794
1795 int telemetry_log_level;
1796
1797 static struct rte_option option = {
1798         .opt_str = "--telemetry",
1799         .cb = &rte_telemetry_init,
1800         .enabled = 0
1801 };
1802
1803 RTE_INIT(rte_telemetry_register)
1804 {
1805         telemetry_log_level = rte_log_register("lib.telemetry");
1806         if (telemetry_log_level >= 0)
1807                 rte_log_set_level(telemetry_log_level, RTE_LOG_ERR);
1808
1809         rte_option_register(&option);
1810 }