Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions internal/oci/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,19 @@ func ParseAnnotationCommaSeparated(key string, a map[string]string) []string {
return results
}

// ParseAnnotationsGUID searches `a` for `key`. If `key` is found, tries to parse it as guid.GUID, otherwise
// returns `def`.
func ParseAnnotationsGUID(a map[string]string, key string, def *guid.GUID) (*guid.GUID, error) {
Comment thread
anmaxvl marked this conversation as resolved.
if v, ok := a[key]; ok {
g, err := guid.FromString(v)
if err != nil {
return nil, fmt.Errorf("failed to parse annotation %q with value %q as GUID: %w", key, v, err)
}
return &g, nil
}
return def, nil
}

func logAnnotationValueParseError(ctx context.Context, k, v, et string, err error) {
entry := log.G(ctx).WithFields(logrus.Fields{
logfields.OCIAnnotation: k,
Expand Down
18 changes: 15 additions & 3 deletions internal/oci/uvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ func parseDevices(ctx context.Context, specWindows *specs.Windows) []uvm.VPCIDev
}

// sets options common to both WCOW and LCOW from annotations.
func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *specs.Spec) {
func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *specs.Spec) error {
opts.MemorySizeInMB = ParseAnnotationsMemory(ctx, s, annotations.MemorySizeInMB, opts.MemorySizeInMB)
opts.LowMMIOGapInMB = ParseAnnotationsUint64(ctx, s.Annotations, annotations.MemoryLowMMIOGapInMB, opts.LowMMIOGapInMB)
opts.HighMMIOBaseInMB = ParseAnnotationsUint64(ctx, s.Annotations, annotations.MemoryHighMMIOBaseInMB, opts.HighMMIOBaseInMB)
Expand Down Expand Up @@ -282,6 +282,14 @@ func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *spe
opts.NumaMemoryBlocksCounts)

maps.Copy(opts.AdditionalHyperVConfig, parseHVSocketServiceTable(ctx, s.Annotations))

// parse error yielding annotations
var err error
opts.ResourcePartitionID, err = ParseAnnotationsGUID(s.Annotations, annotations.ResourcePartitionID, opts.ResourcePartitionID)
if err != nil {
return err
}
return nil
}

