[libvirt] [PATCH 00/15] Hostdev and Hostdev-hybrid patches

This patch series supports the forward mode='hostdev'. The functionality of this mode is the same as interface type='hostdev' but with the added benefit of using interface pools. The patch series also contains a patch to support use of interface names and PCI device addresses interchangeably in a network xml, and return the appropriate one in actualDevice when networkAllocateActualDevice is called. At the top level managed attribute can be specified with identical results as when it's specified for a hostdev. Currently forward mode='hostdev' does not support USB devices. Since the hostdev-hybrid patches are dependent on the hostdev patches, I have also included the support for interface-type="hostdev-hybrid" and forward mode="hostdev-hybrid" in this patch series. The hostdev-hybrid mode makes migration possible along with PCI-passthrough. I had posted a RFC on the hostdev-hybrid methodology earlier on the libvirt mailing list. The RFC can be found here: https://www.redhat.com/archives/libvir-list/2012-February/msg00309.html Shradha Shah (15): Prerequisite Patch. virDomainDevicePCIAddress and respective functions moved to a new file called conf/device_conf.ch Moved the code to create implicit interface pool from PF to a new function RNG updates, new xml parser/formatter code to support forward mode=hostdev Code to return interface name or pci_addr of the VF in actualDevice Forward Mode Hostdev network driver Implementation Forward Mode 'Hostdev' qemu driver implementation RNG updates, new xml parser/formatter code to support interface type=hostdev-hybrid RNG updates, new xml parser/formatter code to support forward mode=hostdev-hybrid Hostdev-hybrid mode requires a direct linkdev and direct mode. ActualParent is used to store the information about the NETDEV that contains HOSTDEV in hybrid case. Hybrid Hostdevs should be marked as ephemeral. Hostdev-hybrid network driver Implementation Hostdev-hybrid qemu driver implementation Using the Ephemeral Flag to prepare for Migration Support. Migration support for hostdev-hybrid. docs/formatdomain.html.in | 29 ++ docs/formatnetwork.html.in | 62 +++ docs/schemas/domaincommon.rng | 50 +++ docs/schemas/network.rng | 83 ++++- include/libvirt/libvirt.h.in | 1 + include/libvirt/virterror.h | 1 + src/Makefile.am | 6 +- src/conf/device_conf.c | 135 ++++++ src/conf/device_conf.h | 65 +++ src/conf/domain_conf.c | 286 +++++++----- src/conf/domain_conf.h | 33 +- src/conf/network_conf.c | 131 +++++- src/conf/network_conf.h | 30 ++- src/libvirt_private.syms | 11 +- src/network/bridge_driver.c | 463 ++++++++++++++++---- src/qemu/qemu_command.c | 99 ++++- src/qemu/qemu_domain.c | 6 +- src/qemu/qemu_domain.h | 3 +- src/qemu/qemu_driver.c | 6 +- src/qemu/qemu_hostdev.c | 97 +++-- src/qemu/qemu_hotplug.c | 35 ++- src/qemu/qemu_migration.c | 106 +++++- src/qemu/qemu_monitor.c | 14 +- src/qemu/qemu_monitor.h | 17 +- src/qemu/qemu_monitor_json.c | 14 +- src/qemu/qemu_monitor_json.h | 14 +- src/qemu/qemu_monitor_text.c | 16 +- src/qemu/qemu_monitor_text.h | 14 +- src/qemu/qemu_process.c | 3 +- src/uml/uml_conf.c | 5 + src/util/pci.c | 2 +- src/util/pci.h | 2 + src/util/virnetdev.c | 65 +++- src/util/virnetdev.h | 10 +- src/util/virterror.c | 3 +- src/xen/xend_internal.c | 3 +- src/xenxs/xen_sxpr.c | 1 + tests/networkxml2xmlin/hostdev-hybrid-pf.xml | 11 + tests/networkxml2xmlin/hostdev-hybrid.xml | 10 + tests/networkxml2xmlin/hostdev-pf.xml | 11 + tests/networkxml2xmlin/hostdev.xml | 10 + tests/networkxml2xmlout/hostdev-hybrid-pf.xml | 7 + tests/networkxml2xmlout/hostdev-hybrid.xml | 10 + tests/networkxml2xmlout/hostdev-pf.xml | 7 + tests/networkxml2xmlout/hostdev.xml | 10 + tests/networkxml2xmltest.c | 4 + .../qemuxml2argv-net-hostdevhybrid.args | 6 + .../qemuxml2argv-net-hostdevhybrid.xml | 35 ++ tests/qemuxml2xmltest.c | 1 + 49 files changed, 1675 insertions(+), 368 deletions(-) create mode 100644 src/conf/device_conf.c create mode 100644 src/conf/device_conf.h create mode 100644 tests/networkxml2xmlin/hostdev-hybrid-pf.xml create mode 100644 tests/networkxml2xmlin/hostdev-hybrid.xml create mode 100644 tests/networkxml2xmlin/hostdev-pf.xml create mode 100644 tests/networkxml2xmlin/hostdev.xml create mode 100644 tests/networkxml2xmlout/hostdev-hybrid-pf.xml create mode 100644 tests/networkxml2xmlout/hostdev-hybrid.xml create mode 100644 tests/networkxml2xmlout/hostdev-pf.xml create mode 100644 tests/networkxml2xmlout/hostdev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-net-hostdevhybrid.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-net-hostdevhybrid.xml -- 1.7.4.4

