Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle long device names when creating QEMU device tags #13516

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 20 additions & 19 deletions lxd/instance/drivers/driver_qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ const qemuPCIDeviceIDStart = 4
// qemuDeviceIDPrefix used as part of the name given QEMU devices generated from user added devices.
const qemuDeviceIDPrefix = "dev-lxd_"

// qemuNetDevIDPrefix used as part of the name given QEMU netdevs generated from user added devices.
const qemuNetDevIDPrefix = "lxd_"
// qemuDeviceNamePrefix used as part of the name given QEMU blockdevs, netdevs and device tags generated from user added devices.
tomponline marked this conversation as resolved.
Show resolved Hide resolved
const qemuDeviceNamePrefix = "lxd_"

// qemuBlockDevIDPrefix used as part of the name given QEMU blockdevs generated from user added devices.
const qemuBlockDevIDPrefix = "lxd_"
// qemuDeviceNameMaxLength used to indicate the maximum length of a qemu block node name and device tags.
const qemuDeviceNameMaxLength = 31

// qemuMigrationNBDExportName is the name of the disk device export by the migration NBD server.
const qemuMigrationNBDExportName = "lxd_root"
Expand Down Expand Up @@ -2180,7 +2180,7 @@ func (d *qemu) deviceStart(dev device.Device, instanceRunning bool) (*deviceConf
func (d *qemu) deviceAttachPath(deviceName string) error {
escapedDeviceName := filesystem.PathNameEncode(deviceName)
deviceID := fmt.Sprintf("%s%s", qemuDeviceIDPrefix, escapedDeviceName)
mountTag := fmt.Sprintf("lxd_%s", deviceName)
mountTag := d.generateQemuDeviceName(deviceName)

// Detect virtiofsd path.
virtiofsdSockPath := filepath.Join(d.DevicesPath(), fmt.Sprintf("virtio-fs.%s.sock", deviceName))
Expand Down Expand Up @@ -2300,7 +2300,7 @@ func (d *qemu) deviceAttachBlockDevice(mount deviceConfig.MountEntryItem) error
func (d *qemu) deviceDetachPath(deviceName string) error {
escapedDeviceName := filesystem.PathNameEncode(deviceName)
deviceID := fmt.Sprintf("%s%s", qemuDeviceIDPrefix, escapedDeviceName)
mountTag := fmt.Sprintf("lxd_%s", deviceName)
mountTag := d.generateQemuDeviceName(deviceName)

// Check if the agent is running.
monitor, err := qmp.Connect(d.monitorPath(), qemuSerialChardevName, d.getMonitorEventHandler())
Expand Down Expand Up @@ -2343,7 +2343,7 @@ func (d *qemu) deviceDetachBlockDevice(deviceName string) error {

escapedDeviceName := filesystem.PathNameEncode(deviceName)
deviceID := fmt.Sprintf("%s%s", qemuDeviceIDPrefix, escapedDeviceName)
blockDevName := d.blockNodeName(escapedDeviceName)
blockDevName := d.generateQemuDeviceName(escapedDeviceName)
tomponline marked this conversation as resolved.
Show resolved Hide resolved

err = monitor.RemoveFDFromFDSet(blockDevName)
if err != nil {
Expand Down Expand Up @@ -2526,7 +2526,7 @@ func (d *qemu) deviceDetachNIC(deviceName string) error {

escapedDeviceName := filesystem.PathNameEncode(deviceName)
deviceID := fmt.Sprintf("%s%s", qemuDeviceIDPrefix, escapedDeviceName)
netDevID := fmt.Sprintf("%s%s", qemuNetDevIDPrefix, escapedDeviceName)
netDevID := fmt.Sprintf("%s%s", qemuDeviceNamePrefix, escapedDeviceName)

// Request removal of device.
err = monitor.RemoveDevice(deviceID)
Expand Down Expand Up @@ -3724,7 +3724,7 @@ func (d *qemu) addRootDriveConfig(qemuDev map[string]string, mountInfo *storageP

// addDriveDirConfig adds the qemu config required for adding a supplementary drive directory share.
func (d *qemu) addDriveDirConfig(cfg *[]cfgSection, bus *qemuBus, fdFiles *[]*os.File, agentMounts *[]instancetype.VMAgentMount, driveConf deviceConfig.MountEntryItem) error {
mountTag := fmt.Sprintf("lxd_%s", driveConf.DevName)
mountTag := d.generateQemuDeviceName(driveConf.DevName)

agentMount := instancetype.VMAgentMount{
Source: mountTag,
Expand Down Expand Up @@ -3952,7 +3952,7 @@ func (d *qemu) addDriveConfig(qemuDev map[string]string, bootIndexes map[string]
},
"discard": "unmap", // Forward as an unmap request. This is the same as `discard=on` in the qemu config file.
"driver": "file",
"node-name": d.blockNodeName(escapedDeviceName),
"node-name": d.generateQemuDeviceName(escapedDeviceName),
"read-only": false,
}

Expand Down Expand Up @@ -4067,7 +4067,7 @@ func (d *qemu) addDriveConfig(qemuDev map[string]string, bootIndexes map[string]
}

qemuDev["drive"] = qemuDevDrive
qemuDev["serial"] = fmt.Sprintf("%s%s", qemuBlockDevIDPrefix, escapedDeviceName)
qemuDev["serial"] = fmt.Sprintf("%s%s", qemuDeviceNamePrefix, escapedDeviceName)

if bus == "virtio-scsi" {
qemuDev["channel"] = "0"
Expand Down Expand Up @@ -4112,7 +4112,7 @@ func (d *qemu) addDriveConfig(qemuDev map[string]string, bootIndexes map[string]
revert := revert.New()
defer revert.Fail()

nodeName := fmt.Sprintf("%s%s", qemuBlockDevIDPrefix, escapedDeviceName)
nodeName := fmt.Sprintf("%s%s", qemuDeviceNamePrefix, escapedDeviceName)

if isRBDImage {
secretID := fmt.Sprintf("pool_%s_%s", blockDev["pool"], blockDev["user"])
Expand Down Expand Up @@ -4308,7 +4308,7 @@ func (d *qemu) addNetDevConfig(busName string, qemuDev map[string]string, bootIn
}

qemuNetDev := map[string]any{
"id": fmt.Sprintf("%s%s", qemuNetDevIDPrefix, escapedDeviceName),
"id": fmt.Sprintf("%s%s", qemuDeviceNamePrefix, escapedDeviceName),
"type": "tap",
"vhost": vhostNetEnabled,
}
Expand Down Expand Up @@ -8686,7 +8686,7 @@ func (d *qemu) checkFeatures(hostArch int, qemuPath string) (map[string]any, err

// Check io_uring feature.
blockDev := map[string]any{
"node-name": d.blockNodeName("feature-check"),
"node-name": d.generateQemuDeviceName("feature-check"),
"driver": "file",
"filename": blockDevPath.Name(),
"aio": "io_uring",
Expand Down Expand Up @@ -8907,21 +8907,22 @@ func (d *qemu) deviceDetachUSB(usbDev deviceConfig.USBDeviceItem) error {
return nil
}

// Block node names may only be up to 31 characters long, so use a hash if longer.
func (d *qemu) blockNodeName(name string) string {
if len(name) > 27 {
// Block node names and device tags may only be up to 31 characters long, so use a hash if longer.
func (d *qemu) generateQemuDeviceName(name string) string {
maxNameLength := qemuDeviceNameMaxLength - len(qemuDeviceNamePrefix)
if len(name) > maxNameLength {
// If the name is too long, hash it as SHA-256 (32 bytes).
// Then encode the SHA-256 binary hash as Base64 Raw URL format and trim down to 27 chars.
// Raw URL avoids the use of "+" character and the padding "=" character which QEMU doesn't allow.
hash := sha256.New()
hash.Write([]byte(name))
binaryHash := hash.Sum(nil)
name = base64.RawURLEncoding.EncodeToString(binaryHash)
name = name[0:27]
name = name[0:maxNameLength]
}

// Apply the lxd_ prefix.
return fmt.Sprintf("%s%s", qemuBlockDevIDPrefix, name)
return fmt.Sprintf("%s%s", qemuDeviceNamePrefix, name)
}

func (d *qemu) setCPUs(count int) error {
Expand Down
Loading