The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6756

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) ===
- Moves config generation templates into own file that is parsed at LXD start time to avoid repetitive parsing and possibility of crashing LXD at VM start time due to invalid template.
- Simplifies NIC config generation to support more config types (such as physical and SR-IOV) in the future.
From 8e080e82f5b215c43cdc9892c59af776b111a933 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 23 Jan 2020 13:49:04 +0000
Subject: [PATCH 1/2] lxd/instance/drivers/driver/qemu/templates: Moves
 templates to separate file

And parses them at LXD start to avoid invalid templates causing LXD to crash at 
VM start time.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/instance/drivers/driver_qemu_templates.go | 225 ++++++++++++++++++
 1 file changed, 225 insertions(+)
 create mode 100644 lxd/instance/drivers/driver_qemu_templates.go

diff --git a/lxd/instance/drivers/driver_qemu_templates.go 
b/lxd/instance/drivers/driver_qemu_templates.go
new file mode 100644
index 0000000000..af15de4f6a
--- /dev/null
+++ b/lxd/instance/drivers/driver_qemu_templates.go
@@ -0,0 +1,225 @@
+package drivers
+
+import (
+       "text/template"
+)
+
+// Base config. This is common for all VMs and has no variables in it.
+var qemuBase = template.Must(template.New("qemuBase").Parse(`
+# Machine
+[machine]
+graphics = "off"
+type = "{{.qemuType}}"
+accel = "kvm"
+usb = "off"
+graphics = "off"
+{{ .qemuConf -}}
+
+[boot-opts]
+strict = "on"
+
+# LXD serial identifier
+[device]
+driver = "virtio-serial"
+
+[device]
+driver = "virtserialport"
+name = "org.linuxcontainers.lxd"
+chardev = "vserial"
+
+[chardev "vserial"]
+backend = "ringbuf"
+size = "{{.ringbufSizeBytes}}B"
+
+# PCIe root
+[device "qemu_pcie1"]
+driver = "pcie-root-port"
+port = "0x10"
+chassis = "1"
+bus = "pcie.0"
+multifunction = "on"
+addr = "0x2"
+
+[device "qemu_scsi"]
+driver = "virtio-scsi-pci"
+bus = "qemu_pcie1"
+addr = "0x0"
+
+# Balloon driver
+[device "qemu_pcie2"]
+driver = "pcie-root-port"
+port = "0x11"
+chassis = "2"
+bus = "pcie.0"
+addr = "0x2.0x1"
+
+[device "qemu_ballon"]
+driver = "virtio-balloon-pci"
+bus = "qemu_pcie2"
+addr = "0x0"
+
+# Random number generator
+[object "qemu_rng"]
+qom-type = "rng-random"
+filename = "/dev/urandom"
+
+[device "qemu_pcie3"]
+driver = "pcie-root-port"
+port = "0x12"
+chassis = "3"
+bus = "pcie.0"
+addr = "0x2.0x2"
+
+[device "dev-qemu_rng"]
+driver = "virtio-rng-pci"
+rng = "qemu_rng"
+bus = "qemu_pcie3"
+addr = "0x0"
+
+# Console
+[chardev "console"]
+backend = "pty"
+`))
+
+var qemuMemory = template.Must(template.New("qemuMemory").Parse(`
+# Memory
+[memory]
+size = "{{.memSizeBytes}}B"
+`))
+
+var qemuVsock = template.Must(template.New("qemuVsock").Parse(`
+# Vsock
+[device "qemu_pcie4"]
+driver = "pcie-root-port"
+port = "0x13"
+chassis = "4"
+bus = "pcie.0"
+addr = "0x2.0x3"
+
+[device]
+driver = "vhost-vsock-pci"
+guest-cid = "{{.vsockID}}"
+bus = "qemu_pcie4"
+addr = "0x0"
+`))
+
+var qemuCPU = template.Must(template.New("qemuCPU").Parse(`
+# CPU
+[smp-opts]
+cpus = "{{.cpuCount}}"
+#sockets = "1"
+#cores = "1"
+#threads = "1"
+`))
+
+var qemuControlSocket = template.Must(template.New("qemuControlSocket").Parse(`
+# Qemu control
+[chardev "monitor"]
+backend = "socket"
+path = "{{.path}}"
+server = "on"
+wait = "off"
+
+[mon]
+chardev = "monitor"
+mode = "control"
+`))
+
+var qemuDriveFirmware = template.Must(template.New("qemuDriveFirmware").Parse(`
+# Firmware (read only)
+[drive]
+file = "{{.roPath}}"
+if = "pflash"
+format = "raw"
+unit = "0"
+readonly = "on"
+
+# Firmware settings (writable)
+[drive]
+file = "{{.nvramPath}}"
+if = "pflash"
+format = "raw"
+unit = "1"
+`))
+
+// Devices use "qemu_" prefix indicating that this is a internally named 
device.
+var qemuDriveConfig = template.Must(template.New("qemuDriveConfig").Parse(`
+# Config drive
+[fsdev "qemu_config"]
+fsdriver = "local"
+security_model = "none"
+readonly = "on"
+path = "{{.path}}"
+
+[device "dev-qemu_config"]
+driver = "virtio-9p-pci"
+fsdev = "qemu_config"
+mount_tag = "config"
+`))
+
+// Devices use "lxd_" prefix indicating that this is a user named device.
+var qemuDrive = template.Must(template.New("qemuDrive").Parse(`
+# {{.devName}} drive
+[drive "lxd_{{.devName}}"]
+file = "{{.devPath}}"
+format = "raw"
+if = "none"
+cache = "{{.cacheMode}}"
+aio = "{{.aioMode}}"
+
+[device "dev-lxd_{{.devName}}"]
+driver = "scsi-hd"
+bus = "qemu_scsi.0"
+channel = "0"
+scsi-id = "{{.bootIndex}}"
+lun = "1"
+drive = "lxd_{{.devName}}"
+bootindex = "{{.bootIndex}}"
+`))
+
+// qemuDevTapCommon is common PCI device template for tap based netdevs.
+var qemuDevTapCommon = template.Must(template.New("qemuDevTapCommon").Parse(`
+[device "qemu_pcie{{.chassisIndex}}"]
+driver = "pcie-root-port"
+port = "0x{{.portIndex}}"
+chassis = "{{.chassisIndex}}"
+bus = "pcie.0"
+addr = "0x2.0x{{.pcieAddr}}"
+
+[device "dev-lxd_{{.devName}}"]
+driver = "virtio-net-pci"
+netdev = "lxd_{{.devName}}"
+mac = "{{.devHwaddr}}"
+bus = "qemu_pcie{{.chassisIndex}}"
+addr = "0x0"
+bootindex = "{{.bootIndex}}"
+`))
+
+// Devices use "lxd_" prefix indicating that this is a user named device.
+var qemuNetDevTapTun = 
template.Must(qemuDevTapCommon.New("qemuNetDevTapTun").Parse(`
+# Network card ("{{.devName}}" device)
+[netdev "lxd_{{.devName}}"]
+type = "tap"
+ifname = "{{.ifName}}"
+script = "no"
+downscript = "no"
+{{ template "qemuDevTapCommon" . -}}
+`))
+
+// Devices use "lxd_" prefix indicating that this is a user named device.
+var qemuNetdevTapFD = 
template.Must(qemuDevTapCommon.New("qemuNetdevTapFD").Parse(`
+# Network card ("{{.devName}}" device)
+[netdev "lxd_{{.devName}}"]
+type = "tap"
+fd = "{{.tapFD}}"
+{{ template "qemuDevTapCommon" . -}}
+`))
+
+// Devices use "lxd_" prefix indicating that this is a user named device.
+var qemuNetdevPhysical = 
template.Must(template.New("qemuNetdevPhysical").Parse(`
+# Network card ("{{.devName}}" device)
+[device "dev-lxd_{{.devName}}"]
+driver = "vfio-pci"
+host = "{{.host}}"
+bootindex = "{{.bootIndex}}"
+`))

