remove experimental tags from all symbol definitions
[dpdk.git] / lib / librte_telemetry / rte_telemetry_parser.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <jansson.h>
10
11 #include <rte_metrics.h>
12 #include <rte_common.h>
13 #include <rte_ethdev.h>
14
15 #include "rte_telemetry_internal.h"
16 #include "rte_telemetry_parser.h"
17
18 typedef int (*command_func)(struct telemetry_impl *, int, json_t *);
19
20 struct rte_telemetry_command {
21         char *text;
22         command_func fn;
23 } command;
24
25 static int32_t
26 rte_telemetry_command_clients(struct telemetry_impl *telemetry, int action,
27         json_t *data)
28 {
29         int ret;
30
31         if (telemetry == NULL) {
32                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
33                 return -1;
34         }
35
36         if (action != ACTION_DELETE) {
37                 TELEMETRY_LOG_WARN("Invalid action for this command");
38                 goto einval_fail;
39         }
40
41         if (!json_is_object(data)) {
42                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
43                 goto einval_fail;
44         }
45
46         json_t *client_path = json_object_get(data, "client_path");
47         if (!json_is_string(client_path)) {
48                 TELEMETRY_LOG_WARN("Command value is not a string");
49                 goto einval_fail;
50         }
51
52         ret = rte_telemetry_unregister_client(telemetry,
53                         json_string_value(client_path));
54         if (ret < 0) {
55                 TELEMETRY_LOG_ERR("Could not unregister client");
56                 goto einval_fail;
57         }
58
59         return 0;
60
61 einval_fail:
62         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
63         if (ret < 0)
64                 TELEMETRY_LOG_ERR("Could not send error");
65         return -1;
66 }
67
68 static int32_t
69 rte_telemetry_command_ports(struct telemetry_impl *telemetry, int action,
70         json_t *data)
71 {
72         int ret;
73
74         if (telemetry == NULL) {
75                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
76                 return -1;
77         }
78
79         if (!json_is_null(data)) {
80                 TELEMETRY_LOG_WARN("Data should be NULL JSON object for 'ports' command");
81                 goto einval_fail;
82         }
83
84         if (action != ACTION_GET) {
85                 TELEMETRY_LOG_WARN("Invalid action for this command");
86                 goto einval_fail;
87         }
88
89         return 0;
90
91 einval_fail:
92         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
93         if (ret < 0)
94                 TELEMETRY_LOG_ERR("Could not send error");
95         return -1;
96 }
97
98 static int32_t
99 rte_telemetry_command_ports_details(struct telemetry_impl *telemetry,
100         int action, json_t *data)
101 {
102         json_t *value, *port_ids_json = json_object_get(data, "ports");
103         uint64_t num_port_ids = json_array_size(port_ids_json);
104         int ret, port_ids[num_port_ids];
105         RTE_SET_USED(port_ids);
106         size_t index;
107
108         if (telemetry == NULL) {
109                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
110                 return -1;
111         }
112
113         if (action != ACTION_GET) {
114                 TELEMETRY_LOG_WARN("Invalid action for this command");
115                 goto einval_fail;
116         }
117
118         if (!json_is_object(data)) {
119                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
120                 goto einval_fail;
121         }
122
123         if (!json_is_array(port_ids_json)) {
124                 TELEMETRY_LOG_WARN("Invalid Port ID array");
125                 goto einval_fail;
126         }
127
128         json_array_foreach(port_ids_json, index, value) {
129                 if (!json_is_integer(value)) {
130                         TELEMETRY_LOG_WARN("Port ID given is invalid");
131                         goto einval_fail;
132                 }
133                 port_ids[index] = json_integer_value(value);
134         }
135
136         return 0;
137
138 einval_fail:
139         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
140         if (ret < 0)
141                 TELEMETRY_LOG_ERR("Could not send error");
142         return -1;
143 }
144
145 static int32_t
146 rte_telemetry_command_port_stats(struct telemetry_impl *telemetry, int action,
147         json_t *data)
148 {
149         int ret;
150
151         if (telemetry == NULL) {
152                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
153                 return -1;
154         }
155
156         if (!json_is_null(data)) {
157                 TELEMETRY_LOG_WARN("Data should be NULL JSON object for 'port_stats' command");
158                 goto einval_fail;
159         }
160
161         if (action != ACTION_GET) {
162                 TELEMETRY_LOG_WARN("Invalid action for this command");
163                 goto einval_fail;
164         }
165
166         return 0;
167
168 einval_fail:
169         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
170         if (ret < 0)
171                 TELEMETRY_LOG_ERR("Could not send error");
172         return -1;
173 }
174
175 static int32_t
176 rte_telemetry_stat_names_to_ids(struct telemetry_impl *telemetry,
177         const char * const *stat_names, uint32_t *stat_ids,
178         uint64_t num_stat_names)
179 {
180         struct rte_metric_name *names;
181         int ret, num_metrics;
182         uint32_t i, k;
183
184         if (stat_names == NULL) {
185                 TELEMETRY_LOG_WARN("Invalid stat_names argument");
186                 goto einval_fail;
187         }
188
189         if (num_stat_names <= 0) {
190                 TELEMETRY_LOG_WARN("Invalid num_stat_names argument");
191                 goto einval_fail;
192         }
193
194         num_metrics = rte_metrics_get_names(NULL, 0);
195         if (num_metrics < 0) {
196                 TELEMETRY_LOG_ERR("Cannot get metrics count");
197                 goto eperm_fail;
198         } else if (num_metrics == 0) {
199                 TELEMETRY_LOG_WARN("No metrics have been registered");
200                 goto eperm_fail;
201         }
202
203         names = malloc(sizeof(struct rte_metric_name) * num_metrics);
204         if (names == NULL) {
205                 TELEMETRY_LOG_ERR("Cannot allocate memory for names");
206
207                 ret = rte_telemetry_send_error_response(telemetry, -ENOMEM);
208                 if (ret < 0)
209                         TELEMETRY_LOG_ERR("Could not send error");
210
211                 return -1;
212         }
213
214         ret = rte_metrics_get_names(names, num_metrics);
215         if (ret < 0 || ret > num_metrics) {
216                 TELEMETRY_LOG_ERR("Cannot get metrics names");
217                 free(names);
218                 goto eperm_fail;
219         }
220
221         k = 0;
222         for (i = 0; i < (uint32_t)num_stat_names; i++) {
223                 uint32_t j;
224                 for (j = 0; j < (uint32_t)num_metrics; j++) {
225                         if (strcmp(stat_names[i], names[j].name) == 0) {
226                                 stat_ids[k] = j;
227                                 k++;
228                                 break;
229                         }
230                 }
231         }
232
233         if (k != num_stat_names) {
234                 TELEMETRY_LOG_WARN("Invalid stat names provided");
235                 free(names);
236                 goto einval_fail;
237         }
238
239         free(names);
240         return 0;
241
242 einval_fail:
243         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
244         if (ret < 0)
245                 TELEMETRY_LOG_ERR("Could not send error");
246         return -1;
247
248 eperm_fail:
249         ret = rte_telemetry_send_error_response(telemetry, -EPERM);
250         if (ret < 0)
251                 TELEMETRY_LOG_ERR("Could not send error");
252         return -1;
253 }
254
255 int32_t
256 rte_telemetry_command_ports_all_stat_values(struct telemetry_impl *telemetry,
257          int action, json_t *data)
258 {
259         int ret, num_metrics, i, p;
260         struct rte_metric_value *values;
261         uint64_t num_port_ids = 0;
262         struct telemetry_encode_param ep;
263
264         memset(&ep, 0, sizeof(ep));
265         if (telemetry == NULL) {
266                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
267                 return -1;
268         }
269
270         if (action != ACTION_GET) {
271                 TELEMETRY_LOG_WARN("Invalid action for this command");
272                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
273                 if (ret < 0)
274                         TELEMETRY_LOG_ERR("Could not send error");
275                 return -1;
276         }
277
278         if (json_is_object(data)) {
279                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
280                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
281                 if (ret < 0)
282                         TELEMETRY_LOG_ERR("Could not send error");
283                 return -1;
284         }
285
286         num_metrics = rte_metrics_get_values(0, NULL, 0);
287         if (num_metrics < 0) {
288                 TELEMETRY_LOG_ERR("Cannot get metrics count");
289
290                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
291                 if (ret < 0)
292                         TELEMETRY_LOG_ERR("Could not send error");
293
294                 return -1;
295         } else if (num_metrics == 0) {
296                 TELEMETRY_LOG_ERR("No metrics to display (none have been registered)");
297
298                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
299                 if (ret < 0)
300                         TELEMETRY_LOG_ERR("Could not send error");
301
302                 return -1;
303         }
304
305         values = malloc(sizeof(struct rte_metric_value) * num_metrics);
306         if (values == NULL) {
307                 TELEMETRY_LOG_ERR("Cannot allocate memory");
308                 ret = rte_telemetry_send_error_response(telemetry,
309                          -ENOMEM);
310                 if (ret < 0)
311                         TELEMETRY_LOG_ERR("Could not send error");
312                 return -1;
313         }
314
315         RTE_ETH_FOREACH_DEV(p) {
316                 ep.pp.port_ids[num_port_ids] = p;
317                 num_port_ids++;
318         }
319
320         if (!num_port_ids) {
321                 TELEMETRY_LOG_WARN("No active ports");
322
323                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
324                 if (ret < 0)
325                         TELEMETRY_LOG_ERR("Could not send error");
326
327                 goto fail;
328         }
329
330         ret = rte_metrics_get_values(ep.pp.port_ids[0], values, num_metrics);
331         if (ret < 0) {
332                 TELEMETRY_LOG_ERR("Could not get stat values");
333                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
334                 if (ret < 0)
335                         TELEMETRY_LOG_ERR("Could not send error");
336                 goto fail;
337         }
338         for (i = 0; i < num_metrics; i++)
339                 ep.pp.metric_ids[i] = values[i].key;
340
341         ep.pp.num_port_ids = num_port_ids;
342         ep.pp.num_metric_ids = num_metrics;
343         ep.type = PORT_STATS;
344
345         ret = rte_telemetry_send_ports_stats_values(&ep, telemetry);
346         if (ret < 0) {
347                 TELEMETRY_LOG_ERR("Sending ports stats values failed");
348                 goto fail;
349         }
350
351         free(values);
352         return 0;
353
354 fail:
355         free(values);
356         return -1;
357 }
358
359 int32_t
360 rte_telemetry_command_global_stat_values(struct telemetry_impl *telemetry,
361          int action, json_t *data)
362 {
363         int ret, num_metrics, i;
364         struct rte_metric_value *values;
365         struct telemetry_encode_param ep;
366
367         memset(&ep, 0, sizeof(ep));
368         if (telemetry == NULL) {
369                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
370                 return -1;
371         }
372
373         if (action != ACTION_GET) {
374                 TELEMETRY_LOG_WARN("Invalid action for this command");
375                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
376                 if (ret < 0)
377                         TELEMETRY_LOG_ERR("Could not send error");
378                 return -1;
379         }
380
381         if (json_is_object(data)) {
382                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
383                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
384                 if (ret < 0)
385                         TELEMETRY_LOG_ERR("Could not send error");
386                 return -1;
387         }
388
389         num_metrics = rte_metrics_get_values(RTE_METRICS_GLOBAL, NULL, 0);
390         if (num_metrics < 0) {
391                 TELEMETRY_LOG_ERR("Cannot get metrics count");
392
393                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
394                 if (ret < 0)
395                         TELEMETRY_LOG_ERR("Could not send error");
396
397                 return -1;
398         } else if (num_metrics == 0) {
399                 TELEMETRY_LOG_ERR("No metrics to display (none have been registered)");
400
401                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
402                 if (ret < 0)
403                         TELEMETRY_LOG_ERR("Could not send error");
404
405                 return -1;
406         }
407
408         values = malloc(sizeof(struct rte_metric_value) * num_metrics);
409         if (values == NULL) {
410                 TELEMETRY_LOG_ERR("Cannot allocate memory");
411                 ret = rte_telemetry_send_error_response(telemetry,
412                          -ENOMEM);
413                 if (ret < 0)
414                         TELEMETRY_LOG_ERR("Could not send error");
415                 return -1;
416         }
417
418         ret = rte_metrics_get_values(RTE_METRICS_GLOBAL, values, num_metrics);
419         if (ret < 0) {
420                 TELEMETRY_LOG_ERR("Could not get stat values");
421                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
422                 if (ret < 0)
423                         TELEMETRY_LOG_ERR("Could not send error");
424                 goto fail;
425         }
426         for (i = 0; i < num_metrics; i++)
427                 ep.gp.metric_ids[i] = values[i].key;
428
429         ep.gp.num_metric_ids = num_metrics;
430         ep.type = GLOBAL_STATS;
431
432         ret = rte_telemetry_send_global_stats_values(&ep, telemetry);
433         if (ret < 0) {
434                 TELEMETRY_LOG_ERR("Sending global stats values failed");
435                 goto fail;
436         }
437
438         free(values);
439         return 0;
440
441 fail:
442         free(values);
443         return -1;
444 }
445
446 int32_t
447 rte_telemetry_command_ports_stats_values_by_name(struct telemetry_impl
448         *telemetry, int action, json_t *data)
449 {
450         int ret;
451         json_t *port_ids_json = json_object_get(data, "ports");
452         json_t *stat_names_json = json_object_get(data, "stats");
453         uint64_t num_stat_names = json_array_size(stat_names_json);
454         const char *stat_names[num_stat_names];
455         struct telemetry_encode_param ep;
456         size_t index;
457         json_t *value;
458
459         ep.pp.num_port_ids = json_array_size(port_ids_json);
460         ep.pp.num_metric_ids = num_stat_names;
461         memset(&ep, 0, sizeof(ep));
462         if (telemetry == NULL) {
463                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
464                 return -1;
465         }
466
467         if (action != ACTION_GET) {
468                 TELEMETRY_LOG_WARN("Invalid action for this command");
469                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
470                 if (ret < 0)
471                         TELEMETRY_LOG_ERR("Could not send error");
472                 return -1;
473         }
474
475         if (!json_is_object(data)) {
476                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
477                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
478                 if (ret < 0)
479                         TELEMETRY_LOG_ERR("Could not send error");
480                 return -1;
481         }
482
483         if (!json_is_array(port_ids_json) ||
484                  !json_is_array(stat_names_json)) {
485                 TELEMETRY_LOG_WARN("Invalid input data array(s)");
486                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
487                 if (ret < 0)
488                         TELEMETRY_LOG_ERR("Could not send error");
489                 return -1;
490         }
491
492         json_array_foreach(port_ids_json, index, value) {
493                 if (!json_is_integer(value)) {
494                         TELEMETRY_LOG_WARN("Port ID given is not valid");
495                         ret = rte_telemetry_send_error_response(telemetry,
496                                 -EINVAL);
497                         if (ret < 0)
498                                 TELEMETRY_LOG_ERR("Could not send error");
499                         return -1;
500                 }
501                 ep.pp.port_ids[index] = json_integer_value(value);
502                 ret = rte_telemetry_is_port_active(ep.pp.port_ids[index]);
503                 if (ret < 1) {
504                         ret = rte_telemetry_send_error_response(telemetry,
505                                 -EINVAL);
506                         if (ret < 0)
507                                 TELEMETRY_LOG_ERR("Could not send error");
508                         return -1;
509                 }
510         }
511
512         json_array_foreach(stat_names_json, index, value) {
513                 if (!json_is_string(value)) {
514                         TELEMETRY_LOG_WARN("Stat Name given is not a string");
515
516                         ret = rte_telemetry_send_error_response(telemetry,
517                                         -EINVAL);
518                         if (ret < 0)
519                                 TELEMETRY_LOG_ERR("Could not send error");
520
521                         return -1;
522                 }
523                 stat_names[index] = json_string_value(value);
524         }
525
526         ret = rte_telemetry_stat_names_to_ids(telemetry, stat_names,
527                 ep.pp.metric_ids, num_stat_names);
528         if (ret < 0) {
529                 TELEMETRY_LOG_ERR("Could not convert stat names to IDs");
530                 return -1;
531         }
532
533         ep.type = PORT_STATS;
534         ret = rte_telemetry_send_ports_stats_values(&ep, telemetry);
535         if (ret < 0) {
536                 TELEMETRY_LOG_ERR("Sending ports stats values failed");
537                 return -1;
538         }
539
540         return 0;
541 }
542
543 static int32_t
544 rte_telemetry_parse_command(struct telemetry_impl *telemetry, int action,
545         const char *command, json_t *data)
546 {
547         int ret;
548         uint32_t i;
549
550         if (telemetry == NULL) {
551                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
552                 return -1;
553         }
554
555         struct rte_telemetry_command commands[] = {
556                 {
557                         .text = "clients",
558                         .fn = &rte_telemetry_command_clients
559                 },
560                 {
561                         .text = "ports",
562                         .fn = &rte_telemetry_command_ports
563                 },
564                 {
565                         .text = "ports_details",
566                         .fn = &rte_telemetry_command_ports_details
567                 },
568                 {
569                         .text = "port_stats",
570                         .fn = &rte_telemetry_command_port_stats
571                 },
572                 {
573                         .text = "ports_stats_values_by_name",
574                         .fn = &rte_telemetry_command_ports_stats_values_by_name
575                 },
576                 {
577                         .text = "ports_all_stat_values",
578                         .fn = &rte_telemetry_command_ports_all_stat_values
579                 },
580                 {
581                         .text = "global_stat_values",
582                         .fn = &rte_telemetry_command_global_stat_values
583                 }
584         };
585
586         const uint32_t num_commands = RTE_DIM(commands);
587
588         for (i = 0; i < num_commands; i++) {
589                 if (strcmp(command, commands[i].text) == 0) {
590                         ret = commands[i].fn(telemetry, action, data);
591                         if (ret < 0) {
592                                 TELEMETRY_LOG_ERR("Command Function for %s failed",
593                                         commands[i].text);
594                                 return -1;
595                         }
596                         return 0;
597                 }
598         }
599
600         TELEMETRY_LOG_WARN("\"%s\" command not found", command);
601
602         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
603         if (ret < 0)
604                 TELEMETRY_LOG_ERR("Could not send error");
605
606         return -1;
607 }
608
609 int32_t
610 rte_telemetry_parse(struct telemetry_impl *telemetry, char *socket_rx_data)
611 {
612         int ret, action_int;
613         json_error_t error;
614         json_t *root, *action, *command, *data;
615
616         if (telemetry == NULL) {
617                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
618                 return -1;
619         }
620
621         root = json_loads(socket_rx_data, 0, &error);
622         if (root == NULL) {
623                 TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s",
624                                 error.text);
625                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
626                 if (ret < 0)
627                         TELEMETRY_LOG_ERR("Could not send error");
628                 return -EPERM;
629         } else if (!json_is_object(root)) {
630                 TELEMETRY_LOG_WARN("JSON Request is not a JSON object");
631                 json_decref(root);
632                 goto einval_fail;
633         }
634
635         action = json_object_get(root, "action");
636         if (action == NULL) {
637                 TELEMETRY_LOG_WARN("Request does not have action field");
638                 goto einval_fail;
639         } else if (!json_is_integer(action)) {
640                 TELEMETRY_LOG_WARN("Action value is not an integer");
641                 goto einval_fail;
642         }
643
644         command = json_object_get(root, "command");
645         if (command == NULL) {
646                 TELEMETRY_LOG_WARN("Request does not have command field");
647                 goto einval_fail;
648         } else if (!json_is_string(command)) {
649                 TELEMETRY_LOG_WARN("Command value is not a string");
650                 goto einval_fail;
651         }
652
653         action_int = json_integer_value(action);
654         if (action_int != ACTION_GET && action_int != ACTION_DELETE) {
655                 TELEMETRY_LOG_WARN("Invalid action code");
656                 goto einval_fail;
657         }
658
659         const char *command_string = json_string_value(command);
660         data = json_object_get(root, "data");
661         if (data == NULL) {
662                 TELEMETRY_LOG_WARN("Request does not have data field");
663                 goto einval_fail;
664         }
665
666         ret = rte_telemetry_parse_command(telemetry, action_int, command_string,
667                 data);
668         if (ret < 0) {
669                 TELEMETRY_LOG_WARN("Could not parse command");
670                 return -EINVAL;
671         }
672
673         return 0;
674
675 einval_fail:
676         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
677         if (ret < 0) {
678                 TELEMETRY_LOG_ERR("Could not send error");
679                 return -EPERM;
680         }
681         return -EINVAL;
682 }