gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/acrn.go (about) 1 // Copyright (c) 2019 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package virtcontainers 7 8 import ( 9 "context" 10 "encoding/json" 11 "fmt" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "strings" 16 "syscall" 17 "time" 18 "unsafe" 19 20 opentracing "github.com/opentracing/opentracing-go" 21 "github.com/pkg/errors" 22 "github.com/sirupsen/logrus" 23 24 "github.com/kata-containers/runtime/virtcontainers/device/config" 25 persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api" 26 "github.com/kata-containers/runtime/virtcontainers/pkg/uuid" 27 "github.com/kata-containers/runtime/virtcontainers/types" 28 "github.com/kata-containers/runtime/virtcontainers/utils" 29 ) 30 31 // Since ACRN is using the store in a quite abnormal way, let's first draw it back from store to here 32 33 // UUIDPathSuffix is the suffix used for uuid storage 34 const ( 35 UUIDPathSuffix = "uuid" 36 uuidFile = "uuid.json" 37 ) 38 39 // ACRN currently supports only known UUIDs for security 40 // reasons (FuSa). When launching VM, only these pre-defined 41 // UUID should be used else VM launch will fail. The main 42 // of purpose UUID is is not used for image identification 43 // but generating vSeed (virtual seed which takes UUID 44 // as one of the parameter) which is used during VM boot. 45 46 // acrnUUIDsToIdx lists Idx corresponding to the UUID 47 var acrnUUIDsToIdx = map[string]uint8{ 48 "a7ada506-1ab0-4b6b-a0da-e513ca9b8c2f": 0, 49 "dbeae168-26e4-4084-9227-622193e56325": 1, 50 "18ed60cd-e9ea-4bf4-8f87-8523fc8347a3": 2, 51 "3f90b6f8-449a-4e72-b99c-063a889fc422": 3, 52 "1ae8587b-e599-4b59-8260-6d14ac166a55": 4, 53 "75f3b94b-49ed-48fc-b019-577ef45adf2b": 5, 54 "ca62cf3c-8359-47e8-a3f7-de2d682dfb02": 6, 55 "e3189497-c3f6-4b97-9e2c-18ac0ab9064d": 7, 56 } 57 58 // acrnIdxToUUIDs lists UUIDs corresponding to the Idx 59 var acrnIdxToUUIDs = map[uint8]string{ 60 0: "a7ada506-1ab0-4b6b-a0da-e513ca9b8c2f", 61 1: "dbeae168-26e4-4084-9227-622193e56325", 62 2: "18ed60cd-e9ea-4bf4-8f87-8523fc8347a3", 63 3: "3f90b6f8-449a-4e72-b99c-063a889fc422", 64 4: "1ae8587b-e599-4b59-8260-6d14ac166a55", 65 5: "75f3b94b-49ed-48fc-b019-577ef45adf2b", 66 6: "ca62cf3c-8359-47e8-a3f7-de2d682dfb02", 67 7: "e3189497-c3f6-4b97-9e2c-18ac0ab9064d", 68 } 69 70 // AcrnInfo keeps track of UUID availability 71 type AcrnInfo struct { 72 UUIDAvailability [8]uint8 73 } 74 75 // AcrnState keeps track of VM UUID, PID. 76 type AcrnState struct { 77 UUID string 78 PID int 79 } 80 81 // Acrn is an Hypervisor interface implementation for the Linux acrn hypervisor. 82 type Acrn struct { 83 id string 84 config HypervisorConfig 85 acrnConfig Config 86 state AcrnState 87 info AcrnInfo 88 arch acrnArch 89 ctx context.Context 90 store persistapi.PersistDriver 91 } 92 93 type acrnPlatformInfo struct { 94 cpuNum uint16 //nolint 95 reserved0 [126]uint8 //nolint 96 maxVCPUsPerVM uint16 //nolint 97 maxKataContainers uint8 98 reserved1 [125]uint8 //nolint 99 } 100 101 const acrnDevice = "/dev/acrn_vhm" 102 103 // ioctl_ACRN_CREATE_VM is the IOCTL to create VM in ACRN. 104 // Current Linux mainstream kernel doesn't have support for ACRN. 105 // Due to this several macros are not defined in Linux headers. 106 // Until the support is available, directly use the value instead 107 // of macros. 108 //https://github.com/kata-containers/runtime/issues/1784 109 const ioctl_ACRN_GET_PLATFORM_INFO = 0x43000003 //nolint 110 111 const ( 112 acrnConsoleSocket = "console.sock" 113 acrnStopSandboxTimeoutSecs = 15 114 ) 115 116 //UUIDBusy marks a particular UUID as busy 117 const UUIDBusy = 1 118 119 //UUIDFree marks a particular UUID as free 120 const UUIDFree = 0 121 122 // agnostic list of kernel parameters 123 var acrnDefaultKernelParameters = []Param{ 124 {"panic", "1"}, 125 } 126 127 func (a *Acrn) kernelParameters() string { 128 // get a list of arch kernel parameters 129 params := a.arch.kernelParameters(a.config.Debug) 130 131 // use default parameters 132 params = append(params, acrnDefaultKernelParameters...) 133 134 // set the maximum number of vCPUs 135 params = append(params, Param{"maxcpus", fmt.Sprintf("%d", a.config.DefaultMaxVCPUs)}) 136 137 // add the params specified by the provided config. As the kernel 138 // honours the last parameter value set and since the config-provided 139 // params are added here, they will take priority over the defaults. 140 params = append(params, a.config.KernelParams...) 141 142 paramsStr := SerializeParams(params, "=") 143 144 return strings.Join(paramsStr, " ") 145 } 146 147 // Adds all capabilities supported by Acrn implementation of hypervisor interface 148 func (a *Acrn) capabilities() types.Capabilities { 149 span, _ := a.trace("capabilities") 150 defer span.Finish() 151 152 return a.arch.capabilities() 153 } 154 155 func (a *Acrn) hypervisorConfig() HypervisorConfig { 156 return a.config 157 } 158 159 // get the acrn binary path 160 func (a *Acrn) acrnPath() (string, error) { 161 p, err := a.config.HypervisorAssetPath() 162 if err != nil { 163 return "", err 164 } 165 166 if p == "" { 167 p, err = a.arch.acrnPath() 168 if err != nil { 169 return "", err 170 } 171 } 172 173 if _, err = os.Stat(p); os.IsNotExist(err) { 174 return "", fmt.Errorf("acrn path (%s) does not exist", p) 175 } 176 177 return p, nil 178 } 179 180 // get the ACRNCTL binary path 181 func (a *Acrn) acrnctlPath() (string, error) { 182 ctlpath, err := a.config.HypervisorCtlAssetPath() 183 if err != nil { 184 return "", err 185 } 186 187 if ctlpath == "" { 188 ctlpath, err = a.arch.acrnctlPath() 189 if err != nil { 190 return "", err 191 } 192 } 193 194 if _, err = os.Stat(ctlpath); os.IsNotExist(err) { 195 return "", fmt.Errorf("acrnctl path (%s) does not exist", ctlpath) 196 } 197 198 return ctlpath, nil 199 } 200 201 // Logger returns a logrus logger appropriate for logging acrn messages 202 func (a *Acrn) Logger() *logrus.Entry { 203 return virtLog.WithField("subsystem", "acrn") 204 } 205 206 func (a *Acrn) trace(name string) (opentracing.Span, context.Context) { 207 if a.ctx == nil { 208 a.Logger().WithField("type", "bug").Error("trace called before context set") 209 a.ctx = context.Background() 210 } 211 212 span, ctx := opentracing.StartSpanFromContext(a.ctx, name) 213 214 span.SetTag("subsystem", "hypervisor") 215 span.SetTag("type", "acrn") 216 217 return span, ctx 218 } 219 220 func (a *Acrn) memoryTopology() (Memory, error) { 221 memMb := uint64(a.config.MemorySize) 222 223 return a.arch.memoryTopology(memMb), nil 224 } 225 226 func (a *Acrn) appendImage(devices []Device, imagePath string) ([]Device, error) { 227 if imagePath == "" { 228 return nil, fmt.Errorf("Image path is empty: %s", imagePath) 229 } 230 231 // Get sandbox and increment the globalIndex. 232 // This is to make sure the VM rootfs occupies 233 // the first Index which is /dev/vda. 234 sandbox, err := globalSandboxList.lookupSandbox(a.id) 235 if sandbox == nil && err != nil { 236 return nil, err 237 } 238 sandbox.GetAndSetSandboxBlockIndex() 239 240 devices, err = a.arch.appendImage(devices, imagePath) 241 if err != nil { 242 return nil, err 243 } 244 245 return devices, nil 246 } 247 248 func (a *Acrn) buildDevices(imagePath string) ([]Device, error) { 249 var devices []Device 250 251 if imagePath == "" { 252 return nil, fmt.Errorf("Image Path should not be empty: %s", imagePath) 253 } 254 255 console, err := a.getSandboxConsole(a.id) 256 if err != nil { 257 return nil, err 258 } 259 260 // Add bridges before any other devices. This way we make sure that 261 // bridge gets the first available PCI address. 262 devices = a.arch.appendBridges(devices) 263 264 //Add LPC device to the list of other devices. 265 devices = a.arch.appendLPC(devices) 266 267 devices = a.arch.appendConsole(devices, console) 268 269 devices, err = a.appendImage(devices, imagePath) 270 if err != nil { 271 return nil, err 272 } 273 274 // Create virtio blk devices with dummy backend as a place 275 // holder for container rootfs (as acrn doesn't support hot-plug). 276 // Once the container rootfs is known, replace the dummy backend 277 // with actual path (using block rescan feature in acrn) 278 devices, err = a.createDummyVirtioBlkDev(devices) 279 if err != nil { 280 return nil, err 281 } 282 283 return devices, nil 284 } 285 286 // setup sets the Acrn structure up. 287 func (a *Acrn) setup(id string, hypervisorConfig *HypervisorConfig) error { 288 span, _ := a.trace("setup") 289 defer span.Finish() 290 291 err := hypervisorConfig.valid() 292 if err != nil { 293 return err 294 } 295 296 a.id = id 297 a.config = *hypervisorConfig 298 a.arch = newAcrnArch(a.config) 299 300 var create bool 301 var uuid string 302 303 if a.state.UUID == "" { 304 create = true 305 } 306 307 if create { 308 a.Logger().Debug("Setting UUID") 309 if uuid, err = a.GetNextAvailableUUID(); err != nil { 310 return err 311 } 312 a.state.UUID = uuid 313 Idx := acrnUUIDsToIdx[uuid] 314 a.info.UUIDAvailability[Idx] = UUIDBusy 315 316 // The path might already exist, but in case of VM templating, 317 // we have to create it since the sandbox has not created it yet. 318 if err = os.MkdirAll(filepath.Join(a.store.RunStoragePath(), id), DirMode); err != nil { 319 return err 320 } 321 322 if err = a.storeInfo(); err != nil { 323 return err 324 } 325 } 326 327 return nil 328 } 329 330 func (a *Acrn) createDummyVirtioBlkDev(devices []Device) ([]Device, error) { 331 span, _ := a.trace("createDummyVirtioBlkDev") 332 defer span.Finish() 333 334 // Since acrn doesn't support hot-plug, dummy virtio-blk 335 // devices are added and later replaced with container-rootfs. 336 // Starting from driveIndex 1, as 0 is allocated for VM rootfs. 337 for driveIndex := 1; driveIndex <= AcrnBlkDevPoolSz; driveIndex++ { 338 drive := config.BlockDrive{ 339 File: "nodisk", 340 Index: driveIndex, 341 } 342 343 devices = a.arch.appendBlockDevice(devices, drive) 344 } 345 346 return devices, nil 347 } 348 349 // createSandbox is the Hypervisor sandbox creation. 350 func (a *Acrn) createSandbox(ctx context.Context, id string, networkNS NetworkNamespace, hypervisorConfig *HypervisorConfig, stateful bool) error { 351 // Save the tracing context 352 a.ctx = ctx 353 354 span, _ := a.trace("createSandbox") 355 defer span.Finish() 356 357 if err := a.setup(id, hypervisorConfig); err != nil { 358 return err 359 } 360 361 memory, err := a.memoryTopology() 362 if err != nil { 363 return err 364 } 365 366 kernelPath, err := a.config.KernelAssetPath() 367 if err != nil { 368 return err 369 } 370 371 imagePath, err := a.config.ImageAssetPath() 372 if err != nil { 373 return err 374 } 375 376 kernel := Kernel{ 377 Path: kernelPath, 378 ImagePath: imagePath, 379 Params: a.kernelParameters(), 380 } 381 382 if a.state.UUID == "" { 383 return fmt.Errorf("ACRN UUID should not be empty") 384 } 385 386 devices, err := a.buildDevices(imagePath) 387 if err != nil { 388 return err 389 } 390 391 acrnPath, err := a.acrnPath() 392 if err != nil { 393 return err 394 } 395 396 acrnctlPath, err := a.acrnctlPath() 397 if err != nil { 398 return err 399 } 400 401 acrnConfig := Config{ 402 UUID: a.state.UUID, 403 ACPIVirt: true, 404 Path: acrnPath, 405 CtlPath: acrnctlPath, 406 Memory: memory, 407 Devices: devices, 408 Kernel: kernel, 409 Name: fmt.Sprintf("sandbox-%s", a.id), 410 } 411 412 a.acrnConfig = acrnConfig 413 414 return nil 415 } 416 417 // startSandbox will start the Sandbox's VM. 418 func (a *Acrn) startSandbox(timeoutSecs int) error { 419 span, _ := a.trace("startSandbox") 420 defer span.Finish() 421 422 if a.config.Debug { 423 params := a.arch.kernelParameters(a.config.Debug) 424 strParams := SerializeParams(params, "=") 425 formatted := strings.Join(strParams, " ") 426 427 // The name of this field matches a similar one generated by 428 // the runtime and allows users to identify which parameters 429 // are set here, which come from the runtime and which are set 430 // by the user. 431 a.Logger().WithField("default-kernel-parameters", formatted).Debug() 432 } 433 434 vmPath := filepath.Join(a.store.RunVMStoragePath(), a.id) 435 err := os.MkdirAll(vmPath, DirMode) 436 if err != nil { 437 return err 438 } 439 defer func() { 440 if err != nil { 441 if err := os.RemoveAll(vmPath); err != nil { 442 a.Logger().WithError(err).Error("Failed to clean up vm directory") 443 } 444 } 445 }() 446 447 var strErr string 448 var PID int 449 PID, strErr, err = LaunchAcrn(a.acrnConfig, virtLog.WithField("subsystem", "acrn-dm")) 450 if err != nil { 451 return fmt.Errorf("%s", strErr) 452 } 453 a.state.PID = PID 454 455 if err = a.waitSandbox(timeoutSecs); err != nil { 456 a.Logger().WithField("acrn wait failed:", err).Debug() 457 return err 458 } 459 460 return nil 461 } 462 463 // waitSandbox will wait for the Sandbox's VM to be up and running. 464 func (a *Acrn) waitSandbox(timeoutSecs int) error { 465 span, _ := a.trace("waitSandbox") 466 defer span.Finish() 467 468 if timeoutSecs < 0 { 469 return fmt.Errorf("Invalid timeout %ds", timeoutSecs) 470 } 471 472 time.Sleep(time.Duration(timeoutSecs) * time.Second) 473 474 return nil 475 } 476 477 // stopSandbox will stop the Sandbox's VM. 478 func (a *Acrn) stopSandbox() (err error) { 479 span, _ := a.trace("stopSandbox") 480 defer span.Finish() 481 482 a.Logger().Info("Stopping acrn VM") 483 484 defer func() { 485 if err != nil { 486 a.Logger().Info("stopSandbox failed") 487 } else { 488 a.Logger().Info("acrn VM stopped") 489 } 490 }() 491 492 // Mark the UUID as free 493 uuid := a.state.UUID 494 Idx := acrnUUIDsToIdx[uuid] 495 496 if err = a.loadInfo(); err != nil { 497 a.Logger().Info("Failed to load UUID availabiity info") 498 return err 499 } 500 501 a.info.UUIDAvailability[Idx] = UUIDFree 502 503 if err = a.storeInfo(); err != nil { 504 a.Logger().Info("Failed to store UUID availabiity info") 505 return err 506 } 507 508 pid := a.state.PID 509 510 // Send signal to the VM process to try to stop it properly 511 if err = syscall.Kill(pid, syscall.SIGINT); err != nil { 512 if err == syscall.ESRCH { 513 return nil 514 } 515 a.Logger().Info("Sending signal to stop acrn VM failed") 516 return err 517 } 518 519 // Wait for the VM process to terminate 520 tInit := time.Now() 521 for { 522 if err = syscall.Kill(pid, syscall.Signal(0)); err != nil { 523 a.Logger().Info("acrn VM stopped after sending signal") 524 return nil 525 } 526 527 if time.Since(tInit).Seconds() >= acrnStopSandboxTimeoutSecs { 528 a.Logger().Warnf("VM still running after waiting %ds", acrnStopSandboxTimeoutSecs) 529 break 530 } 531 532 // Let's avoid to run a too busy loop 533 time.Sleep(time.Duration(50) * time.Millisecond) 534 } 535 536 // Let's try with a hammer now, a SIGKILL should get rid of the 537 // VM process. 538 return syscall.Kill(pid, syscall.SIGKILL) 539 540 } 541 542 func (a *Acrn) updateBlockDevice(drive *config.BlockDrive) error { 543 var err error 544 if drive.File == "" || drive.Index >= AcrnBlkDevPoolSz { 545 return fmt.Errorf("Empty filepath or invalid drive index, Dive ID:%s, Drive Index:%d", 546 drive.ID, drive.Index) 547 } 548 549 slot := AcrnBlkdDevSlot[drive.Index] 550 551 //Explicitly set PCIAddr to NULL, so that VirtPath can be used 552 drive.PCIAddr = "" 553 554 args := []string{"blkrescan", a.acrnConfig.Name, fmt.Sprintf("%d,%s", slot, drive.File)} 555 556 a.Logger().WithFields(logrus.Fields{ 557 "drive": drive, 558 "path": a.config.HypervisorCtlPath, 559 }).Info("updateBlockDevice with acrnctl path") 560 cmd := exec.Command(a.config.HypervisorCtlPath, args...) 561 if err := cmd.Run(); err != nil { 562 a.Logger().WithError(err).Error("updating Block device with newFile path") 563 } 564 565 return err 566 } 567 568 func (a *Acrn) hotplugAddDevice(devInfo interface{}, devType deviceType) (interface{}, error) { 569 span, _ := a.trace("hotplugAddDevice") 570 defer span.Finish() 571 572 switch devType { 573 case blockDev: 574 //The drive placeholder has to exist prior to Update 575 return nil, a.updateBlockDevice(devInfo.(*config.BlockDrive)) 576 default: 577 return nil, fmt.Errorf("hotplugAddDevice: unsupported device: devInfo:%v, deviceType%v", 578 devInfo, devType) 579 } 580 } 581 582 func (a *Acrn) hotplugRemoveDevice(devInfo interface{}, devType deviceType) (interface{}, error) { 583 span, _ := a.trace("hotplugRemoveDevice") 584 defer span.Finish() 585 586 // Not supported. return success 587 588 return nil, nil 589 } 590 591 func (a *Acrn) pauseSandbox() error { 592 span, _ := a.trace("pauseSandbox") 593 defer span.Finish() 594 595 // Not supported. return success 596 597 return nil 598 } 599 600 func (a *Acrn) resumeSandbox() error { 601 span, _ := a.trace("resumeSandbox") 602 defer span.Finish() 603 604 // Not supported. return success 605 606 return nil 607 } 608 609 // addDevice will add extra devices to acrn command line. 610 func (a *Acrn) addDevice(devInfo interface{}, devType deviceType) error { 611 var err error 612 span, _ := a.trace("addDevice") 613 defer span.Finish() 614 615 switch v := devInfo.(type) { 616 case types.Volume: 617 // Not supported. return success 618 err = nil 619 case types.Socket: 620 a.acrnConfig.Devices = a.arch.appendSocket(a.acrnConfig.Devices, v) 621 case types.VSock: 622 // Not supported. return success 623 err = nil 624 case Endpoint: 625 a.acrnConfig.Devices = a.arch.appendNetwork(a.acrnConfig.Devices, v) 626 case config.BlockDrive: 627 a.acrnConfig.Devices = a.arch.appendBlockDevice(a.acrnConfig.Devices, v) 628 case config.VhostUserDeviceAttrs: 629 // Not supported. return success 630 err = nil 631 case config.VFIODev: 632 // Not supported. return success 633 err = nil 634 default: 635 err = nil 636 a.Logger().WithField("unknown-device-type", devInfo).Error("Adding device") 637 } 638 639 return err 640 } 641 642 // getSandboxConsole builds the path of the console where we can read 643 // logs coming from the sandbox. 644 func (a *Acrn) getSandboxConsole(id string) (string, error) { 645 span, _ := a.trace("getSandboxConsole") 646 defer span.Finish() 647 648 return utils.BuildSocketPath(a.store.RunVMStoragePath(), id, acrnConsoleSocket) 649 } 650 651 func (a *Acrn) saveSandbox() error { 652 a.Logger().Info("save sandbox") 653 654 // Not supported. return success 655 656 return nil 657 } 658 659 func (a *Acrn) disconnect() { 660 span, _ := a.trace("disconnect") 661 defer span.Finish() 662 663 // Not supported. 664 } 665 666 func (a *Acrn) getThreadIDs() (vcpuThreadIDs, error) { 667 span, _ := a.trace("getThreadIDs") 668 defer span.Finish() 669 670 // Not supported. return success 671 //Just allocating an empty map 672 673 return vcpuThreadIDs{}, nil 674 } 675 676 func (a *Acrn) resizeMemory(reqMemMB uint32, memoryBlockSizeMB uint32, probe bool) (uint32, memoryDevice, error) { 677 return 0, memoryDevice{}, nil 678 } 679 680 func (a *Acrn) resizeVCPUs(reqVCPUs uint32) (currentVCPUs uint32, newVCPUs uint32, err error) { 681 return 0, 0, nil 682 } 683 684 func (a *Acrn) cleanup() error { 685 span, _ := a.trace("cleanup") 686 defer span.Finish() 687 688 return nil 689 } 690 691 func (a *Acrn) getPids() []int { 692 return []int{a.state.PID} 693 } 694 695 func (a *Acrn) fromGrpc(ctx context.Context, hypervisorConfig *HypervisorConfig, j []byte) error { 696 return errors.New("acrn is not supported by VM cache") 697 } 698 699 func (a *Acrn) toGrpc() ([]byte, error) { 700 return nil, errors.New("acrn is not supported by VM cache") 701 } 702 703 func (a *Acrn) save() (s persistapi.HypervisorState) { 704 s.Pid = a.state.PID 705 s.Type = string(AcrnHypervisor) 706 s.UUID = a.state.UUID 707 return 708 } 709 710 func (a *Acrn) load(s persistapi.HypervisorState) { 711 a.state.PID = s.Pid 712 a.state.UUID = s.UUID 713 } 714 715 func (a *Acrn) check() error { 716 if err := syscall.Kill(a.state.PID, syscall.Signal(0)); err != nil { 717 return errors.Wrapf(err, "failed to ping acrn process") 718 } 719 720 return nil 721 } 722 723 func (a *Acrn) generateSocket(id string, useVsock bool) (interface{}, error) { 724 return generateVMSocket(id, useVsock, a.store.RunVMStoragePath()) 725 } 726 727 // GetACRNUUIDBytes returns UUID bytes that is used for VM creation 728 func (a *Acrn) GetACRNUUIDBytes(uid string) (uuid.UUID, error) { 729 return uuid.Parse(uid) 730 } 731 732 // GetNextAvailableUUID returns next available UUID VM creation 733 // If no valid UUIDs are available it returns err. 734 func (a *Acrn) GetNextAvailableUUID() (string, error) { 735 var MaxVMSupported uint8 736 var Idx uint8 737 var uuidStr string 738 var err error 739 740 if err = a.loadInfo(); err != nil { 741 a.Logger().Infof("Load UUID store failed") 742 } 743 744 if MaxVMSupported, err = a.GetMaxSupportedACRNVM(); err != nil { 745 return "", fmt.Errorf("IOCTL GetMaxSupportedACRNVM failed") 746 } 747 748 for Idx = 0; Idx < MaxVMSupported; Idx++ { 749 if a.info.UUIDAvailability[Idx] == UUIDFree { 750 uuidStr = acrnIdxToUUIDs[Idx] 751 break 752 } 753 } 754 755 if uuidStr == "" { 756 return "", fmt.Errorf("Invalid UUID: Max VMs reached") 757 } 758 759 return uuidStr, nil 760 } 761 762 // GetMaxSupportedACRNVM checks the max number of VMs that can be 763 // launched from kata-runtime. 764 func (a *Acrn) GetMaxSupportedACRNVM() (uint8, error) { 765 flags := syscall.O_RDWR | syscall.O_CLOEXEC 766 767 f, err := syscall.Open(acrnDevice, flags, 0) 768 if err != nil { 769 return 0, err 770 } 771 defer syscall.Close(f) 772 773 var platformInfo acrnPlatformInfo 774 775 ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, 776 uintptr(f), 777 uintptr(ioctl_ACRN_GET_PLATFORM_INFO), 778 uintptr(unsafe.Pointer(&platformInfo))) 779 if ret != 0 || errno != 0 { 780 return 0, errno 781 } 782 783 return platformInfo.maxKataContainers, nil 784 } 785 786 func (a *Acrn) storeInfo() error { 787 relPath := filepath.Join(UUIDPathSuffix, uuidFile) 788 789 jsonOut, err := json.Marshal(a.info) 790 if err != nil { 791 return fmt.Errorf("Could not marshal data: %s", err) 792 } 793 794 if err := a.store.GlobalWrite(relPath, jsonOut); err != nil { 795 return fmt.Errorf("failed to write uuid to file: %v", err) 796 } 797 798 return nil 799 } 800 801 func (a *Acrn) loadInfo() error { 802 relPath := filepath.Join(UUIDPathSuffix, uuidFile) 803 804 data, err := a.store.GlobalRead(relPath) 805 if err != nil { 806 return fmt.Errorf("failed to read uuid from file: %v", err) 807 } 808 809 if err := json.Unmarshal(data, &a.info); err != nil { 810 return fmt.Errorf("failed to unmarshal uuid info: %v", err) 811 } 812 return nil 813 }