1
2
3 package uvm
4
5 import (
6 "context"
7 "encoding/base64"
8 "fmt"
9 "io"
10 "net"
11 "os"
12 "path/filepath"
13 "strings"
14
15 "github.com/Microsoft/go-winio"
16 "github.com/Microsoft/go-winio/pkg/guid"
17 "github.com/Microsoft/hcsshim/internal/security"
18 "github.com/Microsoft/hcsshim/pkg/securitypolicy"
19 "github.com/pkg/errors"
20 "github.com/sirupsen/logrus"
21 "go.opencensus.io/trace"
22
23 "github.com/Microsoft/hcsshim/internal/gcs"
24 hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
25 "github.com/Microsoft/hcsshim/internal/log"
26 "github.com/Microsoft/hcsshim/internal/logfields"
27 "github.com/Microsoft/hcsshim/internal/oc"
28 "github.com/Microsoft/hcsshim/internal/processorinfo"
29 "github.com/Microsoft/hcsshim/internal/protocol/guestrequest"
30 "github.com/Microsoft/hcsshim/internal/schemaversion"
31 "github.com/Microsoft/hcsshim/osversion"
32 )
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 type PreferredRootFSType int
55
56 const (
57 PreferredRootFSTypeInitRd PreferredRootFSType = iota
58 PreferredRootFSTypeVHD
59 PreferredRootFSTypeNA
60
61 entropyVsockPort = 1
62 linuxLogVsockPort = 109
63 )
64
65
66 type OutputHandler func(io.Reader)
67
68 const (
69
70 InitrdFile = "initrd.img"
71
72 VhdFile = "rootfs.vhd"
73
74 KernelFile = "kernel"
75
76
77 UncompressedKernelFile = "vmlinux"
78
79
80 GuestStateFile = "kernelinitrd.vmgs"
81
82
83
84 UVMReferenceInfoFile = "reference_info.cose"
85 )
86
87 type ConfidentialOptions struct {
88 GuestStateFile string
89 UseGuestStateFile bool
90 SecurityPolicy string
91 SecurityPolicyEnabled bool
92 SecurityPolicyEnforcer string
93 UVMReferenceInfoFile string
94 BundleDirectory string
95 }
96
97
98 type OptionsLCOW struct {
99 *Options
100 *ConfidentialOptions
101
102 BootFilesPath string
103 KernelFile string
104 KernelDirect bool
105 RootFSFile string
106 KernelBootOptions string
107 EnableGraphicsConsole bool
108 ConsolePipe string
109 UseGuestConnection bool
110 ExecCommandLine string
111 ForwardStdout bool
112 ForwardStderr bool
113 OutputHandler OutputHandler `json:"-"`
114 VPMemDeviceCount uint32
115 VPMemSizeBytes uint64
116 VPMemNoMultiMapping bool
117 PreferredRootFSType PreferredRootFSType
118 EnableColdDiscardHint bool
119 VPCIEnabled bool
120 EnableScratchEncryption bool
121 DisableTimeSyncService bool
122 }
123
124
125
126
127
128 func defaultLCOWOSBootFilesPath() string {
129 localDirPath := filepath.Join(filepath.Dir(os.Args[0]), "LinuxBootFiles")
130 if _, err := os.Stat(localDirPath); err == nil {
131 return localDirPath
132 }
133 return filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers")
134 }
135
136
137
138
139
140
141
142
143 func NewDefaultOptionsLCOW(id, owner string) *OptionsLCOW {
144
145 kernelDirectSupported := osversion.Build() >= 18286
146 opts := &OptionsLCOW{
147 Options: newDefaultOptions(id, owner),
148 BootFilesPath: defaultLCOWOSBootFilesPath(),
149 KernelFile: KernelFile,
150 KernelDirect: kernelDirectSupported,
151 RootFSFile: InitrdFile,
152 KernelBootOptions: "",
153 EnableGraphicsConsole: false,
154 ConsolePipe: "",
155 UseGuestConnection: true,
156 ExecCommandLine: fmt.Sprintf("/bin/gcs -v4 -log-format json -loglevel %s", logrus.StandardLogger().Level.String()),
157 ForwardStdout: false,
158 ForwardStderr: true,
159 OutputHandler: parseLogrus(id),
160 VPMemDeviceCount: DefaultVPMEMCount,
161 VPMemSizeBytes: DefaultVPMemSizeBytes,
162 VPMemNoMultiMapping: osversion.Get().Build < osversion.V19H1,
163 PreferredRootFSType: PreferredRootFSTypeInitRd,
164 EnableColdDiscardHint: false,
165 VPCIEnabled: false,
166 EnableScratchEncryption: false,
167 DisableTimeSyncService: false,
168 ConfidentialOptions: &ConfidentialOptions{
169 SecurityPolicyEnabled: false,
170 UVMReferenceInfoFile: UVMReferenceInfoFile,
171 },
172 }
173
174 if _, err := os.Stat(filepath.Join(opts.BootFilesPath, VhdFile)); err == nil {
175
176 opts.RootFSFile = VhdFile
177 opts.PreferredRootFSType = PreferredRootFSTypeVHD
178 }
179
180 if kernelDirectSupported {
181
182
183
184
185 if _, err := os.Stat(filepath.Join(opts.BootFilesPath, UncompressedKernelFile)); err == nil {
186 opts.KernelFile = UncompressedKernelFile
187 }
188 }
189 return opts
190 }
191
192
193 func fetchProcessor(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (*hcsschema.Processor2, error) {
194 processorTopology, err := processorinfo.HostProcessorInfo(ctx)
195 if err != nil {
196 return nil, fmt.Errorf("failed to get host processor information: %s", err)
197 }
198
199
200
201 uvm.processorCount = uvm.normalizeProcessorCount(ctx, opts.ProcessorCount, processorTopology)
202
203 processor := &hcsschema.Processor2{
204 Count: uvm.processorCount,
205 Limit: opts.ProcessorLimit,
206 Weight: opts.ProcessorWeight,
207 }
208
209 if opts.CPUGroupID != "" {
210 if osversion.Build() < osversion.V21H1 {
211 return nil, errCPUGroupCreateNotSupported
212 }
213 processor.CpuGroup = &hcsschema.CpuGroup{Id: opts.CPUGroupID}
214 }
215 return processor, nil
216 }
217
218
292
293
294
295
296
297 func makeLCOWVMGSDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcsschema.ComputeSystem, err error) {
298
299 vmgsTemplatePath := filepath.Join(opts.BootFilesPath, opts.GuestStateFile)
300 if _, err := os.Stat(vmgsTemplatePath); os.IsNotExist(err) {
301 return nil, fmt.Errorf("the GuestState vmgs file '%s' was not found", vmgsTemplatePath)
302 }
303
304
305
306 if opts.PreferredRootFSType != PreferredRootFSTypeNA {
307 return nil, fmt.Errorf("cannot override rootfs when using VMGS file")
308 }
309
310 var processor *hcsschema.Processor2
311 processor, err = fetchProcessor(ctx, opts, uvm)
312 if err != nil {
313 return nil, err
314 }
315
316 vmgsFile, err := os.Create(filepath.Join(opts.BundleDirectory, opts.GuestStateFile))
317 if err != nil {
318 return nil, fmt.Errorf("failed to create temporary VMGS file: %w", err)
319 }
320 defer func() {
321 _ = vmgsFile.Close()
322 if err != nil {
323 if rmErr := os.RemoveAll(vmgsFile.Name()); rmErr != nil {
324 log.G(ctx).WithError(rmErr).Error("failed to remove temporary VMGS file")
325 }
326 }
327 }()
328
329 templateFile, err := os.Open(vmgsTemplatePath)
330 if err != nil {
331 return nil, fmt.Errorf("failed to open template VMGS file for copy: %w", err)
332 }
333 defer templateFile.Close()
334
335 if _, err := io.Copy(vmgsFile, templateFile); err != nil {
336 return nil, fmt.Errorf("failed to copy template VMGS file: %w", err)
337 }
338
339 if err := security.GrantVmGroupAccessWithMask(vmgsFile.Name(), security.AccessMaskAll); err != nil {
340 return nil, fmt.Errorf("failed to grant VM group access ALL: %w", err)
341 }
342
343
344 memorySizeInMB := uvm.normalizeMemorySize(ctx, opts.MemorySizeInMB)
345
346 doc := &hcsschema.ComputeSystem{
347 Owner: uvm.owner,
348 SchemaVersion: schemaversion.SchemaV25(),
349 ShouldTerminateOnLastHandleClosed: true,
350 VirtualMachine: &hcsschema.VirtualMachine{
351 StopOnReset: true,
352 Chipset: &hcsschema.Chipset{},
353 ComputeTopology: &hcsschema.Topology{
354 Memory: &hcsschema.Memory2{
355 SizeInMB: memorySizeInMB,
356 AllowOvercommit: opts.AllowOvercommit,
357 EnableDeferredCommit: opts.EnableDeferredCommit,
358 EnableColdDiscardHint: opts.EnableColdDiscardHint,
359 LowMMIOGapInMB: opts.LowMMIOGapInMB,
360 HighMMIOBaseInMB: opts.HighMMIOBaseInMB,
361 HighMMIOGapInMB: opts.HighMMIOGapInMB,
362 },
363 Processor: processor,
364 },
365 Devices: &hcsschema.Devices{
366 HvSocket: &hcsschema.HvSocket2{
367 HvSocketConfig: &hcsschema.HvSocketSystemConfig{
368
369
370 DefaultBindSecurityDescriptor: "D:P(A;;FA;;;WD)",
371 DefaultConnectSecurityDescriptor: "D:P(A;;FA;;;SY)(A;;FA;;;BA)",
372 ServiceTable: make(map[string]hcsschema.HvSocketServiceConfig),
373 },
374 },
375 Plan9: &hcsschema.Plan9{},
376 },
377 },
378 }
379
380
381
382
383
384 hvSockets := [...]uint32{entropyVsockPort, linuxLogVsockPort, gcs.LinuxGcsVsockPort, gcs.LinuxGcsVsockPort + 1}
385 for _, whichSocket := range hvSockets {
386 key := fmt.Sprintf("%08x-facb-11e6-bd58-64006a7986d3", whichSocket)
387 doc.VirtualMachine.Devices.HvSocket.HvSocketConfig.ServiceTable[key] = hcsschema.HvSocketServiceConfig{
388 AllowWildcardBinds: true,
389 BindSecurityDescriptor: "D:P(A;;FA;;;WD)",
390 ConnectSecurityDescriptor: "D:P(A;;FA;;;SY)(A;;FA;;;BA)",
391 }
392 }
393
394
395 if opts.StorageQoSBandwidthMaximum > 0 || opts.StorageQoSIopsMaximum > 0 {
396 doc.VirtualMachine.StorageQoS = &hcsschema.StorageQoS{
397 IopsMaximum: opts.StorageQoSIopsMaximum,
398 BandwidthMaximum: opts.StorageQoSBandwidthMaximum,
399 }
400 }
401
402 if uvm.scsiControllerCount > 0 {
403 doc.VirtualMachine.Devices.Scsi = map[string]hcsschema.Scsi{}
404 for i := 0; i < int(uvm.scsiControllerCount); i++ {
405 doc.VirtualMachine.Devices.Scsi[guestrequest.ScsiControllerGuids[i]] = hcsschema.Scsi{
406 Attachments: make(map[string]hcsschema.Attachment),
407 }
408 }
409 }
410
411
412
413 doc.VirtualMachine.Chipset.Uefi = &hcsschema.Uefi{
414 ApplySecureBootTemplate: "Apply",
415 SecureBootTemplateId: "1734c6e8-3154-4dda-ba5f-a874cc483422",
416
417 }
418
419
420 doc.VirtualMachine.GuestState = &hcsschema.GuestState{
421 GuestStateFilePath: vmgsFile.Name(),
422 GuestStateFileType: "FileMode",
423 ForceTransientState: true,
424 }
425
426 return doc, nil
427 }
428
429
430
431
432
433 func makeLCOWSecurityDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcsschema.ComputeSystem, err error) {
434 doc, vmgsErr := makeLCOWVMGSDoc(ctx, opts, uvm)
435 if vmgsErr != nil {
436 return nil, vmgsErr
437 }
438
439
440
441
442
443
444 policyDigest, err := securitypolicy.NewSecurityPolicyDigest(opts.SecurityPolicy)
445 if err != nil {
446 return nil, err
447 }
448
449
450
451 hostData := base64.StdEncoding.EncodeToString(policyDigest)
452
453
454
455
456 doc.VirtualMachine.SecuritySettings = &hcsschema.SecuritySettings{
457 EnableTpm: false,
458 Isolation: &hcsschema.IsolationSettings{
459 IsolationType: "SecureNestedPaging",
460 LaunchData: hostData,
461
462 },
463 }
464
465 return doc, nil
466 }
467
468
509
510
511 func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcsschema.ComputeSystem, err error) {
512 logrus.Tracef("makeLCOWDoc %v\n", opts)
513
514 kernelFullPath := filepath.Join(opts.BootFilesPath, opts.KernelFile)
515 if _, err := os.Stat(kernelFullPath); os.IsNotExist(err) {
516 return nil, fmt.Errorf("kernel: '%s' not found", kernelFullPath)
517 }
518 rootfsFullPath := filepath.Join(opts.BootFilesPath, opts.RootFSFile)
519 if _, err := os.Stat(rootfsFullPath); os.IsNotExist(err) {
520 return nil, fmt.Errorf("boot file: '%s' not found", rootfsFullPath)
521 }
522
523 var processor *hcsschema.Processor2
524 processor, err = fetchProcessor(ctx, opts, uvm)
525 if err != nil {
526 return nil, err
527 }
528
529
530 memorySizeInMB := uvm.normalizeMemorySize(ctx, opts.MemorySizeInMB)
531
532 doc := &hcsschema.ComputeSystem{
533 Owner: uvm.owner,
534 SchemaVersion: schemaversion.SchemaV21(),
535 ShouldTerminateOnLastHandleClosed: true,
536 VirtualMachine: &hcsschema.VirtualMachine{
537 StopOnReset: true,
538 Chipset: &hcsschema.Chipset{},
539 ComputeTopology: &hcsschema.Topology{
540 Memory: &hcsschema.Memory2{
541 SizeInMB: memorySizeInMB,
542 AllowOvercommit: opts.AllowOvercommit,
543 EnableDeferredCommit: opts.EnableDeferredCommit,
544 EnableColdDiscardHint: opts.EnableColdDiscardHint,
545 LowMMIOGapInMB: opts.LowMMIOGapInMB,
546 HighMMIOBaseInMB: opts.HighMMIOBaseInMB,
547 HighMMIOGapInMB: opts.HighMMIOGapInMB,
548 },
549 Processor: processor,
550 },
551 Devices: &hcsschema.Devices{
552 HvSocket: &hcsschema.HvSocket2{
553 HvSocketConfig: &hcsschema.HvSocketSystemConfig{
554
555
556 DefaultBindSecurityDescriptor: "D:P(A;;FA;;;SY)(A;;FA;;;BA)",
557 },
558 },
559 Plan9: &hcsschema.Plan9{},
560 },
561 },
562 }
563
564
565 if opts.StorageQoSBandwidthMaximum > 0 || opts.StorageQoSIopsMaximum > 0 {
566 doc.VirtualMachine.StorageQoS = &hcsschema.StorageQoS{
567 IopsMaximum: opts.StorageQoSIopsMaximum,
568 BandwidthMaximum: opts.StorageQoSBandwidthMaximum,
569 }
570 }
571
572 if uvm.scsiControllerCount > 0 {
573 doc.VirtualMachine.Devices.Scsi = map[string]hcsschema.Scsi{}
574 for i := 0; i < int(uvm.scsiControllerCount); i++ {
575 doc.VirtualMachine.Devices.Scsi[guestrequest.ScsiControllerGuids[i]] = hcsschema.Scsi{
576 Attachments: make(map[string]hcsschema.Attachment),
577 }
578 }
579 }
580
581 if uvm.vpmemMaxCount > 0 {
582 doc.VirtualMachine.Devices.VirtualPMem = &hcsschema.VirtualPMemController{
583 MaximumCount: uvm.vpmemMaxCount,
584 MaximumSizeBytes: uvm.vpmemMaxSizeBytes,
585 }
586 }
587
588 var kernelArgs string
589 switch opts.PreferredRootFSType {
590 case PreferredRootFSTypeInitRd:
591 if !opts.KernelDirect {
592 kernelArgs = "initrd=/" + opts.RootFSFile
593 }
594 case PreferredRootFSTypeVHD:
595 if uvm.vpmemMaxCount > 0 {
596
597 kernelArgs = "root=/dev/pmem0 ro rootwait init=/init"
598 imageFormat := "Vhd1"
599 if strings.ToLower(filepath.Ext(opts.RootFSFile)) == "vhdx" {
600 imageFormat = "Vhdx"
601 }
602 doc.VirtualMachine.Devices.VirtualPMem.Devices = map[string]hcsschema.VirtualPMemDevice{
603 "0": {
604 HostPath: rootfsFullPath,
605 ReadOnly: true,
606 ImageFormat: imageFormat,
607 },
608 }
609 if uvm.vpmemMultiMapping {
610 pmem := newPackedVPMemDevice()
611 pmem.maxMappedDeviceCount = 1
612
613 st, stErr := os.Stat(rootfsFullPath)
614 if stErr != nil {
615 return nil, errors.Wrapf(stErr, "failed to stat rootfs: %q", rootfsFullPath)
616 }
617 devSize := pageAlign(uint64(st.Size()))
618 memReg, pErr := pmem.Allocate(devSize)
619 if pErr != nil {
620 return nil, errors.Wrap(pErr, "failed to allocate memory for rootfs")
621 }
622 defer func() {
623 if err != nil {
624 if err = pmem.Release(memReg); err != nil {
625 log.G(ctx).WithError(err).Debug("failed to release memory region")
626 }
627 }
628 }()
629
630 dev := newVPMemMappedDevice(opts.RootFSFile, "/", devSize, memReg)
631 if err := pmem.mapVHDLayer(ctx, dev); err != nil {
632 return nil, errors.Wrapf(err, "failed to save internal state for a multi-mapped rootfs device")
633 }
634 uvm.vpmemDevicesMultiMapped[0] = pmem
635 } else {
636 dev := newDefaultVPMemInfo(opts.RootFSFile, "/")
637 uvm.vpmemDevicesDefault[0] = dev
638 }
639 } else {
640 kernelArgs = "root=/dev/sda ro rootwait init=/init"
641 doc.VirtualMachine.Devices.Scsi[guestrequest.ScsiControllerGuids[0]].Attachments["0"] = hcsschema.Attachment{
642 Type_: "VirtualDisk",
643 Path: rootfsFullPath,
644 ReadOnly: true,
645 }
646 uvm.scsiLocations[0][0] = newSCSIMount(uvm, rootfsFullPath, "/", "VirtualDisk", "", 1, 0, 0, true, false)
647 }
648 }
649
650 vmDebugging := false
651 if opts.ConsolePipe != "" {
652 vmDebugging = true
653 kernelArgs += " 8250_core.nr_uarts=1 8250_core.skip_txen_test=1 console=ttyS0,115200"
654 doc.VirtualMachine.Devices.ComPorts = map[string]hcsschema.ComPort{
655 "0": {
656 NamedPipe: opts.ConsolePipe,
657 },
658 }
659 } else {
660 kernelArgs += " 8250_core.nr_uarts=0"
661 }
662
663 if opts.EnableGraphicsConsole {
664 vmDebugging = true
665 kernelArgs += " console=tty"
666 doc.VirtualMachine.Devices.Keyboard = &hcsschema.Keyboard{}
667 doc.VirtualMachine.Devices.EnhancedModeVideo = &hcsschema.EnhancedModeVideo{}
668 doc.VirtualMachine.Devices.VideoMonitor = &hcsschema.VideoMonitor{}
669 }
670
671 if !vmDebugging {
672
673 kernelArgs += " panic=-1 quiet"
674 }
675
676
677 if opts.KernelBootOptions != "" {
678 kernelArgs += " " + opts.KernelBootOptions
679 }
680
681 if !opts.VPCIEnabled {
682 kernelArgs += ` pci=off`
683 }
684
685
686 entropyArgs := fmt.Sprintf("-e %d", entropyVsockPort)
687
688
689
690 execCmdArgs := "/bin/vsockexec"
691
692 if opts.ForwardStdout {
693 execCmdArgs += fmt.Sprintf(" -o %d", linuxLogVsockPort)
694 }
695
696 if opts.ForwardStderr {
697 execCmdArgs += fmt.Sprintf(" -e %d", linuxLogVsockPort)
698 }
699
700 if opts.DisableTimeSyncService {
701 opts.ExecCommandLine = fmt.Sprintf("%s -disable-time-sync", opts.ExecCommandLine)
702 }
703
704 if log.IsScrubbingEnabled() {
705 opts.ExecCommandLine += " -scrub-logs"
706 }
707
708 execCmdArgs += " " + opts.ExecCommandLine
709
710 if opts.ProcessDumpLocation != "" {
711 execCmdArgs += " -core-dump-location " + opts.ProcessDumpLocation
712 }
713
714 initArgs := fmt.Sprintf("%s %s", entropyArgs, execCmdArgs)
715 if vmDebugging {
716
717 initArgs = entropyArgs + ` sh -c "` + execCmdArgs + ` & exec sh"`
718 }
719
720 kernelArgs += fmt.Sprintf(" nr_cpus=%d", opts.ProcessorCount)
721 kernelArgs += ` brd.rd_nr=0 pmtmr=0 -- ` + initArgs
722
723 if !opts.KernelDirect {
724 doc.VirtualMachine.Chipset.Uefi = &hcsschema.Uefi{
725 BootThis: &hcsschema.UefiBootEntry{
726 DevicePath: `\` + opts.KernelFile,
727 DeviceType: "VmbFs",
728 VmbFsRootPath: opts.BootFilesPath,
729 OptionalData: kernelArgs,
730 },
731 }
732 } else {
733 doc.VirtualMachine.Chipset.LinuxKernelDirect = &hcsschema.LinuxKernelDirect{
734 KernelFilePath: kernelFullPath,
735 KernelCmdLine: kernelArgs,
736 }
737 if opts.PreferredRootFSType == PreferredRootFSTypeInitRd {
738 doc.VirtualMachine.Chipset.LinuxKernelDirect.InitRdPath = rootfsFullPath
739 }
740 }
741 return doc, nil
742 }
743
744
745
746
747 func CreateLCOW(ctx context.Context, opts *OptionsLCOW) (_ *UtilityVM, err error) {
748 ctx, span := oc.StartSpan(ctx, "uvm::CreateLCOW")
749 defer span.End()
750 defer func() { oc.SetSpanStatus(span, err) }()
751
752 if opts.ID == "" {
753 g, err := guid.NewV4()
754 if err != nil {
755 return nil, err
756 }
757 opts.ID = g.String()
758 }
759
760 span.AddAttributes(trace.StringAttribute(logfields.UVMID, opts.ID))
761 log.G(ctx).WithField("options", fmt.Sprintf("%+v", opts)).Debug("uvm::CreateLCOW options")
762
763
764 if opts.OutputHandler == nil {
765 opts.OutputHandler = parseLogrus(opts.ID)
766 }
767
768 uvm := &UtilityVM{
769 id: opts.ID,
770 owner: opts.Owner,
771 operatingSystem: "linux",
772 scsiControllerCount: opts.SCSIControllerCount,
773 vpmemMaxCount: opts.VPMemDeviceCount,
774 vpmemMaxSizeBytes: opts.VPMemSizeBytes,
775 vpciDevices: make(map[VPCIDeviceKey]*VPCIDevice),
776 physicallyBacked: !opts.AllowOvercommit,
777 devicesPhysicallyBacked: opts.FullyPhysicallyBacked,
778 createOpts: opts,
779 vpmemMultiMapping: !opts.VPMemNoMultiMapping,
780 encryptScratch: opts.EnableScratchEncryption,
781 noWritableFileShares: opts.NoWritableFileShares,
782 confidentialUVMOptions: opts.ConfidentialOptions,
783 }
784
785 defer func() {
786 if err != nil {
787 uvm.Close()
788 }
789 }()
790
791
792
793 if osversion.Build() >= osversion.RS5 && uvm.vpmemMaxCount == 0 {
794 uvm.scsiControllerCount = 4
795 }
796
797 if err = verifyOptions(ctx, opts); err != nil {
798 return nil, errors.Wrap(err, errBadUVMOpts.Error())
799 }
800
801
802 var doc *hcsschema.ComputeSystem
803 if opts.SecurityPolicyEnabled {
804 doc, err = makeLCOWSecurityDoc(ctx, opts, uvm)
805 log.G(ctx).Tracef("create_lcow::CreateLCOW makeLCOWSecurityDoc result doc: %v err %v", doc, err)
806 } else {
807 doc, err = makeLCOWDoc(ctx, opts, uvm)
808 log.G(ctx).Tracef("create_lcow::CreateLCOW makeLCOWDoc result doc: %v err %v", doc, err)
809 }
810 if err != nil {
811 return nil, err
812 }
813
814 if err = uvm.create(ctx, doc); err != nil {
815 return nil, fmt.Errorf("error while creating the compute system: %w", err)
816 }
817 log.G(ctx).WithField("uvm", uvm).Trace("create_lcow::CreateLCOW uvm.create result")
818
819
820 uvm.entropyListener, err = uvm.listenVsock(entropyVsockPort)
821 if err != nil {
822 return nil, err
823 }
824
825
826
827 if opts.ForwardStdout || opts.ForwardStderr {
828 uvm.outputHandler = opts.OutputHandler
829 uvm.outputProcessingDone = make(chan struct{})
830 uvm.outputListener, err = uvm.listenVsock(linuxLogVsockPort)
831 if err != nil {
832 return nil, err
833 }
834 }
835
836 if opts.UseGuestConnection {
837 log.G(ctx).WithField("vmID", uvm.runtimeID).Debug("Using external GCS bridge")
838 l, err := uvm.listenVsock(gcs.LinuxGcsVsockPort)
839 if err != nil {
840 return nil, err
841 }
842 uvm.gcListener = l
843 }
844
845 uvm.ncProxyClientAddress = opts.NetworkConfigProxy
846
847 return uvm, nil
848 }
849
850 func (uvm *UtilityVM) listenVsock(port uint32) (net.Listener, error) {
851 return winio.ListenHvsock(&winio.HvsockAddr{
852 VMID: uvm.runtimeID,
853 ServiceID: winio.VsockServiceID(port),
854 })
855 }
856
View as plain text