metrics: reduce telemetry code
[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 #include <rte_metrics_telemetry.h>
15
16 #include "rte_telemetry_internal.h"
17 #include "rte_telemetry_parser.h"
18
19 typedef int (*command_func)(struct telemetry_impl *, int, json_t *);
20
21 struct rte_telemetry_command {
22         const char *text;
23         command_func fn;
24 } command;
25
26 static int32_t
27 rte_telemetry_command_clients(struct telemetry_impl *telemetry, int action,
28         json_t *data)
29 {
30         int ret;
31
32         if (telemetry == NULL) {
33                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
34                 return -1;
35         }
36
37         if (action != ACTION_DELETE) {
38                 TELEMETRY_LOG_WARN("Invalid action for this command");
39                 goto einval_fail;
40         }
41
42         if (!json_is_object(data)) {
43                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
44                 goto einval_fail;
45         }
46
47         json_t *client_path = json_object_get(data, "client_path");
48         if (!json_is_string(client_path)) {
49                 TELEMETRY_LOG_WARN("Command value is not a string");
50                 goto einval_fail;
51         }
52
53         ret = rte_telemetry_unregister_client(telemetry,
54                         json_string_value(client_path));
55         if (ret < 0) {
56                 TELEMETRY_LOG_ERR("Could not unregister client");
57                 goto einval_fail;
58         }
59
60         return 0;
61
62 einval_fail:
63         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
64         if (ret < 0)
65                 TELEMETRY_LOG_ERR("Could not send error");
66         return -1;
67 }
68
69 static int32_t
70 rte_telemetry_command_ports(struct telemetry_impl *telemetry, int action,
71         json_t *data)
72 {
73         int ret;
74
75         if (telemetry == NULL) {
76                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
77                 return -1;
78         }
79
80         if (!json_is_null(data)) {
81                 TELEMETRY_LOG_WARN("Data should be NULL JSON object for 'ports' command");
82                 goto einval_fail;
83         }
84
85         if (action != ACTION_GET) {
86                 TELEMETRY_LOG_WARN("Invalid action for this command");
87                 goto einval_fail;
88         }
89
90         return 0;
91
92 einval_fail:
93         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
94         if (ret < 0)
95                 TELEMETRY_LOG_ERR("Could not send error");
96         return -1;
97 }
98
99 static int32_t
100 rte_telemetry_command_ports_details(struct telemetry_impl *telemetry,
101         int action, json_t *data)
102 {
103         json_t *value, *port_ids_json = json_object_get(data, "ports");
104         uint64_t num_port_ids = json_array_size(port_ids_json);
105         int ret, port_ids[num_port_ids];
106         RTE_SET_USED(port_ids);
107         size_t index;
108
109         if (telemetry == NULL) {
110                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
111                 return -1;
112         }
113
114         if (action != ACTION_GET) {
115                 TELEMETRY_LOG_WARN("Invalid action for this command");
116                 goto einval_fail;
117         }
118
119         if (!json_is_object(data)) {
120                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
121                 goto einval_fail;
122         }
123
124         if (!json_is_array(port_ids_json)) {
125                 TELEMETRY_LOG_WARN("Invalid Port ID array");
126                 goto einval_fail;
127         }
128
129         json_array_foreach(port_ids_json, index, value) {
130                 if (!json_is_integer(value)) {
131                         TELEMETRY_LOG_WARN("Port ID given is invalid");
132                         goto einval_fail;
133                 }
134                 port_ids[index] = json_integer_value(value);
135         }
136
137         return 0;
138
139 einval_fail:
140         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
141         if (ret < 0)
142                 TELEMETRY_LOG_ERR("Could not send error");
143         return -1;
144 }
145
146 static int32_t
147 rte_telemetry_command_port_stats(struct telemetry_impl *telemetry, int action,
148         json_t *data)
149 {
150         int ret;
151
152         if (telemetry == NULL) {
153                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
154                 return -1;
155         }
156
157         if (!json_is_null(data)) {
158                 TELEMETRY_LOG_WARN("Data should be NULL JSON object for 'port_stats' command");
159                 goto einval_fail;
160         }
161
162         if (action != ACTION_GET) {
163                 TELEMETRY_LOG_WARN("Invalid action for this command");
164                 goto einval_fail;
165         }
166
167         return 0;
168
169 einval_fail:
170         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
171         if (ret < 0)
172                 TELEMETRY_LOG_ERR("Could not send error");
173         return -1;
174 }
175
176 static int32_t
177 rte_telemetry_command_ports_all_stat_values(struct telemetry_impl *telemetry,
178          int action, json_t *data)
179 {
180         int ret;
181         struct telemetry_encode_param ep;
182
183         memset(&ep, 0, sizeof(ep));
184         if (telemetry == NULL) {
185                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
186                 return -1;
187         }
188
189         if (action != ACTION_GET) {
190                 TELEMETRY_LOG_WARN("Invalid action for this command");
191                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
192                 if (ret < 0)
193                         TELEMETRY_LOG_ERR("Could not send error");
194                 return -1;
195         }
196
197         if (json_is_object(data)) {
198                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
199                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
200                 if (ret < 0)
201                         TELEMETRY_LOG_ERR("Could not send error");
202                 return -1;
203         }
204
205         ret = rte_metrics_tel_get_port_stats_ids(&ep);
206         if (ret < 0) {
207                 TELEMETRY_LOG_ERR("Could not get ports stat values");
208                 ret = rte_telemetry_send_error_response(telemetry, ret);
209                 if (ret < 0)
210                         TELEMETRY_LOG_ERR("Could not send error");
211                 return -1;
212         }
213
214         ret = rte_telemetry_send_ports_stats_values(&ep, telemetry);
215         if (ret < 0) {
216                 TELEMETRY_LOG_ERR("Sending ports stats values failed");
217                 return -1;
218         }
219
220         return 0;
221 }
222
223 static int32_t
224 rte_telemetry_command_global_stat_values(struct telemetry_impl *telemetry,
225          int action, json_t *data)
226 {
227         int ret;
228         struct telemetry_encode_param ep = { .type = GLOBAL_STATS };
229
230         if (telemetry == NULL) {
231                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
232                 return -1;
233         }
234
235         if (action != ACTION_GET) {
236                 TELEMETRY_LOG_WARN("Invalid action for this command");
237                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
238                 if (ret < 0)
239                         TELEMETRY_LOG_ERR("Could not send error");
240                 return -1;
241         }
242
243         if (json_is_object(data)) {
244                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
245                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
246                 if (ret < 0)
247                         TELEMETRY_LOG_ERR("Could not send error");
248                 return -1;
249         }
250
251         ret = rte_telemetry_send_global_stats_values(&ep, telemetry);
252         if (ret < 0) {
253                 TELEMETRY_LOG_ERR("Sending global stats values failed");
254                 return -1;
255         }
256
257         return 0;
258 }
259
260 static int32_t
261 rte_telemetry_command_ports_stats_values_by_name(struct telemetry_impl
262         *telemetry, int action, json_t *data)
263 {
264         int ret;
265         struct telemetry_encode_param ep;
266         if (telemetry == NULL) {
267                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
268                 return -1;
269         }
270
271         if (action != ACTION_GET) {
272                 TELEMETRY_LOG_WARN("Invalid action for this command");
273                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
274                 if (ret < 0)
275                         TELEMETRY_LOG_ERR("Could not send error");
276                 return -1;
277         }
278
279         ret = rte_metrics_tel_extract_data(&ep, data);
280         if (ret < 0) {
281                 TELEMETRY_LOG_ERR("Extracting JSON data failed");
282                 ret = rte_telemetry_send_error_response(telemetry, ret);
283                 if (ret < 0)
284                         TELEMETRY_LOG_ERR("Could not send error");
285                 return -1;
286         }
287
288         ret = rte_telemetry_send_ports_stats_values(&ep, telemetry);
289         if (ret < 0) {
290                 TELEMETRY_LOG_ERR("Sending ports stats values failed");
291                 return -1;
292         }
293
294         return 0;
295 }
296
297 static int32_t
298 rte_telemetry_parse_command(struct telemetry_impl *telemetry, int action,
299         const char *command, json_t *data)
300 {
301         int ret;
302         uint32_t i;
303
304         if (telemetry == NULL) {
305                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
306                 return -1;
307         }
308
309         struct rte_telemetry_command commands[] = {
310                 {
311                         .text = "clients",
312                         .fn = &rte_telemetry_command_clients
313                 },
314                 {
315                         .text = "ports",
316                         .fn = &rte_telemetry_command_ports
317                 },
318                 {
319                         .text = "ports_details",
320                         .fn = &rte_telemetry_command_ports_details
321                 },
322                 {
323                         .text = "port_stats",
324                         .fn = &rte_telemetry_command_port_stats
325                 },
326                 {
327                         .text = "ports_stats_values_by_name",
328                         .fn = &rte_telemetry_command_ports_stats_values_by_name
329                 },
330                 {
331                         .text = "ports_all_stat_values",
332                         .fn = &rte_telemetry_command_ports_all_stat_values
333                 },
334                 {
335                         .text = "global_stat_values",
336                         .fn = &rte_telemetry_command_global_stat_values
337                 }
338         };
339
340         const uint32_t num_commands = RTE_DIM(commands);
341
342         for (i = 0; i < num_commands; i++) {
343                 if (strcmp(command, commands[i].text) == 0) {
344                         ret = commands[i].fn(telemetry, action, data);
345                         if (ret < 0) {
346                                 TELEMETRY_LOG_ERR("Command Function for %s failed",
347                                         commands[i].text);
348                                 return -1;
349                         }
350                         return 0;
351                 }
352         }
353
354         TELEMETRY_LOG_WARN("\"%s\" command not found", command);
355
356         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
357         if (ret < 0)
358                 TELEMETRY_LOG_ERR("Could not send error");
359
360         return -1;
361 }
362
363 int32_t
364 rte_telemetry_parse(struct telemetry_impl *telemetry, char *socket_rx_data)
365 {
366         int ret, action_int;
367         json_error_t error;
368         json_t *root, *action, *command, *data;
369
370         if (telemetry == NULL) {
371                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
372                 return -1;
373         }
374
375         root = json_loads(socket_rx_data, 0, &error);
376         if (root == NULL) {
377                 TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s",
378                                 error.text);
379                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
380                 if (ret < 0)
381                         TELEMETRY_LOG_ERR("Could not send error");
382                 return -EPERM;
383         } else if (!json_is_object(root)) {
384                 TELEMETRY_LOG_WARN("JSON Request is not a JSON object");
385                 json_decref(root);
386                 goto einval_fail;
387         }
388
389         action = json_object_get(root, "action");
390         if (action == NULL) {
391                 TELEMETRY_LOG_WARN("Request does not have action field");
392                 goto einval_fail;
393         } else if (!json_is_integer(action)) {
394                 TELEMETRY_LOG_WARN("Action value is not an integer");
395                 goto einval_fail;
396         }
397
398         command = json_object_get(root, "command");
399         if (command == NULL) {
400                 TELEMETRY_LOG_WARN("Request does not have command field");
401                 goto einval_fail;
402         } else if (!json_is_string(command)) {
403                 TELEMETRY_LOG_WARN("Command value is not a string");
404                 goto einval_fail;
405         }
406
407         action_int = json_integer_value(action);
408         if (action_int != ACTION_GET && action_int != ACTION_DELETE) {
409                 TELEMETRY_LOG_WARN("Invalid action code");
410                 goto einval_fail;
411         }
412
413         const char *command_string = json_string_value(command);
414         data = json_object_get(root, "data");
415         if (data == NULL) {
416                 TELEMETRY_LOG_WARN("Request does not have data field");
417                 goto einval_fail;
418         }
419
420         ret = rte_telemetry_parse_command(telemetry, action_int, command_string,
421                 data);
422         if (ret < 0) {
423                 TELEMETRY_LOG_WARN("Could not parse command");
424                 return -EINVAL;
425         }
426
427         return 0;
428
429 einval_fail:
430         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
431         if (ret < 0) {
432                 TELEMETRY_LOG_ERR("Could not send error");
433                 return -EPERM;
434         }
435         return -EINVAL;
436 }