Refactoring existing code without causing any functional changes to prepare for new code. This patch makes the code reusable. Signed-off-by: Shradha Shah <sshah@solarflare.com> --- include/libvirt/virterror.h | 1 + src/Makefile.am | 6 ++- src/conf/device_conf.c | 135 ++++++++++++++++++++++++++++++++++++++++++ src/conf/device_conf.h | 65 ++++++++++++++++++++ src/conf/domain_conf.c | 114 ++++------------------------------- src/conf/domain_conf.h | 25 +------- src/libvirt_private.syms | 10 ++- src/qemu/qemu_command.c | 13 ++-- src/qemu/qemu_hotplug.c | 7 +- src/qemu/qemu_monitor.c | 14 ++-- src/qemu/qemu_monitor.h | 17 +++--- src/qemu/qemu_monitor_json.c | 14 ++-- src/qemu/qemu_monitor_json.h | 14 ++-- src/qemu/qemu_monitor_text.c | 16 +++--- src/qemu/qemu_monitor_text.h | 14 ++-- src/util/virterror.c | 3 +- src/xen/xend_internal.c | 3 +- 17 files changed, 290 insertions(+), 181 deletions(-) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index ad8e101..a3516f6 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -110,6 +110,7 @@ typedef enum { VIR_FROM_AUTH = 46, /* Error from auth handling */ VIR_FROM_DBUS = 47, /* Error from DBus */ VIR_FROM_PARALLELS = 48, /* Error from Parallels */ + VIR_FROM_DEVICE = 49, /* Error from Device */ # ifdef VIR_ENUM_SENTINELS VIR_ERR_DOMAIN_LAST diff --git a/src/Makefile.am b/src/Makefile.am index 6ed4a41..d6ebfdf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -200,6 +200,9 @@ CONSOLE_CONF_SOURCES = \ DOMAIN_LIST_SOURCES = \ conf/virdomainlist.c conf/virdomainlist.h +DEVICE_CONF_SOURCES = \ + conf/device_conf.c conf/device_conf.h + CONF_SOURCES = \ $(NETDEV_CONF_SOURCES) \ $(DOMAIN_CONF_SOURCES) \ @@ -213,7 +216,8 @@ CONF_SOURCES = \ $(SECRET_CONF_SOURCES) \ $(CPU_CONF_SOURCES) \ $(CONSOLE_CONF_SOURCES) \ - $(DOMAIN_LIST_SOURCES) + $(DOMAIN_LIST_SOURCES) \ + $(DEVICE_CONF_SOURCES) # The remote RPC driver, covering domains, storage, networks, etc REMOTE_DRIVER_GENERATED = \ diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c new file mode 100644 index 0000000..d4eb764 --- /dev/null +++ b/src/conf/device_conf.c @@ -0,0 +1,135 @@ +/* + * device_conf.h: device XML handling + * + * Copyright (C) 2006-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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Shradha Shah <sshah@solarflare.com> + */ + +#include <config.h> +#include "virterror_internal.h" +#include "datatypes.h" +#include "memory.h" +#include "xml.h" +#include "uuid.h" +#include "util.h" +#include "buf.h" +#include "conf/device_conf.h" + +#define VIR_FROM_THIS VIR_FROM_DEVICE + +#define virDeviceReportError(code, ...) \ + virReportErrorHelper(VIR_FROM_DEVICE, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +VIR_ENUM_IMPL(virDeviceAddressPciMulti, + VIR_DEVICE_ADDRESS_PCI_MULTI_LAST, + "default", + "on", + "off") + +int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr) +{ + /* PCI bus has 32 slots and 8 functions per slot */ + if (addr->slot >= 32 || addr->function >= 8) + return 0; + return addr->domain || addr->bus || addr->slot; +} + + +int +virDevicePCIAddressParseXML(xmlNodePtr node, + virDevicePCIAddressPtr addr) +{ + char *domain, *slot, *bus, *function, *multi; + int ret = -1; + + memset(addr, 0, sizeof(*addr)); + + domain = virXMLPropString(node, "domain"); + bus = virXMLPropString(node, "bus"); + slot = virXMLPropString(node, "slot"); + function = virXMLPropString(node, "function"); + multi = virXMLPropString(node, "multifunction"); + + if (domain && + virStrToLong_ui(domain, NULL, 0, &addr->domain) < 0) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'domain' attribute")); + goto cleanup; + } + + if (bus && + virStrToLong_ui(bus, NULL, 0, &addr->bus) < 0) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'bus' attribute")); + goto cleanup; + } + + if (slot && + virStrToLong_ui(slot, NULL, 0, &addr->slot) < 0) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'slot' attribute")); + goto cleanup; + } + + if (function && + virStrToLong_ui(function, NULL, 0, &addr->function) < 0) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'function' attribute")); + goto cleanup; + } + + if (multi && + ((addr->multi = virDeviceAddressPciMultiTypeFromString(multi)) <= 0)) { + virDeviceReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown value '%s' for <address> 'multifunction' attribute"), + multi); + goto cleanup; + + } + if (!virDevicePCIAddressIsValid(addr)) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Insufficient specification for PCI address")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(domain); + VIR_FREE(bus); + VIR_FREE(slot); + VIR_FREE(function); + VIR_FREE(multi); + return ret; +} + +int +virDevicePCIAddressFormat(virBufferPtr buf, + virDevicePCIAddress addr, + bool includeTypeInAddr) +{ + virBufferAsprintf(buf, " <address %sdomain='0x%.4x' bus='0x%.2x' " + "slot='0x%.2x' function='0x%.1x'/>\n", + includeTypeInAddr ? "type='pci' " : "", + addr.domain, + addr.bus, + addr.slot, + addr.function); + return 0; +} diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h new file mode 100644 index 0000000..b060798 --- /dev/null +++ b/src/conf/device_conf.h @@ -0,0 +1,65 @@ +/* + * device_conf.h: device XML handling entry points + * + * Copyright (C) 2006-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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Shradha Shah <sshah@solarflare.com> + */ + +#ifndef __DEVICE_CONF_H__ +# define __DEVICE_CONF_H__ + +# include <libxml/parser.h> +# include <libxml/tree.h> +# include <libxml/xpath.h> + +# include "internal.h" +# include "util.h" +# include "threads.h" +# include "buf.h" + +enum virDeviceAddressPciMulti { + VIR_DEVICE_ADDRESS_PCI_MULTI_DEFAULT = 0, + VIR_DEVICE_ADDRESS_PCI_MULTI_ON, + VIR_DEVICE_ADDRESS_PCI_MULTI_OFF, + + VIR_DEVICE_ADDRESS_PCI_MULTI_LAST +}; + +typedef struct _virDevicePCIAddress virDevicePCIAddress; +typedef virDevicePCIAddress *virDevicePCIAddressPtr; +struct _virDevicePCIAddress { + unsigned int domain; + unsigned int bus; + unsigned int slot; + unsigned int function; + int multi; /* enum virDomainDeviceAddressPciMulti */ +}; + +int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr); + +int virDevicePCIAddressParseXML(xmlNodePtr node, + virDevicePCIAddressPtr addr); + +int virDevicePCIAddressFormat(virBufferPtr buf, + virDevicePCIAddress addr, + bool includeTypeInAddr); + + +VIR_ENUM_DECL(virDeviceAddressPciMulti) + +#endif /* __DEVICE_CONF_H__ */ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index d8c0969..ecad6cc 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -52,6 +52,7 @@ #include "netdev_vport_profile_conf.h" #include "netdev_bandwidth_conf.h" #include "virdomainlist.h" +#include "device_conf.h" #define VIR_FROM_THIS VIR_FROM_DOMAIN @@ -153,12 +154,6 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "spapr-vio", "virtio-s390") -VIR_ENUM_IMPL(virDomainDeviceAddressPciMulti, - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_LAST, - "default", - "on", - "off") - VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST, "block", "file", @@ -1897,7 +1892,7 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, switch (info->type) { case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI: - return virDomainDevicePCIAddressIsValid(&info->addr.pci); + return virDevicePCIAddressIsValid(&info->addr.pci); case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE: return 1; @@ -1909,16 +1904,6 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, return 0; } - -int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr) -{ - /* PCI bus has 32 slots and 8 functions per slot */ - if (addr->slot >= 32 || addr->function >= 8) - return 0; - return addr->domain || addr->bus || addr->slot; -} - - static bool virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info, unsigned int flags) { @@ -2143,7 +2128,7 @@ virDomainDeviceInfoFormat(virBufferPtr buf, info->addr.pci.function); if (info->addr.pci.multi) { virBufferAsprintf(buf, " multifunction='%s'", - virDomainDeviceAddressPciMultiTypeToString(info->addr.pci.multi)); + virDeviceAddressPciMultiTypeToString(info->addr.pci.multi)); } break; @@ -2191,75 +2176,6 @@ virDomainDeviceInfoFormat(virBufferPtr buf, } static int -virDomainDevicePCIAddressParseXML(xmlNodePtr node, - virDomainDevicePCIAddressPtr addr) -{ - char *domain, *slot, *bus, *function, *multi; - int ret = -1; - - memset(addr, 0, sizeof(*addr)); - - domain = virXMLPropString(node, "domain"); - bus = virXMLPropString(node, "bus"); - slot = virXMLPropString(node, "slot"); - function = virXMLPropString(node, "function"); - multi = virXMLPropString(node, "multifunction"); - - if (domain && - virStrToLong_ui(domain, NULL, 0, &addr->domain) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot parse <address> 'domain' attribute")); - goto cleanup; - } - - if (bus && - virStrToLong_ui(bus, NULL, 0, &addr->bus) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot parse <address> 'bus' attribute")); - goto cleanup; - } - - if (slot && - virStrToLong_ui(slot, NULL, 0, &addr->slot) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot parse <address> 'slot' attribute")); - goto cleanup; - } - - if (function && - virStrToLong_ui(function, NULL, 0, &addr->function) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot parse <address> 'function' attribute")); - goto cleanup; - } - - if (multi && - ((addr->multi = virDomainDeviceAddressPciMultiTypeFromString(multi)) <= 0)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unknown value '%s' for <address> 'multifunction' attribute"), - multi); - goto cleanup; - - } - if (!virDomainDevicePCIAddressIsValid(addr)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Insufficient specification for PCI address")); - goto cleanup; - } - - ret = 0; - -cleanup: - VIR_FREE(domain); - VIR_FREE(bus); - VIR_FREE(slot); - VIR_FREE(function); - VIR_FREE(multi); - return ret; -} - - -static int virDomainDeviceDriveAddressParseXML(xmlNodePtr node, virDomainDeviceDriveAddressPtr addr) { @@ -2620,7 +2536,7 @@ virDomainDeviceInfoParseXML(xmlNodePtr node, switch (info->type) { case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI: - if (virDomainDevicePCIAddressParseXML(address, &info->addr.pci) < 0) + if (virDevicePCIAddressParseXML(address, &info->addr.pci) < 0) goto cleanup; break; @@ -2668,7 +2584,7 @@ cleanup: static int virDomainParseLegacyDeviceAddress(char *devaddr, - virDomainDevicePCIAddressPtr pci) + virDevicePCIAddressPtr pci) { char *tmp; @@ -2853,10 +2769,10 @@ virDomainHostdevSubsysPciDefParseXML(const xmlNodePtr node, while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { if (xmlStrEqual(cur->name, BAD_CAST "address")) { - virDomainDevicePCIAddressPtr addr = + virDevicePCIAddressPtr addr = &def->source.subsys.u.pci; - if (virDomainDevicePCIAddressParseXML(cur, addr) < 0) + if (virDevicePCIAddressParseXML(cur, addr) < 0) goto out; } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) && xmlStrEqual(cur->name, BAD_CAST "state")) { @@ -11519,14 +11435,12 @@ virDomainHostdevSourceFormat(virBufferPtr buf, } break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: - virBufferAsprintf(buf, " <address %sdomain='0x%.4x' bus='0x%.2x' " - "slot='0x%.2x' function='0x%.1x'/>\n", - includeTypeInAddr ? "type='pci' " : "", - def->source.subsys.u.pci.domain, - def->source.subsys.u.pci.bus, - def->source.subsys.u.pci.slot, - def->source.subsys.u.pci.function); - + if (virDevicePCIAddressFormat(buf, + def->source.subsys.u.pci, + includeTypeInAddr) != 0) + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("PCI address Formatting failed")); + if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) && (def->origstates.states.pci.unbind_from_stub || def->origstates.states.pci.remove_slot || @@ -11539,7 +11453,7 @@ virDomainHostdevSourceFormat(virBufferPtr buf, if (def->origstates.states.pci.reprobe) virBufferAddLit(buf, " <reprobe/>\n"); virBufferAddLit(buf, " </origstates>\n"); - } + } break; default: virReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3f25ad2..a2e4816 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -44,6 +44,7 @@ # include "virnetdevopenvswitch.h" # include "virnetdevbandwidth.h" # include "virobject.h" +# include "device_conf.h" /* forward declarations of all device types, required by * virDomainDeviceDef @@ -179,14 +180,6 @@ enum virDomainDeviceAddressType { VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST }; -enum virDomainDeviceAddressPciMulti { - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_DEFAULT = 0, - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON, - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_OFF, - - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_LAST -}; - enum virDomainPciRombarMode { VIR_DOMAIN_PCI_ROMBAR_DEFAULT = 0, VIR_DOMAIN_PCI_ROMBAR_ON, @@ -195,16 +188,6 @@ enum virDomainPciRombarMode { VIR_DOMAIN_PCI_ROMBAR_LAST }; -typedef struct _virDomainDevicePCIAddress virDomainDevicePCIAddress; -typedef virDomainDevicePCIAddress *virDomainDevicePCIAddressPtr; -struct _virDomainDevicePCIAddress { - unsigned int domain; - unsigned int bus; - unsigned int slot; - unsigned int function; - int multi; /* enum virDomainDeviceAddressPciMulti */ -}; - typedef struct _virDomainDeviceDriveAddress virDomainDeviceDriveAddress; typedef virDomainDeviceDriveAddress *virDomainDeviceDriveAddressPtr; struct _virDomainDeviceDriveAddress { @@ -266,7 +249,7 @@ struct _virDomainDeviceInfo { char *alias; int type; union { - virDomainDevicePCIAddress pci; + virDevicePCIAddress pci; virDomainDeviceDriveAddress drive; virDomainDeviceVirtioSerialAddress vioserial; virDomainDeviceCcidAddress ccid; @@ -377,7 +360,7 @@ struct _virDomainHostdevSubsys { unsigned vendor; unsigned product; } usb; - virDomainDevicePCIAddress pci; /* host address */ + virDevicePCIAddress pci; /* host address */ } u; }; @@ -1897,7 +1880,6 @@ virDomainDeviceDefPtr virDomainDeviceDefCopy(virCapsPtr caps, virDomainDeviceDefPtr src); int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, int type); -int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr); void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); void virDomainDefClearPCIAddresses(virDomainDefPtr def); void virDomainDefClearDeviceAliases(virDomainDefPtr def); @@ -2168,7 +2150,6 @@ VIR_ENUM_DECL(virDomainLifecycle) VIR_ENUM_DECL(virDomainLifecycleCrash) VIR_ENUM_DECL(virDomainDevice) VIR_ENUM_DECL(virDomainDeviceAddress) -VIR_ENUM_DECL(virDomainDeviceAddressPciMulti) VIR_ENUM_DECL(virDomainDisk) VIR_ENUM_DECL(virDomainDiskDevice) VIR_ENUM_DECL(virDomainDiskBus) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c023dbf..f752f49 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -218,6 +218,13 @@ virStorageVolClass; virStreamClass; +# device_conf.h +virDeviceAddressPciMultiTypeFromString; +virDeviceAddressPciMultiTypeToString; +virDevicePCIAddressIsValid; +virDevicePCIAddressParseXML; +virDevicePCIAddressFormat; + # dnsmasq.h dnsmasqAddDhcpHost; dnsmasqAddHost; @@ -297,14 +304,11 @@ virDomainDefParseNode; virDomainDefParseString; virDomainDeleteConfig; virDomainDeviceAddressIsValid; -virDomainDeviceAddressPciMultiTypeFromString; -virDomainDeviceAddressPciMultiTypeToString; virDomainDeviceAddressTypeToString; virDomainDeviceDefCopy; virDomainDeviceDefFree; virDomainDeviceDefParse; virDomainDeviceInfoIterate; -virDomainDevicePCIAddressIsValid; virDomainDeviceTypeToString; virDomainDiskBusTypeToString; virDomainDiskCacheTypeFromString; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 9383530..6f6c6cd 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -40,6 +40,7 @@ #include "network/bridge_driver.h" #include "virnetdevtap.h" #include "base64.h" +#include "device_conf.h" #include <sys/utsname.h> #include <sys/stat.h> @@ -1027,7 +1028,7 @@ static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, addr = NULL; if ((info->addr.pci.function == 0) && - (info->addr.pci.multi != VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON)) { + (info->addr.pci.multi != VIR_DEVICE_ADDRESS_PCI_MULTI_ON)) { /* a function 0 w/o multifunction=on must reserve the entire slot */ int function; virDomainDeviceInfo temp_info = *info; @@ -1610,7 +1611,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) /* USB2 needs special handling to put all companions in the same slot */ if (IS_USB2_CONTROLLER(def->controllers[i])) { - virDomainDevicePCIAddress addr = { 0, 0, 0, 0, false }; + virDevicePCIAddress addr = { 0, 0, 0, 0, false }; for (j = 0 ; j < i ; j++) { if (IS_USB2_CONTROLLER(def->controllers[j]) && def->controllers[j]->idx == def->controllers[i]->idx) { @@ -1625,7 +1626,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) break; case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1: addr.function = 0; - addr.multi = VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON; + addr.multi = VIR_DEVICE_ADDRESS_PCI_MULTI_ON; break; case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2: addr.function = 1; @@ -1779,7 +1780,7 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, "are supported with this QEMU binary")); return -1; } - if (info->addr.pci.multi == VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON) { + if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_ON) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'multifunction=on' is not supported with " "this QEMU binary")); @@ -1797,9 +1798,9 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, virBufferAsprintf(buf, ",bus=pci.0"); else virBufferAsprintf(buf, ",bus=pci"); - if (info->addr.pci.multi == VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON) + if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_ON) virBufferAddLit(buf, ",multifunction=on"); - else if (info->addr.pci.multi == VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_OFF) + else if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_OFF) virBufferAddLit(buf, ",multifunction=off"); virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot); if (info->addr.pci.function != 0) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index e128e58..3eeeb29 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -43,6 +43,7 @@ #include "virnetdev.h" #include "virnetdevbridge.h" #include "virnetdevtap.h" +#include "device_conf.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -258,7 +259,7 @@ int qemuDomainAttachPciDiskDevice(virConnectPtr conn, } } } else { - virDomainDevicePCIAddress guestAddr = disk->info.addr.pci; + virDevicePCIAddress guestAddr = disk->info.addr.pci; ret = qemuMonitorAddPCIDisk(priv->mon, disk->src, type, @@ -655,7 +656,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, char *netstr = NULL; virNetDevVPortProfilePtr vport = NULL; int ret = -1; - virDomainDevicePCIAddress guestAddr; + virDevicePCIAddress guestAddr; int vlan; bool releaseaddr = false; bool iface_connected = false; @@ -974,7 +975,7 @@ int qemuDomainAttachHostPciDevice(struct qemud_driver *driver, configfd, configfd_name); qemuDomainObjExitMonitorWithDriver(driver, vm); } else { - virDomainDevicePCIAddress guestAddr = hostdev->info->addr.pci; + virDevicePCIAddress guestAddr = hostdev->info->addr.pci; qemuDomainObjEnterMonitorWithDriver(driver, vm); ret = qemuMonitorAddPCIHostDevice(priv->mon, diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index b0f3bb6..6ce1839 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2151,8 +2151,8 @@ int qemuMonitorAddUSBDeviceMatch(qemuMonitorPtr mon, int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr) { int ret; VIR_DEBUG("mon=%p domain=%d bus=%d slot=%d function=%d", @@ -2176,7 +2176,7 @@ int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon, int qemuMonitorAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { int ret; VIR_DEBUG("mon=%p path=%s bus=%s", @@ -2198,7 +2198,7 @@ int qemuMonitorAddPCIDisk(qemuMonitorPtr mon, int qemuMonitorAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { int ret; VIR_DEBUG("mon=%p nicstr=%s", mon, nicstr); @@ -2218,7 +2218,7 @@ int qemuMonitorAddPCINetwork(qemuMonitorPtr mon, int qemuMonitorRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { int ret; VIR_DEBUG("mon=%p domain=%d bus=%d slot=%d function=%d", @@ -2454,7 +2454,7 @@ int qemuMonitorGetPtyPaths(qemuMonitorPtr mon, int qemuMonitorAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { VIR_DEBUG("mon=%p type=%s", mon, bus); int ret; @@ -2476,7 +2476,7 @@ int qemuMonitorAttachPCIDiskController(qemuMonitorPtr mon, int qemuMonitorAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr) { VIR_DEBUG("mon=%p drivestr=%s domain=%d bus=%d slot=%d function=%d", diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 42f33d1..ad8d2f1 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -32,6 +32,7 @@ # include "bitmap.h" # include "virhash.h" # include "json.h" +# include "device_conf.h" typedef struct _qemuMonitor qemuMonitor; typedef qemuMonitor *qemuMonitorPtr; @@ -415,8 +416,8 @@ int qemuMonitorAddUSBDeviceMatch(qemuMonitorPtr mon, int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr); /* XXX disk driver type eg, qcow/etc. * XXX cache mode @@ -424,17 +425,17 @@ int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon, int qemuMonitorAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); /* XXX do we really want to hardcode 'nicstr' as the * sendable item here */ int qemuMonitorAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorSendFileHandle(qemuMonitorPtr mon, @@ -473,11 +474,11 @@ int qemuMonitorGetPtyPaths(qemuMonitorPtr mon, int qemuMonitorAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr); @@ -485,7 +486,7 @@ typedef struct _qemuMonitorPCIAddress qemuMonitorPCIAddress; struct _qemuMonitorPCIAddress { unsigned int vendor; unsigned int product; - virDomainDevicePCIAddress addr; + virDevicePCIAddress addr; }; int qemuMonitorGetAllPCIAddresses(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 3ede88d..7d577b9 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2628,8 +2628,8 @@ int qemuMonitorJSONAddUSBDeviceMatch(qemuMonitorPtr mon ATTRIBUTE_UNUSED, int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *hostAddr ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *hostAddr ATTRIBUTE_UNUSED, + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_add not supported in JSON mode")); @@ -2640,7 +2640,7 @@ int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon ATTRIBUTE_UNUSED, int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED, const char *path ATTRIBUTE_UNUSED, const char *bus ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_add not supported in JSON mode")); @@ -2650,7 +2650,7 @@ int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED, int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon ATTRIBUTE_UNUSED, const char *nicstr ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_add not supported in JSON mode")); @@ -2659,7 +2659,7 @@ int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon ATTRIBUTE_UNUSED, int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_del not supported in JSON mode")); @@ -2916,7 +2916,7 @@ int qemuMonitorJSONGetPtyPaths(qemuMonitorPtr mon, int qemuMonitorJSONAttachPCIDiskController(qemuMonitorPtr mon ATTRIBUTE_UNUSED, const char *bus ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_add not supported in JSON mode")); @@ -2955,7 +2955,7 @@ qemuMonitorJSONGetGuestDriveAddress(virJSONValuePtr reply, int qemuMonitorJSONAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress* controllerAddr, + virDevicePCIAddress* controllerAddr, virDomainDeviceDriveAddress* driveAddr) { int ret; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index e732178..3255007 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -163,20 +163,20 @@ int qemuMonitorJSONAddUSBDeviceMatch(qemuMonitorPtr mon, int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr); int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon, const char *fdname, @@ -203,11 +203,11 @@ int qemuMonitorJSONGetPtyPaths(qemuMonitorPtr mon, int qemuMonitorJSONAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorJSONAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr); int qemuMonitorJSONGetAllPCIAddresses(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index fa17927..a575e30 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1898,7 +1898,7 @@ int qemuMonitorTextAddUSBDeviceMatch(qemuMonitorPtr mon, static int qemuMonitorTextParsePciAddReply(qemuMonitorPtr mon ATTRIBUTE_UNUSED, const char *reply, - virDomainDevicePCIAddress *addr) + virDevicePCIAddress *addr) { char *s, *e; @@ -1960,8 +1960,8 @@ qemuMonitorTextParsePciAddReply(qemuMonitorPtr mon ATTRIBUTE_UNUSED, int qemuMonitorTextAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr) { char *cmd; char *reply = NULL; @@ -2006,7 +2006,7 @@ cleanup: int qemuMonitorTextAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { char *cmd = NULL; char *reply = NULL; @@ -2058,7 +2058,7 @@ cleanup: int qemuMonitorTextAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { char *cmd; char *reply = NULL; @@ -2091,7 +2091,7 @@ cleanup: int qemuMonitorTextRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { char *cmd = NULL; char *reply = NULL; @@ -2439,7 +2439,7 @@ cleanup: int qemuMonitorTextAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { char *cmd = NULL; char *reply = NULL; @@ -2528,7 +2528,7 @@ qemudParseDriveAddReply(const char *reply, int qemuMonitorTextAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr) { char *cmd = NULL; diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index c6fd464..aca32a0 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -147,20 +147,20 @@ int qemuMonitorTextAddUSBDeviceMatch(qemuMonitorPtr mon, int qemuMonitorTextAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr); int qemuMonitorTextAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorTextAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorTextRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorTextSendFileHandle(qemuMonitorPtr mon, const char *fdname, @@ -187,11 +187,11 @@ int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon, int qemuMonitorTextAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr); int qemuMonitorTextAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr); int qemuMonitorTextGetAllPCIAddresses(qemuMonitorPtr mon, diff --git a/src/util/virterror.c b/src/util/virterror.c index a40cfe0..d630db8 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -112,7 +112,8 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST, "URI Utils", /* 45 */ "Authentication Utils", "DBus Utils", - "Parallels Cloud Server" + "Parallels Cloud Server", + "Device Config" ) diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 892d0e5..f93b249 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -46,6 +46,7 @@ #include "count-one-bits.h" #include "virfile.h" #include "viruri.h" +#include "device_conf.h" /* required for cpumap_t */ #include <xen/dom0_ops.h> @@ -2725,7 +2726,7 @@ xenDaemonAttachDeviceFlags(virDomainPtr domain, const char *xml, if (xenFormatSxprOnePCI(dev->data.hostdev, &buf, 0) < 0) goto cleanup; - virDomainDevicePCIAddress PCIAddr; + virDevicePCIAddress PCIAddr; PCIAddr = dev->data.hostdev->source.subsys.u.pci; virAsprintf(&target, "PCI device: %.4x:%.2x:%.2x", PCIAddr.domain, -- 1.7.4.4

On 08/10/2012 12:22 PM, Shradha Shah wrote:
Refactoring existing code without causing any functional changes to prepare for new code. This patch makes the code reusable.
Please make the first line of the description *much* shorter (try for around 60 characters) and put most of the explanation in the body of the log message. For example: conf: move DevicePCIAddress functions to separate file Move the functions the parse/format, and validate PCI addresses to their own file so they can be conveniently used in other places besides device_conf.c ACK with a modified log message and fix of the 3 nits indicated below.
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- include/libvirt/virterror.h | 1 + src/Makefile.am | 6 ++- src/conf/device_conf.c | 135 ++++++++++++++++++++++++++++++++++++++++++ src/conf/device_conf.h | 65 ++++++++++++++++++++ src/conf/domain_conf.c | 114 ++++------------------------------- src/conf/domain_conf.h | 25 +------- src/libvirt_private.syms | 10 ++- src/qemu/qemu_command.c | 13 ++-- src/qemu/qemu_hotplug.c | 7 +- src/qemu/qemu_monitor.c | 14 ++-- src/qemu/qemu_monitor.h | 17 +++--- src/qemu/qemu_monitor_json.c | 14 ++-- src/qemu/qemu_monitor_json.h | 14 ++-- src/qemu/qemu_monitor_text.c | 16 +++--- src/qemu/qemu_monitor_text.h | 14 ++-- src/util/virterror.c | 3 +- src/xen/xend_internal.c | 3 +- 17 files changed, 290 insertions(+), 181 deletions(-)
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index ad8e101..a3516f6 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -110,6 +110,7 @@ typedef enum { VIR_FROM_AUTH = 46, /* Error from auth handling */ VIR_FROM_DBUS = 47, /* Error from DBus */ VIR_FROM_PARALLELS = 48, /* Error from Parallels */ + VIR_FROM_DEVICE = 49, /* Error from Device */
# ifdef VIR_ENUM_SENTINELS VIR_ERR_DOMAIN_LAST diff --git a/src/Makefile.am b/src/Makefile.am index 6ed4a41..d6ebfdf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -200,6 +200,9 @@ CONSOLE_CONF_SOURCES = \ DOMAIN_LIST_SOURCES = \ conf/virdomainlist.c conf/virdomainlist.h
+DEVICE_CONF_SOURCES = \ + conf/device_conf.c conf/device_conf.h + CONF_SOURCES = \ $(NETDEV_CONF_SOURCES) \ $(DOMAIN_CONF_SOURCES) \ @@ -213,7 +216,8 @@ CONF_SOURCES = \ $(SECRET_CONF_SOURCES) \ $(CPU_CONF_SOURCES) \ $(CONSOLE_CONF_SOURCES) \ - $(DOMAIN_LIST_SOURCES) + $(DOMAIN_LIST_SOURCES) \ + $(DEVICE_CONF_SOURCES)
# The remote RPC driver, covering domains, storage, networks, etc REMOTE_DRIVER_GENERATED = \ diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c new file mode 100644 index 0000000..d4eb764 --- /dev/null +++ b/src/conf/device_conf.c @@ -0,0 +1,135 @@ +/* + * device_conf.h: device XML handling + * + * Copyright (C) 2006-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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Shradha Shah <sshah@solarflare.com>
Since the the majority of the contents of this file are just a cut-paste from another existing file, the authorship should be taken from there.
+ */ + +#include <config.h> +#include "virterror_internal.h" +#include "datatypes.h" +#include "memory.h" +#include "xml.h" +#include "uuid.h" +#include "util.h" +#include "buf.h" +#include "conf/device_conf.h"
The conf directory is in the include path already, so you don't need to add it to the filename.
+ +#define VIR_FROM_THIS VIR_FROM_DEVICE + +#define virDeviceReportError(code, ...) \ + virReportErrorHelper(VIR_FROM_DEVICE, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__)
Dan Berrange recently changed all of the code to use a common error function: virReportError. You should remove this macro, and replace all occurences of virDeviceReportError with virReportError.
+ +VIR_ENUM_IMPL(virDeviceAddressPciMulti, + VIR_DEVICE_ADDRESS_PCI_MULTI_LAST, + "default", + "on", + "off") + +int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr) +{ + /* PCI bus has 32 slots and 8 functions per slot */ + if (addr->slot >= 32 || addr->function >= 8) + return 0; + return addr->domain || addr->bus || addr->slot; +} + + +int +virDevicePCIAddressParseXML(xmlNodePtr node, + virDevicePCIAddressPtr addr) +{ + char *domain, *slot, *bus, *function, *multi; + int ret = -1; + + memset(addr, 0, sizeof(*addr)); + + domain = virXMLPropString(node, "domain"); + bus = virXMLPropString(node, "bus"); + slot = virXMLPropString(node, "slot"); + function = virXMLPropString(node, "function"); + multi = virXMLPropString(node, "multifunction"); + + if (domain && + virStrToLong_ui(domain, NULL, 0, &addr->domain) < 0) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'domain' attribute")); + goto cleanup; + } + + if (bus && + virStrToLong_ui(bus, NULL, 0, &addr->bus) < 0) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'bus' attribute")); + goto cleanup; + } + + if (slot && + virStrToLong_ui(slot, NULL, 0, &addr->slot) < 0) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'slot' attribute")); + goto cleanup; + } + + if (function && + virStrToLong_ui(function, NULL, 0, &addr->function) < 0) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'function' attribute")); + goto cleanup; + } + + if (multi && + ((addr->multi = virDeviceAddressPciMultiTypeFromString(multi)) <= 0)) { + virDeviceReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown value '%s' for <address> 'multifunction' attribute"), + multi); + goto cleanup; + + } + if (!virDevicePCIAddressIsValid(addr)) { + virDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Insufficient specification for PCI address")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(domain); + VIR_FREE(bus); + VIR_FREE(slot); + VIR_FREE(function); + VIR_FREE(multi); + return ret; +} + +int +virDevicePCIAddressFormat(virBufferPtr buf, + virDevicePCIAddress addr, + bool includeTypeInAddr) +{ + virBufferAsprintf(buf, " <address %sdomain='0x%.4x' bus='0x%.2x' " + "slot='0x%.2x' function='0x%.1x'/>\n", + includeTypeInAddr ? "type='pci' " : "", + addr.domain, + addr.bus, + addr.slot, + addr.function); + return 0; +} diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h new file mode 100644 index 0000000..b060798 --- /dev/null +++ b/src/conf/device_conf.h @@ -0,0 +1,65 @@ +/* + * device_conf.h: device XML handling entry points + * + * Copyright (C) 2006-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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Shradha Shah <sshah@solarflare.com> + */ + +#ifndef __DEVICE_CONF_H__ +# define __DEVICE_CONF_H__ + +# include <libxml/parser.h> +# include <libxml/tree.h> +# include <libxml/xpath.h> + +# include "internal.h" +# include "util.h" +# include "threads.h" +# include "buf.h" + +enum virDeviceAddressPciMulti { + VIR_DEVICE_ADDRESS_PCI_MULTI_DEFAULT = 0, + VIR_DEVICE_ADDRESS_PCI_MULTI_ON, + VIR_DEVICE_ADDRESS_PCI_MULTI_OFF, + + VIR_DEVICE_ADDRESS_PCI_MULTI_LAST +}; + +typedef struct _virDevicePCIAddress virDevicePCIAddress; +typedef virDevicePCIAddress *virDevicePCIAddressPtr; +struct _virDevicePCIAddress { + unsigned int domain; + unsigned int bus; + unsigned int slot; + unsigned int function; + int multi; /* enum virDomainDeviceAddressPciMulti */ +}; + +int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr); + +int virDevicePCIAddressParseXML(xmlNodePtr node, + virDevicePCIAddressPtr addr); + +int virDevicePCIAddressFormat(virBufferPtr buf, + virDevicePCIAddress addr, + bool includeTypeInAddr); + + +VIR_ENUM_DECL(virDeviceAddressPciMulti) + +#endif /* __DEVICE_CONF_H__ */ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index d8c0969..ecad6cc 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -52,6 +52,7 @@ #include "netdev_vport_profile_conf.h" #include "netdev_bandwidth_conf.h" #include "virdomainlist.h" +#include "device_conf.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@@ -153,12 +154,6 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "spapr-vio", "virtio-s390")
-VIR_ENUM_IMPL(virDomainDeviceAddressPciMulti, - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_LAST, - "default", - "on", - "off") - VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST, "block", "file", @@ -1897,7 +1892,7 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
switch (info->type) { case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI: - return virDomainDevicePCIAddressIsValid(&info->addr.pci); + return virDevicePCIAddressIsValid(&info->addr.pci);
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE: return 1; @@ -1909,16 +1904,6 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, return 0; }
- -int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr) -{ - /* PCI bus has 32 slots and 8 functions per slot */ - if (addr->slot >= 32 || addr->function >= 8) - return 0; - return addr->domain || addr->bus || addr->slot; -} - - static bool virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info, unsigned int flags) { @@ -2143,7 +2128,7 @@ virDomainDeviceInfoFormat(virBufferPtr buf, info->addr.pci.function); if (info->addr.pci.multi) { virBufferAsprintf(buf, " multifunction='%s'", - virDomainDeviceAddressPciMultiTypeToString(info->addr.pci.multi)); + virDeviceAddressPciMultiTypeToString(info->addr.pci.multi)); } break;
@@ -2191,75 +2176,6 @@ virDomainDeviceInfoFormat(virBufferPtr buf, }
static int -virDomainDevicePCIAddressParseXML(xmlNodePtr node, - virDomainDevicePCIAddressPtr addr) -{ - char *domain, *slot, *bus, *function, *multi; - int ret = -1; - - memset(addr, 0, sizeof(*addr)); - - domain = virXMLPropString(node, "domain"); - bus = virXMLPropString(node, "bus"); - slot = virXMLPropString(node, "slot"); - function = virXMLPropString(node, "function"); - multi = virXMLPropString(node, "multifunction"); - - if (domain && - virStrToLong_ui(domain, NULL, 0, &addr->domain) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot parse <address> 'domain' attribute")); - goto cleanup; - } - - if (bus && - virStrToLong_ui(bus, NULL, 0, &addr->bus) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot parse <address> 'bus' attribute")); - goto cleanup; - } - - if (slot && - virStrToLong_ui(slot, NULL, 0, &addr->slot) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot parse <address> 'slot' attribute")); - goto cleanup; - } - - if (function && - virStrToLong_ui(function, NULL, 0, &addr->function) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot parse <address> 'function' attribute")); - goto cleanup; - } - - if (multi && - ((addr->multi = virDomainDeviceAddressPciMultiTypeFromString(multi)) <= 0)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unknown value '%s' for <address> 'multifunction' attribute"), - multi); - goto cleanup; - - } - if (!virDomainDevicePCIAddressIsValid(addr)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Insufficient specification for PCI address")); - goto cleanup; - } - - ret = 0; - -cleanup: - VIR_FREE(domain); - VIR_FREE(bus); - VIR_FREE(slot); - VIR_FREE(function); - VIR_FREE(multi); - return ret; -} - - -static int virDomainDeviceDriveAddressParseXML(xmlNodePtr node, virDomainDeviceDriveAddressPtr addr) { @@ -2620,7 +2536,7 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
switch (info->type) { case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI: - if (virDomainDevicePCIAddressParseXML(address, &info->addr.pci) < 0) + if (virDevicePCIAddressParseXML(address, &info->addr.pci) < 0) goto cleanup; break;
@@ -2668,7 +2584,7 @@ cleanup:
static int virDomainParseLegacyDeviceAddress(char *devaddr, - virDomainDevicePCIAddressPtr pci) + virDevicePCIAddressPtr pci) { char *tmp;
@@ -2853,10 +2769,10 @@ virDomainHostdevSubsysPciDefParseXML(const xmlNodePtr node, while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { if (xmlStrEqual(cur->name, BAD_CAST "address")) { - virDomainDevicePCIAddressPtr addr = + virDevicePCIAddressPtr addr = &def->source.subsys.u.pci;
- if (virDomainDevicePCIAddressParseXML(cur, addr) < 0) + if (virDevicePCIAddressParseXML(cur, addr) < 0) goto out; } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) && xmlStrEqual(cur->name, BAD_CAST "state")) { @@ -11519,14 +11435,12 @@ virDomainHostdevSourceFormat(virBufferPtr buf, } break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: - virBufferAsprintf(buf, " <address %sdomain='0x%.4x' bus='0x%.2x' " - "slot='0x%.2x' function='0x%.1x'/>\n", - includeTypeInAddr ? "type='pci' " : "", - def->source.subsys.u.pci.domain, - def->source.subsys.u.pci.bus, - def->source.subsys.u.pci.slot, - def->source.subsys.u.pci.function); - + if (virDevicePCIAddressFormat(buf, + def->source.subsys.u.pci, + includeTypeInAddr) != 0) + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("PCI address Formatting failed")); + if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) && (def->origstates.states.pci.unbind_from_stub || def->origstates.states.pci.remove_slot || @@ -11539,7 +11453,7 @@ virDomainHostdevSourceFormat(virBufferPtr buf, if (def->origstates.states.pci.reprobe) virBufferAddLit(buf, " <reprobe/>\n"); virBufferAddLit(buf, " </origstates>\n"); - } + } break; default: virReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3f25ad2..a2e4816 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -44,6 +44,7 @@ # include "virnetdevopenvswitch.h" # include "virnetdevbandwidth.h" # include "virobject.h" +# include "device_conf.h"
/* forward declarations of all device types, required by * virDomainDeviceDef @@ -179,14 +180,6 @@ enum virDomainDeviceAddressType { VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST };
-enum virDomainDeviceAddressPciMulti { - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_DEFAULT = 0, - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON, - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_OFF, - - VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_LAST -}; - enum virDomainPciRombarMode { VIR_DOMAIN_PCI_ROMBAR_DEFAULT = 0, VIR_DOMAIN_PCI_ROMBAR_ON, @@ -195,16 +188,6 @@ enum virDomainPciRombarMode { VIR_DOMAIN_PCI_ROMBAR_LAST };
-typedef struct _virDomainDevicePCIAddress virDomainDevicePCIAddress; -typedef virDomainDevicePCIAddress *virDomainDevicePCIAddressPtr; -struct _virDomainDevicePCIAddress { - unsigned int domain; - unsigned int bus; - unsigned int slot; - unsigned int function; - int multi; /* enum virDomainDeviceAddressPciMulti */ -}; - typedef struct _virDomainDeviceDriveAddress virDomainDeviceDriveAddress; typedef virDomainDeviceDriveAddress *virDomainDeviceDriveAddressPtr; struct _virDomainDeviceDriveAddress { @@ -266,7 +249,7 @@ struct _virDomainDeviceInfo { char *alias; int type; union { - virDomainDevicePCIAddress pci; + virDevicePCIAddress pci; virDomainDeviceDriveAddress drive; virDomainDeviceVirtioSerialAddress vioserial; virDomainDeviceCcidAddress ccid; @@ -377,7 +360,7 @@ struct _virDomainHostdevSubsys { unsigned vendor; unsigned product; } usb; - virDomainDevicePCIAddress pci; /* host address */ + virDevicePCIAddress pci; /* host address */ } u; };
@@ -1897,7 +1880,6 @@ virDomainDeviceDefPtr virDomainDeviceDefCopy(virCapsPtr caps, virDomainDeviceDefPtr src); int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, int type); -int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr); void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); void virDomainDefClearPCIAddresses(virDomainDefPtr def); void virDomainDefClearDeviceAliases(virDomainDefPtr def); @@ -2168,7 +2150,6 @@ VIR_ENUM_DECL(virDomainLifecycle) VIR_ENUM_DECL(virDomainLifecycleCrash) VIR_ENUM_DECL(virDomainDevice) VIR_ENUM_DECL(virDomainDeviceAddress) -VIR_ENUM_DECL(virDomainDeviceAddressPciMulti) VIR_ENUM_DECL(virDomainDisk) VIR_ENUM_DECL(virDomainDiskDevice) VIR_ENUM_DECL(virDomainDiskBus) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c023dbf..f752f49 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -218,6 +218,13 @@ virStorageVolClass; virStreamClass;
+# device_conf.h +virDeviceAddressPciMultiTypeFromString; +virDeviceAddressPciMultiTypeToString; +virDevicePCIAddressIsValid; +virDevicePCIAddressParseXML; +virDevicePCIAddressFormat; + # dnsmasq.h dnsmasqAddDhcpHost; dnsmasqAddHost; @@ -297,14 +304,11 @@ virDomainDefParseNode; virDomainDefParseString; virDomainDeleteConfig; virDomainDeviceAddressIsValid; -virDomainDeviceAddressPciMultiTypeFromString; -virDomainDeviceAddressPciMultiTypeToString; virDomainDeviceAddressTypeToString; virDomainDeviceDefCopy; virDomainDeviceDefFree; virDomainDeviceDefParse; virDomainDeviceInfoIterate; -virDomainDevicePCIAddressIsValid; virDomainDeviceTypeToString; virDomainDiskBusTypeToString; virDomainDiskCacheTypeFromString; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 9383530..6f6c6cd 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -40,6 +40,7 @@ #include "network/bridge_driver.h" #include "virnetdevtap.h" #include "base64.h" +#include "device_conf.h"
#include <sys/utsname.h> #include <sys/stat.h> @@ -1027,7 +1028,7 @@ static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, addr = NULL;
if ((info->addr.pci.function == 0) && - (info->addr.pci.multi != VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON)) { + (info->addr.pci.multi != VIR_DEVICE_ADDRESS_PCI_MULTI_ON)) { /* a function 0 w/o multifunction=on must reserve the entire slot */ int function; virDomainDeviceInfo temp_info = *info; @@ -1610,7 +1611,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
/* USB2 needs special handling to put all companions in the same slot */ if (IS_USB2_CONTROLLER(def->controllers[i])) { - virDomainDevicePCIAddress addr = { 0, 0, 0, 0, false }; + virDevicePCIAddress addr = { 0, 0, 0, 0, false }; for (j = 0 ; j < i ; j++) { if (IS_USB2_CONTROLLER(def->controllers[j]) && def->controllers[j]->idx == def->controllers[i]->idx) { @@ -1625,7 +1626,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) break; case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1: addr.function = 0; - addr.multi = VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON; + addr.multi = VIR_DEVICE_ADDRESS_PCI_MULTI_ON; break; case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2: addr.function = 1; @@ -1779,7 +1780,7 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, "are supported with this QEMU binary")); return -1; } - if (info->addr.pci.multi == VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON) { + if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_ON) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'multifunction=on' is not supported with " "this QEMU binary")); @@ -1797,9 +1798,9 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, virBufferAsprintf(buf, ",bus=pci.0"); else virBufferAsprintf(buf, ",bus=pci"); - if (info->addr.pci.multi == VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON) + if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_ON) virBufferAddLit(buf, ",multifunction=on"); - else if (info->addr.pci.multi == VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_OFF) + else if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_OFF) virBufferAddLit(buf, ",multifunction=off"); virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot); if (info->addr.pci.function != 0) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index e128e58..3eeeb29 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -43,6 +43,7 @@ #include "virnetdev.h" #include "virnetdevbridge.h" #include "virnetdevtap.h" +#include "device_conf.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -258,7 +259,7 @@ int qemuDomainAttachPciDiskDevice(virConnectPtr conn, } } } else { - virDomainDevicePCIAddress guestAddr = disk->info.addr.pci; + virDevicePCIAddress guestAddr = disk->info.addr.pci; ret = qemuMonitorAddPCIDisk(priv->mon, disk->src, type, @@ -655,7 +656,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, char *netstr = NULL; virNetDevVPortProfilePtr vport = NULL; int ret = -1; - virDomainDevicePCIAddress guestAddr; + virDevicePCIAddress guestAddr; int vlan; bool releaseaddr = false; bool iface_connected = false; @@ -974,7 +975,7 @@ int qemuDomainAttachHostPciDevice(struct qemud_driver *driver, configfd, configfd_name); qemuDomainObjExitMonitorWithDriver(driver, vm); } else { - virDomainDevicePCIAddress guestAddr = hostdev->info->addr.pci; + virDevicePCIAddress guestAddr = hostdev->info->addr.pci;
qemuDomainObjEnterMonitorWithDriver(driver, vm); ret = qemuMonitorAddPCIHostDevice(priv->mon, diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index b0f3bb6..6ce1839 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2151,8 +2151,8 @@ int qemuMonitorAddUSBDeviceMatch(qemuMonitorPtr mon,
int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr) { int ret; VIR_DEBUG("mon=%p domain=%d bus=%d slot=%d function=%d", @@ -2176,7 +2176,7 @@ int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon, int qemuMonitorAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { int ret; VIR_DEBUG("mon=%p path=%s bus=%s", @@ -2198,7 +2198,7 @@ int qemuMonitorAddPCIDisk(qemuMonitorPtr mon,
int qemuMonitorAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { int ret; VIR_DEBUG("mon=%p nicstr=%s", mon, nicstr); @@ -2218,7 +2218,7 @@ int qemuMonitorAddPCINetwork(qemuMonitorPtr mon,
int qemuMonitorRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { int ret; VIR_DEBUG("mon=%p domain=%d bus=%d slot=%d function=%d", @@ -2454,7 +2454,7 @@ int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
int qemuMonitorAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { VIR_DEBUG("mon=%p type=%s", mon, bus); int ret; @@ -2476,7 +2476,7 @@ int qemuMonitorAttachPCIDiskController(qemuMonitorPtr mon,
int qemuMonitorAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr) { VIR_DEBUG("mon=%p drivestr=%s domain=%d bus=%d slot=%d function=%d", diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 42f33d1..ad8d2f1 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -32,6 +32,7 @@ # include "bitmap.h" # include "virhash.h" # include "json.h" +# include "device_conf.h"
typedef struct _qemuMonitor qemuMonitor; typedef qemuMonitor *qemuMonitorPtr; @@ -415,8 +416,8 @@ int qemuMonitorAddUSBDeviceMatch(qemuMonitorPtr mon,
int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr);
/* XXX disk driver type eg, qcow/etc. * XXX cache mode @@ -424,17 +425,17 @@ int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon, int qemuMonitorAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
/* XXX do we really want to hardcode 'nicstr' as the * sendable item here */ int qemuMonitorAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorSendFileHandle(qemuMonitorPtr mon, @@ -473,11 +474,11 @@ int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
int qemuMonitorAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr);
@@ -485,7 +486,7 @@ typedef struct _qemuMonitorPCIAddress qemuMonitorPCIAddress; struct _qemuMonitorPCIAddress { unsigned int vendor; unsigned int product; - virDomainDevicePCIAddress addr; + virDevicePCIAddress addr; };
int qemuMonitorGetAllPCIAddresses(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 3ede88d..7d577b9 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2628,8 +2628,8 @@ int qemuMonitorJSONAddUSBDeviceMatch(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *hostAddr ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *hostAddr ATTRIBUTE_UNUSED, + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_add not supported in JSON mode")); @@ -2640,7 +2640,7 @@ int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon ATTRIBUTE_UNUSED, int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED, const char *path ATTRIBUTE_UNUSED, const char *bus ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_add not supported in JSON mode")); @@ -2650,7 +2650,7 @@ int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon ATTRIBUTE_UNUSED, const char *nicstr ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_add not supported in JSON mode")); @@ -2659,7 +2659,7 @@ int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_del not supported in JSON mode")); @@ -2916,7 +2916,7 @@ int qemuMonitorJSONGetPtyPaths(qemuMonitorPtr mon,
int qemuMonitorJSONAttachPCIDiskController(qemuMonitorPtr mon ATTRIBUTE_UNUSED, const char *bus ATTRIBUTE_UNUSED, - virDomainDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) + virDevicePCIAddress *guestAddr ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("pci_add not supported in JSON mode")); @@ -2955,7 +2955,7 @@ qemuMonitorJSONGetGuestDriveAddress(virJSONValuePtr reply,
int qemuMonitorJSONAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress* controllerAddr, + virDevicePCIAddress* controllerAddr, virDomainDeviceDriveAddress* driveAddr) { int ret; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index e732178..3255007 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -163,20 +163,20 @@ int qemuMonitorJSONAddUSBDeviceMatch(qemuMonitorPtr mon,
int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr);
int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon, const char *fdname, @@ -203,11 +203,11 @@ int qemuMonitorJSONGetPtyPaths(qemuMonitorPtr mon,
int qemuMonitorJSONAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorJSONAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr);
int qemuMonitorJSONGetAllPCIAddresses(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index fa17927..a575e30 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1898,7 +1898,7 @@ int qemuMonitorTextAddUSBDeviceMatch(qemuMonitorPtr mon, static int qemuMonitorTextParsePciAddReply(qemuMonitorPtr mon ATTRIBUTE_UNUSED, const char *reply, - virDomainDevicePCIAddress *addr) + virDevicePCIAddress *addr) { char *s, *e;
@@ -1960,8 +1960,8 @@ qemuMonitorTextParsePciAddReply(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
int qemuMonitorTextAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr) { char *cmd; char *reply = NULL; @@ -2006,7 +2006,7 @@ cleanup: int qemuMonitorTextAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { char *cmd = NULL; char *reply = NULL; @@ -2058,7 +2058,7 @@ cleanup:
int qemuMonitorTextAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { char *cmd; char *reply = NULL; @@ -2091,7 +2091,7 @@ cleanup:
int qemuMonitorTextRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { char *cmd = NULL; char *reply = NULL; @@ -2439,7 +2439,7 @@ cleanup:
int qemuMonitorTextAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr) + virDevicePCIAddress *guestAddr) { char *cmd = NULL; char *reply = NULL; @@ -2528,7 +2528,7 @@ qemudParseDriveAddReply(const char *reply,
int qemuMonitorTextAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr) { char *cmd = NULL; diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index c6fd464..aca32a0 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -147,20 +147,20 @@ int qemuMonitorTextAddUSBDeviceMatch(qemuMonitorPtr mon,
int qemuMonitorTextAddPCIHostDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *hostAddr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *hostAddr, + virDevicePCIAddress *guestAddr);
int qemuMonitorTextAddPCIDisk(qemuMonitorPtr mon, const char *path, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorTextAddPCINetwork(qemuMonitorPtr mon, const char *nicstr, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorTextRemovePCIDevice(qemuMonitorPtr mon, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorTextSendFileHandle(qemuMonitorPtr mon, const char *fdname, @@ -187,11 +187,11 @@ int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon,
int qemuMonitorTextAttachPCIDiskController(qemuMonitorPtr mon, const char *bus, - virDomainDevicePCIAddress *guestAddr); + virDevicePCIAddress *guestAddr);
int qemuMonitorTextAttachDrive(qemuMonitorPtr mon, const char *drivestr, - virDomainDevicePCIAddress *controllerAddr, + virDevicePCIAddress *controllerAddr, virDomainDeviceDriveAddress *driveAddr);
int qemuMonitorTextGetAllPCIAddresses(qemuMonitorPtr mon, diff --git a/src/util/virterror.c b/src/util/virterror.c index a40cfe0..d630db8 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -112,7 +112,8 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST, "URI Utils", /* 45 */ "Authentication Utils", "DBus Utils", - "Parallels Cloud Server" + "Parallels Cloud Server", + "Device Config" )
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 892d0e5..f93b249 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -46,6 +46,7 @@ #include "count-one-bits.h" #include "virfile.h" #include "viruri.h" +#include "device_conf.h"
/* required for cpumap_t */ #include <xen/dom0_ops.h> @@ -2725,7 +2726,7 @@ xenDaemonAttachDeviceFlags(virDomainPtr domain, const char *xml, if (xenFormatSxprOnePCI(dev->data.hostdev, &buf, 0) < 0) goto cleanup;
- virDomainDevicePCIAddress PCIAddr; + virDevicePCIAddress PCIAddr;
PCIAddr = dev->data.hostdev->source.subsys.u.pci; virAsprintf(&target, "PCI device: %.4x:%.2x:%.2x", PCIAddr.domain,

Just code movement no functional changes here. This makes the code reusable Signed-off-by: Shradha Shah <sshah@solarflare.com> --- src/network/bridge_driver.c | 86 ++++++++++++++++++++++++++---------------- 1 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index a5046f1..f128bd0 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2728,6 +2728,56 @@ int networkRegister(void) { * "backend" function table. */ +/* networkCreateInterfacePool: + * @netdef: the original NetDef from the network + * + * Creates an implicit interface pool of VF's when a PF dev is given + */ +static int +networkCreateInterfacePool(virNetworkDefPtr netdef) { + unsigned int num_virt_fns = 0; + char **vfname = NULL; + int ret = -1, ii = 0; + + if ((virNetDevGetVirtualFunctions(netdef->forwardPfs->dev, + &vfname, &num_virt_fns)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get Virtual functions on %s"), + netdef->forwardPfs->dev); + goto finish; + } + + if (num_virt_fns == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("No Vf's present on SRIOV PF %s"), + netdef->forwardPfs->dev); + goto finish; + } + + if ((VIR_ALLOC_N(netdef->forwardIfs, num_virt_fns)) < 0) { + virReportOOMError(); + goto finish; + } + + netdef->nForwardIfs = num_virt_fns; + + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + netdef->forwardIfs[ii].dev = strdup(vfname[ii]); + if (!netdef->forwardIfs[ii].dev) { + virReportOOMError(); + goto finish; + } + netdef->forwardIfs[ii].usageCount = 0; + } + + ret = 0; +finish: + for (ii = 0; ii < num_virt_fns; ii++) + VIR_FREE(vfname[ii]); + VIR_FREE(vfname); + return ret; +} + /* networkAllocateActualDevice: * @iface: the original NetDef from the domain * @@ -2746,8 +2796,6 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) virNetworkObjPtr network; virNetworkDefPtr netdef; virPortGroupDefPtr portgroup; - unsigned int num_virt_fns = 0; - char **vfname = NULL; int ii; int ret = -1; @@ -2894,36 +2942,11 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) */ if (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) { if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { - if ((virNetDevGetVirtualFunctions(netdef->forwardPfs->dev, - &vfname, &num_virt_fns)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not get Virtual functions on %s"), - netdef->forwardPfs->dev); + if ((networkCreateInterfacePool(netdef)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not Interface Pool")); goto cleanup; } - - if (num_virt_fns == 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("No Vf's present on SRIOV PF %s"), - netdef->forwardPfs->dev); - goto cleanup; - } - - if ((VIR_ALLOC_N(netdef->forwardIfs, num_virt_fns)) < 0) { - virReportOOMError(); - goto cleanup; - } - - netdef->nForwardIfs = num_virt_fns; - - for (ii = 0; ii < netdef->nForwardIfs; ii++) { - netdef->forwardIfs[ii].dev = strdup(vfname[ii]); - if (!netdef->forwardIfs[ii].dev) { - virReportOOMError(); - goto cleanup; - } - netdef->forwardIfs[ii].usageCount = 0; - } } /* pick first dev with 0 usageCount */ @@ -2976,9 +2999,6 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) ret = 0; cleanup: - for (ii = 0; ii < num_virt_fns; ii++) - VIR_FREE(vfname[ii]); - VIR_FREE(vfname); if (network) virNetworkObjUnlock(network); if (ret < 0) { -- 1.7.4.4

On 08/10/2012 12:23 PM, Shradha Shah wrote:
Just code movement no functional changes here. This makes the code reusable
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- src/network/bridge_driver.c | 86 ++++++++++++++++++++++++++---------------- 1 files changed, 53 insertions(+), 33 deletions(-)
Nearly pure code movement. ACK.
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index a5046f1..f128bd0 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2728,6 +2728,56 @@ int networkRegister(void) { * "backend" function table. */
+/* networkCreateInterfacePool: + * @netdef: the original NetDef from the network + * + * Creates an implicit interface pool of VF's when a PF dev is given + */ +static int +networkCreateInterfacePool(virNetworkDefPtr netdef) { + unsigned int num_virt_fns = 0; + char **vfname = NULL; + int ret = -1, ii = 0; + + if ((virNetDevGetVirtualFunctions(netdef->forwardPfs->dev, + &vfname, &num_virt_fns)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get Virtual functions on %s"), + netdef->forwardPfs->dev); + goto finish; + } + + if (num_virt_fns == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("No Vf's present on SRIOV PF %s"), + netdef->forwardPfs->dev); + goto finish; + } + + if ((VIR_ALLOC_N(netdef->forwardIfs, num_virt_fns)) < 0) { + virReportOOMError(); + goto finish; + } + + netdef->nForwardIfs = num_virt_fns; + + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + netdef->forwardIfs[ii].dev = strdup(vfname[ii]); + if (!netdef->forwardIfs[ii].dev) { + virReportOOMError(); + goto finish; + } + netdef->forwardIfs[ii].usageCount = 0; + } + + ret = 0; +finish: + for (ii = 0; ii < num_virt_fns; ii++) + VIR_FREE(vfname[ii]); + VIR_FREE(vfname); + return ret; +} + /* networkAllocateActualDevice: * @iface: the original NetDef from the domain * @@ -2746,8 +2796,6 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) virNetworkObjPtr network; virNetworkDefPtr netdef; virPortGroupDefPtr portgroup; - unsigned int num_virt_fns = 0; - char **vfname = NULL; int ii; int ret = -1;
@@ -2894,36 +2942,11 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) */ if (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) { if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { - if ((virNetDevGetVirtualFunctions(netdef->forwardPfs->dev, - &vfname, &num_virt_fns)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not get Virtual functions on %s"), - netdef->forwardPfs->dev); + if ((networkCreateInterfacePool(netdef)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not Interface Pool")); goto cleanup; } - - if (num_virt_fns == 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("No Vf's present on SRIOV PF %s"), - netdef->forwardPfs->dev); - goto cleanup; - } - - if ((VIR_ALLOC_N(netdef->forwardIfs, num_virt_fns)) < 0) { - virReportOOMError(); - goto cleanup; - } - - netdef->nForwardIfs = num_virt_fns; - - for (ii = 0; ii < netdef->nForwardIfs; ii++) { - netdef->forwardIfs[ii].dev = strdup(vfname[ii]); - if (!netdef->forwardIfs[ii].dev) { - virReportOOMError(); - goto cleanup; - } - netdef->forwardIfs[ii].usageCount = 0; - } }
/* pick first dev with 0 usageCount */ @@ -2976,9 +2999,6 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
ret = 0; cleanup: - for (ii = 0; ii < num_virt_fns; ii++) - VIR_FREE(vfname[ii]); - VIR_FREE(vfname); if (network) virNetworkObjUnlock(network); if (ret < 0) {

On 08/10/2012 12:23 PM, Shradha Shah wrote:
Just code movement no functional changes here. This makes the code reusable
BTW - again for this patch, make the title line much shorter, e.g: network: helper function to create interface pool from PF Existing code that creates a list of forwardIfs from a single PF was moved to the new utility function networkCreateInterfacePool. No functional change.
@@ -2894,36 +2942,11 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) */ if (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) { if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { - if ((virNetDevGetVirtualFunctions(netdef->forwardPfs->dev, - &vfname, &num_virt_fns)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not get Virtual functions on %s"), - netdef->forwardPfs->dev); + if ((networkCreateInterfacePool(netdef)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not Interface Pool"));
I just noticed - networkCreateInterfacePool() logs its own, more specific error. If you log an error here, it will overwrite the better error. So don't.

This patch introduces the new forward mode='hostdev' along with attribute managed Includes updates to the network RNG and new xml parser/formatter code. Signed-off-by: Shradha Shah <sshah@solarflare.com> --- docs/schemas/network.rng | 82 +++++++++++++++++++-- src/conf/network_conf.c | 127 ++++++++++++++++++++++++++++---- src/conf/network_conf.h | 29 +++++++- src/network/bridge_driver.c | 18 ++-- tests/networkxml2xmlin/hostdev-pf.xml | 11 +++ tests/networkxml2xmlin/hostdev.xml | 10 +++ tests/networkxml2xmlout/hostdev-pf.xml | 7 ++ tests/networkxml2xmlout/hostdev.xml | 10 +++ tests/networkxml2xmltest.c | 2 + 9 files changed, 263 insertions(+), 33 deletions(-) diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 2ae879e..d1297cd 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -82,17 +82,41 @@ <value>passthrough</value> <value>private</value> <value>vepa</value> + <value>hostdev</value> + </choice> + </attribute> + </optional> + + <optional> + <attribute name="managed"> + <choice> + <value>yes</value> + <value>no</value> </choice> </attribute> </optional> <interleave> - <zeroOrMore> - <element name='interface'> - <attribute name='dev'> - <ref name='deviceName'/> - </attribute> - </element> - </zeroOrMore> + <choice> + <group> + <zeroOrMore> + <element name='interface'> + <attribute name='dev'> + <ref name='deviceName'/> + </attribute> + </element> + </zeroOrMore> + </group> + <group> + <zeroOrMore> + <element name='address'> + <attribute name='type'> + <value>pci</value> + </attribute> + <ref name="pciaddress"/> + </element> + </zeroOrMore> + </group> + </choice> <optional> <element name='pf'> <attribute name='dev'> @@ -238,4 +262,48 @@ </interleave> </element> </define> + <define name="pciaddress"> + <optional> + <attribute name="domain"> + <ref name="pciDomain"/> + </attribute> + </optional> + <attribute name="bus"> + <ref name="pciBus"/> + </attribute> + <attribute name="slot"> + <ref name="pciSlot"/> + </attribute> + <attribute name="function"> + <ref name="pciFunc"/> + </attribute> + <optional> + <attribute name="multifunction"> + <choice> + <value>on</value> + <value>off</value> + </choice> + </attribute> + </optional> + </define> + <define name="pciDomain"> + <data type="string"> + <param name="pattern">(0x)?[0-9a-fA-F]{1,4}</param> + </data> + </define> + <define name="pciBus"> + <data type="string"> + <param name="pattern">(0x)?[0-9a-fA-F]{1,2}</param> + </data> + </define> + <define name="pciSlot"> + <data type="string"> + <param name="pattern">(0x)?[0-1]?[0-9a-fA-F]</param> + </data> + </define> + <define name="pciFunc"> + <data type="string"> + <param name="pattern">(0x)?[0-7]</param> + </data> + </define> </grammar> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index a3714d9..294939d 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -49,7 +49,12 @@ VIR_ENUM_IMPL(virNetworkForward, VIR_NETWORK_FORWARD_LAST, - "none", "nat", "route", "bridge", "private", "vepa", "passthrough" ) + "none", "nat", "route", "bridge", "private", "vepa", "passthrough", "hostdev") + +VIR_ENUM_DECL(virNetworkForwardHostdevDevice) +VIR_ENUM_IMPL(virNetworkForwardHostdevDevice, + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST, + "none", "pci") virNetworkObjPtr virNetworkFindByUUID(const virNetworkObjListPtr nets, const unsigned char *uuid) @@ -94,6 +99,12 @@ virPortGroupDefClear(virPortGroupDefPtr def) static void virNetworkForwardIfDefClear(virNetworkForwardIfDefPtr def) { + VIR_FREE(def->device.dev); +} + +static void +virNetworkForwardPfDefClear(virNetworkForwardPfDefPtr def) +{ VIR_FREE(def->dev); } @@ -157,12 +168,13 @@ void virNetworkDefFree(virNetworkDefPtr def) VIR_FREE(def->domain); for (ii = 0 ; ii < def->nForwardPfs && def->forwardPfs ; ii++) { - virNetworkForwardIfDefClear(&def->forwardPfs[ii]); + virNetworkForwardPfDefClear(&def->forwardPfs[ii]); } VIR_FREE(def->forwardPfs); for (ii = 0 ; ii < def->nForwardIfs && def->forwardIfs ; ii++) { - virNetworkForwardIfDefClear(&def->forwardIfs[ii]); + if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) + virNetworkForwardIfDefClear(&def->forwardIfs[ii]); } VIR_FREE(def->forwardIfs); @@ -929,11 +941,14 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) xmlNodePtr *portGroupNodes = NULL; xmlNodePtr *forwardIfNodes = NULL; xmlNodePtr *forwardPfNodes = NULL; + xmlNodePtr *forwardAddrNodes = NULL; xmlNodePtr dnsNode = NULL; xmlNodePtr virtPortNode = NULL; xmlNodePtr forwardNode = NULL; - int nIps, nPortGroups, nForwardIfs, nForwardPfs; + int nIps, nPortGroups, nForwardIfs, nForwardPfs, nForwardAddrs; char *forwardDev = NULL; + char *forwardManaged = NULL; + char *type = NULL; xmlNodePtr save = ctxt->node; xmlNodePtr bandwidthNode = NULL; @@ -1079,17 +1094,30 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) } forwardDev = virXPathString("string(./@dev)", ctxt); + forwardManaged = virXPathString("string(./@managed)", ctxt); + if(forwardManaged != NULL) { + if (STREQ(forwardManaged, "yes")) + def->managed = 1; + else + def->managed = 0; + } /* all of these modes can use a pool of physical interfaces */ nForwardIfs = virXPathNodeSet("./interface", ctxt, &forwardIfNodes); nForwardPfs = virXPathNodeSet("./pf", ctxt, &forwardPfNodes); + nForwardAddrs = virXPathNodeSet("./address", ctxt, &forwardAddrNodes); - if (nForwardIfs < 0 || nForwardPfs < 0) { + if (nForwardIfs < 0 || nForwardPfs < 0 || nForwardAddrs < 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("No interface pool or SRIOV physical device given")); goto error; } + if ((nForwardIfs > 0) && (nForwardAddrs > 0)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Address and interface attributes are mutually exclusive")); + } + if (nForwardPfs == 1) { if (VIR_ALLOC_N(def->forwardPfs, nForwardPfs) < 0) { virReportOOMError(); @@ -1119,7 +1147,55 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) _("Use of more than one physical interface is not allowed")); goto error; } - if (nForwardIfs > 0 || forwardDev) { + if (nForwardAddrs > 0) { + int ii; + + if (VIR_ALLOC_N(def->forwardIfs, nForwardAddrs) < 0) { + virReportOOMError(); + goto error; + } + + if (forwardDev) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("A forward Dev should not be used when using address attribute")); + goto error; + } + + for (ii = 0; ii < nForwardAddrs; ii++) { + type = virXMLPropString(*forwardAddrNodes, "type"); + + if (type) { + if ((def->forwardIfs[ii].type = virNetworkForwardHostdevDeviceTypeFromString(type)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown address type '%s'"), type); + goto error; + } + } else { + virReportError(VIR_ERR_XML_ERROR, + "%s", _("No type specified for device address")); + goto error; + } + + switch (def->forwardIfs[ii].type) { + case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: + if (virDevicePCIAddressParseXML(*forwardAddrNodes, &(def->forwardIfs[ii].device.pci)) < 0) + goto error; + break; + + /* Add USB case here */ + + default: + virReportError(VIR_ERR_XML_ERROR, + _("unknown address type '%s'"), type); + goto error; + } + + def->forwardIfs[ii].usageCount = 0; + type = NULL; + def->nForwardIfs++; + } + } + else if (nForwardIfs > 0 || forwardDev) { int ii; /* allocate array to hold all the portgroups */ @@ -1130,7 +1206,8 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) if (forwardDev) { def->forwardIfs[0].usageCount = 0; - def->forwardIfs[0].dev = forwardDev; + def->forwardIfs[0].device.dev = forwardDev; + def->forwardIfs[0].type = 0; forwardDev = NULL; def->nForwardIfs++; } @@ -1148,10 +1225,10 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) if ((ii == 0) && (def->nForwardIfs == 1)) { /* both forwardDev and an interface element are present. * If they don't match, it's an error. */ - if (STRNEQ(forwardDev, def->forwardIfs[0].dev)) { - virReportError(VIR_ERR_XML_ERROR, + if (STRNEQ(forwardDev, def->forwardIfs[0].device.dev)) { + virReportError(VIR_ERR_XML_ERROR, _("forward dev '%s' must match first interface element dev '%s' in network '%s'"), - def->forwardIfs[0].dev, + def->forwardIfs[0].device.dev, forwardDev, def->name); goto error; } @@ -1159,16 +1236,19 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) continue; } - def->forwardIfs[ii].dev = forwardDev; + def->forwardIfs[ii].device.dev = forwardDev; forwardDev = NULL; def->forwardIfs[ii].usageCount = 0; + def->forwardIfs[ii].type = 0; def->nForwardIfs++; } } + VIR_FREE(type); VIR_FREE(forwardDev); + VIR_FREE(forwardManaged); VIR_FREE(forwardPfNodes); VIR_FREE(forwardIfNodes); - + VIR_FREE(forwardAddrNodes); switch (def->forwardType) { case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_NAT: @@ -1193,6 +1273,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: + case VIR_NETWORK_FORWARD_HOSTDEV: if (def->bridge) { virReportError(VIR_ERR_XML_ERROR, _("bridge name not allowed in %s mode (network '%s')"), @@ -1478,6 +1559,12 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags) } virBufferAddLit(&buf, " <forward"); virBufferEscapeString(&buf, " dev='%s'", dev); + if (def->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (def->managed == 1) + virBufferAddLit(&buf, " managed='yes'"); + else + virBufferAddLit(&buf, " managed='no'"); + } virBufferAsprintf(&buf, " mode='%s'%s>\n", mode, (def->nForwardIfs || def->nForwardPfs) ? "" : "/"); @@ -1489,8 +1576,20 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags) if (def->nForwardIfs && (!def->nForwardPfs || !(flags & VIR_NETWORK_XML_INACTIVE))) { for (ii = 0; ii < def->nForwardIfs; ii++) { - virBufferEscapeString(&buf, " <interface dev='%s'/>\n", - def->forwardIfs[ii].dev); + if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) + virBufferEscapeString(&buf, " <interface dev='%s'/>\n", + def->forwardIfs[ii].device.dev); + else { + if (def->forwardIfs[ii].type == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI) { + if (virDevicePCIAddressFormat(&buf, + def->forwardIfs[ii].device.pci, + true) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("PCI address format failed")); + goto error; + } + } + } } } if (def->nForwardPfs || def->nForwardIfs) diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index a95b382..a57db36 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -36,6 +36,7 @@ # include "virnetdevbandwidth.h" # include "virnetdevvportprofile.h" # include "virmacaddr.h" +# include "device_conf.h" enum virNetworkForwardType { VIR_NETWORK_FORWARD_NONE = 0, @@ -45,10 +46,19 @@ enum virNetworkForwardType { VIR_NETWORK_FORWARD_PRIVATE, VIR_NETWORK_FORWARD_VEPA, VIR_NETWORK_FORWARD_PASSTHROUGH, + VIR_NETWORK_FORWARD_HOSTDEV, VIR_NETWORK_FORWARD_LAST, }; +enum virNetworkForwardHostdevDeviceType { + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NONE = 0, + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI, + /* USB Device to be added here when supported */ + + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST, +}; + typedef struct _virNetworkDHCPRangeDef virNetworkDHCPRangeDef; typedef virNetworkDHCPRangeDef *virNetworkDHCPRangeDefPtr; struct _virNetworkDHCPRangeDef { @@ -131,7 +141,19 @@ struct _virNetworkIpDef { typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef; typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr; struct _virNetworkForwardIfDef { - char *dev; /* name of device */ + int type; + union { + virDevicePCIAddress pci; /*PCI Address of device */ + /* when USB devices are supported a new variable to be added here */ + char *dev; /* name of device */ + }device; + int usageCount; /* how many guest interfaces are bound to this device? */ +}; + +typedef struct _virNetworkForwardPfDef virNetworkForwardPfDef; +typedef virNetworkForwardPfDef *virNetworkForwardPfDefPtr; +struct _virNetworkForwardPfDef { + char *dev; /* name of device */ int usageCount; /* how many guest interfaces are bound to this device? */ }; @@ -159,12 +181,13 @@ struct _virNetworkDef { bool mac_specified; int forwardType; /* One of virNetworkForwardType constants */ + int managed; /* managed attribute for hostdev mode */ /* If there are multiple forward devices (i.e. a pool of * interfaces), they will be listed here. */ size_t nForwardPfs; - virNetworkForwardIfDefPtr forwardPfs; + virNetworkForwardPfDefPtr forwardPfs; size_t nForwardIfs; virNetworkForwardIfDefPtr forwardIfs; @@ -234,7 +257,7 @@ static inline const char * virNetworkDefForwardIf(const virNetworkDefPtr def, size_t n) { return ((def->forwardIfs && (def->nForwardIfs > n)) - ? def->forwardIfs[n].dev : NULL); + ? def->forwardIfs[n].device.dev : NULL); } virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net, diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index f128bd0..df3cc25 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2762,8 +2762,8 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { netdef->nForwardIfs = num_virt_fns; for (ii = 0; ii < netdef->nForwardIfs; ii++) { - netdef->forwardIfs[ii].dev = strdup(vfname[ii]); - if (!netdef->forwardIfs[ii].dev) { + netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); + if (!netdef->forwardIfs[ii].device.dev) { virReportOOMError(); goto finish; } @@ -2985,7 +2985,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) netdef->name); goto cleanup; } - iface->data.network.actual->data.direct.linkdev = strdup(dev->dev); + iface->data.network.actual->data.direct.linkdev = strdup(dev->device.dev); if (!iface->data.network.actual->data.direct.linkdev) { virReportOOMError(); goto cleanup; @@ -2993,7 +2993,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) /* we are now assured of success, so mark the allocation */ dev->usageCount++; VIR_DEBUG("Using physical device %s, usageCount %d", - dev->dev, dev->usageCount); + dev->device.dev, dev->usageCount); } } @@ -3068,7 +3068,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) /* find the matching interface in the pool and increment its usageCount */ for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { dev = &netdef->forwardIfs[ii]; break; } @@ -3099,7 +3099,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) /* we are now assured of success, so mark the allocation */ dev->usageCount++; VIR_DEBUG("Using physical device %s, usageCount %d", - dev->dev, dev->usageCount); + dev->device.dev, dev->usageCount); } ret = 0; @@ -3169,7 +3169,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) virNetworkForwardIfDefPtr dev = NULL; for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { dev = &netdef->forwardIfs[ii]; break; } @@ -3184,7 +3184,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) dev->usageCount--; VIR_DEBUG("Releasing physical device %s, usageCount %d", - dev->dev, dev->usageCount); + dev->device.dev, dev->usageCount); } ret = 0; @@ -3265,7 +3265,7 @@ networkGetNetworkAddress(const char *netname, char **netaddr) case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: if ((netdef->nForwardIfs > 0) && netdef->forwardIfs) - dev_name = netdef->forwardIfs[0].dev; + dev_name = netdef->forwardIfs[0].device.dev; if (!dev_name) { virReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/tests/networkxml2xmlin/hostdev-pf.xml b/tests/networkxml2xmlin/hostdev-pf.xml new file mode 100644 index 0000000..e07db69 --- /dev/null +++ b/tests/networkxml2xmlin/hostdev-pf.xml @@ -0,0 +1,11 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <pf dev='eth2'/> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmlin/hostdev.xml b/tests/networkxml2xmlin/hostdev.xml new file mode 100644 index 0000000..0ec52d2 --- /dev/null +++ b/tests/networkxml2xmlin/hostdev.xml @@ -0,0 +1,10 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmlout/hostdev-pf.xml b/tests/networkxml2xmlout/hostdev-pf.xml new file mode 100644 index 0000000..e955312 --- /dev/null +++ b/tests/networkxml2xmlout/hostdev-pf.xml @@ -0,0 +1,7 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <pf dev='eth2'/> + </forward> +</network> diff --git a/tests/networkxml2xmlout/hostdev.xml b/tests/networkxml2xmlout/hostdev.xml new file mode 100644 index 0000000..0ec52d2 --- /dev/null +++ b/tests/networkxml2xmlout/hostdev.xml @@ -0,0 +1,10 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index 8641c41..c9c8311 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -105,6 +105,8 @@ mymain(void) DO_TEST("vepa-net"); DO_TEST("bandwidth-network"); DO_TEST_FULL("passthrough-pf", VIR_NETWORK_XML_INACTIVE); + DO_TEST("hostdev"); + DO_TEST_FULL("hostdev-pf", VIR_NETWORK_XML_INACTIVE); return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.7.4.4

On 08/10/2012 12:23 PM, Shradha Shah wrote:
This patch introduces the new forward mode='hostdev' along with attribute managed Includes updates to the network RNG and new xml parser/formatter code.
This one still needs some tweaks. See below...
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- docs/schemas/network.rng | 82 +++++++++++++++++++-- src/conf/network_conf.c | 127 ++++++++++++++++++++++++++++---- src/conf/network_conf.h | 29 +++++++- src/network/bridge_driver.c | 18 ++-- tests/networkxml2xmlin/hostdev-pf.xml | 11 +++ tests/networkxml2xmlin/hostdev.xml | 10 +++ tests/networkxml2xmlout/hostdev-pf.xml | 7 ++ tests/networkxml2xmlout/hostdev.xml | 10 +++ tests/networkxml2xmltest.c | 2 + 9 files changed, 263 insertions(+), 33 deletions(-)
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 2ae879e..d1297cd 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -82,17 +82,41 @@ <value>passthrough</value> <value>private</value> <value>vepa</value> + <value>hostdev</value> + </choice> + </attribute> + </optional> + + <optional> + <attribute name="managed"> + <choice> + <value>yes</value> + <value>no</value> </choice> </attribute> </optional> <interleave> - <zeroOrMore> - <element name='interface'> - <attribute name='dev'> - <ref name='deviceName'/> - </attribute> - </element> - </zeroOrMore> + <choice> + <group> + <zeroOrMore> + <element name='interface'> + <attribute name='dev'> + <ref name='deviceName'/> + </attribute> + </element> + </zeroOrMore> + </group> + <group> + <zeroOrMore> + <element name='address'> + <attribute name='type'> + <value>pci</value> + </attribute> + <ref name="pciaddress"/> + </element> + </zeroOrMore> + </group> + </choice> <optional> <element name='pf'> <attribute name='dev'> @@ -238,4 +262,48 @@ </interleave> </element> </define> + <define name="pciaddress">
I'm kind of surprised there isn't already a pci address type in the rng... Oh, *now* I see - there is already a pciaddress type, but it's defined in domaincommon.rng, and you need to use it in network.rng. Rather than defining the whole thing twice, you should either move the definition to basictypes.rng or (if anyone objects to something that complex going into a file that has "basic" in the name) to a new file - devicetypes.rng or something like that. (This is analogous to the split of the pci device data and functions into device_conf.[ch]).
+ <optional> + <attribute name="domain"> + <ref name="pciDomain"/> + </attribute> + </optional> + <attribute name="bus"> + <ref name="pciBus"/> + </attribute> + <attribute name="slot"> + <ref name="pciSlot"/> + </attribute> + <attribute name="function"> + <ref name="pciFunc"/> + </attribute> + <optional> + <attribute name="multifunction"> + <choice> + <value>on</value> + <value>off</value> + </choice> + </attribute> + </optional> + </define> + <define name="pciDomain"> + <data type="string"> + <param name="pattern">(0x)?[0-9a-fA-F]{1,4}</param> + </data> + </define> + <define name="pciBus"> + <data type="string"> + <param name="pattern">(0x)?[0-9a-fA-F]{1,2}</param> + </data> + </define> + <define name="pciSlot"> + <data type="string"> + <param name="pattern">(0x)?[0-1]?[0-9a-fA-F]</param> + </data> + </define> + <define name="pciFunc"> + <data type="string"> + <param name="pattern">(0x)?[0-7]</param> + </data> + </define>
Yeah, basically everything from here up to my previous comment is the same here and in domaincommon.rng - definitely move it. (put it it basictypes.rng until/unless someone objects :-)
</grammar> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index a3714d9..294939d 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -49,7 +49,12 @@
VIR_ENUM_IMPL(virNetworkForward, VIR_NETWORK_FORWARD_LAST, - "none", "nat", "route", "bridge", "private", "vepa", "passthrough" ) + "none", "nat", "route", "bridge", "private", "vepa", "passthrough", "hostdev") + +VIR_ENUM_DECL(virNetworkForwardHostdevDevice) +VIR_ENUM_IMPL(virNetworkForwardHostdevDevice, + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST, + "none", "pci")
virNetworkObjPtr virNetworkFindByUUID(const virNetworkObjListPtr nets, const unsigned char *uuid) @@ -94,6 +99,12 @@ virPortGroupDefClear(virPortGroupDefPtr def) static void virNetworkForwardIfDefClear(virNetworkForwardIfDefPtr def) { + VIR_FREE(def->device.dev); +} + +static void +virNetworkForwardPfDefClear(virNetworkForwardPfDefPtr def) +{ VIR_FREE(def->dev); }
Ah, I see you encountered a practical reason for something that I recently did just because the old way looked wrong - creating a separate type for for ForwardPf. Depending on whose patches get pushed first, there will be a conflict. We should probably push yours first, since they have a concrete reason for the change.
@@ -157,12 +168,13 @@ void virNetworkDefFree(virNetworkDefPtr def) VIR_FREE(def->domain);
for (ii = 0 ; ii < def->nForwardPfs && def->forwardPfs ; ii++) { - virNetworkForwardIfDefClear(&def->forwardPfs[ii]); + virNetworkForwardPfDefClear(&def->forwardPfs[ii]); } VIR_FREE(def->forwardPfs);
for (ii = 0 ; ii < def->nForwardIfs && def->forwardIfs ; ii++) { - virNetworkForwardIfDefClear(&def->forwardIfs[ii]); + if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) + virNetworkForwardIfDefClear(&def->forwardIfs[ii]);
Don't put the "if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) here. It looks like there is a "type" field in the forwardIf now, so let virNetworkForwardIfDefClear decide for itself if it needs to clear anything.,
} VIR_FREE(def->forwardIfs);
@@ -929,11 +941,14 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) xmlNodePtr *portGroupNodes = NULL; xmlNodePtr *forwardIfNodes = NULL; xmlNodePtr *forwardPfNodes = NULL; + xmlNodePtr *forwardAddrNodes = NULL; xmlNodePtr dnsNode = NULL; xmlNodePtr virtPortNode = NULL; xmlNodePtr forwardNode = NULL; - int nIps, nPortGroups, nForwardIfs, nForwardPfs; + int nIps, nPortGroups, nForwardIfs, nForwardPfs, nForwardAddrs; char *forwardDev = NULL; + char *forwardManaged = NULL; + char *type = NULL; xmlNodePtr save = ctxt->node; xmlNodePtr bandwidthNode = NULL;
@@ -1079,17 +1094,30 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) }
forwardDev = virXPathString("string(./@dev)", ctxt); + forwardManaged = virXPathString("string(./@managed)", ctxt); + if(forwardManaged != NULL) { + if (STREQ(forwardManaged, "yes"))
Use STRCASEEQ just to allow for the unlikely case that someone will enter "Yes" or "YES".
+ def->managed = 1; + else + def->managed = 0;
Everything allocated with VIR_ALLOC is initialized to 0 - you don't need the else part of this.
+ }
/* all of these modes can use a pool of physical interfaces */ nForwardIfs = virXPathNodeSet("./interface", ctxt, &forwardIfNodes); nForwardPfs = virXPathNodeSet("./pf", ctxt, &forwardPfNodes); + nForwardAddrs = virXPathNodeSet("./address", ctxt, &forwardAddrNodes);
- if (nForwardIfs < 0 || nForwardPfs < 0) { + if (nForwardIfs < 0 || nForwardPfs < 0 || nForwardAddrs < 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("No interface pool or SRIOV physical device given")); goto error; }
+ if ((nForwardIfs > 0) && (nForwardAddrs > 0)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Address and interface attributes are mutually exclusive")); + } +
Well, we *could* allow that, but I guess that would mean we would then need to check for two entries pointing at the same hardware (and I doubt anyone will ever want to do it anyway :-)
if (nForwardPfs == 1) { if (VIR_ALLOC_N(def->forwardPfs, nForwardPfs) < 0) { virReportOOMError(); @@ -1119,7 +1147,55 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) _("Use of more than one physical interface is not allowed")); goto error; } - if (nForwardIfs > 0 || forwardDev) { + if (nForwardAddrs > 0) { + int ii; + + if (VIR_ALLOC_N(def->forwardIfs, nForwardAddrs) < 0) { + virReportOOMError(); + goto error; + } + + if (forwardDev) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("A forward Dev should not be used when using address attribute")); + goto error; + }
Okay. That makes sense.
+ + for (ii = 0; ii < nForwardAddrs; ii++) { + type = virXMLPropString(*forwardAddrNodes, "type");
You should be using "forwardAddrNodes[ii]" rather than *forwardAddrNodes, otherwise you're going to be getting all nForwardAddrs of device data from the first address element, rather than each being from a different one. (I think you did a cut-paste from the PF parsing bit, which only allows a single element).
+ + if (type) { + if ((def->forwardIfs[ii].type = virNetworkForwardHostdevDeviceTypeFromString(type)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown address type '%s'"), type); + goto error; + } + } else { + virReportError(VIR_ERR_XML_ERROR, + "%s", _("No type specified for device address")); + goto error; + } + + switch (def->forwardIfs[ii].type) { + case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: + if (virDevicePCIAddressParseXML(*forwardAddrNodes, &(def->forwardIfs[ii].device.pci)) < 0)
Here also you need to use forwardAddrNodes[ii] instead of *forwardAddrNodes.
+ goto error; + break; + + /* Add USB case here */ + + default: + virReportError(VIR_ERR_XML_ERROR, + _("unknown address type '%s'"), type); + goto error; + } + + def->forwardIfs[ii].usageCount = 0; + type = NULL;
This leaks the string pointed to by type. Instead you need to VIR_FREE(type);
+ def->nForwardIfs++; + } + } + else if (nForwardIfs > 0 || forwardDev) { int ii;
/* allocate array to hold all the portgroups */ @@ -1130,7 +1206,8 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
if (forwardDev) { def->forwardIfs[0].usageCount = 0; - def->forwardIfs[0].dev = forwardDev; + def->forwardIfs[0].device.dev = forwardDev; + def->forwardIfs[0].type = 0; forwardDev = NULL; def->nForwardIfs++; } @@ -1148,10 +1225,10 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) if ((ii == 0) && (def->nForwardIfs == 1)) { /* both forwardDev and an interface element are present. * If they don't match, it's an error. */ - if (STRNEQ(forwardDev, def->forwardIfs[0].dev)) { - virReportError(VIR_ERR_XML_ERROR, + if (STRNEQ(forwardDev, def->forwardIfs[0].device.dev)) { + virReportError(VIR_ERR_XML_ERROR, _("forward dev '%s' must match first interface element dev '%s' in network '%s'"), - def->forwardIfs[0].dev, + def->forwardIfs[0].device.dev, forwardDev, def->name); goto error; } @@ -1159,16 +1236,19 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) continue; }
- def->forwardIfs[ii].dev = forwardDev; + def->forwardIfs[ii].device.dev = forwardDev; forwardDev = NULL; def->forwardIfs[ii].usageCount = 0; + def->forwardIfs[ii].type = 0;
Instead of setting this to 0, add a new value VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV to the enum.
def->nForwardIfs++; } } + VIR_FREE(type); VIR_FREE(forwardDev); + VIR_FREE(forwardManaged); VIR_FREE(forwardPfNodes); VIR_FREE(forwardIfNodes); - + VIR_FREE(forwardAddrNodes); switch (def->forwardType) { case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_NAT: @@ -1193,6 +1273,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: + case VIR_NETWORK_FORWARD_HOSTDEV: if (def->bridge) { virReportError(VIR_ERR_XML_ERROR, _("bridge name not allowed in %s mode (network '%s')"), @@ -1478,6 +1559,12 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags) } virBufferAddLit(&buf, " <forward"); virBufferEscapeString(&buf, " dev='%s'", dev); + if (def->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (def->managed == 1) + virBufferAddLit(&buf, " managed='yes'"); + else + virBufferAddLit(&buf, " managed='no'"); + } virBufferAsprintf(&buf, " mode='%s'%s>\n", mode, (def->nForwardIfs || def->nForwardPfs) ? "" : "/");
@@ -1489,8 +1576,20 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags) if (def->nForwardIfs && (!def->nForwardPfs || !(flags & VIR_NETWORK_XML_INACTIVE))) { for (ii = 0; ii < def->nForwardIfs; ii++) { - virBufferEscapeString(&buf, " <interface dev='%s'/>\n", - def->forwardIfs[ii].dev); + if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) + virBufferEscapeString(&buf, " <interface dev='%s'/>\n", + def->forwardIfs[ii].device.dev); + else { + if (def->forwardIfs[ii].type == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI) { + if (virDevicePCIAddressFormat(&buf, + def->forwardIfs[ii].device.pci, + true) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("PCI address format failed"));
Although virDevicePCIAddressFormat() currently always succeeds, other formatting functions that fail will log their own error message before returning. So, in this case you should just goto error, without logging any extra message.
+ goto error; + } + } + } } } if (def->nForwardPfs || def->nForwardIfs) diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index a95b382..a57db36 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -36,6 +36,7 @@ # include "virnetdevbandwidth.h" # include "virnetdevvportprofile.h" # include "virmacaddr.h" +# include "device_conf.h"
enum virNetworkForwardType { VIR_NETWORK_FORWARD_NONE = 0, @@ -45,10 +46,19 @@ enum virNetworkForwardType { VIR_NETWORK_FORWARD_PRIVATE, VIR_NETWORK_FORWARD_VEPA, VIR_NETWORK_FORWARD_PASSTHROUGH, + VIR_NETWORK_FORWARD_HOSTDEV,
VIR_NETWORK_FORWARD_LAST, };
+enum virNetworkForwardHostdevDeviceType { + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NONE = 0, + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI,
As I mentioned above, add a VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV here.
+ /* USB Device to be added here when supported */ + + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST, +}; + typedef struct _virNetworkDHCPRangeDef virNetworkDHCPRangeDef; typedef virNetworkDHCPRangeDef *virNetworkDHCPRangeDefPtr; struct _virNetworkDHCPRangeDef { @@ -131,7 +141,19 @@ struct _virNetworkIpDef { typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef; typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr; struct _virNetworkForwardIfDef { - char *dev; /* name of device */ + int type; + union { + virDevicePCIAddress pci; /*PCI Address of device */ + /* when USB devices are supported a new variable to be added here */ + char *dev; /* name of device */ + }device; + int usageCount; /* how many guest interfaces are bound to this device? */ +}; + +typedef struct _virNetworkForwardPfDef virNetworkForwardPfDef; +typedef virNetworkForwardPfDef *virNetworkForwardPfDefPtr; +struct _virNetworkForwardPfDef { + char *dev; /* name of device */ int usageCount; /* how many guest interfaces are bound to this device? */ };
@@ -159,12 +181,13 @@ struct _virNetworkDef { bool mac_specified;
int forwardType; /* One of virNetworkForwardType constants */ + int managed; /* managed attribute for hostdev mode */
/* If there are multiple forward devices (i.e. a pool of * interfaces), they will be listed here. */ size_t nForwardPfs; - virNetworkForwardIfDefPtr forwardPfs; + virNetworkForwardPfDefPtr forwardPfs;
size_t nForwardIfs; virNetworkForwardIfDefPtr forwardIfs; @@ -234,7 +257,7 @@ static inline const char * virNetworkDefForwardIf(const virNetworkDefPtr def, size_t n) { return ((def->forwardIfs && (def->nForwardIfs > n)) - ? def->forwardIfs[n].dev : NULL); + ? def->forwardIfs[n].device.dev : NULL); }
virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net, diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index f128bd0..df3cc25 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2762,8 +2762,8 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { netdef->nForwardIfs = num_virt_fns;
for (ii = 0; ii < netdef->nForwardIfs; ii++) { - netdef->forwardIfs[ii].dev = strdup(vfname[ii]); - if (!netdef->forwardIfs[ii].dev) { + netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); + if (!netdef->forwardIfs[ii].device.dev) { virReportOOMError(); goto finish; } @@ -2985,7 +2985,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) netdef->name); goto cleanup; } - iface->data.network.actual->data.direct.linkdev = strdup(dev->dev); + iface->data.network.actual->data.direct.linkdev = strdup(dev->device.dev); if (!iface->data.network.actual->data.direct.linkdev) { virReportOOMError(); goto cleanup; @@ -2993,7 +2993,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) /* we are now assured of success, so mark the allocation */ dev->usageCount++; VIR_DEBUG("Using physical device %s, usageCount %d", - dev->dev, dev->usageCount); + dev->device.dev, dev->usageCount); } }
@@ -3068,7 +3068,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) /* find the matching interface in the pool and increment its usageCount */
for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { dev = &netdef->forwardIfs[ii]; break; } @@ -3099,7 +3099,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) /* we are now assured of success, so mark the allocation */ dev->usageCount++; VIR_DEBUG("Using physical device %s, usageCount %d", - dev->dev, dev->usageCount); + dev->device.dev, dev->usageCount); }
ret = 0; @@ -3169,7 +3169,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) virNetworkForwardIfDefPtr dev = NULL;
for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { dev = &netdef->forwardIfs[ii]; break; } @@ -3184,7 +3184,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface)
dev->usageCount--; VIR_DEBUG("Releasing physical device %s, usageCount %d", - dev->dev, dev->usageCount); + dev->device.dev, dev->usageCount); }
ret = 0; @@ -3265,7 +3265,7 @@ networkGetNetworkAddress(const char *netname, char **netaddr) case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: if ((netdef->nForwardIfs > 0) && netdef->forwardIfs) - dev_name = netdef->forwardIfs[0].dev; + dev_name = netdef->forwardIfs[0].device.dev;
if (!dev_name) { virReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/tests/networkxml2xmlin/hostdev-pf.xml b/tests/networkxml2xmlin/hostdev-pf.xml new file mode 100644 index 0000000..e07db69 --- /dev/null +++ b/tests/networkxml2xmlin/hostdev-pf.xml @@ -0,0 +1,11 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <pf dev='eth2'/> + <address type='pci' domain='0' bus='3' slot='0' function='1'/>
Is it legal to have a pf using a netdev name along with a list of pci devices? I thought it was either/or?
+ <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmlin/hostdev.xml b/tests/networkxml2xmlin/hostdev.xml new file mode 100644 index 0000000..0ec52d2 --- /dev/null +++ b/tests/networkxml2xmlin/hostdev.xml @@ -0,0 +1,10 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmlout/hostdev-pf.xml b/tests/networkxml2xmlout/hostdev-pf.xml new file mode 100644 index 0000000..e955312 --- /dev/null +++ b/tests/networkxml2xmlout/hostdev-pf.xml @@ -0,0 +1,7 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <pf dev='eth2'/>
Wait, so it's legal to do it, but the <address> elements are all tossed? That doesn't seem good.
+ </forward> +</network> diff --git a/tests/networkxml2xmlout/hostdev.xml b/tests/networkxml2xmlout/hostdev.xml new file mode 100644 index 0000000..0ec52d2 --- /dev/null +++ b/tests/networkxml2xmlout/hostdev.xml @@ -0,0 +1,10 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index 8641c41..c9c8311 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -105,6 +105,8 @@ mymain(void) DO_TEST("vepa-net"); DO_TEST("bandwidth-network"); DO_TEST_FULL("passthrough-pf", VIR_NETWORK_XML_INACTIVE); + DO_TEST("hostdev"); + DO_TEST_FULL("hostdev-pf", VIR_NETWORK_XML_INACTIVE);
return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; }

On 08/13/2012 11:27 PM, Laine Stump wrote:
On 08/10/2012 12:23 PM, Shradha Shah wrote:
This patch introduces the new forward mode='hostdev' along with attribute managed Includes updates to the network RNG and new xml parser/formatter code.
This one still needs some tweaks. See below...
Yeah, basically everything from here up to my previous comment is the same here and in domaincommon.rng - definitely move it. (put it it basictypes.rng until/unless someone objects :-)
No objection from me for using basictypes.rng. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 08/14/2012 06:27 AM, Laine Stump wrote:
On 08/10/2012 12:23 PM, Shradha Shah wrote:
This patch introduces the new forward mode='hostdev' along with attribute managed Includes updates to the network RNG and new xml parser/formatter code.
This one still needs some tweaks. See below...
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- docs/schemas/network.rng | 82 +++++++++++++++++++-- src/conf/network_conf.c | 127 ++++++++++++++++++++++++++++---- src/conf/network_conf.h | 29 +++++++- src/network/bridge_driver.c | 18 ++-- tests/networkxml2xmlin/hostdev-pf.xml | 11 +++ tests/networkxml2xmlin/hostdev.xml | 10 +++ tests/networkxml2xmlout/hostdev-pf.xml | 7 ++ tests/networkxml2xmlout/hostdev.xml | 10 +++ tests/networkxml2xmltest.c | 2 + 9 files changed, 263 insertions(+), 33 deletions(-)
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 2ae879e..d1297cd 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -82,17 +82,41 @@ <value>passthrough</value> <value>private</value> <value>vepa</value> + <value>hostdev</value> + </choice> + </attribute> + </optional> + + <optional> + <attribute name="managed"> + <choice> + <value>yes</value> + <value>no</value> </choice> </attribute> </optional> <interleave> - <zeroOrMore> - <element name='interface'> - <attribute name='dev'> - <ref name='deviceName'/> - </attribute> - </element> - </zeroOrMore> + <choice> + <group> + <zeroOrMore> + <element name='interface'> + <attribute name='dev'> + <ref name='deviceName'/> + </attribute> + </element> + </zeroOrMore> + </group> + <group> + <zeroOrMore> + <element name='address'> + <attribute name='type'> + <value>pci</value> + </attribute> + <ref name="pciaddress"/> + </element> + </zeroOrMore> + </group> + </choice> <optional> <element name='pf'> <attribute name='dev'> @@ -238,4 +262,48 @@ </interleave> </element> </define> + <define name="pciaddress">
I'm kind of surprised there isn't already a pci address type in the rng...
Oh, *now* I see - there is already a pciaddress type, but it's defined in domaincommon.rng, and you need to use it in network.rng.
Rather than defining the whole thing twice, you should either move the definition to basictypes.rng or (if anyone objects to something that complex going into a file that has "basic" in the name) to a new file - devicetypes.rng or something like that. (This is analogous to the split of the pci device data and functions into device_conf.[ch]).
+ <optional> + <attribute name="domain"> + <ref name="pciDomain"/> + </attribute> + </optional> + <attribute name="bus"> + <ref name="pciBus"/> + </attribute> + <attribute name="slot"> + <ref name="pciSlot"/> + </attribute> + <attribute name="function"> + <ref name="pciFunc"/> + </attribute> + <optional> + <attribute name="multifunction"> + <choice> + <value>on</value> + <value>off</value> + </choice> + </attribute> + </optional> + </define> + <define name="pciDomain"> + <data type="string"> + <param name="pattern">(0x)?[0-9a-fA-F]{1,4}</param> + </data> + </define> + <define name="pciBus"> + <data type="string"> + <param name="pattern">(0x)?[0-9a-fA-F]{1,2}</param> + </data> + </define> + <define name="pciSlot"> + <data type="string"> + <param name="pattern">(0x)?[0-1]?[0-9a-fA-F]</param> + </data> + </define> + <define name="pciFunc"> + <data type="string"> + <param name="pattern">(0x)?[0-7]</param> + </data> + </define>
Yeah, basically everything from here up to my previous comment is the same here and in domaincommon.rng - definitely move it. (put it it basictypes.rng until/unless someone objects :-)
</grammar> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index a3714d9..294939d 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -49,7 +49,12 @@
VIR_ENUM_IMPL(virNetworkForward, VIR_NETWORK_FORWARD_LAST, - "none", "nat", "route", "bridge", "private", "vepa", "passthrough" ) + "none", "nat", "route", "bridge", "private", "vepa", "passthrough", "hostdev") + +VIR_ENUM_DECL(virNetworkForwardHostdevDevice) +VIR_ENUM_IMPL(virNetworkForwardHostdevDevice, + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST, + "none", "pci")
virNetworkObjPtr virNetworkFindByUUID(const virNetworkObjListPtr nets, const unsigned char *uuid) @@ -94,6 +99,12 @@ virPortGroupDefClear(virPortGroupDefPtr def) static void virNetworkForwardIfDefClear(virNetworkForwardIfDefPtr def) { + VIR_FREE(def->device.dev); +} + +static void +virNetworkForwardPfDefClear(virNetworkForwardPfDefPtr def) +{ VIR_FREE(def->dev); }
Ah, I see you encountered a practical reason for something that I recently did just because the old way looked wrong - creating a separate type for for ForwardPf. Depending on whose patches get pushed first, there will be a conflict. We should probably push yours first, since they have a concrete reason for the change.
@@ -157,12 +168,13 @@ void virNetworkDefFree(virNetworkDefPtr def) VIR_FREE(def->domain);
for (ii = 0 ; ii < def->nForwardPfs && def->forwardPfs ; ii++) { - virNetworkForwardIfDefClear(&def->forwardPfs[ii]); + virNetworkForwardPfDefClear(&def->forwardPfs[ii]); } VIR_FREE(def->forwardPfs);
for (ii = 0 ; ii < def->nForwardIfs && def->forwardIfs ; ii++) { - virNetworkForwardIfDefClear(&def->forwardIfs[ii]); + if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) + virNetworkForwardIfDefClear(&def->forwardIfs[ii]);
Don't put the "if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) here. It looks like there is a "type" field in the forwardIf now, so let virNetworkForwardIfDefClear decide for itself if it needs to clear anything.,
} VIR_FREE(def->forwardIfs);
@@ -929,11 +941,14 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) xmlNodePtr *portGroupNodes = NULL; xmlNodePtr *forwardIfNodes = NULL; xmlNodePtr *forwardPfNodes = NULL; + xmlNodePtr *forwardAddrNodes = NULL; xmlNodePtr dnsNode = NULL; xmlNodePtr virtPortNode = NULL; xmlNodePtr forwardNode = NULL; - int nIps, nPortGroups, nForwardIfs, nForwardPfs; + int nIps, nPortGroups, nForwardIfs, nForwardPfs, nForwardAddrs; char *forwardDev = NULL; + char *forwardManaged = NULL; + char *type = NULL; xmlNodePtr save = ctxt->node; xmlNodePtr bandwidthNode = NULL;
@@ -1079,17 +1094,30 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) }
forwardDev = virXPathString("string(./@dev)", ctxt); + forwardManaged = virXPathString("string(./@managed)", ctxt); + if(forwardManaged != NULL) { + if (STREQ(forwardManaged, "yes"))
Use STRCASEEQ just to allow for the unlikely case that someone will enter "Yes" or "YES".
+ def->managed = 1; + else + def->managed = 0;
Everything allocated with VIR_ALLOC is initialized to 0 - you don't need the else part of this.
+ }
/* all of these modes can use a pool of physical interfaces */ nForwardIfs = virXPathNodeSet("./interface", ctxt, &forwardIfNodes); nForwardPfs = virXPathNodeSet("./pf", ctxt, &forwardPfNodes); + nForwardAddrs = virXPathNodeSet("./address", ctxt, &forwardAddrNodes);
- if (nForwardIfs < 0 || nForwardPfs < 0) { + if (nForwardIfs < 0 || nForwardPfs < 0 || nForwardAddrs < 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("No interface pool or SRIOV physical device given")); goto error; }
+ if ((nForwardIfs > 0) && (nForwardAddrs > 0)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Address and interface attributes are mutually exclusive")); + } +
Well, we *could* allow that, but I guess that would mean we would then need to check for two entries pointing at the same hardware (and I doubt anyone will ever want to do it anyway :-)
if (nForwardPfs == 1) { if (VIR_ALLOC_N(def->forwardPfs, nForwardPfs) < 0) { virReportOOMError(); @@ -1119,7 +1147,55 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) _("Use of more than one physical interface is not allowed")); goto error; } - if (nForwardIfs > 0 || forwardDev) { + if (nForwardAddrs > 0) { + int ii; + + if (VIR_ALLOC_N(def->forwardIfs, nForwardAddrs) < 0) { + virReportOOMError(); + goto error; + } + + if (forwardDev) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("A forward Dev should not be used when using address attribute")); + goto error; + }
Okay. That makes sense.
+ + for (ii = 0; ii < nForwardAddrs; ii++) { + type = virXMLPropString(*forwardAddrNodes, "type");
You should be using "forwardAddrNodes[ii]" rather than *forwardAddrNodes, otherwise you're going to be getting all nForwardAddrs of device data from the first address element, rather than each being from a different one. (I think you did a cut-paste from the PF parsing bit, which only allows a single element).
+ + if (type) { + if ((def->forwardIfs[ii].type = virNetworkForwardHostdevDeviceTypeFromString(type)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown address type '%s'"), type); + goto error; + } + } else { + virReportError(VIR_ERR_XML_ERROR, + "%s", _("No type specified for device address")); + goto error; + } + + switch (def->forwardIfs[ii].type) { + case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: + if (virDevicePCIAddressParseXML(*forwardAddrNodes, &(def->forwardIfs[ii].device.pci)) < 0)
Here also you need to use forwardAddrNodes[ii] instead of *forwardAddrNodes.
+ goto error; + break; + + /* Add USB case here */ + + default: + virReportError(VIR_ERR_XML_ERROR, + _("unknown address type '%s'"), type); + goto error; + } + + def->forwardIfs[ii].usageCount = 0; + type = NULL;
This leaks the string pointed to by type. Instead you need to VIR_FREE(type);
+ def->nForwardIfs++; + } + } + else if (nForwardIfs > 0 || forwardDev) { int ii;
/* allocate array to hold all the portgroups */ @@ -1130,7 +1206,8 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
if (forwardDev) { def->forwardIfs[0].usageCount = 0; - def->forwardIfs[0].dev = forwardDev; + def->forwardIfs[0].device.dev = forwardDev; + def->forwardIfs[0].type = 0; forwardDev = NULL; def->nForwardIfs++; } @@ -1148,10 +1225,10 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) if ((ii == 0) && (def->nForwardIfs == 1)) { /* both forwardDev and an interface element are present. * If they don't match, it's an error. */ - if (STRNEQ(forwardDev, def->forwardIfs[0].dev)) { - virReportError(VIR_ERR_XML_ERROR, + if (STRNEQ(forwardDev, def->forwardIfs[0].device.dev)) { + virReportError(VIR_ERR_XML_ERROR, _("forward dev '%s' must match first interface element dev '%s' in network '%s'"), - def->forwardIfs[0].dev, + def->forwardIfs[0].device.dev, forwardDev, def->name); goto error; } @@ -1159,16 +1236,19 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) continue; }
- def->forwardIfs[ii].dev = forwardDev; + def->forwardIfs[ii].device.dev = forwardDev; forwardDev = NULL; def->forwardIfs[ii].usageCount = 0; + def->forwardIfs[ii].type = 0;
Instead of setting this to 0, add a new value VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV to the enum.
def->nForwardIfs++; } } + VIR_FREE(type); VIR_FREE(forwardDev); + VIR_FREE(forwardManaged); VIR_FREE(forwardPfNodes); VIR_FREE(forwardIfNodes); - + VIR_FREE(forwardAddrNodes); switch (def->forwardType) { case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_NAT: @@ -1193,6 +1273,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: + case VIR_NETWORK_FORWARD_HOSTDEV: if (def->bridge) { virReportError(VIR_ERR_XML_ERROR, _("bridge name not allowed in %s mode (network '%s')"), @@ -1478,6 +1559,12 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags) } virBufferAddLit(&buf, " <forward"); virBufferEscapeString(&buf, " dev='%s'", dev); + if (def->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (def->managed == 1) + virBufferAddLit(&buf, " managed='yes'"); + else + virBufferAddLit(&buf, " managed='no'"); + } virBufferAsprintf(&buf, " mode='%s'%s>\n", mode, (def->nForwardIfs || def->nForwardPfs) ? "" : "/");
@@ -1489,8 +1576,20 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags) if (def->nForwardIfs && (!def->nForwardPfs || !(flags & VIR_NETWORK_XML_INACTIVE))) { for (ii = 0; ii < def->nForwardIfs; ii++) { - virBufferEscapeString(&buf, " <interface dev='%s'/>\n", - def->forwardIfs[ii].dev); + if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) + virBufferEscapeString(&buf, " <interface dev='%s'/>\n", + def->forwardIfs[ii].device.dev); + else { + if (def->forwardIfs[ii].type == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI) { + if (virDevicePCIAddressFormat(&buf, + def->forwardIfs[ii].device.pci, + true) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("PCI address format failed"));
Although virDevicePCIAddressFormat() currently always succeeds, other formatting functions that fail will log their own error message before returning. So, in this case you should just goto error, without logging any extra message.
+ goto error; + } + } + } } } if (def->nForwardPfs || def->nForwardIfs) diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index a95b382..a57db36 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -36,6 +36,7 @@ # include "virnetdevbandwidth.h" # include "virnetdevvportprofile.h" # include "virmacaddr.h" +# include "device_conf.h"
enum virNetworkForwardType { VIR_NETWORK_FORWARD_NONE = 0, @@ -45,10 +46,19 @@ enum virNetworkForwardType { VIR_NETWORK_FORWARD_PRIVATE, VIR_NETWORK_FORWARD_VEPA, VIR_NETWORK_FORWARD_PASSTHROUGH, + VIR_NETWORK_FORWARD_HOSTDEV,
VIR_NETWORK_FORWARD_LAST, };
+enum virNetworkForwardHostdevDeviceType { + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NONE = 0, + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI,
As I mentioned above, add a VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV here.
+ /* USB Device to be added here when supported */ + + VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST, +}; + typedef struct _virNetworkDHCPRangeDef virNetworkDHCPRangeDef; typedef virNetworkDHCPRangeDef *virNetworkDHCPRangeDefPtr; struct _virNetworkDHCPRangeDef { @@ -131,7 +141,19 @@ struct _virNetworkIpDef { typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef; typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr; struct _virNetworkForwardIfDef { - char *dev; /* name of device */ + int type; + union { + virDevicePCIAddress pci; /*PCI Address of device */ + /* when USB devices are supported a new variable to be added here */ + char *dev; /* name of device */ + }device; + int usageCount; /* how many guest interfaces are bound to this device? */ +}; + +typedef struct _virNetworkForwardPfDef virNetworkForwardPfDef; +typedef virNetworkForwardPfDef *virNetworkForwardPfDefPtr; +struct _virNetworkForwardPfDef { + char *dev; /* name of device */ int usageCount; /* how many guest interfaces are bound to this device? */ };
@@ -159,12 +181,13 @@ struct _virNetworkDef { bool mac_specified;
int forwardType; /* One of virNetworkForwardType constants */ + int managed; /* managed attribute for hostdev mode */
/* If there are multiple forward devices (i.e. a pool of * interfaces), they will be listed here. */ size_t nForwardPfs; - virNetworkForwardIfDefPtr forwardPfs; + virNetworkForwardPfDefPtr forwardPfs;
size_t nForwardIfs; virNetworkForwardIfDefPtr forwardIfs; @@ -234,7 +257,7 @@ static inline const char * virNetworkDefForwardIf(const virNetworkDefPtr def, size_t n) { return ((def->forwardIfs && (def->nForwardIfs > n)) - ? def->forwardIfs[n].dev : NULL); + ? def->forwardIfs[n].device.dev : NULL); }
virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net, diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index f128bd0..df3cc25 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2762,8 +2762,8 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { netdef->nForwardIfs = num_virt_fns;
for (ii = 0; ii < netdef->nForwardIfs; ii++) { - netdef->forwardIfs[ii].dev = strdup(vfname[ii]); - if (!netdef->forwardIfs[ii].dev) { + netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); + if (!netdef->forwardIfs[ii].device.dev) { virReportOOMError(); goto finish; } @@ -2985,7 +2985,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) netdef->name); goto cleanup; } - iface->data.network.actual->data.direct.linkdev = strdup(dev->dev); + iface->data.network.actual->data.direct.linkdev = strdup(dev->device.dev); if (!iface->data.network.actual->data.direct.linkdev) { virReportOOMError(); goto cleanup; @@ -2993,7 +2993,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) /* we are now assured of success, so mark the allocation */ dev->usageCount++; VIR_DEBUG("Using physical device %s, usageCount %d", - dev->dev, dev->usageCount); + dev->device.dev, dev->usageCount); } }
@@ -3068,7 +3068,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) /* find the matching interface in the pool and increment its usageCount */
for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { dev = &netdef->forwardIfs[ii]; break; } @@ -3099,7 +3099,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) /* we are now assured of success, so mark the allocation */ dev->usageCount++; VIR_DEBUG("Using physical device %s, usageCount %d", - dev->dev, dev->usageCount); + dev->device.dev, dev->usageCount); }
ret = 0; @@ -3169,7 +3169,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) virNetworkForwardIfDefPtr dev = NULL;
for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { dev = &netdef->forwardIfs[ii]; break; } @@ -3184,7 +3184,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface)
dev->usageCount--; VIR_DEBUG("Releasing physical device %s, usageCount %d", - dev->dev, dev->usageCount); + dev->device.dev, dev->usageCount); }
ret = 0; @@ -3265,7 +3265,7 @@ networkGetNetworkAddress(const char *netname, char **netaddr) case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: if ((netdef->nForwardIfs > 0) && netdef->forwardIfs) - dev_name = netdef->forwardIfs[0].dev; + dev_name = netdef->forwardIfs[0].device.dev;
if (!dev_name) { virReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/tests/networkxml2xmlin/hostdev-pf.xml b/tests/networkxml2xmlin/hostdev-pf.xml new file mode 100644 index 0000000..e07db69 --- /dev/null +++ b/tests/networkxml2xmlin/hostdev-pf.xml @@ -0,0 +1,11 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <pf dev='eth2'/> + <address type='pci' domain='0' bus='3' slot='0' function='1'/>
Is it legal to have a pf using a netdev name along with a list of pci devices? I thought it was either/or?
This is a test to test the inactive flag that can be used with net-dumpxml. An active network will have a pf along with the interface pool but when the inactive flag is used only the inactive part of the network xml should be formatted. Hence the address part of the xml is thrown out.
+ <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmlin/hostdev.xml b/tests/networkxml2xmlin/hostdev.xml new file mode 100644 index 0000000..0ec52d2 --- /dev/null +++ b/tests/networkxml2xmlin/hostdev.xml @@ -0,0 +1,10 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmlout/hostdev-pf.xml b/tests/networkxml2xmlout/hostdev-pf.xml new file mode 100644 index 0000000..e955312 --- /dev/null +++ b/tests/networkxml2xmlout/hostdev-pf.xml @@ -0,0 +1,7 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <pf dev='eth2'/>
Wait, so it's legal to do it, but the <address> elements are all tossed? That doesn't seem good.
+ </forward> +</network> diff --git a/tests/networkxml2xmlout/hostdev.xml b/tests/networkxml2xmlout/hostdev.xml new file mode 100644 index 0000000..0ec52d2 --- /dev/null +++ b/tests/networkxml2xmlout/hostdev.xml @@ -0,0 +1,10 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index 8641c41..c9c8311 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -105,6 +105,8 @@ mymain(void) DO_TEST("vepa-net"); DO_TEST("bandwidth-network"); DO_TEST_FULL("passthrough-pf", VIR_NETWORK_XML_INACTIVE); + DO_TEST("hostdev"); + DO_TEST_FULL("hostdev-pf", VIR_NETWORK_XML_INACTIVE);
return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; }
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 08/15/2012 07:25 AM, Shradha Shah wrote:
On 08/10/2012 12:23 PM, Shradha Shah wrote:
diff --git a/tests/networkxml2xmlin/hostdev-pf.xml b/tests/networkxml2xmlin/hostdev-pf.xml new file mode 100644 index 0000000..e07db69 --- /dev/null +++ b/tests/networkxml2xmlin/hostdev-pf.xml @@ -0,0 +1,11 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev" managed="yes"> + <pf dev='eth2'/> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> Is it legal to have a pf using a netdev name along with a list of pci devices? I thought it was either/or? This is a test to test the inactive flag that can be used with net-dumpxml. An active network will have a pf along with the interface pool but when the inactive flag is used only the inactive part of the network xml should be
On 08/14/2012 06:27 AM, Laine Stump wrote: formatted. Hence the address part of the xml is thrown out.
But that means if somebody mistakenly believes that they can specify (for example), one entire PF, plus several VFs of another, that config will be accepted and the VFs from the second PF will be silently discarded rather than logging an error. I think you may need to log an error rather than ignoring it.

