github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/qemu_amd64_test.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  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  	"testing"
    13  
    14  	govmmQemu "github.com/kata-containers/govmm/qemu"
    15  	"github.com/kata-containers/runtime/virtcontainers/types"
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  func qemuConfig(machineType string) HypervisorConfig {
    20  	return HypervisorConfig{
    21  		HypervisorMachineType: machineType,
    22  	}
    23  }
    24  
    25  func newTestQemu(machineType string) qemuArch {
    26  	config := qemuConfig(machineType)
    27  	return newQemuArch(config)
    28  }
    29  
    30  func TestQemuAmd64Capabilities(t *testing.T) {
    31  	assert := assert.New(t)
    32  
    33  	amd64 := newTestQemu(QemuPC)
    34  	caps := amd64.capabilities()
    35  	assert.True(caps.IsBlockDeviceHotplugSupported())
    36  
    37  	amd64 = newTestQemu(QemuQ35)
    38  	caps = amd64.capabilities()
    39  	assert.True(caps.IsBlockDeviceHotplugSupported())
    40  
    41  	amd64 = newTestQemu(QemuMicrovm)
    42  	caps = amd64.capabilities()
    43  	assert.False(caps.IsBlockDeviceHotplugSupported())
    44  }
    45  
    46  func TestQemuAmd64Bridges(t *testing.T) {
    47  	assert := assert.New(t)
    48  	amd64 := newTestQemu(QemuPC)
    49  	len := 5
    50  
    51  	amd64.bridges(uint32(len))
    52  	bridges := amd64.getBridges()
    53  	assert.Len(bridges, len)
    54  
    55  	for i, b := range bridges {
    56  		id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
    57  		assert.Equal(types.PCI, b.Type)
    58  		assert.Equal(id, b.ID)
    59  		assert.NotNil(b.Devices)
    60  	}
    61  
    62  	amd64 = newTestQemu(QemuQ35)
    63  	amd64.bridges(uint32(len))
    64  	bridges = amd64.getBridges()
    65  	assert.Len(bridges, len)
    66  
    67  	for i, b := range bridges {
    68  		id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
    69  		assert.Equal(types.PCI, b.Type)
    70  		assert.Equal(id, b.ID)
    71  		assert.NotNil(b.Devices)
    72  	}
    73  
    74  	amd64 = newTestQemu(QemuMicrovm)
    75  	amd64.bridges(uint32(len))
    76  	bridges = amd64.getBridges()
    77  	assert.Nil(bridges)
    78  
    79  	amd64 = newTestQemu(QemuQ35 + QemuPC)
    80  	amd64.bridges(uint32(len))
    81  	bridges = amd64.getBridges()
    82  	assert.Nil(bridges)
    83  }
    84  
    85  func TestQemuAmd64CPUModel(t *testing.T) {
    86  	assert := assert.New(t)
    87  	amd64 := newTestQemu(QemuPC)
    88  
    89  	expectedOut := defaultCPUModel
    90  	model := amd64.cpuModel()
    91  	assert.Equal(expectedOut, model)
    92  
    93  	amd64.disableNestingChecks()
    94  	base, ok := amd64.(*qemuAmd64)
    95  	assert.True(ok)
    96  	base.vmFactory = true
    97  	expectedOut = defaultCPUModel + ",vmx=off"
    98  	model = amd64.cpuModel()
    99  	assert.Equal(expectedOut, model)
   100  }
   101  
   102  func TestQemuAmd64MemoryTopology(t *testing.T) {
   103  	assert := assert.New(t)
   104  	amd64 := newTestQemu(QemuPC)
   105  	memoryOffset := 1024
   106  
   107  	hostMem := uint64(100)
   108  	mem := uint64(120)
   109  	slots := uint8(10)
   110  	expectedMemory := govmmQemu.Memory{
   111  		Size:   fmt.Sprintf("%dM", mem),
   112  		Slots:  slots,
   113  		MaxMem: fmt.Sprintf("%dM", hostMem+uint64(memoryOffset)),
   114  	}
   115  
   116  	m := amd64.memoryTopology(mem, hostMem, slots)
   117  	assert.Equal(expectedMemory, m)
   118  }
   119  
   120  func TestQemuAmd64AppendImage(t *testing.T) {
   121  	assert := assert.New(t)
   122  
   123  	f, err := ioutil.TempFile("", "img")
   124  	assert.NoError(err)
   125  	defer func() { _ = f.Close() }()
   126  	defer func() { _ = os.Remove(f.Name()) }()
   127  
   128  	imageStat, err := f.Stat()
   129  	assert.NoError(err)
   130  
   131  	// save default supportedQemuMachines options
   132  	machinesCopy := make([]govmmQemu.Machine, len(supportedQemuMachines))
   133  	assert.Equal(len(supportedQemuMachines), copy(machinesCopy, supportedQemuMachines))
   134  
   135  	cfg := qemuConfig(QemuPC)
   136  	cfg.ImagePath = f.Name()
   137  	cfg.DisableImageNvdimm = false
   138  	amd64 := newQemuArch(cfg)
   139  	for _, m := range amd64.(*qemuAmd64).supportedQemuMachines {
   140  		assert.Contains(m.Options, qemuNvdimmOption)
   141  	}
   142  
   143  	expectedOut := []govmmQemu.Device{
   144  		govmmQemu.Object{
   145  			Driver:   govmmQemu.NVDIMM,
   146  			Type:     govmmQemu.MemoryBackendFile,
   147  			DeviceID: "nv0",
   148  			ID:       "mem0",
   149  			MemPath:  f.Name(),
   150  			Size:     (uint64)(imageStat.Size()),
   151  		},
   152  	}
   153  
   154  	devices, err := amd64.appendImage(nil, f.Name())
   155  	assert.NoError(err)
   156  	assert.Equal(expectedOut, devices)
   157  
   158  	// restore default supportedQemuMachines options
   159  	assert.Equal(len(supportedQemuMachines), copy(supportedQemuMachines, machinesCopy))
   160  
   161  	cfg.DisableImageNvdimm = true
   162  	amd64 = newQemuArch(cfg)
   163  	for _, m := range amd64.(*qemuAmd64).supportedQemuMachines {
   164  		assert.NotContains(m.Options, qemuNvdimmOption)
   165  	}
   166  
   167  	found := false
   168  	devices, err = amd64.appendImage(nil, f.Name())
   169  	assert.NoError(err)
   170  	for _, d := range devices {
   171  		if b, ok := d.(govmmQemu.BlockDevice); ok {
   172  			assert.Equal(b.Driver, govmmQemu.VirtioBlock)
   173  			assert.True(b.ShareRW)
   174  			found = true
   175  		}
   176  	}
   177  	assert.True(found)
   178  
   179  	// restore default supportedQemuMachines options
   180  	assert.Equal(len(supportedQemuMachines), copy(supportedQemuMachines, machinesCopy))
   181  }
   182  
   183  func TestQemuAmd64AppendBridges(t *testing.T) {
   184  	var devices []govmmQemu.Device
   185  	assert := assert.New(t)
   186  
   187  	// check PC
   188  	amd64 := newTestQemu(QemuPC)
   189  
   190  	amd64.bridges(1)
   191  	bridges := amd64.getBridges()
   192  	assert.Len(bridges, 1)
   193  
   194  	devices = amd64.appendBridges(devices)
   195  	assert.Len(devices, 1)
   196  
   197  	expectedOut := []govmmQemu.Device{
   198  		govmmQemu.BridgeDevice{
   199  			Type:    govmmQemu.PCIBridge,
   200  			Bus:     defaultPCBridgeBus,
   201  			ID:      bridges[0].ID,
   202  			Chassis: 1,
   203  			SHPC:    true,
   204  			Addr:    "2",
   205  		},
   206  	}
   207  
   208  	assert.Equal(expectedOut, devices)
   209  
   210  	// Check Q35
   211  	amd64 = newTestQemu(QemuQ35)
   212  
   213  	amd64.bridges(1)
   214  	bridges = amd64.getBridges()
   215  	assert.Len(bridges, 1)
   216  
   217  	devices = []govmmQemu.Device{}
   218  	devices = amd64.appendBridges(devices)
   219  	assert.Len(devices, 1)
   220  
   221  	expectedOut = []govmmQemu.Device{
   222  		govmmQemu.BridgeDevice{
   223  			Type:    govmmQemu.PCIBridge,
   224  			Bus:     defaultBridgeBus,
   225  			ID:      bridges[0].ID,
   226  			Chassis: 1,
   227  			SHPC:    true,
   228  			Addr:    "2",
   229  		},
   230  	}
   231  
   232  	assert.Equal(expectedOut, devices)
   233  }
   234  
   235  func TestQemuAmd64WithInitrd(t *testing.T) {
   236  	assert := assert.New(t)
   237  
   238  	cfg := qemuConfig(QemuPC)
   239  	cfg.InitrdPath = "dummy-initrd"
   240  	amd64 := newQemuArch(cfg)
   241  
   242  	for _, m := range amd64.(*qemuAmd64).supportedQemuMachines {
   243  		assert.NotContains(m.Options, qemuNvdimmOption)
   244  	}
   245  }
   246  
   247  func TestQemuAmd64Microvm(t *testing.T) {
   248  	assert := assert.New(t)
   249  
   250  	cfg := qemuConfig(QemuMicrovm)
   251  	amd64 := newQemuArch(cfg)
   252  	assert.False(cfg.DisableImageNvdimm)
   253  
   254  	for _, m := range amd64.(*qemuAmd64).supportedQemuMachines {
   255  		assert.NotContains(m.Options, qemuNvdimmOption)
   256  	}
   257  
   258  	assert.False(amd64.supportGuestMemoryHotplug())
   259  }
   260  
   261  func TestQemuAmd64Iommu(t *testing.T) {
   262  	assert := assert.New(t)
   263  
   264  	config := qemuConfig(QemuQ35)
   265  	config.IOMMU = true
   266  	qemu := newQemuArch(config)
   267  
   268  	p := qemu.kernelParameters(false)
   269  	assert.Contains(p, Param{"intel_iommu", "on"})
   270  
   271  	m, err := qemu.machine()
   272  
   273  	assert.NoError(err)
   274  	assert.Contains(m.Options, "kernel_irqchip=split")
   275  }