From b8a83ac255fab9129e895210490b8ee9d0f10413 Mon Sep 17 00:00:00 2001 From: Markus Lehtonen Date: Fri, 15 Aug 2025 15:06:48 +0300 Subject: [PATCH 1/3] libcontainer/intelrdt: support explicit assignment to root CLOS Makes it possible e.g. to enable monitoring (linux.intelRdt.enableMonitoring) without creating a CLOS (resctrl group) for the container. Implements https://github.com/opencontainers/runtime-spec/pull/1289. Signed-off-by: Markus Lehtonen --- libcontainer/configs/validate/validator.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libcontainer/configs/validate/validator.go b/libcontainer/configs/validate/validator.go index 9be17ba05..e9a33a218 100644 --- a/libcontainer/configs/validate/validator.go +++ b/libcontainer/configs/validate/validator.go @@ -287,8 +287,9 @@ func intelrdtCheck(config *configs.Config) error { return fmt.Errorf("intelRdt is specified in config, but Intel RDT is not enabled") } - if config.IntelRdt.ClosID == "." || config.IntelRdt.ClosID == ".." || strings.Contains(config.IntelRdt.ClosID, "/") { - return fmt.Errorf("invalid intelRdt.ClosID %q", config.IntelRdt.ClosID) + switch clos := config.IntelRdt.ClosID; { + case clos == ".", clos == "..", len(clos) > 1 && strings.Contains(clos, "/"): + return fmt.Errorf("invalid intelRdt.ClosID %q", clos) } if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" { From ba68a17ad1bc68a44450c686d6f01a89a3e69c75 Mon Sep 17 00:00:00 2001 From: Markus Lehtonen Date: Wed, 27 Aug 2025 15:23:17 +0300 Subject: [PATCH 2/3] libcontainer/configs: add validator unit tests for intelRdt Signed-off-by: Markus Lehtonen --- libcontainer/configs/validate/intelrdt.go | 41 ++++++ .../configs/validate/intelrdt_test.go | 122 ++++++++++++++++++ libcontainer/configs/validate/validator.go | 7 +- 3 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 libcontainer/configs/validate/intelrdt.go create mode 100644 libcontainer/configs/validate/intelrdt_test.go diff --git a/libcontainer/configs/validate/intelrdt.go b/libcontainer/configs/validate/intelrdt.go new file mode 100644 index 000000000..7b6015b82 --- /dev/null +++ b/libcontainer/configs/validate/intelrdt.go @@ -0,0 +1,41 @@ +package validate + +import ( + "sync" + + "github.com/opencontainers/runc/libcontainer/intelrdt" +) + +// Cache the result of intelrdt IsEnabled functions to avoid repeated sysfs +// access and enable mocking for unit tests. +type intelRdtStatus struct { + sync.Once + rdtEnabled bool + catEnabled bool + mbaEnabled bool +} + +var intelRdt = &intelRdtStatus{} + +func (i *intelRdtStatus) init() { + i.Do(func() { + i.rdtEnabled = intelrdt.IsEnabled() + i.catEnabled = intelrdt.IsCATEnabled() + i.mbaEnabled = intelrdt.IsMBAEnabled() + }) +} + +func (i *intelRdtStatus) isEnabled() bool { + i.init() + return i.rdtEnabled +} + +func (i *intelRdtStatus) isCATEnabled() bool { + i.init() + return i.catEnabled +} + +func (i *intelRdtStatus) isMBAEnabled() bool { + i.init() + return i.mbaEnabled +} diff --git a/libcontainer/configs/validate/intelrdt_test.go b/libcontainer/configs/validate/intelrdt_test.go new file mode 100644 index 000000000..d8672225f --- /dev/null +++ b/libcontainer/configs/validate/intelrdt_test.go @@ -0,0 +1,122 @@ +package validate + +import ( + "testing" + + "github.com/opencontainers/runc/libcontainer/configs" +) + +func TestValidateIntelRdt(t *testing.T) { + // Call init to trigger the sync.Once and enable overriding the rdt status + intelRdt.init() + + testCases := []struct { + name string + rdtEnabled bool + catEnabled bool + mbaEnabled bool + config *configs.IntelRdt + isErr bool + }{ + { + name: "rdt not supported, no config", + rdtEnabled: false, + config: nil, + isErr: false, + }, + { + name: "rdt not supported, with config", + rdtEnabled: false, + config: &configs.IntelRdt{}, + isErr: true, + }, + { + name: "empty config", + rdtEnabled: true, + config: &configs.IntelRdt{}, + isErr: false, + }, + { + name: "root clos", + rdtEnabled: true, + config: &configs.IntelRdt{ + ClosID: "/", + }, + isErr: false, + }, + { + name: "invalid ClosID (.)", + rdtEnabled: true, + config: &configs.IntelRdt{ + ClosID: ".", + }, + isErr: true, + }, + { + name: "invalid ClosID (..)", + rdtEnabled: true, + config: &configs.IntelRdt{ + ClosID: "..", + }, + isErr: true, + }, + { + name: "invalid ClosID (contains /)", + rdtEnabled: true, + config: &configs.IntelRdt{ + ClosID: "foo/bar", + }, + isErr: true, + }, + { + name: "cat not supported", + rdtEnabled: true, + catEnabled: false, + config: &configs.IntelRdt{ + L3CacheSchema: "0=ff", + }, + isErr: true, + }, + { + name: "mba not supported", + rdtEnabled: true, + mbaEnabled: false, + config: &configs.IntelRdt{ + MemBwSchema: "0=100", + }, + isErr: true, + }, + { + name: "valid config", + rdtEnabled: true, + catEnabled: true, + mbaEnabled: true, + config: &configs.IntelRdt{ + ClosID: "clos-1", + L3CacheSchema: "0=ff", + MemBwSchema: "0=100", + }, + isErr: false, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + intelRdt.rdtEnabled = tc.rdtEnabled + intelRdt.catEnabled = tc.catEnabled + intelRdt.mbaEnabled = tc.mbaEnabled + + config := &configs.Config{ + Rootfs: "/var", + IntelRdt: tc.config, + } + + err := Validate(config) + if tc.isErr && err == nil { + t.Error("expected error, got nil") + } + if !tc.isErr && err != nil { + t.Error(err) + } + }) + } +} diff --git a/libcontainer/configs/validate/validator.go b/libcontainer/configs/validate/validator.go index e9a33a218..1fe66e148 100644 --- a/libcontainer/configs/validate/validator.go +++ b/libcontainer/configs/validate/validator.go @@ -10,7 +10,6 @@ import ( "github.com/opencontainers/cgroups" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/opencontainers/runtime-spec/specs-go" selinux "github.com/opencontainers/selinux/go-selinux" "github.com/sirupsen/logrus" @@ -283,7 +282,7 @@ func sysctl(config *configs.Config) error { func intelrdtCheck(config *configs.Config) error { if config.IntelRdt != nil { - if !intelrdt.IsEnabled() { + if !intelRdt.isEnabled() { return fmt.Errorf("intelRdt is specified in config, but Intel RDT is not enabled") } @@ -292,10 +291,10 @@ func intelrdtCheck(config *configs.Config) error { return fmt.Errorf("invalid intelRdt.ClosID %q", clos) } - if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" { + if !intelRdt.isCATEnabled() && config.IntelRdt.L3CacheSchema != "" { return errors.New("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled") } - if !intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema != "" { + if !intelRdt.isMBAEnabled() && config.IntelRdt.MemBwSchema != "" { return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled") } } From 762819496e97a785136631bd8fc1272db8d27e96 Mon Sep 17 00:00:00 2001 From: Markus Lehtonen Date: Fri, 29 Aug 2025 12:34:51 +0300 Subject: [PATCH 3/3] libcontainer/configs/validate: add doc.go Add package comment to make revive pass muster. Signed-off-by: Markus Lehtonen --- libcontainer/configs/validate/doc.go | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 libcontainer/configs/validate/doc.go diff --git a/libcontainer/configs/validate/doc.go b/libcontainer/configs/validate/doc.go new file mode 100644 index 000000000..8819c8806 --- /dev/null +++ b/libcontainer/configs/validate/doc.go @@ -0,0 +1,2 @@ +// Package validate provides helpers for validating configuration. +package validate