From 1a52a71e551957d5432d22a1f27d471787149409 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 23 Jan 2020 13:50:05 +0000
Subject: [PATCH 2/2] lxd/instance/drivers/driver/qemu: Updates template usage

Simplifies template usage ready for physical NIC type support.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/instance/drivers/driver_qemu.go | 290 ++++------------------------
 1 file changed, 41 insertions(+), 249 deletions(-)

diff --git a/lxd/instance/drivers/driver_qemu.go 
b/lxd/instance/drivers/driver_qemu.go
index 66879f9620..dd4196d9dc 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -1214,89 +1214,11 @@ func (vm *qemu) deviceBootPriorities() (map[string]int, 
error) {
 func (vm *qemu) generateQemuConfigFile(qemuType string, qemuConf string, 
devConfs []*deviceConfig.RunConfig, fdFiles *[]string) (string, error) {
        var sb *strings.Builder = &strings.Builder{}
 
-       // Base config. This is common for all VMs and has no variables in it.
-       t := template.Must(template.New("").Parse(`
-# Machine
-[machine]
-graphics = "off"
-type = "{{.qemuType}}"
-accel = "kvm"
-usb = "off"
-graphics = "off"
-{{.qemuConf}}
-
-[boot-opts]
-strict = "on"
-
-# LXD serial identifier
-[device]
-driver = "virtio-serial"
-
-[device]
-driver = "virtserialport"
-name = "org.linuxcontainers.lxd"
-chardev = "vserial"
-
-[chardev "vserial"]
-backend = "ringbuf"
-size = "{{.ringbufSizeBytes}}B"
-
-# PCIe root
-[device "qemu_pcie1"]
-driver = "pcie-root-port"
-port = "0x10"
-chassis = "1"
-bus = "pcie.0"
-multifunction = "on"
-addr = "0x2"
-
-[device "qemu_scsi"]
-driver = "virtio-scsi-pci"
-bus = "qemu_pcie1"
-addr = "0x0"
-
-# Balloon driver
-[device "qemu_pcie2"]
-driver = "pcie-root-port"
-port = "0x11"
-chassis = "2"
-bus = "pcie.0"
-addr = "0x2.0x1"
-
-[device "qemu_ballon"]
-driver = "virtio-balloon-pci"
-bus = "qemu_pcie2"
-addr = "0x0"
-
-# Random number generator
-[object "qemu_rng"]
-qom-type = "rng-random"
-filename = "/dev/urandom"
-
-[device "qemu_pcie3"]
-driver = "pcie-root-port"
-port = "0x12"
-chassis = "3"
-bus = "pcie.0"
-addr = "0x2.0x2"
-
-[device "dev-qemu_rng"]
-driver = "virtio-rng-pci"
-rng = "qemu_rng"
-bus = "qemu_pcie3"
-addr = "0x0"
-
-# Console
-[chardev "console"]
-backend = "pty"
-`))
-
-       m := map[string]interface{}{
+       err := qemuBase.Execute(sb, map[string]interface{}{
                "qemuType":         qemuType,
                "qemuConf":         qemuConf,
                "ringbufSizeBytes": qmp.RingbufSize,
-       }
-       err := t.Execute(sb, m)
+       })
        if err != nil {
                return "", err
        }
@@ -1381,42 +1303,16 @@ func (vm *qemu) addMemoryConfig(sb *strings.Builder) 
error {
                return fmt.Errorf("limits.memory invalid: %v", err)
        }
 
-       t := template.Must(template.New("").Parse(`
-# Memory
-[memory]
-size = "{{.memSizeBytes}}B"
-`))
-
-       m := map[string]interface{}{
+       return qemuMemory.Execute(sb, map[string]interface{}{
                "memSizeBytes": memSizeBytes,
-       }
-       return t.Execute(sb, m)
+       })
 }
 
 // addVsockConfig adds the qemu config required for setting up the host->VM 
vsock socket.
 func (vm *qemu) addVsockConfig(sb *strings.Builder) error {
-       vsockID := vm.vsockID()
-
-       t := template.Must(template.New("").Parse(`
-# Vsock
-[device "qemu_pcie4"]
-driver = "pcie-root-port"
-port = "0x13"
-chassis = "4"
-bus = "pcie.0"
-addr = "0x2.0x3"
-
-[device]
-driver = "vhost-vsock-pci"
-guest-cid = "{{.vsockID}}"
-bus = "qemu_pcie4"
-addr = "0x0"
-`))
-
-       m := map[string]interface{}{
-               "vsockID": vsockID,
-       }
-       return t.Execute(sb, m)
+       return qemuVsock.Execute(sb, map[string]interface{}{
+               "vsockID": vm.vsockID(),
+       })
 }
 
 // addCPUConfig adds the qemu config required for setting the number of 
virtualised CPUs.
@@ -1432,93 +1328,31 @@ func (vm *qemu) addCPUConfig(sb *strings.Builder) error 
{
                return fmt.Errorf("limits.cpu invalid: %v", err)
        }
 
-       t := template.Must(template.New("").Parse(`
-# CPU
-[smp-opts]
-cpus = "{{.cpuCount}}"
-#sockets = "1"
-#cores = "1"
-#threads = "1"
-`))
-
-       m := map[string]interface{}{
+       return qemuCPU.Execute(sb, map[string]interface{}{
                "cpuCount": cpuCount,
-       }
-       return t.Execute(sb, m)
+       })
 }
 
 // addMonitorConfig adds the qemu config required for setting up the host side 
