1
2
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
25struct cmd_quit_result {
26 cmdline_fixed_string_t quit;
27};
28
29static 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
39cmdline_parse_token_string_t cmd_quit_quit =
40 TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
41
42cmdline_parse_inst_t cmd_quit = {
43 .f = cmd_quit_parsed,
44 .data = NULL,
45 .help_str = "close the application",
46 .tokens = {
47 (void *)&cmd_quit_quit,
48 NULL,
49 },
50};
51
52
53struct cmd_show_vm_result {
54 cmdline_fixed_string_t show_vm;
55 cmdline_fixed_string_t vm_name;
56};
57
58static void
59cmd_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
104cmdline_parse_token_string_t cmd_vm_show =
105 TOKEN_STRING_INITIALIZER(struct cmd_show_vm_result,
106 show_vm, "show_vm");
107cmdline_parse_token_string_t cmd_show_vm_name =
108 TOKEN_STRING_INITIALIZER(struct cmd_show_vm_result,
109 vm_name, NULL);
110
111cmdline_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
126
127
128struct 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
135static void
136cmd_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
149cmdline_parse_token_string_t cmd_set_pcpu =
150 TOKEN_STRING_INITIALIZER(struct cmd_set_pcpu_result,
151 set_pcpu, "set_pcpu");
152cmdline_parse_token_string_t cmd_set_pcpu_vm_name =
153 TOKEN_STRING_INITIALIZER(struct cmd_set_pcpu_result,
154 vm_name, NULL);
155cmdline_parse_token_num_t set_pcpu_vcpu =
156 TOKEN_NUM_INITIALIZER(struct cmd_set_pcpu_result,
157 vcpu, RTE_UINT8);
158cmdline_parse_token_num_t set_pcpu_core =
159 TOKEN_NUM_INITIALIZER(struct cmd_set_pcpu_result,
160 core, RTE_UINT64);
161
162
163cmdline_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
177struct cmd_vm_op_result {
178 cmdline_fixed_string_t op_vm;
179 cmdline_fixed_string_t vm_name;
180};
181
182static void
183cmd_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
195cmdline_parse_token_string_t cmd_vm_op =
196 TOKEN_STRING_INITIALIZER(struct cmd_vm_op_result,
197 op_vm, "add_vm#rm_vm");
198cmdline_parse_token_string_t cmd_vm_name =
199 TOKEN_STRING_INITIALIZER(struct cmd_vm_op_result,
200 vm_name, NULL);
201
202cmdline_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
216struct 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};
221static void
222cmd_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
268cmdline_parse_token_string_t cmd_channels_op =
269 TOKEN_STRING_INITIALIZER(struct cmd_channels_op_result,
270 op, "add_channels");
271cmdline_parse_token_string_t cmd_channels_vm_name =
272 TOKEN_STRING_INITIALIZER(struct cmd_channels_op_result,
273 vm_name, NULL);
274cmdline_parse_token_string_t cmd_channels_list =
275 TOKEN_STRING_INITIALIZER(struct cmd_channels_op_result,
276 channel_list, NULL);
277
278cmdline_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
295struct 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
301static void
302cmd_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
319cmdline_parse_token_string_t cmd_set_query =
320 TOKEN_STRING_INITIALIZER(struct cmd_set_query_result,
321 set_query, "set_query");
322cmdline_parse_token_string_t cmd_set_query_vm_name =
323 TOKEN_STRING_INITIALIZER(struct cmd_set_query_result,
324 vm_name, NULL);
325cmdline_parse_token_string_t cmd_set_query_status =
326 TOKEN_STRING_INITIALIZER(struct cmd_set_query_result,
327 query_status, "enable#disable");
328
329cmdline_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
342struct 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
349static void
350cmd_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
397cmdline_parse_token_string_t cmd_channels_status_op =
398 TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
399 op, "set_channel_status");
400cmdline_parse_token_string_t cmd_channels_status_vm_name =
401 TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
402 vm_name, NULL);
403cmdline_parse_token_string_t cmd_channels_status_list =
404 TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
405 channel_list, NULL);
406cmdline_parse_token_string_t cmd_channels_status =
407 TOKEN_STRING_INITIALIZER(struct cmd_channels_status_op_result,
408 status, "enabled#disabled");
409
410cmdline_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
430struct cmd_show_cpu_freq_result {
431 cmdline_fixed_string_t show_cpu_freq;
432 uint8_t core_num;
433};
434
435static void
436cmd_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
451cmdline_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
455cmdline_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
459cmdline_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
470struct 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
476static void
477cmd_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
501cmdline_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");
504cmdline_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);
507cmdline_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
511cmdline_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
524cmdline_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
537void
538run_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}
549