diff --git a/ChangeLog b/ChangeLog index 049c9c7276..3a666b7c66 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Wed Jan 7 13:54:05 CET 2009 Daniel Veillard + + * src/domain_conf.c src/qemu_conf.c: implement PCI passthrough + for recent KVM versions in a similar way to USB, patch by + Jason Krieg. Some cleanups and reformating too. + Wed Jan 7 11:54:06 CET 2009 Daniel Veillard * src/openvz_driver.c: fix the mac addresses generation for diff --git a/src/domain_conf.c b/src/domain_conf.c index f63b84688a..ce7f170aac 100644 --- a/src/domain_conf.c +++ b/src/domain_conf.c @@ -142,7 +142,7 @@ VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST, "usb", "pci") -#define virDomainReportError(conn, code, fmt...) \ +#define virDomainReportError(conn, code, fmt...) \ virReportErrorHelper(conn, VIR_FROM_DOMAIN, code, __FILE__, \ __FUNCTION__, __LINE__, fmt) @@ -893,8 +893,8 @@ virDomainNetDefParseXML(virConnectPtr conn, switch (def->type) { case VIR_DOMAIN_NET_TYPE_NETWORK: if (network == NULL) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("No 'network' attribute specified with ")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("No 'network' attribute specified with ")); goto error; } def->data.network.name = network; @@ -919,8 +919,8 @@ virDomainNetDefParseXML(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_BRIDGE: if (bridge == NULL) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("No 'dev' attribute specified with ")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("No 'dev' attribute specified with ")); goto error; } def->data.bridge.brname = bridge; @@ -931,21 +931,21 @@ virDomainNetDefParseXML(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_MCAST: if (port == NULL) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("No 'port' attribute specified with socket interface")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("No 'port' attribute specified with socket interface")); goto error; } if (virStrToLong_i(port, NULL, 10, &def->data.socket.port) < 0) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("Cannot parse 'port' attribute with socket interface")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse 'port' attribute with socket interface")); goto error; } if (address == NULL) { if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT || def->type == VIR_DOMAIN_NET_TYPE_MCAST) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("No 'address' attribute specified with socket interface")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("No 'address' attribute specified with socket interface")); goto error; } } else { @@ -970,7 +970,7 @@ virDomainNetDefParseXML(virConnectPtr conn, int char_ok = c_isalnum(model[i]) || model[i] == '_'; if (!char_ok) { virDomainReportError (conn, VIR_ERR_INVALID_ARG, "%s", - _("Model name contains invalid characters")); + _("Model name contains invalid characters")); goto error; } } @@ -1142,8 +1142,8 @@ virDomainChrDefParseXML(virConnectPtr conn, case VIR_DOMAIN_CHR_TYPE_PIPE: if (path == NULL && def->type != VIR_DOMAIN_CHR_TYPE_PTY) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source path attribute for char device")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing source path attribute for char device")); goto error; } @@ -1159,13 +1159,13 @@ virDomainChrDefParseXML(virConnectPtr conn, if (mode == NULL || STREQ(mode, "connect")) { if (connectHost == NULL) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source host attribute for char device")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing source host attribute for char device")); goto error; } if (connectService == NULL) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source service attribute for char device")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing source service attribute for char device")); goto error; } @@ -1176,13 +1176,13 @@ virDomainChrDefParseXML(virConnectPtr conn, def->data.tcp.listen = 0; } else { if (bindHost == NULL) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source host attribute for char device")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing source host attribute for char device")); goto error; } if (bindService == NULL) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source service attribute for char device")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing source service attribute for char device")); goto error; } @@ -1201,8 +1201,8 @@ virDomainChrDefParseXML(virConnectPtr conn, case VIR_DOMAIN_CHR_TYPE_UDP: if (connectService == NULL) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source service attribute for char device")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing source service attribute for char device")); goto error; } @@ -1219,8 +1219,8 @@ virDomainChrDefParseXML(virConnectPtr conn, case VIR_DOMAIN_CHR_TYPE_UNIX: if (path == NULL) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source path attribute for char device")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing source path attribute for char device")); goto error; } @@ -1293,7 +1293,7 @@ virDomainInputDefParseXML(virConnectPtr conn, if (def->bus == VIR_DOMAIN_INPUT_BUS_PS2 && /* Only allow mouse for ps2 */ def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("ps2 bus does not support %s input device"), + _("ps2 bus does not support %s input device"), type); goto error; } @@ -1311,7 +1311,7 @@ virDomainInputDefParseXML(virConnectPtr conn, } if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("xen bus does not support %s input device"), + _("xen bus does not support %s input device"), type); goto error; } @@ -1480,7 +1480,7 @@ virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn, if (vendor) { if (virStrToLong_ui(vendor, NULL, 0, - &def->source.subsys.u.usb.vendor) < 0) { + &def->source.subsys.u.usb.vendor) < 0) { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, _("cannot parse vendor id %s"), vendor); VIR_FREE(vendor); @@ -1499,7 +1499,8 @@ virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn, if (virStrToLong_ui(product, NULL, 0, &def->source.subsys.u.usb.product) < 0) { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("cannot parse product %s"), product); + _("cannot parse product %s"), + product); VIR_FREE(product); goto out; } @@ -1540,13 +1541,14 @@ virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn, } VIR_FREE(device); } else { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("usb address needs device id")); + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("usb address needs device id")); goto out; } } else { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("unknown usb source type '%s'"), cur->name); + _("unknown usb source type '%s'"), + cur->name); goto out; } } @@ -1572,6 +1574,97 @@ out: } +static int +virDomainHostdevSubsysPciDefParseXML(virConnectPtr conn, + const xmlNodePtr node, + virDomainHostdevDefPtr def) { + + int ret = -1; + xmlNodePtr cur; + + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + if (xmlStrEqual(cur->name, BAD_CAST "address")) { + + char *domain = virXMLPropString(cur, "domain"); + if (domain) { + if (virStrToLong_ui(domain, NULL, 0, + &def->source.subsys.u.pci.domain) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot parse domain %s"), + domain); + VIR_FREE(domain); + goto out; + } + VIR_FREE(domain); + } + + char *bus = virXMLPropString(cur, "bus"); + if (bus) { + if (virStrToLong_ui(bus, NULL, 0, + &def->source.subsys.u.pci.bus) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot parse bus %s"), bus); + VIR_FREE(bus); + goto out; + } + VIR_FREE(bus); + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("pci address needs bus id")); + goto out; + } + + char *slot = virXMLPropString(cur, "slot"); + if (slot) { + if (virStrToLong_ui(slot, NULL, 0, + &def->source.subsys.u.pci.slot) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot parse slot %s"), + slot); + VIR_FREE(slot); + goto out; + } + VIR_FREE(slot); + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("pci address needs slot id")); + goto out; + } + + char *function = virXMLPropString(cur, "function"); + if (function) { + if (virStrToLong_ui(function, NULL, 0, + &def->source.subsys.u.pci.function) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot parse function %s"), + function); + VIR_FREE(function); + goto out; + } + VIR_FREE(function); + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("pci address needs function id")); + goto out; + } + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown pci source type '%s'"), + cur->name); + goto out; + } + } + cur = cur->next; + } + + ret = 0; +out: + return ret; +} + + static virDomainHostdevDefPtr virDomainHostdevDefParseXML(virConnectPtr conn, const xmlNodePtr node) { @@ -1619,6 +1712,11 @@ virDomainHostdevDefParseXML(virConnectPtr conn, if (virDomainHostdevSubsysUsbDefParseXML(conn, cur, def) < 0) goto error; } + if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { + if (virDomainHostdevSubsysPciDefParseXML(conn, cur, def) < 0) + goto error; + } } else { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, _("unknown node %s"), cur->name); @@ -2378,9 +2476,9 @@ cleanup: #endif /* ! PROXY */ /************************************************************************ - * * - * Parser and converter for the CPUset strings used in libvirt * - * * + * * + * Parser and converter for the CPUset strings used in libvirt * + * * ************************************************************************/ /** * virDomainCpuNumberParse @@ -2995,7 +3093,7 @@ virDomainHostdevDefFormat(virConnectPtr conn, } type = virDomainHostdevSubsysTypeToString(def->source.subsys.type); - if (!type || def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + if (!type || (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) ) { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, _("unexpected hostdev type %d"), def->source.subsys.type); @@ -3005,15 +3103,24 @@ virDomainHostdevDefFormat(virConnectPtr conn, virBufferVSprintf(buf, " \n", mode, type); virBufferAddLit(buf, " \n"); - if (def->source.subsys.u.usb.vendor) { - virBufferVSprintf(buf, " \n", - def->source.subsys.u.usb.vendor); - virBufferVSprintf(buf, " \n", - def->source.subsys.u.usb.product); - } else { - virBufferVSprintf(buf, "
\n", - def->source.subsys.u.usb.bus, - def->source.subsys.u.usb.device); + if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { + if (def->source.subsys.u.usb.vendor) { + virBufferVSprintf(buf, " \n", + def->source.subsys.u.usb.vendor); + virBufferVSprintf(buf, " \n", + def->source.subsys.u.usb.product); + } else { + virBufferVSprintf(buf, "
\n", + def->source.subsys.u.usb.bus, + def->source.subsys.u.usb.device); + } + } + if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { + virBufferVSprintf(buf, "
\n", + def->source.subsys.u.pci.domain, + def->source.subsys.u.pci.bus, + def->source.subsys.u.pci.slot, + def->source.subsys.u.pci.function); } virBufferAddLit(buf, " \n"); diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 5d84f8561f..faf1e12ade 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -1203,8 +1203,10 @@ int qemudBuildCommandLine(virConnectPtr conn, for (i = 0 ; i < vm->def->nhostdevs ; i++) { int ret; char* usbdev; + char* pcidev; virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i]; + /* USB */ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { if(hostdev->source.subsys.u.usb.vendor) { @@ -1224,6 +1226,23 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG_LIT(usbdev); VIR_FREE(usbdev); } + + /* PCI */ + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { + ret = virAsprintf(&pcidev, "host=%.2x:%.2x.%.1x", + hostdev->source.subsys.u.pci.bus, + hostdev->source.subsys.u.pci.slot, + hostdev->source.subsys.u.pci.function); + if (ret < 0) { + pcidev = NULL; + goto error; + } + ADD_ARG_LIT("-pcidevice"); + ADD_ARG_LIT(pcidev); + VIR_FREE(pcidev); + } + } if (migrateFrom) {