Skip to content

Commit 62ec6dc

Browse files
authored
Merge pull request opencontainers#2920 from marquiz/devel/rdt
libcontainer/intelrdt: support ClosID parameter
2 parents 11d141b + 9393700 commit 62ec6dc

File tree

7 files changed

+93
-70
lines changed

7 files changed

+93
-70
lines changed

libcontainer/configs/intelrdt.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package configs
22

33
type IntelRdt struct {
4+
// The identity for RDT Class of Service
5+
ClosID string `json:"closID,omitempty"`
6+
47
// The schema for L3 cache id and capacity bitmask (CBM)
58
// Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
69
L3CacheSchema string `json:"l3_cache_schema,omitempty"`

libcontainer/configs/validate/validator.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -205,19 +205,16 @@ func (v *ConfigValidator) intelrdt(config *configs.Config) error {
205205
return errors.New("intelRdt is specified in config, but Intel RDT is not supported or enabled")
206206
}
207207

208+
if config.IntelRdt.ClosID == "." || config.IntelRdt.ClosID == ".." || strings.Contains(config.IntelRdt.ClosID, "/") {
209+
return fmt.Errorf("invalid intelRdt.ClosID %q", config.IntelRdt.ClosID)
210+
}
211+
208212
if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" {
209213
return errors.New("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled")
210214
}
211215
if !intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema != "" {
212216
return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled")
213217
}
214-
215-
if intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema == "" {
216-
return errors.New("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
217-
}
218-
if intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema == "" {
219-
return errors.New("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty")
220-
}
221218
}
222219

223220
return nil