VM monitor device.
 func (vm *qemu) addMonitorConfig(sb *strings.Builder) error {
-       monitorPath := vm.getMonitorPath()
-
-       t := template.Must(template.New("").Parse(`
-# Qemu control
-[chardev "monitor"]
-backend = "socket"
-path = "{{.path}}"
-server = "on"
-wait = "off"
-
-[mon]
-chardev = "monitor"
-mode = "control"
-`))
-
-       m := map[string]interface{}{
-               "path": monitorPath,
-       }
-       return t.Execute(sb, m)
+       return qemuControlSocket.Execute(sb, map[string]interface{}{
+               "path": vm.getMonitorPath(),
+       })
 }
 
 // addFirmwareConfig adds the qemu config required for adding a secure boot 
compatible EFI firmware.
 func (vm *qemu) addFirmwareConfig(sb *strings.Builder) error {
-       nvramPath := vm.getNvramPath()
-
-       t := template.Must(template.New("").Parse(`
-# Firmware (read only)
-[drive]
-file = "{{.roPath}}"
-if = "pflash"
-format = "raw"
-unit = "0"
-readonly = "on"
-
-# Firmware settings (writable)
-[drive]
-file = "{{.nvramPath}}"
-if = "pflash"
-format = "raw"
-unit = "1"
-`))
-
-       m := map[string]interface{}{
+       return qemuDriveFirmware.Execute(sb, map[string]interface{}{
                "roPath":    filepath.Join(vm.ovmfPath(), "OVMF_CODE.fd"),
-               "nvramPath": nvramPath,
-       }
-       return t.Execute(sb, m)
+               "nvramPath": vm.getNvramPath(),
+       })
 }
 
 // addConfDriveConfig adds the qemu config required for adding the config 
