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

providers/libvirt: add support for aarch64 host #2193

Merged
merged 1 commit into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
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
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)
}
}
Loading