libcontainer/container_linux.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,9 +1902,10 @@ func (c *linuxContainer) currentState() (*State, error) {
19021902
startTime, _ = c.initProcess.startTime()
19031903
externalDescriptors = c.initProcess.externalDescriptors()
19041904
}
1905-
intelRdtPath, err := intelrdt.GetIntelRdtPath(c.ID())
1906-
if err != nil {
1907-
intelRdtPath = ""
1905+
1906+
intelRdtPath := ""
1907+
if c.intelRdtManager != nil {
1908+
intelRdtPath = c.intelRdtManager.GetPath()
19081909
}
19091910
state := &State{
19101911
BaseState: BaseState{

libcontainer/intelrdt/intelrdt.go

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ import (
7272
* |-- ...
7373
* |-- schemata
7474
* |-- tasks
75-
* |-- <container_id>
75+
* |-- <clos>
7676
* |-- ...
7777
* |-- schemata
7878
* |-- tasks
@@ -155,7 +155,7 @@ type Manager interface {
155155
// Returns statistics for Intel RDT
156156
GetStats() (*Stats, error)
157157

158-
// Destroys the Intel RDT 'container_id' group
158+
// Destroys the Intel RDT container-specific 'container_id' group
159159
Destroy() error
160160

161161
// Returns Intel RDT path to save in a state file and to be able to
@@ -205,9 +205,7 @@ var (
205205
)
206206

207207
type intelRdtData struct {
208-
root string
209208
config *configs.Config
210-
pid int
211209
}
212210

213211
// Check if Intel RDT sub-features are enabled in featuresInit()
@@ -405,18 +403,6 @@ func writeFile(dir, file, data string) error {
405403
return nil
406404
}
407405

408-
func getIntelRdtData(c *configs.Config, pid int) (*intelRdtData, error) {
409-
rootPath, err := getIntelRdtRoot()
410-
if err != nil {
411-
return nil, err
412-
}
413-
return &intelRdtData{
414-
root: rootPath,
415-
config: c,
416-
pid: pid,
417-
}, nil
418-
}
419-
420406
// Get the read-only L3 cache information
421407
func getL3CacheInfo() (*L3CacheInfo, error) {
422408
l3CacheInfo := &L3CacheInfo{}
@@ -531,15 +517,19 @@ func IsMBAScEnabled() bool {
531517
return mbaScEnabled
532518
}
533519

534-
// Get the 'container_id' path in Intel RDT "resource control" filesystem
535-
func GetIntelRdtPath(id string) (string, error) {
520+
// Get the path of the clos group in "resource control" filesystem that the container belongs to
521+
func (m *intelRdtManager) getIntelRdtPath() (string, error) {
536522
rootPath, err := getIntelRdtRoot()
537523
if err != nil {
538524
return "", err
539525
}
540526

541-
path := filepath.Join(rootPath, id)
542-
return path, nil
527+
clos := m.id
528+
if m.config.IntelRdt != nil && m.config.IntelRdt.ClosID != "" {
529+
clos = m.config.IntelRdt.ClosID
530+
}
531+
532+
return filepath.Join(rootPath, clos), nil
543533
}
544534

545535
// Applies Intel RDT configuration to the process with the specified pid
@@ -548,38 +538,56 @@ func (m *intelRdtManager) Apply(pid int) (err error) {
548538
if m.config.IntelRdt == nil {
549539
return nil
550540
}
551-
d, err := getIntelRdtData(m.config, pid)
541+
542+
path, err := m.getIntelRdtPath()
552543
if err != nil {
553544
return err
554545
}
555546

556547
m.mu.Lock()
557548
defer m.mu.Unlock()
558-
path, err := d.join(m.id)
559-
if err != nil {
560-
return err
549+
550+
if m.config.IntelRdt.ClosID != "" && m.config.IntelRdt.L3CacheSchema == "" && m.config.IntelRdt.MemBwSchema == "" {
551+
// Check that the CLOS exists, i.e. it has been pre-configured to
552+
// conform with the runtime spec
553+
if _, err := os.Stat(path); err != nil {
554+
return fmt.Errorf("clos dir not accessible (must be pre-created when l3CacheSchema and memBwSchema are empty): %w", err)
555+
}
556+
}
557+
558+
if err := os.MkdirAll(path, 0o755); err != nil {
559+
return newLastCmdError(err)
560+
}
561+
562+
if err := WriteIntelRdtTasks(path, pid); err != nil {
563+
return newLastCmdError(err)
561564
}
562565

563566
m.path = path
564567
return nil
565568
}
566569

567-
// Destroys the Intel RDT 'container_id' group
570+
// Destroys the Intel RDT container-specific 'container_id' group
568571
func (m *intelRdtManager) Destroy() error {
569-
m.mu.Lock()
570-
defer m.mu.Unlock()
571-
if err := os.RemoveAll(m.GetPath()); err != nil {
572-
return err
572+
// Don't remove resctrl group if closid has been explicitly specified. The
573+
// group is likely externally managed, i.e. by some other entity than us.
574+
// There are probably other containers/tasks sharing the same group.
575+
if m.config.IntelRdt == nil || m.config.IntelRdt.ClosID == "" {
576+
m.mu.Lock()
577+
defer m.mu.Unlock()
578+
if err := os.RemoveAll(m.GetPath()); err != nil {
579+
return err
580+
}
581+
m.path = ""
573582
}
574-
m.path = ""
575583
return nil
576584
}
577585

578586
// Returns Intel RDT path to save in a state file and to be able to
579587
// restore the object later
580588
func (m *intelRdtManager) GetPath() string {
581589
if m.path == "" {
582-
m.path, _ = GetIntelRdtPath(m.id)
590+
m.path, _ = m.getIntelRdtPath()
583591
}
584592
return m.path
585593
}
@@ -606,7 +614,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
606614
}
607615
schemaRootStrings := strings.Split(tmpRootStrings, "\n")
608616

609-
// The L3 cache and memory bandwidth schemata in 'container_id' group
617+
// The L3 cache and memory bandwidth schemata in container's clos group
610618
containerPath := m.GetPath()
611619
tmpStrings, err := getIntelRdtParamString(containerPath, "schemata")
612620
if err != nil {
@@ -629,7 +637,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
629637
}
630638
}
631639

632-
// The L3 cache schema in 'container_id' group
640+
// The L3 cache schema in container's clos group
633641
for _, schema := range schemaStrings {
634642
if strings.Contains(schema, "L3") {
635643
stats.L3CacheSchema = strings.TrimSpace(schema)
@@ -652,7 +660,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
652660
}
653661
}
654662

655-
// The memory bandwidth schema in 'container_id' group
663+
// The memory bandwidth schema in container's clos group
656664
for _, schema := range schemaStrings {
657665
if strings.Contains(schema, "MB") {
658666
stats.MemBwSchema = strings.TrimSpace(schema)
@@ -722,6 +730,12 @@ func (m *intelRdtManager) Set(container *configs.Config) error {
722730
l3CacheSchema := container.IntelRdt.L3CacheSchema
723731
memBwSchema := container.IntelRdt.MemBwSchema
724732

733+
// TODO: verify that l3CacheSchema and/or memBwSchema match the
734+
// existing schemata if ClosID has been specified. This is a more
735+
// involved than reading the file and doing plain string comparison as
736+
// the value written in does not necessarily match what gets read out
737+
// (leading zeros, cache id ordering etc).
738+
725739
// Write a single joint schema string to schemata file
726740
if l3CacheSchema != "" && memBwSchema != "" {
727741
if err := writeFile(path, "schemata", l3CacheSchema+"\n"+memBwSchema); err != nil {
@@ -747,18 +761,6 @@ func (m *intelRdtManager) Set(container *configs.Config) error {
747761
return nil
748762
}
749763

750-
func (raw *intelRdtData) join(id string) (string, error) {
751-
path := filepath.Join(raw.root, id)
752-
if err := os.MkdirAll(path, 0o755); err != nil {
753-
return "", newLastCmdError(err)
754-
}
755-
756-
if err := WriteIntelRdtTasks(path, raw.pid); err != nil {
757-
return "", err
758-
}
759-
return path, nil
760-
}
761-
762764
func newLastCmdError(err error) error {
763765
status, err1 := getLastCmdStatus()
764766
if err1 == nil {

libcontainer/intelrdt/intelrdt_test.go

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@ package intelrdt
55
import (
66
"errors"
77
"io"
8+
"os"
9+
"path/filepath"
810
"strings"
911
"testing"
1012
)
1113

1214
func TestIntelRdtSetL3CacheSchema(t *testing.T) {
13-
if !IsCATEnabled() {
14-
return
15-
}
16-
1715
helper := NewIntelRdtTestUtil(t)
1816

1917
const (
@@ -44,10 +42,6 @@ func TestIntelRdtSetL3CacheSchema(t *testing.T) {
4442
}
4543

4644
func TestIntelRdtSetMemBwSchema(t *testing.T) {
47-
if !IsMBAEnabled() {
48-
return
49-
}
50-
5145
helper := NewIntelRdtTestUtil(t)
5246

5347
const (
@@ -78,10 +72,6 @@ func TestIntelRdtSetMemBwSchema(t *testing.T) {
7872
}
7973

8074
func TestIntelRdtSetMemBwScSchema(t *testing.T) {
81-
if !IsMBAScEnabled() {
82-
return
83-
}
84-
8575
helper := NewIntelRdtTestUtil(t)
8676

8777
const (
@@ -111,6 +101,35 @@ func TestIntelRdtSetMemBwScSchema(t *testing.T) {
111101
}
112102
}
113103

104+
func TestApply(t *testing.T) {
105+
helper := NewIntelRdtTestUtil(t)
106+
107+
const closID = "test-clos"
108+
109+
helper.IntelRdtData.config.IntelRdt.ClosID = closID
110+
intelrdt := NewManager(helper.IntelRdtData.config, "", helper.IntelRdtPath)
111+
if err := intelrdt.Apply(1234); err == nil {
112+
t.Fatal("unexpected success when applying pid")
113+
}
114+
if _, err := os.Stat(filepath.Join(helper.IntelRdtPath, closID)); err == nil {
115+
t.Fatal("closid dir should not exist")
116+
}
117+
118+
// Dir should be created if some schema has been specified
119+
intelrdt.(*intelRdtManager).config.IntelRdt.L3CacheSchema = "L3:0=f"
120+
if err := intelrdt.Apply(1235); err != nil {
121+
t.Fatalf("Apply() failed: %v", err)
122+
}
123+
124+
pids, err := getIntelRdtParamString(intelrdt.GetPath(), "tasks")
125+
if err != nil {
126+
t.Fatalf("failed to read tasks file: %v", err)
127+
}
128+
if pids != "1235" {
129+
t.Fatalf("unexpected tasks file, expected '1235', got %q", pids)
130+
}
131+
}
132+
114133
const (
115134
mountinfoValid = `18 40 0:18 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw
116135
19 40 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw

libcontainer/intelrdt/util_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ func NewIntelRdtTestUtil(t *testing.T) *intelRdtTestUtil {
3030
config: &configs.Config{
3131
IntelRdt: &configs.IntelRdt{},
3232
},
33-
root: t.TempDir(),
3433
}
35-
testIntelRdtPath := filepath.Join(d.root, "resctrl")
34+
intelRdtRoot = t.TempDir()
35+
testIntelRdtPath := filepath.Join(intelRdtRoot, "resctrl")
3636

3737
// Ensure the full mock Intel RDT "resource control" filesystem path exists
3838
if err := os.MkdirAll(testIntelRdtPath, 0o755); err != nil {

libcontainer/specconv/spec_linux.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
301301
}
302302
if spec.Linux.IntelRdt != nil {
303303
config.IntelRdt = &configs.IntelRdt{
304+
ClosID: spec.Linux.IntelRdt.ClosID,
304305
L3CacheSchema: spec.Linux.IntelRdt.L3CacheSchema,
305306
MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
306307
}

0 commit comments

Comments
 (0)