The network pool should be able to keep track of both, network device names nad PCI addresses, and return the appropriate one in the actualDevice when networkAllocateActualDevice is called. Signed-off-by: Shradha Shah <sshah@solarflare.com> --- src/network/bridge_driver.c | 33 +++++++++++++++++++++++++++------ src/util/virnetdev.c | 25 ++++++++++++------------- src/util/virnetdev.h | 4 +++- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index df3cc25..602e17d 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -59,6 +59,7 @@ #include "dnsmasq.h" #include "configmake.h" #include "virnetdev.h" +#include "pci.h" #include "virnetdevbridge.h" #include "virnetdevtap.h" @@ -2737,10 +2738,11 @@ static int networkCreateInterfacePool(virNetworkDefPtr netdef) { unsigned int num_virt_fns = 0; char **vfname = NULL; + struct pci_config_address **virt_fns; int ret = -1, ii = 0; if ((virNetDevGetVirtualFunctions(netdef->forwardPfs->dev, - &vfname, &num_virt_fns)) < 0) { + &vfname, &virt_fns, &num_virt_fns)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not get Virtual functions on %s"), netdef->forwardPfs->dev); @@ -2762,19 +2764,38 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { netdef->nForwardIfs = num_virt_fns; for (ii = 0; ii < netdef->nForwardIfs; ii++) { - netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); - if (!netdef->forwardIfs[ii].device.dev) { - virReportOOMError(); - goto finish; + if (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) { + if(vfname[ii]) { + netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); + if (!netdef->forwardIfs[ii].device.dev) { + virReportOOMError(); + goto finish; + } + } + else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Passthrough mode requires interface names")); + goto finish; + } + } + else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + netdef->forwardIfs[ii].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI; /*Assuming PCI as VF's are PCI devices */ + netdef->forwardIfs[ii].device.pci.domain = virt_fns[ii]->domain; + netdef->forwardIfs[ii].device.pci.bus = virt_fns[ii]->bus; + netdef->forwardIfs[ii].device.pci.slot = virt_fns[ii]->slot; + netdef->forwardIfs[ii].device.pci.function = virt_fns[ii]->function; } netdef->forwardIfs[ii].usageCount = 0; } ret = 0; finish: - for (ii = 0; ii < num_virt_fns; ii++) + for (ii = 0; ii < num_virt_fns; ii++) { VIR_FREE(vfname[ii]); + VIR_FREE(virt_fns[ii]); + } VIR_FREE(vfname); + VIR_FREE(virt_fns); return ret; } diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index f1ee0a4..8103aff 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -29,6 +29,7 @@ #include "command.h" #include "memory.h" #include "pci.h" +#include "logging.h" #include <sys/ioctl.h> #ifdef HAVE_NET_IF_H @@ -981,18 +982,18 @@ virNetDevSysfsDeviceFile(char **pf_sysfs_device_link, const char *ifname, int virNetDevGetVirtualFunctions(const char *pfname, char ***vfname, + struct pci_config_address ***virt_fns, unsigned int *n_vfname) { int ret = -1, i; char *pf_sysfs_device_link = NULL; char *pci_sysfs_device_link = NULL; - struct pci_config_address **virt_fns; char *pciConfigAddr; if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0) return ret; - if (pciGetVirtualFunctions(pf_sysfs_device_link, &virt_fns, + if (pciGetVirtualFunctions(pf_sysfs_device_link, virt_fns, n_vfname) < 0) goto cleanup; @@ -1003,10 +1004,10 @@ virNetDevGetVirtualFunctions(const char *pfname, for (i = 0; i < *n_vfname; i++) { - if (pciGetDeviceAddrString(virt_fns[i]->domain, - virt_fns[i]->bus, - virt_fns[i]->slot, - virt_fns[i]->function, + if (pciGetDeviceAddrString((*virt_fns)[i]->domain, + (*virt_fns)[i]->bus, + (*virt_fns)[i]->slot, + (*virt_fns)[i]->function, &pciConfigAddr) < 0) { virReportSystemError(ENOSYS, "%s", _("Failed to get PCI Config Address String")); @@ -1019,20 +1020,17 @@ virNetDevGetVirtualFunctions(const char *pfname, } if (pciDeviceNetName(pci_sysfs_device_link, &((*vfname)[i])) < 0) { - virReportSystemError(ENOSYS, "%s", - _("Failed to get interface name of the VF")); - goto cleanup; + VIR_INFO("VF does not have an interface name"); } } ret = 0; cleanup: - if (ret < 0) + if (ret < 0) { VIR_FREE(*vfname); - for (i = 0; i < *n_vfname; i++) - VIR_FREE(virt_fns[i]); - VIR_FREE(virt_fns); + VIR_FREE(*virt_fns); + } VIR_FREE(pf_sysfs_device_link); VIR_FREE(pci_sysfs_device_link); VIR_FREE(pciConfigAddr); @@ -1169,6 +1167,7 @@ cleanup: int virNetDevGetVirtualFunctions(const char *pfname ATTRIBUTE_UNUSED, char ***vfname ATTRIBUTE_UNUSED, + struct pci_config_address ***virt_fns ATTRIBUTE_UNUSED, unsigned int *n_vfname ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, "%s", diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index c663e49..705ad9c 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -26,6 +26,7 @@ # include "virsocketaddr.h" # include "virnetlink.h" # include "virmacaddr.h" +# include "pci.h" int virNetDevExists(const char *brname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; @@ -103,9 +104,10 @@ int virNetDevGetPhysicalFunction(const char *ifname, char **pfname) int virNetDevGetVirtualFunctions(const char *pfname, char ***vfname, + struct pci_config_address ***virt_fns, unsigned int *n_vfname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) - ATTRIBUTE_RETURN_CHECK; + ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK; int virNetDevLinkDump(const char *ifname, int ifindex, struct nlattr **tb, -- 1.7.4.4

