/* * virsh-host.c: Commands in "Host and Hypervisor" group. * * Copyright (C) 2005, 2007-2012 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . * * Daniel Veillard * Karel Zak * Daniel P. Berrange * */ #include #include "virsh-host.h" #include #include #include #include #include "internal.h" #include "buf.h" #include "memory.h" #include "util.h" #include "virsh-domain.h" #include "xml.h" #include "virtypedparam.h" #include "json.h" /* * "capabilities" command */ static const vshCmdInfo info_capabilities[] = { {"help", N_("capabilities")}, {"desc", N_("Returns capabilities of hypervisor/driver.")}, {NULL, NULL} }; static bool cmdCapabilities(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { char *caps; if ((caps = virConnectGetCapabilities(ctl->conn)) == NULL) { vshError(ctl, "%s", _("failed to get capabilities")); return false; } vshPrint(ctl, "%s\n", caps); VIR_FREE(caps); return true; } /* * "connect" command */ static const vshCmdInfo info_connect[] = { {"help", N_("(re)connect to hypervisor")}, {"desc", N_("Connect to local hypervisor. This is built-in command after shell start up.")}, {NULL, NULL} }; static const vshCmdOptDef opts_connect[] = { {"name", VSH_OT_DATA, VSH_OFLAG_EMPTY_OK, N_("hypervisor connection URI")}, {"readonly", VSH_OT_BOOL, 0, N_("read-only connection")}, {NULL, 0, 0, NULL} }; static bool cmdConnect(vshControl *ctl, const vshCmd *cmd) { bool ro = vshCommandOptBool(cmd, "readonly"); const char *name = NULL; if (ctl->conn) { int ret; if ((ret = virConnectClose(ctl->conn)) != 0) { vshError(ctl, _("Failed to disconnect from the hypervisor, %d leaked reference(s)"), ret); return false; } ctl->conn = NULL; } VIR_FREE(ctl->name); if (vshCommandOptString(cmd, "name", &name) < 0) { vshError(ctl, "%s", _("Please specify valid connection URI")); return false; } ctl->name = vshStrdup(ctl, name); ctl->useGetInfo = false; ctl->useSnapshotOld = false; ctl->readonly = ro; ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault, ctl->readonly ? VIR_CONNECT_RO : 0); if (!ctl->conn) vshError(ctl, "%s", _("Failed to connect to the hypervisor")); return !!ctl->conn; } /* * "freecell" command */ static const vshCmdInfo info_freecell[] = { {"help", N_("NUMA free memory")}, {"desc", N_("display available free memory for the NUMA cell.")}, {NULL, NULL} }; static const vshCmdOptDef opts_freecell[] = { {"cellno", VSH_OT_INT, 0, N_("NUMA cell number")}, {"all", VSH_OT_BOOL, 0, N_("show free memory for all NUMA cells")}, {NULL, 0, 0, NULL} }; static bool cmdFreecell(vshControl *ctl, const vshCmd *cmd) { bool func_ret = false; int ret; int cell = -1, cell_given; unsigned long long memory; xmlNodePtr *nodes = NULL; unsigned long nodes_cnt; unsigned long *nodes_id = NULL; unsigned long long *nodes_free = NULL; int all_given; int i; char *cap_xml = NULL; xmlDocPtr xml = NULL; xmlXPathContextPtr ctxt = NULL; if ((cell_given = vshCommandOptInt(cmd, "cellno", &cell)) < 0) { vshError(ctl, "%s", _("cell number has to be a number")); goto cleanup; } all_given = vshCommandOptBool(cmd, "all"); if (all_given && cell_given) { vshError(ctl, "%s", _("--cellno and --all are mutually exclusive. " "Please choose only one.")); goto cleanup; } if (all_given) { cap_xml = virConnectGetCapabilities(ctl->conn); if (!cap_xml) { vshError(ctl, "%s", _("unable to get node capabilities")); goto cleanup; } xml = virXMLParseStringCtxt(cap_xml, _("(capabilities)"), &ctxt); if (!xml) { vshError(ctl, "%s", _("unable to get node capabilities")); goto cleanup; } nodes_cnt = virXPathNodeSet("/capabilities/host/topology/cells/cell", ctxt, &nodes); if (nodes_cnt == -1) { vshError(ctl, "%s", _("could not get information about " "NUMA topology")); goto cleanup; } nodes_free = vshCalloc(ctl, nodes_cnt, sizeof(*nodes_free)); nodes_id = vshCalloc(ctl, nodes_cnt, sizeof(*nodes_id)); for (i = 0; i < nodes_cnt; i++) { unsigned long id; char *val = virXMLPropString(nodes[i], "id"); if (virStrToLong_ul(val, NULL, 10, &id)) { vshError(ctl, "%s", _("conversion from string failed")); VIR_FREE(val); goto cleanup; } VIR_FREE(val); nodes_id[i]=id; ret = virNodeGetCellsFreeMemory(ctl->conn, &(nodes_free[i]), id, 1); if (ret != 1) { vshError(ctl, _("failed to get free memory for NUMA node " "number: %lu"), id); goto cleanup; } } memory = 0; for (cell = 0; cell < nodes_cnt; cell++) { vshPrint(ctl, "%5lu: %10llu KiB\n", nodes_id[cell], (nodes_free[cell]/1024)); memory += nodes_free[cell]; } vshPrintExtra(ctl, "--------------------\n"); vshPrintExtra(ctl, "%5s: %10llu KiB\n", _("Total"), memory/1024); } else { if (!cell_given) { memory = virNodeGetFreeMemory(ctl->conn); if (memory == 0) goto cleanup; } else { ret = virNodeGetCellsFreeMemory(ctl->conn, &memory, cell, 1); if (ret != 1) goto cleanup; } if (cell == -1) vshPrint(ctl, "%s: %llu KiB\n", _("Total"), (memory/1024)); else vshPrint(ctl, "%d: %llu KiB\n", cell, (memory/1024)); } func_ret = true; cleanup: xmlXPathFreeContext(ctxt); xmlFreeDoc(xml); VIR_FREE(nodes); VIR_FREE(nodes_free); VIR_FREE(nodes_id); VIR_FREE(cap_xml); return func_ret; } /* * "nodeinfo" command */ static const vshCmdInfo info_nodeinfo[] = { {"help", N_("node information")}, {"desc", N_("Returns basic information about the node.")}, {NULL, NULL} }; static bool cmdNodeinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { virNodeInfo info; if (virNodeGetInfo(ctl->conn, &info) < 0) { vshError(ctl, "%s", _("failed to get node information")); return false; } vshPrint(ctl, "%-20s %s\n", _("CPU model:"), info.model); vshPrint(ctl, "%-20s %d\n", _("CPU(s):"), info.cpus); vshPrint(ctl, "%-20s %d MHz\n", _("CPU frequency:"), info.mhz); vshPrint(ctl, "%-20s %d\n", _("CPU socket(s):"), info.sockets); vshPrint(ctl, "%-20s %d\n", _("Core(s) per socket:"), info.cores); vshPrint(ctl, "%-20s %d\n", _("Thread(s) per core:"), info.threads); vshPrint(ctl, "%-20s %d\n", _("NUMA cell(s):"), info.nodes); vshPrint(ctl, "%-20s %lu KiB\n", _("Memory size:"), info.memory); return true; } /* * "nodecpumap" command */ static const vshCmdInfo info_node_cpumap[] = { {"help", N_("node cpu map")}, {"desc", N_("Displays the node's total number of CPUs, the number of" " online CPUs and the list of online CPUs.")}, {NULL, NULL} }; static bool cmdNodeCpuMap(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { int cpu, cpunum; unsigned char *cpumap = NULL; unsigned int online; bool ret = false; cpunum = virNodeGetCPUMap(ctl->conn, &cpumap, &online, 0); if (cpunum < 0) { vshError(ctl, "%s", _("Unable to get cpu map")); goto cleanup; } vshPrint(ctl, "%-15s %d\n", _("CPUs present:"), cpunum); vshPrint(ctl, "%-15s %d\n", _("CPUs online:"), online); vshPrint(ctl, "%-15s ", _("CPU map:")); for (cpu = 0; cpu < cpunum; cpu++) vshPrint(ctl, "%c", VIR_CPU_USED(cpumap, cpu) ? 'y' : '-'); vshPrint(ctl, "\n"); ret = true; cleanup: VIR_FREE(cpumap); return ret; } /* * "nodecpustats" command */ static const vshCmdInfo info_nodecpustats[] = { {"help", N_("Prints cpu stats of the node.")}, {"desc", N_("Returns cpu stats of the node, in nanoseconds.")}, {NULL, NULL} }; static const vshCmdOptDef opts_node_cpustats[] = { {"cpu", VSH_OT_INT, 0, N_("prints specified cpu statistics only.")}, {"percent", VSH_OT_BOOL, 0, N_("prints by percentage during 1 second.")}, {NULL, 0, 0, NULL} }; static bool cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd) { int i, j; bool flag_utilization = false; bool flag_percent = vshCommandOptBool(cmd, "percent"); int cpuNum = VIR_NODE_CPU_STATS_ALL_CPUS; virNodeCPUStatsPtr params; int nparams = 0; bool ret = false; struct cpu_stats { unsigned long long user; unsigned long long sys; unsigned long long idle; unsigned long long iowait; unsigned long long util; } cpu_stats[2]; double user_time, sys_time, idle_time, iowait_time, total_time; double usage; if (vshCommandOptInt(cmd, "cpu", &cpuNum) < 0) { vshError(ctl, "%s", _("Invalid value of cpuNum")); return false; } if (virNodeGetCPUStats(ctl->conn, cpuNum, NULL, &nparams, 0) != 0) { vshError(ctl, "%s", _("Unable to get number of cpu stats")); return false; } if (nparams == 0) { /* nothing to output */ return true; } memset(cpu_stats, 0, sizeof(cpu_stats)); params = vshCalloc(ctl, nparams, sizeof(*params)); for (i = 0; i < 2; i++) { if (i > 0) sleep(1); if (virNodeGetCPUStats(ctl->conn, cpuNum, params, &nparams, 0) != 0) { vshError(ctl, "%s", _("Unable to get node cpu stats")); goto cleanup; } for (j = 0; j < nparams; j++) { unsigned long long value = params[j].value; if (STREQ(params[j].field, VIR_NODE_CPU_STATS_KERNEL)) { cpu_stats[i].sys = value; } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_USER)) { cpu_stats[i].user = value; } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IDLE)) { cpu_stats[i].idle = value; } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IOWAIT)) { cpu_stats[i].iowait = value; } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_UTILIZATION)) { cpu_stats[i].util = value; flag_utilization = true; } } if (flag_utilization || !flag_percent) break; } if (!flag_percent) { if (!flag_utilization) { vshPrint(ctl, "%-15s %20llu\n", _("user:"), cpu_stats[0].user); vshPrint(ctl, "%-15s %20llu\n", _("system:"), cpu_stats[0].sys); vshPrint(ctl, "%-15s %20llu\n", _("idle:"), cpu_stats[0].idle); vshPrint(ctl, "%-15s %20llu\n", _("iowait:"), cpu_stats[0].iowait); } } else { if (flag_utilization) { usage = cpu_stats[0].util; vshPrint(ctl, "%-15s %5.1lf%%\n", _("usage:"), usage); vshPrint(ctl, "%-15s %5.1lf%%\n", _("idle:"), 100 - usage); } else { user_time = cpu_stats[1].user - cpu_stats[0].user; sys_time = cpu_stats[1].sys - cpu_stats[0].sys; idle_time = cpu_stats[1].idle - cpu_stats[0].idle; iowait_time = cpu_stats[1].iowait - cpu_stats[0].iowait; total_time = user_time + sys_time + idle_time + iowait_time; usage = (user_time + sys_time) / total_time * 100; vshPrint(ctl, "%-15s %5.1lf%%\n", _("usage:"), usage); vshPrint(ctl, "%-15s %5.1lf%%\n", _("user:"), user_time / total_time * 100); vshPrint(ctl, "%-15s %5.1lf%%\n", _("system:"), sys_time / total_time * 100); vshPrint(ctl, "%-15s %5.1lf%%\n", _("idle:"), idle_time / total_time * 100); vshPrint(ctl, "%-15s %5.1lf%%\n", _("iowait:"), iowait_time / total_time * 100); } } ret = true; cleanup: VIR_FREE(params); return ret; } /* * "nodememstats" command */ static const vshCmdInfo info_nodememstats[] = { {"help", N_("Prints memory stats of the node.")}, {"desc", N_("Returns memory stats of the node, in kilobytes.")}, {NULL, NULL} }; static const vshCmdOptDef opts_node_memstats[] = { {"cell", VSH_OT_INT, 0, N_("prints specified cell statistics only.")}, {NULL, 0, 0, NULL} }; static bool cmdNodeMemStats(vshControl *ctl, const vshCmd *cmd) { int nparams = 0; unsigned int i = 0; int cellNum = VIR_NODE_MEMORY_STATS_ALL_CELLS; virNodeMemoryStatsPtr params = NULL; bool ret = false; if (vshCommandOptInt(cmd, "cell", &cellNum) < 0) { vshError(ctl, "%s", _("Invalid value of cellNum")); return false; } /* get the number of memory parameters */ if (virNodeGetMemoryStats(ctl->conn, cellNum, NULL, &nparams, 0) != 0) { vshError(ctl, "%s", _("Unable to get number of memory stats")); goto cleanup; } if (nparams == 0) { /* nothing to output */ ret = true; goto cleanup; } /* now go get all the memory parameters */ params = vshCalloc(ctl, nparams, sizeof(*params)); if (virNodeGetMemoryStats(ctl->conn, cellNum, params, &nparams, 0) != 0) { vshError(ctl, "%s", _("Unable to get memory stats")); goto cleanup; } for (i = 0; i < nparams; i++) vshPrint(ctl, "%-7s: %20llu KiB\n", params[i].field, params[i].value); ret = true; cleanup: VIR_FREE(params); return ret; } /* * "nodesuspend" command */ static const vshCmdInfo info_nodesuspend[] = { {"help", N_("suspend the host node for a given time duration")}, {"desc", N_("Suspend the host node for a given time duration " "and attempt to resume thereafter.")}, {NULL, NULL} }; static const vshCmdOptDef opts_node_suspend[] = { {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("mem(Suspend-to-RAM), " "disk(Suspend-to-Disk), hybrid(Hybrid-Suspend)")}, {"duration", VSH_OT_INT, VSH_OFLAG_REQ, N_("Suspend duration in seconds, at least 60")}, {NULL, 0, 0, NULL} }; static bool cmdNodeSuspend(vshControl *ctl, const vshCmd *cmd) { const char *target = NULL; unsigned int suspendTarget; long long duration; if (vshCommandOptString(cmd, "target", &target) < 0) { vshError(ctl, _("Invalid target argument")); return false; } if (vshCommandOptLongLong(cmd, "duration", &duration) < 0) { vshError(ctl, _("Invalid duration argument")); return false; } if (STREQ(target, "mem")) suspendTarget = VIR_NODE_SUSPEND_TARGET_MEM; else if (STREQ(target, "disk")) suspendTarget = VIR_NODE_SUSPEND_TARGET_DISK; else if (STREQ(target, "hybrid")) suspendTarget = VIR_NODE_SUSPEND_TARGET_HYBRID; else { vshError(ctl, "%s", _("Invalid target")); return false; } if (duration <= 0) { vshError(ctl, "%s", _("Invalid duration")); return false; } if (virNodeSuspendForDuration(ctl->conn, suspendTarget, duration, 0) < 0) { vshError(ctl, "%s", _("The host was not suspended")); return false; } return true; } /* * "qemu-monitor-command" command */ static const vshCmdInfo info_qemu_monitor_command[] = { {"help", N_("QEMU Monitor Command")}, {"desc", N_("QEMU Monitor Command")}, {NULL, NULL} }; static const vshCmdOptDef opts_qemu_monitor_command[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"hmp", VSH_OT_BOOL, 0, N_("command is in human monitor protocol")}, {"pretty", VSH_OT_BOOL, 0, N_("pretty-print any qemu monitor protocol output")}, {"cmd", VSH_OT_ARGV, VSH_OFLAG_REQ, N_("command")}, {NULL, 0, 0, NULL} }; static bool cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom = NULL; bool ret = false; char *monitor_cmd = NULL; char *result = NULL; unsigned int flags = 0; const vshCmdOpt *opt = NULL; virBuffer buf = VIR_BUFFER_INITIALIZER; bool pad = false; virJSONValuePtr pretty = NULL; dom = vshCommandOptDomain(ctl, cmd, NULL); if (dom == NULL) goto cleanup; while ((opt = vshCommandOptArgv(cmd, opt))) { if (pad) virBufferAddChar(&buf, ' '); pad = true; virBufferAdd(&buf, opt->data, -1); } if (virBufferError(&buf)) { vshPrint(ctl, "%s", _("Failed to collect command")); goto cleanup; } monitor_cmd = virBufferContentAndReset(&buf); if (vshCommandOptBool(cmd, "hmp")) { if (vshCommandOptBool(cmd, "pretty")) { vshError(ctl, _("--hmp and --pretty are not compatible")); goto cleanup; } flags |= VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP; } if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0) goto cleanup; if (vshCommandOptBool(cmd, "pretty")) { char *tmp; pretty = virJSONValueFromString(result); if (pretty && (tmp = virJSONValueToString(pretty, true))) { VIR_FREE(result); result = tmp; } else { vshResetLibvirtError(); } } vshPrint(ctl, "%s\n", result); ret = true; cleanup: VIR_FREE(result); VIR_FREE(monitor_cmd); virJSONValueFree(pretty); if (dom) virDomainFree(dom); return ret; } /* * "qemu-attach" command */ static const vshCmdInfo info_qemu_attach[] = { {"help", N_("QEMU Attach")}, {"desc", N_("QEMU Attach")}, {NULL, NULL} }; static const vshCmdOptDef opts_qemu_attach[] = { {"pid", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pid")}, {NULL, 0, 0, NULL} }; static bool cmdQemuAttach(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom = NULL; bool ret = false; unsigned int flags = 0; unsigned int pid_value; /* API uses unsigned int, not pid_t */ if (vshCommandOptUInt(cmd, "pid", &pid_value) <= 0) { vshError(ctl, "%s", _("missing pid value")); goto cleanup; } if (!(dom = virDomainQemuAttach(ctl->conn, pid_value, flags))) goto cleanup; if (dom != NULL) { vshPrint(ctl, _("Domain %s attached to pid %u\n"), virDomainGetName(dom), pid_value); virDomainFree(dom); ret = true; } else { vshError(ctl, _("Failed to attach to pid %u"), pid_value); } cleanup: return ret; } /* * "qemu-agent-command" command */ static const vshCmdInfo info_qemu_agent_command[] = { {"help", N_("QEMU Guest Agent Command")}, {"desc", N_("Run an arbitrary qemu guest agent command; use at your own risk")}, {NULL, NULL} }; static const vshCmdOptDef opts_qemu_agent_command[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"timeout", VSH_OT_INT, VSH_OFLAG_REQ_OPT, N_("timeout seconds. must be positive.")}, {"async", VSH_OT_BOOL, 0, N_("execute command without waiting for timeout")}, {"block", VSH_OT_BOOL, 0, N_("execute command without timeout")}, {"cmd", VSH_OT_ARGV, VSH_OFLAG_REQ, N_("command")}, {NULL, 0, 0, NULL} }; static bool cmdQemuAgentCommand(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom = NULL; bool ret = false; char *guest_agent_cmd = NULL; char *result = NULL; int timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT; int judge = 0; unsigned int flags = 0; const vshCmdOpt *opt = NULL; virBuffer buf = VIR_BUFFER_INITIALIZER; bool pad = false; dom = vshCommandOptDomain(ctl, cmd, NULL); if (dom == NULL) goto cleanup; while ((opt = vshCommandOptArgv(cmd, opt))) { if (pad) virBufferAddChar(&buf, ' '); pad = true; virBufferAdd(&buf, opt->data, -1); } if (virBufferError(&buf)) { vshPrint(ctl, "%s", _("Failed to collect command")); goto cleanup; } guest_agent_cmd = virBufferContentAndReset(&buf); judge = vshCommandOptInt(cmd, "timeout", &timeout); if (judge < 0) { vshError(ctl, "%s", _("timeout number has to be a number")); goto cleanup; } else if (judge > 0) { judge = 1; } if (judge && timeout < 1) { vshError(ctl, "%s", _("timeout must be positive")); goto cleanup; } if (vshCommandOptBool(cmd, "async")) { timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT; judge++; } if (vshCommandOptBool(cmd, "block")) { timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK; judge++; } if (judge > 1) { vshError(ctl, "%s", _("timeout, async and block options are exclusive")); goto cleanup; } result = virDomainQemuAgentCommand(dom, guest_agent_cmd, timeout, flags); if (result) printf("%s\n", result); ret = true; cleanup: VIR_FREE(result); VIR_FREE(guest_agent_cmd); if (dom) virDomainFree(dom); return ret; } /* * "sysinfo" command */ static const vshCmdInfo info_sysinfo[] = { {"help", N_("print the hypervisor sysinfo")}, {"desc", N_("output an XML string for the hypervisor sysinfo, if available")}, {NULL, NULL} }; static bool cmdSysinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { char *sysinfo; sysinfo = virConnectGetSysinfo(ctl->conn, 0); if (sysinfo == NULL) { vshError(ctl, "%s", _("failed to get sysinfo")); return false; } vshPrint(ctl, "%s", sysinfo); VIR_FREE(sysinfo); return true; } /* * "hostname" command */ static const vshCmdInfo info_hostname[] = { {"help", N_("print the hypervisor hostname")}, {"desc", ""}, {NULL, NULL} }; static bool cmdHostname(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { char *hostname; hostname = virConnectGetHostname(ctl->conn); if (hostname == NULL) { vshError(ctl, "%s", _("failed to get hostname")); return false; } vshPrint(ctl, "%s\n", hostname); VIR_FREE(hostname); return true; } /* * "uri" command */ static const vshCmdInfo info_uri[] = { {"help", N_("print the hypervisor canonical URI")}, {"desc", ""}, {NULL, NULL} }; static bool cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { char *uri; uri = virConnectGetURI(ctl->conn); if (uri == NULL) { vshError(ctl, "%s", _("failed to get URI")); return false; } vshPrint(ctl, "%s\n", uri); VIR_FREE(uri); return true; } /* * "version" command */ static const vshCmdInfo info_version[] = { {"help", N_("show version")}, {"desc", N_("Display the system version information.")}, {NULL, NULL} }; static const vshCmdOptDef opts_version[] = { {"daemon", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("report daemon version too")}, {NULL, 0, 0, NULL} }; static bool cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { unsigned long hvVersion; const char *hvType; unsigned long libVersion; unsigned long includeVersion; unsigned long apiVersion; unsigned long daemonVersion; int ret; unsigned int major; unsigned int minor; unsigned int rel; hvType = virConnectGetType(ctl->conn); if (hvType == NULL) { vshError(ctl, "%s", _("failed to get hypervisor type")); return false; } includeVersion = LIBVIR_VERSION_NUMBER; major = includeVersion / 1000000; includeVersion %= 1000000; minor = includeVersion / 1000; rel = includeVersion % 1000; vshPrint(ctl, _("Compiled against library: libvirt %d.%d.%d\n"), major, minor, rel); ret = virGetVersion(&libVersion, hvType, &apiVersion); if (ret < 0) { vshError(ctl, "%s", _("failed to get the library version")); return false; } major = libVersion / 1000000; libVersion %= 1000000; minor = libVersion / 1000; rel = libVersion % 1000; vshPrint(ctl, _("Using library: libvirt %d.%d.%d\n"), major, minor, rel); major = apiVersion / 1000000; apiVersion %= 1000000; minor = apiVersion / 1000; rel = apiVersion % 1000; vshPrint(ctl, _("Using API: %s %d.%d.%d\n"), hvType, major, minor, rel); ret = virConnectGetVersion(ctl->conn, &hvVersion); if (ret < 0) { vshError(ctl, "%s", _("failed to get the hypervisor version")); return false; } if (hvVersion == 0) { vshPrint(ctl, _("Cannot extract running %s hypervisor version\n"), hvType); } else { major = hvVersion / 1000000; hvVersion %= 1000000; minor = hvVersion / 1000; rel = hvVersion % 1000; vshPrint(ctl, _("Running hypervisor: %s %d.%d.%d\n"), hvType, major, minor, rel); } if (vshCommandOptBool(cmd, "daemon")) { ret = virConnectGetLibVersion(ctl->conn, &daemonVersion); if (ret < 0) { vshError(ctl, "%s", _("failed to get the daemon version")); } else { major = daemonVersion / 1000000; daemonVersion %= 1000000; minor = daemonVersion / 1000; rel = daemonVersion % 1000; vshPrint(ctl, _("Running against daemon: %d.%d.%d\n"), major, minor, rel); } } return true; } static const vshCmdInfo info_node_memory_tune[] = { {"help", N_("Get or set node memory parameters")}, {"desc", N_("Get or set node memory parameters" " To get the memory parameters, use following command: \n\n" " virsh # node-memory-tune")}, {NULL, NULL} }; static const vshCmdOptDef opts_node_memory_tune[] = { {"shm-pages-to-scan", VSH_OT_INT, VSH_OFLAG_NONE, N_("number of pages to scan before the shared memory service " "goes to sleep")}, {"shm-sleep-millisecs", VSH_OT_INT, VSH_OFLAG_NONE, N_("number of millisecs the shared memory service should " "sleep before next scan")}, {"shm-merge-across-nodes", VSH_OT_INT, VSH_OFLAG_NONE, N_("Specifies if pages from different numa nodes can be merged")}, {NULL, 0, 0, NULL} }; static bool cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) { virTypedParameterPtr params = NULL; int nparams = 0; unsigned int flags = 0; unsigned int shm_pages_to_scan = 0; unsigned int shm_sleep_millisecs = 0; unsigned int shm_merge_across_nodes = 0; bool has_shm_pages_to_scan = false; bool has_shm_sleep_millisecs = false; bool has_shm_merge_across_nodes = false; bool ret = false; int rc = -1; int i = 0; if ((rc = vshCommandOptUInt(cmd, "shm-pages-to-scan", &shm_pages_to_scan)) < 0) { vshError(ctl, "%s", _("invalid shm-pages-to-scan number")); return false; } else if (rc > 0) { nparams++; has_shm_pages_to_scan = true; } if ((rc = vshCommandOptUInt(cmd, "shm-sleep-millisecs", &shm_sleep_millisecs)) < 0) { vshError(ctl, "%s", _("invalid shm-sleep-millisecs number")); return false; } else if (rc > 0) { nparams++; has_shm_sleep_millisecs = true; } if ((rc = vshCommandOptUInt(cmd, "shm-merge-across-nodes", &shm_merge_across_nodes)) < 0) { vshError(ctl, "%s", _("invalid shm-merge-across-nodes number")); return false; } else if (rc > 0) { nparams++; has_shm_merge_across_nodes = true; } if (nparams == 0) { /* Get the number of memory parameters */ if (virNodeGetMemoryParameters(ctl->conn, NULL, &nparams, flags) != 0) { vshError(ctl, "%s", _("Unable to get number of memory parameters")); goto cleanup; } if (nparams == 0) { ret = true; goto cleanup; } /* Now go get all the memory parameters */ params = vshCalloc(ctl, nparams, sizeof(*params)); if (virNodeGetMemoryParameters(ctl->conn, params, &nparams, flags) != 0) { vshError(ctl, "%s", _("Unable to get memory parameters")); goto cleanup; } /* XXX: Need to sort the returned params once new parameter * fields not of shared memory are added. */ vshPrint(ctl, _("Shared memory:\n")); for (i = 0; i < nparams; i++) { char *str = vshGetTypedParamValue(ctl, ¶ms[i]); vshPrint(ctl, "\t%-15s %s\n", params[i].field, str); VIR_FREE(str); } ret = true; } else { /* Set the memory parameters */ params = vshCalloc(ctl, nparams, sizeof(*params)); if (i < nparams && has_shm_pages_to_scan) { if (virTypedParameterAssign(¶ms[i++], VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, VIR_TYPED_PARAM_UINT, shm_pages_to_scan) < 0) goto error; } if (i < nparams && has_shm_sleep_millisecs) { if (virTypedParameterAssign(¶ms[i++], VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, VIR_TYPED_PARAM_UINT, shm_sleep_millisecs) < 0) goto error; } if (i < nparams && has_shm_merge_across_nodes) { if (virTypedParameterAssign(¶ms[i++], VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES, VIR_TYPED_PARAM_UINT, shm_merge_across_nodes) < 0) goto error; } if (virNodeSetMemoryParameters(ctl->conn, params, nparams, flags) != 0) goto error; else ret = true; } cleanup: VIR_FREE(params); return ret; error: vshError(ctl, "%s", _("Unable to change memory parameters")); goto cleanup; } const vshCmdDef hostAndHypervisorCmds[] = { {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, {"connect", cmdConnect, opts_connect, info_connect, VSH_CMD_FLAG_NOCONNECT}, {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, {"hostname", cmdHostname, NULL, info_hostname, 0}, {"node-memory-tune", cmdNodeMemoryTune, opts_node_memory_tune, info_node_memory_tune, 0}, {"nodecpumap", cmdNodeCpuMap, NULL, info_node_cpumap, 0}, {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, {"nodesuspend", cmdNodeSuspend, opts_node_suspend, info_nodesuspend, 0}, {"qemu-attach", cmdQemuAttach, opts_qemu_attach, info_qemu_attach, 0}, {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, info_qemu_monitor_command, 0}, {"qemu-agent-command", cmdQemuAgentCommand, opts_qemu_agent_command, info_qemu_agent_command, 0}, {"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0}, {"uri", cmdURI, NULL, info_uri, 0}, {"version", cmdVersion, opts_version, info_version, 0}, {NULL, NULL, NULL, NULL, 0} };