// SpecToUVMCreateOpts parses `s` and returns either `*uvm.OptionsLCOW` or
Expand All @@ -292,7 +300,9 @@ func SpecToUVMCreateOpts(ctx context.Context, s *specs.Spec, id, owner string) (
}
if IsLCOW(s) {
lopts := uvm.NewDefaultOptionsLCOW(id, owner)
specToUVMCreateOptionsCommon(ctx, lopts.Options, s)
if err := specToUVMCreateOptionsCommon(ctx, lopts.Options, s); err != nil {
return nil, err
}

/*
WARNING!!!!!!!!!!
Expand Down Expand Up @@ -339,7 +349,9 @@ func SpecToUVMCreateOpts(ctx context.Context, s *specs.Spec, id, owner string) (
return lopts, nil
} else if IsWCOW(s) {
wopts := uvm.NewDefaultOptionsWCOW(id, owner)
specToUVMCreateOptionsCommon(ctx, wopts.Options, s)
if err := specToUVMCreateOptionsCommon(ctx, wopts.Options, s); err != nil {
return nil, err
}

wopts.DisableCompartmentNamespace = ParseAnnotationsBool(ctx, s.Annotations, annotations.DisableCompartmentNamespace, wopts.DisableCompartmentNamespace)
wopts.NoDirectMap = ParseAnnotationsBool(ctx, s.Annotations, annotations.VSMBNoDirectMap, wopts.NoDirectMap)
Expand Down
13 changes: 13 additions & 0 deletions internal/tools/uvmboot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"sync"
"time"

"github.com/Microsoft/go-winio/pkg/guid"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"

Expand All @@ -24,6 +25,7 @@ const (
measureArgName = "measure"
parallelArgName = "parallel"
countArgName = "count"
resourcePartitionArgName = "resource-partition"

execCommandLineArgName = "exec"
uvmConsolePipe = "\\\\.\\pipe\\uvmpipe"
Expand Down Expand Up @@ -82,6 +84,10 @@ func main() {
Usage: "Launch the GCS and perform requested operations via its RPC interface",
Destination: &useGCS,
},
cli.StringFlag{
Name: resourcePartitionArgName,
Usage: "Resource partition GUID to assign UVM to",
},
}

app.Commands = []cli.Command{
Expand Down Expand Up @@ -125,6 +131,13 @@ func setGlobalOptions(c *cli.Context, options *uvm.Options) {
if c.GlobalIsSet(enableDeferredCommitArgName) {
options.EnableDeferredCommit = c.GlobalBool(enableDeferredCommitArgName)
}
if c.GlobalIsSet(resourcePartitionArgName) {
rpID, err := guid.FromString(c.GlobalString(resourcePartitionArgName))
if err != nil {
logrus.Fatalf("Failed to parse resource partition GUID: %v", err)
}
options.ResourcePartitionID = &rpID
}
// Always set the console pipe in uvmboot, it helps with testing/debugging
options.ConsolePipe = uvmConsolePipe
}
Expand Down
14 changes: 14 additions & 0 deletions internal/uvm/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ type Options struct {
// CPUGroupID set the ID of a CPUGroup on the host that the UVM should be added to on start.
// Defaults to an empty string which indicates the UVM should not be added to any CPUGroup.
CPUGroupID string

// ResourcePartitionID holds the resource partition guid.GUID the UVM should be assigned to.
ResourcePartitionID *guid.GUID

// NetworkConfigProxy holds the address of the network config proxy service.
// This != "" determines whether to start the ComputeAgent TTRPC service
// that receives the UVMs set of NICs from this proxy instead of enumerating
Expand Down Expand Up @@ -171,6 +175,11 @@ func verifyOptions(_ context.Context, options interface{}) error {
if opts.EnableColdDiscardHint && osversion.Build() < 18967 {
return errors.New("EnableColdDiscardHint is not supported on builds older than 18967")
}
if opts.ResourcePartitionID != nil {
if opts.CPUGroupID != "" {
return errors.New("resource partition ID and CPU group ID cannot be set at the same time")
}
}
case *OptionsWCOW:
if opts.EnableDeferredCommit && !opts.AllowOvercommit {
return errors.New("EnableDeferredCommit is not supported on physically backed VMs")
Expand All @@ -184,6 +193,11 @@ func verifyOptions(_ context.Context, options interface{}) error {
if opts.SecurityPolicyEnabled && opts.GuestStateFilePath == "" {
return fmt.Errorf("GuestStateFilePath must be provided when enabling security policy")
}
if opts.ResourcePartitionID != nil {
if opts.CPUGroupID != "" {
return errors.New("resource partition ID and CPU group ID cannot be set at the same time")
}
}
}
return nil
}
Expand Down
5 changes: 5 additions & 0 deletions internal/uvm/create_lcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,11 @@ func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcs
doc.VirtualMachine.ComputeTopology.Memory.SlitType = &firmwareFallbackMeasured
}

if opts.ResourcePartitionID != nil {
// TODO (maksiman): assign pod to resource partition and potentially do an OS version check before that
log.G(ctx).WithField("resource-partition-id", opts.ResourcePartitionID.String()).Debug("setting resource partition ID")
}

// Add optional devices that were specified on the UVM spec
if len(opts.AssignedDevices) > 0 {
if doc.VirtualMachine.Devices.VirtualPci == nil {
Expand Down
5 changes: 5 additions & 0 deletions internal/uvm/create_wcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ func prepareCommonConfigDoc(ctx context.Context, uvm *UtilityVM, opts *OptionsWC
doc.VirtualMachine.ComputeTopology.Memory.SlitType = &firmwareFallbackMeasured
}

if opts.ResourcePartitionID != nil {
// TODO (maksiman): assign pod to resource partition and potentially do an OS version check before that
log.G(ctx).WithField("resource-partition-id", opts.ResourcePartitionID.String()).Debug("setting resource partition ID")
}

maps.Copy(doc.VirtualMachine.Devices.HvSocket.HvSocketConfig.ServiceTable, opts.AdditionalHyperVConfig)

// Handle StorageQoS if set
Expand Down
6 changes: 6 additions & 0 deletions pkg/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ const (
// uVM CPU annotations.
const (
// CPUGroupID specifies the cpugroup ID that a UVM should be assigned to, if any.
// Passing this annotation together with ResourcePartitionID will result in an error.
CPUGroupID = "io.microsoft.virtualmachine.cpugroup.id"

// ProcessorCount overrides the hypervisor isolated vCPU count set
Expand Down Expand Up @@ -312,6 +313,11 @@ const (
// number of memory blocks at slice index 1, etc.
// This should be used for explicit vNUMA topology.
NumaCountOfMemoryBlocks = "io.microsoft.virtualmachine.computetopology.numa.count-of-memory-blocks"

// ResourcePartitionID is a GUID string representing a resource partition ID the UVM should be associated with.
// Resource partition will have its own CPU group, as a result this annotation cannot be used together with
// CPUGroupID and will yield an error.
ResourcePartitionID = "io.microsoft.virtualmachine.resource-partition-id"
)

// uVM storage (Quality of Service) annotations.
Expand Down