Adding this feature will allow users to easily attach a hostdev network
interface using PCI passthrough.
The interface can be attached using --type=hostdev and PCI address or
network device name as --source. This command also allows you to tell,
whether the interface should be managed and to choose a assignment
driver.
Resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=997561
Signed-off-by: Pavel Hrdina <phrdina(a)redhat.com>
---
tools/virsh-domain.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 86 insertions(+), 4 deletions(-)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index e8503ec..b124441 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -56,6 +56,7 @@
#include "virtime.h"
#include "virtypedparam.h"
#include "virxml.h"
+#include "virsh-nodedev.h"
/* Gnulib doesn't guarantee SA_SIGINFO support. */
#ifndef SA_SIGINFO
@@ -866,6 +867,14 @@ static const vshCmdOptDef opts_attach_interface[] = {
.type = VSH_OT_BOOL,
.help = N_("print XML document rather than attach the interface")
},
+ {.name = "managed",
+ .type = VSH_OT_BOOL,
+ .help = N_("set the interface to be managed by libvirt")
+ },
+ {.name = "driver",
+ .type = VSH_OT_STRING,
+ .help = N_("set driver for hostdev interface, default is 'kvm'")
+ },
{.name = NULL}
};
@@ -919,7 +928,7 @@ 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;
+ *inboundStr = NULL, *outboundStr = NULL, *driver = NULL;
virNetDevBandwidthRate inbound, outbound;
virDomainNetType typ;
int ret;
@@ -931,6 +940,7 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
bool config = vshCommandOptBool(cmd, "config");
bool live = vshCommandOptBool(cmd, "live");
bool persistent = vshCommandOptBool(cmd, "persistent");
+ bool managed = vshCommandOptBool(cmd, "managed");
VSH_EXCLUSIVE_OPTIONS_VAR(persistent, current);
@@ -949,7 +959,8 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
vshCommandOptStringReq(ctl, cmd, "script", &script) < 0 ||
vshCommandOptStringReq(ctl, cmd, "model", &model) < 0 ||
vshCommandOptStringReq(ctl, cmd, "inbound", &inboundStr) < 0 ||
- vshCommandOptStringReq(ctl, cmd, "outbound", &outboundStr) < 0)
+ vshCommandOptStringReq(ctl, cmd, "outbound", &outboundStr) < 0
||
+ vshCommandOptStringReq(ctl, cmd, "driver", &driver) < 0)
goto cleanup;
/* check interface type */
@@ -982,8 +993,23 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
}
}
+ if (typ != VIR_DOMAIN_NET_TYPE_HOSTDEV) {
+ if (managed) {
+ vshError(ctl, _("--managed is usable only with --type=hostdev"));
+ goto cleanup;
+ }
+ if (driver) {
+ vshError(ctl, _("--driver is usable only with --type=hostdev"));
+ goto cleanup;
+ }
+ }
+
/* Make XML of interface */
- virBufferAsprintf(&buf, "<interface type='%s'>\n",
type);
+ virBufferAsprintf(&buf, "<interface type='%s'", type);
+ if (managed)
+ virBufferAddLit(&buf, " managed='yes'>\n");
+ else
+ virBufferAddLit(&buf, ">\n");
virBufferAdjustIndent(&buf, 2);
switch (typ) {
@@ -995,6 +1021,63 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
case VIR_DOMAIN_NET_TYPE_DIRECT:
virBufferAsprintf(&buf, "<source dev='%s'/>\n",
source);
break;
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ {
+ struct PCIAddress pciAddr = {0, 0, 0, 0};
+
+ if (str2PCIAddress(source, &pciAddr) < 0) {
+ const char *caps[] = {"net"};
+ char *tmpName = NULL;
+ virshNodeDeviceListPtr list = NULL;
+ virNodeDevicePtr netDev = NULL;
+ size_t i;
+
+ list = virshNodeDeviceListCollect(ctl, (char **)caps, 1,
+ VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET);
+
+ if (!list) {
+ vshError(ctl, _("cannot list network devices"));
+ goto cleanup;
+ }
+
+ if (virAsprintf(&tmpName, "net_%s", source) < 0)
+ goto cleanup;
+
+ for (i = 0; i < list->ndevices; i++) {
+ if (STREQLEN(tmpName, virNodeDeviceGetName(list->devices[i]),
+ strlen(tmpName)))
+ netDev = list->devices[i];
+ }
+ VIR_FREE(tmpName);
+
+ if (!netDev) {
+ vshError(ctl, _("network interface '%s' doesn't
exist"),
+ source);
+ goto cleanup;
+ }
+
+ if (str2PCIAddress(virNodeDeviceGetParent(netDev)+4, &pciAddr) < 0) {
+ virshNodeDeviceListFree(list);
+ vshError(ctl, _("cannot parse pci address for network "
+ "interface '%s'"), source);
+ goto cleanup;
+ }
+
+ virshNodeDeviceListFree(list);
+ }
+ if (driver)
+ virBufferAsprintf(&buf, "<driver name='%s'/>\n",
driver);
+
+ virBufferAddLit(&buf, "<source>\n");
+ virBufferAdjustIndent(&buf, 2);
+ virBufferAsprintf(&buf, "<address type='pci'
domain='0x%.4x'"
+ " bus='0x%.2x' slot='0x%.2x'
function='0x%.1x'/>\n",
+ pciAddr.domain, pciAddr.bus,
+ pciAddr.slot, pciAddr.function);
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</source>\n");
+ break;
+ }
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_ETHERNET:
@@ -1004,7 +1087,6 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
case VIR_DOMAIN_NET_TYPE_MCAST:
case VIR_DOMAIN_NET_TYPE_UDP:
case VIR_DOMAIN_NET_TYPE_INTERNAL:
- case VIR_DOMAIN_NET_TYPE_HOSTDEV:
case VIR_DOMAIN_NET_TYPE_LAST:
vshError(ctl, _("No support for %s in command
'attach-interface'"),
type);
--
2.6.2