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