From cc383384dbeb765ec84668cc9fca289121e64e02 Mon Sep 17 00:00:00 2001 From: Tao Xu Date: Tue, 19 Nov 2024 15:59:36 +0000 Subject: [PATCH] libvirt: add support for aarch64 host create domainXML for aarch64/arm64 architecture in cloud-provider/libvirt, and check iommu=on for virtio device only in test. Signed-off-by: Tao Xu Reviewed-by: Seunguk Shin Reviewed-by: Nick Connolly --- src/cloud-providers/libvirt/libvirt.go | 113 ++++++++++++++++++++ src/cloud-providers/libvirt/libvirt_test.go | 42 +++++++- 2 files changed, 152 insertions(+), 3 deletions(-) diff --git a/src/cloud-providers/libvirt/libvirt.go b/src/cloud-providers/libvirt/libvirt.go index a68fae40d..559acbf69 100644 --- a/src/cloud-providers/libvirt/libvirt.go +++ b/src/cloud-providers/libvirt/libvirt.go @@ -21,6 +21,8 @@ import ( const ( // architecture value for the s390x architecture archS390x = "s390x" + // architecutre value for aarch64/arm64 + archAArch64 = "aarch64" // hvm indicates that the OS is one designed to run on bare metal, so requires full virtualization. typeHardwareVirtualMachine = "hvm" // The amount of retries to get the domain IP addresses @@ -490,11 +492,122 @@ func enableSEV(client *libvirtClient, cfg *domainConfig, vm *vmConfig, domain *l return domain, nil } +func createDomainXMLaarch64(client *libvirtClient, cfg *domainConfig, vm *vmConfig) (*libvirtxml.Domain, error) { + + guest, err := getGuestForArchType(client.caps, archAArch64, typeHardwareVirtualMachine) + if err != nil { + return nil, err + } + canonicalmachine, err := getCanonicalMachineName(client.caps, archAArch64, typeHardwareVirtualMachine, "virt") + if err != nil { + return nil, err + } + + bootDisk := libvirtxml.DomainDisk{ + Device: "disk", + Target: &libvirtxml.DomainDiskTarget{ + Dev: "vda", + Bus: "virtio", + }, + Driver: &libvirtxml.DomainDiskDriver{ + Name: "qemu", + Type: "qcow2", + // only for virtio device + IOMMU: "on", + }, + Source: &libvirtxml.DomainDiskSource{ + File: &libvirtxml.DomainDiskSourceFile{ + File: cfg.bootDisk, + }, + }, + Boot: &libvirtxml.DomainDeviceBoot{ + Order: 1, + }, + } + cloudInitDisk := libvirtxml.DomainDisk{ + Device: "cdrom", + Target: &libvirtxml.DomainDiskTarget{ + // logical dev name, just a hint + Dev: "sda", + Bus: "scsi", + }, + Driver: &libvirtxml.DomainDiskDriver{ + Name: "qemu", + Type: "raw", + }, + Source: &libvirtxml.DomainDiskSource{ + File: &libvirtxml.DomainDiskSourceFile{ + File: cfg.cidataDisk, + }, + }, + ReadOnly: &libvirtxml.DomainDiskReadOnly{}, + } + + domain := &libvirtxml.Domain{ + Type: "kvm", + Name: cfg.name, + Description: "This Virtual Machine is the peer-pod VM", + OS: &libvirtxml.DomainOS{ + Type: &libvirtxml.DomainOSType{ + Type: typeHardwareVirtualMachine, + Arch: archAArch64, + Machine: canonicalmachine, + }, + // firmware autoselection since libvirt v5.2.0 + // https://libvirt.org/formatdomain.html#bios-bootloader + Firmware: "efi", + }, + Memory: &libvirtxml.DomainMemory{Value: cfg.mem, Unit: "GiB"}, + VCPU: &libvirtxml.DomainVCPU{Value: cfg.cpu}, + CPU: &libvirtxml.DomainCPU{Mode: "host-passthrough"}, + Devices: &libvirtxml.DomainDeviceList{ + Disks: []libvirtxml.DomainDisk{ + bootDisk, + cloudInitDisk, + }, + // scsi target device for readonly ROM device + // virtio-scsi controller for better compatibility + Controllers: []libvirtxml.DomainController{ + { + Type: "scsi", + Model: "virtio-scsi", + }, + }, + Emulator: guest.Arch.Emulator, + MemBalloon: &libvirtxml.DomainMemBalloon{Model: "virtio", Driver: &libvirtxml.DomainMemBalloonDriver{IOMMU: "on"}}, + Interfaces: []libvirtxml.DomainInterface{ + { + Model: &libvirtxml.DomainInterfaceModel{ + Type: "virtio", + }, + Source: &libvirtxml.DomainInterfaceSource{ + Network: &libvirtxml.DomainInterfaceSourceNetwork{ + Network: cfg.networkName, + }, + }, + Driver: &libvirtxml.DomainInterfaceDriver{ + IOMMU: "on", + }, + }, + }, + Consoles: []libvirtxml.DomainConsole{ + { + Target: &libvirtxml.DomainConsoleTarget{Type: "serial"}, + }, + }, + }, + } + + return domain, nil +} + // createDomainXML detects the machine type of the libvirt host and will return a libvirt XML for that machine type func createDomainXML(client *libvirtClient, cfg *domainConfig, vm *vmConfig) (*libvirtxml.Domain, error) { switch client.nodeInfo.Model { case archS390x: return createDomainXMLs390x(client, cfg, vm) + case archAArch64: + return createDomainXMLaarch64(client, cfg, vm) default: return createDomainXMLx86_64(client, cfg, vm) } diff --git a/src/cloud-providers/libvirt/libvirt_test.go b/src/cloud-providers/libvirt/libvirt_test.go index 2fa036fa8..6cacb4601 100644 --- a/src/cloud-providers/libvirt/libvirt_test.go +++ b/src/cloud-providers/libvirt/libvirt_test.go @@ -62,18 +62,18 @@ func TestGetArchitecture(t *testing.T) { func verifyDomainXML(domXML *libvirtxml.Domain) error { arch := domXML.OS.Type.Arch - if arch != archS390x { + if arch != archS390x && arch != archAArch64 { return nil } // verify we have iommu on the disks for i, disk := range domXML.Devices.Disks { - if disk.Driver.IOMMU != "on" { + if disk.Target.Bus == "virtio" && disk.Driver.IOMMU != "on" { return fmt.Errorf("disk [%d] does not have IOMMU assigned", i) } } // verify we have iommu on the networks for i, iface := range domXML.Devices.Interfaces { - if iface.Driver.IOMMU != "on" { + if iface.Model.Type == "virtio" && iface.Driver.IOMMU != "on" { return fmt.Errorf("interface [%d] does not have IOMMU assigned", i) } } @@ -116,3 +116,39 @@ func TestCreateDomainXMLs390x(t *testing.T) { t.Error(err) } } + +func TestCreateDomainXMLaarch64(t *testing.T) { + checkConfig(t) + + client, err := NewLibvirtClient(testCfg) + if err != nil { + t.Error(err) + } + defer client.connection.Close() + + vm := vmConfig{} + + domainCfg := domainConfig{ + name: "TestCreateDomainAArch64", + cpu: 2, + mem: 4, + networkName: client.networkName, + bootDisk: "/var/lib/libvirt/images/root.qcow2", + cidataDisk: "/var/lib/libvirt/images/cloudinit.iso", + } + + domCfg, err := createDomainXML(client, &domainCfg, &vm) + if err != nil { + t.Error(err) + } + + arch := domCfg.OS.Type.Arch + if domCfg.OS.Type.Arch != archAArch64 { + t.Skipf("Skipping because architecture is [%s] and not [%s].", arch, archAArch64) + } + + err = verifyDomainXML(domCfg) + if err != nil { + t.Error(err) + } +}