telemetry: invert dependency on metrics library
[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_metrics_telemetry.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         const 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_command_ports_all_stat_values(struct telemetry_impl *telemetry,
177          int action, json_t *data)
178 {
179         int ret;
180         struct telemetry_encode_param ep;
181
182         memset(&ep, 0, sizeof(ep));
183         if (telemetry == NULL) {
184                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
185                 return -1;
186         }
187
188         if (action != ACTION_GET) {
189                 TELEMETRY_LOG_WARN("Invalid action for this command");
190                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
191                 if (ret < 0)
192                         TELEMETRY_LOG_ERR("Could not send error");
193                 return -1;
194         }
195
196         if (json_is_object(data)) {
197                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
198                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
199                 if (ret < 0)
200                         TELEMETRY_LOG_ERR("Could not send error");
201                 return -1;
202         }
203
204         ret = metrics_fns->get_port_stats_ids(&ep);
205         if (ret < 0) {
206                 TELEMETRY_LOG_ERR("Could not get ports stat values");
207                 ret = rte_telemetry_send_error_response(telemetry, ret);
208                 if (ret < 0)
209                         TELEMETRY_LOG_ERR("Could not send error");
210                 return -1;
211         }
212
213         ret = rte_telemetry_send_ports_stats_values(&ep, telemetry);
214         if (ret < 0) {
215                 TELEMETRY_LOG_ERR("Sending ports stats values failed");
216                 return -1;
217         }
218
219         return 0;
220 }
221
222 static int32_t
223 rte_telemetry_command_global_stat_values(struct telemetry_impl *telemetry,
224          int action, json_t *data)
225 {
226         int ret;
227         struct telemetry_encode_param ep = { .type = GLOBAL_STATS };
228
229         if (telemetry == NULL) {
230                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
231                 return -1;
232         }
233
234         if (action != ACTION_GET) {
235                 TELEMETRY_LOG_WARN("Invalid action for this command");
236                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
237                 if (ret < 0)
238                         TELEMETRY_LOG_ERR("Could not send error");
239                 return -1;
240         }
241
242         if (json_is_object(data)) {
243                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
244                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
245                 if (ret < 0)
246                         TELEMETRY_LOG_ERR("Could not send error");
247                 return -1;
248         }
249
250         ret = rte_telemetry_send_global_stats_values(&ep, telemetry);
251         if (ret < 0) {
252                 TELEMETRY_LOG_ERR("Sending global stats values failed");
253                 return -1;
254         }
255
256         return 0;
257 }
258
259 static int32_t
260 rte_telemetry_command_ports_stats_values_by_name(struct telemetry_impl
261         *telemetry, int action, json_t *data)
262 {
263         int ret;
264         struct telemetry_encode_param 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         ret = metrics_fns->extract_data(&ep, data);
279         if (ret < 0) {
280                 TELEMETRY_LOG_ERR("Extracting JSON data failed");
281                 ret = rte_telemetry_send_error_response(telemetry, ret);
282                 if (ret < 0)
283                         TELEMETRY_LOG_ERR("Could not send error");
284                 return -1;
285         }
286
287         ret = rte_telemetry_send_ports_stats_values(&ep, telemetry);
288         if (ret < 0) {
289                 TELEMETRY_LOG_ERR("Sending ports stats values failed");
290                 return -1;
291         }
292
293         return 0;
294 }
295
296 static int32_t
297 rte_telemetry_parse_command(struct telemetry_impl *telemetry, int action,
298         const char *command, json_t *data)
299 {
300         int ret;
301         uint32_t i;
302
303         if (telemetry == NULL) {
304                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
305                 return -1;
306         }
307
308         struct rte_telemetry_command commands[] = {
309                 {
310                         .text = "clients",
311                         .fn = &rte_telemetry_command_clients
312                 },
313                 {
314                         .text = "ports",
315                         .fn = &rte_telemetry_command_ports
316                 },
317                 {
318                         .text = "ports_details",
319                         .fn = &rte_telemetry_command_ports_details
320                 },
321                 {
322                         .text = "port_stats",
323                         .fn = &rte_telemetry_command_port_stats
324                 },
325                 {
326                         .text = "ports_stats_values_by_name",
327                         .fn = &rte_telemetry_command_ports_stats_values_by_name
328                 },
329                 {
330                         .text = "ports_all_stat_values",
331                         .fn = &rte_telemetry_command_ports_all_stat_values
332                 },
333                 {
334                         .text = "global_stat_values",
335                         .fn = &rte_telemetry_command_global_stat_values
336                 }
337         };
338
339         const uint32_t num_commands = RTE_DIM(commands);
340
341         for (i = 0; i < num_commands; i++) {
342                 if (strcmp(command, commands[i].text) == 0) {
343                         ret = commands[i].fn(telemetry, action, data);
344                         if (ret < 0) {
345                                 TELEMETRY_LOG_ERR("Command Function for %s failed",
346                                         commands[i].text);
347                                 return -1;
348                         }
349                         return 0;
350                 }
351         }
352
353         TELEMETRY_LOG_WARN("\"%s\" command not found", command);
354
355         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
356         if (ret < 0)
357                 TELEMETRY_LOG_ERR("Could not send error");
358
359         return -1;
360 }
361
362 int32_t
363 rte_telemetry_parse(struct telemetry_impl *telemetry, char *socket_rx_data)
364 {
365         int ret, action_int;
366         json_error_t error;
367         json_t *root, *action, *command, *data;
368
369         if (telemetry == NULL) {
370                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
371                 return -1;
372         }
373
374         root = json_loads(socket_rx_data, 0, &error);
375         if (root == NULL) {
376                 TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s",
377                                 error.text);
378                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
379                 if (ret < 0)
380                         TELEMETRY_LOG_ERR("Could not send error");
381                 return -EPERM;
382         } else if (!json_is_object(root)) {
383                 TELEMETRY_LOG_WARN("JSON Request is not a JSON object");
384                 json_decref(root);
385                 goto einval_fail;
386         }
387
388         action = json_object_get(root, "action");
389         if (action == NULL) {
390                 TELEMETRY_LOG_WARN("Request does not have action field");
391                 goto einval_fail;
392         } else if (!json_is_integer(action)) {
393                 TELEMETRY_LOG_WARN("Action value is not an integer");
394                 goto einval_fail;
395         }
396
397         command = json_object_get(root, "command");
398         if (command == NULL) {
399                 TELEMETRY_LOG_WARN("Request does not have command field");
400                 goto einval_fail;
401         } else if (!json_is_string(command)) {
402                 TELEMETRY_LOG_WARN("Command value is not a string");
403                 goto einval_fail;
404         }
405
406         action_int = json_integer_value(action);
407         if (action_int != ACTION_GET && action_int != ACTION_DELETE) {
408                 TELEMETRY_LOG_WARN("Invalid action code");
409                 goto einval_fail;
410         }
411
412         const char *command_string = json_string_value(command);
413         data = json_object_get(root, "data");
414         if (data == NULL) {
415                 TELEMETRY_LOG_WARN("Request does not have data field");
416                 goto einval_fail;
417         }
418
419         ret = rte_telemetry_parse_command(telemetry, action_int, command_string,
420                 data);
421         if (ret < 0) {
422                 TELEMETRY_LOG_WARN("Could not parse command");
423                 return -EINVAL;
424         }
425
426         return 0;
427
428 einval_fail:
429         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
430         if (ret < 0) {
431                 TELEMETRY_LOG_ERR("Could not send error");
432                 return -EPERM;
433         }
434         return -EINVAL;
435 }