Ján Tomko wrote:
On 05/11/2014 08:48 AM, Roman Bogorodskiy wrote:
> Automatically allocate PCI addresses for devices instead
> of hardcoding them in the driver code. The current
> allocation schema is to dedicate an entire slot for each devices.
>
> Also, allow having arbitrary number of devices.
I think this can be split in a separate patch.
Sounds good. Originally, I decided to send it in a single series to
justify the list of functions and types moved.
But now as the first two patches are ACKed, I'll push them (hopefully
today or tomorrow) and continue iterating with the bhyve one.
> diff --git a/src/bhyve/bhyve_command.c
b/src/bhyve/bhyve_command.c
> index 91a8731..bc7ec5c 100644
> --- a/src/bhyve/bhyve_command.c
> +++ b/src/bhyve/bhyve_command.c
> @@ -41,21 +41,14 @@ VIR_LOG_INIT("bhyve.bhyve_command");
> static int
> bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd, bool dryRun)
> {
> - virDomainNetDefPtr net = NULL;
> - char *brname = NULL;
> - char *realifname = NULL;
> - int *tapfd = NULL;
> char macaddr[VIR_MAC_STRING_BUFLEN];
> + size_t i;
>
> - if (def->nnets != 1) {
> - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> - _("domain should have one and only one net
defined"));
> - return -1;
> - }
> -
> - net = def->nets[0];
> -
> - if (net) {
> + for (i = 0; i < def->nnets; i++) {
Moving this loop to the caller of the function would reduce the extra
indentation level.
Makes sense, will fix.
> + char *realifname = NULL;
> + int *tapfd = NULL;
> + char *brname = NULL;
> + virDomainNetDefPtr net = net = def->nets[i];;
No need to assign it twice and one semicolon would be enough. :)
Must we a fat finger of mine while messing with vim. Funny that it is
still a valid code.
> int actualType = virDomainNetGetActualType(net);
>
> if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
> @@ -146,7 +141,7 @@ bhyveBuildConsoleArgStr(const virDomainDef *def, virCommandPtr
cmd)
> return -1;
> }
>
> - virCommandAddArgList(cmd, "-s", "31,lpc", NULL);
> + virCommandAddArgList(cmd, "-s", "1,lpc", NULL);
Are both slot numbers arbitrary? And do we care about backwards compatibility?
Yes, both these slot numbers are arbitrary. I'm not sure we need to care
about backwards compatibility because guest console configuration
does not depend on the pci slot used for that PCI-ISA bridge.
> virCommandAddArg(cmd, "-l");
> virCommandAddArgFormat(cmd, "com%d,%s",
> chr->target.port + 1,
chr->source.data.file.path);
> @@ -157,46 +152,43 @@ bhyveBuildConsoleArgStr(const virDomainDef *def, virCommandPtr
cmd)
> static int
> bhyveBuildDiskArgStr(const virDomainDef *def, virCommandPtr cmd)
> {
> - virDomainDiskDefPtr disk;
> const char *bus_type;
> + size_t i;
> +
> + for (i = 0; i < def->ndisks; i++) {
> + virDomainDiskDefPtr disk = def->disks[i];
> +
> + switch (disk->bus) {
> + case VIR_DOMAIN_DISK_BUS_SATA:
> + bus_type = "ahci-hd";
> + break;
> + case VIR_DOMAIN_DISK_BUS_VIRTIO:
> + bus_type = "virtio-blk";
> + break;
> + default:
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("unsupported disk bus type"));
> + return -1;
> + }
>
> - if (def->ndisks != 1) {
> - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> - _("domain should have one and only one disk
defined"));
> - return -1;
> - }
> -
> - disk = def->disks[0];
> -
> - switch (disk->bus) {
> - case VIR_DOMAIN_DISK_BUS_SATA:
> - bus_type = "ahci-hd";
> - break;
> - case VIR_DOMAIN_DISK_BUS_VIRTIO:
> - bus_type = "virtio-blk";
> - break;
> - default:
> - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> - _("unsupported disk bus type"));
> - return -1;
> - }
> + if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("unsupported disk device"));
> + return -1;
> + }
>
> - if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
> - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> - _("unsupported disk device"));
> - return -1;
> - }
> + if (virDomainDiskGetType(disk) != VIR_STORAGE_TYPE_FILE) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("unsupported disk type"));
> + return -1;
> + }
>
> - if (virDomainDiskGetType(disk) != VIR_STORAGE_TYPE_FILE) {
> - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> - _("unsupported disk type"));
> - return -1;
> + virCommandAddArg(cmd, "-s");
> + virCommandAddArgFormat(cmd, "%d:0,%s,%s",
> + disk->info.addr.pci.slot, bus_type,
> + virDomainDiskGetSource(disk));
Do SATA disks use a PCI slot too?
Yes:
http://www.freebsd.org/cgi/man.cgi?query=bhyve&sektion=0&manpath=...
Basically, all the devices added through the "-s" flag are pci devices
that require the slot number (and function, optionally).
> +static int
> +bhyveCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
> + virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
> + virDomainDeviceInfoPtr info,
> + void *opaque)
> +{
> + int ret = -1;
> + virDomainPCIAddressSetPtr addrs = opaque;
> + virDevicePCIAddressPtr addr = &info->addr.pci;
> +
> + if (addr->domain == 0 && addr->bus == 0) {
> + if (addr->slot == 0) {
> + return 0;
> + } else if (addr->slot == 1) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("PCI bus 0 slot 1 is reserved for the implicit
"
> + "LPC PCI-ISA bridge"));
It's only implied when the console is present. Does it make sense to let
someone use the address if they don't want the ISA bridge?
Maybe we should generate an explicit <controller> element for it too.
As we currently do not have explicit support for PCI-ISA bridges, and in
bhyve it's used for console only (and unlikely will be used for
something else), the idea was to just reserve this slot to get a
consistent and reproducible pci addresses allocation and also not to
deal with a new controller type just for that single feature.
> +bhyveAssignDevicePCISlots(virDomainDefPtr def,
> + virDomainPCIAddressSetPtr addrs)
> +{
> + size_t i;
> + virDevicePCIAddress lpc_addr;
> +
> + /* explicitly reserve slot 1 for LPC-ISA bridge */
> + memset(&lpc_addr, 0, sizeof(lpc_addr));
> + lpc_addr.slot = 0x1;
> +
> + if (virDomainPCIAddressReserveSlot(addrs, &lpc_addr,
VIR_PCI_CONNECT_TYPE_PCI) < 0)
> + goto error;
> +
> + for (i = 0; i < def->ndisks; i++) {
> + if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE
&&
> + def->disks[i]->info.addr.pci.slot != 0)
> + continue;
> + if (virDomainPCIAddressReserveNextSlot(addrs,
> + &def->disks[i]->info,
> + VIR_PCI_CONNECT_TYPE_PCI) < 0)
> + goto error;
> + }
> +
> + for (i = 0; i < def->nnets; i++) {
> + if (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
> + continue;
> + if (virDomainPCIAddressReserveNextSlot(addrs,
> + &def->nets[i]->info,
> + VIR_PCI_CONNECT_TYPE_PCI) < 0)
> + goto error;
> + }
Assigning nets before disks would match the hardcoded slots that were used by
a domain with one net and one disk before.
Good point.
> +
> + for (i = 0; i < def->ncontrollers; i++) {
> + if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
> + if (def->controllers[i]->info.type !=
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
> + continue;
> + if (def->controllers[i]->model ==
VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT)
> + continue;
> +
> + if (virDomainPCIAddressReserveNextSlot(addrs,
> +
&def->controllers[i]->info,
> + VIR_PCI_CONNECT_TYPE_PCI) <
0)
> + goto error;
> + }
I think unsupported controllers don't need PCI slots.
I will take a look into that.
Thanks a lot for reviewing this rather huge patchset!
Roman Bogorodskiy