dpdk/examples/vm_power_manager/vm_power_cli.c
<<
>>
Prefs
   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
  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,  /* 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 *** */
  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/* *** vCPU to pCPU mapping operations *** */
 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/* *** VM channel operations *** */
 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/* *** CPU Frequency operations *** */
 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