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