1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
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>
20 #include "vm_power_cli.h"
21 #include "channel_manager.h"
22 #include "channel_monitor.h"
23 #include "power_manager.h"
24 #include "channel_commands.h"
26 struct cmd_quit_result {
27 cmdline_fixed_string_t quit;
30 static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
32 __attribute__((unused)) void *data)
34 channel_monitor_exit();
35 channel_manager_exit();
40 cmdline_parse_token_string_t cmd_quit_quit =
41 TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
43 cmdline_parse_inst_t cmd_quit = {
44 .f = cmd_quit_parsed, /* function to call */
45 .data = NULL, /* 2nd arg of func */
46 .help_str = "close the application",
47 .tokens = { /* token list, NULL terminated */
48 (void *)&cmd_quit_quit,
53 /* *** VM operations *** */
54 struct cmd_show_vm_result {
55 cmdline_fixed_string_t show_vm;
56 cmdline_fixed_string_t vm_name;
60 cmd_show_vm_parsed(void *parsed_result, struct cmdline *cl,
61 __attribute__((unused)) void *data)
63 struct cmd_show_vm_result *res = parsed_result;
67 if (get_info_vm(res->vm_name, &info) != 0)
69 cmdline_printf(cl, "VM: '%s', status = ", info.name);
70 if (info.status == CHANNEL_MGR_VM_ACTIVE)
71 cmdline_printf(cl, "ACTIVE\n");
73 cmdline_printf(cl, "INACTIVE\n");
74 cmdline_printf(cl, "Channels %u\n", info.num_channels);
75 for (i = 0; i < info.num_channels; i++) {
76 cmdline_printf(cl, " [%u]: %s, status = ", i,
77 info.channels[i].channel_path);
78 switch (info.channels[i].status) {
79 case CHANNEL_MGR_CHANNEL_CONNECTED:
80 cmdline_printf(cl, "CONNECTED\n");
82 case CHANNEL_MGR_CHANNEL_DISCONNECTED:
83 cmdline_printf(cl, "DISCONNECTED\n");
85 case CHANNEL_MGR_CHANNEL_DISABLED:
86 cmdline_printf(cl, "DISABLED\n");
88 case CHANNEL_MGR_CHANNEL_PROCESSING:
89 cmdline_printf(cl, "PROCESSING\n");
92 cmdline_printf(cl, "UNKNOWN\n");
96 cmdline_printf(cl, "Virtual CPU(s): %u\n", info.num_vcpus);
97 for (i = 0; i < info.num_vcpus; i++) {
98 cmdline_printf(cl, " [%u]: Physical CPU Mask 0x%"PRIx64"\n", i,
105 cmdline_parse_token_string_t cmd_vm_show =
106 TOKEN_STRING_INITIALIZER(struct cmd_show_vm_result,
108 cmdline_parse_token_string_t cmd_show_vm_name =
109 TOKEN_STRING_INITIALIZER(struct cmd_show_vm_result,
112 cmdline_parse_inst_t cmd_show_vm_set = {
113 .f = cmd_show_vm_parsed,
115 .help_str = "show_vm <vm_name>, prints the information on the "
116 "specified VM(s), the information lists the number of vCPUS, the "
117 "pinning to pCPU(s) as a bit mask, along with any communication "
118 "channels associated with each VM",
120 (void *)&cmd_vm_show,
121 (void *)&cmd_show_vm_name,
126 /* *** vCPU to pCPU mapping operations *** */
127 struct cmd_set_pcpu_mask_result {
128 cmdline_fixed_string_t set_pcpu_mask;
129 cmdline_fixed_string_t vm_name;
135 cmd_set_pcpu_mask_parsed(void *parsed_result, struct cmdline *cl,
136 __attribute__((unused)) void *data)
138 struct cmd_set_pcpu_mask_result *res = parsed_result;
140 if (set_pcpus_mask(res->vm_name, res->vcpu, res->core_mask) == 0)
141 cmdline_printf(cl, "Pinned vCPU(%"PRId8") to pCPU core "
142 "mask(0x%"PRIx64")\n", res->vcpu, res->core_mask);
144 cmdline_printf(cl, "Unable to pin vCPU(%"PRId8") to pCPU core "
145 "mask(0x%"PRIx64")\n", res->vcpu, res->core_mask);
148 cmdline_parse_token_string_t cmd_set_pcpu_mask =
149 TOKEN_STRING_INITIALIZER(struct cmd_set_pcpu_mask_result,
150 set_pcpu_mask, "set_pcpu_mask");
151 cmdline_parse_token_string_t cmd_set_pcpu_mask_vm_name =
152 TOKEN_STRING_INITIALIZER(struct cmd_set_pcpu_mask_result,
154 cmdline_parse_token_num_t set_pcpu_mask_vcpu =
155 TOKEN_NUM_INITIALIZER(struct cmd_set_pcpu_mask_result,
157 cmdline_parse_token_num_t set_pcpu_mask_core_mask =
158 TOKEN_NUM_INITIALIZER(struct cmd_set_pcpu_mask_result,
162 cmdline_parse_inst_t cmd_set_pcpu_mask_set = {
163 .f = cmd_set_pcpu_mask_parsed,
165 .help_str = "set_pcpu_mask <vm_name> <vcpu> <pcpu>, Set the binding "
166 "of Virtual CPU on VM to the Physical CPU mask.",
168 (void *)&cmd_set_pcpu_mask,
169 (void *)&cmd_set_pcpu_mask_vm_name,
170 (void *)&set_pcpu_mask_vcpu,
171 (void *)&set_pcpu_mask_core_mask,
176 struct cmd_set_pcpu_result {
177 cmdline_fixed_string_t set_pcpu;
178 cmdline_fixed_string_t vm_name;
184 cmd_set_pcpu_parsed(void *parsed_result, struct cmdline *cl,
185 __attribute__((unused)) void *data)
187 struct cmd_set_pcpu_result *res = parsed_result;
189 if (set_pcpu(res->vm_name, res->vcpu, res->core) == 0)
190 cmdline_printf(cl, "Pinned vCPU(%"PRId8") to pCPU core "
191 "%"PRId8")\n", res->vcpu, res->core);
193 cmdline_printf(cl, "Unable to pin vCPU(%"PRId8") to pCPU core "
194 "%"PRId8")\n", res->vcpu, res->core);
197 cmdline_parse_token_string_t cmd_set_pcpu =
198 TOKEN_STRING_INITIALIZER(struct cmd_set_pcpu_result,
199 set_pcpu, "set_pcpu");
200 cmdline_parse_token_string_t cmd_set_pcpu_vm_name =
201 TOKEN_STRING_INITIALIZER(struct cmd_set_pcpu_result,
203 cmdline_parse_token_num_t set_pcpu_vcpu =
204 TOKEN_NUM_INITIALIZER(struct cmd_set_pcpu_result,
206 cmdline_parse_token_num_t set_pcpu_core =
207 TOKEN_NUM_INITIALIZER(struct cmd_set_pcpu_result,
211 cmdline_parse_inst_t cmd_set_pcpu_set = {
212 .f = cmd_set_pcpu_parsed,
214 .help_str = "set_pcpu <vm_name> <vcpu> <pcpu>, Set the binding "
215 "of Virtual CPU on VM to the Physical CPU.",
217 (void *)&cmd_set_pcpu,
218 (void *)&cmd_set_pcpu_vm_name,
219 (void *)&set_pcpu_vcpu,
220 (void *)&set_pcpu_core,
225 struct cmd_vm_op_result {
226 cmdline_fixed_string_t op_vm;
227 cmdline_fixed_string_t vm_name;
231 cmd_vm_op_parsed(void *parsed_result, struct cmdline *cl,
232 __attribute__((unused)) void *data)
234 struct cmd_vm_op_result *res = parsed_result;
236 if (!strcmp(res->op_vm, "add_vm")) {
237 if (add_vm(res->vm_name) < 0)
238 cmdline_printf(cl, "Unable to add VM '%s'\n", res->vm_name);
239 } else if (remove_vm(res->vm_name) < 0)
240 cmdline_printf(cl, "Unable to remove VM '%s'\n", res->vm_name);
243 cmdline_parse_token_string_t cmd_vm_op =
244 TOKEN_STRING_INITIALIZER(struct cmd_vm_op_result,
245 op_vm, "add_vm#rm_vm");
246 cmdline_parse_token_string_t cmd_vm_name =
247 TOKEN_STRING_INITIALIZER(struct cmd_vm_op_result,
250 cmdline_parse_inst_t cmd_vm_op_set = {
251 .f = cmd_vm_op_parsed,
253 .help_str = "add_vm|rm_vm <name>, add a VM for "
254 "subsequent operations with the CLI or remove a previously added "
255 "VM from the VM Power Manager",
258 (void *)&cmd_vm_name,
263 /* *** VM channel operations *** */
264 struct cmd_channels_op_result {
265 cmdline_fixed_string_t op;
266 cmdline_fixed_string_t vm_name;
267 cmdline_fixed_string_t channel_list;
270 cmd_channels_op_parsed(void *parsed_result, struct cmdline *cl,
271 __attribute__((unused)) void *data)
273 unsigned num_channels = 0, channel_num, i;
275 unsigned channel_list[CHANNEL_CMDS_MAX_VM_CHANNELS];
276 char *token, *remaining, *tail_ptr;
277 struct cmd_channels_op_result *res = parsed_result;
279 if (!strcmp(res->channel_list, "all")) {
280 channels_added = add_all_channels(res->vm_name);
281 cmdline_printf(cl, "Added %d channels for VM '%s'\n",
282 channels_added, res->vm_name);
286 remaining = res->channel_list;
288 if (remaining == NULL || remaining[0] == '\0')
291 token = strsep(&remaining, ",");
295 channel_num = (unsigned)strtol(token, &tail_ptr, 10);
296 if ((errno != 0) || tail_ptr == NULL || (*tail_ptr != '\0'))
299 if (channel_num == CHANNEL_CMDS_MAX_VM_CHANNELS) {
300 cmdline_printf(cl, "Channel number '%u' exceeds the maximum number "
301 "of allowable channels(%u) for VM '%s'\n", channel_num,
302 CHANNEL_CMDS_MAX_VM_CHANNELS, res->vm_name);
305 channel_list[num_channels++] = channel_num;
307 for (i = 0; i < num_channels; i++)
308 cmdline_printf(cl, "[%u]: Adding channel %u\n", i, channel_list[i]);
310 channels_added = add_channels(res->vm_name, channel_list,
312 cmdline_printf(cl, "Enabled %d channels for '%s'\n", channels_added,
316 cmdline_parse_token_string_t cmd_channels_op =
317 TOKEN_STRING_INITIALIZER(struct cmd_channels_op_result,
319 cmdline_parse_token_string_t cmd_channels_vm_name =
320 TOKEN_STRING_INITIALIZER(struct cmd_channels_op_result,
322 cmdline_parse_token_string_t cmd_channels_list =
323 TOKEN_STRING_INITIALIZER(struct cmd_channels_op_result,
326 cmdline_parse_inst_t cmd_channels_op_set = {
327 .f = cmd_channels_op_parsed,
329 .help_str = "add_channels <vm_name> <list>|all, add "
330 "communication channels for the specified VM, the "
331 "virtio channels must be enabled in the VM "
332 "configuration(qemu/libvirt) and the associated VM must be active. "
333 "<list> is a comma-separated list of channel numbers to add, using "
334 "the keyword 'all' will attempt to add all channels for the VM",
336 (void *)&cmd_channels_op,
337 (void *)&cmd_channels_vm_name,
338 (void *)&cmd_channels_list,
343 struct cmd_channels_status_op_result {
344 cmdline_fixed_string_t op;
345 cmdline_fixed_string_t vm_name;
346 cmdline_fixed_string_t channel_list;
347 cmdline_fixed_string_t status;
351 cmd_channels_status_op_parsed(void *parsed_result, struct cmdline *cl,
352 __attribute__((unused)) void *data)
354 unsigned num_channels = 0, channel_num;
356 unsigned channel_list[CHANNEL_CMDS_MAX_VM_CHANNELS];
357 char *token, *remaining, *tail_ptr;
358 struct cmd_channels_status_op_result *res = parsed_result;
359 enum channel_status status;
361 if (!strcmp(res->status, "enabled"))
362 status = CHANNEL_MGR_CHANNEL_CONNECTED;
364 status = CHANNEL_MGR_CHANNEL_DISABLED;
366 if (!strcmp(res->channel_list, "all")) {
367 changed = set_channel_status_all(res->vm_name, status);
368 cmdline_printf(cl, "Updated status of %d channels "
369 "for VM '%s'\n", changed, res->vm_name);
372 remaining = res->channel_list;
374 if (remaining == NULL || remaining[0] == '\0')
376 token = strsep(&remaining, ",");
380 channel_num = (unsigned)strtol(token, &tail_ptr, 10);
381 if ((errno != 0) || tail_ptr == NULL || (*tail_ptr != '\0'))
384 if (channel_num == CHANNEL_CMDS_MAX_VM_CHANNELS) {
385 cmdline_printf(cl, "%u exceeds the maximum number of allowable "
386 "channels(%u) for VM '%s'\n", channel_num,
387 CHANNEL_CMDS_MAX_VM_CHANNELS, res->vm_name);
390 channel_list[num_channels++] = channel_num;
392 changed = set_channel_status(res->vm_name, channel_list, num_channels,
394 cmdline_printf(cl, "Updated status of %d channels "
395 "for VM '%s'\n", changed, res->vm_name);
398 cmdline_parse_token_string_t cmd_channels_status_op =
399 TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
400 op, "set_channel_status");
401 cmdline_parse_token_string_t cmd_channels_status_vm_name =
402 TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
404 cmdline_parse_token_string_t cmd_channels_status_list =
405 TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
407 cmdline_parse_token_string_t cmd_channels_status =
408 TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
409 status, "enabled#disabled");
411 cmdline_parse_inst_t cmd_channels_status_op_set = {
412 .f = cmd_channels_status_op_parsed,
414 .help_str = "set_channel_status <vm_name> <list>|all enabled|disabled, "
415 " enable or disable the communication channels in "
416 "list(comma-separated) for the specified VM, alternatively "
417 "list can be replaced with keyword 'all'. "
418 "Disabled channels will still receive packets on the host, "
419 "however the commands they specify will be ignored. "
420 "Set status to 'enabled' to begin processing requests again.",
422 (void *)&cmd_channels_status_op,
423 (void *)&cmd_channels_status_vm_name,
424 (void *)&cmd_channels_status_list,
425 (void *)&cmd_channels_status,
430 /* *** CPU Frequency operations *** */
431 struct cmd_show_cpu_freq_mask_result {
432 cmdline_fixed_string_t show_cpu_freq_mask;
437 cmd_show_cpu_freq_mask_parsed(void *parsed_result, struct cmdline *cl,
438 __attribute__((unused)) void *data)
440 struct cmd_show_cpu_freq_mask_result *res = parsed_result;
442 uint64_t mask = res->core_mask;
445 for (i = 0; mask; mask &= ~(1ULL << i++)) {
446 if ((mask >> i) & 1) {
447 freq = power_manager_get_current_frequency(i);
449 cmdline_printf(cl, "Core %u: %"PRId32"\n", i, freq);
454 cmdline_parse_token_string_t cmd_show_cpu_freq_mask =
455 TOKEN_STRING_INITIALIZER(struct cmd_show_cpu_freq_mask_result,
456 show_cpu_freq_mask, "show_cpu_freq_mask");
457 cmdline_parse_token_num_t cmd_show_cpu_freq_mask_core_mask =
458 TOKEN_NUM_INITIALIZER(struct cmd_show_cpu_freq_mask_result,
461 cmdline_parse_inst_t cmd_show_cpu_freq_mask_set = {
462 .f = cmd_show_cpu_freq_mask_parsed,
464 .help_str = "show_cpu_freq_mask <mask>, Get the current frequency for each "
465 "core specified in the mask",
467 (void *)&cmd_show_cpu_freq_mask,
468 (void *)&cmd_show_cpu_freq_mask_core_mask,
473 struct cmd_set_cpu_freq_mask_result {
474 cmdline_fixed_string_t set_cpu_freq_mask;
476 cmdline_fixed_string_t cmd;
480 cmd_set_cpu_freq_mask_parsed(void *parsed_result, struct cmdline *cl,
481 __attribute__((unused)) void *data)
483 struct cmd_set_cpu_freq_mask_result *res = parsed_result;
486 if (!strcmp(res->cmd , "up"))
487 ret = power_manager_scale_mask_up(res->core_mask);
488 else if (!strcmp(res->cmd , "down"))
489 ret = power_manager_scale_mask_down(res->core_mask);
490 else if (!strcmp(res->cmd , "min"))
491 ret = power_manager_scale_mask_min(res->core_mask);
492 else if (!strcmp(res->cmd , "max"))
493 ret = power_manager_scale_mask_max(res->core_mask);
494 else if (!strcmp(res->cmd, "enable_turbo"))
495 ret = power_manager_enable_turbo_mask(res->core_mask);
496 else if (!strcmp(res->cmd, "disable_turbo"))
497 ret = power_manager_disable_turbo_mask(res->core_mask);
499 cmdline_printf(cl, "Error scaling core_mask(0x%"PRIx64") '%s' , not "
500 "all cores specified have been scaled\n",
501 res->core_mask, res->cmd);
505 cmdline_parse_token_string_t cmd_set_cpu_freq_mask =
506 TOKEN_STRING_INITIALIZER(struct cmd_set_cpu_freq_mask_result,
507 set_cpu_freq_mask, "set_cpu_freq_mask");
508 cmdline_parse_token_num_t cmd_set_cpu_freq_mask_core_mask =
509 TOKEN_NUM_INITIALIZER(struct cmd_set_cpu_freq_mask_result,
511 cmdline_parse_token_string_t cmd_set_cpu_freq_mask_result =
512 TOKEN_STRING_INITIALIZER(struct cmd_set_cpu_freq_mask_result,
513 cmd, "up#down#min#max#enable_turbo#disable_turbo");
515 cmdline_parse_inst_t cmd_set_cpu_freq_mask_set = {
516 .f = cmd_set_cpu_freq_mask_parsed,
518 .help_str = "set_cpu_freq <core_mask> <up|down|min|max|enable_turbo|disable_turbo>, adjust the current "
519 "frequency for the cores specified in <core_mask>",
521 (void *)&cmd_set_cpu_freq_mask,
522 (void *)&cmd_set_cpu_freq_mask_core_mask,
523 (void *)&cmd_set_cpu_freq_mask_result,
530 struct cmd_show_cpu_freq_result {
531 cmdline_fixed_string_t show_cpu_freq;
536 cmd_show_cpu_freq_parsed(void *parsed_result, struct cmdline *cl,
537 __attribute__((unused)) void *data)
539 struct cmd_show_cpu_freq_result *res = parsed_result;
540 uint32_t curr_freq = power_manager_get_current_frequency(res->core_num);
542 if (curr_freq == 0) {
543 cmdline_printf(cl, "Unable to get frequency for core %u\n",
547 cmdline_printf(cl, "Core %u frequency: %"PRId32"\n", res->core_num,
551 cmdline_parse_token_string_t cmd_show_cpu_freq =
552 TOKEN_STRING_INITIALIZER(struct cmd_show_cpu_freq_result,
553 show_cpu_freq, "show_cpu_freq");
555 cmdline_parse_token_num_t cmd_show_cpu_freq_core_num =
556 TOKEN_NUM_INITIALIZER(struct cmd_show_cpu_freq_result,
559 cmdline_parse_inst_t cmd_show_cpu_freq_set = {
560 .f = cmd_show_cpu_freq_parsed,
562 .help_str = "Get the current frequency for the specified core",
564 (void *)&cmd_show_cpu_freq,
565 (void *)&cmd_show_cpu_freq_core_num,
570 struct cmd_set_cpu_freq_result {
571 cmdline_fixed_string_t set_cpu_freq;
573 cmdline_fixed_string_t cmd;
577 cmd_set_cpu_freq_parsed(void *parsed_result, struct cmdline *cl,
578 __attribute__((unused)) void *data)
581 struct cmd_set_cpu_freq_result *res = parsed_result;
583 if (!strcmp(res->cmd , "up"))
584 ret = power_manager_scale_core_up(res->core_num);
585 else if (!strcmp(res->cmd , "down"))
586 ret = power_manager_scale_core_down(res->core_num);
587 else if (!strcmp(res->cmd , "min"))
588 ret = power_manager_scale_core_min(res->core_num);
589 else if (!strcmp(res->cmd , "max"))
590 ret = power_manager_scale_core_max(res->core_num);
591 else if (!strcmp(res->cmd, "enable_turbo"))
592 ret = power_manager_enable_turbo_core(res->core_num);
593 else if (!strcmp(res->cmd, "disable_turbo"))
594 ret = power_manager_disable_turbo_core(res->core_num);
596 cmdline_printf(cl, "Error scaling core(%u) '%s'\n", res->core_num,
601 cmdline_parse_token_string_t cmd_set_cpu_freq =
602 TOKEN_STRING_INITIALIZER(struct cmd_set_cpu_freq_result,
603 set_cpu_freq, "set_cpu_freq");
604 cmdline_parse_token_num_t cmd_set_cpu_freq_core_num =
605 TOKEN_NUM_INITIALIZER(struct cmd_set_cpu_freq_result,
607 cmdline_parse_token_string_t cmd_set_cpu_freq_cmd_cmd =
608 TOKEN_STRING_INITIALIZER(struct cmd_set_cpu_freq_result,
609 cmd, "up#down#min#max#enable_turbo#disable_turbo");
611 cmdline_parse_inst_t cmd_set_cpu_freq_set = {
612 .f = cmd_set_cpu_freq_parsed,
614 .help_str = "set_cpu_freq <core_num> <up|down|min|max|enable_turbo|disable_turbo>, adjust the current "
615 "frequency for the specified core",
617 (void *)&cmd_set_cpu_freq,
618 (void *)&cmd_set_cpu_freq_core_num,
619 (void *)&cmd_set_cpu_freq_cmd_cmd,
624 cmdline_parse_ctx_t main_ctx[] = {
625 (cmdline_parse_inst_t *)&cmd_quit,
626 (cmdline_parse_inst_t *)&cmd_vm_op_set,
627 (cmdline_parse_inst_t *)&cmd_channels_op_set,
628 (cmdline_parse_inst_t *)&cmd_channels_status_op_set,
629 (cmdline_parse_inst_t *)&cmd_show_vm_set,
630 (cmdline_parse_inst_t *)&cmd_show_cpu_freq_mask_set,
631 (cmdline_parse_inst_t *)&cmd_set_cpu_freq_mask_set,
632 (cmdline_parse_inst_t *)&cmd_show_cpu_freq_set,
633 (cmdline_parse_inst_t *)&cmd_set_cpu_freq_set,
634 (cmdline_parse_inst_t *)&cmd_set_pcpu_mask_set,
635 (cmdline_parse_inst_t *)&cmd_set_pcpu_set,
640 run_cli(__attribute__((unused)) void *arg)
644 cl = cmdline_stdin_new(main_ctx, "vmpower> ");
648 cmdline_interact(cl);
649 cmdline_stdin_exit(cl);