mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-22 20:00:18 +00:00
Manager can start CVM with NVIDIA GPU support (#595)
CI / lint (push) Has been cancelled
CI / test (agent) (push) Has been cancelled
CI / test (cli) (push) Has been cancelled
CI / test (cmd) (push) Has been cancelled
CI / test (internal) (push) Has been cancelled
CI / test (manager, true) (push) Has been cancelled
CI / test (pkg) (push) Has been cancelled
CI / upload-coverage (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (agent) (push) Has been cancelled
CI / test (cli) (push) Has been cancelled
CI / test (cmd) (push) Has been cancelled
CI / test (internal) (push) Has been cancelled
CI / test (manager, true) (push) Has been cancelled
CI / test (pkg) (push) Has been cancelled
CI / upload-coverage (push) Has been cancelled
This commit is contained in:
@@ -81,6 +81,14 @@ type DiskConfig struct {
|
||||
SCSIID string `env:"DISK_SCSI_ID" envDefault:"scsi0"`
|
||||
}
|
||||
|
||||
type GPUConfig struct {
|
||||
EnableGPU bool
|
||||
GPUBDF string `env:"GPU_BDF" envDefault:""`
|
||||
PCIeRootPort string `env:"GPU_PCIE_ROOT_PORT" envDefault:"pci.1"`
|
||||
PCIeBus string `env:"GPU_PCIE_BUS" envDefault:"pcie.0"`
|
||||
FWCfgPciMmio string `env:"GPU_FW_CFG_MMIO_MB" envDefault:"262144"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
EnableSEVSNP bool
|
||||
EnableTDX bool
|
||||
@@ -121,6 +129,9 @@ type Config struct {
|
||||
// vTPM
|
||||
IGVMConfig
|
||||
|
||||
// GPU passthrough
|
||||
GPUConfig
|
||||
|
||||
// display
|
||||
NoGraphic bool `env:"NO_GRAPHIC" envDefault:"true"`
|
||||
Monitor string `env:"MONITOR" envDefault:"pty"`
|
||||
@@ -227,6 +238,23 @@ func (config Config) ConstructQemuArgs() []string {
|
||||
config.DiskConfig.SCSIID))
|
||||
}
|
||||
|
||||
// GPU passthrough via VFIO
|
||||
if config.GPUConfig.EnableGPU {
|
||||
args = append(args, "-device",
|
||||
fmt.Sprintf("pcie-root-port,id=%s,bus=%s",
|
||||
config.GPUConfig.PCIeRootPort,
|
||||
config.GPUConfig.PCIeBus))
|
||||
|
||||
args = append(args, "-device",
|
||||
fmt.Sprintf("vfio-pci,host=%s,bus=%s",
|
||||
config.GPUConfig.GPUBDF,
|
||||
config.GPUConfig.PCIeRootPort))
|
||||
|
||||
args = append(args, "-fw_cfg",
|
||||
fmt.Sprintf("name=opt/ovmf/X-PciMmio64Mb,string=%s",
|
||||
config.GPUConfig.FWCfgPciMmio))
|
||||
}
|
||||
|
||||
// SEV-SNP
|
||||
if config.EnableSEVSNP {
|
||||
sevSnpType := "sev-snp-guest"
|
||||
@@ -317,5 +345,13 @@ func NewConfig() (*Config, error) {
|
||||
cfg.EnableSEVSNP = SEVSNPEnabledOnHost()
|
||||
cfg.EnableTDX = TDXEnabledOnHost()
|
||||
|
||||
bdf, detected := GPUPassthroughAvailable()
|
||||
if cfg.GPUConfig.GPUBDF != "" {
|
||||
cfg.GPUConfig.EnableGPU = true
|
||||
} else if detected {
|
||||
cfg.GPUConfig.EnableGPU = true
|
||||
cfg.GPUConfig.GPUBDF = bdf
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
@@ -151,6 +151,79 @@ func TestConstructQemuArgs(t *testing.T) {
|
||||
"-monitor", "pty",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GPU passthrough configuration",
|
||||
config: Config{
|
||||
QemuBinPath: "qemu-system-x86_64",
|
||||
EnableKVM: true,
|
||||
Machine: "q35",
|
||||
CPU: "EPYC",
|
||||
SMPCount: 4,
|
||||
MaxCPUs: 64,
|
||||
MemID: "ram1",
|
||||
MemoryConfig: MemoryConfig{
|
||||
Size: "2048M",
|
||||
Slots: 5,
|
||||
Max: "30G",
|
||||
},
|
||||
OVMFCodeConfig: OVMFCodeConfig{
|
||||
If: "pflash",
|
||||
Format: "raw",
|
||||
Unit: 0,
|
||||
File: "/usr/share/OVMF/OVMF_CODE.fd",
|
||||
ReadOnly: "on",
|
||||
},
|
||||
OVMFVarsConfig: OVMFVarsConfig{
|
||||
If: "pflash",
|
||||
Format: "raw",
|
||||
Unit: 1,
|
||||
File: "/usr/share/OVMF/OVMF_VARS.fd",
|
||||
},
|
||||
NetDevConfig: NetDevConfig{
|
||||
ID: "vmnic",
|
||||
HostFwdAgent: 7020,
|
||||
GuestFwdAgent: 7002,
|
||||
},
|
||||
VirtioNetPciConfig: VirtioNetPciConfig{
|
||||
DisableLegacy: "on",
|
||||
IOMMUPlatform: true,
|
||||
Addr: "0x2",
|
||||
},
|
||||
KernelConfig: KernelConfig{
|
||||
KernelFile: "img/bzImage",
|
||||
RootFsFile: "img/rootfs.cpio.gz",
|
||||
},
|
||||
GPUConfig: GPUConfig{
|
||||
EnableGPU: true,
|
||||
GPUBDF: "0000:02:00.0",
|
||||
PCIeRootPort: "pci.1",
|
||||
PCIeBus: "pcie.0",
|
||||
FWCfgPciMmio: "262144",
|
||||
},
|
||||
KernelCommandLine: "quiet console=null",
|
||||
NoGraphic: true,
|
||||
Monitor: "pty",
|
||||
},
|
||||
expected: []string{
|
||||
"-enable-kvm",
|
||||
"-machine", "q35",
|
||||
"-cpu", "EPYC",
|
||||
"-smp", "4,maxcpus=64",
|
||||
"-m", "2048M,slots=5,maxmem=30G",
|
||||
"-drive", "if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on",
|
||||
"-drive", "if=pflash,format=raw,unit=1,file=/usr/share/OVMF/OVMF_VARS.fd",
|
||||
"-netdev", "user,id=vmnic,hostfwd=tcp::7020-:7002",
|
||||
"-device", "virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,addr=0x2,romfile=",
|
||||
"-device", "pcie-root-port,id=pci.1,bus=pcie.0",
|
||||
"-device", "vfio-pci,host=0000:02:00.0,bus=pci.1",
|
||||
"-fw_cfg", "name=opt/ovmf/X-PciMmio64Mb,string=262144",
|
||||
"-kernel", "img/bzImage",
|
||||
"-append", "quiet console=null",
|
||||
"-initrd", "img/rootfs.cpio.gz",
|
||||
"-nographic",
|
||||
"-monitor", "pty",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -319,3 +319,36 @@ func GetVirtualSizeGB(path string) (int, error) {
|
||||
gb := (bytes + (1<<30 - 1)) >> 30
|
||||
return int(gb), nil
|
||||
}
|
||||
|
||||
// GPUPassthroughAvailable scans for NVIDIA GPU devices bound to the vfio-pci
|
||||
// driver and returns the BDF of the first one found.
|
||||
func GPUPassthroughAvailable() (string, bool) {
|
||||
const vfioPCIPath = "/sys/bus/pci/drivers/vfio-pci"
|
||||
entries, err := os.ReadDir(vfioPCIPath)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
bdf := entry.Name()
|
||||
if !strings.Contains(bdf, ":") {
|
||||
continue
|
||||
}
|
||||
|
||||
vendor, err := os.ReadFile(fmt.Sprintf("/sys/bus/pci/devices/%s/vendor", bdf))
|
||||
if err != nil || strings.TrimSpace(string(vendor)) != "0x10de" {
|
||||
continue
|
||||
}
|
||||
|
||||
class, err := os.ReadFile(fmt.Sprintf("/sys/bus/pci/devices/%s/class", bdf))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
classStr := strings.TrimSpace(string(class))
|
||||
// 0x0302xx = 3D Controller (e.g. H100), 0x0300xx = VGA Compatible Controller
|
||||
if strings.HasPrefix(classStr, "0x0302") || strings.HasPrefix(classStr, "0x0300") {
|
||||
return bdf, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user