The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7519
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
From 69598929e8eac6447019dd5087ec38534fec72b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Thu, 11 Jun 2020 19:46:38 -0400 Subject: [PATCH] lxd/vm: Move bus allocator to own file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/instance/drivers/driver_qemu.go | 170 +++++------------------- lxd/instance/drivers/driver_qemu_bus.go | 142 ++++++++++++++++++++ 2 files changed, 172 insertions(+), 140 deletions(-) create mode 100644 lxd/instance/drivers/driver_qemu_bus.go diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go index c2a81f479f..7c12346a98 100644 --- a/lxd/instance/drivers/driver_qemu.go +++ b/lxd/instance/drivers/driver_qemu.go @@ -1548,7 +1548,7 @@ func (vm *qemu) deviceBootPriorities() (map[string]int, error) { // generateQemuConfigFile writes the qemu config file and returns its location. // It writes the config file inside the VM's log path. -func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunConfig, fdFiles *[]string) (string, error) { +func (vm *qemu) generateQemuConfigFile(busName string, devConfs []*deviceConfig.RunConfig, fdFiles *[]string) (string, error) { var sb *strings.Builder = &strings.Builder{} err := qemuBase.Execute(sb, map[string]interface{}{ @@ -1585,123 +1585,13 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC return "", err } - // allocateBusAddress is used to create any needed root ports and provide - // the bus and address that should be used by a device. It supports - // automatically setting up multi-function devices and optimize their use. - portNum := 0 - devNum := 1 - - type entry struct { - bridgeDev int // Device number on the root bridge. - bridgeFn int // Function number on the root bridge. - - dev string // Existing device name. - fn int // Function number on the existing device. - } - entries := map[string]*entry{} - - var rootPort *entry - allocateRootPort := func() *entry { - if rootPort == nil { - rootPort = &entry{ - bridgeDev: devNum, - } - devNum++ - } else { - if rootPort.bridgeFn == 7 { - rootPort.bridgeFn = 0 - rootPort.bridgeDev = devNum - devNum++ - } else { - rootPort.bridgeFn++ - } - } - - return rootPort - } - - allocateBusAddr := func(group string) (string, string, bool) { - // FIXME: Need to figure out if ccw needs any bus logic. - if bus == "ccw" { - return "", "", false - } - - // Find a device group if specified. - var p *entry - if group != "" { - var ok bool - p, ok = entries[group] - if ok { - // Check if group is full. - if p.fn == 7 { - p.fn = 0 - if bus == "pci" { - p.bridgeDev = devNum - devNum++ - } else if bus == "pcie" { - r := allocateRootPort() - p.bridgeDev = r.bridgeDev - p.bridgeFn = r.bridgeFn - } - } else { - p.fn++ - } - } else { - // Create a new group. - p = &entry{} - - if bus == "pci" { - p.bridgeDev = devNum - devNum++ - } else if bus == "pcie" { - r := allocateRootPort() - p.bridgeDev = r.bridgeDev - p.bridgeFn = r.bridgeFn - } - - entries[group] = p - } - } else { - // Create a new temporary group. - p = &entry{} - - if bus == "pci" { - p.bridgeDev = devNum - devNum++ - } else if bus == "pcie" { - r := allocateRootPort() - p.bridgeDev = r.bridgeDev - p.bridgeFn = r.bridgeFn - } - } - - multi := p.fn == 0 && group != "" - - if bus == "pci" { - return "pci.0", fmt.Sprintf("%x.%d", p.bridgeDev, p.fn), multi - } - - if bus == "pcie" { - if p.fn == 0 { - qemuPCIe.Execute(sb, map[string]interface{}{ - "index": portNum, - "addr": fmt.Sprintf("%x.%d", p.bridgeDev, p.bridgeFn), - "multifunction": p.bridgeFn == 0, - }) - p.dev = fmt.Sprintf("qemu_pcie%d", portNum) - portNum++ - } - - return p.dev, fmt.Sprintf("00.%d", p.fn), multi - } - - return "", "", false - } + // Setup the bus allocator. + bus := qemuNewBus(busName, sb) // Now add the fixed set of devices. - devBus, devAddr, multi := allocateBusAddr("generic") + devBus, devAddr, multi := bus.allocate("generic") err = qemuBalloon.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -1710,9 +1600,9 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC return "", err } - devBus, devAddr, multi = allocateBusAddr("generic") + devBus, devAddr, multi = bus.allocate("generic") err = qemuRNG.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -1721,9 +1611,9 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC return "", err } - devBus, devAddr, multi = allocateBusAddr("generic") + devBus, devAddr, multi = bus.allocate("generic") err = qemuKeyboard.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -1732,9 +1622,9 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC return "", err } - devBus, devAddr, multi = allocateBusAddr("generic") + devBus, devAddr, multi = bus.allocate("generic") err = qemuTablet.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -1743,9 +1633,9 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC return "", err } - devBus, devAddr, multi = allocateBusAddr("generic") + devBus, devAddr, multi = bus.allocate("generic") err = qemuVsock.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -1756,9 +1646,9 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC return "", err } - devBus, devAddr, multi = allocateBusAddr("generic") + devBus, devAddr, multi = bus.allocate("generic") err = qemuSerial.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -1769,9 +1659,9 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC return "", err } - devBus, devAddr, multi = allocateBusAddr("") + devBus, devAddr, multi = bus.allocate("") err = qemuSCSI.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -1780,9 +1670,9 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC return "", err } - devBus, devAddr, multi = allocateBusAddr("9p") + devBus, devAddr, multi = bus.allocate("9p") err = qemuDriveConfig.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -1793,9 +1683,9 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC return "", err } - devBus, devAddr, multi = allocateBusAddr("") + devBus, devAddr, multi = bus.allocate("") err = qemuGPU.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -1821,7 +1711,7 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC if drive.TargetPath == "/" { err = vm.addRootDriveConfig(sb, bootIndexes, drive) } else if drive.FSType == "9p" { - err = vm.addDriveDirConfig(sb, bus, allocateBusAddr, fdFiles, &agentMounts, drive) + err = vm.addDriveDirConfig(sb, bus, fdFiles, &agentMounts, drive) } else { err = vm.addDriveConfig(sb, bootIndexes, drive) } @@ -1833,7 +1723,7 @@ func (vm *qemu) generateQemuConfigFile(bus string, devConfs []*deviceConfig.RunC // Add network device. if len(runConf.NetworkInterface) > 0 { - err = vm.addNetDevConfig(sb, bus, allocateBusAddr, bootIndexes, runConf.NetworkInterface, fdFiles) + err = vm.addNetDevConfig(sb, bus, bootIndexes, runConf.NetworkInterface, fdFiles) if err != nil { return "", err } @@ -1990,7 +1880,7 @@ func (vm *qemu) addRootDriveConfig(sb *strings.Builder, bootIndexes map[string]i } // addDriveDirConfig adds the qemu config required for adding a supplementary drive directory share. -func (vm *qemu) addDriveDirConfig(sb *strings.Builder, bus string, allocateBusAddr func(group string) (string, string, bool), fdFiles *[]string, agentMounts *[]instancetype.VMAgentMount, driveConf deviceConfig.MountEntryItem) error { +func (vm *qemu) addDriveDirConfig(sb *strings.Builder, bus *qemuBus, fdFiles *[]string, agentMounts *[]instancetype.VMAgentMount, driveConf deviceConfig.MountEntryItem) error { mountTag := fmt.Sprintf("lxd_%s", driveConf.DevName) agentMount := instancetype.VMAgentMount{ @@ -2008,12 +1898,12 @@ func (vm *qemu) addDriveDirConfig(sb *strings.Builder, bus string, allocateBusAd // Record the 9p mount for the agent. *agentMounts = append(*agentMounts, agentMount) - devBus, devAddr, multi := allocateBusAddr("9p") + devBus, devAddr, multi := bus.allocate("9p") // For read only shares, do not use proxy. if shared.StringInSlice("ro", driveConf.Opts) { return qemuDriveDir.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -2028,7 +1918,7 @@ func (vm *qemu) addDriveDirConfig(sb *strings.Builder, bus string, allocateBusAd // Only use proxy for writable shares. proxyFD := vm.addFileDescriptor(fdFiles, driveConf.DevPath) return qemuDriveDir.Execute(sb, map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devBus": devBus, "devAddr": devAddr, "multifunction": multi, @@ -2078,7 +1968,7 @@ func (vm *qemu) addDriveConfig(sb *strings.Builder, bootIndexes map[string]int, } // addNetDevConfig adds the qemu config required for adding a network device. -func (vm *qemu) addNetDevConfig(sb *strings.Builder, bus string, allocateBusAddr func(group string) (string, string, bool), bootIndexes map[string]int, nicConfig []deviceConfig.RunConfigItem, fdFiles *[]string) error { +func (vm *qemu) addNetDevConfig(sb *strings.Builder, bus *qemuBus, bootIndexes map[string]int, nicConfig []deviceConfig.RunConfigItem, fdFiles *[]string) error { var devName, nicName, devHwaddr, pciSlotName string for _, nicItem := range nicConfig { if nicItem.Key == "devName" { @@ -2094,7 +1984,7 @@ func (vm *qemu) addNetDevConfig(sb *strings.Builder, bus string, allocateBusAddr var tpl *template.Template tplFields := map[string]interface{}{ - "bus": bus, + "bus": bus.name, "devName": devName, "devHwaddr": devHwaddr, "bootIndex": bootIndexes[devName], @@ -2126,7 +2016,7 @@ func (vm *qemu) addNetDevConfig(sb *strings.Builder, bus string, allocateBusAddr tpl = qemuNetdevPhysical } - devBus, devAddr, multi := allocateBusAddr("") + devBus, devAddr, multi := bus.allocate("") tplFields["devBus"] = devBus tplFields["devAddr"] = devAddr tplFields["multifunction"] = multi diff --git a/lxd/instance/drivers/driver_qemu_bus.go b/lxd/instance/drivers/driver_qemu_bus.go new file mode 100644 index 0000000000..c38e47d572 --- /dev/null +++ b/lxd/instance/drivers/driver_qemu_bus.go @@ -0,0 +1,142 @@ +package drivers + +import ( + "fmt" + "strings" +) + +type qemuBusEntry struct { + bridgeDev int // Device number on the root bridge. + bridgeFn int // Function number on the root bridge. + + dev string // Existing device name. + fn int // Function number on the existing device. +} + +type qemuBus struct { + name string // Bus type. + sb *strings.Builder // String builder to use. + + portNum int // Next available port/chassis on the bridge. + devNum int // Next available device number on the bridge. + + rootPort *qemuBusEntry // Current root port. + + entries map[string]*qemuBusEntry // Map of qemuBusEntry for a particular shared device. +} + +func (a *qemuBus) allocateRoot() *qemuBusEntry { + if a.rootPort == nil { + a.rootPort = &qemuBusEntry{ + bridgeDev: a.devNum, + } + a.devNum++ + } else { + if a.rootPort.bridgeFn == 7 { + a.rootPort.bridgeFn = 0 + a.rootPort.bridgeDev = a.devNum + a.devNum++ + } else { + a.rootPort.bridgeFn++ + } + } + + return a.rootPort +} + +// allocate() does any needed port allocation and returns the bus name, +// address and whether the device needs to be configured as multi-function. +// +// The group parameter allows for grouping devices together as a single +// multi-function device. It automatically keeps track of the number of +// functions already used and will allocate a new device as needed. +func (a *qemuBus) allocate(group string) (string, string, bool) { + if a.name == "ccw" { + return "", "", false + } + + // Find a device group if specified. + var p *qemuBusEntry + if group != "" { + var ok bool + p, ok = a.entries[group] + if ok { + // Check if group is full. + if p.fn == 7 { + p.fn = 0 + if a.name == "pci" { + p.bridgeDev = a.devNum + a.devNum++ + } else if a.name == "pcie" { + r := a.allocateRoot() + p.bridgeDev = r.bridgeDev + p.bridgeFn = r.bridgeFn + } + } else { + p.fn++ + } + } else { + // Create a new group. + p = &qemuBusEntry{} + + if a.name == "pci" { + p.bridgeDev = a.devNum + a.devNum++ + } else if a.name == "pcie" { + r := a.allocateRoot() + p.bridgeDev = r.bridgeDev + p.bridgeFn = r.bridgeFn + } + + a.entries[group] = p + } + } else { + // Create a new temporary group. + p = &qemuBusEntry{} + + if a.name == "pci" { + p.bridgeDev = a.devNum + a.devNum++ + } else if a.name == "pcie" { + r := a.allocateRoot() + p.bridgeDev = r.bridgeDev + p.bridgeFn = r.bridgeFn + } + } + + multi := p.fn == 0 && group != "" + + if a.name == "pci" { + return "pci.0", fmt.Sprintf("%x.%d", p.bridgeDev, p.fn), multi + } + + if a.name == "pcie" { + if p.fn == 0 { + qemuPCIe.Execute(a.sb, map[string]interface{}{ + "index": a.portNum, + "addr": fmt.Sprintf("%x.%d", p.bridgeDev, p.bridgeFn), + "multifunction": p.bridgeFn == 0, + }) + p.dev = fmt.Sprintf("qemu_pcie%d", a.portNum) + a.portNum++ + } + + return p.dev, fmt.Sprintf("00.%d", p.fn), multi + } + + return "", "", false +} + +func qemuNewBus(name string, sb *strings.Builder) *qemuBus { + a := &qemuBus{ + name: name, + sb: sb, + + portNum: 0, // No PCIe ports are used in the default config. + devNum: 1, // Address 0 is used by the DRAM controller. + + entries: map[string]*qemuBusEntry{}, + } + + return a +}
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel