gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/qemu_arch_base_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 "net" 12 "os" 13 "path/filepath" 14 "testing" 15 16 govmmQemu "github.com/intel/govmm/qemu" 17 "github.com/stretchr/testify/assert" 18 19 "github.com/kata-containers/runtime/virtcontainers/device/config" 20 "github.com/kata-containers/runtime/virtcontainers/persist/fs" 21 "github.com/kata-containers/runtime/virtcontainers/types" 22 "github.com/pkg/errors" 23 ) 24 25 const ( 26 qemuArchBaseMachineType = "pc" 27 qemuArchBaseQemuPath = "/usr/bin/qemu-system-x86_64" 28 ) 29 30 var qemuArchBaseQemuPaths = map[string]string{ 31 qemuArchBaseMachineType: qemuArchBaseQemuPath, 32 } 33 34 var qemuArchBaseKernelParamsNonDebug = []Param{ 35 {"quiet", ""}, 36 {"systemd.show_status", "false"}, 37 } 38 39 var qemuArchBaseKernelParamsDebug = []Param{ 40 {"debug", ""}, 41 {"systemd.show_status", "true"}, 42 {"systemd.log_level", "debug"}, 43 } 44 45 var qemuArchBaseKernelParams = []Param{ 46 {"root", "/dev/vda"}, 47 {"rootfstype", "ext4"}, 48 } 49 50 var qemuArchBaseSupportedQemuMachines = []govmmQemu.Machine{ 51 { 52 Type: qemuArchBaseMachineType, 53 }, 54 } 55 56 func newQemuArchBase() *qemuArchBase { 57 return &qemuArchBase{ 58 machineType: qemuArchBaseMachineType, 59 nestedRun: false, 60 qemuPaths: qemuArchBaseQemuPaths, 61 supportedQemuMachines: qemuArchBaseSupportedQemuMachines, 62 kernelParamsNonDebug: qemuArchBaseKernelParamsNonDebug, 63 kernelParamsDebug: qemuArchBaseKernelParamsDebug, 64 kernelParams: qemuArchBaseKernelParams, 65 } 66 } 67 68 func TestQemuArchBaseEnableNestingChecks(t *testing.T) { 69 assert := assert.New(t) 70 qemuArchBase := newQemuArchBase() 71 72 qemuArchBase.enableNestingChecks() 73 assert.True(qemuArchBase.nestedRun) 74 } 75 76 func TestQemuArchBaseDisableNestingChecks(t *testing.T) { 77 assert := assert.New(t) 78 qemuArchBase := newQemuArchBase() 79 80 qemuArchBase.disableNestingChecks() 81 assert.False(qemuArchBase.nestedRun) 82 } 83 84 func TestQemuArchBaseMachine(t *testing.T) { 85 assert := assert.New(t) 86 qemuArchBase := newQemuArchBase() 87 88 m, err := qemuArchBase.machine() 89 assert.NoError(err) 90 assert.Equal(m.Type, qemuArchBaseMachineType) 91 92 machines := []govmmQemu.Machine{ 93 { 94 Type: "bad", 95 }, 96 } 97 qemuArchBase.supportedQemuMachines = machines 98 m, err = qemuArchBase.machine() 99 assert.Error(err) 100 assert.Equal("", m.Type) 101 } 102 103 func TestQemuArchBaseQemuPath(t *testing.T) { 104 assert := assert.New(t) 105 qemuArchBase := newQemuArchBase() 106 107 p, err := qemuArchBase.qemuPath() 108 assert.NoError(err) 109 assert.Equal(p, qemuArchBaseQemuPath) 110 111 paths := map[string]string{ 112 "bad": qemuArchBaseQemuPath, 113 } 114 qemuArchBase.qemuPaths = paths 115 p, err = qemuArchBase.qemuPath() 116 assert.Error(err) 117 assert.Equal("", p) 118 } 119 120 func TestQemuArchBaseKernelParameters(t *testing.T) { 121 assert := assert.New(t) 122 qemuArchBase := newQemuArchBase() 123 124 // with debug params 125 expectedParams := qemuArchBaseKernelParams 126 debugParams := qemuArchBaseKernelParamsDebug 127 expectedParams = append(expectedParams, debugParams...) 128 p := qemuArchBase.kernelParameters(true) 129 assert.Equal(expectedParams, p) 130 131 // with non-debug params 132 expectedParams = qemuArchBaseKernelParams 133 nonDebugParams := qemuArchBaseKernelParamsNonDebug 134 expectedParams = append(expectedParams, nonDebugParams...) 135 p = qemuArchBase.kernelParameters(false) 136 assert.Equal(expectedParams, p) 137 } 138 139 func TestQemuArchBaseCapabilities(t *testing.T) { 140 assert := assert.New(t) 141 qemuArchBase := newQemuArchBase() 142 143 c := qemuArchBase.capabilities() 144 assert.True(c.IsBlockDeviceHotplugSupported()) 145 } 146 147 func TestQemuArchBaseBridges(t *testing.T) { 148 assert := assert.New(t) 149 qemuArchBase := newQemuArchBase() 150 len := 5 151 152 qemuArchBase.bridges(uint32(len)) 153 bridges := qemuArchBase.getBridges() 154 assert.Len(bridges, len) 155 156 for i, b := range bridges { 157 id := fmt.Sprintf("%s-bridge-%d", types.PCI, i) 158 assert.Equal(types.PCI, b.Type) 159 assert.Equal(id, b.ID) 160 assert.NotNil(b.Devices) 161 } 162 } 163 164 func TestQemuAddDeviceToBridge(t *testing.T) { 165 assert := assert.New(t) 166 167 // addDeviceToBridge successfully 168 q := newQemuArchBase() 169 q.machineType = QemuPC 170 171 q.bridges(1) 172 for i := uint32(1); i <= types.PCIBridgeMaxCapacity; i++ { 173 _, _, err := q.addDeviceToBridge(fmt.Sprintf("qemu-bridge-%d", i), types.PCI) 174 assert.Nil(err) 175 } 176 177 // fail to add device to bridge cause no more available bridge slot 178 _, _, err := q.addDeviceToBridge("qemu-bridge-31", types.PCI) 179 exceptErr := errors.New("no more bridge slots available") 180 assert.Equal(exceptErr.Error(), err.Error()) 181 182 // addDeviceToBridge fails cause q.Bridges == 0 183 q = newQemuArchBase() 184 q.machineType = QemuPCLite 185 q.bridges(0) 186 _, _, err = q.addDeviceToBridge("qemu-bridge", types.PCI) 187 if assert.Error(err) { 188 exceptErr = errors.New("failed to get available address from bridges") 189 assert.Equal(exceptErr.Error(), err.Error()) 190 } 191 } 192 193 func TestQemuArchBaseCPUTopology(t *testing.T) { 194 assert := assert.New(t) 195 qemuArchBase := newQemuArchBase() 196 vcpus := uint32(2) 197 198 expectedSMP := govmmQemu.SMP{ 199 CPUs: vcpus, 200 Sockets: defaultMaxQemuVCPUs, 201 Cores: defaultCores, 202 Threads: defaultThreads, 203 MaxCPUs: defaultMaxQemuVCPUs, 204 } 205 206 smp := qemuArchBase.cpuTopology(vcpus, defaultMaxQemuVCPUs) 207 assert.Equal(expectedSMP, smp) 208 } 209 210 func TestQemuArchBaseCPUModel(t *testing.T) { 211 assert := assert.New(t) 212 qemuArchBase := newQemuArchBase() 213 214 assert.Equal(defaultCPUModel, qemuArchBase.cpuModel()) 215 } 216 217 func TestQemuArchBaseMemoryTopology(t *testing.T) { 218 assert := assert.New(t) 219 qemuArchBase := newQemuArchBase() 220 221 hostMem := uint64(100) 222 mem := uint64(120) 223 slots := uint8(12) 224 expectedMemory := govmmQemu.Memory{ 225 Size: fmt.Sprintf("%dM", mem), 226 Slots: slots, 227 MaxMem: fmt.Sprintf("%dM", hostMem), 228 } 229 230 m := qemuArchBase.memoryTopology(mem, hostMem, slots) 231 assert.Equal(expectedMemory, m) 232 } 233 234 func testQemuArchBaseAppend(t *testing.T, structure interface{}, expected []govmmQemu.Device) { 235 var devices []govmmQemu.Device 236 var err error 237 assert := assert.New(t) 238 qemuArchBase := newQemuArchBase() 239 240 switch s := structure.(type) { 241 case types.Volume: 242 devices, err = qemuArchBase.append9PVolume(devices, s) 243 case types.Socket: 244 devices = qemuArchBase.appendSocket(devices, s) 245 case config.BlockDrive: 246 devices, err = qemuArchBase.appendBlockDevice(devices, s) 247 case config.VFIODev: 248 devices = qemuArchBase.appendVFIODevice(devices, s) 249 case config.VhostUserDeviceAttrs: 250 devices, err = qemuArchBase.appendVhostUserDevice(devices, s) 251 } 252 253 assert.NoError(err) 254 assert.Equal(devices, expected) 255 } 256 257 func TestQemuArchBaseAppendConsoles(t *testing.T) { 258 var devices []govmmQemu.Device 259 var err error 260 assert := assert.New(t) 261 qemuArchBase := newQemuArchBase() 262 263 path := filepath.Join(filepath.Join(fs.MockRunStoragePath(), sandboxID), consoleSocket) 264 265 expectedOut := []govmmQemu.Device{ 266 govmmQemu.SerialDevice{ 267 Driver: govmmQemu.VirtioSerial, 268 ID: "serial0", 269 }, 270 govmmQemu.CharDevice{ 271 Driver: govmmQemu.Console, 272 Backend: govmmQemu.Socket, 273 DeviceID: "console0", 274 ID: "charconsole0", 275 Path: path, 276 }, 277 } 278 279 devices, err = qemuArchBase.appendConsole(devices, path) 280 assert.NoError(err) 281 assert.Equal(expectedOut, devices) 282 } 283 284 func TestQemuArchBaseAppendImage(t *testing.T) { 285 var devices []govmmQemu.Device 286 assert := assert.New(t) 287 qemuArchBase := newQemuArchBase() 288 289 image, err := ioutil.TempFile("", "img") 290 assert.NoError(err) 291 defer os.Remove(image.Name()) 292 err = image.Close() 293 assert.NoError(err) 294 295 devices, err = qemuArchBase.appendImage(devices, image.Name()) 296 assert.NoError(err) 297 assert.Len(devices, 1) 298 299 drive, ok := devices[0].(govmmQemu.BlockDevice) 300 assert.True(ok) 301 302 expectedOut := []govmmQemu.Device{ 303 govmmQemu.BlockDevice{ 304 Driver: govmmQemu.VirtioBlock, 305 ID: drive.ID, 306 File: image.Name(), 307 AIO: govmmQemu.Threads, 308 Format: "raw", 309 Interface: "none", 310 ShareRW: true, 311 ReadOnly: true, 312 }, 313 } 314 315 assert.Equal(expectedOut, devices) 316 } 317 318 func TestQemuArchBaseAppendBridges(t *testing.T) { 319 var devices []govmmQemu.Device 320 assert := assert.New(t) 321 qemuArchBase := newQemuArchBase() 322 323 qemuArchBase.bridges(1) 324 bridges := qemuArchBase.getBridges() 325 assert.Len(bridges, 1) 326 327 devices = qemuArchBase.appendBridges(devices) 328 assert.Len(devices, 1) 329 330 expectedOut := []govmmQemu.Device{ 331 govmmQemu.BridgeDevice{ 332 Type: govmmQemu.PCIBridge, 333 Bus: defaultBridgeBus, 334 ID: bridges[0].ID, 335 Chassis: 1, 336 SHPC: true, 337 Addr: "2", 338 }, 339 } 340 341 assert.Equal(expectedOut, devices) 342 } 343 344 func TestQemuArchBaseAppend9PVolume(t *testing.T) { 345 mountTag := "testMountTag" 346 hostPath := "testHostPath" 347 348 expectedOut := []govmmQemu.Device{ 349 govmmQemu.FSDevice{ 350 Driver: govmmQemu.Virtio9P, 351 FSDriver: govmmQemu.Local, 352 ID: fmt.Sprintf("extra-9p-%s", mountTag), 353 Path: hostPath, 354 MountTag: mountTag, 355 SecurityModel: govmmQemu.None, 356 }, 357 } 358 359 volume := types.Volume{ 360 MountTag: mountTag, 361 HostPath: hostPath, 362 } 363 364 testQemuArchBaseAppend(t, volume, expectedOut) 365 } 366 367 func TestQemuArchBaseAppendSocket(t *testing.T) { 368 deviceID := "channelTest" 369 id := "charchTest" 370 hostPath := "/tmp/hyper_test.sock" 371 name := "sh.hyper.channel.test" 372 373 expectedOut := []govmmQemu.Device{ 374 govmmQemu.CharDevice{ 375 Driver: govmmQemu.VirtioSerialPort, 376 Backend: govmmQemu.Socket, 377 DeviceID: deviceID, 378 ID: id, 379 Path: hostPath, 380 Name: name, 381 }, 382 } 383 384 socket := types.Socket{ 385 DeviceID: deviceID, 386 ID: id, 387 HostPath: hostPath, 388 Name: name, 389 } 390 391 testQemuArchBaseAppend(t, socket, expectedOut) 392 } 393 394 func TestQemuArchBaseAppendBlockDevice(t *testing.T) { 395 id := "blockDevTest" 396 file := "/root" 397 format := "raw" 398 399 expectedOut := []govmmQemu.Device{ 400 govmmQemu.BlockDevice{ 401 Driver: govmmQemu.VirtioBlock, 402 ID: id, 403 File: "/root", 404 AIO: govmmQemu.Threads, 405 Format: govmmQemu.BlockDeviceFormat(format), 406 Interface: "none", 407 }, 408 } 409 410 drive := config.BlockDrive{ 411 File: file, 412 Format: format, 413 ID: id, 414 } 415 416 testQemuArchBaseAppend(t, drive, expectedOut) 417 } 418 419 func TestQemuArchBaseAppendVhostUserDevice(t *testing.T) { 420 socketPath := "nonexistentpath.sock" 421 macAddress := "00:11:22:33:44:55:66" 422 id := "deadbeef" 423 424 expectedOut := []govmmQemu.Device{ 425 govmmQemu.VhostUserDevice{ 426 SocketPath: socketPath, 427 CharDevID: fmt.Sprintf("char-%s", id), 428 TypeDevID: fmt.Sprintf("net-%s", id), 429 Address: macAddress, 430 VhostUserType: govmmQemu.VhostUserNet, 431 }, 432 } 433 434 vhostUserDevice := config.VhostUserDeviceAttrs{ 435 Type: config.VhostUserNet, 436 MacAddress: macAddress, 437 } 438 vhostUserDevice.DevID = id 439 vhostUserDevice.SocketPath = socketPath 440 441 testQemuArchBaseAppend(t, vhostUserDevice, expectedOut) 442 } 443 444 func TestQemuArchBaseAppendVFIODevice(t *testing.T) { 445 bdf := "02:10.1" 446 447 expectedOut := []govmmQemu.Device{ 448 govmmQemu.VFIODevice{ 449 BDF: bdf, 450 }, 451 } 452 453 vfDevice := config.VFIODev{ 454 BDF: bdf, 455 } 456 457 testQemuArchBaseAppend(t, vfDevice, expectedOut) 458 } 459 460 func TestQemuArchBaseAppendVFIODeviceWithVendorDeviceID(t *testing.T) { 461 bdf := "02:10.1" 462 vendorID := "0x1234" 463 deviceID := "0x5678" 464 465 expectedOut := []govmmQemu.Device{ 466 govmmQemu.VFIODevice{ 467 BDF: bdf, 468 VendorID: vendorID, 469 DeviceID: deviceID, 470 }, 471 } 472 473 vfDevice := config.VFIODev{ 474 BDF: bdf, 475 VendorID: vendorID, 476 DeviceID: deviceID, 477 } 478 479 testQemuArchBaseAppend(t, vfDevice, expectedOut) 480 } 481 482 func TestQemuArchBaseAppendSCSIController(t *testing.T) { 483 var devices []govmmQemu.Device 484 assert := assert.New(t) 485 qemuArchBase := newQemuArchBase() 486 487 expectedOut := []govmmQemu.Device{ 488 govmmQemu.SCSIController{ 489 ID: scsiControllerID, 490 }, 491 } 492 493 devices, ioThread, err := qemuArchBase.appendSCSIController(devices, false) 494 assert.Equal(expectedOut, devices) 495 assert.Nil(ioThread) 496 assert.NoError(err) 497 498 _, ioThread, err = qemuArchBase.appendSCSIController(devices, true) 499 assert.NotNil(ioThread) 500 assert.NoError(err) 501 } 502 503 func TestQemuArchBaseAppendNetwork(t *testing.T) { 504 var devices []govmmQemu.Device 505 var err error 506 assert := assert.New(t) 507 qemuArchBase := newQemuArchBase() 508 509 macAddr := net.HardwareAddr{0x02, 0x00, 0xCA, 0xFE, 0x00, 0x04} 510 511 macvlanEp := &BridgedMacvlanEndpoint{ 512 NetPair: NetworkInterfacePair{ 513 TapInterface: TapInterface{ 514 ID: "uniqueTestID-4", 515 Name: "br4_kata", 516 TAPIface: NetworkInterface{ 517 Name: "tap4_kata", 518 }, 519 }, 520 VirtIface: NetworkInterface{ 521 Name: "eth4", 522 HardAddr: macAddr.String(), 523 }, 524 NetInterworkingModel: DefaultNetInterworkingModel, 525 }, 526 EndpointType: BridgedMacvlanEndpointType, 527 } 528 529 macvtapEp := &MacvtapEndpoint{ 530 EndpointType: MacvtapEndpointType, 531 EndpointProperties: NetworkInfo{ 532 Iface: NetlinkIface{ 533 Type: "macvtap", 534 }, 535 }, 536 } 537 538 expectedOut := []govmmQemu.Device{ 539 govmmQemu.NetDevice{ 540 Type: networkModelToQemuType(macvlanEp.NetPair.NetInterworkingModel), 541 Driver: govmmQemu.VirtioNet, 542 ID: fmt.Sprintf("network-%d", 0), 543 IFName: macvlanEp.NetPair.TAPIface.Name, 544 MACAddress: macvlanEp.NetPair.TAPIface.HardAddr, 545 DownScript: "no", 546 Script: "no", 547 FDs: macvlanEp.NetPair.VMFds, 548 VhostFDs: macvlanEp.NetPair.VhostFds, 549 }, 550 govmmQemu.NetDevice{ 551 Type: govmmQemu.MACVTAP, 552 Driver: govmmQemu.VirtioNet, 553 ID: fmt.Sprintf("network-%d", 1), 554 IFName: macvtapEp.Name(), 555 MACAddress: macvtapEp.HardwareAddr(), 556 DownScript: "no", 557 Script: "no", 558 FDs: macvtapEp.VMFds, 559 VhostFDs: macvtapEp.VhostFds, 560 }, 561 } 562 563 devices, err = qemuArchBase.appendNetwork(devices, macvlanEp) 564 assert.NoError(err) 565 devices, err = qemuArchBase.appendNetwork(devices, macvtapEp) 566 assert.NoError(err) 567 assert.Equal(expectedOut, devices) 568 }