gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/hypervisor.go (about)

     1  // Copyright (c) 2016 Intel Corporation
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  
     6  package virtcontainers
     7  
     8  import (
     9  	"bufio"
    10  	"context"
    11  	"fmt"
    12  	"os"
    13  	"path/filepath"
    14  	"runtime"
    15  	"strconv"
    16  	"strings"
    17  
    18  	"github.com/kata-containers/runtime/virtcontainers/device/config"
    19  	"github.com/kata-containers/runtime/virtcontainers/persist"
    20  	persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
    21  	"github.com/kata-containers/runtime/virtcontainers/types"
    22  	"github.com/kata-containers/runtime/virtcontainers/utils"
    23  )
    24  
    25  // HypervisorType describes an hypervisor type.
    26  type HypervisorType string
    27  
    28  type operation int
    29  
    30  const (
    31  	addDevice operation = iota
    32  	removeDevice
    33  )
    34  
    35  const (
    36  	// FirecrackerHypervisor is the FC hypervisor.
    37  	FirecrackerHypervisor HypervisorType = "firecracker"
    38  
    39  	// QemuHypervisor is the QEMU hypervisor.
    40  	QemuHypervisor HypervisorType = "qemu"
    41  
    42  	// AcrnHypervisor is the ACRN hypervisor.
    43  	AcrnHypervisor HypervisorType = "acrn"
    44  
    45  	// ClhHypervisor is the ICH hypervisor.
    46  	ClhHypervisor HypervisorType = "clh"
    47  
    48  	// MockHypervisor is a mock hypervisor for testing purposes
    49  	MockHypervisor HypervisorType = "mock"
    50  )
    51  
    52  const (
    53  	procMemInfo = "/proc/meminfo"
    54  	procCPUInfo = "/proc/cpuinfo"
    55  )
    56  
    57  const (
    58  	defaultVCPUs = 1
    59  	// 2 GiB
    60  	defaultMemSzMiB = 2048
    61  
    62  	defaultBridges = 1
    63  
    64  	defaultBlockDriver = config.VirtioSCSI
    65  
    66  	defaultSocketName        = "kata.sock"
    67  	defaultSocketDeviceID    = "channel0"
    68  	defaultSocketChannelName = "agent.channel.0"
    69  	defaultSocketID          = "charch0"
    70  
    71  	// port numbers below 1024 are called privileged ports. Only a process with
    72  	// CAP_NET_BIND_SERVICE capability may bind to these port numbers.
    73  	vSockPort = 1024
    74  
    75  	// Port where the agent will send the logs. Logs are sent through the vsock in cases
    76  	// where the hypervisor has no console.sock, i.e firecracker
    77  	vSockLogsPort = 1025
    78  
    79  	// MinHypervisorMemory is the minimum memory required for a VM.
    80  	MinHypervisorMemory = 256
    81  )
    82  
    83  // In some architectures the maximum number of vCPUs depends on the number of physical cores.
    84  var defaultMaxQemuVCPUs = MaxQemuVCPUs()
    85  
    86  // agnostic list of kernel root parameters for NVDIMM
    87  var commonNvdimmKernelRootParams = []Param{ //nolint: unused, deadcode, varcheck
    88  	{"root", "/dev/pmem0p1"},
    89  	{"rootflags", "dax,data=ordered,errors=remount-ro ro"},
    90  	{"rootfstype", "ext4"},
    91  }
    92  
    93  // agnostic list of kernel root parameters for NVDIMM
    94  var commonNvdimmNoDAXKernelRootParams = []Param{ //nolint: unused, deadcode, varcheck
    95  	{"root", "/dev/pmem0p1"},
    96  	{"rootflags", "data=ordered,errors=remount-ro ro"},
    97  	{"rootfstype", "ext4"},
    98  }
    99  
   100  // agnostic list of kernel root parameters for virtio-blk
   101  var commonVirtioblkKernelRootParams = []Param{ //nolint: unused, deadcode, varcheck
   102  	{"root", "/dev/vda1"},
   103  	{"rootflags", "data=ordered,errors=remount-ro ro"},
   104  	{"rootfstype", "ext4"},
   105  }
   106  
   107  // deviceType describes a virtualized device type.
   108  type deviceType int
   109  
   110  const (
   111  	// ImgDev is the image device type.
   112  	imgDev deviceType = iota
   113  
   114  	// FsDev is the filesystem device type.
   115  	fsDev
   116  
   117  	// NetDev is the network device type.
   118  	netDev
   119  
   120  	// BlockDev is the block device type.
   121  	blockDev
   122  
   123  	// SerialPortDev is the serial port device type.
   124  	serialPortDev
   125  
   126  	// vSockPCIDev is the vhost vsock PCI device type.
   127  	vSockPCIDev
   128  
   129  	// VFIODevice is VFIO device type
   130  	vfioDev
   131  
   132  	// vhostuserDev is a Vhost-user device type
   133  	vhostuserDev
   134  
   135  	// CPUDevice is CPU device type
   136  	cpuDev
   137  
   138  	// memoryDevice is memory device type
   139  	memoryDev
   140  
   141  	// hybridVirtioVsockDev is a hybrid virtio-vsock device supported
   142  	// only on certain hypervisors, like firecracker.
   143  	hybridVirtioVsockDev
   144  )
   145  
   146  type memoryDevice struct {
   147  	slot   int
   148  	sizeMB int
   149  	addr   uint64
   150  	probe  bool
   151  }
   152  
   153  // Set sets an hypervisor type based on the input string.
   154  func (hType *HypervisorType) Set(value string) error {
   155  	switch value {
   156  	case "qemu":
   157  		*hType = QemuHypervisor
   158  		return nil
   159  	case "firecracker":
   160  		*hType = FirecrackerHypervisor
   161  		return nil
   162  	case "acrn":
   163  		*hType = AcrnHypervisor
   164  		return nil
   165  	case "clh":
   166  		*hType = ClhHypervisor
   167  		return nil
   168  	case "mock":
   169  		*hType = MockHypervisor
   170  		return nil
   171  	default:
   172  		return fmt.Errorf("Unknown hypervisor type %s", value)
   173  	}
   174  }
   175  
   176  // String converts an hypervisor type to a string.
   177  func (hType *HypervisorType) String() string {
   178  	switch *hType {
   179  	case QemuHypervisor:
   180  		return string(QemuHypervisor)
   181  	case FirecrackerHypervisor:
   182  		return string(FirecrackerHypervisor)
   183  	case AcrnHypervisor:
   184  		return string(AcrnHypervisor)
   185  	case ClhHypervisor:
   186  		return string(ClhHypervisor)
   187  	case MockHypervisor:
   188  		return string(MockHypervisor)
   189  	default:
   190  		return ""
   191  	}
   192  }
   193  
   194  // newHypervisor returns an hypervisor from and hypervisor type.
   195  func newHypervisor(hType HypervisorType) (hypervisor, error) {
   196  	store, err := persist.GetDriver()
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  
   201  	switch hType {
   202  	case QemuHypervisor:
   203  		return &qemu{
   204  			store: store,
   205  		}, nil
   206  	case FirecrackerHypervisor:
   207  		return &firecracker{}, nil
   208  	case AcrnHypervisor:
   209  		return &Acrn{
   210  			store: store,
   211  		}, nil
   212  	case ClhHypervisor:
   213  		return &cloudHypervisor{
   214  			store: store,
   215  		}, nil
   216  	case MockHypervisor:
   217  		return &mockHypervisor{}, nil
   218  	default:
   219  		return nil, fmt.Errorf("Unknown hypervisor type %s", hType)
   220  	}
   221  }
   222  
   223  // Param is a key/value representation for hypervisor and kernel parameters.
   224  type Param struct {
   225  	Key   string
   226  	Value string
   227  }
   228  
   229  // HypervisorConfig is the hypervisor configuration.
   230  type HypervisorConfig struct {
   231  	// NumVCPUs specifies default number of vCPUs for the VM.
   232  	NumVCPUs uint32
   233  
   234  	//DefaultMaxVCPUs specifies the maximum number of vCPUs for the VM.
   235  	DefaultMaxVCPUs uint32
   236  
   237  	// DefaultMem specifies default memory size in MiB for the VM.
   238  	MemorySize uint32
   239  
   240  	// DefaultBridges specifies default number of bridges for the VM.
   241  	// Bridges can be used to hot plug devices
   242  	DefaultBridges uint32
   243  
   244  	// Msize9p is used as the msize for 9p shares
   245  	Msize9p uint32
   246  
   247  	// MemSlots specifies default memory slots the VM.
   248  	MemSlots uint32
   249  
   250  	// MemOffset specifies memory space for nvdimm device
   251  	MemOffset uint32
   252  
   253  	// VirtioFSCacheSize is the DAX cache size in MiB
   254  	VirtioFSCacheSize uint32
   255  
   256  	// KernelParams are additional guest kernel parameters.
   257  	KernelParams []Param
   258  
   259  	// HypervisorParams are additional hypervisor parameters.
   260  	HypervisorParams []Param
   261  
   262  	// KernelPath is the guest kernel host path.
   263  	KernelPath string
   264  
   265  	// ImagePath is the guest image host path.
   266  	ImagePath string
   267  
   268  	// InitrdPath is the guest initrd image host path.
   269  	// ImagePath and InitrdPath cannot be set at the same time.
   270  	InitrdPath string
   271  
   272  	// FirmwarePath is the bios host path
   273  	FirmwarePath string
   274  
   275  	// MachineAccelerators are machine specific accelerators
   276  	MachineAccelerators string
   277  
   278  	// CPUFeatures are cpu specific features
   279  	CPUFeatures string
   280  
   281  	// HypervisorPath is the hypervisor executable host path.
   282  	HypervisorPath string
   283  
   284  	// HypervisorCtlPath is the hypervisor ctl executable host path.
   285  	HypervisorCtlPath string
   286  
   287  	// JailerPath is the jailer executable host path.
   288  	JailerPath string
   289  
   290  	// BlockDeviceDriver specifies the driver to be used for block device
   291  	// either VirtioSCSI or VirtioBlock with the default driver being defaultBlockDriver
   292  	BlockDeviceDriver string
   293  
   294  	// HypervisorMachineType specifies the type of machine being
   295  	// emulated.
   296  	HypervisorMachineType string
   297  
   298  	// MemoryPath is the memory file path of VM memory. Used when either BootToBeTemplate or
   299  	// BootFromTemplate is true.
   300  	MemoryPath string
   301  
   302  	// DevicesStatePath is the VM device state file path. Used when either BootToBeTemplate or
   303  	// BootFromTemplate is true.
   304  	DevicesStatePath string
   305  
   306  	// EntropySource is the path to a host source of
   307  	// entropy (/dev/random, /dev/urandom or real hardware RNG device)
   308  	EntropySource string
   309  
   310  	// Shared file system type:
   311  	//   - virtio-9p (default)
   312  	//   - virtio-fs
   313  	SharedFS string
   314  
   315  	// VirtioFSDaemon is the virtio-fs vhost-user daemon path
   316  	VirtioFSDaemon string
   317  
   318  	// VirtioFSCache cache mode for fs version cache or "none"
   319  	VirtioFSCache string
   320  
   321  	// VirtioFSExtraArgs passes options to virtiofsd daemon
   322  	VirtioFSExtraArgs []string
   323  
   324  	// File based memory backend root directory
   325  	FileBackedMemRootDir string
   326  
   327  	// customAssets is a map of assets.
   328  	// Each value in that map takes precedence over the configured assets.
   329  	// For example, if there is a value for the "kernel" key in this map,
   330  	// it will be used for the sandbox's kernel path instead of KernelPath.
   331  	customAssets map[types.AssetType]*types.Asset
   332  
   333  	// BlockDeviceCacheSet specifies cache-related options will be set to block devices or not.
   334  	BlockDeviceCacheSet bool
   335  
   336  	// BlockDeviceCacheDirect specifies cache-related options for block devices.
   337  	// Denotes whether use of O_DIRECT (bypass the host page cache) is enabled.
   338  	BlockDeviceCacheDirect bool
   339  
   340  	// BlockDeviceCacheNoflush specifies cache-related options for block devices.
   341  	// Denotes whether flush requests for the device are ignored.
   342  	BlockDeviceCacheNoflush bool
   343  
   344  	// DisableBlockDeviceUse disallows a block device from being used.
   345  	DisableBlockDeviceUse bool
   346  
   347  	// EnableIOThreads enables IO to be processed in a separate thread.
   348  	// Supported currently for virtio-scsi driver.
   349  	EnableIOThreads bool
   350  
   351  	// Debug changes the default hypervisor and kernel parameters to
   352  	// enable debug output where available.
   353  	Debug bool
   354  
   355  	// MemPrealloc specifies if the memory should be pre-allocated
   356  	MemPrealloc bool
   357  
   358  	// HugePages specifies if the memory should be pre-allocated from huge pages
   359  	HugePages bool
   360  
   361  	// VirtioMem is used to enable/disable virtio-mem
   362  	VirtioMem bool
   363  
   364  	// Realtime Used to enable/disable realtime
   365  	Realtime bool
   366  
   367  	// Mlock is used to control memory locking when Realtime is enabled
   368  	// Realtime=true and Mlock=false, allows for swapping out of VM memory
   369  	// enabling higher density
   370  	Mlock bool
   371  
   372  	// DisableNestingChecks is used to override customizations performed
   373  	// when running on top of another VMM.
   374  	DisableNestingChecks bool
   375  
   376  	// UseVSock use a vsock for agent communication
   377  	UseVSock bool
   378  
   379  	// DisableImageNvdimm is used to disable guest rootfs image nvdimm devices
   380  	DisableImageNvdimm bool
   381  
   382  	// HotplugVFIOOnRootBus is used to indicate if devices need to be hotplugged on the
   383  	// root bus instead of a bridge.
   384  	HotplugVFIOOnRootBus bool
   385  
   386  	// PCIeRootPort is used to indicate the number of PCIe Root Port devices
   387  	// The PCIe Root Port device is used to hot-plug the PCIe device
   388  	PCIeRootPort uint32
   389  
   390  	// BootToBeTemplate used to indicate if the VM is created to be a template VM
   391  	BootToBeTemplate bool
   392  
   393  	// BootFromTemplate used to indicate if the VM should be created from a template VM
   394  	BootFromTemplate bool
   395  
   396  	// DisableVhostNet is used to indicate if host supports vhost_net
   397  	DisableVhostNet bool
   398  
   399  	// EnableVhostUserStore is used to indicate if host supports vhost-user-blk/scsi
   400  	EnableVhostUserStore bool
   401  
   402  	// VhostUserStorePath is the directory path where vhost-user devices
   403  	// related folders, sockets and device nodes should be.
   404  	VhostUserStorePath string
   405  
   406  	// GuestHookPath is the path within the VM that will be used for 'drop-in' hooks
   407  	GuestHookPath string
   408  
   409  	// VMid is the id of the VM that create the hypervisor if the VM is created by the factory.
   410  	// VMid is "" if the hypervisor is not created by the factory.
   411  	VMid string
   412  
   413  	// SELinux label for the VM
   414  	SELinuxProcessLabel string
   415  }
   416  
   417  // vcpu mapping from vcpu number to thread number
   418  type vcpuThreadIDs struct {
   419  	vcpus map[int]int
   420  }
   421  
   422  func (conf *HypervisorConfig) checkTemplateConfig() error {
   423  	if conf.BootToBeTemplate && conf.BootFromTemplate {
   424  		return fmt.Errorf("Cannot set both 'to be' and 'from' vm tempate")
   425  	}
   426  
   427  	if conf.BootToBeTemplate || conf.BootFromTemplate {
   428  		if conf.MemoryPath == "" {
   429  			return fmt.Errorf("Missing MemoryPath for vm template")
   430  		}
   431  
   432  		if conf.BootFromTemplate && conf.DevicesStatePath == "" {
   433  			return fmt.Errorf("Missing DevicesStatePath to load from vm template")
   434  		}
   435  	}
   436  
   437  	return nil
   438  }
   439  
   440  func (conf *HypervisorConfig) valid() error {
   441  	if conf.KernelPath == "" {
   442  		return fmt.Errorf("Missing kernel path")
   443  	}
   444  
   445  	if conf.ImagePath == "" && conf.InitrdPath == "" {
   446  		return fmt.Errorf("Missing image and initrd path")
   447  	}
   448  
   449  	if err := conf.checkTemplateConfig(); err != nil {
   450  		return err
   451  	}
   452  
   453  	if conf.NumVCPUs == 0 {
   454  		conf.NumVCPUs = defaultVCPUs
   455  	}
   456  
   457  	if conf.MemorySize == 0 {
   458  		conf.MemorySize = defaultMemSzMiB
   459  	}
   460  
   461  	if conf.DefaultBridges == 0 {
   462  		conf.DefaultBridges = defaultBridges
   463  	}
   464  
   465  	if conf.BlockDeviceDriver == "" {
   466  		conf.BlockDeviceDriver = defaultBlockDriver
   467  	}
   468  
   469  	if conf.DefaultMaxVCPUs == 0 {
   470  		conf.DefaultMaxVCPUs = defaultMaxQemuVCPUs
   471  	}
   472  
   473  	if conf.Msize9p == 0 && conf.SharedFS != config.VirtioFS {
   474  		conf.Msize9p = defaultMsize9p
   475  	}
   476  
   477  	return nil
   478  }
   479  
   480  // AddKernelParam allows the addition of new kernel parameters to an existing
   481  // hypervisor configuration.
   482  func (conf *HypervisorConfig) AddKernelParam(p Param) error {
   483  	if p.Key == "" {
   484  		return fmt.Errorf("Empty kernel parameter")
   485  	}
   486  
   487  	conf.KernelParams = append(conf.KernelParams, p)
   488  
   489  	return nil
   490  }
   491  
   492  func (conf *HypervisorConfig) addCustomAsset(a *types.Asset) error {
   493  	if a == nil || a.Path() == "" {
   494  		// We did not get a custom asset, we will use the default one.
   495  		return nil
   496  	}
   497  
   498  	if !a.Valid() {
   499  		return fmt.Errorf("Invalid %s at %s", a.Type(), a.Path())
   500  	}
   501  
   502  	virtLog.Debugf("Using custom %v asset %s", a.Type(), a.Path())
   503  
   504  	if conf.customAssets == nil {
   505  		conf.customAssets = make(map[types.AssetType]*types.Asset)
   506  	}
   507  
   508  	conf.customAssets[a.Type()] = a
   509  
   510  	return nil
   511  }
   512  
   513  func (conf *HypervisorConfig) assetPath(t types.AssetType) (string, error) {
   514  	// Custom assets take precedence over the configured ones
   515  	a, ok := conf.customAssets[t]
   516  	if ok {
   517  		return a.Path(), nil
   518  	}
   519  
   520  	// We could not find a custom asset for the given type, let's
   521  	// fall back to the configured ones.
   522  	switch t {
   523  	case types.KernelAsset:
   524  		return conf.KernelPath, nil
   525  	case types.ImageAsset:
   526  		return conf.ImagePath, nil
   527  	case types.InitrdAsset:
   528  		return conf.InitrdPath, nil
   529  	case types.HypervisorAsset:
   530  		return conf.HypervisorPath, nil
   531  	case types.HypervisorCtlAsset:
   532  		return conf.HypervisorCtlPath, nil
   533  	case types.JailerAsset:
   534  		return conf.JailerPath, nil
   535  	case types.FirmwareAsset:
   536  		return conf.FirmwarePath, nil
   537  	default:
   538  		return "", fmt.Errorf("Unknown asset type %v", t)
   539  	}
   540  }
   541  
   542  func (conf *HypervisorConfig) isCustomAsset(t types.AssetType) bool {
   543  	_, ok := conf.customAssets[t]
   544  	return ok
   545  }
   546  
   547  // KernelAssetPath returns the guest kernel path
   548  func (conf *HypervisorConfig) KernelAssetPath() (string, error) {
   549  	return conf.assetPath(types.KernelAsset)
   550  }
   551  
   552  // CustomKernelAsset returns true if the kernel asset is a custom one, false otherwise.
   553  func (conf *HypervisorConfig) CustomKernelAsset() bool {
   554  	return conf.isCustomAsset(types.KernelAsset)
   555  }
   556  
   557  // ImageAssetPath returns the guest image path
   558  func (conf *HypervisorConfig) ImageAssetPath() (string, error) {
   559  	return conf.assetPath(types.ImageAsset)
   560  }
   561  
   562  // CustomImageAsset returns true if the image asset is a custom one, false otherwise.
   563  func (conf *HypervisorConfig) CustomImageAsset() bool {
   564  	return conf.isCustomAsset(types.ImageAsset)
   565  }
   566  
   567  // InitrdAssetPath returns the guest initrd path
   568  func (conf *HypervisorConfig) InitrdAssetPath() (string, error) {
   569  	return conf.assetPath(types.InitrdAsset)
   570  }
   571  
   572  // CustomInitrdAsset returns true if the initrd asset is a custom one, false otherwise.
   573  func (conf *HypervisorConfig) CustomInitrdAsset() bool {
   574  	return conf.isCustomAsset(types.InitrdAsset)
   575  }
   576  
   577  // HypervisorAssetPath returns the VM hypervisor path
   578  func (conf *HypervisorConfig) HypervisorAssetPath() (string, error) {
   579  	return conf.assetPath(types.HypervisorAsset)
   580  }
   581  
   582  // HypervisorCtlAssetPath returns the VM hypervisor ctl path
   583  func (conf *HypervisorConfig) HypervisorCtlAssetPath() (string, error) {
   584  	return conf.assetPath(types.HypervisorCtlAsset)
   585  }
   586  
   587  // JailerAssetPath returns the VM Jailer path
   588  func (conf *HypervisorConfig) JailerAssetPath() (string, error) {
   589  	return conf.assetPath(types.JailerAsset)
   590  }
   591  
   592  // CustomHypervisorAsset returns true if the hypervisor asset is a custom one, false otherwise.
   593  func (conf *HypervisorConfig) CustomHypervisorAsset() bool {
   594  	return conf.isCustomAsset(types.HypervisorAsset)
   595  }
   596  
   597  // FirmwareAssetPath returns the guest firmware path
   598  func (conf *HypervisorConfig) FirmwareAssetPath() (string, error) {
   599  	return conf.assetPath(types.FirmwareAsset)
   600  }
   601  
   602  // CustomFirmwareAsset returns true if the firmware asset is a custom one, false otherwise.
   603  func (conf *HypervisorConfig) CustomFirmwareAsset() bool {
   604  	return conf.isCustomAsset(types.FirmwareAsset)
   605  }
   606  
   607  func appendParam(params []Param, parameter string, value string) []Param {
   608  	return append(params, Param{parameter, value})
   609  }
   610  
   611  // SerializeParams converts []Param to []string
   612  func SerializeParams(params []Param, delim string) []string {
   613  	var parameters []string
   614  
   615  	for _, p := range params {
   616  		if p.Key == "" && p.Value == "" {
   617  			continue
   618  		} else if p.Key == "" {
   619  			parameters = append(parameters, fmt.Sprint(p.Value))
   620  		} else if p.Value == "" {
   621  			parameters = append(parameters, fmt.Sprint(p.Key))
   622  		} else if delim == "" {
   623  			parameters = append(parameters, fmt.Sprint(p.Key))
   624  			parameters = append(parameters, fmt.Sprint(p.Value))
   625  		} else {
   626  			parameters = append(parameters, fmt.Sprintf("%s%s%s", p.Key, delim, p.Value))
   627  		}
   628  	}
   629  
   630  	return parameters
   631  }
   632  
   633  // DeserializeParams converts []string to []Param
   634  func DeserializeParams(parameters []string) []Param {
   635  	var params []Param
   636  
   637  	for _, param := range parameters {
   638  		if param == "" {
   639  			continue
   640  		}
   641  		p := strings.SplitN(param, "=", 2)
   642  		if len(p) == 2 {
   643  			params = append(params, Param{Key: p[0], Value: p[1]})
   644  		} else {
   645  			params = append(params, Param{Key: p[0], Value: ""})
   646  		}
   647  	}
   648  
   649  	return params
   650  }
   651  
   652  func getHostMemorySizeKb(memInfoPath string) (uint64, error) {
   653  	f, err := os.Open(memInfoPath)
   654  	if err != nil {
   655  		return 0, err
   656  	}
   657  	defer f.Close()
   658  
   659  	scanner := bufio.NewScanner(f)
   660  	for scanner.Scan() {
   661  		// Expected format: ["MemTotal:", "1234", "kB"]
   662  		parts := strings.Fields(scanner.Text())
   663  
   664  		// Sanity checks: Skip malformed entries.
   665  		if len(parts) < 3 || parts[0] != "MemTotal:" || parts[2] != "kB" {
   666  			continue
   667  		}
   668  
   669  		sizeKb, err := strconv.ParseUint(parts[1], 0, 64)
   670  		if err != nil {
   671  			continue
   672  		}
   673  
   674  		return sizeKb, nil
   675  	}
   676  
   677  	// Handle errors that may have occurred during the reading of the file.
   678  	if err := scanner.Err(); err != nil {
   679  		return 0, err
   680  	}
   681  
   682  	return 0, fmt.Errorf("unable get MemTotal from %s", memInfoPath)
   683  }
   684  
   685  // RunningOnVMM checks if the system is running inside a VM.
   686  func RunningOnVMM(cpuInfoPath string) (bool, error) {
   687  	if runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x" {
   688  		virtLog.Info("Unable to know if the system is running inside a VM")
   689  		return false, nil
   690  	}
   691  
   692  	flagsField := "flags"
   693  
   694  	f, err := os.Open(cpuInfoPath)
   695  	if err != nil {
   696  		return false, err
   697  	}
   698  	defer f.Close()
   699  
   700  	scanner := bufio.NewScanner(f)
   701  	for scanner.Scan() {
   702  		// Expected format: ["flags", ":", ...] or ["flags:", ...]
   703  		fields := strings.Fields(scanner.Text())
   704  		if len(fields) < 2 {
   705  			continue
   706  		}
   707  
   708  		if !strings.HasPrefix(fields[0], flagsField) {
   709  			continue
   710  		}
   711  
   712  		for _, field := range fields[1:] {
   713  			if field == "hypervisor" {
   714  				return true, nil
   715  			}
   716  		}
   717  
   718  		// As long as we have been able to analyze the fields from
   719  		// "flags", there is no reason to check what comes next from
   720  		// /proc/cpuinfo, because we already know we are not running
   721  		// on a VMM.
   722  		return false, nil
   723  	}
   724  
   725  	if err := scanner.Err(); err != nil {
   726  		return false, err
   727  	}
   728  
   729  	return false, fmt.Errorf("Couldn't find %q from %q output", flagsField, cpuInfoPath)
   730  }
   731  
   732  func getHypervisorPid(h hypervisor) int {
   733  	pids := h.getPids()
   734  	if len(pids) == 0 {
   735  		return 0
   736  	}
   737  	return pids[0]
   738  }
   739  
   740  func generateVMSocket(id string, useVsock bool, vmStogarePath string) (interface{}, error) {
   741  	if useVsock {
   742  		vhostFd, contextID, err := utils.FindContextID()
   743  		if err != nil {
   744  			return nil, err
   745  		}
   746  
   747  		return types.VSock{
   748  			VhostFd:   vhostFd,
   749  			ContextID: contextID,
   750  			Port:      uint32(vSockPort),
   751  		}, nil
   752  	}
   753  
   754  	path, err := utils.BuildSocketPath(filepath.Join(vmStogarePath, id), defaultSocketName)
   755  	if err != nil {
   756  		return nil, err
   757  	}
   758  
   759  	return types.Socket{
   760  		DeviceID: defaultSocketDeviceID,
   761  		ID:       defaultSocketID,
   762  		HostPath: path,
   763  		Name:     defaultSocketChannelName,
   764  	}, nil
   765  }
   766  
   767  // hypervisor is the virtcontainers hypervisor interface.
   768  // The default hypervisor implementation is Qemu.
   769  type hypervisor interface {
   770  	createSandbox(ctx context.Context, id string, networkNS NetworkNamespace, hypervisorConfig *HypervisorConfig, stateful bool) error
   771  	startSandbox(timeout int) error
   772  	stopSandbox() error
   773  	pauseSandbox() error
   774  	saveSandbox() error
   775  	resumeSandbox() error
   776  	addDevice(devInfo interface{}, devType deviceType) error
   777  	hotplugAddDevice(devInfo interface{}, devType deviceType) (interface{}, error)
   778  	hotplugRemoveDevice(devInfo interface{}, devType deviceType) (interface{}, error)
   779  	resizeMemory(memMB uint32, memoryBlockSizeMB uint32, probe bool) (uint32, memoryDevice, error)
   780  	resizeVCPUs(vcpus uint32) (uint32, uint32, error)
   781  	getSandboxConsole(sandboxID string) (string, error)
   782  	disconnect()
   783  	capabilities() types.Capabilities
   784  	hypervisorConfig() HypervisorConfig
   785  	getThreadIDs() (vcpuThreadIDs, error)
   786  	cleanup() error
   787  	// getPids returns a slice of hypervisor related process ids.
   788  	// The hypervisor pid must be put at index 0.
   789  	getPids() []int
   790  	fromGrpc(ctx context.Context, hypervisorConfig *HypervisorConfig, j []byte) error
   791  	toGrpc() ([]byte, error)
   792  	check() error
   793  
   794  	save() persistapi.HypervisorState
   795  	load(persistapi.HypervisorState)
   796  
   797  	// generate the socket to communicate the host and guest
   798  	generateSocket(id string, useVsock bool) (interface{}, error)
   799  }