Skip to content

Commit

Permalink
libvirt: add support for aarch64 host
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Seunguk Shin <[email protected]>
Reviewed-by: Nick Connolly <[email protected]>
  • Loading branch information
xutao323 committed Dec 9, 2024
1 parent 4dea914 commit cc38338
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 3 deletions.
113 changes: 113 additions & 0 deletions src/cloud-providers/libvirt/libvirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down
42 changes: 39 additions & 3 deletions src/cloud-providers/libvirt/libvirt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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)
}
}

0 comments on commit cc38338

Please sign in to comment.