From: KAMEZAWA Hiroyuki <kamezawa.hiroyu(a)jp.fujitsu.com>
This is for reusing PCIAddress parser etc..in AttachInterface.
This patch just moves defs. No functional/logical changes at all.
---
tools/virsh.c | 916 ++++++++++++++++++++++++++++----------------------------
1 files changed, 458 insertions(+), 458 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index f6571f7..2cb3a19 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -12310,75 +12310,193 @@ cmdUpdateDevice(vshControl *ctl, const vshCmd *cmd)
/*
- * "attach-interface" command
+ * "attach-disk" command
*/
-static const vshCmdInfo info_attach_interface[] = {
- {"help", N_("attach network interface")},
- {"desc", N_("Attach new network interface.")},
+static const vshCmdInfo info_attach_disk[] = {
+ {"help", N_("attach disk device")},
+ {"desc", N_("Attach new disk device.")},
{NULL, NULL}
};
-static const vshCmdOptDef opts_attach_interface[] = {
- {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
- {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface
type")},
- {"source", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source of network
interface")},
- {"target", VSH_OT_DATA, 0, N_("target network name")},
- {"mac", VSH_OT_DATA, 0, N_("MAC address")},
- {"script", VSH_OT_DATA, 0, N_("script used to bridge network
interface")},
- {"model", VSH_OT_DATA, 0, N_("model type")},
- {"persistent", VSH_OT_BOOL, 0, N_("persist interface
attachment")},
- {"inbound", VSH_OT_DATA, VSH_OFLAG_NONE, N_("control domain's
incoming traffics")},
- {"outbound", VSH_OT_DATA, VSH_OFLAG_NONE, N_("control domain's
outgoing traffics")},
+static const vshCmdOptDef opts_attach_disk[] = {
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
+ {"source", VSH_OT_DATA, VSH_OFLAG_REQ | VSH_OFLAG_EMPTY_OK,
+ N_("source of disk device")},
+ {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk
device")},
+ {"driver", VSH_OT_STRING, 0, N_("driver of disk device")},
+ {"subdriver", VSH_OT_STRING, 0, N_("subdriver of disk device")},
+ {"cache", VSH_OT_STRING, 0, N_("cache mode of disk
device")},
+ {"type", VSH_OT_STRING, 0, N_("target device type")},
+ {"mode", VSH_OT_STRING, 0, N_("mode of device reading and
writing")},
+ {"persistent", VSH_OT_BOOL, 0, N_("persist disk attachment")},
+ {"sourcetype", VSH_OT_STRING, 0, N_("type of source
(block|file)")},
+ {"serial", VSH_OT_STRING, 0, N_("serial of disk device")},
+ {"shareable", VSH_OT_BOOL, 0, N_("shareable between domains")},
+ {"address", VSH_OT_STRING, 0, N_("address of disk device")},
+ {"multifunction", VSH_OT_BOOL, 0,
+ N_("use multifunction pci under specified address")},
{NULL, 0, 0, NULL}
};
-/* parse inbound and outbound which are in the format of
- * 'average,peak,burst', in which peak and burst are optional,
- * thus 'average,,burst' and 'average,peak' are also legal. */
-static int parseRateStr(const char *rateStr, virNetDevBandwidthRatePtr rate)
+enum {
+ DISK_ADDR_TYPE_INVALID,
+ DISK_ADDR_TYPE_PCI,
+ DISK_ADDR_TYPE_SCSI,
+ DISK_ADDR_TYPE_IDE,
+};
+
+struct PCIAddress {
+ unsigned int domain;
+ unsigned int bus;
+ unsigned int slot;
+ unsigned int function;
+};
+
+struct SCSIAddress {
+ unsigned int controller;
+ unsigned int bus;
+ unsigned int unit;
+};
+
+struct IDEAddress {
+ unsigned int controller;
+ unsigned int bus;
+ unsigned int unit;
+};
+
+struct DiskAddress {
+ int type;
+ union {
+ struct PCIAddress pci;
+ struct SCSIAddress scsi;
+ struct IDEAddress ide;
+ } addr;
+};
+
+static int str2PCIAddress(const char *str, struct PCIAddress *pciAddr)
{
- const char *average = NULL;
- char *peak = NULL, *burst = NULL;
+ char *domain, *bus, *slot, *function;
- average = rateStr;
- if (!average)
+ if (!pciAddr)
return -1;
- if (virStrToLong_ull(average, &peak, 10, &rate->average) < 0)
+ if (!str)
return -1;
- /* peak will be updated to point to the end of rateStr in case
- * of 'average' */
- if (peak && *peak != '\0') {
- burst = strchr(peak + 1, ',');
- if (!(burst && (burst - peak == 1))) {
- if (virStrToLong_ull(peak + 1, &burst, 10, &rate->peak) < 0)
- return -1;
- }
+ domain = (char *)str;
- /* burst will be updated to point to the end of rateStr in case
- * of 'average,peak' */
- if (burst && *burst != '\0') {
- if (virStrToLong_ull(burst + 1, NULL, 10, &rate->burst) < 0)
- return -1;
- }
- }
+ if (virStrToLong_ui(domain, &bus, 0, &pciAddr->domain) != 0)
+ return -1;
+ bus++;
+ if (virStrToLong_ui(bus, &slot, 0, &pciAddr->bus) != 0)
+ return -1;
+
+ slot++;
+ if (virStrToLong_ui(slot, &function, 0, &pciAddr->slot) != 0)
+ return -1;
+
+ function++;
+ if (virStrToLong_ui(function, NULL, 0, &pciAddr->function) != 0)
+ return -1;
return 0;
}
+static int str2SCSIAddress(const char *str, struct SCSIAddress *scsiAddr)
+{
+ char *controller, *bus, *unit;
+
+ if (!scsiAddr)
+ return -1;
+ if (!str)
+ return -1;
+
+ controller = (char *)str;
+
+ if (virStrToLong_ui(controller, &bus, 0, &scsiAddr->controller) != 0)
+ return -1;
+
+ bus++;
+ if (virStrToLong_ui(bus, &unit, 0, &scsiAddr->bus) != 0)
+ return -1;
+
+ unit++;
+ if (virStrToLong_ui(unit, NULL, 0, &scsiAddr->unit) != 0)
+ return -1;
+
+ return 0;
+}
+
+static int str2IDEAddress(const char *str, struct IDEAddress *ideAddr)
+{
+ char *controller, *bus, *unit;
+
+ if (!ideAddr)
+ return -1;
+ if (!str)
+ return -1;
+
+ controller = (char *)str;
+
+ if (virStrToLong_ui(controller, &bus, 0, &ideAddr->controller) != 0)
+ return -1;
+
+ bus++;
+ if (virStrToLong_ui(bus, &unit, 0, &ideAddr->bus) != 0)
+ return -1;
+
+ unit++;
+ if (virStrToLong_ui(unit, NULL, 0, &ideAddr->unit) != 0)
+ return -1;
+
+ return 0;
+}
+
+/* pci address pci:0000.00.0x0a.0 (domain:bus:slot:function)
+ * ide disk address: ide:00.00.0 (controller:bus:unit)
+ * scsi disk address: scsi:00.00.0 (controller:bus:unit)
+ */
+
+static int str2DiskAddress(const char *str, struct DiskAddress *diskAddr)
+{
+ char *type, *addr;
+
+ if (!diskAddr)
+ return -1;
+ if (!str)
+ return -1;
+
+ type = (char *)str;
+ addr = strchr(type, ':');
+ if (!addr)
+ return -1;
+
+ if (STREQLEN(type, "pci", addr - type)) {
+ diskAddr->type = DISK_ADDR_TYPE_PCI;
+ return str2PCIAddress(addr + 1, &diskAddr->addr.pci);
+ } else if (STREQLEN(type, "scsi", addr - type)) {
+ diskAddr->type = DISK_ADDR_TYPE_SCSI;
+ return str2SCSIAddress(addr + 1, &diskAddr->addr.scsi);
+ } else if (STREQLEN(type, "ide", addr - type)) {
+ diskAddr->type = DISK_ADDR_TYPE_IDE;
+ return str2IDEAddress(addr + 1, &diskAddr->addr.ide);
+ }
+
+ return -1;
+}
+
static bool
-cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
+cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
{
virDomainPtr dom = NULL;
- const char *mac = NULL, *target = NULL, *script = NULL,
- *type = NULL, *source = NULL, *model = NULL,
- *inboundStr = NULL, *outboundStr = NULL;
- virNetDevBandwidthRate inbound, outbound;
- int typ;
+ const char *source = NULL, *target = NULL, *driver = NULL,
+ *subdriver = NULL, *type = NULL, *mode = NULL,
+ *cache = NULL, *serial = NULL, *straddr = NULL;
+ struct DiskAddress diskAddr;
+ bool isFile = false, functionReturn = false;
int ret;
- bool functionReturn = false;
unsigned int flags;
+ const char *stype = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *xml;
@@ -12388,97 +12506,130 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
goto cleanup;
- if (vshCommandOptString(cmd, "type", &type) <= 0)
+ if (vshCommandOptString(cmd, "source", &source) <= 0)
goto cleanup;
+ /* Allow empty string as a placeholder that implies no source, for
+ * use in adding a cdrom drive with no disk. */
+ if (!*source)
+ source = NULL;
- if (vshCommandOptString(cmd, "source", &source) < 0 ||
- vshCommandOptString(cmd, "target", &target) < 0 ||
- vshCommandOptString(cmd, "mac", &mac) < 0 ||
- vshCommandOptString(cmd, "script", &script) < 0 ||
- vshCommandOptString(cmd, "model", &model) < 0 ||
- vshCommandOptString(cmd, "inbound", &inboundStr) < 0 ||
- vshCommandOptString(cmd, "outbound", &outboundStr) < 0) {
- vshError(ctl, "missing argument");
+ if (vshCommandOptString(cmd, "target", &target) <= 0)
goto cleanup;
- }
- /* check interface type */
- if (STREQ(type, "network")) {
- typ = 1;
- } else if (STREQ(type, "bridge")) {
- typ = 2;
- } else {
- vshError(ctl, _("No support for %s in command
'attach-interface'"),
- type);
+ if (vshCommandOptString(cmd, "driver", &driver) < 0 ||
+ vshCommandOptString(cmd, "subdriver", &subdriver) < 0 ||
+ vshCommandOptString(cmd, "type", &type) < 0 ||
+ vshCommandOptString(cmd, "mode", &mode) < 0 ||
+ vshCommandOptString(cmd, "cache", &cache) < 0 ||
+ vshCommandOptString(cmd, "serial", &serial) < 0 ||
+ vshCommandOptString(cmd, "address", &straddr) < 0 ||
+ vshCommandOptString(cmd, "sourcetype", &stype) < 0) {
+ vshError(ctl, "%s", _("missing option"));
goto cleanup;
}
- if (inboundStr) {
- memset(&inbound, 0, sizeof(inbound));
- if (parseRateStr(inboundStr, &inbound) < 0) {
- vshError(ctl, _("inbound format is incorrect"));
- goto cleanup;
- }
- if (inbound.average == 0) {
- vshError(ctl, _("inbound average is mandatory"));
- goto cleanup;
- }
+ if (!stype) {
+ if (driver && (STREQ(driver, "file") || STREQ(driver,
"tap")))
+ isFile = true;
+ } else if (STREQ(stype, "file")) {
+ isFile = true;
+ } else if (STRNEQ(stype, "block")) {
+ vshError(ctl, _("Unknown source type: '%s'"), stype);
+ goto cleanup;
}
- if (outboundStr) {
- memset(&outbound, 0, sizeof(outbound));
- if (parseRateStr(outboundStr, &outbound) < 0) {
- vshError(ctl, _("outbound format is incorrect"));
- goto cleanup;
- }
- if (outbound.average == 0) {
- vshError(ctl, _("outbound average is mandatory"));
+
+ if (mode) {
+ if (STRNEQ(mode, "readonly") && STRNEQ(mode,
"shareable")) {
+ vshError(ctl, _("No support for %s in command
'attach-disk'"),
+ mode);
goto cleanup;
}
}
- /* Make XML of interface */
- virBufferAsprintf(&buf, "<interface type='%s'>\n",
type);
+ /* Make XML of disk */
+ virBufferAsprintf(&buf, "<disk type='%s'",
+ (isFile) ? "file" : "block");
+ if (type)
+ virBufferAsprintf(&buf, " device='%s'", type);
+ virBufferAddLit(&buf, ">\n");
- if (typ == 1)
- virBufferAsprintf(&buf, " <source network='%s'/>\n",
source);
- else if (typ == 2)
- virBufferAsprintf(&buf, " <source bridge='%s'/>\n",
source);
+ if (driver || subdriver)
+ virBufferAsprintf(&buf, " <driver");
- if (target != NULL)
- virBufferAsprintf(&buf, " <target dev='%s'/>\n",
target);
- if (mac != NULL)
- virBufferAsprintf(&buf, " <mac address='%s'/>\n",
mac);
- if (script != NULL)
- virBufferAsprintf(&buf, " <script path='%s'/>\n",
script);
- if (model != NULL)
- virBufferAsprintf(&buf, " <model type='%s'/>\n",
model);
+ if (driver)
+ virBufferAsprintf(&buf, " name='%s'", driver);
+ if (subdriver)
+ virBufferAsprintf(&buf, " type='%s'", subdriver);
+ if (cache)
+ virBufferAsprintf(&buf, " cache='%s'", cache);
- if (inboundStr || outboundStr) {
- virBufferAsprintf(&buf, " <bandwidth>\n");
- if (inboundStr && inbound.average > 0) {
- virBufferAsprintf(&buf, " <inbound
average='%llu'", inbound.average);
- if (inbound.peak > 0)
- virBufferAsprintf(&buf, " peak='%llu'",
inbound.peak);
- if (inbound.burst > 0)
- virBufferAsprintf(&buf, " burst='%llu'",
inbound.burst);
- virBufferAsprintf(&buf, "/>\n");
+ if (driver || subdriver || cache)
+ virBufferAddLit(&buf, "/>\n");
+
+ if (source)
+ virBufferAsprintf(&buf, " <source %s='%s'/>\n",
+ (isFile) ? "file" : "dev",
+ source);
+ virBufferAsprintf(&buf, " <target dev='%s'/>\n",
target);
+ if (mode)
+ virBufferAsprintf(&buf, " <%s/>\n", mode);
+
+ if (serial)
+ virBufferAsprintf(&buf, " <serial>%s</serial>\n",
serial);
+
+ if (vshCommandOptBool(cmd, "shareable"))
+ virBufferAsprintf(&buf, " <shareable/>\n");
+
+ if (straddr) {
+ if (str2DiskAddress(straddr, &diskAddr) != 0) {
+ vshError(ctl, _("Invalid address."));
+ goto cleanup;
}
- if (outboundStr && outbound.average > 0) {
- virBufferAsprintf(&buf, " <outbound
average='%llu'", outbound.average);
- if (outbound.peak > 0)
- virBufferAsprintf(&buf, " peak='%llu'",
outbound.peak);
- if (outbound.burst > 0)
- virBufferAsprintf(&buf, " burst='%llu'",
outbound.burst);
- virBufferAsprintf(&buf, "/>\n");
+
+ if (STRPREFIX((const char *)target, "vd")) {
+ if (diskAddr.type == DISK_ADDR_TYPE_PCI) {
+ virBufferAsprintf(&buf,
+ " <address type='pci'
domain='0x%04x'"
+ " bus ='0x%02x' slot='0x%02x'
function='0x%0x'",
+ diskAddr.addr.pci.domain, diskAddr.addr.pci.bus,
+ diskAddr.addr.pci.slot, diskAddr.addr.pci.function);
+ if (vshCommandOptBool(cmd, "multifunction"))
+ virBufferAddLit(&buf, " multifunction='on'");
+ virBufferAddLit(&buf, "/>\n");
+ } else {
+ vshError(ctl, "%s", _("expecting a pci:0000.00.00.00
address."));
+ goto cleanup;
+ }
+ } else if (STRPREFIX((const char *)target, "sd")) {
+ if (diskAddr.type == DISK_ADDR_TYPE_SCSI) {
+ virBufferAsprintf(&buf,
+ " <address type='drive'
controller='%d'"
+ " bus='%d' unit='%d'
/>\n",
+ diskAddr.addr.scsi.controller, diskAddr.addr.scsi.bus,
+ diskAddr.addr.scsi.unit);
+ } else {
+ vshError(ctl, "%s", _("expecting a scsi:00.00.00
address."));
+ goto cleanup;
+ }
+ } else if (STRPREFIX((const char *)target, "hd")) {
+ if (diskAddr.type == DISK_ADDR_TYPE_IDE) {
+ virBufferAsprintf(&buf,
+ " <address type='drive'
controller='%d'"
+ " bus='%d' unit='%d'
/>\n",
+ diskAddr.addr.ide.controller, diskAddr.addr.ide.bus,
+ diskAddr.addr.ide.unit);
+ } else {
+ vshError(ctl, "%s", _("expecting an ide:00.00.00
address."));
+ goto cleanup;
+ }
}
- virBufferAsprintf(&buf, " </bandwidth>\n");
}
- virBufferAddLit(&buf, "</interface>\n");
+ virBufferAddLit(&buf, "</disk>\n");
if (virBufferError(&buf)) {
vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
- goto cleanup;
+ return false;
}
xml = virBufferContentAndReset(&buf);
@@ -12495,9 +12646,9 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
VIR_FREE(xml);
if (ret != 0) {
- vshError(ctl, "%s", _("Failed to attach interface"));
+ vshError(ctl, "%s", _("Failed to attach disk"));
} else {
- vshPrint(ctl, "%s", _("Interface attached successfully\n"));
+ vshPrint(ctl, "%s", _("Disk attached successfully\n"));
functionReturn = true;
}
@@ -12509,37 +12660,35 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
}
/*
- * "detach-interface" command
+ * "detach-disk" command
*/
-static const vshCmdInfo info_detach_interface[] = {
- {"help", N_("detach network interface")},
- {"desc", N_("Detach network interface.")},
+static const vshCmdInfo info_detach_disk[] = {
+ {"help", N_("detach disk device")},
+ {"desc", N_("Detach disk device.")},
{NULL, NULL}
};
-static const vshCmdOptDef opts_detach_interface[] = {
+static const vshCmdOptDef opts_detach_disk[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
- {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface
type")},
- {"mac", VSH_OT_STRING, 0, N_("MAC address")},
- {"persistent", VSH_OT_BOOL, 0, N_("persist interface
detachment")},
+ {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk
device")},
+ {"persistent", VSH_OT_BOOL, 0, N_("persist disk detachment")},
{NULL, 0, 0, NULL}
};
static bool
-cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
+cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
{
- virDomainPtr dom = NULL;
xmlDocPtr xml = NULL;
xmlXPathObjectPtr obj=NULL;
xmlXPathContextPtr ctxt = NULL;
xmlNodePtr cur = NULL;
xmlBufferPtr xml_buf = NULL;
- const char *mac =NULL, *type = NULL;
+ virDomainPtr dom = NULL;
+ const char *target = NULL;
char *doc;
- char buf[64];
- int i = 0, diff_mac;
+ int i = 0, diff_tgt;
int ret;
- int functionReturn = false;
+ bool functionReturn = false;
unsigned int flags;
if (!vshConnectionUsability(ctl, ctl->conn))
@@ -12548,13 +12697,8 @@ cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
goto cleanup;
- if (vshCommandOptString(cmd, "type", &type) <= 0)
- goto cleanup;
-
- if (vshCommandOptString(cmd, "mac", &mac) < 0) {
- vshError(ctl, "%s", _("missing option"));
+ if (vshCommandOptString(cmd, "target", &target) <= 0)
goto cleanup;
- }
doc = virDomainGetXMLDesc(dom, 0);
if (!doc)
@@ -12563,44 +12707,34 @@ cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
xml = virXMLParseStringCtxt(doc, _("(domain_definition)"), &ctxt);
VIR_FREE(doc);
if (!xml) {
- vshError(ctl, "%s", _("Failed to get interface
information"));
+ vshError(ctl, "%s", _("Failed to get disk information"));
goto cleanup;
}
- snprintf(buf, sizeof(buf), "/domain/devices/interface[@type='%s']",
type);
- obj = xmlXPathEval(BAD_CAST buf, ctxt);
+ obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
(obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
- vshError(ctl, _("No found interface whose type is %s"), type);
- goto cleanup;
- }
-
- if ((!mac) && (obj->nodesetval->nodeNr > 1)) {
- vshError(ctl, _("Domain has %d interfaces. Please specify which one "
- "to detach using --mac"),
obj->nodesetval->nodeNr);
+ vshError(ctl, "%s", _("Failed to get disk information"));
goto cleanup;
}
- if (!mac)
- goto hit;
-
- /* search mac */
+ /* search target */
for (; i < obj->nodesetval->nodeNr; i++) {
cur = obj->nodesetval->nodeTab[i]->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE &&
- xmlStrEqual(cur->name, BAD_CAST "mac")) {
- char *tmp_mac = virXMLPropString(cur, "address");
- diff_mac = virMacAddrCompare (tmp_mac, mac);
- VIR_FREE(tmp_mac);
- if (!diff_mac) {
+ xmlStrEqual(cur->name, BAD_CAST "target")) {
+ char *tmp_tgt = virXMLPropString(cur, "dev");
+ diff_tgt = STREQ(tmp_tgt, target);
+ VIR_FREE(tmp_tgt);
+ if (diff_tgt) {
goto hit;
}
}
cur = cur->next;
}
}
- vshError(ctl, _("No found interface whose MAC address is %s"), mac);
+ vshError(ctl, _("No found disk whose target is %s"), target);
goto cleanup;
hit:
@@ -12627,210 +12761,92 @@ cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
}
if (ret != 0) {
- vshError(ctl, "%s", _("Failed to detach interface"));
+ vshError(ctl, "%s", _("Failed to detach disk"));
} else {
- vshPrint(ctl, "%s", _("Interface detached successfully\n"));
+ vshPrint(ctl, "%s", _("Disk detached successfully\n"));
functionReturn = true;
}
cleanup:
- if (dom)
- virDomainFree(dom);
xmlXPathFreeObject(obj);
xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml);
xmlBufferFree(xml_buf);
+ if (dom)
+ virDomainFree(dom);
return functionReturn;
}
/*
- * "attach-disk" command
+ * "attach-interface" command
*/
-static const vshCmdInfo info_attach_disk[] = {
- {"help", N_("attach disk device")},
- {"desc", N_("Attach new disk device.")},
+static const vshCmdInfo info_attach_interface[] = {
+ {"help", N_("attach network interface")},
+ {"desc", N_("Attach new network interface.")},
{NULL, NULL}
};
-static const vshCmdOptDef opts_attach_disk[] = {
- {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
- {"source", VSH_OT_DATA, VSH_OFLAG_REQ | VSH_OFLAG_EMPTY_OK,
- N_("source of disk device")},
- {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk
device")},
- {"driver", VSH_OT_STRING, 0, N_("driver of disk device")},
- {"subdriver", VSH_OT_STRING, 0, N_("subdriver of disk device")},
- {"cache", VSH_OT_STRING, 0, N_("cache mode of disk
device")},
- {"type", VSH_OT_STRING, 0, N_("target device type")},
- {"mode", VSH_OT_STRING, 0, N_("mode of device reading and
writing")},
- {"persistent", VSH_OT_BOOL, 0, N_("persist disk attachment")},
- {"sourcetype", VSH_OT_STRING, 0, N_("type of source
(block|file)")},
- {"serial", VSH_OT_STRING, 0, N_("serial of disk device")},
- {"shareable", VSH_OT_BOOL, 0, N_("shareable between domains")},
- {"address", VSH_OT_STRING, 0, N_("address of disk device")},
- {"multifunction", VSH_OT_BOOL, 0,
- N_("use multifunction pci under specified address")},
+static const vshCmdOptDef opts_attach_interface[] = {
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
+ {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface
type")},
+ {"source", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source of network
interface")},
+ {"target", VSH_OT_DATA, 0, N_("target network name")},
+ {"mac", VSH_OT_DATA, 0, N_("MAC address")},
+ {"script", VSH_OT_DATA, 0, N_("script used to bridge network
interface")},
+ {"model", VSH_OT_DATA, 0, N_("model type")},
+ {"persistent", VSH_OT_BOOL, 0, N_("persist interface
attachment")},
+ {"inbound", VSH_OT_DATA, VSH_OFLAG_NONE, N_("control domain's
incoming traffics")},
+ {"outbound", VSH_OT_DATA, VSH_OFLAG_NONE, N_("control domain's
outgoing traffics")},
{NULL, 0, 0, NULL}
};
-enum {
- DISK_ADDR_TYPE_INVALID,
- DISK_ADDR_TYPE_PCI,
- DISK_ADDR_TYPE_SCSI,
- DISK_ADDR_TYPE_IDE,
-};
-
-struct PCIAddress {
- unsigned int domain;
- unsigned int bus;
- unsigned int slot;
- unsigned int function;
-};
-
-struct SCSIAddress {
- unsigned int controller;
- unsigned int bus;
- unsigned int unit;
-};
-
-struct IDEAddress {
- unsigned int controller;
- unsigned int bus;
- unsigned int unit;
-};
-
-struct DiskAddress {
- int type;
- union {
- struct PCIAddress pci;
- struct SCSIAddress scsi;
- struct IDEAddress ide;
- } addr;
-};
-
-static int str2PCIAddress(const char *str, struct PCIAddress *pciAddr)
-{
- char *domain, *bus, *slot, *function;
-
- if (!pciAddr)
- return -1;
- if (!str)
- return -1;
-
- domain = (char *)str;
-
- if (virStrToLong_ui(domain, &bus, 0, &pciAddr->domain) != 0)
- return -1;
-
- bus++;
- if (virStrToLong_ui(bus, &slot, 0, &pciAddr->bus) != 0)
- return -1;
-
- slot++;
- if (virStrToLong_ui(slot, &function, 0, &pciAddr->slot) != 0)
- return -1;
-
- function++;
- if (virStrToLong_ui(function, NULL, 0, &pciAddr->function) != 0)
- return -1;
-
- return 0;
-}
-
-static int str2SCSIAddress(const char *str, struct SCSIAddress *scsiAddr)
-{
- char *controller, *bus, *unit;
-
- if (!scsiAddr)
- return -1;
- if (!str)
- return -1;
-
- controller = (char *)str;
-
- if (virStrToLong_ui(controller, &bus, 0, &scsiAddr->controller) != 0)
- return -1;
-
- bus++;
- if (virStrToLong_ui(bus, &unit, 0, &scsiAddr->bus) != 0)
- return -1;
-
- unit++;
- if (virStrToLong_ui(unit, NULL, 0, &scsiAddr->unit) != 0)
- return -1;
-
- return 0;
-}
-
-static int str2IDEAddress(const char *str, struct IDEAddress *ideAddr)
+/* parse inbound and outbound which are in the format of
+ * 'average,peak,burst', in which peak and burst are optional,
+ * thus 'average,,burst' and 'average,peak' are also legal. */
+static int parseRateStr(const char *rateStr, virNetDevBandwidthRatePtr rate)
{
- char *controller, *bus, *unit;
+ const char *average = NULL;
+ char *peak = NULL, *burst = NULL;
- if (!ideAddr)
+ average = rateStr;
+ if (!average)
return -1;
- if (!str)
+ if (virStrToLong_ull(average, &peak, 10, &rate->average) < 0)
return -1;
- controller = (char *)str;
-
- if (virStrToLong_ui(controller, &bus, 0, &ideAddr->controller) != 0)
- return -1;
+ /* peak will be updated to point to the end of rateStr in case
+ * of 'average' */
+ if (peak && *peak != '\0') {
+ burst = strchr(peak + 1, ',');
+ if (!(burst && (burst - peak == 1))) {
+ if (virStrToLong_ull(peak + 1, &burst, 10, &rate->peak) < 0)
+ return -1;
+ }
- bus++;
- if (virStrToLong_ui(bus, &unit, 0, &ideAddr->bus) != 0)
- return -1;
+ /* burst will be updated to point to the end of rateStr in case
+ * of 'average,peak' */
+ if (burst && *burst != '\0') {
+ if (virStrToLong_ull(burst + 1, NULL, 10, &rate->burst) < 0)
+ return -1;
+ }
+ }
- unit++;
- if (virStrToLong_ui(unit, NULL, 0, &ideAddr->unit) != 0)
- return -1;
return 0;
}
-/* pci address pci:0000.00.0x0a.0 (domain:bus:slot:function)
- * ide disk address: ide:00.00.0 (controller:bus:unit)
- * scsi disk address: scsi:00.00.0 (controller:bus:unit)
- */
-
-static int str2DiskAddress(const char *str, struct DiskAddress *diskAddr)
-{
- char *type, *addr;
-
- if (!diskAddr)
- return -1;
- if (!str)
- return -1;
-
- type = (char *)str;
- addr = strchr(type, ':');
- if (!addr)
- return -1;
-
- if (STREQLEN(type, "pci", addr - type)) {
- diskAddr->type = DISK_ADDR_TYPE_PCI;
- return str2PCIAddress(addr + 1, &diskAddr->addr.pci);
- } else if (STREQLEN(type, "scsi", addr - type)) {
- diskAddr->type = DISK_ADDR_TYPE_SCSI;
- return str2SCSIAddress(addr + 1, &diskAddr->addr.scsi);
- } else if (STREQLEN(type, "ide", addr - type)) {
- diskAddr->type = DISK_ADDR_TYPE_IDE;
- return str2IDEAddress(addr + 1, &diskAddr->addr.ide);
- }
-
- return -1;
-}
-
static bool
-cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
-{
- virDomainPtr dom = NULL;
- const char *source = NULL, *target = NULL, *driver = NULL,
- *subdriver = NULL, *type = NULL, *mode = NULL,
- *cache = NULL, *serial = NULL, *straddr = NULL;
- struct DiskAddress diskAddr;
- bool isFile = false, functionReturn = false;
+cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
+{
+ virDomainPtr dom = NULL;
+ const char *mac = NULL, *target = NULL, *script = NULL,
+ *type = NULL, *source = NULL, *model = NULL,
+ *inboundStr = NULL, *outboundStr = NULL;
+ virNetDevBandwidthRate inbound, outbound;
+ int typ;
int ret;
+ bool functionReturn = false;
unsigned int flags;
- const char *stype = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *xml;
@@ -12840,130 +12856,97 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
goto cleanup;
- if (vshCommandOptString(cmd, "source", &source) <= 0)
- goto cleanup;
- /* Allow empty string as a placeholder that implies no source, for
- * use in adding a cdrom drive with no disk. */
- if (!*source)
- source = NULL;
-
- if (vshCommandOptString(cmd, "target", &target) <= 0)
+ if (vshCommandOptString(cmd, "type", &type) <= 0)
goto cleanup;
- if (vshCommandOptString(cmd, "driver", &driver) < 0 ||
- vshCommandOptString(cmd, "subdriver", &subdriver) < 0 ||
- vshCommandOptString(cmd, "type", &type) < 0 ||
- vshCommandOptString(cmd, "mode", &mode) < 0 ||
- vshCommandOptString(cmd, "cache", &cache) < 0 ||
- vshCommandOptString(cmd, "serial", &serial) < 0 ||
- vshCommandOptString(cmd, "address", &straddr) < 0 ||
- vshCommandOptString(cmd, "sourcetype", &stype) < 0) {
- vshError(ctl, "%s", _("missing option"));
+ if (vshCommandOptString(cmd, "source", &source) < 0 ||
+ vshCommandOptString(cmd, "target", &target) < 0 ||
+ vshCommandOptString(cmd, "mac", &mac) < 0 ||
+ vshCommandOptString(cmd, "script", &script) < 0 ||
+ vshCommandOptString(cmd, "model", &model) < 0 ||
+ vshCommandOptString(cmd, "inbound", &inboundStr) < 0 ||
+ vshCommandOptString(cmd, "outbound", &outboundStr) < 0) {
+ vshError(ctl, "missing argument");
goto cleanup;
}
- if (!stype) {
- if (driver && (STREQ(driver, "file") || STREQ(driver,
"tap")))
- isFile = true;
- } else if (STREQ(stype, "file")) {
- isFile = true;
- } else if (STRNEQ(stype, "block")) {
- vshError(ctl, _("Unknown source type: '%s'"), stype);
+ /* check interface type */
+ if (STREQ(type, "network")) {
+ typ = 1;
+ } else if (STREQ(type, "bridge")) {
+ typ = 2;
+ } else {
+ vshError(ctl, _("No support for %s in command
'attach-interface'"),
+ type);
goto cleanup;
}
- if (mode) {
- if (STRNEQ(mode, "readonly") && STRNEQ(mode,
"shareable")) {
- vshError(ctl, _("No support for %s in command
'attach-disk'"),
- mode);
+ if (inboundStr) {
+ memset(&inbound, 0, sizeof(inbound));
+ if (parseRateStr(inboundStr, &inbound) < 0) {
+ vshError(ctl, _("inbound format is incorrect"));
+ goto cleanup;
+ }
+ if (inbound.average == 0) {
+ vshError(ctl, _("inbound average is mandatory"));
+ goto cleanup;
+ }
+ }
+ if (outboundStr) {
+ memset(&outbound, 0, sizeof(outbound));
+ if (parseRateStr(outboundStr, &outbound) < 0) {
+ vshError(ctl, _("outbound format is incorrect"));
+ goto cleanup;
+ }
+ if (outbound.average == 0) {
+ vshError(ctl, _("outbound average is mandatory"));
goto cleanup;
}
}
- /* Make XML of disk */
- virBufferAsprintf(&buf, "<disk type='%s'",
- (isFile) ? "file" : "block");
- if (type)
- virBufferAsprintf(&buf, " device='%s'", type);
- virBufferAddLit(&buf, ">\n");
-
- if (driver || subdriver)
- virBufferAsprintf(&buf, " <driver");
-
- if (driver)
- virBufferAsprintf(&buf, " name='%s'", driver);
- if (subdriver)
- virBufferAsprintf(&buf, " type='%s'", subdriver);
- if (cache)
- virBufferAsprintf(&buf, " cache='%s'", cache);
-
- if (driver || subdriver || cache)
- virBufferAddLit(&buf, "/>\n");
-
- if (source)
- virBufferAsprintf(&buf, " <source %s='%s'/>\n",
- (isFile) ? "file" : "dev",
- source);
- virBufferAsprintf(&buf, " <target dev='%s'/>\n",
target);
- if (mode)
- virBufferAsprintf(&buf, " <%s/>\n", mode);
+ /* Make XML of interface */
+ virBufferAsprintf(&buf, "<interface type='%s'>\n",
type);
- if (serial)
- virBufferAsprintf(&buf, " <serial>%s</serial>\n",
serial);
+ if (typ == 1)
+ virBufferAsprintf(&buf, " <source network='%s'/>\n",
source);
+ else if (typ == 2)
+ virBufferAsprintf(&buf, " <source bridge='%s'/>\n",
source);
- if (vshCommandOptBool(cmd, "shareable"))
- virBufferAsprintf(&buf, " <shareable/>\n");
+ if (target != NULL)
+ virBufferAsprintf(&buf, " <target dev='%s'/>\n",
target);
+ if (mac != NULL)
+ virBufferAsprintf(&buf, " <mac address='%s'/>\n",
mac);
+ if (script != NULL)
+ virBufferAsprintf(&buf, " <script path='%s'/>\n",
script);
+ if (model != NULL)
+ virBufferAsprintf(&buf, " <model type='%s'/>\n",
model);
- if (straddr) {
- if (str2DiskAddress(straddr, &diskAddr) != 0) {
- vshError(ctl, _("Invalid address."));
- goto cleanup;
+ if (inboundStr || outboundStr) {
+ virBufferAsprintf(&buf, " <bandwidth>\n");
+ if (inboundStr && inbound.average > 0) {
+ virBufferAsprintf(&buf, " <inbound
average='%llu'", inbound.average);
+ if (inbound.peak > 0)
+ virBufferAsprintf(&buf, " peak='%llu'",
inbound.peak);
+ if (inbound.burst > 0)
+ virBufferAsprintf(&buf, " burst='%llu'",
inbound.burst);
+ virBufferAsprintf(&buf, "/>\n");
}
-
- if (STRPREFIX((const char *)target, "vd")) {
- if (diskAddr.type == DISK_ADDR_TYPE_PCI) {
- virBufferAsprintf(&buf,
- " <address type='pci'
domain='0x%04x'"
- " bus ='0x%02x' slot='0x%02x'
function='0x%0x'",
- diskAddr.addr.pci.domain, diskAddr.addr.pci.bus,
- diskAddr.addr.pci.slot, diskAddr.addr.pci.function);
- if (vshCommandOptBool(cmd, "multifunction"))
- virBufferAddLit(&buf, " multifunction='on'");
- virBufferAddLit(&buf, "/>\n");
- } else {
- vshError(ctl, "%s", _("expecting a pci:0000.00.00.00
address."));
- goto cleanup;
- }
- } else if (STRPREFIX((const char *)target, "sd")) {
- if (diskAddr.type == DISK_ADDR_TYPE_SCSI) {
- virBufferAsprintf(&buf,
- " <address type='drive'
controller='%d'"
- " bus='%d' unit='%d'
/>\n",
- diskAddr.addr.scsi.controller, diskAddr.addr.scsi.bus,
- diskAddr.addr.scsi.unit);
- } else {
- vshError(ctl, "%s", _("expecting a scsi:00.00.00
address."));
- goto cleanup;
- }
- } else if (STRPREFIX((const char *)target, "hd")) {
- if (diskAddr.type == DISK_ADDR_TYPE_IDE) {
- virBufferAsprintf(&buf,
- " <address type='drive'
controller='%d'"
- " bus='%d' unit='%d'
/>\n",
- diskAddr.addr.ide.controller, diskAddr.addr.ide.bus,
- diskAddr.addr.ide.unit);
- } else {
- vshError(ctl, "%s", _("expecting an ide:00.00.00
address."));
- goto cleanup;
- }
+ if (outboundStr && outbound.average > 0) {
+ virBufferAsprintf(&buf, " <outbound
average='%llu'", outbound.average);
+ if (outbound.peak > 0)
+ virBufferAsprintf(&buf, " peak='%llu'",
outbound.peak);
+ if (outbound.burst > 0)
+ virBufferAsprintf(&buf, " burst='%llu'",
outbound.burst);
+ virBufferAsprintf(&buf, "/>\n");
}
+ virBufferAsprintf(&buf, " </bandwidth>\n");
}
- virBufferAddLit(&buf, "</disk>\n");
+ virBufferAddLit(&buf, "</interface>\n");
if (virBufferError(&buf)) {
vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
- return false;
+ goto cleanup;
}
xml = virBufferContentAndReset(&buf);
@@ -12980,9 +12963,9 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
VIR_FREE(xml);
if (ret != 0) {
- vshError(ctl, "%s", _("Failed to attach disk"));
+ vshError(ctl, "%s", _("Failed to attach interface"));
} else {
- vshPrint(ctl, "%s", _("Disk attached successfully\n"));
+ vshPrint(ctl, "%s", _("Interface attached successfully\n"));
functionReturn = true;
}
@@ -12994,35 +12977,37 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
}
/*
- * "detach-disk" command
+ * "detach-interface" command
*/
-static const vshCmdInfo info_detach_disk[] = {
- {"help", N_("detach disk device")},
- {"desc", N_("Detach disk device.")},
+static const vshCmdInfo info_detach_interface[] = {
+ {"help", N_("detach network interface")},
+ {"desc", N_("Detach network interface.")},
{NULL, NULL}
};
-static const vshCmdOptDef opts_detach_disk[] = {
+static const vshCmdOptDef opts_detach_interface[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
- {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk
device")},
- {"persistent", VSH_OT_BOOL, 0, N_("persist disk detachment")},
+ {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface
type")},
+ {"mac", VSH_OT_STRING, 0, N_("MAC address")},
+ {"persistent", VSH_OT_BOOL, 0, N_("persist interface
detachment")},
{NULL, 0, 0, NULL}
};
static bool
-cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
+cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
{
+ virDomainPtr dom = NULL;
xmlDocPtr xml = NULL;
xmlXPathObjectPtr obj=NULL;
xmlXPathContextPtr ctxt = NULL;
xmlNodePtr cur = NULL;
xmlBufferPtr xml_buf = NULL;
- virDomainPtr dom = NULL;
- const char *target = NULL;
+ const char *mac =NULL, *type = NULL;
char *doc;
- int i = 0, diff_tgt;
+ char buf[64];
+ int i = 0, diff_mac;
int ret;
- bool functionReturn = false;
+ int functionReturn = false;
unsigned int flags;
if (!vshConnectionUsability(ctl, ctl->conn))
@@ -13031,8 +13016,13 @@ cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
goto cleanup;
- if (vshCommandOptString(cmd, "target", &target) <= 0)
+ if (vshCommandOptString(cmd, "type", &type) <= 0)
+ goto cleanup;
+
+ if (vshCommandOptString(cmd, "mac", &mac) < 0) {
+ vshError(ctl, "%s", _("missing option"));
goto cleanup;
+ }
doc = virDomainGetXMLDesc(dom, 0);
if (!doc)
@@ -13041,34 +13031,44 @@ cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
xml = virXMLParseStringCtxt(doc, _("(domain_definition)"), &ctxt);
VIR_FREE(doc);
if (!xml) {
- vshError(ctl, "%s", _("Failed to get disk information"));
+ vshError(ctl, "%s", _("Failed to get interface
information"));
goto cleanup;
}
- obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
+ snprintf(buf, sizeof(buf), "/domain/devices/interface[@type='%s']",
type);
+ obj = xmlXPathEval(BAD_CAST buf, ctxt);
if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
(obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
- vshError(ctl, "%s", _("Failed to get disk information"));
+ vshError(ctl, _("No found interface whose type is %s"), type);
goto cleanup;
}
- /* search target */
+ if ((!mac) && (obj->nodesetval->nodeNr > 1)) {
+ vshError(ctl, _("Domain has %d interfaces. Please specify which one "
+ "to detach using --mac"),
obj->nodesetval->nodeNr);
+ goto cleanup;
+ }
+
+ if (!mac)
+ goto hit;
+
+ /* search mac */
for (; i < obj->nodesetval->nodeNr; i++) {
cur = obj->nodesetval->nodeTab[i]->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE &&
- xmlStrEqual(cur->name, BAD_CAST "target")) {
- char *tmp_tgt = virXMLPropString(cur, "dev");
- diff_tgt = STREQ(tmp_tgt, target);
- VIR_FREE(tmp_tgt);
- if (diff_tgt) {
+ xmlStrEqual(cur->name, BAD_CAST "mac")) {
+ char *tmp_mac = virXMLPropString(cur, "address");
+ diff_mac = virMacAddrCompare (tmp_mac, mac);
+ VIR_FREE(tmp_mac);
+ if (!diff_mac) {
goto hit;
}
}
cur = cur->next;
}
}
- vshError(ctl, _("No found disk whose target is %s"), target);
+ vshError(ctl, _("No found interface whose MAC address is %s"), mac);
goto cleanup;
hit:
@@ -13095,19 +13095,19 @@ cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
}
if (ret != 0) {
- vshError(ctl, "%s", _("Failed to detach disk"));
+ vshError(ctl, "%s", _("Failed to detach interface"));
} else {
- vshPrint(ctl, "%s", _("Disk detached successfully\n"));
+ vshPrint(ctl, "%s", _("Interface detached successfully\n"));
functionReturn = true;
}
cleanup:
+ if (dom)
+ virDomainFree(dom);
xmlXPathFreeObject(obj);
xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml);
xmlBufferFree(xml_buf);
- if (dom)
- virDomainFree(dom);
return functionReturn;
}
--
1.7.4.1