eal/ppc: use compiler builtins for atomics
[dpdk.git] / examples / vm_power_manager / vm_power_cli.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #include <stdlib.h>
6 #include <stdint.h>
7 #include <inttypes.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <termios.h>
11 #include <errno.h>
12
13 #include <cmdline_rdline.h>
14 #include <cmdline_parse.h>
15 #include <cmdline_parse_string.h>
16 #include <cmdline_parse_num.h>
17 #include <cmdline_socket.h>
18 #include <cmdline.h>
19
20 #include "vm_power_cli.h"
21 #include "channel_manager.h"
22 #include "channel_monitor.h"
23 #include "power_manager.h"
24
25 struct cmd_quit_result {
26         cmdline_fixed_string_t quit;
27 };
28
29 static void cmd_quit_parsed(__rte_unused void *parsed_result,
30                 struct cmdline *cl,
31                 __rte_unused void *data)
32 {
33         channel_monitor_exit();
34         channel_manager_exit();
35         power_manager_exit();
36         cmdline_quit(cl);
37 }
38
39 cmdline_parse_token_string_t cmd_quit_quit =
40         TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
41
42 cmdline_parse_inst_t cmd_quit = {
43         .f = cmd_quit_parsed,  /* function to call */
44         .data = NULL,      /* 2nd arg of func */
45         .help_str = "close the application",
46         .tokens = {        /* token list, NULL terminated */
47                 (void *)&cmd_quit_quit,
48                 NULL,
49         },
50 };
51
52 /* *** VM operations *** */
53 struct cmd_show_vm_result {
54         cmdline_fixed_string_t show_vm;
55         cmdline_fixed_string_t vm_name;
56 };
57
58 static void
59 cmd_show_vm_parsed(void *parsed_result, struct cmdline *cl,
60                 __rte_unused void *data)
61 {
62         struct cmd_show_vm_result *res = parsed_result;
63         struct vm_info info;
64         unsigned i;
65
66         if (get_info_vm(res->vm_name, &info) != 0)
67                 return;
68         cmdline_printf(cl, "VM: '%s', status = ", info.name);
69         if (info.status == CHANNEL_MGR_VM_ACTIVE)
70                 cmdline_printf(cl, "ACTIVE\n");
71         else
72                 cmdline_printf(cl, "INACTIVE\n");
73         cmdline_printf(cl, "Channels %u\n", info.num_channels);
74         for (i = 0; i < info.num_channels; i++) {
75                 cmdline_printf(cl, "  [%u]: %s, status = ", i,
76                                 info.channels[i].channel_path);
77                 switch (info.channels[i].status) {
78                 case CHANNEL_MGR_CHANNEL_CONNECTED:
79                         cmdline_printf(cl, "CONNECTED\n");
80                         break;
81                 case CHANNEL_MGR_CHANNEL_DISCONNECTED:
82                         cmdline_printf(cl, "DISCONNECTED\n");
83                         break;
84                 case CHANNEL_MGR_CHANNEL_DISABLED:
85                         cmdline_printf(cl, "DISABLED\n");
86                         break;
87                 case CHANNEL_MGR_CHANNEL_PROCESSING:
88                         cmdline_printf(cl, "PROCESSING\n");
89                         break;
90                 default:
91                         cmdline_printf(cl, "UNKNOWN\n");
92                         break;
93                 }
94         }
95         cmdline_printf(cl, "Virtual CPU(s): %u\n", info.num_vcpus);
96         for (i = 0; i < info.num_vcpus; i++) {
97                 cmdline_printf(cl, "  [%u]: Physical CPU %d\n", i,
98                                 info.pcpu_map[i]);
99         }
100 }
101
102
103
104 cmdline_parse_token_string_t cmd_vm_show =
105         TOKEN_STRING_INITIALIZER(struct cmd_show_vm_result,
106                                 show_vm, "show_vm");
107 cmdline_parse_token_string_t cmd_show_vm_name =
108         TOKEN_STRING_INITIALIZER(struct cmd_show_vm_result,
109                         vm_name, NULL);
110
111 cmdline_parse_inst_t cmd_show_vm_set = {
112         .f = cmd_show_vm_parsed,
113         .data = NULL,
114         .help_str = "show_vm <vm_name>, prints the information on the "
115                         "specified VM(s), the information lists the number of vCPUS, the "
116                         "pinning to pCPU(s) as a bit mask, along with any communication "
117                         "channels associated with each VM",
118         .tokens = {
119                 (void *)&cmd_vm_show,
120                 (void *)&cmd_show_vm_name,
121                 NULL,
122         },
123 };
124
125 /* *** vCPU to pCPU mapping operations *** */
126
127
128 struct cmd_set_pcpu_result {
129         cmdline_fixed_string_t set_pcpu;
130         cmdline_fixed_string_t vm_name;
131         uint8_t vcpu;
132         uint8_t core;
133 };
134
135 static void
136 cmd_set_pcpu_parsed(void *parsed_result, struct cmdline *cl,
137                 __rte_unused void *data)
138 {
139         struct cmd_set_pcpu_result *res = parsed_result;
140
141         if (set_pcpu(res->vm_name, res->vcpu, res->core) == 0)
142                 cmdline_printf(cl, "Pinned vCPU(%"PRId8") to pCPU core "
143                                 "%"PRId8")\n", res->vcpu, res->core);
144         else
145                 cmdline_printf(cl, "Unable to pin vCPU(%"PRId8") to pCPU core "
146                                 "%"PRId8")\n", res->vcpu, res->core);
147 }
148
149 cmdline_parse_token_string_t cmd_set_pcpu =
150                 TOKEN_STRING_INITIALIZER(struct cmd_set_pcpu_result,
151                                 set_pcpu, "set_pcpu");
152 cmdline_parse_token_string_t cmd_set_pcpu_vm_name =
153                 TOKEN_STRING_INITIALIZER(struct cmd_set_pcpu_result,
154                                 vm_name, NULL);
155 cmdline_parse_token_num_t set_pcpu_vcpu =
156                 TOKEN_NUM_INITIALIZER(struct cmd_set_pcpu_result,
157                                 vcpu, RTE_UINT8);
158 cmdline_parse_token_num_t set_pcpu_core =
159                 TOKEN_NUM_INITIALIZER(struct cmd_set_pcpu_result,
160                                 core, RTE_UINT64);
161
162
163 cmdline_parse_inst_t cmd_set_pcpu_set = {
164                 .f = cmd_set_pcpu_parsed,
165                 .data = NULL,
166                 .help_str = "set_pcpu <vm_name> <vcpu> <pcpu>, Set the binding "
167                                 "of Virtual CPU on VM to the Physical CPU.",
168                                 .tokens = {
169                                                 (void *)&cmd_set_pcpu,
170                                                 (void *)&cmd_set_pcpu_vm_name,
171                                                 (void *)&set_pcpu_vcpu,
172                                                 (void *)&set_pcpu_core,
173                                                 NULL,
174                 },
175 };
176
177 struct cmd_vm_op_result {
178         cmdline_fixed_string_t op_vm;
179         cmdline_fixed_string_t vm_name;
180 };
181
182 static void
183 cmd_vm_op_parsed(void *parsed_result, struct cmdline *cl,
184                 __rte_unused void *data)
185 {
186         struct cmd_vm_op_result *res = parsed_result;
187
188         if (!strcmp(res->op_vm, "add_vm")) {
189                 if (add_vm(res->vm_name) < 0)
190                         cmdline_printf(cl, "Unable to add VM '%s'\n", res->vm_name);
191         } else if (remove_vm(res->vm_name) < 0)
192                 cmdline_printf(cl, "Unable to remove VM '%s'\n", res->vm_name);
193 }
194
195 cmdline_parse_token_string_t cmd_vm_op =
196         TOKEN_STRING_INITIALIZER(struct cmd_vm_op_result,
197                         op_vm, "add_vm#rm_vm");
198 cmdline_parse_token_string_t cmd_vm_name =
199         TOKEN_STRING_INITIALIZER(struct cmd_vm_op_result,
200                         vm_name, NULL);
201
202 cmdline_parse_inst_t cmd_vm_op_set = {
203         .f = cmd_vm_op_parsed,
204         .data = NULL,
205         .help_str = "add_vm|rm_vm <name>, add a VM for "
206                         "subsequent operations with the CLI or remove a previously added "
207                         "VM from the VM Power Manager",
208         .tokens = {
209                 (void *)&cmd_vm_op,
210                 (void *)&cmd_vm_name,
211         NULL,
212         },
213 };
214
215 /* *** VM channel operations *** */
216 struct cmd_channels_op_result {
217         cmdline_fixed_string_t op;
218         cmdline_fixed_string_t vm_name;
219         cmdline_fixed_string_t channel_list;
220 };
221 static void
222 cmd_channels_op_parsed(void *parsed_result, struct cmdline *cl,
223                         __rte_unused void *data)
224 {
225         unsigned num_channels = 0, channel_num, i;
226         int channels_added;
227         unsigned int channel_list[RTE_MAX_LCORE];
228         char *token, *remaining, *tail_ptr;
229         struct cmd_channels_op_result *res = parsed_result;
230
231         if (!strcmp(res->channel_list, "all")) {
232                 channels_added = add_all_channels(res->vm_name);
233                 cmdline_printf(cl, "Added %d channels for VM '%s'\n",
234                                 channels_added, res->vm_name);
235                 return;
236         }
237
238         remaining = res->channel_list;
239         while (1) {
240                 if (remaining == NULL || remaining[0] == '\0')
241                         break;
242
243                 token = strsep(&remaining, ",");
244                 if (token == NULL)
245                         break;
246                 errno = 0;
247                 channel_num = (unsigned)strtol(token, &tail_ptr, 10);
248                 if ((errno != 0) || tail_ptr == NULL || (*tail_ptr != '\0'))
249                         break;
250
251                 if (channel_num == RTE_MAX_LCORE) {
252                         cmdline_printf(cl, "Channel number '%u' exceeds the maximum number "
253                                         "of allowable channels(%u) for VM '%s'\n", channel_num,
254                                         RTE_MAX_LCORE, res->vm_name);
255                         return;
256                 }
257                 channel_list[num_channels++] = channel_num;
258         }
259         for (i = 0; i < num_channels; i++)
260                 cmdline_printf(cl, "[%u]: Adding channel %u\n", i, channel_list[i]);
261
262         channels_added = add_channels(res->vm_name, channel_list,
263                         num_channels);
264         cmdline_printf(cl, "Enabled %d channels for '%s'\n", channels_added,
265                         res->vm_name);
266 }
267
268 cmdline_parse_token_string_t cmd_channels_op =
269         TOKEN_STRING_INITIALIZER(struct cmd_channels_op_result,
270                                 op, "add_channels");
271 cmdline_parse_token_string_t cmd_channels_vm_name =
272         TOKEN_STRING_INITIALIZER(struct cmd_channels_op_result,
273                         vm_name, NULL);
274 cmdline_parse_token_string_t cmd_channels_list =
275         TOKEN_STRING_INITIALIZER(struct cmd_channels_op_result,
276                         channel_list, NULL);
277
278 cmdline_parse_inst_t cmd_channels_op_set = {
279         .f = cmd_channels_op_parsed,
280         .data = NULL,
281         .help_str = "add_channels <vm_name> <list>|all, add "
282                         "communication channels for the specified VM, the "
283                         "virtio channels must be enabled in the VM "
284                         "configuration(qemu/libvirt) and the associated VM must be active. "
285                         "<list> is a comma-separated list of channel numbers to add, using "
286                         "the keyword 'all' will attempt to add all channels for the VM",
287         .tokens = {
288                 (void *)&cmd_channels_op,
289                 (void *)&cmd_channels_vm_name,
290                 (void *)&cmd_channels_list,
291                 NULL,
292         },
293 };
294
295 struct cmd_set_query_result {
296         cmdline_fixed_string_t set_query;
297         cmdline_fixed_string_t vm_name;
298         cmdline_fixed_string_t query_status;
299 };
300
301 static void
302 cmd_set_query_parsed(void *parsed_result,
303                 __rte_unused struct cmdline *cl,
304                 __rte_unused void *data)
305 {
306         struct cmd_set_query_result *res = parsed_result;
307
308         if (!strcmp(res->query_status, "enable")) {
309                 if (set_query_status(res->vm_name, true) < 0)
310                         cmdline_printf(cl, "Unable to allow query for VM '%s'\n",
311                                         res->vm_name);
312         } else if (!strcmp(res->query_status, "disable")) {
313                 if (set_query_status(res->vm_name, false) < 0)
314                         cmdline_printf(cl, "Unable to disallow query for VM '%s'\n",
315                                         res->vm_name);
316         }
317 }
318
319 cmdline_parse_token_string_t cmd_set_query =
320         TOKEN_STRING_INITIALIZER(struct cmd_set_query_result,
321                         set_query, "set_query");
322 cmdline_parse_token_string_t cmd_set_query_vm_name =
323         TOKEN_STRING_INITIALIZER(struct cmd_set_query_result,
324                         vm_name, NULL);
325 cmdline_parse_token_string_t cmd_set_query_status =
326         TOKEN_STRING_INITIALIZER(struct cmd_set_query_result,
327                         query_status, "enable#disable");
328
329 cmdline_parse_inst_t cmd_set_query_set = {
330         .f = cmd_set_query_parsed,
331         .data = NULL,
332         .help_str = "set_query <vm_name> <enable|disable>, allow or disallow queries"
333                         " for the specified VM",
334         .tokens = {
335                 (void *)&cmd_set_query,
336                 (void *)&cmd_set_query_vm_name,
337                 (void *)&cmd_set_query_status,
338                 NULL,
339         },
340 };
341
342 struct cmd_channels_status_op_result {
343         cmdline_fixed_string_t op;
344         cmdline_fixed_string_t vm_name;
345         cmdline_fixed_string_t channel_list;
346         cmdline_fixed_string_t status;
347 };
348
349 static void
350 cmd_channels_status_op_parsed(void *parsed_result, struct cmdline *cl,
351                        __rte_unused void *data)
352 {
353         unsigned num_channels = 0, channel_num;
354         int changed;
355         unsigned int channel_list[RTE_MAX_LCORE];
356         char *token, *remaining, *tail_ptr;
357         struct cmd_channels_status_op_result *res = parsed_result;
358         enum channel_status status;
359
360         if (!strcmp(res->status, "enabled"))
361                 status = CHANNEL_MGR_CHANNEL_CONNECTED;
362         else
363                 status = CHANNEL_MGR_CHANNEL_DISABLED;
364
365         if (!strcmp(res->channel_list, "all")) {
366                 changed = set_channel_status_all(res->vm_name, status);
367                 cmdline_printf(cl, "Updated status of %d channels "
368                                 "for VM '%s'\n", changed, res->vm_name);
369                 return;
370         }
371         remaining = res->channel_list;
372         while (1) {
373                 if (remaining == NULL || remaining[0] == '\0')
374                         break;
375                 token = strsep(&remaining, ",");
376                 if (token == NULL)
377                         break;
378                 errno = 0;
379                 channel_num = (unsigned)strtol(token, &tail_ptr, 10);
380                 if ((errno != 0) || tail_ptr == NULL || (*tail_ptr != '\0'))
381                         break;
382
383                 if (channel_num == RTE_MAX_LCORE) {
384                         cmdline_printf(cl, "%u exceeds the maximum number of allowable "
385                                         "channels(%u) for VM '%s'\n", channel_num,
386                                         RTE_MAX_LCORE, res->vm_name);
387                         return;
388                 }
389                 channel_list[num_channels++] = channel_num;
390         }
391         changed = set_channel_status(res->vm_name, channel_list, num_channels,
392                         status);
393         cmdline_printf(cl, "Updated status of %d channels "
394                                         "for VM '%s'\n", changed, res->vm_name);
395 }
396
397 cmdline_parse_token_string_t cmd_channels_status_op =
398         TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
399                                 op, "set_channel_status");
400 cmdline_parse_token_string_t cmd_channels_status_vm_name =
401         TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
402                         vm_name, NULL);
403 cmdline_parse_token_string_t cmd_channels_status_list =
404         TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
405                         channel_list, NULL);
406 cmdline_parse_token_string_t cmd_channels_status =
407         TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
408                         status, "enabled#disabled");
409
410 cmdline_parse_inst_t cmd_channels_status_op_set = {
411         .f = cmd_channels_status_op_parsed,
412         .data = NULL,
413         .help_str = "set_channel_status <vm_name> <list>|all enabled|disabled, "
414                         " enable or disable the communication channels in "
415                         "list(comma-separated) for the specified VM, alternatively "
416                         "list can be replaced with keyword 'all'. "
417                         "Disabled channels will still receive packets on the host, "
418                         "however the commands they specify will be ignored. "
419                         "Set status to 'enabled' to begin processing requests again.",
420         .tokens = {
421                 (void *)&cmd_channels_status_op,
422                 (void *)&cmd_channels_status_vm_name,
423                 (void *)&cmd_channels_status_list,
424                 (void *)&cmd_channels_status,
425                 NULL,
426         },
427 };
428
429 /* *** CPU Frequency operations *** */
430 struct cmd_show_cpu_freq_result {
431         cmdline_fixed_string_t show_cpu_freq;
432         uint8_t core_num;
433 };
434
435 static void
436 cmd_show_cpu_freq_parsed(void *parsed_result, struct cmdline *cl,
437                        __rte_unused void *data)
438 {
439         struct cmd_show_cpu_freq_result *res = parsed_result;
440         uint32_t curr_freq = power_manager_get_current_frequency(res->core_num);
441
442         if (curr_freq == 0) {
443                 cmdline_printf(cl, "Unable to get frequency for core %u\n",
444                                 res->core_num);
445                 return;
446         }
447         cmdline_printf(cl, "Core %u frequency: %"PRId32"\n", res->core_num,
448                         curr_freq);
449 }
450
451 cmdline_parse_token_string_t cmd_show_cpu_freq =
452         TOKEN_STRING_INITIALIZER(struct cmd_show_cpu_freq_result,
453                         show_cpu_freq, "show_cpu_freq");
454
455 cmdline_parse_token_num_t cmd_show_cpu_freq_core_num =
456         TOKEN_NUM_INITIALIZER(struct cmd_show_cpu_freq_result,
457                         core_num, RTE_UINT8);
458
459 cmdline_parse_inst_t cmd_show_cpu_freq_set = {
460         .f = cmd_show_cpu_freq_parsed,
461         .data = NULL,
462         .help_str = "Get the current frequency for the specified core",
463         .tokens = {
464                 (void *)&cmd_show_cpu_freq,
465                 (void *)&cmd_show_cpu_freq_core_num,
466                 NULL,
467         },
468 };
469
470 struct cmd_set_cpu_freq_result {
471         cmdline_fixed_string_t set_cpu_freq;
472         uint8_t core_num;
473         cmdline_fixed_string_t cmd;
474 };
475
476 static void
477 cmd_set_cpu_freq_parsed(void *parsed_result, struct cmdline *cl,
478                        __rte_unused void *data)
479 {
480         int ret = -1;
481         struct cmd_set_cpu_freq_result *res = parsed_result;
482
483         if (!strcmp(res->cmd , "up"))
484                 ret = power_manager_scale_core_up(res->core_num);
485         else if (!strcmp(res->cmd , "down"))
486                 ret = power_manager_scale_core_down(res->core_num);
487         else if (!strcmp(res->cmd , "min"))
488                 ret = power_manager_scale_core_min(res->core_num);
489         else if (!strcmp(res->cmd , "max"))
490                 ret = power_manager_scale_core_max(res->core_num);
491         else if (!strcmp(res->cmd, "enable_turbo"))
492                 ret = power_manager_enable_turbo_core(res->core_num);
493         else if (!strcmp(res->cmd, "disable_turbo"))
494                 ret = power_manager_disable_turbo_core(res->core_num);
495         if (ret < 0) {
496                 cmdline_printf(cl, "Error scaling core(%u) '%s'\n", res->core_num,
497                                 res->cmd);
498         }
499 }
500
501 cmdline_parse_token_string_t cmd_set_cpu_freq =
502         TOKEN_STRING_INITIALIZER(struct cmd_set_cpu_freq_result,
503                         set_cpu_freq, "set_cpu_freq");
504 cmdline_parse_token_num_t cmd_set_cpu_freq_core_num =
505         TOKEN_NUM_INITIALIZER(struct cmd_set_cpu_freq_result,
506                         core_num, RTE_UINT8);
507 cmdline_parse_token_string_t cmd_set_cpu_freq_cmd_cmd =
508         TOKEN_STRING_INITIALIZER(struct cmd_set_cpu_freq_result,
509                         cmd, "up#down#min#max#enable_turbo#disable_turbo");
510
511 cmdline_parse_inst_t cmd_set_cpu_freq_set = {
512         .f = cmd_set_cpu_freq_parsed,
513         .data = NULL,
514         .help_str = "set_cpu_freq <core_num> <up|down|min|max|enable_turbo|disable_turbo>, adjust the current "
515                         "frequency for the specified core",
516         .tokens = {
517                 (void *)&cmd_set_cpu_freq,
518                 (void *)&cmd_set_cpu_freq_core_num,
519                 (void *)&cmd_set_cpu_freq_cmd_cmd,
520                 NULL,
521         },
522 };
523
524 cmdline_parse_ctx_t main_ctx[] = {
525                 (cmdline_parse_inst_t *)&cmd_quit,
526                 (cmdline_parse_inst_t *)&cmd_vm_op_set,
527                 (cmdline_parse_inst_t *)&cmd_channels_op_set,
528                 (cmdline_parse_inst_t *)&cmd_channels_status_op_set,
529                 (cmdline_parse_inst_t *)&cmd_show_vm_set,
530                 (cmdline_parse_inst_t *)&cmd_show_cpu_freq_set,
531                 (cmdline_parse_inst_t *)&cmd_set_cpu_freq_set,
532                 (cmdline_parse_inst_t *)&cmd_set_pcpu_set,
533                 (cmdline_parse_inst_t *)&cmd_set_query_set,
534                 NULL,
535 };
536
537 void
538 run_cli(__rte_unused void *arg)
539 {
540         struct cmdline *cl;
541
542         cl = cmdline_stdin_new(main_ctx, "vmpower> ");
543         if (cl == NULL)
544                 return;
545
546         cmdline_interact(cl);
547         cmdline_stdin_exit(cl);
548 }