telemetry: move some functions to 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_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;
229
230         memset(&ep, 0, sizeof(ep));
231         if (telemetry == NULL) {
232                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
233                 return -1;
234         }
235
236         if (action != ACTION_GET) {
237                 TELEMETRY_LOG_WARN("Invalid action for this command");
238                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
239                 if (ret < 0)
240                         TELEMETRY_LOG_ERR("Could not send error");
241                 return -1;
242         }
243
244         if (json_is_object(data)) {
245                 TELEMETRY_LOG_WARN("Invalid data provided for this command");
246                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
247                 if (ret < 0)
248                         TELEMETRY_LOG_ERR("Could not send error");
249                 return -1;
250         }
251
252         ret = rte_metrics_tel_get_global_stats(&ep);
253         if (ret < 0) {
254                 TELEMETRY_LOG_ERR("Could not get global stat values");
255                 ret = rte_telemetry_send_error_response(telemetry, ret);
256                 if (ret < 0)
257                         TELEMETRY_LOG_ERR("Could not send error");
258                 return -1;
259         }
260
261         ret = rte_telemetry_send_global_stats_values(&ep, telemetry);
262         if (ret < 0) {
263                 TELEMETRY_LOG_ERR("Sending global stats values failed");
264                 return -1;
265         }
266
267         return 0;
268 }
269
270 static int32_t
271 rte_telemetry_command_ports_stats_values_by_name(struct telemetry_impl
272         *telemetry, int action, json_t *data)
273 {
274         int ret;
275         struct telemetry_encode_param ep;
276         if (telemetry == NULL) {
277                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
278                 return -1;
279         }
280
281         if (action != ACTION_GET) {
282                 TELEMETRY_LOG_WARN("Invalid action for this command");
283                 ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
284                 if (ret < 0)
285                         TELEMETRY_LOG_ERR("Could not send error");
286                 return -1;
287         }
288
289         ret = rte_metrics_tel_extract_data(&ep, data);
290         if (ret < 0) {
291                 TELEMETRY_LOG_ERR("Extracting JSON data failed");
292                 ret = rte_telemetry_send_error_response(telemetry, ret);
293                 if (ret < 0)
294                         TELEMETRY_LOG_ERR("Could not send error");
295                 return -1;
296         }
297
298         ret = rte_telemetry_send_ports_stats_values(&ep, telemetry);
299         if (ret < 0) {
300                 TELEMETRY_LOG_ERR("Sending ports stats values failed");
301                 return -1;
302         }
303
304         return 0;
305 }
306
307 static int32_t
308 rte_telemetry_parse_command(struct telemetry_impl *telemetry, int action,
309         const char *command, json_t *data)
310 {
311         int ret;
312         uint32_t i;
313
314         if (telemetry == NULL) {
315                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
316                 return -1;
317         }
318
319         struct rte_telemetry_command commands[] = {
320                 {
321                         .text = "clients",
322                         .fn = &rte_telemetry_command_clients
323                 },
324                 {
325                         .text = "ports",
326                         .fn = &rte_telemetry_command_ports
327                 },
328                 {
329                         .text = "ports_details",
330                         .fn = &rte_telemetry_command_ports_details
331                 },
332                 {
333                         .text = "port_stats",
334                         .fn = &rte_telemetry_command_port_stats
335                 },
336                 {
337                         .text = "ports_stats_values_by_name",
338                         .fn = &rte_telemetry_command_ports_stats_values_by_name
339                 },
340                 {
341                         .text = "ports_all_stat_values",
342                         .fn = &rte_telemetry_command_ports_all_stat_values
343                 },
344                 {
345                         .text = "global_stat_values",
346                         .fn = &rte_telemetry_command_global_stat_values
347                 }
348         };
349
350         const uint32_t num_commands = RTE_DIM(commands);
351
352         for (i = 0; i < num_commands; i++) {
353                 if (strcmp(command, commands[i].text) == 0) {
354                         ret = commands[i].fn(telemetry, action, data);
355                         if (ret < 0) {
356                                 TELEMETRY_LOG_ERR("Command Function for %s failed",
357                                         commands[i].text);
358                                 return -1;
359                         }
360                         return 0;
361                 }
362         }
363
364         TELEMETRY_LOG_WARN("\"%s\" command not found", command);
365
366         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
367         if (ret < 0)
368                 TELEMETRY_LOG_ERR("Could not send error");
369
370         return -1;
371 }
372
373 int32_t
374 rte_telemetry_parse(struct telemetry_impl *telemetry, char *socket_rx_data)
375 {
376         int ret, action_int;
377         json_error_t error;
378         json_t *root, *action, *command, *data;
379
380         if (telemetry == NULL) {
381                 TELEMETRY_LOG_ERR("Invalid telemetry argument");
382                 return -1;
383         }
384
385         root = json_loads(socket_rx_data, 0, &error);
386         if (root == NULL) {
387                 TELEMETRY_LOG_WARN("Could not load JSON object from data passed in : %s",
388                                 error.text);
389                 ret = rte_telemetry_send_error_response(telemetry, -EPERM);
390                 if (ret < 0)
391                         TELEMETRY_LOG_ERR("Could not send error");
392                 return -EPERM;
393         } else if (!json_is_object(root)) {
394                 TELEMETRY_LOG_WARN("JSON Request is not a JSON object");
395                 json_decref(root);
396                 goto einval_fail;
397         }
398
399         action = json_object_get(root, "action");
400         if (action == NULL) {
401                 TELEMETRY_LOG_WARN("Request does not have action field");
402                 goto einval_fail;
403         } else if (!json_is_integer(action)) {
404                 TELEMETRY_LOG_WARN("Action value is not an integer");
405                 goto einval_fail;
406         }
407
408         command = json_object_get(root, "command");
409         if (command == NULL) {
410                 TELEMETRY_LOG_WARN("Request does not have command field");
411                 goto einval_fail;
412         } else if (!json_is_string(command)) {
413                 TELEMETRY_LOG_WARN("Command value is not a string");
414                 goto einval_fail;
415         }
416
417         action_int = json_integer_value(action);
418         if (action_int != ACTION_GET && action_int != ACTION_DELETE) {
419                 TELEMETRY_LOG_WARN("Invalid action code");
420                 goto einval_fail;
421         }
422
423         const char *command_string = json_string_value(command);
424         data = json_object_get(root, "data");
425         if (data == NULL) {
426                 TELEMETRY_LOG_WARN("Request does not have data field");
427                 goto einval_fail;
428         }
429
430         ret = rte_telemetry_parse_command(telemetry, action_int, command_string,
431                 data);
432         if (ret < 0) {
433                 TELEMETRY_LOG_WARN("Could not parse command");
434                 return -EINVAL;
435         }
436
437         return 0;
438
439 einval_fail:
440         ret = rte_telemetry_send_error_response(telemetry, -EINVAL);
441         if (ret < 0) {
442                 TELEMETRY_LOG_ERR("Could not send error");
443                 return -EPERM;
444         }
445         return -EINVAL;
446 }