drive.
 func (vm *qemu) addConfDriveConfig(sb *strings.Builder) error {
-       // Devices use "qemu_" prefix indicating that this is a internally 
named device.
-       t := template.Must(template.New("").Parse(`
-# Config drive
-[fsdev "qemu_config"]
-fsdriver = "local"
-security_model = "none"
-readonly = "on"
-path = "{{.path}}"
-
-[device "dev-qemu_config"]
-driver = "virtio-9p-pci"
-fsdev = "qemu_config"
-mount_tag = "config"
-`))
-
-       m := map[string]interface{}{
+       return qemuDriveConfig.Execute(sb, map[string]interface{}{
                "path": filepath.Join(vm.Path(), "config"),
-       }
-       return t.Execute(sb, m)
+       })
 }
 
 // addRootDriveConfig adds the qemu config required for adding the root drive.
@@ -1580,40 +1414,18 @@ func (vm *qemu) addDriveConfig(sb *strings.Builder, 
bootIndexes map[string]int,
                }
        }
 
-       // Devices use "lxd_" prefix indicating that this is a user named 
device.
-       t := template.Must(template.New("").Parse(`
-# {{.devName}} drive
-[drive "lxd_{{.devName}}"]
-file = "{{.devPath}}"
-format = "raw"
-if = "none"
-cache = "{{.cacheMode}}"
-aio = "{{.aioMode}}"
-
-[device "dev-lxd_{{.devName}}"]
-driver = "scsi-hd"
-bus = "qemu_scsi.0"
-channel = "0"
-scsi-id = "{{.bootIndex}}"
-lun = "1"
-drive = "lxd_{{.devName}}"
-bootindex = "{{.bootIndex}}"
-`))
-
-       m := map[string]interface{}{
+       return qemuDrive.Execute(sb, map[string]interface{}{
                "devName":   driveConf.DevName,
                "devPath":   driveConf.DevPath,
                "bootIndex": bootIndexes[driveConf.DevName],
                "cacheMode": cacheMode,
                "aioMode":   aioMode,
-       }
-       return t.Execute(sb, m)
+       })
 }
 
 // addNetDevConfig adds the qemu config required for adding a network device.
 func (vm *qemu) addNetDevConfig(sb *strings.Builder, nicIndex int, bootIndexes 
map[string]int, nicConfig []deviceConfig.RunConfigItem, fdFiles *[]string) 
error {
        var devName, nicName, devHwaddr string
-       var tapFD int
        for _, nicItem := range nicConfig {
                if nicItem.Key == "devName" {
                        devName = nicItem.Value
@@ -1624,6 +1436,16 @@ func (vm *qemu) addNetDevConfig(sb *strings.Builder, 
nicIndex int, bootIndexes m
                }
        }
 
+       var tpl *template.Template
+       tplFields := map[string]interface{}{
+               "devName":      devName,
+               "devHwaddr":    devHwaddr,
+               "bootIndex":    bootIndexes[devName],
+               "chassisIndex": 5 + nicIndex,
+               "portIndex":    14 + nicIndex,
+               "pcieAddr":     4 + nicIndex,
+       }
+
        // Detect MACVTAP interface types and figure out which tap device is 
being used.
        // This is so we can open a file handle to the tap device and pass it 
to the qemu process.
        if shared.PathExists(fmt.Sprintf("/sys/class/net/%s/macvtap", nicName)) 
{
@@ -1639,49 +1461,19 @@ func (vm *qemu) addNetDevConfig(sb *strings.Builder, 
nicIndex int, bootIndexes m
 
                // Append the tap device file path to the list of files to be 
opened and passed to qemu.
                *fdFiles = append(*fdFiles, fmt.Sprintf("/dev/tap%d", ifindex))
-               tapFD = 2 + len(*fdFiles) // Use 2+fdFiles count, as first file 
descriptor available is 3.
-       }
-
-       // Devices use "lxd_" prefix indicating that this is a user named 
device.
-       t := template.Must(template.New("").Parse(`
-# Network card ("{{.devName}}" device)
-[netdev "lxd_{{.devName}}"]
-type = "tap"
-{{ if ne .tapFD 0 }}
-fd = "{{.tapFD}}"
-{{ else }}
-ifname = "{{.ifName}}"
-script = "no"
-downscript = "no"
-{{ end }}
-
-[device "qemu_pcie{{.chassisIndex}}"]
-driver = "pcie-root-port"
-port = "0x{{.portIndex}}"
-chassis = "{{.chassisIndex}}"
-bus = "pcie.0"
-addr = "0x2.0x{{.pcieAddr}}"
-
-[device "dev-lxd_{{.devName}}"]
-driver = "virtio-net-pci"
-netdev = "lxd_{{.devName}}"
-mac = "{{.devHwaddr}}"
-bus = "qemu_pcie{{.chassisIndex}}"
-addr = "0x0"
-bootindex = "{{.bootIndex}}"
-`))
-
-       m := map[string]interface{}{
-               "devName":      devName,
-               "ifName":       nicName,
-               "chassisIndex": 5 + nicIndex,
-               "portIndex":    14 + nicIndex,
-               "pcieAddr":     4 + nicIndex,
-               "devHwaddr":    devHwaddr,
-               "bootIndex":    bootIndexes[devName],
-               "tapFD":        tapFD,
+               tplFields["tapFD"] = 2 + len(*fdFiles) // Use 2+fdFiles count, 
as first user file descriptor is 3.
+               tpl = qemuNetdevTapFD
+       } else if shared.PathExists(fmt.Sprintf("/sys/class/net/%s/tun_flags", 
nicName)) {
+               // Detect TAP (via TUN driver) device.
+               tplFields["ifName"] = nicName
+               tpl = qemuNetDevTapTun
        }
-       return t.Execute(sb, m)
+
+       if tpl != nil {
+               return tpl.Execute(sb, tplFields)
+       }
+
+       return fmt.Errorf("Unrecognised device type")
 }
 
 // pidFilePath returns the path where the qemu process should write its PID.
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to