New upstream version 18.11-rc1
[deb_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         int selftest = 0;
664
665         RTE_ETH_FOREACH_DEV(pid) {
666                 telemetry->reg_index = rte_telemetry_reg_ethdev_to_metrics(pid);
667                 break;
668         }
669
670         if (telemetry->reg_index < 0) {
671                 TELEMETRY_LOG_ERR("Failed to register ethdev metrics");
672                 return -1;
673         }
674
675         telemetry->metrics_register_done = 1;
676         if (selftest) {
677                 ret = rte_telemetry_socket_messaging_testing(telemetry->reg_index,
678                                 telemetry->server_fd);
679                 if (ret < 0)
680                         return -1;
681
682                 ret = rte_telemetry_parser_test(telemetry);
683                 if (ret < 0) {
684                         TELEMETRY_LOG_ERR("Parser Tests Failed");
685                         return -1;
686                 }
687
688                 TELEMETRY_LOG_INFO("Success - All Parser Tests Passed");
689         }
690
691         return 0;
692 }
693
694 static int32_t
695 rte_telemetry_read_client(struct telemetry_impl *telemetry)
696 {
697         char buf[BUF_SIZE];
698         int ret, buffer_read;
699
700         buffer_read = read(telemetry->accept_fd, buf, BUF_SIZE-1);
701
702         if (buffer_read == -1) {
703                 TELEMETRY_LOG_ERR("Read error");
704                 return -1;
705         } else if (buffer_read == 0) {
706                 goto close_socket;
707         } else {
708                 buf[buffer_read] = '\0';
709                 ret = rte_telemetry_parse_client_message(telemetry, buf);
710                 if (ret < 0)
711                         TELEMETRY_LOG_WARN("Parse message failed");
712                 goto close_socket;
713         }
714
715 close_socket:
716         if (close(telemetry->accept_fd) < 0) {
717                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
718                 free(telemetry);
719                 return -EPERM;
720         }
721         telemetry->accept_fd = 0;
722
723         return 0;
724 }
725
726 static int32_t
727 rte_telemetry_accept_new_client(struct telemetry_impl *telemetry)
728 {
729         int ret;
730
731         if (telemetry->accept_fd <= 0) {
732                 ret = listen(telemetry->server_fd, 1);
733                 if (ret < 0) {
734                         TELEMETRY_LOG_ERR("Listening error with server fd");
735                         return -1;
736                 }
737
738                 telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL);
739                 if (telemetry->accept_fd >= 0 &&
740                         telemetry->metrics_register_done == 0) {
741                         ret = rte_telemetry_initial_accept(telemetry);
742                         if (ret < 0) {
743                                 TELEMETRY_LOG_ERR("Failed to run initial configurations/tests");
744                                 return -1;
745                         }
746                 }
747         } else {
748                 ret = rte_telemetry_read_client(telemetry);
749                 if (ret < 0) {
750                         TELEMETRY_LOG_ERR("Failed to read socket buffer");
751                         return -1;
752                 }
753         }
754
755         return 0;
756 }
757
758 static int32_t
759 rte_telemetry_read_client_sockets(struct telemetry_impl *telemetry)
760 {
761         int ret;
762         telemetry_client *client;
763         char client_buf[BUF_SIZE];
764         int bytes;
765
766         TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
767                 bytes = read(client->fd, client_buf, BUF_SIZE-1);
768
769                 if (bytes > 0) {
770                         client_buf[bytes] = '\0';
771                         telemetry->request_client = client;
772                         ret = rte_telemetry_parse(telemetry, client_buf);
773                         if (ret < 0) {
774                                 TELEMETRY_LOG_WARN("Parse socket input failed: %i",
775                                                 ret);
776                                 return -1;
777                         }
778                 }
779         }
780
781         return 0;
782 }
783
784 static int32_t
785 rte_telemetry_run(void *userdata)
786 {
787         int ret;
788         struct telemetry_impl *telemetry = userdata;
789
790         if (telemetry == NULL) {
791                 TELEMETRY_LOG_WARN("TELEMETRY could not be initialised");
792                 return -1;
793         }
794
795         ret = rte_telemetry_accept_new_client(telemetry);
796         if (ret < 0) {
797                 TELEMETRY_LOG_ERR("Accept and read new client failed");
798                 return -1;
799         }
800
801         ret = rte_telemetry_read_client_sockets(telemetry);
802         if (ret < 0) {
803                 TELEMETRY_LOG_ERR("Client socket read failed");
804                 return -1;
805         }
806
807         return 0;
808 }
809
810 static void
811 *rte_telemetry_run_thread_func(void *userdata)
812 {
813         int ret;
814         struct telemetry_impl *telemetry = userdata;
815
816         if (telemetry == NULL) {
817                 TELEMETRY_LOG_ERR("%s passed a NULL instance", __func__);
818                 pthread_exit(0);
819         }
820
821         while (telemetry->thread_status) {
822                 rte_telemetry_run(telemetry);
823                 ret = usleep(SLEEP_TIME);
824                 if (ret < 0)
825                         TELEMETRY_LOG_ERR("Calling thread could not be put to sleep");
826         }
827         pthread_exit(0);
828 }
829
830 static int32_t
831 rte_telemetry_set_socket_nonblock(int fd)
832 {
833         int flags;
834
835         if (fd < 0) {
836                 TELEMETRY_LOG_ERR("Invalid fd provided");
837                 return -1;
838         }
839
840         flags = fcntl(fd, F_GETFL, 0);
841         if (flags < 0)
842                 flags = 0;
843
844         return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
845 }
846
847 static int32_t
848 rte_telemetry_create_socket(struct telemetry_impl *telemetry)
849 {
850         int ret;
851         struct sockaddr_un addr;
852         char socket_path[BUF_SIZE];
853
854         if (telemetry == NULL)
855                 return -1;
856
857         telemetry->server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
858         if (telemetry->server_fd == -1) {
859                 TELEMETRY_LOG_ERR("Failed to open socket");
860                 return -1;
861         }
862
863         ret  = rte_telemetry_set_socket_nonblock(telemetry->server_fd);
864         if (ret < 0) {
865                 TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK");
866                 goto close_socket;
867         }
868
869         addr.sun_family = AF_UNIX;
870         rte_telemetry_get_runtime_dir(socket_path, sizeof(socket_path));
871         strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
872         unlink(socket_path);
873
874         if (bind(telemetry->server_fd, (struct sockaddr *)&addr,
875                 sizeof(addr)) < 0) {
876                 TELEMETRY_LOG_ERR("Socket binding error");
877                 goto close_socket;
878         }
879
880         return 0;
881
882 close_socket:
883         if (close(telemetry->server_fd) < 0) {
884                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
885                 return -EPERM;
886         }
887
888         return -1;
889 }
890
891 int32_t __rte_experimental
892 rte_telemetry_init()
893 {
894         int ret;
895         pthread_attr_t attr;
896         const char *telemetry_ctrl_thread = "telemetry";
897
898         if (static_telemetry) {
899                 TELEMETRY_LOG_WARN("TELEMETRY structure already initialised");
900                 return -EALREADY;
901         }
902
903         static_telemetry = calloc(1, sizeof(struct telemetry_impl));
904         if (static_telemetry == NULL) {
905                 TELEMETRY_LOG_ERR("Memory could not be allocated");
906                 return -ENOMEM;
907         }
908
909         static_telemetry->socket_id = rte_socket_id();
910         rte_metrics_init(static_telemetry->socket_id);
911
912         ret = pthread_attr_init(&attr);
913         if (ret != 0) {
914                 TELEMETRY_LOG_ERR("Pthread attribute init failed");
915                 return -EPERM;
916         }
917
918         ret = rte_telemetry_create_socket(static_telemetry);
919         if (ret < 0) {
920                 ret = rte_telemetry_cleanup();
921                 if (ret < 0)
922                         TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
923                 return -EPERM;
924         }
925         TAILQ_INIT(&static_telemetry->client_list_head);
926
927         ret = rte_ctrl_thread_create(&static_telemetry->thread_id,
928                 telemetry_ctrl_thread, &attr, rte_telemetry_run_thread_func,
929                 (void *)static_telemetry);
930         static_telemetry->thread_status = 1;
931
932         if (ret < 0) {
933                 ret = rte_telemetry_cleanup();
934                 if (ret < 0)
935                         TELEMETRY_LOG_ERR("TELEMETRY cleanup failed");
936                 return -EPERM;
937         }
938
939         return 0;
940 }
941
942 static int32_t
943 rte_telemetry_client_cleanup(struct telemetry_client *client)
944 {
945         int ret;
946
947         ret = close(client->fd);
948         free(client->file_path);
949         free(client);
950
951         if (ret < 0) {
952                 TELEMETRY_LOG_ERR("Close client socket failed");
953                 return -EPERM;
954         }
955
956         return 0;
957 }
958
959 int32_t __rte_experimental
960 rte_telemetry_cleanup(void)
961 {
962         int ret;
963         struct telemetry_impl *telemetry = static_telemetry;
964         telemetry_client *client, *temp_client;
965
966         TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
967                 temp_client) {
968                 TAILQ_REMOVE(&telemetry->client_list_head, client, client_list);
969                 ret = rte_telemetry_client_cleanup(client);
970                 if (ret < 0) {
971                         TELEMETRY_LOG_ERR("Client cleanup failed");
972                         return -EPERM;
973                 }
974         }
975
976         ret = close(telemetry->server_fd);
977         if (ret < 0) {
978                 TELEMETRY_LOG_ERR("Close TELEMETRY socket failed");
979                 free(telemetry);
980                 return -EPERM;
981         }
982
983         telemetry->thread_status = 0;
984         pthread_join(telemetry->thread_id, NULL);
985         free(telemetry);
986         static_telemetry = NULL;
987
988         return 0;
989 }
990
991 int32_t
992 rte_telemetry_unregister_client(struct telemetry_impl *telemetry,
993         const char *client_path)
994 {
995         int ret;
996         telemetry_client *client, *temp_client;
997
998         if (telemetry == NULL) {
999                 TELEMETRY_LOG_WARN("TELEMETRY is not initialised");
1000                 return -ENODEV;
1001         }
1002
1003         if (client_path == NULL) {
1004                 TELEMETRY_LOG_ERR("Invalid client path");
1005                 goto einval_fail;
1006         }
1007
1008         if (TAILQ_EMPTY(&telemetry->client_list_head)) {
1009                 TELEMETRY_LOG_ERR("There are no clients currently registered");
1010                 return -EPERM;
1011         }
1012
1013         TAILQ_FOREACH_SAFE(client, &telemetry->client_list_head, client_list,
1014                         temp_client) {
1015                 if (strcmp(client_path, client->file_path) == 0) {
1016                         TAILQ_REMOVE(&telemetry->client_list_head, client,
1017                                 client_list);
1018                         ret = rte_telemetry_client_cleanup(client);
1019
1020                         if (ret < 0) {
1021                                 TELEMETRY_LOG_ERR("Client cleanup failed");
1022                                 return -EPERM;
1023                         }
1024
1025                         return 0;
1026                 }
1027         }
1028
1029         TELEMETRY_LOG_WARN("Couldn't find client, possibly not registered yet.");
1030         return -1;
1031
1032 einval_fail:
1033         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
1034         if (ret < 0)
1035                 TELEMETRY_LOG_ERR("Could not send error");
1036         return -EINVAL;
1037 }
1038
1039 int32_t
1040 rte_telemetry_register_client(struct telemetry_impl *telemetry,
1041         const char *client_path)
1042 {
1043         int ret, fd;
1044         struct sockaddr_un addrs;
1045
1046         if (telemetry == NULL) {
1047                 TELEMETRY_LOG_ERR("Could not initialize TELEMETRY API");
1048                 return -ENODEV;
1049         }
1050
1051         if (client_path == NULL) {
1052                 TELEMETRY_LOG_ERR("Invalid client path");
1053                 return -EINVAL;
1054         }
1055
1056         telemetry_client *client;
1057         TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) {
1058                 if (strcmp(client_path, client->file_path) == 0) {
1059                         TELEMETRY_LOG_WARN("'%s' already registered",
1060                                         client_path);
1061                         return -EINVAL;
1062                 }
1063         }
1064
1065         fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1066         if (fd == -1) {
1067                 TELEMETRY_LOG_ERR("Client socket error");
1068                 return -EACCES;
1069         }
1070
1071         ret = rte_telemetry_set_socket_nonblock(fd);
1072         if (ret < 0) {
1073                 TELEMETRY_LOG_ERR("Could not set socket to NONBLOCK");
1074                 return -EPERM;
1075         }
1076
1077         addrs.sun_family = AF_UNIX;
1078         strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path));
1079         telemetry_client *new_client = malloc(sizeof(telemetry_client));
1080         new_client->file_path = strdup(client_path);
1081         new_client->fd = fd;
1082
1083         if (connect(fd, (struct sockaddr *)&addrs, sizeof(addrs)) == -1) {
1084                 TELEMETRY_LOG_ERR("TELEMETRY client connect to %s didn't work",
1085                                 client_path);
1086                 ret = rte_telemetry_client_cleanup(new_client);
1087                 if (ret < 0) {
1088                         TELEMETRY_LOG_ERR("Client cleanup failed");
1089                         return -EPERM;
1090                 }
1091                 return -EINVAL;
1092         }
1093
1094         TAILQ_INSERT_HEAD(&telemetry->client_list_head, new_client, client_list);
1095
1096         return 0;
1097 }
1098
1099 int32_t
1100 rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf)
1101 {
1102         int ret, action_int;
1103         json_error_t error;
1104         json_t *root = json_loads(buf, 0, &error);
1105
1106         if (root == NULL) {
1107                 TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s",
1108                                 error.text);
1109                 goto fail;
1110         } else if (!json_is_object(root)) {
1111                 TELEMETRY_LOG_WARN("JSON Request is not a JSON object");
1112                 goto fail;
1113         }
1114
1115         json_t *action = json_object_get(root, "action");
1116         if (action == NULL) {
1117                 TELEMETRY_LOG_WARN("Request does not have action field");
1118                 goto fail;
1119         } else if (!json_is_integer(action)) {
1120                 TELEMETRY_LOG_WARN("Action value is not an integer");
1121                 goto fail;
1122         }
1123
1124         json_t *command = json_object_get(root, "command");
1125         if (command == NULL) {
1126                 TELEMETRY_LOG_WARN("Request does not have command field");
1127                 goto fail;
1128         } else if (!json_is_string(command)) {
1129                 TELEMETRY_LOG_WARN("Command value is not a string");
1130                 goto fail;
1131         }
1132
1133         action_int = json_integer_value(action);
1134         if (action_int != ACTION_POST) {
1135                 TELEMETRY_LOG_WARN("Invalid action code");
1136                 goto fail;
1137         }
1138
1139         if (strcmp(json_string_value(command), "clients") != 0) {
1140                 TELEMETRY_LOG_WARN("Invalid command");
1141                 goto fail;
1142         }
1143
1144         json_t *data = json_object_get(root, "data");
1145         if (data == NULL) {
1146                 TELEMETRY_LOG_WARN("Request does not have data field");
1147                 goto fail;
1148         }
1149
1150         json_t *client_path = json_object_get(data, "client_path");
1151         if (client_path == NULL) {
1152                 TELEMETRY_LOG_WARN("Request does not have client_path field");
1153                 goto fail;
1154         }
1155
1156         if (!json_is_string(client_path)) {
1157                 TELEMETRY_LOG_WARN("Client_path value is not a string");
1158                 goto fail;
1159         }
1160
1161         ret = rte_telemetry_register_client(telemetry,
1162                         json_string_value(client_path));
1163         if (ret < 0) {
1164                 TELEMETRY_LOG_ERR("Could not register client");
1165                 telemetry->register_fail_count++;
1166                 goto fail;
1167         }
1168
1169         return 0;
1170
1171 fail:
1172         TELEMETRY_LOG_WARN("Client attempted to register with invalid message");
1173         json_decref(root);
1174         return -1;
1175 }
1176
1177 int32_t
1178 rte_telemetry_dummy_client_socket(const char *valid_client_path)
1179 {
1180         int sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1181         struct sockaddr_un addr = {0};
1182
1183         if (sockfd < 0) {
1184                 TELEMETRY_LOG_ERR("Test socket creation failure");
1185                 return -1;
1186         }
1187
1188         addr.sun_family = AF_UNIX;
1189         strlcpy(addr.sun_path, valid_client_path, sizeof(addr.sun_path));
1190         unlink(valid_client_path);
1191
1192         if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1193                 TELEMETRY_LOG_ERR("Test socket binding failure");
1194                 return -1;
1195         }
1196
1197         if (listen(sockfd, 1) < 0) {
1198                 TELEMETRY_LOG_ERR("Listen failure");
1199                 return -1;
1200         }
1201
1202         return sockfd;
1203 }
1204
1205 int32_t __rte_experimental
1206 rte_telemetry_selftest(void)
1207 {
1208         const char *invalid_client_path = SELFTEST_INVALID_CLIENT;
1209         const char *valid_client_path = SELFTEST_VALID_CLIENT;
1210         int ret, sockfd;
1211
1212         TELEMETRY_LOG_INFO("Selftest");
1213
1214         ret = rte_telemetry_init();
1215         if (ret < 0) {
1216                 TELEMETRY_LOG_ERR("Valid initialisation test failed");
1217                 return -1;
1218         }
1219
1220         TELEMETRY_LOG_INFO("Success - Valid initialisation test passed");
1221
1222         ret = rte_telemetry_init();
1223         if (ret != -EALREADY) {
1224                 TELEMETRY_LOG_ERR("Invalid initialisation test failed");
1225                 return -1;
1226         }
1227
1228         TELEMETRY_LOG_INFO("Success - Invalid initialisation test passed");
1229
1230         ret = rte_telemetry_unregister_client(static_telemetry,
1231                         invalid_client_path);
1232         if (ret != -EPERM) {
1233                 TELEMETRY_LOG_ERR("Invalid unregister test failed");
1234                 return -1;
1235         }
1236
1237         TELEMETRY_LOG_INFO("Success - Invalid unregister test passed");
1238
1239         sockfd = rte_telemetry_dummy_client_socket(valid_client_path);
1240         if (sockfd < 0) {
1241                 TELEMETRY_LOG_ERR("Test socket creation failed");
1242                 return -1;
1243         }
1244
1245         ret = rte_telemetry_register_client(static_telemetry, valid_client_path);
1246         if (ret != 0) {
1247                 TELEMETRY_LOG_ERR("Valid register test failed: %i", ret);
1248                 return -1;
1249         }
1250
1251         accept(sockfd, NULL, NULL);
1252         TELEMETRY_LOG_INFO("Success - Valid register test passed");
1253
1254         ret = rte_telemetry_register_client(static_telemetry, valid_client_path);
1255         if (ret != -EINVAL) {
1256                 TELEMETRY_LOG_ERR("Invalid register test failed: %i", ret);
1257                 return -1;
1258         }
1259
1260         TELEMETRY_LOG_INFO("Success - Invalid register test passed");
1261
1262         ret = rte_telemetry_unregister_client(static_telemetry,
1263                 invalid_client_path);
1264         if (ret != -1) {
1265                 TELEMETRY_LOG_ERR("Invalid unregister test failed: %i", ret);
1266                 return -1;
1267         }
1268
1269         TELEMETRY_LOG_INFO("Success - Invalid unregister test passed");
1270
1271         ret = rte_telemetry_unregister_client(static_telemetry, valid_client_path);
1272         if (ret != 0) {
1273                 TELEMETRY_LOG_ERR("Valid unregister test failed: %i", ret);
1274                 return -1;
1275         }
1276
1277         TELEMETRY_LOG_INFO("Success - Valid unregister test passed");
1278
1279         ret = rte_telemetry_cleanup();
1280         if (ret < 0) {
1281                 TELEMETRY_LOG_ERR("Cleanup test failed");
1282                 return -1;
1283         }
1284
1285         TELEMETRY_LOG_INFO("Success - Valid cleanup test passed");
1286
1287         return 0;
1288 }
1289
1290 int32_t
1291 rte_telemetry_socket_messaging_testing(int index, int socket)
1292 {
1293         struct telemetry_impl *telemetry = calloc(1, sizeof(telemetry_impl));
1294         int fd, bad_send_fd, send_fd, bad_fd, bad_recv_fd, recv_fd, ret;
1295
1296         if (telemetry == NULL) {
1297                 TELEMETRY_LOG_ERR("Could not initialize Telemetry API");
1298                 return -1;
1299         }
1300
1301         telemetry->server_fd = socket;
1302         telemetry->reg_index = index;
1303         TELEMETRY_LOG_INFO("Beginning Telemetry socket message Selftest");
1304         rte_telemetry_socket_test_setup(telemetry, &send_fd, &recv_fd);
1305         TELEMETRY_LOG_INFO("Register valid client test");
1306
1307         ret = rte_telemetry_socket_register_test(telemetry, &fd, send_fd,
1308                 recv_fd);
1309         if (ret < 0) {
1310                 TELEMETRY_LOG_ERR("Register valid client test failed!");
1311                 free(telemetry);
1312                 return -1;
1313         }
1314
1315         TELEMETRY_LOG_INFO("Success - Register valid client test passed!");
1316
1317         TELEMETRY_LOG_INFO("Register invalid/same client test");
1318         ret = rte_telemetry_socket_test_setup(telemetry, &bad_send_fd,
1319                 &bad_recv_fd);
1320         ret = rte_telemetry_socket_register_test(telemetry, &bad_fd,
1321                 bad_send_fd, bad_recv_fd);
1322         if (!ret) {
1323                 TELEMETRY_LOG_ERR("Register invalid/same client test failed!");
1324                 free(telemetry);
1325                 return -1;
1326         }
1327
1328         TELEMETRY_LOG_INFO("Success - Register invalid/same client test passed!");
1329
1330         ret = rte_telemetry_json_socket_message_test(telemetry, fd);
1331         if (ret < 0) {
1332                 free(telemetry);
1333                 return -1;
1334         }
1335
1336         free(telemetry);
1337         return 0;
1338 }
1339
1340 int32_t
1341 rte_telemetry_socket_register_test(struct telemetry_impl *telemetry, int *fd,
1342         int send_fd, int recv_fd)
1343 {
1344         int ret;
1345         char good_req_string[BUF_SIZE];
1346
1347         snprintf(good_req_string, sizeof(good_req_string),
1348         "{\"action\":1,\"command\":\"clients\",\"data\":{\"client_path\""
1349                 ":\"%s\"}}", SOCKET_TEST_CLIENT_PATH);
1350
1351         listen(recv_fd, 1);
1352
1353         ret = send(send_fd, good_req_string, strlen(good_req_string), 0);
1354         if (ret < 0) {
1355                 TELEMETRY_LOG_ERR("Could not send message over socket");
1356                 return -1;
1357         }
1358
1359         rte_telemetry_run(telemetry);
1360
1361         if (telemetry->register_fail_count != 0)
1362                 return -1;
1363
1364         *fd = accept(recv_fd, NULL, NULL);
1365
1366         return 0;
1367 }
1368
1369 int32_t
1370 rte_telemetry_socket_test_setup(struct telemetry_impl *telemetry, int *send_fd,
1371         int *recv_fd)
1372 {
1373         int ret;
1374         const char *client_path = SOCKET_TEST_CLIENT_PATH;
1375         char socket_path[BUF_SIZE];
1376         struct sockaddr_un addr = {0};
1377         struct sockaddr_un addrs = {0};
1378         *send_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1379         *recv_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1380
1381         listen(telemetry->server_fd, 5);
1382         addr.sun_family = AF_UNIX;
1383         rte_telemetry_get_runtime_dir(socket_path, sizeof(socket_path));
1384         strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
1385
1386         ret = connect(*send_fd, (struct sockaddr *) &addr, sizeof(addr));
1387         if (ret < 0) {
1388                 TELEMETRY_LOG_ERR("Could not connect socket");
1389                 return -1;
1390         }
1391
1392         telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL);
1393
1394         addrs.sun_family = AF_UNIX;
1395         strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path));
1396         unlink(client_path);
1397
1398         ret = bind(*recv_fd, (struct sockaddr *)&addrs, sizeof(addrs));
1399         if (ret < 0) {
1400                 TELEMETRY_LOG_ERR("Could not bind socket");
1401                 return -1;
1402         }
1403
1404         return 0;
1405 }
1406
1407 static int32_t
1408 rte_telemetry_stat_parse(char *buf, struct json_data *json_data_struct)
1409 {
1410         json_error_t error;
1411         json_t *root = json_loads(buf, 0, &error);
1412         int arraylen, i;
1413         json_t *status, *dataArray, *port, *stats, *name, *value, *dataArrayObj,
1414                *statsArrayObj;
1415
1416         stats = NULL;
1417         port = NULL;
1418         name = NULL;
1419
1420         if (buf == NULL) {
1421                 TELEMETRY_LOG_ERR("JSON message is NULL");
1422                 return -EINVAL;
1423         }
1424
1425         if (root == NULL) {
1426                 TELEMETRY_LOG_ERR("Could not load JSON object from data passed in : %s",
1427                                 error.text);
1428                 return -EPERM;
1429         } else if (!json_is_object(root)) {
1430                 TELEMETRY_LOG_ERR("JSON Request is not a JSON object");
1431                 json_decref(root);
1432                 return -EINVAL;
1433         }
1434
1435         status = json_object_get(root, "status_code");
1436         if (!status) {
1437                 TELEMETRY_LOG_ERR("Request does not have status field");
1438                 return -EINVAL;
1439         } else if (!json_is_string(status)) {
1440                 TELEMETRY_LOG_ERR("Status value is not a string");
1441                 return -EINVAL;
1442         }
1443
1444         json_data_struct->status_code = strdup(json_string_value(status));
1445
1446         dataArray = json_object_get(root, "data");
1447         if (dataArray == NULL) {
1448                 TELEMETRY_LOG_ERR("Request does not have data field");
1449                 return -EINVAL;
1450         }
1451
1452         arraylen = json_array_size(dataArray);
1453         if (arraylen == 0) {
1454                 json_data_struct->data = "null";
1455                 return -EINVAL;
1456         }
1457
1458         for (i = 0; i < arraylen; i++) {
1459                 dataArrayObj = json_array_get(dataArray, i);
1460                 port = json_object_get(dataArrayObj, "port");
1461                 stats = json_object_get(dataArrayObj, "stats");
1462         }
1463
1464         if (port == NULL) {
1465                 TELEMETRY_LOG_ERR("Request does not have port field");
1466                 return -EINVAL;
1467         }
1468
1469         if (!json_is_integer(port)) {
1470                 TELEMETRY_LOG_ERR("Port value is not an integer");
1471                 return -EINVAL;
1472         }
1473
1474         json_data_struct->port = json_integer_value(port);
1475
1476         if (stats == NULL) {
1477                 TELEMETRY_LOG_ERR("Request does not have stats field");
1478                 return -EINVAL;
1479         }
1480
1481         arraylen = json_array_size(stats);
1482         for (i = 0; i < arraylen; i++) {
1483                 statsArrayObj = json_array_get(stats, i);
1484                 name = json_object_get(statsArrayObj, "name");
1485                 value = json_object_get(statsArrayObj, "value");
1486         }
1487
1488         if (name == NULL) {
1489                 TELEMETRY_LOG_ERR("Request does not have name field");
1490                 return -EINVAL;
1491         }
1492
1493         if (!json_is_string(name)) {
1494                 TELEMETRY_LOG_ERR("Stat name value is not a string");
1495                 return -EINVAL;
1496         }
1497
1498         json_data_struct->stat_name = strdup(json_string_value(name));
1499
1500         if (value == NULL) {
1501                 TELEMETRY_LOG_ERR("Request does not have value field");
1502                 return -EINVAL;
1503         }
1504
1505         if (!json_is_integer(value)) {
1506                 TELEMETRY_LOG_ERR("Stat value is not an integer");
1507                 return -EINVAL;
1508         }
1509
1510         json_data_struct->stat_value = json_integer_value(value);
1511
1512         return 0;
1513 }
1514
1515 static void
1516 rte_telemetry_free_test_data(struct json_data *data)
1517 {
1518         free(data->status_code);
1519         free(data->stat_name);
1520         free(data);
1521 }
1522
1523 int32_t
1524 rte_telemetry_valid_json_test(struct telemetry_impl *telemetry, int fd)
1525 {
1526         int ret;
1527         int port = 0;
1528         int value = 0;
1529         int fail_count = 0;
1530         int buffer_read = 0;
1531         char buf[BUF_SIZE];
1532         struct json_data *data_struct;
1533         errno = 0;
1534         const char *status = "Status OK: 200";
1535         const char *name = "rx_good_packets";
1536         const char *valid_json_message = "{\"action\":0,\"command\":"
1537         "\"ports_stats_values_by_name\",\"data\":{\"ports\""
1538         ":[0],\"stats\":[\"rx_good_packets\"]}}";
1539
1540         ret = send(fd, valid_json_message, strlen(valid_json_message), 0);
1541         if (ret < 0) {
1542                 TELEMETRY_LOG_ERR("Could not send message over socket");
1543                 return -1;
1544         }
1545
1546         rte_telemetry_run(telemetry);
1547         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1548
1549         if (buffer_read == -1) {
1550                 TELEMETRY_LOG_ERR("Read error");
1551                 return -1;
1552         }
1553
1554         buf[buffer_read] = '\0';
1555         data_struct = calloc(1, sizeof(struct json_data));
1556         ret = rte_telemetry_stat_parse(buf, data_struct);
1557
1558         if (ret < 0) {
1559                 TELEMETRY_LOG_ERR("Could not parse stats");
1560                 fail_count++;
1561         }
1562
1563         if (strcmp(data_struct->status_code, status) != 0) {
1564                 TELEMETRY_LOG_ERR("Status code is invalid");
1565                 fail_count++;
1566         }
1567
1568         if (data_struct->port != port) {
1569                 TELEMETRY_LOG_ERR("Port is invalid");
1570                 fail_count++;
1571         }
1572
1573         if (strcmp(data_struct->stat_name, name) != 0) {
1574                 TELEMETRY_LOG_ERR("Stat name is invalid");
1575                 fail_count++;
1576         }
1577
1578         if (data_struct->stat_value != value) {
1579                 TELEMETRY_LOG_ERR("Stat value is invalid");
1580                 fail_count++;
1581         }
1582
1583         rte_telemetry_free_test_data(data_struct);
1584         if (fail_count > 0)
1585                 return -1;
1586
1587         TELEMETRY_LOG_INFO("Success - Passed valid JSON message test passed");
1588
1589         return 0;
1590 }
1591
1592 int32_t
1593 rte_telemetry_invalid_json_test(struct telemetry_impl *telemetry, int fd)
1594 {
1595         int ret;
1596         char buf[BUF_SIZE];
1597         int fail_count = 0;
1598         const char *invalid_json = "{]";
1599         const char *status = "Status Error: Unknown";
1600         const char *data = "null";
1601         struct json_data *data_struct;
1602         int buffer_read = 0;
1603         errno = 0;
1604
1605         ret = send(fd, invalid_json, strlen(invalid_json), 0);
1606         if (ret < 0) {
1607                 TELEMETRY_LOG_ERR("Could not send message over socket");
1608                 return -1;
1609         }
1610
1611         rte_telemetry_run(telemetry);
1612         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1613
1614         if (buffer_read == -1) {
1615                 TELEMETRY_LOG_ERR("Read error");
1616                 return -1;
1617         }
1618
1619         buf[buffer_read] = '\0';
1620
1621         data_struct = calloc(1, sizeof(struct json_data));
1622         ret = rte_telemetry_stat_parse(buf, data_struct);
1623
1624         if (ret < 0)
1625                 TELEMETRY_LOG_ERR("Could not parse stats");
1626
1627         if (strcmp(data_struct->status_code, status) != 0) {
1628                 TELEMETRY_LOG_ERR("Status code is invalid");
1629                 fail_count++;
1630         }
1631
1632         if (strcmp(data_struct->data, data) != 0) {
1633                 TELEMETRY_LOG_ERR("Data status is invalid");
1634                 fail_count++;
1635         }
1636
1637         rte_telemetry_free_test_data(data_struct);
1638         if (fail_count > 0)
1639                 return -1;
1640
1641         TELEMETRY_LOG_INFO("Success - Passed invalid JSON message test");
1642
1643         return 0;
1644 }
1645
1646 int32_t
1647 rte_telemetry_json_contents_test(struct telemetry_impl *telemetry, int fd)
1648 {
1649         int ret;
1650         char buf[BUF_SIZE];
1651         int fail_count = 0;
1652         char *status = "Status Error: Invalid Argument 404";
1653         char *data = "null";
1654         struct json_data *data_struct;
1655         const char *invalid_contents = "{\"action\":0,\"command\":"
1656         "\"ports_stats_values_by_name\",\"data\":{\"ports\""
1657         ":[0],\"stats\":[\"some_invalid_param\","
1658         "\"another_invalid_param\"]}}";
1659         int buffer_read = 0;
1660         errno = 0;
1661
1662         ret = send(fd, invalid_contents, strlen(invalid_contents), 0);
1663         if (ret < 0) {
1664                 TELEMETRY_LOG_ERR("Could not send message over socket");
1665                 return -1;
1666         }
1667
1668         rte_telemetry_run(telemetry);
1669         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1670
1671         if (buffer_read == -1) {
1672                 TELEMETRY_LOG_ERR("Read error");
1673                 return -1;
1674         }
1675
1676         buf[buffer_read] = '\0';
1677         data_struct = calloc(1, sizeof(struct json_data));
1678         ret = rte_telemetry_stat_parse(buf, data_struct);
1679
1680         if (ret < 0)
1681                 TELEMETRY_LOG_ERR("Could not parse stats");
1682
1683         if (strcmp(data_struct->status_code, status) != 0) {
1684                 TELEMETRY_LOG_ERR("Status code is invalid");
1685                 fail_count++;
1686         }
1687
1688         if (strcmp(data_struct->data, data) != 0) {
1689                 TELEMETRY_LOG_ERR("Data status is invalid");
1690                 fail_count++;
1691         }
1692
1693         rte_telemetry_free_test_data(data_struct);
1694         if (fail_count > 0)
1695                 return -1;
1696
1697         TELEMETRY_LOG_INFO("Success - Passed invalid JSON content test");
1698
1699         return 0;
1700 }
1701
1702 int32_t
1703 rte_telemetry_json_empty_test(struct telemetry_impl *telemetry, int fd)
1704 {
1705         int ret;
1706         char buf[BUF_SIZE];
1707         int fail_count = 0;
1708         const char *status = "Status Error: Invalid Argument 404";
1709         char *data = "null";
1710         struct json_data *data_struct;
1711         const char *empty_json  = "{}";
1712         int buffer_read = 0;
1713         errno = 0;
1714
1715         ret = (send(fd, empty_json, strlen(empty_json), 0));
1716         if (ret < 0) {
1717                 TELEMETRY_LOG_ERR("Could not send message over socket");
1718                 return -1;
1719         }
1720
1721         rte_telemetry_run(telemetry);
1722         buffer_read = recv(fd, buf, BUF_SIZE-1, 0);
1723
1724         if (buffer_read == -1) {
1725                 TELEMETRY_LOG_ERR("Read error");
1726                 return -1;
1727         }
1728
1729         buf[buffer_read] = '\0';
1730         data_struct = calloc(1, sizeof(struct json_data));
1731         ret = rte_telemetry_stat_parse(buf, data_struct);
1732
1733         if (ret < 0)
1734                 TELEMETRY_LOG_ERR("Could not parse stats");
1735
1736         if (strcmp(data_struct->status_code, status) != 0) {
1737                 TELEMETRY_LOG_ERR("Status code is invalid");
1738                 fail_count++;
1739         }
1740
1741         if (strcmp(data_struct->data, data) != 0) {
1742                 TELEMETRY_LOG_ERR("Data status is invalid");
1743                 fail_count++;
1744         }
1745
1746         rte_telemetry_free_test_data(data_struct);
1747
1748         if (fail_count > 0)
1749                 return -1;
1750
1751         TELEMETRY_LOG_INFO("Success - Passed JSON empty message test");
1752
1753         return 0;
1754 }
1755
1756 int32_t
1757 rte_telemetry_json_socket_message_test(struct telemetry_impl *telemetry, int fd)
1758 {
1759         uint16_t i;
1760         int ret, fail_count;
1761
1762         fail_count = 0;
1763         struct telemetry_message_test socket_json_tests[] = {
1764                 {.test_name = "Invalid JSON test",
1765                         .test_func_ptr = rte_telemetry_invalid_json_test},
1766                 {.test_name = "Valid JSON test",
1767                         .test_func_ptr = rte_telemetry_valid_json_test},
1768                 {.test_name = "JSON contents test",
1769                         .test_func_ptr = rte_telemetry_json_contents_test},
1770                 {.test_name = "JSON empty tests",
1771                         .test_func_ptr = rte_telemetry_json_empty_test}
1772                 };
1773
1774 #define NUM_TESTS RTE_DIM(socket_json_tests)
1775
1776         for (i = 0; i < NUM_TESTS; i++) {
1777                 TELEMETRY_LOG_INFO("%s", socket_json_tests[i].test_name);
1778                 ret = (socket_json_tests[i].test_func_ptr)
1779                         (telemetry, fd);
1780                 if (ret < 0) {
1781                         TELEMETRY_LOG_ERR("%s failed",
1782                                         socket_json_tests[i].test_name);
1783                         fail_count++;
1784                 }
1785         }
1786
1787         if (fail_count > 0) {
1788                 TELEMETRY_LOG_ERR("Failed %i JSON socket message test(s)",
1789                                 fail_count);
1790                 return -1;
1791         }
1792
1793         TELEMETRY_LOG_INFO("Success - All JSON tests passed");
1794
1795         return 0;
1796 }
1797
1798 int telemetry_log_level;
1799
1800 static struct rte_option option = {
1801         .opt_str = "--telemetry",
1802         .cb = &rte_telemetry_init,
1803         .enabled = 0
1804 };
1805
1806 RTE_INIT(rte_telemetry_register)
1807 {
1808         telemetry_log_level = rte_log_register("lib.telemetry");
1809         if (telemetry_log_level >= 0)
1810                 rte_log_set_level(telemetry_log_level, RTE_LOG_ERR);
1811
1812         rte_option_register(&option);
1813 }