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  }