This patch introduces the new interface type='hostdev-hybrid' along with attribute managed Includes updates to the domain RNG and new xml parser/formatter code. Also introduces a ephemeral tag for hybrid hostdevs. The ephemeral tag for hybrid hostdevs will be useful for live migration support at a later stage. --- docs/formatdomain.html.in | 29 ++++++ docs/schemas/domaincommon.rng | 50 ++++++++++ src/conf/domain_conf.c | 96 +++++++++++++++++--- src/conf/domain_conf.h | 2 + src/uml/uml_conf.c | 5 + src/xenxs/xen_sxpr.c | 1 + .../qemuxml2argv-net-hostdevhybrid.args | 8 ++ .../qemuxml2argv-net-hostdevhybrid.xml | 35 +++++++ tests/qemuxml2argvtest.c | 2 + .../qemuxml2xmlout-net-hostdevhybrid.xml | 40 ++++++++ tests/qemuxml2xmltest.c | 1 + 11 files changed, 256 insertions(+), 13 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 503685f..70cf362 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2659,6 +2659,20 @@ guest instead of <interface type='hostdev'/>. </p> + <p> + Libvirt later than 0.10.0 also supports "intelligent passthrough" + of VF in the hybrid mode. This is done by using the <interface + type='hostdev-hybrid'/> functionality. Similar to <interface + type='hostdev'/> the device's MAC address is first optionally + configured and the device is optionally associated with an 802.1Qbh + capable switch using an optionally specified <virtualport> + element (see the examples of virtualport given above for + type='direct' network devices). The Vf is passed into the guest as + a PCI device and at the same time a virtual interface with + type='direct' mode='bridge' is created in the guest. This hybrid mode + of intelligent passthrough makes Live migration possible. + </p> + <pre> ... <devices> @@ -2674,6 +2688,21 @@ </devices> ...</pre> +<pre> + ... + <devices> + <interface type='hostdev-hybrid'> + <source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </source> + <mac address='52:54:00:6d:90:02'> + <virtualport type='802.1Qbh'> + <parameters profileid='finance'/> + </virtualport> + </interface> + </devices> + ...</pre> + <h5><a name="elementsNICSMulticast">Multicast tunnel</a></h5> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index c2c6184..eedc255 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1677,6 +1677,56 @@ <ref name="interface-options"/> </interleave> </group> + <group> + <attribute name="type"> + <value>hostdev-hybrid</value> + </attribute> + <optional> + <attribute name="managed"> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> + <interleave> + <element name="source"> + <choice> + <group> + <ref name="usbproduct"/> + <optional> + <ref name="usbaddress"/> + </optional> + </group> + <element name="address"> + <choice> + <group> + <attribute name="type"> + <value>pci</value> + </attribute> + <ref name="pciaddress"/> + </group> + <group> + <attribute name="type"> + <value>usb</value> + </attribute> + <attribute name="bus"> + <ref name="usbAddr"/> + </attribute> + <attribute name="device"> + <ref name="usbPort"/> + </attribute> + </group> + </choice> + </element> + </choice> + </element> + <optional> + <ref name="virtualPortProfile"/> + </optional> + <ref name="interface-options"/> + </interleave> + </group> </choice> </element> </define> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 8952b69..d8ab40c 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -293,7 +293,8 @@ VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST, "bridge", "internal", "direct", - "hostdev") + "hostdev", + "hostdev-hybrid") VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST, "default", @@ -1020,6 +1021,9 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def) case VIR_DOMAIN_NET_TYPE_HOSTDEV: virDomainHostdevDefClear(&def->data.hostdev.def); break; + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: + virDomainHostdevDefClear(&def->data.hostdev.def); + break; default: break; } @@ -1072,6 +1076,10 @@ void virDomainNetDefFree(virDomainNetDefPtr def) virDomainHostdevDefClear(&def->data.hostdev.def); break; + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: + virDomainHostdevDefClear(&def->data.hostdev.def); + break; + case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_LAST: break; @@ -1563,8 +1571,10 @@ void virDomainDefFree(virDomainDefPtr def) * so the original object must still be available during the call * to virDomainHostdevDefFree(). */ - for (i = 0 ; i < def->nhostdevs ; i++) - virDomainHostdevDefFree(def->hostdevs[i]); + for (i = 0 ; i < def->nhostdevs ; i++) { + if (def->hostdevs[i]->ephemeral == 0) + virDomainHostdevDefFree(def->hostdevs[i]); + } VIR_FREE(def->hostdevs); for (i = 0 ; i < def->nleases ; i++) @@ -4525,6 +4535,7 @@ virDomainActualNetDefParseXML(xmlNodePtr node, if (actual->type != VIR_DOMAIN_NET_TYPE_BRIDGE && actual->type != VIR_DOMAIN_NET_TYPE_DIRECT && actual->type != VIR_DOMAIN_NET_TYPE_HOSTDEV && + actual->type != VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID && actual->type != VIR_DOMAIN_NET_TYPE_NETWORK) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported type '%s' in interface's <actual> element"), @@ -4536,7 +4547,8 @@ virDomainActualNetDefParseXML(xmlNodePtr node, if (virtPortNode) { if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE || actual->type == VIR_DOMAIN_NET_TYPE_DIRECT || - actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || + actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) { /* the virtualport in <actual> should always already * have an instanceid/interfaceid if its required, * so don't let the parser generate one */ @@ -4589,6 +4601,30 @@ virDomainActualNetDefParseXML(xmlNodePtr node, hostdev, flags) < 0) { goto error; } + } else if (actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) { + virDomainHostdevDefPtr hostdev = &actual->data.hostdev.def; + + hostdev->parent.type = VIR_DOMAIN_DEVICE_NONE; + if (VIR_ALLOC(hostdev->info) < 0) { + virReportOOMError(); + goto error; + } + hostdev->ephemeral = 1; + /* The helper function expects type to already be found and + * passed in as a string, since it is in a different place in + * NetDef vs HostdevDef. + */ + addrtype = virXPathString("string(./source/address/@type)", ctxt); + /* if not explicitly stated, source/vendor implies usb device */ + if (!addrtype && virXPathNode("./source/vendor", ctxt) && + (addrtype = strdup("usb")) == NULL) { + virReportOOMError(); + goto error; + } + if (virDomainHostdevPartsParse(node, ctxt, NULL, addrtype, + hostdev, flags) < 0) { + goto error; + } } bandwidth_node = virXPathNode("./bandwidth", ctxt); @@ -4708,7 +4744,8 @@ virDomainNetDefParseXML(virCapsPtr caps, } } else if (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE || def->type == VIR_DOMAIN_NET_TYPE_DIRECT || - def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || + def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) { if (!(def->virtPortProfile = virNetDevVPortProfileParse(cur, VIR_VPORT_XML_GENERATE_MISSING_DEFAULTS| @@ -4968,6 +5005,27 @@ virDomainNetDefParseXML(virCapsPtr caps, } break; + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: + hostdev = &def->data.hostdev.def; + hostdev->parent.type = VIR_DOMAIN_DEVICE_NONE; + if (VIR_ALLOC(hostdev->info) < 0) { + virReportOOMError(); + goto error; + } + hostdev->ephemeral = 1; + addrtype = virXPathString("string(./source/address/@type)", ctxt); + /* if not explicitly stated, source/vendor implies usb device */ + if (!addrtype && virXPathNode("./source/vendor", ctxt) && + ((addrtype = strdup("usb")) == NULL)) { + virReportOOMError(); + goto error; + } + if (virDomainHostdevPartsParse(node, ctxt, NULL, addrtype, + hostdev, flags) < 0) { + goto error; + } + break; + case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_LAST: break; @@ -7609,7 +7667,8 @@ int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net) return -1; def->nets[def->nnets] = net; def->nnets++; - if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { /* hostdev net devices must also exist in the hostdevs array */ return virDomainHostdevInsert(def, &net->data.hostdev.def); } @@ -7631,7 +7690,8 @@ virDomainNetRemove(virDomainDefPtr def, size_t i) { virDomainNetDefPtr net = def->nets[i]; - if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { /* hostdev net devices are normally also be in the hostdevs * array, but might have already been removed by the time we * get here. @@ -8995,8 +9055,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, def->nets[def->nnets++] = net; - /* <interface type='hostdev'> must also be in the hostdevs array */ - if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV && + /* <interface type='hostdev' and 'hostdev-hybrid'> must also be in + the hostdevs array */ + if (((net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) && virDomainHostdevInsert(def, &net->data.hostdev.def) < 0) { goto no_memory; } @@ -11941,7 +12003,8 @@ virDomainActualNetDefFormat(virBufferPtr buf, } virBufferAsprintf(buf, "<actual type='%s'", type); - if (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV && + if ((def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || + def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) && def->data.hostdev.def.managed) { virBufferAddLit(buf, " managed='yes'"); } @@ -11971,6 +12034,7 @@ virDomainActualNetDefFormat(virBufferPtr buf, break; case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: if (virDomainHostdevSourceFormat(buf, &def->data.hostdev.def, flags, true) < 0) { return -1; @@ -12011,7 +12075,8 @@ virDomainNetDefFormat(virBufferPtr buf, } virBufferAsprintf(buf, " <interface type='%s'", type); - if (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV && + if (((def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) && def->data.hostdev.def.managed) { virBufferAddLit(buf, " managed='yes'"); } @@ -12078,6 +12143,7 @@ virDomainNetDefFormat(virBufferPtr buf, break; case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: if (virDomainHostdevSourceFormat(buf, &def->data.hostdev.def, flags, true) < 0) { return -1; @@ -14620,10 +14686,12 @@ virDomainNetGetActualDirectMode(virDomainNetDefPtr iface) virDomainHostdevDefPtr virDomainNetGetActualHostdev(virDomainNetDefPtr iface) { - if (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) + if ((iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) return &iface->data.hostdev.def; if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK && - iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + (iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || + iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)){ return &iface->data.network.actual->data.hostdev.def; } return NULL; @@ -14636,6 +14704,7 @@ virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface) case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: return iface->virtPortProfile; case VIR_DOMAIN_NET_TYPE_NETWORK: if (!iface->data.network.actual) @@ -14644,6 +14713,7 @@ virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface) case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: return iface->data.network.actual->virtPortProfile; default: return NULL; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3995c2d..156eb32 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -378,6 +378,7 @@ struct _virDomainHostdevDef { virDomainDeviceDef parent; /* higher level Def containing this */ int mode; /* enum virDomainHostdevMode */ unsigned int managed : 1; + unsigned int ephemeral : 1; union { virDomainHostdevSubsys subsys; struct { @@ -727,6 +728,7 @@ enum virDomainNetType { VIR_DOMAIN_NET_TYPE_INTERNAL, VIR_DOMAIN_NET_TYPE_DIRECT, VIR_DOMAIN_NET_TYPE_HOSTDEV, + VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID, VIR_DOMAIN_NET_TYPE_LAST, }; diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 410f3e2..edea034 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -261,6 +261,11 @@ umlBuildCommandLineNet(virConnectPtr conn, _("hostdev networking type not supported")); goto error; + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("hostdev-hybrid networking type not supported")); + goto error; + case VIR_DOMAIN_NET_TYPE_LAST: break; } diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index 8bb3849..c94b787 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -1987,6 +1987,7 @@ xenFormatSxprNet(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: case VIR_DOMAIN_NET_TYPE_LAST: break; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-hostdevhybrid.args b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdevhybrid.args new file mode 100644 index 0000000..a4c50d1 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdevhybrid.args @@ -0,0 +1,8 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S \ +-M pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \ +-hda /dev/HostVG/QEMUGuest1 \ +-device rtl8139,vlan=0,id=net0,mac=00:11:22:33:44:55,bus=pci.0,addr=0x3 \ +-net user,vlan=0,name=hostnet0 -usb \ +-device pci-assign,host=03:07.1,id=hostdev0,bus=pci.0,addr=0x4 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-hostdevhybrid.xml b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdevhybrid.xml new file mode 100644 index 0000000..dcf3fd1 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdevhybrid.xml @@ -0,0 +1,35 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <interface type='hostdev-hybrid' managed='yes'> + <mac address='00:11:22:33:44:55'/> + <source> + <address type='pci' domain='0x0002' bus='0x03' slot='0x07' function='0x1'/> + </source> + <virtualport type='802.1Qbg'> + <parameters managerid='11' typeid='1193047' typeidversion='2' instanceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/> + </virtualport> + </interface> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 47c3f6c..4155352 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -576,6 +576,8 @@ mymain(void) DO_TEST("net-mcast", NONE); DO_TEST("net-hostdev", QEMU_CAPS_PCIDEVICE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); + DO_TEST("net-hostdevhybrid", + QEMU_CAPS_PCIDEVICE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); DO_TEST("serial-vc", NONE); DO_TEST("serial-pty", NONE); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-hostdevhybrid.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-hostdevhybrid.xml new file mode 100644 index 0000000..5ab9ed3 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-hostdevhybrid.xml @@ -0,0 +1,40 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <interface type='hostdev-hybrid' managed='yes'> + <mac address='00:11:22:33:44:55'/> + <source> + <address type='pci' domain='0x0002' bus='0x03' slot='0x07' function='0x1'/> + </source> + <virtualport type='802.1Qbg'> + <parameters managerid='11' typeid='1193047' typeidversion='2' instanceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/> + </virtualport> + </interface> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0002' bus='0x03' slot='0x07' function='0x1'/> + </source> + </hostdev> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 87d9e77..73846e2 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -181,6 +181,7 @@ mymain(void) DO_TEST("net-eth-ifname"); DO_TEST("net-virtio-network-portgroup"); DO_TEST("net-hostdev"); + DO_TEST_DIFFERENT("net-hostdevhybrid"); DO_TEST("net-openvswitch"); DO_TEST("sound"); DO_TEST("sound-device"); -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list