gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/qemu_arch_base.go (about) 1 // Copyright (c) 2018 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package virtcontainers 7 8 import ( 9 "context" 10 "encoding/hex" 11 "errors" 12 "fmt" 13 "os" 14 "strconv" 15 "strings" 16 17 govmmQemu "github.com/intel/govmm/qemu" 18 19 "github.com/kata-containers/runtime/virtcontainers/device/config" 20 "github.com/kata-containers/runtime/virtcontainers/types" 21 "github.com/kata-containers/runtime/virtcontainers/utils" 22 ) 23 24 type qemuArch interface { 25 // enableNestingChecks nesting checks will be honoured 26 enableNestingChecks() 27 28 // disableNestingChecks nesting checks will be ignored 29 disableNestingChecks() 30 31 // runNested indicates if the hypervisor runs in a nested environment 32 runNested() bool 33 34 // enableVhostNet vhost will be enabled 35 enableVhostNet() 36 37 // disableVhostNet vhost will be disabled 38 disableVhostNet() 39 40 // machine returns the machine type 41 machine() (govmmQemu.Machine, error) 42 43 // qemuPath returns the path to the QEMU binary 44 qemuPath() (string, error) 45 46 // kernelParameters returns the kernel parameters 47 // if debug is true then kernel debug parameters are included 48 kernelParameters(debug bool) []Param 49 50 //capabilities returns the capabilities supported by QEMU 51 capabilities() types.Capabilities 52 53 // bridges sets the number bridges for the machine type 54 bridges(number uint32) 55 56 // cpuTopology returns the CPU topology for the given amount of vcpus 57 cpuTopology(vcpus, maxvcpus uint32) govmmQemu.SMP 58 59 // cpuModel returns the CPU model for the machine type 60 cpuModel() string 61 62 // memoryTopology returns the memory topology using the given amount of memoryMb and hostMemoryMb 63 memoryTopology(memoryMb, hostMemoryMb uint64, slots uint8) govmmQemu.Memory 64 65 // appendConsole appends a console to devices 66 appendConsole(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) 67 68 // appendImage appends an image to devices 69 appendImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) 70 71 // appendBlockImage appends an image as block device 72 appendBlockImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) 73 74 // appendNvdimmImage appends an image as nvdimm device 75 appendNvdimmImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) 76 77 // appendSCSIController appens a SCSI controller to devices 78 appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread, error) 79 80 // appendBridges appends bridges to devices 81 appendBridges(devices []govmmQemu.Device) []govmmQemu.Device 82 83 // append9PVolume appends a 9P volume to devices 84 append9PVolume(devices []govmmQemu.Device, volume types.Volume) ([]govmmQemu.Device, error) 85 86 // appendSocket appends a socket to devices 87 appendSocket(devices []govmmQemu.Device, socket types.Socket) []govmmQemu.Device 88 89 // appendVSock appends a vsock PCI to devices 90 appendVSock(devices []govmmQemu.Device, vsock types.VSock) ([]govmmQemu.Device, error) 91 92 // appendNetwork appends a endpoint device to devices 93 appendNetwork(devices []govmmQemu.Device, endpoint Endpoint) ([]govmmQemu.Device, error) 94 95 // appendBlockDevice appends a block drive to devices 96 appendBlockDevice(devices []govmmQemu.Device, drive config.BlockDrive) ([]govmmQemu.Device, error) 97 98 // appendVhostUserDevice appends a vhost user device to devices 99 appendVhostUserDevice(devices []govmmQemu.Device, drive config.VhostUserDeviceAttrs) ([]govmmQemu.Device, error) 100 101 // appendVFIODevice appends a VFIO device to devices 102 appendVFIODevice(devices []govmmQemu.Device, vfioDevice config.VFIODev) []govmmQemu.Device 103 104 // appendRNGDevice appends a RNG device to devices 105 appendRNGDevice(devices []govmmQemu.Device, rngDevice config.RNGDev) ([]govmmQemu.Device, error) 106 107 // addDeviceToBridge adds devices to the bus 108 addDeviceToBridge(ID string, t types.Type) (string, types.Bridge, error) 109 110 // removeDeviceFromBridge removes devices to the bus 111 removeDeviceFromBridge(ID string) error 112 113 // getBridges grants access to Bridges 114 getBridges() []types.Bridge 115 116 // setBridges grants access to Bridges 117 setBridges(bridges []types.Bridge) 118 119 // addBridge adds a new Bridge to the list of Bridges 120 addBridge(types.Bridge) 121 122 // handleImagePath handles the Hypervisor Config image path 123 handleImagePath(config HypervisorConfig) 124 125 // supportGuestMemoryHotplug returns if the guest supports memory hotplug 126 supportGuestMemoryHotplug() bool 127 128 // setIgnoreSharedMemoryMigrationCaps set bypass-shared-memory capability for migration 129 setIgnoreSharedMemoryMigrationCaps(context.Context, *govmmQemu.QMP) error 130 131 // appendPCIeRootPortDevice appends a pcie-root-port device to pcie.0 bus 132 appendPCIeRootPortDevice(devices []govmmQemu.Device, number uint32) []govmmQemu.Device 133 } 134 135 type qemuArchBase struct { 136 machineType string 137 memoryOffset uint32 138 nestedRun bool 139 vhost bool 140 disableNvdimm bool 141 dax bool 142 networkIndex int 143 qemuPaths map[string]string 144 supportedQemuMachines []govmmQemu.Machine 145 kernelParamsNonDebug []Param 146 kernelParamsDebug []Param 147 kernelParams []Param 148 Bridges []types.Bridge 149 } 150 151 const ( 152 defaultCores uint32 = 1 153 defaultThreads uint32 = 1 154 defaultCPUModel = "host" 155 defaultBridgeBus = "pcie.0" 156 defaultPCBridgeBus = "pci.0" 157 maxDevIDSize = 31 158 defaultMsize9p = 8192 159 pcieRootPortPrefix = "rp" 160 ) 161 162 // This is the PCI start address assigned to the first bridge that 163 // is added on the qemu command line. In case of x86_64, the first two PCI 164 // addresses (0 and 1) are used by the platform while in case of ARM, address 165 // 0 is reserved. 166 const bridgePCIStartAddr = 2 167 168 const ( 169 // QemuPCLite is the QEMU pc-lite machine type for amd64 170 QemuPCLite = "pc-lite" 171 172 // QemuPC is the QEMU pc machine type for amd64 173 QemuPC = "pc" 174 175 // QemuQ35 is the QEMU Q35 machine type for amd64 176 QemuQ35 = "q35" 177 178 // QemuMicrovm is the QEMU microvm machine type for amd64 179 QemuMicrovm = "microvm" 180 181 // QemuVirt is the QEMU virt machine type for aarch64 or amd64 182 QemuVirt = "virt" 183 184 // QemuPseries is a QEMU virt machine type for ppc64le 185 QemuPseries = "pseries" 186 187 // QemuCCWVirtio is a QEMU virt machine type for for s390x 188 QemuCCWVirtio = "s390-ccw-virtio" 189 190 qmpCapMigrationIgnoreShared = "x-ignore-shared" 191 192 qemuNvdimmOption = "nvdimm" 193 ) 194 195 // kernelParamsNonDebug is a list of the default kernel 196 // parameters that will be used in standard (non-debug) mode. 197 var kernelParamsNonDebug = []Param{ 198 {"quiet", ""}, 199 } 200 201 // kernelParamsSystemdNonDebug is a list of the default systemd related 202 // kernel parameters that will be used in standard (non-debug) mode. 203 var kernelParamsSystemdNonDebug = []Param{ 204 {"systemd.show_status", "false"}, 205 } 206 207 // kernelParamsDebug is a list of the default kernel 208 // parameters that will be used in debug mode (as much boot output as 209 // possible). 210 var kernelParamsDebug = []Param{ 211 {"debug", ""}, 212 } 213 214 // kernelParamsSystemdDebug is a list of the default systemd related kernel 215 // parameters that will be used in debug mode (as much boot output as 216 // possible). 217 var kernelParamsSystemdDebug = []Param{ 218 {"systemd.show_status", "true"}, 219 {"systemd.log_level", "debug"}, 220 } 221 222 func (q *qemuArchBase) enableNestingChecks() { 223 q.nestedRun = true 224 } 225 226 func (q *qemuArchBase) disableNestingChecks() { 227 q.nestedRun = false 228 } 229 230 func (q *qemuArchBase) runNested() bool { 231 return q.nestedRun 232 } 233 234 func (q *qemuArchBase) enableVhostNet() { 235 q.vhost = true 236 } 237 238 func (q *qemuArchBase) disableVhostNet() { 239 q.vhost = false 240 } 241 242 func (q *qemuArchBase) machine() (govmmQemu.Machine, error) { 243 for _, m := range q.supportedQemuMachines { 244 if m.Type == q.machineType { 245 return m, nil 246 } 247 } 248 249 return govmmQemu.Machine{}, fmt.Errorf("unrecognised machine type: %v", q.machineType) 250 } 251 252 func (q *qemuArchBase) qemuPath() (string, error) { 253 p, ok := q.qemuPaths[q.machineType] 254 if !ok { 255 return "", fmt.Errorf("Unknown machine type: %s", q.machineType) 256 } 257 258 return p, nil 259 } 260 261 func (q *qemuArchBase) kernelParameters(debug bool) []Param { 262 params := q.kernelParams 263 264 if debug { 265 params = append(params, q.kernelParamsDebug...) 266 } else { 267 params = append(params, q.kernelParamsNonDebug...) 268 } 269 270 return params 271 } 272 273 func (q *qemuArchBase) capabilities() types.Capabilities { 274 var caps types.Capabilities 275 caps.SetBlockDeviceHotplugSupport() 276 caps.SetMultiQueueSupport() 277 caps.SetFsSharingSupport() 278 return caps 279 } 280 281 func (q *qemuArchBase) bridges(number uint32) { 282 for i := uint32(0); i < number; i++ { 283 q.Bridges = append(q.Bridges, types.NewBridge(types.PCI, fmt.Sprintf("%s-bridge-%d", types.PCI, i), make(map[uint32]string), 0)) 284 } 285 } 286 287 func (q *qemuArchBase) cpuTopology(vcpus, maxvcpus uint32) govmmQemu.SMP { 288 smp := govmmQemu.SMP{ 289 CPUs: vcpus, 290 Sockets: maxvcpus, 291 Cores: defaultCores, 292 Threads: defaultThreads, 293 MaxCPUs: maxvcpus, 294 } 295 296 return smp 297 } 298 299 func (q *qemuArchBase) cpuModel() string { 300 return defaultCPUModel 301 } 302 303 func (q *qemuArchBase) memoryTopology(memoryMb, hostMemoryMb uint64, slots uint8) govmmQemu.Memory { 304 memMax := fmt.Sprintf("%dM", hostMemoryMb) 305 mem := fmt.Sprintf("%dM", memoryMb) 306 memory := govmmQemu.Memory{ 307 Size: mem, 308 Slots: slots, 309 MaxMem: memMax, 310 } 311 312 return memory 313 } 314 315 func (q *qemuArchBase) appendConsole(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 316 serial := govmmQemu.SerialDevice{ 317 Driver: govmmQemu.VirtioSerial, 318 ID: "serial0", 319 DisableModern: q.nestedRun, 320 } 321 322 devices = append(devices, serial) 323 324 console := govmmQemu.CharDevice{ 325 Driver: govmmQemu.Console, 326 Backend: govmmQemu.Socket, 327 DeviceID: "console0", 328 ID: "charconsole0", 329 Path: path, 330 } 331 332 devices = append(devices, console) 333 334 return devices, nil 335 } 336 337 func genericImage(path string) (config.BlockDrive, error) { 338 if _, err := os.Stat(path); os.IsNotExist(err) { 339 return config.BlockDrive{}, err 340 } 341 342 randBytes, err := utils.GenerateRandomBytes(8) 343 if err != nil { 344 return config.BlockDrive{}, err 345 } 346 347 id := utils.MakeNameID("image", hex.EncodeToString(randBytes), maxDevIDSize) 348 349 drive := config.BlockDrive{ 350 File: path, 351 Format: "raw", 352 ID: id, 353 ShareRW: true, 354 ReadOnly: true, 355 } 356 357 return drive, nil 358 } 359 360 func (q *qemuArchBase) appendNvdimmImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 361 imageFile, err := os.Open(path) 362 if err != nil { 363 return nil, err 364 } 365 defer imageFile.Close() 366 367 imageStat, err := imageFile.Stat() 368 if err != nil { 369 return nil, err 370 } 371 372 object := govmmQemu.Object{ 373 Driver: govmmQemu.NVDIMM, 374 Type: govmmQemu.MemoryBackendFile, 375 DeviceID: "nv0", 376 ID: "mem0", 377 MemPath: path, 378 Size: (uint64)(imageStat.Size()), 379 } 380 381 devices = append(devices, object) 382 383 return devices, nil 384 } 385 386 func (q *qemuArchBase) appendImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 387 return q.appendBlockImage(devices, path) 388 } 389 390 func (q *qemuArchBase) appendBlockImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 391 drive, err := genericImage(path) 392 if err != nil { 393 return nil, err 394 } 395 devices, err = q.appendBlockDevice(devices, drive) 396 if err != nil { 397 return nil, err 398 } 399 return devices, nil 400 } 401 402 func genericSCSIController(enableIOThreads, nestedRun bool) (govmmQemu.SCSIController, *govmmQemu.IOThread) { 403 scsiController := govmmQemu.SCSIController{ 404 ID: scsiControllerID, 405 DisableModern: nestedRun, 406 } 407 408 var t *govmmQemu.IOThread 409 410 if enableIOThreads { 411 randBytes, _ := utils.GenerateRandomBytes(8) 412 413 t = &govmmQemu.IOThread{ 414 ID: fmt.Sprintf("%s-%s", "iothread", hex.EncodeToString(randBytes)), 415 } 416 417 scsiController.IOThread = t.ID 418 } 419 420 return scsiController, t 421 } 422 423 func (q *qemuArchBase) appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread, error) { 424 d, t := genericSCSIController(enableIOThreads, q.nestedRun) 425 devices = append(devices, d) 426 return devices, t, nil 427 } 428 429 // appendBridges appends to devices the given bridges 430 func (q *qemuArchBase) appendBridges(devices []govmmQemu.Device) []govmmQemu.Device { 431 for idx, b := range q.Bridges { 432 if b.Type == types.CCW { 433 continue 434 } 435 t := govmmQemu.PCIBridge 436 if b.Type == types.PCIE { 437 t = govmmQemu.PCIEBridge 438 } 439 440 q.Bridges[idx].Addr = bridgePCIStartAddr + idx 441 442 devices = append(devices, 443 govmmQemu.BridgeDevice{ 444 Type: t, 445 Bus: defaultBridgeBus, 446 ID: b.ID, 447 // Each bridge is required to be assigned a unique chassis id > 0 448 Chassis: idx + 1, 449 SHPC: true, 450 Addr: strconv.FormatInt(int64(q.Bridges[idx].Addr), 10), 451 }, 452 ) 453 } 454 455 return devices 456 } 457 458 func generic9PVolume(volume types.Volume, nestedRun bool) govmmQemu.FSDevice { 459 devID := fmt.Sprintf("extra-9p-%s", volume.MountTag) 460 if len(devID) > maxDevIDSize { 461 devID = devID[:maxDevIDSize] 462 } 463 464 return govmmQemu.FSDevice{ 465 Driver: govmmQemu.Virtio9P, 466 FSDriver: govmmQemu.Local, 467 ID: devID, 468 Path: volume.HostPath, 469 MountTag: volume.MountTag, 470 SecurityModel: govmmQemu.None, 471 DisableModern: nestedRun, 472 } 473 } 474 475 func (q *qemuArchBase) append9PVolume(devices []govmmQemu.Device, volume types.Volume) ([]govmmQemu.Device, error) { 476 if volume.MountTag == "" || volume.HostPath == "" { 477 return devices, nil 478 } 479 480 d := generic9PVolume(volume, q.nestedRun) 481 devices = append(devices, d) 482 return devices, nil 483 } 484 485 func (q *qemuArchBase) appendSocket(devices []govmmQemu.Device, socket types.Socket) []govmmQemu.Device { 486 devID := socket.ID 487 if len(devID) > maxDevIDSize { 488 devID = devID[:maxDevIDSize] 489 } 490 491 devices = append(devices, 492 govmmQemu.CharDevice{ 493 Driver: govmmQemu.VirtioSerialPort, 494 Backend: govmmQemu.Socket, 495 DeviceID: socket.DeviceID, 496 ID: devID, 497 Path: socket.HostPath, 498 Name: socket.Name, 499 }, 500 ) 501 502 return devices 503 } 504 505 func (q *qemuArchBase) appendVSock(devices []govmmQemu.Device, vsock types.VSock) ([]govmmQemu.Device, error) { 506 devices = append(devices, 507 govmmQemu.VSOCKDevice{ 508 ID: fmt.Sprintf("vsock-%d", vsock.ContextID), 509 ContextID: vsock.ContextID, 510 VHostFD: vsock.VhostFd, 511 DisableModern: q.nestedRun, 512 }, 513 ) 514 515 return devices, nil 516 517 } 518 519 func networkModelToQemuType(model NetInterworkingModel) govmmQemu.NetDeviceType { 520 switch model { 521 case NetXConnectMacVtapModel: 522 return govmmQemu.MACVTAP 523 default: 524 //TAP should work for most other cases 525 return govmmQemu.TAP 526 } 527 } 528 529 func genericNetwork(endpoint Endpoint, vhost, nestedRun bool, index int) (govmmQemu.NetDevice, error) { 530 var d govmmQemu.NetDevice 531 switch ep := endpoint.(type) { 532 case *VethEndpoint, *BridgedMacvlanEndpoint, *IPVlanEndpoint: 533 netPair := ep.NetworkPair() 534 d = govmmQemu.NetDevice{ 535 Type: networkModelToQemuType(netPair.NetInterworkingModel), 536 Driver: govmmQemu.VirtioNet, 537 ID: fmt.Sprintf("network-%d", index), 538 IFName: netPair.TAPIface.Name, 539 MACAddress: netPair.TAPIface.HardAddr, 540 DownScript: "no", 541 Script: "no", 542 VHost: vhost, 543 DisableModern: nestedRun, 544 FDs: netPair.VMFds, 545 VhostFDs: netPair.VhostFds, 546 } 547 case *MacvtapEndpoint: 548 d = govmmQemu.NetDevice{ 549 Type: govmmQemu.MACVTAP, 550 Driver: govmmQemu.VirtioNet, 551 ID: fmt.Sprintf("network-%d", index), 552 IFName: ep.Name(), 553 MACAddress: ep.HardwareAddr(), 554 DownScript: "no", 555 Script: "no", 556 VHost: vhost, 557 DisableModern: nestedRun, 558 FDs: ep.VMFds, 559 VhostFDs: ep.VhostFds, 560 } 561 case *TuntapEndpoint: 562 netPair := ep.NetworkPair() 563 d = govmmQemu.NetDevice{ 564 Type: govmmQemu.NetDeviceType("tap"), 565 Driver: govmmQemu.VirtioNet, 566 ID: fmt.Sprintf("network-%d", index), 567 IFName: netPair.TAPIface.Name, 568 MACAddress: netPair.TAPIface.HardAddr, 569 DownScript: "no", 570 Script: "no", 571 VHost: vhost, 572 DisableModern: nestedRun, 573 FDs: netPair.VMFds, 574 VhostFDs: netPair.VhostFds, 575 } 576 default: 577 return govmmQemu.NetDevice{}, fmt.Errorf("Unknown type for endpoint") 578 } 579 580 return d, nil 581 } 582 583 func (q *qemuArchBase) appendNetwork(devices []govmmQemu.Device, endpoint Endpoint) ([]govmmQemu.Device, error) { 584 d, err := genericNetwork(endpoint, q.vhost, q.nestedRun, q.networkIndex) 585 if err != nil { 586 return devices, fmt.Errorf("Failed to append network %v", err) 587 } 588 q.networkIndex++ 589 devices = append(devices, d) 590 return devices, nil 591 } 592 593 func genericBlockDevice(drive config.BlockDrive, nestedRun bool) (govmmQemu.BlockDevice, error) { 594 if drive.File == "" || drive.ID == "" || drive.Format == "" { 595 return govmmQemu.BlockDevice{}, fmt.Errorf("Empty File, ID or Format for drive %v", drive) 596 } 597 598 if len(drive.ID) > maxDevIDSize { 599 drive.ID = drive.ID[:maxDevIDSize] 600 } 601 602 return govmmQemu.BlockDevice{ 603 Driver: govmmQemu.VirtioBlock, 604 ID: drive.ID, 605 File: drive.File, 606 AIO: govmmQemu.Threads, 607 Format: govmmQemu.BlockDeviceFormat(drive.Format), 608 Interface: "none", 609 DisableModern: nestedRun, 610 ShareRW: drive.ShareRW, 611 ReadOnly: drive.ReadOnly, 612 }, nil 613 } 614 615 func (q *qemuArchBase) appendBlockDevice(devices []govmmQemu.Device, drive config.BlockDrive) ([]govmmQemu.Device, error) { 616 d, err := genericBlockDevice(drive, q.nestedRun) 617 if err != nil { 618 return devices, fmt.Errorf("Failed to append block device %v", err) 619 } 620 devices = append(devices, d) 621 return devices, nil 622 } 623 624 func (q *qemuArchBase) appendVhostUserDevice(devices []govmmQemu.Device, attr config.VhostUserDeviceAttrs) ([]govmmQemu.Device, error) { 625 qemuVhostUserDevice := govmmQemu.VhostUserDevice{} 626 627 switch attr.Type { 628 case config.VhostUserNet: 629 qemuVhostUserDevice.TypeDevID = utils.MakeNameID("net", attr.DevID, maxDevIDSize) 630 qemuVhostUserDevice.Address = attr.MacAddress 631 qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserNet 632 case config.VhostUserSCSI: 633 qemuVhostUserDevice.TypeDevID = utils.MakeNameID("scsi", attr.DevID, maxDevIDSize) 634 qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserSCSI 635 case config.VhostUserBlk: 636 qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserBlk 637 case config.VhostUserFS: 638 qemuVhostUserDevice.TypeDevID = utils.MakeNameID("fs", attr.DevID, maxDevIDSize) 639 qemuVhostUserDevice.Tag = attr.Tag 640 qemuVhostUserDevice.CacheSize = attr.CacheSize 641 qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserFS 642 } 643 644 qemuVhostUserDevice.SocketPath = attr.SocketPath 645 qemuVhostUserDevice.CharDevID = utils.MakeNameID("char", attr.DevID, maxDevIDSize) 646 647 devices = append(devices, qemuVhostUserDevice) 648 649 return devices, nil 650 } 651 652 func (q *qemuArchBase) appendVFIODevice(devices []govmmQemu.Device, vfioDev config.VFIODev) []govmmQemu.Device { 653 if vfioDev.BDF == "" { 654 return devices 655 } 656 657 devices = append(devices, 658 govmmQemu.VFIODevice{ 659 BDF: vfioDev.BDF, 660 VendorID: vfioDev.VendorID, 661 DeviceID: vfioDev.DeviceID, 662 Bus: vfioDev.Bus, 663 }, 664 ) 665 666 return devices 667 } 668 669 func (q *qemuArchBase) appendRNGDevice(devices []govmmQemu.Device, rngDev config.RNGDev) ([]govmmQemu.Device, error) { 670 devices = append(devices, 671 govmmQemu.RngDevice{ 672 ID: rngDev.ID, 673 Filename: rngDev.Filename, 674 }, 675 ) 676 677 return devices, nil 678 } 679 680 func (q *qemuArchBase) handleImagePath(config HypervisorConfig) { 681 if config.ImagePath != "" { 682 kernelRootParams := commonVirtioblkKernelRootParams 683 if !q.disableNvdimm { 684 for i := range q.supportedQemuMachines { 685 q.supportedQemuMachines[i].Options = strings.Join([]string{ 686 q.supportedQemuMachines[i].Options, 687 qemuNvdimmOption, 688 }, ",") 689 } 690 if q.dax { 691 kernelRootParams = commonNvdimmKernelRootParams 692 } else { 693 kernelRootParams = commonNvdimmNoDAXKernelRootParams 694 } 695 } 696 q.kernelParams = append(q.kernelParams, kernelRootParams...) 697 q.kernelParamsNonDebug = append(q.kernelParamsNonDebug, kernelParamsSystemdNonDebug...) 698 q.kernelParamsDebug = append(q.kernelParamsDebug, kernelParamsSystemdDebug...) 699 } 700 } 701 702 func (q *qemuArchBase) supportGuestMemoryHotplug() bool { 703 return true 704 } 705 706 func (q *qemuArchBase) setIgnoreSharedMemoryMigrationCaps(ctx context.Context, qmp *govmmQemu.QMP) error { 707 err := qmp.ExecSetMigrationCaps(ctx, []map[string]interface{}{ 708 { 709 "capability": qmpCapMigrationIgnoreShared, 710 "state": true, 711 }, 712 }) 713 return err 714 } 715 716 func (q *qemuArchBase) addDeviceToBridge(ID string, t types.Type) (string, types.Bridge, error) { 717 var err error 718 var addr uint32 719 720 if len(q.Bridges) == 0 { 721 return "", types.Bridge{}, errors.New("failed to get available address from bridges") 722 } 723 724 // looking for an empty address in the bridges 725 for _, b := range q.Bridges { 726 if t != b.Type { 727 continue 728 } 729 addr, err = b.AddDevice(ID) 730 if err == nil { 731 switch t { 732 case types.CCW: 733 return fmt.Sprintf("%04x", addr), b, nil 734 case types.PCI, types.PCIE: 735 return fmt.Sprintf("%02x", addr), b, nil 736 } 737 } 738 } 739 740 return "", types.Bridge{}, fmt.Errorf("no more bridge slots available") 741 } 742 743 func (q *qemuArchBase) removeDeviceFromBridge(ID string) error { 744 var err error 745 for _, b := range q.Bridges { 746 err = b.RemoveDevice(ID) 747 if err == nil { 748 // device was removed correctly 749 return nil 750 } 751 } 752 753 return err 754 } 755 756 func (q *qemuArchBase) getBridges() []types.Bridge { 757 return q.Bridges 758 } 759 760 func (q *qemuArchBase) setBridges(bridges []types.Bridge) { 761 q.Bridges = bridges 762 } 763 764 func (q *qemuArchBase) addBridge(b types.Bridge) { 765 q.Bridges = append(q.Bridges, b) 766 } 767 768 // appendPCIeRootPortDevice appends to devices the given pcie-root-port 769 func (q *qemuArchBase) appendPCIeRootPortDevice(devices []govmmQemu.Device, number uint32) []govmmQemu.Device { 770 return genericAppendPCIeRootPort(devices, number, q.machineType) 771 }