On 08/10/2012 12:23 PM, Shradha Shah wrote:
The network pool should be able to keep track of both, network device names nad PCI addresses, and return the appropriate one in the actualDevice when networkAllocateActualDevice is called.
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- src/network/bridge_driver.c | 33 +++++++++++++++++++++++++++------ src/util/virnetdev.c | 25 ++++++++++++------------- src/util/virnetdev.h | 4 +++- 3 files changed, 42 insertions(+), 20 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index df3cc25..602e17d 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -59,6 +59,7 @@ #include "dnsmasq.h" #include "configmake.h" #include "virnetdev.h" +#include "pci.h" #include "virnetdevbridge.h" #include "virnetdevtap.h"
@@ -2737,10 +2738,11 @@ static int networkCreateInterfacePool(virNetworkDefPtr netdef) { unsigned int num_virt_fns = 0; char **vfname = NULL; + struct pci_config_address **virt_fns; int ret = -1, ii = 0;
if ((virNetDevGetVirtualFunctions(netdef->forwardPfs->dev, - &vfname, &num_virt_fns)) < 0) { + &vfname, &virt_fns, &num_virt_fns)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not get Virtual functions on %s"), netdef->forwardPfs->dev); @@ -2762,19 +2764,38 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { netdef->nForwardIfs = num_virt_fns;
for (ii = 0; ii < netdef->nForwardIfs; ii++) { - netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); - if (!netdef->forwardIfs[ii].device.dev) { - virReportOOMError(); - goto finish;
To be pure in the separation of patches, the following if else should be removed from this patch, with just the contents of the "if" clause here. Then the if else + body of the else should be added in the next patch. (And at any rate, the if() condition is incorrect here - really that part should happen for all forwardTypes except HOSTDEV (BRIDGE, PRIVATE, and VEPA also require netdev names.) Aside from that movement of code to the next patch, ACK.
+ if (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) { + if(vfname[ii]) { + netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); + if (!netdef->forwardIfs[ii].device.dev) { + virReportOOMError(); + goto finish; + } + } + else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Passthrough mode requires interface names")); + goto finish; + } + } + else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + netdef->forwardIfs[ii].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI; /*Assuming PCI as VF's are PCI devices */ + netdef->forwardIfs[ii].device.pci.domain = virt_fns[ii]->domain; + netdef->forwardIfs[ii].device.pci.bus = virt_fns[ii]->bus; + netdef->forwardIfs[ii].device.pci.slot = virt_fns[ii]->slot; + netdef->forwardIfs[ii].device.pci.function = virt_fns[ii]->function; } netdef->forwardIfs[ii].usageCount = 0; }
ret = 0; finish: - for (ii = 0; ii < num_virt_fns; ii++) + for (ii = 0; ii < num_virt_fns; ii++) { VIR_FREE(vfname[ii]); + VIR_FREE(virt_fns[ii]); + } VIR_FREE(vfname); + VIR_FREE(virt_fns); return ret; }
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index f1ee0a4..8103aff 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -29,6 +29,7 @@ #include "command.h" #include "memory.h" #include "pci.h" +#include "logging.h"
#include <sys/ioctl.h> #ifdef HAVE_NET_IF_H @@ -981,18 +982,18 @@ virNetDevSysfsDeviceFile(char **pf_sysfs_device_link, const char *ifname, int virNetDevGetVirtualFunctions(const char *pfname, char ***vfname, + struct pci_config_address ***virt_fns, unsigned int *n_vfname) { int ret = -1, i; char *pf_sysfs_device_link = NULL; char *pci_sysfs_device_link = NULL; - struct pci_config_address **virt_fns; char *pciConfigAddr;
if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0) return ret;
- if (pciGetVirtualFunctions(pf_sysfs_device_link, &virt_fns, + if (pciGetVirtualFunctions(pf_sysfs_device_link, virt_fns, n_vfname) < 0) goto cleanup;
@@ -1003,10 +1004,10 @@ virNetDevGetVirtualFunctions(const char *pfname,
for (i = 0; i < *n_vfname; i++) { - if (pciGetDeviceAddrString(virt_fns[i]->domain, - virt_fns[i]->bus, - virt_fns[i]->slot, - virt_fns[i]->function, + if (pciGetDeviceAddrString((*virt_fns)[i]->domain, + (*virt_fns)[i]->bus, + (*virt_fns)[i]->slot, + (*virt_fns)[i]->function, &pciConfigAddr) < 0) { virReportSystemError(ENOSYS, "%s", _("Failed to get PCI Config Address String")); @@ -1019,20 +1020,17 @@ virNetDevGetVirtualFunctions(const char *pfname, }
if (pciDeviceNetName(pci_sysfs_device_link, &((*vfname)[i])) < 0) { - virReportSystemError(ENOSYS, "%s", - _("Failed to get interface name of the VF")); - goto cleanup; + VIR_INFO("VF does not have an interface name"); } }
ret = 0;
cleanup: - if (ret < 0) + if (ret < 0) { VIR_FREE(*vfname); - for (i = 0; i < *n_vfname; i++) - VIR_FREE(virt_fns[i]); - VIR_FREE(virt_fns); + VIR_FREE(*virt_fns); + } VIR_FREE(pf_sysfs_device_link); VIR_FREE(pci_sysfs_device_link); VIR_FREE(pciConfigAddr); @@ -1169,6 +1167,7 @@ cleanup: int virNetDevGetVirtualFunctions(const char *pfname ATTRIBUTE_UNUSED, char ***vfname ATTRIBUTE_UNUSED, + struct pci_config_address ***virt_fns ATTRIBUTE_UNUSED, unsigned int *n_vfname ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, "%s", diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index c663e49..705ad9c 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -26,6 +26,7 @@ # include "virsocketaddr.h" # include "virnetlink.h" # include "virmacaddr.h" +# include "pci.h"
int virNetDevExists(const char *brname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; @@ -103,9 +104,10 @@ int virNetDevGetPhysicalFunction(const char *ifname, char **pfname)
int virNetDevGetVirtualFunctions(const char *pfname, char ***vfname, + struct pci_config_address ***virt_fns, unsigned int *n_vfname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) - ATTRIBUTE_RETURN_CHECK; + ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
int virNetDevLinkDump(const char *ifname, int ifindex, struct nlattr **tb,

On 08/14/2012 06:36 AM, Laine Stump wrote:
On 08/10/2012 12:23 PM, Shradha Shah wrote:
The network pool should be able to keep track of both, network device names nad PCI addresses, and return the appropriate one in the actualDevice when networkAllocateActualDevice is called.
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- src/network/bridge_driver.c | 33 +++++++++++++++++++++++++++------ src/util/virnetdev.c | 25 ++++++++++++------------- src/util/virnetdev.h | 4 +++- 3 files changed, 42 insertions(+), 20 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index df3cc25..602e17d 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -59,6 +59,7 @@ #include "dnsmasq.h" #include "configmake.h" #include "virnetdev.h" +#include "pci.h" #include "virnetdevbridge.h" #include "virnetdevtap.h"
@@ -2737,10 +2738,11 @@ static int networkCreateInterfacePool(virNetworkDefPtr netdef) { unsigned int num_virt_fns = 0; char **vfname = NULL; + struct pci_config_address **virt_fns; int ret = -1, ii = 0;
if ((virNetDevGetVirtualFunctions(netdef->forwardPfs->dev, - &vfname, &num_virt_fns)) < 0) { + &vfname, &virt_fns, &num_virt_fns)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not get Virtual functions on %s"), netdef->forwardPfs->dev); @@ -2762,19 +2764,38 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { netdef->nForwardIfs = num_virt_fns;
for (ii = 0; ii < netdef->nForwardIfs; ii++) { - netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); - if (!netdef->forwardIfs[ii].device.dev) { - virReportOOMError(); - goto finish;
To be pure in the separation of patches, the following if else should be removed from this patch, with just the contents of the "if" clause here. Then the if else + body of the else should be added in the next patch.
(And at any rate, the if() condition is incorrect here - really that part should happen for all forwardTypes except HOSTDEV (BRIDGE, PRIVATE, and VEPA also require netdev names.)
I did not include the BRIDGE, PRIVATE and VEPA cases here because the networkCreateInterfacePool function is not called in those cases. Should I still include the conditions for BRIDGE, PRIVATE and VEPA?
Aside from that movement of code to the next patch, ACK.
+ if (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) { + if(vfname[ii]) { + netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); + if (!netdef->forwardIfs[ii].device.dev) { + virReportOOMError(); + goto finish; + } + } + else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Passthrough mode requires interface names")); + goto finish; + } + } + else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + netdef->forwardIfs[ii].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI; /*Assuming PCI as VF's are PCI devices */ + netdef->forwardIfs[ii].device.pci.domain = virt_fns[ii]->domain; + netdef->forwardIfs[ii].device.pci.bus = virt_fns[ii]->bus; + netdef->forwardIfs[ii].device.pci.slot = virt_fns[ii]->slot; + netdef->forwardIfs[ii].device.pci.function = virt_fns[ii]->function; } netdef->forwardIfs[ii].usageCount = 0; }
ret = 0; finish: - for (ii = 0; ii < num_virt_fns; ii++) + for (ii = 0; ii < num_virt_fns; ii++) { VIR_FREE(vfname[ii]); + VIR_FREE(virt_fns[ii]); + } VIR_FREE(vfname); + VIR_FREE(virt_fns); return ret; }
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index f1ee0a4..8103aff 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -29,6 +29,7 @@ #include "command.h" #include "memory.h" #include "pci.h" +#include "logging.h"
#include <sys/ioctl.h> #ifdef HAVE_NET_IF_H @@ -981,18 +982,18 @@ virNetDevSysfsDeviceFile(char **pf_sysfs_device_link, const char *ifname, int virNetDevGetVirtualFunctions(const char *pfname, char ***vfname, + struct pci_config_address ***virt_fns, unsigned int *n_vfname) { int ret = -1, i; char *pf_sysfs_device_link = NULL; char *pci_sysfs_device_link = NULL; - struct pci_config_address **virt_fns; char *pciConfigAddr;
if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0) return ret;
- if (pciGetVirtualFunctions(pf_sysfs_device_link, &virt_fns, + if (pciGetVirtualFunctions(pf_sysfs_device_link, virt_fns, n_vfname) < 0) goto cleanup;
@@ -1003,10 +1004,10 @@ virNetDevGetVirtualFunctions(const char *pfname,
for (i = 0; i < *n_vfname; i++) { - if (pciGetDeviceAddrString(virt_fns[i]->domain, - virt_fns[i]->bus, - virt_fns[i]->slot, - virt_fns[i]->function, + if (pciGetDeviceAddrString((*virt_fns)[i]->domain, + (*virt_fns)[i]->bus, + (*virt_fns)[i]->slot, + (*virt_fns)[i]->function, &pciConfigAddr) < 0) { virReportSystemError(ENOSYS, "%s", _("Failed to get PCI Config Address String")); @@ -1019,20 +1020,17 @@ virNetDevGetVirtualFunctions(const char *pfname, }
if (pciDeviceNetName(pci_sysfs_device_link, &((*vfname)[i])) < 0) { - virReportSystemError(ENOSYS, "%s", - _("Failed to get interface name of the VF")); - goto cleanup; + VIR_INFO("VF does not have an interface name"); } }
ret = 0;
cleanup: - if (ret < 0) + if (ret < 0) { VIR_FREE(*vfname); - for (i = 0; i < *n_vfname; i++) - VIR_FREE(virt_fns[i]); - VIR_FREE(virt_fns); + VIR_FREE(*virt_fns); + } VIR_FREE(pf_sysfs_device_link); VIR_FREE(pci_sysfs_device_link); VIR_FREE(pciConfigAddr); @@ -1169,6 +1167,7 @@ cleanup: int virNetDevGetVirtualFunctions(const char *pfname ATTRIBUTE_UNUSED, char ***vfname ATTRIBUTE_UNUSED, + struct pci_config_address ***virt_fns ATTRIBUTE_UNUSED, unsigned int *n_vfname ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, "%s", diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index c663e49..705ad9c 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -26,6 +26,7 @@ # include "virsocketaddr.h" # include "virnetlink.h" # include "virmacaddr.h" +# include "pci.h"
int virNetDevExists(const char *brname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; @@ -103,9 +104,10 @@ int virNetDevGetPhysicalFunction(const char *ifname, char **pfname)
int virNetDevGetVirtualFunctions(const char *pfname, char ***vfname, + struct pci_config_address ***virt_fns, unsigned int *n_vfname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) - ATTRIBUTE_RETURN_CHECK; + ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
int virNetDevLinkDump(const char *ifname, int ifindex, struct nlattr **tb,
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 08/15/2012 06:47 AM, Shradha Shah wrote:
On 08/14/2012 06:36 AM, Laine Stump wrote:
On 08/10/2012 12:23 PM, Shradha Shah wrote:
The network pool should be able to keep track of both, network device names nad PCI addresses, and return the appropriate one in the actualDevice when networkAllocateActualDevice is called.
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- src/network/bridge_driver.c | 33 +++++++++++++++++++++++++++------ src/util/virnetdev.c | 25 ++++++++++++------------- src/util/virnetdev.h | 4 +++- 3 files changed, 42 insertions(+), 20 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index df3cc25..602e17d 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -59,6 +59,7 @@ #include "dnsmasq.h" #include "configmake.h" #include "virnetdev.h" +#include "pci.h" #include "virnetdevbridge.h" #include "virnetdevtap.h"
@@ -2737,10 +2738,11 @@ static int networkCreateInterfacePool(virNetworkDefPtr netdef) { unsigned int num_virt_fns = 0; char **vfname = NULL; + struct pci_config_address **virt_fns; int ret = -1, ii = 0;
if ((virNetDevGetVirtualFunctions(netdef->forwardPfs->dev, - &vfname, &num_virt_fns)) < 0) { + &vfname, &virt_fns, &num_virt_fns)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not get Virtual functions on %s"), netdef->forwardPfs->dev); @@ -2762,19 +2764,38 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { netdef->nForwardIfs = num_virt_fns;
for (ii = 0; ii < netdef->nForwardIfs; ii++) { - netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]); - if (!netdef->forwardIfs[ii].device.dev) { - virReportOOMError(); - goto finish; To be pure in the separation of patches, the following if else should be removed from this patch, with just the contents of the "if" clause here. Then the if else + body of the else should be added in the next patch.
(And at any rate, the if() condition is incorrect here - really that part should happen for all forwardTypes except HOSTDEV (BRIDGE, PRIVATE, and VEPA also require netdev names.) I did not include the BRIDGE, PRIVATE and VEPA cases here because the networkCreateInterfacePool function is not called in those cases.
Should I still include the conditions for BRIDGE, PRIVATE and VEPA?
Ah. It *should* be called for those cases as well. I hadn't noticed that it wasn't. Those modes can also benefit from auto-creating the list of devices.

This patch updates the network driver to properly utilize the new attributes/elements that are now in virNetworkDef Signed-off-by: Shradha Shah <sshah@solarflare.com> --- docs/formatnetwork.html.in | 62 +++++++++++ src/network/bridge_driver.c | 237 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 254 insertions(+), 45 deletions(-) diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 7e8e991..96b9eb2 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -210,6 +210,37 @@ (usually either a domain start, or a hotplug interface attach to a domain).<span class="since">Since 0.9.4</span> </dd> + <dt><code>hostdev</code></dt> + <dd> + This network facilitates PCI Passthrough of a network device. + A network device is chosen from the interface pool and + directly assigned to the guest using generic device + passthrough, after first optionally setting the device's MAC + address to the configured value, and associating the device with + an 802.1Qbh capable switch using an optionally specified + <code><virtualport></code> element. + Note that - due to limitations in standard single-port PCI + ethernet card driver design - only SR-IOV (Single Root I/O + Virtualization) virtual function (VF) devices can be assigned + in this manner; to assign a standard single-port PCI or PCIe + ethernet card to a guest, use the traditional <code>< + hostdev></code> device definition and <span class="since"> + Since 0.9.12</span> + + <p>Note that this "intelligent passthrough" of network devices is + very similar to the functionality of a standard <code>< + hostdev></code> device, the difference being that this + method allows specifying a MAC address and <code><virtualport + ></code> for the passed-through device. If these capabilities + are not required, if you have a standard single-port PCI, PCIe, + or USB network card that doesn't support SR-IOV (and hence would + anyway lose the configured MAC address during reset after being + assigned to the guest domain), or if you are using a version of + libvirt older than 0.9.12, you should use standard + <code><hostdev></code> to assign the device to the + guest instead of <code><forward mode='hostdev'/></code>. + </p> + </dd> </dl> As mentioned above, a <code><forward></code> element can have multiple <code><interface></code> subelements, each @@ -249,6 +280,37 @@ particular, 'passthrough' mode, and 'private' mode when using 802.1Qbh), libvirt will choose an unused physical interface or, if it can't find an unused interface, fail the operation.</p> + + <span class="since">since 0.9.12</span> and when using forward mode + 'hostdev' we specify the interface pool by using the + <code><address></code> element and <code>< + type></code> <code><domain></code> <code><bus></code> + <code><slot></code> and <code><function></code> + sub-elements. + + <pre> +... + <forward mode='hostdev' managed='yes'> + <address type='pci' domain='0' bus='4' slot='0' function='1'/> + <address type='pci' domain='0' bus='4' slot='0' function='2'/> + <address type='pci' domain='0' bus='4' slot='0' function='3'/> + </forward> +... + </pre> + + Alternatively the interface pool can also be mentioned using a + single physical function <code><pf></code> subelement to + call out the corresponding physical interface associated with + multiple virtual interfaces (similar to the passthrough mode): + + <pre> +... + <forward mode='hostdev' managed='yes'> + <pf dev='eth0'/> + </forward> +... + </pre> + </dd> </dl> <h5><a name="elementQoS">Quality of service</a></h5> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 602e17d..33bc09e 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1934,7 +1934,7 @@ networkStartNetworkExternal(struct network_driver *driver ATTRIBUTE_UNUSED, virNetworkObjPtr network ATTRIBUTE_UNUSED) { /* put anything here that needs to be done each time a network of - * type BRIDGE, PRIVATE, VEPA, or PASSTHROUGH is started. On + * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On * failure, undo anything you've done, and return -1. On success * return 0. */ @@ -1945,7 +1945,7 @@ static int networkShutdownNetworkExternal(struct network_driver *driver ATTRIBUT virNetworkObjPtr network ATTRIBUTE_UNUSED) { /* put anything here that needs to be done each time a network of - * type BRIDGE, PRIVATE, VEPA, or PASSTHROUGH is shutdown. On + * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On * failure, undo anything you've done, and return -1. On success * return 0. */ @@ -1976,6 +1976,7 @@ networkStartNetwork(struct network_driver *driver, case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: + case VIR_NETWORK_FORWARD_HOSTDEV: ret = networkStartNetworkExternal(driver, network); break; } @@ -2035,6 +2036,7 @@ static int networkShutdownNetwork(struct network_driver *driver, case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: + case VIR_NETWORK_FORWARD_HOSTDEV: ret = networkShutdownNetworkExternal(driver, network); break; } @@ -2778,7 +2780,7 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { goto finish; } } - else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { netdef->forwardIfs[ii].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI; /*Assuming PCI as VF's are PCI devices */ netdef->forwardIfs[ii].device.pci.domain = virt_fns[ii]->domain; netdef->forwardIfs[ii].device.pci.bus = virt_fns[ii]->bus; @@ -2817,6 +2819,8 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) virNetworkObjPtr network; virNetworkDefPtr netdef; virPortGroupDefPtr portgroup; + virNetDevVPortProfilePtr virtport = NULL; + virNetworkForwardIfDefPtr dev = NULL; int ii; int ret = -1; @@ -2869,6 +2873,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) */ if (iface->data.network.actual) iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK; + } else if ((netdef->forwardType == VIR_NETWORK_FORWARD_BRIDGE) && netdef->bridge) { @@ -2889,11 +2894,74 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) goto cleanup; } + } else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (!iface->data.network.actual + && (VIR_ALLOC(iface->data.network.actual) < 0)) { + virReportOOMError(); + goto cleanup; + } + + iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_HOSTDEV; + if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { + if(networkCreateInterfacePool(netdef) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create Interface Pool from PF")); + goto cleanup; + } + } + /* pick first dev with 0 usageCount */ + + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (netdef->forwardIfs[ii].usageCount == 0) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + if (!dev) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("network '%s' requires exclusive access to interfaces, but none are available"), + netdef->name); + goto cleanup; + } + iface->data.network.actual->data.hostdev.def.parent.type = VIR_DOMAIN_DEVICE_NET; + iface->data.network.actual->data.hostdev.def.parent.data.net = iface; + iface->data.network.actual->data.hostdev.def.info = &iface->info; + iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + iface->data.network.actual->data.hostdev.def.managed = netdef->managed; + iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type; + iface->data.network.actual->data.hostdev.def.source.subsys.u.pci = dev->device.pci; + + if (iface->data.network.virtPortProfile) { + virtport = iface->data.network.virtPortProfile; + } else { + if (portgroup) + virtport = portgroup->virtPortProfile; + else + virtport = netdef->virtPortProfile; + } + if (virtport) { + if (VIR_ALLOC(iface->data.network.actual->data.hostdev.virtPortProfile) < 0) { + virReportOOMError(); + goto cleanup; + } + /* There are no pointers in a virtualPortProfile, so a shallow copy + * is sufficient + */ + *iface->data.network.actual->data.direct.virtPortProfile = *virtport; + } + + dev->usageCount++; + VIR_DEBUG("Using physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount); + } else if ((netdef->forwardType == VIR_NETWORK_FORWARD_BRIDGE) || (netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) || (netdef->forwardType == VIR_NETWORK_FORWARD_VEPA) || (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH)) { - virNetDevVPortProfilePtr virtport = NULL; /* <forward type='bridge|private|vepa|passthrough'> are all * VIR_DOMAIN_NET_TYPE_DIRECT. @@ -2952,7 +3020,6 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) netdef->name); goto cleanup; } else { - virNetworkForwardIfDefPtr dev = NULL; /* pick an interface from the pool */ @@ -3045,14 +3112,16 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network; virNetworkDefPtr netdef; - const char *actualDev; + const char *actualDev = NULL; + virDomainHostdevDefPtr def = NULL; int ret = -1; if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) return 0; if (!iface->data.network.actual || - (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT)) { + ((virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT) && + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV))) { VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name); return 0; } @@ -3067,19 +3136,28 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) goto cleanup; } - actualDev = virDomainNetGetActualDirectDev(iface); - if (!actualDev) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("the interface uses a direct " - "mode, but has no source dev")); - goto cleanup; + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + actualDev = virDomainNetGetActualDirectDev(iface); + if (!actualDev) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a direct mode, but has no source dev")); + goto cleanup; + } + } + + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + def = virDomainNetGetActualHostdev(iface); + if (!def) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a hostdev mode, but has no hostdev")); + goto cleanup; + } } netdef = network->def; - if (netdef->nForwardIfs == 0) { + if ((netdef->nForwardIfs == 0) && (netdef->nForwardPfs == 0)) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' uses a direct mode, but " - "has no forward dev and no interface pool"), + _("network '%s' uses a direct/hostdev mode, but has no forward dev and no interface pool"), netdef->name); goto cleanup; } else { @@ -3087,27 +3165,49 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) virNetworkForwardIfDefPtr dev = NULL; /* find the matching interface in the pool and increment its usageCount */ + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + } - for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { - dev = &netdef->forwardIfs[ii]; - break; + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { + if(networkCreateInterfacePool(netdef) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create Interface Pool from PF")); + goto cleanup; + } + } + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if((def->source.subsys.u.pci.domain == netdef->forwardIfs[ii].device.pci.domain) && + (def->source.subsys.u.pci.bus == netdef->forwardIfs[ii].device.pci.bus) && + (def->source.subsys.u.pci.slot == netdef->forwardIfs[ii].device.pci.slot) && + (def->source.subsys.u.pci.function == netdef->forwardIfs[ii].device.pci.function)) { + dev = &netdef->forwardIfs[ii]; + break; + } } } + /* dev points at the physical device we want to use */ if (!dev) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' doesn't have dev='%s' in use by domain"), - netdef->name, actualDev); + _("network '%s' doesn't have dev in use by domain"), + netdef->name); goto cleanup; } - /* PASSTHROUGH mode, and PRIVATE Mode + 802.1Qbh both require + /* PASSTHROUGH mode, HOSTDEV mode and PRIVATE Mode + 802.1Qbh both require * exclusive access to a device, so current usageCount must be * 0 in those cases. */ if ((dev->usageCount > 0) && ((netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) || + (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) || ((netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) && iface->data.network.actual->data.direct.virtPortProfile && (iface->data.network.actual->data.direct.virtPortProfile->virtPortType @@ -3119,8 +3219,18 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) } /* we are now assured of success, so mark the allocation */ dev->usageCount++; - VIR_DEBUG("Using physical device %s, usageCount %d", - dev->device.dev, dev->usageCount); + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + VIR_DEBUG("Using physical device %s, usageCount %d", + dev->device.dev, dev->usageCount); + } + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + VIR_DEBUG("Using physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount); + } } ret = 0; @@ -3147,14 +3257,16 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network = NULL; virNetworkDefPtr netdef; - const char *actualDev; + const char *actualDev = NULL; + virDomainHostdevDefPtr def = NULL; int ret = -1; if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) return 0; if (!iface->data.network.actual || - (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT)) { + ((virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT) && + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV))) { VIR_DEBUG("Nothing to release to network %s", iface->data.network.name); ret = 0; goto cleanup; @@ -3170,44 +3282,79 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) goto cleanup; } - actualDev = virDomainNetGetActualDirectDev(iface); - if (!actualDev) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("the interface uses a direct " - "mode, but has no source dev")); - goto cleanup; + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + actualDev = virDomainNetGetActualDirectDev(iface); + if (!actualDev) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a direct mode, but has no source dev")); + goto cleanup; + } + } + + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + def = virDomainNetGetActualHostdev(iface); + if (!def) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a hostdev mode, but has no hostdev")); + goto cleanup; + } } netdef = network->def; - if (netdef->nForwardIfs == 0) { + if ((netdef->nForwardIfs == 0) && (netdef->nForwardPfs == 0)) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' uses a direct mode, but " + _("network '%s' uses a direct/hostdev mode, but " "has no forward dev and no interface pool"), netdef->name); goto cleanup; } else { int ii; virNetworkForwardIfDefPtr dev = NULL; - - for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { - dev = &netdef->forwardIfs[ii]; - break; + + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + } + + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if((def->source.subsys.u.pci.domain == netdef->forwardIfs[ii].device.pci.domain) && + (def->source.subsys.u.pci.bus == netdef->forwardIfs[ii].device.pci.bus) && + (def->source.subsys.u.pci.slot == netdef->forwardIfs[ii].device.pci.slot) && + (def->source.subsys.u.pci.function == netdef->forwardIfs[ii].device.pci.function)) { + dev = &netdef->forwardIfs[ii]; + break; + } } } + /* dev points at the physical device we've been using */ if (!dev) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' doesn't have dev='%s' in use by domain"), - netdef->name, actualDev); + _("network '%s' doesn't have dev in use by domain"), + netdef->name); goto cleanup; } dev->usageCount--; - VIR_DEBUG("Releasing physical device %s, usageCount %d", - dev->device.dev, dev->usageCount); + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + VIR_DEBUG("Releasing physical device %s, usageCount %d", + dev->device.dev, dev->usageCount); + } + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + VIR_DEBUG("Releasing physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount); + } } - + ret = 0; cleanup: if (network) -- 1.7.4.4

On 08/10/2012 12:24 PM, Shradha Shah wrote:
This patch updates the network driver to properly utilize the new attributes/elements that are now in virNetworkDef
Some minor nits, nothing major, but still needs one more iteration. I'll try to look at the hostdev-hybrid patches in the morning...
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- docs/formatnetwork.html.in | 62 +++++++++++ src/network/bridge_driver.c | 237 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 254 insertions(+), 45 deletions(-)
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 7e8e991..96b9eb2 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -210,6 +210,37 @@ (usually either a domain start, or a hotplug interface attach to a domain).<span class="since">Since 0.9.4</span> </dd> + <dt><code>hostdev</code></dt> + <dd> + This network facilitates PCI Passthrough of a network device. + A network device is chosen from the interface pool and + directly assigned to the guest using generic device + passthrough, after first optionally setting the device's MAC + address to the configured value, and associating the device with
You should probably say "optionally associating" here too, to make sure nobody misunderstands and thinks the 802.1Qbh part is mandatory.
+ an 802.1Qbh capable switch using an optionally specified + <code><virtualport></code> element. + Note that - due to limitations in standard single-port PCI + ethernet card driver design - only SR-IOV (Single Root I/O + Virtualization) virtual function (VF) devices can be assigned + in this manner; to assign a standard single-port PCI or PCIe + ethernet card to a guest, use the traditional <code>< + hostdev></code> device definition and <span class="since">
s/definition and/definition./
+ Since 0.9.12</span>
All of the 0.9.12's need to be changed to 0.10.0.
+ + <p>Note that this "intelligent passthrough" of network devices is + very similar to the functionality of a standard <code>< + hostdev></code> device, the difference being that this + method allows specifying a MAC address and <code><virtualport + ></code> for the passed-through device. If these capabilities + are not required, if you have a standard single-port PCI, PCIe, + or USB network card that doesn't support SR-IOV (and hence would + anyway lose the configured MAC address during reset after being + assigned to the guest domain), or if you are using a version of + libvirt older than 0.9.12, you should use standard
s/use/use a/
+ <code><hostdev></code> to assign the device to the
s/to assign/definition to assign/
+ guest instead of <code><forward mode='hostdev'/></code>. + </p> + </dd> </dl> As mentioned above, a <code><forward></code> element can have multiple <code><interface></code> subelements, each @@ -249,6 +280,37 @@ particular, 'passthrough' mode, and 'private' mode when using 802.1Qbh), libvirt will choose an unused physical interface or, if it can't find an unused interface, fail the operation.</p> + + <span class="since">since 0.9.12</span> and when using forward mode + 'hostdev' we specify the interface pool by using the + <code><address></code> element and <code>< + type></code> <code><domain></code> <code><bus></code> + <code><slot></code> and <code><function></code> + sub-elements. + + <pre> +... + <forward mode='hostdev' managed='yes'> + <address type='pci' domain='0' bus='4' slot='0' function='1'/> + <address type='pci' domain='0' bus='4' slot='0' function='2'/> + <address type='pci' domain='0' bus='4' slot='0' function='3'/> + </forward> +... + </pre> + + Alternatively the interface pool can also be mentioned using a
s/mentioned/defined/
+ single physical function <code><pf></code> subelement to + call out the corresponding physical interface associated with + multiple virtual interfaces (similar to the passthrough mode):
s/the passthrough/passthrough/
+ + <pre> +... + <forward mode='hostdev' managed='yes'> + <pf dev='eth0'/> + </forward> +... + </pre> + </dd> </dl> <h5><a name="elementQoS">Quality of service</a></h5> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 602e17d..33bc09e 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1934,7 +1934,7 @@ networkStartNetworkExternal(struct network_driver *driver ATTRIBUTE_UNUSED, virNetworkObjPtr network ATTRIBUTE_UNUSED) { /* put anything here that needs to be done each time a network of - * type BRIDGE, PRIVATE, VEPA, or PASSTHROUGH is started. On + * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On * failure, undo anything you've done, and return -1. On success * return 0. */ @@ -1945,7 +1945,7 @@ static int networkShutdownNetworkExternal(struct network_driver *driver ATTRIBUT virNetworkObjPtr network ATTRIBUTE_UNUSED) { /* put anything here that needs to be done each time a network of - * type BRIDGE, PRIVATE, VEPA, or PASSTHROUGH is shutdown. On + * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On * failure, undo anything you've done, and return -1. On success * return 0. */ @@ -1976,6 +1976,7 @@ networkStartNetwork(struct network_driver *driver, case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: + case VIR_NETWORK_FORWARD_HOSTDEV: ret = networkStartNetworkExternal(driver, network); break; } @@ -2035,6 +2036,7 @@ static int networkShutdownNetwork(struct network_driver *driver, case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: + case VIR_NETWORK_FORWARD_HOSTDEV: ret = networkShutdownNetworkExternal(driver, network); break; } @@ -2778,7 +2780,7 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { goto finish; } } - else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { netdef->forwardIfs[ii].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI; /*Assuming PCI as VF's are PCI devices */ netdef->forwardIfs[ii].device.pci.domain = virt_fns[ii]->domain; netdef->forwardIfs[ii].device.pci.bus = virt_fns[ii]->bus; @@ -2817,6 +2819,8 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) virNetworkObjPtr network; virNetworkDefPtr netdef; virPortGroupDefPtr portgroup; + virNetDevVPortProfilePtr virtport = NULL; + virNetworkForwardIfDefPtr dev = NULL; int ii; int ret = -1;
@@ -2869,6 +2873,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) */ if (iface->data.network.actual) iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK; +
Extraneous whitespace change ^^^
} else if ((netdef->forwardType == VIR_NETWORK_FORWARD_BRIDGE) && netdef->bridge) {
@@ -2889,11 +2894,74 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) goto cleanup; }
+ } else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (!iface->data.network.actual + && (VIR_ALLOC(iface->data.network.actual) < 0)) { + virReportOOMError(); + goto cleanup; + } + + iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_HOSTDEV; + if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { + if(networkCreateInterfacePool(netdef) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create Interface Pool from PF"));
networkCreateInterfacePool() logs its own error. Don't log another one.
+ goto cleanup; + } + } + /* pick first dev with 0 usageCount */ + + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (netdef->forwardIfs[ii].usageCount == 0) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + if (!dev) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("network '%s' requires exclusive access to interfaces, but none are available"), + netdef->name); + goto cleanup; + } + iface->data.network.actual->data.hostdev.def.parent.type = VIR_DOMAIN_DEVICE_NET; + iface->data.network.actual->data.hostdev.def.parent.data.net = iface; + iface->data.network.actual->data.hostdev.def.info = &iface->info; + iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + iface->data.network.actual->data.hostdev.def.managed = netdef->managed; + iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type; + iface->data.network.actual->data.hostdev.def.source.subsys.u.pci = dev->device.pci; + + if (iface->data.network.virtPortProfile) { + virtport = iface->data.network.virtPortProfile; + } else { + if (portgroup) + virtport = portgroup->virtPortProfile; + else + virtport = netdef->virtPortProfile; + } + if (virtport) { + if (VIR_ALLOC(iface->data.network.actual->data.hostdev.virtPortProfile) < 0) { + virReportOOMError(); + goto cleanup; + } + /* There are no pointers in a virtualPortProfile, so a shallow copy + * is sufficient + */ + *iface->data.network.actual->data.direct.virtPortProfile = *virtport; + }
All the above code will need to be removed when my virtualport merging patch is pushed - it's all handled in common code now.
+ + dev->usageCount++; + VIR_DEBUG("Using physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount);
You could combine some of those args to save lines...
+ } else if ((netdef->forwardType == VIR_NETWORK_FORWARD_BRIDGE) || (netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) || (netdef->forwardType == VIR_NETWORK_FORWARD_VEPA) || (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH)) { - virNetDevVPortProfilePtr virtport = NULL;
/* <forward type='bridge|private|vepa|passthrough'> are all * VIR_DOMAIN_NET_TYPE_DIRECT. @@ -2952,7 +3020,6 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) netdef->name); goto cleanup; } else { - virNetworkForwardIfDefPtr dev = NULL;
/* pick an interface from the pool */
@@ -3045,14 +3112,16 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network; virNetworkDefPtr netdef; - const char *actualDev; + const char *actualDev = NULL; + virDomainHostdevDefPtr def = NULL; int ret = -1;
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) return 0;
if (!iface->data.network.actual || - (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT)) { + ((virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT) && + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV))) { VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name); return 0; } @@ -3067,19 +3136,28 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) goto cleanup; }
- actualDev = virDomainNetGetActualDirectDev(iface); - if (!actualDev) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("the interface uses a direct " - "mode, but has no source dev")); - goto cleanup; + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + actualDev = virDomainNetGetActualDirectDev(iface); + if (!actualDev) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a direct mode, but has no source dev")); + goto cleanup; + } + }
... else ...
+ + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + def = virDomainNetGetActualHostdev(iface); + if (!def) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a hostdev mode, but has no hostdev")); + goto cleanup; + } }
netdef = network->def; - if (netdef->nForwardIfs == 0) { + if ((netdef->nForwardIfs == 0) && (netdef->nForwardPfs == 0)) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' uses a direct mode, but " - "has no forward dev and no interface pool"), + _("network '%s' uses a direct/hostdev mode, but has no forward dev and no interface pool"), netdef->name); goto cleanup; } else { @@ -3087,27 +3165,49 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) virNetworkForwardIfDefPtr dev = NULL;
/* find the matching interface in the pool and increment its usageCount */ + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + }
- for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { - dev = &netdef->forwardIfs[ii]; - break;
again "... else ..."
+ if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { + if(networkCreateInterfacePool(netdef) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create Interface Pool from PF")); + goto cleanup; + } + } + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if((def->source.subsys.u.pci.domain == netdef->forwardIfs[ii].device.pci.domain) && + (def->source.subsys.u.pci.bus == netdef->forwardIfs[ii].device.pci.bus) && + (def->source.subsys.u.pci.slot == netdef->forwardIfs[ii].device.pci.slot) && + (def->source.subsys.u.pci.function == netdef->forwardIfs[ii].device.pci.function)) {
Isn't there a virDevicePCIAddressEqual() function?
+ dev = &netdef->forwardIfs[ii]; + break; + } } } + /* dev points at the physical device we want to use */ if (!dev) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' doesn't have dev='%s' in use by domain"), - netdef->name, actualDev); + _("network '%s' doesn't have dev in use by domain"), + netdef->name);
It would probably be very useful to print the netdev name if we were looking for a netdev, and print out the PCI device info if we were looking for a PCI device.
goto cleanup; }
- /* PASSTHROUGH mode, and PRIVATE Mode + 802.1Qbh both require + /* PASSTHROUGH mode, HOSTDEV mode and PRIVATE Mode + 802.1Qbh both require * exclusive access to a device, so current usageCount must be * 0 in those cases. */ if ((dev->usageCount > 0) && ((netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) || + (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) || ((netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) && iface->data.network.actual->data.direct.virtPortProfile && (iface->data.network.actual->data.direct.virtPortProfile->virtPortType @@ -3119,8 +3219,18 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) } /* we are now assured of success, so mark the allocation */ dev->usageCount++; - VIR_DEBUG("Using physical device %s, usageCount %d", - dev->device.dev, dev->usageCount); + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + VIR_DEBUG("Using physical device %s, usageCount %d", + dev->device.dev, dev->usageCount); + }
... else ...
+ if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + VIR_DEBUG("Using physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount); + } }
ret = 0; @@ -3147,14 +3257,16 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network = NULL; virNetworkDefPtr netdef; - const char *actualDev; + const char *actualDev = NULL; + virDomainHostdevDefPtr def = NULL; int ret = -1;
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) return 0;
if (!iface->data.network.actual || - (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT)) {
You know, as often as you're calling virDomainNetGetActualType(iface), maybe you should define a variable "enum virDomainNetType actualType = virDomainNetGetActualType(iface)" at the top of the function.
+ ((virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT) && + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV))) { VIR_DEBUG("Nothing to release to network %s", iface->data.network.name); ret = 0; goto cleanup; @@ -3170,44 +3282,79 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) goto cleanup; }
- actualDev = virDomainNetGetActualDirectDev(iface); - if (!actualDev) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("the interface uses a direct " - "mode, but has no source dev")); - goto cleanup; + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + actualDev = virDomainNetGetActualDirectDev(iface); + if (!actualDev) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a direct mode, but has no source dev")); + goto cleanup; + } + } + ... else ...
+ if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + def = virDomainNetGetActualHostdev(iface); + if (!def) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a hostdev mode, but has no hostdev")); + goto cleanup; + } }
netdef = network->def; - if (netdef->nForwardIfs == 0) { + if ((netdef->nForwardIfs == 0) && (netdef->nForwardPfs == 0)) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' uses a direct mode, but " + _("network '%s' uses a direct/hostdev mode, but " "has no forward dev and no interface pool"), netdef->name); goto cleanup; } else { int ii; virNetworkForwardIfDefPtr dev = NULL; - - for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { - dev = &netdef->forwardIfs[ii]; - break; + + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + } + ... else ...
+ if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if((def->source.subsys.u.pci.domain == netdef->forwardIfs[ii].device.pci.domain) && + (def->source.subsys.u.pci.bus == netdef->forwardIfs[ii].device.pci.bus) && + (def->source.subsys.u.pci.slot == netdef->forwardIfs[ii].device.pci.slot) && + (def->source.subsys.u.pci.function == netdef->forwardIfs[ii].device.pci.function)) {
Again, some kind of virDevicePCIAddressEqual() function would be nice.
+ dev = &netdef->forwardIfs[ii]; + break; + } } } + /* dev points at the physical device we've been using */ if (!dev) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' doesn't have dev='%s' in use by domain"), - netdef->name, actualDev); + _("network '%s' doesn't have dev in use by domain"), + netdef->name); goto cleanup; }
dev->usageCount--; - VIR_DEBUG("Releasing physical device %s, usageCount %d", - dev->device.dev, dev->usageCount); + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + VIR_DEBUG("Releasing physical device %s, usageCount %d", + dev->device.dev, dev->usageCount); + } + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + VIR_DEBUG("Releasing physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount); + } } - + ret = 0; cleanup: if (network)

Signed-off-by: Shradha Shah <sshah@solarflare.com> --- src/qemu/qemu_command.c | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6f6c6cd..bb66364 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -24,6 +24,7 @@ #include <config.h> #include "qemu_command.h" +#include "qemu_hostdev.h" #include "qemu_capabilities.h" #include "qemu_bridge_filter.h" #include "cpu/cpu.h" @@ -5221,12 +5222,38 @@ qemuBuildCommandLine(virConnectPtr conn, actualType = virDomainNetGetActualType(net); if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net); + virDomainHostdevDefPtr found; /* type='hostdev' interfaces are handled in codepath * for standard hostdev (NB: when there is a network * with <forward mode='hostdev', there will need to be * code here that adds the newly minted hostdev to the * hostdevs array). */ + if (qemuAssignDeviceHostdevAlias(def, + hostdev, + (def->nhostdevs-1)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not assign alias to Net Hostdev")); + goto error; + } + + if (virDomainHostdevFind(def, + hostdev, + &found) < 0) { + if (virDomainHostdevInsert(def, + hostdev) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Hostdev not inserted into the array")); + goto error; + } + if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid, + &hostdev, 1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Prepare Hostdev PCI Devices failed")); + goto error; + } + } continue; } -- 1.7.4.4

On 08/10/2012 12:24 PM, Shradha Shah wrote: Some explanation is needed in the commit log of what this is being done here. A cut-paste of the comment in the code would be a good start (any anyway, that comment can be changed since it's talking about "when there is a network with <forward mode='hostdev'>", but that "when" is "now" :-)
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- src/qemu/qemu_command.c | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6f6c6cd..bb66364 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -24,6 +24,7 @@ #include <config.h>
#include "qemu_command.h" +#include "qemu_hostdev.h" #include "qemu_capabilities.h" #include "qemu_bridge_filter.h" #include "cpu/cpu.h" @@ -5221,12 +5222,38 @@ qemuBuildCommandLine(virConnectPtr conn,
actualType = virDomainNetGetActualType(net); if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net); + virDomainHostdevDefPtr found; /* type='hostdev' interfaces are handled in codepath * for standard hostdev (NB: when there is a network * with <forward mode='hostdev', there will need to be * code here that adds the newly minted hostdev to the * hostdevs array). */ + if (qemuAssignDeviceHostdevAlias(def, + hostdev,
Combine the above two lines.
+ (def->nhostdevs-1)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not assign alias to Net Hostdev")); + goto error; + } + + if (virDomainHostdevFind(def, + hostdev, + &found) < 0) {
If the device is found already on the list, you should log an error and fail.
+ if (virDomainHostdevInsert(def, + hostdev) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Hostdev not inserted into the array")); + goto error; + } + if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid, + &hostdev, 1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Prepare Hostdev PCI Devices failed")); + goto error;
It took me awhile to follow that trail, but I do finally understand that this is necessary (because qemuPrepareHostDevices has already been called by the time we get to here and are building the qemu commandline).
+ } + } continue; }
ACK with a better commit log message, fixing the comment in the code, and logging an error if the device is found already on the hostdev list.

On 08/14/2012 07:44 AM, Laine Stump wrote:
On 08/10/2012 12:24 PM, Shradha Shah wrote:
Some explanation is needed in the commit log of what this is being done here. A cut-paste of the comment in the code would be a good start (any anyway, that comment can be changed since it's talking about "when there is a network with <forward mode='hostdev'>", but that "when" is "now" :-)
Signed-off-by: Shradha Shah <sshah@solarflare.com> --- src/qemu/qemu_command.c | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6f6c6cd..bb66364 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -24,6 +24,7 @@ #include <config.h>
#include "qemu_command.h" +#include "qemu_hostdev.h" #include "qemu_capabilities.h" #include "qemu_bridge_filter.h" #include "cpu/cpu.h" @@ -5221,12 +5222,38 @@ qemuBuildCommandLine(virConnectPtr conn,
actualType = virDomainNetGetActualType(net); if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net); + virDomainHostdevDefPtr found; /* type='hostdev' interfaces are handled in codepath * for standard hostdev (NB: when there is a network * with <forward mode='hostdev', there will need to be * code here that adds the newly minted hostdev to the * hostdevs array). */ + if (qemuAssignDeviceHostdevAlias(def, + hostdev,
Combine the above two lines.
+ (def->nhostdevs-1)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not assign alias to Net Hostdev")); + goto error; + } + + if (virDomainHostdevFind(def, + hostdev, + &found) < 0) {
If the device is found already on the list, you should log an error and fail.
The device will be found on the list when using interface type=hostdev. If I log an error and fail wouldn't that mean that interface type=hostdev will always fail at this point?
+ if (virDomainHostdevInsert(def, + hostdev) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Hostdev not inserted into the array")); + goto error; + } + if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid, + &hostdev, 1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Prepare Hostdev PCI Devices failed")); + goto error;
It took me awhile to follow that trail, but I do finally understand that this is necessary (because qemuPrepareHostDevices has already been called by the time we get to here and are building the qemu commandline).
+ } + } continue; }
ACK with a better commit log message, fixing the comment in the code, and logging an error if the device is found already on the hostdev list.
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 08/15/2012 06:43 AM, Shradha Shah wrote:
On 08/14/2012 07:44 AM, Laine Stump wrote:
On 08/10/2012 12:24 PM, Shradha Shah wrote:
+ (def->nhostdevs-1)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not assign alias to Net Hostdev")); + goto error; + } + + if (virDomainHostdevFind(def, + hostdev, + &found) < 0) {
If the device is found already on the list, you should log an error and fail. The device will be found on the list when using interface type=hostdev. If I log an error and fail wouldn't that mean that interface type=hostdev will always fail at this point?
Right. Good point. I guess it's only an error if net->type == VIR_DOMAIN_NET_TYPE_NETWORK. Actually, if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) && (net->type != VIR_DOMAIN_NET_TYPE_NETWORK), then you don't need to do *any* of that code (except "continue;"). Once you've done that, a successful return from virDomainHostdevFind *is* an error (because it means some other device in the domain is trying to use the same physical device). BTW, I've pushed all of my openvswitch/virtualport/vlan patches which will have conflicts with your patches in src/network/bridge_driver.c. If resolving the conflicts is problematic, let me know and I'll try to help out

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. --- docs/formatdomain.html.in | 29 ++++++ docs/schemas/domaincommon.rng | 50 ++++++++++ src/conf/domain_conf.c | 97 ++++++++++++++++++-- src/conf/domain_conf.h | 1 + src/uml/uml_conf.c | 5 + src/xenxs/xen_sxpr.c | 1 + .../qemuxml2argv-net-hostdevhybrid.args | 6 + .../qemuxml2argv-net-hostdevhybrid.xml | 35 +++++++ tests/qemuxml2xmltest.c | 1 + 9 files changed, 215 insertions(+), 10 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index f97c630..045e655 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2504,6 +2504,20 @@ guest instead of <interface type='hostdev'/>. </p> + <p> + Libvirt later than 0.9.13 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 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> @@ -2519,6 +2533,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 c85d763..2f95e91 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1597,6 +1597,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 ecad6cc..39b5cdb 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -289,7 +289,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", @@ -1023,6 +1024,10 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def) virDomainHostdevDefClear(&def->data.hostdev.def); VIR_FREE(def->data.hostdev.virtPortProfile); break; + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: + virDomainHostdevDefClear(&def->data.hostdev.def); + VIR_FREE(def->data.hostdev.virtPortProfile); + break; default: break; } @@ -1078,6 +1083,11 @@ void virDomainNetDefFree(virDomainNetDefPtr def) VIR_FREE(def->data.hostdev.virtPortProfile); break; + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: + virDomainHostdevDefClear(&def->data.hostdev.def); + VIR_FREE(def->data.hostdev.virtPortProfile); + break; + case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_LAST: break; @@ -4312,6 +4322,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"), @@ -4375,6 +4386,37 @@ virDomainActualNetDefParseXML(xmlNodePtr node, virNetDevVPortProfileParse(virtPortNode)))) { goto error; } + } else if (actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) { + xmlNodePtr virtPortNode = virXPathNode("./virtualport", ctxt); + virDomainHostdevDefPtr hostdev = &actual->data.hostdev.def; + + hostdev->parent.type = VIR_DOMAIN_DEVICE_NONE; + + if (VIR_ALLOC(hostdev->info) < 0) { + virReportOOMError(); + goto error; + } + /* 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; + } + + if (virtPortNode && + (!(actual->data.hostdev.virtPortProfile = + virNetDevVPortProfileParse(virtPortNode)))) { + goto error; + } } bandwidth_node = virXPathNode("./bandwidth", ctxt); @@ -4485,7 +4527,8 @@ virDomainNetDefParseXML(virCapsPtr caps, (def->type == VIR_DOMAIN_NET_TYPE_DIRECT || def->type == VIR_DOMAIN_NET_TYPE_NETWORK || def->type == VIR_DOMAIN_NET_TYPE_BRIDGE || - def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) && + def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || + def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) && xmlStrEqual(cur->name, BAD_CAST "virtualport")) { if (!(virtPort = virNetDevVPortProfileParse(cur))) goto error; @@ -4733,6 +4776,28 @@ virDomainNetDefParseXML(virCapsPtr caps, def->data.hostdev.virtPortProfile = virtPort; virtPort = NULL; 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; + } + 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; + } + def->data.hostdev.virtPortProfile = virtPort; + virtPort = NULL; + break; case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_LAST: @@ -7352,7 +7417,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); } @@ -7374,7 +7440,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. @@ -8675,8 +8742,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; } @@ -11486,7 +11555,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'"); } @@ -11525,6 +11595,7 @@ virDomainActualNetDefFormat(virBufferPtr buf, break; case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: virBufferAdjustIndent(buf, 8); if (virDomainHostdevSourceFormat(buf, &def->data.hostdev.def, flags, true) < 0) { @@ -11571,7 +11642,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'"); } @@ -11649,6 +11721,7 @@ virDomainNetDefFormat(virBufferPtr buf, break; case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: virBufferAdjustIndent(buf, 6); if (virDomainHostdevSourceFormat(buf, &def->data.hostdev.def, flags, true) < 0) { @@ -14982,10 +15055,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; @@ -15000,6 +15075,7 @@ virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface) case VIR_DOMAIN_NET_TYPE_BRIDGE: return iface->data.bridge.virtPortProfile; case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: return iface->data.hostdev.virtPortProfile; case VIR_DOMAIN_NET_TYPE_NETWORK: if (!iface->data.network.actual) @@ -15010,6 +15086,7 @@ virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface) case VIR_DOMAIN_NET_TYPE_BRIDGE: return iface->data.network.actual->data.bridge.virtPortProfile; case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: return iface->data.network.actual->data.hostdev.virtPortProfile; default: return NULL; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a2e4816..7bcaee4 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -710,6 +710,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 4c299d8..63fc27c 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -260,6 +260,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..398a0cd --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdevhybrid.args @@ -0,0 +1,6 @@ +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 -usb \ +-device pci-assign,host=03:07.1,id=hostdev0,bus=pci.0,addr=0x3 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 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/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index dcdba4f..46ad421 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -178,6 +178,7 @@ mymain(void) DO_TEST("net-eth-ifname"); DO_TEST("net-virtio-network-portgroup"); DO_TEST("net-hostdev"); + DO_TEST("net-hostdevhybrid"); DO_TEST("sound"); DO_TEST("sound-device"); DO_TEST("net-bandwidth"); -- 1.7.4.4

On 08/10/2012 10:24 AM, Shradha Shah wrote:
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. ---
I'm assuming Laine will resume reviewing this series. But in the meantime, it may help if you rebase the remaining patches, since a lot has gone in since you first posted.
+++ b/docs/formatdomain.html.in @@ -2504,6 +2504,20 @@ guest instead of <interface type='hostdev'/>. </p>
+ <p> + Libvirt later than 0.9.13 also supports "intelligent passthrough"
Rather than using 'later than 0.9.13', I'd use <span class="since">since 0.10.0</span>. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

I will be rebasing this remaining patch series this week. Many Thanks, Regards, Shradha Shah On 08/21/2012 11:34 PM, Eric Blake wrote:
On 08/10/2012 10:24 AM, Shradha Shah wrote:
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. ---
I'm assuming Laine will resume reviewing this series. But in the meantime, it may help if you rebase the remaining patches, since a lot has gone in since you first posted.
+++ b/docs/formatdomain.html.in @@ -2504,6 +2504,20 @@ guest instead of <interface type='hostdev'/>. </p>
+ <p> + Libvirt later than 0.9.13 also supports "intelligent passthrough"
Rather than using 'later than 0.9.13', I'd use <span class="since">since 0.10.0</span>.

This patch introduces the new forward mode='hostdev-hybrid' along with attribute managed Includes updates to the network RNG and new xml parser/formatter code. --- docs/schemas/network.rng | 1 + src/conf/network_conf.c | 12 ++++++++---- src/conf/network_conf.h | 1 + tests/networkxml2xmlin/hostdev-hybrid-pf.xml | 11 +++++++++++ tests/networkxml2xmlin/hostdev-hybrid.xml | 10 ++++++++++ tests/networkxml2xmlout/hostdev-hybrid-pf.xml | 7 +++++++ tests/networkxml2xmlout/hostdev-hybrid.xml | 10 ++++++++++ tests/networkxml2xmltest.c | 2 ++ 8 files changed, 50 insertions(+), 4 deletions(-) diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index d1297cd..0118b96 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -83,6 +83,7 @@ <value>private</value> <value>vepa</value> <value>hostdev</value> + <value>hostdev-hybrid</value> </choice> </attribute> </optional> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 294939d..f299a3d 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -49,7 +49,7 @@ VIR_ENUM_IMPL(virNetworkForward, VIR_NETWORK_FORWARD_LAST, - "none", "nat", "route", "bridge", "private", "vepa", "passthrough", "hostdev") + "none", "nat", "route", "bridge", "private", "vepa", "passthrough", "hostdev", "hostdev-hybrid") VIR_ENUM_DECL(virNetworkForwardHostdevDevice) VIR_ENUM_IMPL(virNetworkForwardHostdevDevice, @@ -173,7 +173,8 @@ void virNetworkDefFree(virNetworkDefPtr def) VIR_FREE(def->forwardPfs); for (ii = 0 ; ii < def->nForwardIfs && def->forwardIfs ; ii++) { - if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) + if ((def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) && + (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV_HYBRID)) virNetworkForwardIfDefClear(&def->forwardIfs[ii]); } VIR_FREE(def->forwardIfs); @@ -1274,6 +1275,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: case VIR_NETWORK_FORWARD_HOSTDEV: + case VIR_NETWORK_FORWARD_HOSTDEV_HYBRID: if (def->bridge) { virReportError(VIR_ERR_XML_ERROR, _("bridge name not allowed in %s mode (network '%s')"), @@ -1559,7 +1561,8 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags) } virBufferAddLit(&buf, " <forward"); virBufferEscapeString(&buf, " dev='%s'", dev); - if (def->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (def->forwardType == VIR_NETWORK_FORWARD_HOSTDEV || + def->forwardType == VIR_NETWORK_FORWARD_HOSTDEV_HYBRID) { if (def->managed == 1) virBufferAddLit(&buf, " managed='yes'"); else @@ -1576,7 +1579,8 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags) if (def->nForwardIfs && (!def->nForwardPfs || !(flags & VIR_NETWORK_XML_INACTIVE))) { for (ii = 0; ii < def->nForwardIfs; ii++) { - if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV) + if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV && + def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV_HYBRID) virBufferEscapeString(&buf, " <interface dev='%s'/>\n", def->forwardIfs[ii].device.dev); else { diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index a57db36..3348877 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -47,6 +47,7 @@ enum virNetworkForwardType { VIR_NETWORK_FORWARD_VEPA, VIR_NETWORK_FORWARD_PASSTHROUGH, VIR_NETWORK_FORWARD_HOSTDEV, + VIR_NETWORK_FORWARD_HOSTDEV_HYBRID, VIR_NETWORK_FORWARD_LAST, }; diff --git a/tests/networkxml2xmlin/hostdev-hybrid-pf.xml b/tests/networkxml2xmlin/hostdev-hybrid-pf.xml new file mode 100644 index 0000000..c4d2f93 --- /dev/null +++ b/tests/networkxml2xmlin/hostdev-hybrid-pf.xml @@ -0,0 +1,11 @@ +<network> + <name>hostdev-hybrid</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev-hybrid" managed="yes"> + <pf dev='eth2'/> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmlin/hostdev-hybrid.xml b/tests/networkxml2xmlin/hostdev-hybrid.xml new file mode 100644 index 0000000..29960aa --- /dev/null +++ b/tests/networkxml2xmlin/hostdev-hybrid.xml @@ -0,0 +1,10 @@ +<network> + <name>hostdev-hybrid</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev-hybrid" managed="yes"> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmlout/hostdev-hybrid-pf.xml b/tests/networkxml2xmlout/hostdev-hybrid-pf.xml new file mode 100644 index 0000000..0a0e2b4 --- /dev/null +++ b/tests/networkxml2xmlout/hostdev-hybrid-pf.xml @@ -0,0 +1,7 @@ +<network> + <name>hostdev-hybrid</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev-hybrid" managed="yes"> + <pf dev='eth2'/> + </forward> +</network> diff --git a/tests/networkxml2xmlout/hostdev-hybrid.xml b/tests/networkxml2xmlout/hostdev-hybrid.xml new file mode 100644 index 0000000..29960aa --- /dev/null +++ b/tests/networkxml2xmlout/hostdev-hybrid.xml @@ -0,0 +1,10 @@ +<network> + <name>hostdev-hybrid</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode="hostdev-hybrid" managed="yes"> + <address type='pci' domain='0' bus='3' slot='0' function='1'/> + <address type='pci' domain='0' bus='3' slot='0' function='2'/> + <address type='pci' domain='0' bus='3' slot='0' function='3'/> + <address type='pci' domain='0' bus='3' slot='0' function='4'/> + </forward> +</network> diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index c9c8311..bd08db5 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -107,6 +107,8 @@ mymain(void) DO_TEST_FULL("passthrough-pf", VIR_NETWORK_XML_INACTIVE); DO_TEST("hostdev"); DO_TEST_FULL("hostdev-pf", VIR_NETWORK_XML_INACTIVE); + DO_TEST("hostdev-hybrid"); + DO_TEST_FULL("hostdev-hybrid-pf", VIR_NETWORK_XML_INACTIVE); return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.7.4.4

In this mode the guest contains a Virtual network device along with a SRIOV VF passed through to the guest as a pci device. --- src/conf/domain_conf.c | 37 +++++++++++++++++++++++++++++++++++-- src/conf/domain_conf.h | 5 +++++ src/libvirt_private.syms | 1 + src/util/pci.c | 2 +- src/util/pci.h | 2 ++ src/util/virnetdev.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/util/virnetdev.h | 6 ++++++ 7 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 39b5cdb..e73c07d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1025,6 +1025,7 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def) VIR_FREE(def->data.hostdev.virtPortProfile); break; case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: + VIR_FREE(def->data.hostdev.linkdev); virDomainHostdevDefClear(&def->data.hostdev.def); VIR_FREE(def->data.hostdev.virtPortProfile); break; @@ -1084,6 +1085,7 @@ void virDomainNetDefFree(virDomainNetDefPtr def) break; case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: + VIR_FREE(def->data.hostdev.linkdev); virDomainHostdevDefClear(&def->data.hostdev.def); VIR_FREE(def->data.hostdev.virtPortProfile); break; @@ -4475,6 +4477,7 @@ virDomainNetDefParseXML(virCapsPtr caps, char *mode = NULL; char *linkstate = NULL; char *addrtype = NULL; + char *pfname = NULL; virNWFilterHashTablePtr filterparams = NULL; virNetDevVPortProfilePtr virtPort = NULL; virDomainActualNetDefPtr actual = NULL; @@ -4795,6 +4798,26 @@ virDomainNetDefParseXML(virCapsPtr caps, hostdev, flags) < 0) { goto error; } + if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { + if (virNetDevGetPhysicalFunctionFromVfPciAddr(hostdev->source.subsys.u.pci.domain, + hostdev->source.subsys.u.pci.bus, + hostdev->source.subsys.u.pci.slot, + hostdev->source.subsys.u.pci.function, + &pfname) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get Physical Function of the hostdev")); + goto error; + } + } + if (pfname != NULL) + def->data.hostdev.linkdev = strdup(pfname); + else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Linkdev is required in %s mode"), + virDomainNetTypeToString(def->type)); + goto error; + } + def->data.hostdev.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE; def->data.hostdev.virtPortProfile = virtPort; virtPort = NULL; break; @@ -15033,11 +15056,16 @@ virDomainNetGetActualDirectDev(virDomainNetDefPtr iface) { if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT) return iface->data.direct.linkdev; + if (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) + return iface->data.hostdev.linkdev; if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) return NULL; if (!iface->data.network.actual) return NULL; - return iface->data.network.actual->data.direct.linkdev; + if (iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) + return iface->data.network.actual->data.hostdev.linkdev; + else + return iface->data.network.actual->data.direct.linkdev; } int @@ -15045,11 +15073,16 @@ virDomainNetGetActualDirectMode(virDomainNetDefPtr iface) { if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT) return iface->data.direct.mode; + if (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) + return iface->data.hostdev.mode; if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) return 0; if (!iface->data.network.actual) return 0; - return iface->data.network.actual->data.direct.mode; + if (iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) + return iface->data.network.actual->data.hostdev.mode; + else + return iface->data.network.actual->data.direct.mode; } virDomainHostdevDefPtr diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7bcaee4..053c71c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -43,6 +43,7 @@ # include "virnetdevvportprofile.h" # include "virnetdevopenvswitch.h" # include "virnetdevbandwidth.h" +# include "virnetdev.h" # include "virobject.h" # include "device_conf.h" @@ -762,6 +763,8 @@ struct _virDomainActualNetDef { virNetDevVPortProfilePtr virtPortProfile; } direct; struct { + char *linkdev; + int mode; virDomainHostdevDef def; virNetDevVPortProfilePtr virtPortProfile; } hostdev; @@ -819,6 +822,8 @@ struct _virDomainNetDef { virNetDevVPortProfilePtr virtPortProfile; } direct; struct { + char *linkdev; + int mode; virDomainHostdevDef def; virNetDevVPortProfilePtr virtPortProfile; } hostdev; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f752f49..fae69ef 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1366,6 +1366,7 @@ virNetDevGetMTU; virNetDevGetPhysicalFunction; virNetDevGetVLanID; virNetDevGetVirtualFunctionIndex; +virNetDevGetPhysicalFunctionFromVfPciAddr; virNetDevGetVirtualFunctionInfo; virNetDevGetVirtualFunctions; virNetDevIsOnline; diff --git a/src/util/pci.c b/src/util/pci.c index 137521b..5bf1758 100644 --- a/src/util/pci.c +++ b/src/util/pci.c @@ -803,7 +803,7 @@ pciDriverFile(char **buffer, const char *driver, const char *file) return 0; } -static int +int pciDeviceFile(char **buffer, const char *device, const char *file) { VIR_FREE(*buffer); diff --git a/src/util/pci.h b/src/util/pci.h index 8bbab07..936fee4 100644 --- a/src/util/pci.h +++ b/src/util/pci.h @@ -116,6 +116,8 @@ int pciConfigAddressToSysfsFile(struct pci_config_address *dev, int pciDeviceNetName(char *device_link_sysfs_path, char **netname); +int pciDeviceFile(char **buffer, const char *device, const char *file); + int pciSysfsFile(char *pciDeviceName, char **pci_sysfs_device_link) ATTRIBUTE_RETURN_CHECK; diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 8103aff..46d0cda 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1099,6 +1099,46 @@ virNetDevGetVirtualFunctionIndex(const char *pfname, const char *vfname, } /** + * virNetDevGetPhyscialFunctionFromVfPciAddr + * + * @domain : Domain part of VF PCI addr + * @bus : Bus part of VF PCI addr + * @slot : Slot part of VF PCI addr + * @function : Function part of VF PCI addr + * @pfname : Contains sriov physical function for Vf upon + * successful return + * + * Returns 0 on success, -1 on failure + * + */ +int +virNetDevGetPhysicalFunctionFromVfPciAddr(unsigned domain, + unsigned bus, + unsigned slot, + unsigned function, + char **pfname) +{ + char *pciConfigAddr; + char *physfn_sysfs_path = NULL; + int ret = -1; + + if (pciGetDeviceAddrString(domain, bus, slot, function, + &pciConfigAddr) < 0) { + goto cleanup; + } + if (pciDeviceFile(&physfn_sysfs_path, pciConfigAddr, "physfn") < 0) { + goto cleanup; + } + ret = pciDeviceNetName(physfn_sysfs_path, pfname); + +cleanup: + VIR_FREE(pciConfigAddr); + VIR_FREE(physfn_sysfs_path); + + return ret; +} + +/** * virNetDevGetPhysicalFunction * * @ifname : name of the physical function interface name diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index 705ad9c..66b57db 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -99,6 +99,12 @@ int virNetDevGetVirtualFunctionIndex(const char *pfname, const char *vfname, ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK; +int virNetDevGetPhysicalFunctionFromVfPciAddr(unsigned domain, unsigned bus, + unsigned slot, unsigned function, + char **pfname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) + ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK; + int virNetDevGetPhysicalFunction(const char *ifname, char **pfname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; -- 1.7.4.4

The parent type for hostdev hybrid needs to be VIR_DOMAIN_DEVICE_NONE as the device is passed into the guest as a PCI Device. In order to store the information of the NETDEV that is the parent of the HOSTDEV in question we use a new variable actualParent. This variable also helps during VF MAC address, vlan and virtportprofile configuration. ActualParent = Parent in case of forward mode="hostdev" --- src/conf/domain_conf.c | 8 ++++ src/conf/domain_conf.h | 1 + src/qemu/qemu_hostdev.c | 91 +++++++++++++++++++++++++++++++++-------------- src/qemu/qemu_hotplug.c | 2 +- 4 files changed, 74 insertions(+), 28 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e73c07d..361850a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4366,6 +4366,8 @@ virDomainActualNetDefParseXML(xmlNodePtr node, hostdev->parent.type = VIR_DOMAIN_DEVICE_NET; hostdev->parent.data.net = parent; + hostdev->actualParent.type = VIR_DOMAIN_DEVICE_NET; + hostdev->actualParent.data.net = parent; hostdev->info = &parent->info; /* The helper function expects type to already be found and * passed in as a string, since it is in a different place in @@ -4393,6 +4395,8 @@ virDomainActualNetDefParseXML(xmlNodePtr node, virDomainHostdevDefPtr hostdev = &actual->data.hostdev.def; hostdev->parent.type = VIR_DOMAIN_DEVICE_NONE; + hostdev->actualParent.type = VIR_DOMAIN_DEVICE_NET; + hostdev->actualParent.data.net = parent; if (VIR_ALLOC(hostdev->info) < 0) { virReportOOMError(); @@ -4760,6 +4764,8 @@ virDomainNetDefParseXML(virCapsPtr caps, hostdev = &def->data.hostdev.def; hostdev->parent.type = VIR_DOMAIN_DEVICE_NET; hostdev->parent.data.net = def; + hostdev->actualParent.type = VIR_DOMAIN_DEVICE_NET; + hostdev->actualParent.data.net = def; hostdev->info = &def->info; /* The helper function expects type to already be found and * passed in as a string, since it is in a different place in @@ -4783,6 +4789,8 @@ virDomainNetDefParseXML(virCapsPtr caps, case VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID: hostdev = &def->data.hostdev.def; hostdev->parent.type = VIR_DOMAIN_DEVICE_NONE; + hostdev->actualParent.type = VIR_DOMAIN_DEVICE_NET; + hostdev->actualParent.data.net = def; if (VIR_ALLOC(hostdev->info) < 0) { virReportOOMError(); goto error; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 053c71c..4584671 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -368,6 +368,7 @@ struct _virDomainHostdevSubsys { /* basic device for direct passthrough */ struct _virDomainHostdevDef { virDomainDeviceDef parent; /* higher level Def containing this */ + virDomainDeviceDef actualParent; /*used only in the case of hybrid hostdev*/ int mode; /* enum virDomainHostdevMode */ unsigned int managed : 1; union { diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 7619fd0..d2712f4 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -319,17 +319,36 @@ qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0) return ret; - virtPort = virDomainNetGetActualVirtPortProfile( - hostdev->parent.data.net); - if (virtPort) - ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, - virtPort, &hostdev->parent.data.net->mac, uuid, - port_profile_associate); - else - /* Set only mac */ - ret = virNetDevReplaceNetConfig(linkdev, vf, - &hostdev->parent.data.net->mac, vlanid, - stateDir); + if (hostdev->parent.data.net) { + virtPort = virDomainNetGetActualVirtPortProfile(hostdev->parent.data.net); + if (virtPort) + ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, + virtPort, + &hostdev->parent.data.net->mac, + uuid, + port_profile_associate); + else + /* Set only mac */ + ret = virNetDevReplaceNetConfig(linkdev, vf, + &hostdev->parent.data.net->mac, + vlanid, + stateDir); + } + else if (hostdev->actualParent.data.net) { + virtPort = virDomainNetGetActualVirtPortProfile(hostdev->actualParent.data.net); + if (virtPort) + ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, + virtPort, + &hostdev->actualParent.data.net->mac, + uuid, + port_profile_associate); + else + /* Set only mac */ + ret = virNetDevReplaceNetConfig(linkdev, vf, + &hostdev->actualParent.data.net->mac, + vlanid, + stateDir); + } VIR_FREE(linkdev); return ret; @@ -357,17 +376,29 @@ qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0) return ret; - virtPort = virDomainNetGetActualVirtPortProfile( - hostdev->parent.data.net); - if (virtPort) - ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, - &hostdev->parent.data.net->mac, NULL, - port_profile_associate); - else - ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir); - + if (hostdev->parent.data.net) { + virtPort = virDomainNetGetActualVirtPortProfile(hostdev->parent.data.net); + if (virtPort) + ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, + &hostdev->parent.data.net->mac, + NULL, + port_profile_associate); + else + ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir); + } + if (hostdev->actualParent.data.net) { + virtPort = virDomainNetGetActualVirtPortProfile(hostdev->actualParent.data.net); + if (virtPort) + ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, + &hostdev->actualParent.data.net->mac, + NULL, + port_profile_associate); + else + ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir); + } + VIR_FREE(linkdev); - + return ret; } @@ -450,8 +481,10 @@ int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver, continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; - if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && - hostdev->parent.data.net) { + if ((hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && + hostdev->parent.data.net) || + (hostdev->actualParent.type == VIR_DOMAIN_DEVICE_NET && + hostdev->actualParent.data.net)) { if (qemuDomainHostdevNetConfigReplace(hostdev, uuid, driver->stateDir) < 0) { goto resetvfnetconfig; @@ -540,8 +573,10 @@ inactivedevs: resetvfnetconfig: for (i = 0; i < last_processed_hostdev_vf; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; - if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && - hostdev->parent.data.net) { + if ((hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && + hostdev->parent.data.net) || + (hostdev->actualParent.type == VIR_DOMAIN_DEVICE_NET && + hostdev->actualParent.data.net)) { qemuDomainHostdevNetConfigRestore(hostdev, driver->stateDir); } } @@ -799,8 +834,10 @@ void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver, continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; - if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && - hostdev->parent.data.net) { + if ((hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && + hostdev->parent.data.net) || + (hostdev->actualParent.type == VIR_DOMAIN_DEVICE_NET && + hostdev->actualParent.data.net)) { qemuDomainHostdevNetConfigRestore(hostdev, driver->stateDir); } } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 3eeeb29..1822289 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1994,7 +1994,7 @@ qemuDomainDetachHostPciDevice(struct qemud_driver *driver, * For SRIOV net host devices, unset mac and port profile before * reset and reattach device */ - if (detach->parent.data.net) + if (detach->parent.data.net || detach->actualParent.data.net) qemuDomainHostdevNetConfigRestore(detach, driver->stateDir); pci = pciGetDevice(subsys->u.pci.domain, subsys->u.pci.bus, -- 1.7.4.4

The ephemeral flag is checked along with the hostdev parent type before freeing a hostdev. Additionally Hostdev-Hybrid mode supports live migration with PCI Passthrough. Ephemeral flag plays a very important role in the upcoming migration suppot patch. --- include/libvirt/libvirt.h.in | 1 + src/conf/domain_conf.c | 6 +++++- src/conf/domain_conf.h | 1 + src/qemu/qemu_hotplug.c | 3 ++- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index d21d029..6c68fdd 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1631,6 +1631,7 @@ typedef enum { VIR_DOMAIN_XML_SECURE = (1 << 0), /* dump security sensitive information too */ VIR_DOMAIN_XML_INACTIVE = (1 << 1), /* dump inactive domain information */ VIR_DOMAIN_XML_UPDATE_CPU = (1 << 2), /* update guest CPU requirements according to host CPU */ + VIR_DOMAIN_XML_NO_EPHEMERAL_DEVICES = (1 << 24), /* Do not include ephemeral devices */ } virDomainXMLFlags; char * virDomainGetXMLDesc (virDomainPtr domain, diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 361850a..00624ee 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1544,7 +1544,9 @@ void virDomainDefFree(virDomainDefPtr def) * to virDomainHostdevDefFree(). */ for (i = 0 ; i < def->nhostdevs ; i++) - virDomainHostdevDefFree(def->hostdevs[i]); + if (def->hostdevs[i]->ephemeral == 0) { + virDomainHostdevDefFree(def->hostdevs[i]); + } VIR_FREE(def->hostdevs); for (i = 0 ; i < def->nleases ; i++) @@ -4402,6 +4404,7 @@ virDomainActualNetDefParseXML(xmlNodePtr node, 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. @@ -4795,6 +4798,7 @@ virDomainNetDefParseXML(virCapsPtr caps, 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) && diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4584671..f88363a 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -371,6 +371,7 @@ struct _virDomainHostdevDef { virDomainDeviceDef actualParent; /*used only in the case of hybrid hostdev*/ int mode; /* enum virDomainHostdevMode */ unsigned int managed : 1; + unsigned int ephemeral: 1; union { virDomainHostdevSubsys subsys; struct { diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 1822289..0fd506e 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -2107,7 +2107,8 @@ int qemuDomainDetachThisHostDevice(struct qemud_driver *driver, VIR_WARN("Failed to restore host device labelling"); } virDomainHostdevRemove(vm->def, idx); - virDomainHostdevDefFree(detach); + if (detach->ephemeral == 0) + virDomainHostdevDefFree(detach); } return ret; } -- 1.7.4.4

This patch updates the network driver to properly utilize the new attributes/elements that are now in virNetworkDef --- src/network/bridge_driver.c | 139 +++++++++++++++++++++++++++++++++++++----- 1 files changed, 122 insertions(+), 17 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 33bc09e..457716c 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1934,9 +1934,9 @@ networkStartNetworkExternal(struct network_driver *driver ATTRIBUTE_UNUSED, virNetworkObjPtr network ATTRIBUTE_UNUSED) { /* put anything here that needs to be done each time a network of - * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On - * failure, undo anything you've done, and return -1. On success - * return 0. + * type BRIDGE, PRIVATE, VEPA, HOSTDEV, HOSTDEV-HYBRID or PASSTHROUGH + * is started. On failure, undo anything you've done, and return -1. + * On success return 0. */ return 0; } @@ -1945,9 +1945,9 @@ static int networkShutdownNetworkExternal(struct network_driver *driver ATTRIBUT virNetworkObjPtr network ATTRIBUTE_UNUSED) { /* put anything here that needs to be done each time a network of - * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On - * failure, undo anything you've done, and return -1. On success - * return 0. + * type BRIDGE, PRIVATE, VEPA, HOSTDEV, HOSTDEV-HYBRID or PASSTHROUGH + * is shutdown. On failure, undo anything you've done, and return -1. + * On success return 0. */ return 0; } @@ -1977,6 +1977,7 @@ networkStartNetwork(struct network_driver *driver, case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: case VIR_NETWORK_FORWARD_HOSTDEV: + case VIR_NETWORK_FORWARD_HOSTDEV_HYBRID: ret = networkStartNetworkExternal(driver, network); break; } @@ -2037,6 +2038,7 @@ static int networkShutdownNetwork(struct network_driver *driver, case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: case VIR_NETWORK_FORWARD_HOSTDEV: + case VIR_NETWORK_FORWARD_HOSTDEV_HYBRID: ret = networkShutdownNetworkExternal(driver, network); break; } @@ -2780,7 +2782,8 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { goto finish; } } - if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV || + netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV_HYBRID) { netdef->forwardIfs[ii].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI; /*Assuming PCI as VF's are PCI devices */ netdef->forwardIfs[ii].device.pci.domain = virt_fns[ii]->domain; netdef->forwardIfs[ii].device.pci.bus = virt_fns[ii]->bus; @@ -2925,6 +2928,8 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) } iface->data.network.actual->data.hostdev.def.parent.type = VIR_DOMAIN_DEVICE_NET; iface->data.network.actual->data.hostdev.def.parent.data.net = iface; + iface->data.network.actual->data.hostdev.def.actualParent.type = VIR_DOMAIN_DEVICE_NET; + iface->data.network.actual->data.hostdev.def.actualParent.data.net = iface; iface->data.network.actual->data.hostdev.def.info = &iface->info; iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; iface->data.network.actual->data.hostdev.def.managed = netdef->managed; @@ -2958,6 +2963,97 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) dev->device.pci.function, dev->usageCount); + } else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV_HYBRID) { + char *pfname = NULL; + if (!iface->data.network.actual + && (VIR_ALLOC(iface->data.network.actual) < 0)) { + virReportOOMError(); + goto cleanup; + } + iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID; + + if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { + if(networkCreateInterfacePool(netdef) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create Interface Pool from PF")); + goto cleanup; + } + } + /* pick first dev with 0 usageCount */ + + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (netdef->forwardIfs[ii].usageCount == 0) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + if (!dev) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("network '%s' requires exclusive access to interfaces, but none are available"), + netdef->name); + goto cleanup; + } + iface->data.network.actual->data.hostdev.def.parent.type = VIR_DOMAIN_DEVICE_NONE; + iface->data.network.actual->data.hostdev.def.actualParent.type = VIR_DOMAIN_DEVICE_NET; + iface->data.network.actual->data.hostdev.def.actualParent.data.net = iface; + + if (VIR_ALLOC(iface->data.network.actual->data.hostdev.def.info) < 0) { + virReportOOMError(); + goto cleanup; + } + iface->data.network.actual->data.hostdev.def.ephemeral = 1; + + iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + iface->data.network.actual->data.hostdev.def.managed = netdef->managed; + iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type; + iface->data.network.actual->data.hostdev.def.source.subsys.u.pci = dev->device.pci; + + if (virNetDevGetPhysicalFunctionFromVfPciAddr(dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + &pfname) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get Physical function of the selected VF")); + goto cleanup; + } + + if (pfname != NULL) + iface->data.network.actual->data.hostdev.linkdev = strdup(pfname); + else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Linkdev is required in hostdev-hybrid mode")); + goto cleanup; + } + iface->data.network.actual->data.hostdev.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE; + + if (iface->data.network.virtPortProfile) { + virtport = iface->data.network.virtPortProfile; + } else { + if (portgroup) + virtport = portgroup->virtPortProfile; + else + virtport = netdef->virtPortProfile; + } + if (virtport) { + if (VIR_ALLOC(iface->data.network.actual->data.hostdev.virtPortProfile) < 0) { + virReportOOMError(); + goto cleanup; + } + /* There are no pointers in a virtualPortProfile, so a shallow copy + * is sufficient + */ + *iface->data.network.actual->data.direct.virtPortProfile = *virtport; + } + + dev->usageCount++; + VIR_DEBUG("Using physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount); + } else if ((netdef->forwardType == VIR_NETWORK_FORWARD_BRIDGE) || (netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) || (netdef->forwardType == VIR_NETWORK_FORWARD_VEPA) || @@ -3121,7 +3217,8 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) if (!iface->data.network.actual || ((virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT) && - (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV))) { + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV) && + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID))) { VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name); return 0; } @@ -3145,7 +3242,8 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) } } - if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { def = virDomainNetGetActualHostdev(iface); if (!def) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -3174,7 +3272,8 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) } } - if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { if(networkCreateInterfacePool(netdef) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -3201,13 +3300,14 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) goto cleanup; } - /* PASSTHROUGH mode, HOSTDEV mode and PRIVATE Mode + 802.1Qbh both require - * exclusive access to a device, so current usageCount must be + /* PASSTHROUGH mode, HOSTDEV mode, HOSTDEV-HYBRIDand PRIVATE Mode + 802.1Qbh + * both require exclusive access to a device, so current usageCount must be * 0 in those cases. */ if ((dev->usageCount > 0) && ((netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) || (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) || + (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV_HYBRID) || ((netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) && iface->data.network.actual->data.direct.virtPortProfile && (iface->data.network.actual->data.direct.virtPortProfile->virtPortType @@ -3223,7 +3323,8 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) VIR_DEBUG("Using physical device %s, usageCount %d", dev->device.dev, dev->usageCount); } - if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { VIR_DEBUG("Using physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", dev->device.pci.domain, dev->device.pci.bus, @@ -3266,7 +3367,8 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) if (!iface->data.network.actual || ((virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT) && - (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV))) { + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV) && + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID))) { VIR_DEBUG("Nothing to release to network %s", iface->data.network.name); ret = 0; goto cleanup; @@ -3291,7 +3393,8 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) } } - if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { def = virDomainNetGetActualHostdev(iface); if (!def) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -3320,7 +3423,8 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) } } - if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { for (ii = 0; ii < netdef->nForwardIfs; ii++) { if((def->source.subsys.u.pci.domain == netdef->forwardIfs[ii].device.pci.domain) && (def->source.subsys.u.pci.bus == netdef->forwardIfs[ii].device.pci.bus) && @@ -3345,7 +3449,8 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) VIR_DEBUG("Releasing physical device %s, usageCount %d", dev->device.dev, dev->usageCount); } - if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { VIR_DEBUG("Releasing physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", dev->device.pci.domain, dev->device.pci.bus, -- 1.7.4.4

--- src/qemu/qemu_command.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_hotplug.c | 23 ++++++++++++++++-- src/qemu/qemu_process.c | 3 +- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index bb66364..d67394e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -27,6 +27,7 @@ #include "qemu_hostdev.h" #include "qemu_capabilities.h" #include "qemu_bridge_filter.h" +#include "qemu_hostdev.h" #include "cpu/cpu.h" #include "memory.h" #include "logging.h" @@ -4330,10 +4331,16 @@ qemuBuildCommandLine(virConnectPtr conn, bool emitBootindex = false; int usbcontroller = 0; bool usblegacy = false; + + virDomainObjPtr vm = NULL; + virDomainObjListPtr doms = &driver->domains; + uname_normalize(&ut); virUUIDFormat(def->uuid, uuid); + vm = virHashLookup(doms->objs, uuid); + emulator = def->emulator; /* @@ -5257,6 +5264,58 @@ qemuBuildCommandLine(virConnectPtr conn, continue; } + if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) { + virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net); + virDomainHostdevDefPtr found; + if (vmop == VIR_NETDEV_VPORT_PROFILE_OP_CREATE) { + if (qemuAssignDeviceHostdevAlias(def, + hostdev, + (def->nhostdevs-1)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not assign alias to Net Hostdev")); + goto error; + } + + if (virDomainHostdevFind(def, + hostdev, + &found) < 0) { + qemuDomainObjPrivatePtr priv = vm->privateData; + if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, + hostdev->info) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not assign PCI addr to Hostdev hybrid")); + goto error; + } + + if (virDomainHostdevInsert(def, + hostdev) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Hostdev not inserted into the array")); + goto error; + } + + if (qemuPrepareHostdevPCIDevices(driver, def->name, + def->uuid, &hostdev, 1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Prepare Hostdev PCI Devices failed")); + goto error; + } + } + } + + int tapfd = qemuPhysIfaceConnect(def, driver, net, + qemuCaps, vmop); + if (tapfd < 0) + goto error; + + last_good_net = i; + virCommandTransferFD(cmd, tapfd); + + if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", + tapfd) >= sizeof(tapfd_name)) + goto no_memory; + } + if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { /* diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 0fd506e..3586d3e 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -694,6 +694,21 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, goto cleanup; } + if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) { + ret = qemuDomainAttachHostDevice(driver, vm, + virDomainNetGetActualHostdev(net)); + if (ret < 0) + goto cleanup; + + if ((tapfd = qemuPhysIfaceConnect(vm->def, driver, net, + priv->qemuCaps, + VIR_NETDEV_VPORT_PROFILE_OP_CREATE)) < 0) + goto cleanup; + iface_connected = true; + if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0) + goto cleanup; + } + if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { /* @@ -2198,7 +2213,8 @@ qemuDomainDetachNetDevice(struct qemud_driver *driver, goto cleanup; } - if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + if ((virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { ret = qemuDomainDetachThisHostDevice(driver, vm, virDomainNetGetActualHostdev(detach), -1); @@ -2270,8 +2286,9 @@ qemuDomainDetachNetDevice(struct qemud_driver *driver, VIR_WARN("Unable to release PCI address on NIC"); virDomainConfNWFilterTeardown(detach); - - if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_DIRECT) { + + if ((virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_DIRECT) || + (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { ignore_value(virNetDevMacVLanDeleteWithVPortProfile( detach->ifname, &detach->mac, virDomainNetGetActualDirectDev(detach), diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index df4a016..9f9a5d2 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4098,7 +4098,8 @@ void qemuProcessStop(struct qemud_driver *driver, def = vm->def; for (i = 0; i < def->nnets; i++) { virDomainNetDefPtr net = def->nets[i]; - if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) { + if ((virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) || + (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID)) { ignore_value(virNetDevMacVLanDeleteWithVPortProfile( net->ifname, &net->mac, virDomainNetGetActualDirectDev(net), -- 1.7.4.4

--- src/conf/domain_conf.c | 24 +++++++++++++++++++----- src/qemu/qemu_domain.c | 6 +++++- src/qemu/qemu_domain.h | 3 ++- src/qemu/qemu_driver.c | 6 +++--- src/qemu/qemu_hostdev.c | 6 ++++++ src/qemu/qemu_migration.c | 4 ++-- 6 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 00624ee..1005265 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -12759,7 +12759,8 @@ virDomainDefFormatInternal(virDomainDefPtr def, virCheckFlags(DUMPXML_FLAGS | VIR_DOMAIN_XML_INTERNAL_STATUS | VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET | - VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES, + VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES | + VIR_DOMAIN_XML_NO_EPHEMERAL_DEVICES, -1); if (!(type = virDomainVirtTypeToString(def->virtType))) { @@ -13216,10 +13217,22 @@ virDomainDefFormatInternal(virDomainDefPtr def, /* If parent.type != NONE, this is just a pointer to the * hostdev in a higher-level device (e.g. virDomainNetDef), * and will have already been formatted there. + * Hostdevs marked as ephemeral are hybrid hostdevs and + * should not be formatted. */ - if (def->hostdevs[n]->parent.type == VIR_DOMAIN_DEVICE_NONE && - virDomainHostdevDefFormat(buf, def->hostdevs[n], flags) < 0) { - goto cleanup; + if (def->hostdevs[n]->parent.type == VIR_DOMAIN_DEVICE_NONE) { + if ((flags & VIR_DOMAIN_XML_NO_EPHEMERAL_DEVICES) == 0) { + if (virDomainHostdevDefFormat(buf, def->hostdevs[n], flags) < 0) { + goto cleanup; + } + } + else { + if (def->hostdevs[n]->ephemeral == 0) { + if (virDomainHostdevDefFormat(buf, def->hostdevs[n], flags) < 0) { + goto cleanup; + } + } + } } } @@ -13267,7 +13280,8 @@ virDomainDefFormat(virDomainDefPtr def, unsigned int flags) { virBuffer buf = VIR_BUFFER_INITIALIZER; - virCheckFlags(DUMPXML_FLAGS, NULL); + virCheckFlags(DUMPXML_FLAGS | VIR_DOMAIN_XML_NO_EPHEMERAL_DEVICES, + NULL); if (virDomainDefFormatInternal(def, flags, &buf) < 0) return NULL; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index c47890b..447ec24 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1335,12 +1335,16 @@ char * qemuDomainDefFormatLive(struct qemud_driver *driver, virDomainDefPtr def, bool inactive, - bool compatible) + bool compatible, + bool ephemeral) { unsigned int flags = QEMU_DOMAIN_FORMAT_LIVE_FLAGS; if (inactive) flags |= VIR_DOMAIN_XML_INACTIVE; + + if (ephemeral) + flags |= VIR_DOMAIN_XML_NO_EPHEMERAL_DEVICES; return qemuDomainDefFormatXML(driver, def, flags, compatible); } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index b96087e..8e707a5 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -268,7 +268,8 @@ char *qemuDomainFormatXML(struct qemud_driver *driver, char *qemuDomainDefFormatLive(struct qemud_driver *driver, virDomainDefPtr def, bool inactive, - bool compatible); + bool compatible, + bool ephemeral); void qemuDomainObjTaint(struct qemud_driver *driver, virDomainObjPtr obj, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9bf89bb..e879d6e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2683,9 +2683,9 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom, virDomainDefFree(def); goto endjob; } - xml = qemuDomainDefFormatLive(driver, def, true, true); + xml = qemuDomainDefFormatLive(driver, def, true, true, false); } else { - xml = qemuDomainDefFormatLive(driver, vm->def, true, true); + xml = qemuDomainDefFormatLive(driver, vm->def, true, true, false); } if (!xml) { virReportError(VIR_ERR_OPERATION_FAILED, @@ -10607,7 +10607,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, } else { /* Easiest way to clone inactive portion of vm->def is via * conversion in and back out of xml. */ - if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, false)) || + if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, false, false)) || !(def->dom = virDomainDefParseString(driver->caps, xml, QEMU_EXPECTED_VIRT_TYPES, VIR_DOMAIN_XML_INACTIVE))) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index d2712f4..743d809 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -50,6 +50,8 @@ qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; + if (hostdev->ephemeral == 1) + continue; dev = pciGetDevice(hostdev->source.subsys.u.pci.domain, hostdev->source.subsys.u.pci.bus, @@ -92,6 +94,8 @@ qemuGetActivePciHostDeviceList(struct qemud_driver *driver, continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; + if (hostdev->ephemeral == 1) + continue; dev = pciGetDevice(hostdev->source.subsys.u.pci.domain, hostdev->source.subsys.u.pci.bus, @@ -133,6 +137,8 @@ int qemuUpdateActivePciHostdevs(struct qemud_driver *driver, continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; + if (hostdev->ephemeral == 1) + continue; dev = pciGetDevice(hostdev->source.subsys.u.pci.domain, hostdev->source.subsys.u.pci.bus, diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index f65c81a..d8aefa0 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1166,9 +1166,9 @@ char *qemuMigrationBegin(struct qemud_driver *driver, if (!virDomainDefCheckABIStability(vm->def, def)) goto cleanup; - rv = qemuDomainDefFormatLive(driver, def, false, true); + rv = qemuDomainDefFormatLive(driver, def, false, true, true); } else { - rv = qemuDomainDefFormatLive(driver, vm->def, false, true); + rv = qemuDomainDefFormatLive(driver, vm->def, false, true, true); } cleanup: -- 1.7.4.4

This patch uses the ephemeral flag to prevent the hybrid hostdev from being formatted into the xml. Before migration the hybrid hostdev is hot unplugged and hotplugged again after migration is the specific hostdev is available on the destination host. --- src/qemu/qemu_migration.c | 102 ++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 97 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index d8aefa0..21894e8 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -31,6 +31,7 @@ #include "qemu_monitor.h" #include "qemu_domain.h" #include "qemu_process.h" +#include "qemu_hotplug.h" #include "qemu_capabilities.h" #include "qemu_cgroup.h" @@ -49,6 +50,7 @@ #include "storage_file.h" #include "viruri.h" #include "hooks.h" +#include "network/bridge_driver.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -122,6 +124,79 @@ struct _qemuMigrationCookie { virDomainDefPtr persistent; }; +static void +qemuMigrationRemoveEphemeralDevices(struct qemud_driver *driver, + virDomainObjPtr vm) +{ + virDomainHostdevDefPtr dev; + virDomainDeviceDef def; + unsigned int i; + + for (i = 0; i < vm->def->nhostdevs; i++) { + dev = vm->def->hostdevs[i]; + if (dev->ephemeral == 1) { + def.type = VIR_DOMAIN_DEVICE_HOSTDEV; + def.data.hostdev = dev; + + if (qemuDomainDetachHostDevice(driver, vm, &def) >= 0) { + continue; /* nhostdevs reduced */ + } + } + } +} + +static void +qemuMigrationRestoreEphemeralDevices(struct qemud_driver *driver, + virDomainObjPtr vm) +{ + virDomainNetDefPtr net; + unsigned int i; + + /* Do nothing if ephemeral devices are present in which case this + function was called before qemuMigrationRemoveEphemeralDevices */ + + for (i = 0; i < vm->def->nhostdevs; i++) { + if (vm->def->hostdevs[i]->ephemeral == 1) + return; + } + + for (i = 0; i < vm->def->nnets; i++) { + net = vm->def->nets[i]; + + if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) { + if (qemuDomainAttachHostDevice(driver, vm, + virDomainNetGetActualHostdev(net)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Hybrid Hostdev cannot be attached after migration")); + networkReleaseActualDevice(net); + } + } + return; + } +} + +static void +qemuMigrationAttachEphemeralDevices(struct qemud_driver *driver, + virDomainObjPtr vm) +{ + virDomainNetDefPtr net; + unsigned int i; + + for (i = 0; i < vm->def->nnets; i++) { + net = vm->def->nets[i]; + + if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV_HYBRID) { + if (qemuDomainAttachHostDevice(driver, vm, + virDomainNetGetActualHostdev(net)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Hybrid Hostdev cannot be attached after migration")); + networkReleaseActualDevice(net); + } + } + } + return; +} + static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap) { if (!grap) @@ -800,6 +875,7 @@ qemuMigrationIsAllowed(struct qemud_driver *driver, virDomainObjPtr vm, virDomainDefPtr def) { int nsnapshots; + unsigned int i; if (vm) { if (qemuProcessAutoDestroyActive(driver, vm)) { @@ -817,10 +893,12 @@ qemuMigrationIsAllowed(struct qemud_driver *driver, virDomainObjPtr vm, def = vm->def; } - if (def->nhostdevs > 0) { - virReportError(VIR_ERR_OPERATION_INVALID, - "%s", _("Domain with assigned host devices cannot be migrated")); - return false; + for (i = 0; i < def->nhostdevs; i++) { + if (def->hostdevs[i]->ephemeral == 0) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("Domain with assigned host devices cannot be migrated")); + return false; + } } return true; @@ -2042,6 +2120,8 @@ static int doNativeMigrate(struct qemud_driver *driver, "cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu", driver, vm, uri, NULLSTR(cookiein), cookieinlen, cookieout, cookieoutlen, flags, resource); + + qemuMigrationRemoveEphemeralDevices(driver, vm); if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) { char *tmp; @@ -2069,6 +2149,9 @@ static int doNativeMigrate(struct qemud_driver *driver, ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout, cookieoutlen, flags, resource, &spec, dconn); + if (ret != 0 ) + qemuMigrationRestoreEphemeralDevices(driver, vm); + if (spec.destType == MIGRATION_DEST_FD) VIR_FORCE_CLOSE(spec.dest.fd.qemu); @@ -2106,6 +2189,8 @@ static int doTunnelMigrate(struct qemud_driver *driver, _("Source qemu is too old to support tunnelled migration")); return -1; } + + qemuMigrationRemoveEphemeralDevices(driver, vm); spec.fwdType = MIGRATION_FWD_STREAM; spec.fwd.stream = st; @@ -2153,6 +2238,8 @@ static int doTunnelMigrate(struct qemud_driver *driver, cookieoutlen, flags, resource, &spec, dconn); cleanup: + if (ret != 0) + qemuMigrationRestoreEphemeralDevices(driver, vm); if (spec.destType == MIGRATION_DEST_FD) { VIR_FORCE_CLOSE(spec.dest.fd.qemu); VIR_FORCE_CLOSE(spec.dest.fd.local); @@ -2197,7 +2284,8 @@ static int doPeer2PeerMigrate2(struct qemud_driver *driver, */ if (!(dom_xml = qemuDomainFormatXML(driver, vm, VIR_DOMAIN_XML_SECURE | - VIR_DOMAIN_XML_UPDATE_CPU, + VIR_DOMAIN_XML_UPDATE_CPU | + VIR_DOMAIN_XML_NO_EPHEMERAL_DEVICES, true))) return -1; @@ -3057,6 +3145,8 @@ qemuMigrationFinish(struct qemud_driver *driver, goto endjob; } + qemuMigrationAttachEphemeralDevices(driver, vm); + /* Guest is successfully running, so cancel previous auto destroy */ qemuProcessAutoDestroyRemove(driver, vm); } else { @@ -3154,6 +3244,8 @@ int qemuMigrationConfirm(struct qemud_driver *driver, VIR_WARN("Failed to save status on vm %s", vm->def->name); goto cleanup; } + + qemuMigrationRestoreEphemeralDevices(driver, vm); } qemuMigrationCookieFree(mig); -- 1.7.4.4
participants (3)
-
Eric Blake
-
Laine Stump
-
Shradha Shah