Skip to content

Commit 57c92f8

Browse files
authored
Merge pull request #164 from marquiz/devel/intel-rdt
Add IntelRdt to CDI spec
2 parents 7b12d28 + 1537b1d commit 57c92f8

File tree

9 files changed

+239
-6
lines changed

9 files changed

+239
-6
lines changed

.codespellrc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
[codespell]
22
skip = .git,*.pdf,*.svg,*.sum,*.mod
3-
#
4-
# ignore-words-list =
3+
ignore-words-list = clos

SPEC.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
## Version
1010

11-
This is CDI **spec** version **0.6.0**.
11+
This is CDI **spec** version **0.7.0**.
1212

1313
### Update policy
1414

@@ -27,7 +27,8 @@ Released versions of the spec are available as Git tags.
2727
| v0.4.0 | | Added `type` field to Mount specification |
2828
| v0.5.0 | | Add `HostPath` to `DeviceNodes` |
2929
| v0.6.0 | | Add `Annotations` field to `Spec` and `Device` specifications |
30-
| | | Allow dots (`.`) in name segment of `Kind` field |
30+
| | | Allow dots (`.`) in name segment of `Kind` field. |
31+
| v0.7.0 | | Add `IntelRdt`field. |
3132

3233
*Note*: The initial release of a **spec** with version `v0.x.0` will be tagged as
3334
`v0.x.0` with subsequent changes to the API applicable to this version tagged as `v0.x.y`.
@@ -82,7 +83,7 @@ The keywords "must", "must not", "required", "shall", "shall not", "should", "sh
8283

8384
```
8485
{
85-
"cdiVersion": "0.6.0",
86+
"cdiVersion": "0.7.0",
8687
"kind": "<name>",
8788
8889
// This field contains a set of key-value pairs that may be used to provide
@@ -150,6 +151,13 @@ The keywords "must", "must not", "required", "shall", "shall not", "should", "sh
150151
"timeout": <int> (optional)
151152
}
152153
]
154+
"intelRdt": { (optional)
155+
"closID": "<name>", (optional)
156+
"l3CacheSchema": "string" (optional)
157+
"memBwSchema": "string" (optional)
158+
"enableCMT": "<boolean>" (optional)
159+
"enableMBM": "<boolean>" (optional)
160+
}
153161
}
154162
]
155163
}
@@ -220,6 +228,12 @@ The `containerEdits` field has the following definition:
220228
* `args` (array of strings, OPTIONAL) with the same semantics as IEEE Std 1003.1-2008 execv's argv.
221229
* `env` (array of strings, OPTIONAL) with the same semantics as IEEE Std 1003.1-2008's environ.
222230
* `timeout` (int, OPTIONAL) is the number of seconds before aborting the hook. If set, timeout MUST be greater than zero. If not set container runtime will wait for the hook to return.
231+
* `intelRdt` (object, OPTIONAL) describes the Linux [resctrl][resctrl] settings for the container (object, OPTIONAL)
232+
* `closID` (string, OPTIONAL) name of the `CLOS` (Class of Service).
233+
* `l3CacheSchema` (string, OPTIONAL) L3 cache allocation schema for the `CLOS`.
234+
* `memBwSchema` (string, OPTIONAL) memory bandwidth allocation schema for the `CLOS`.
235+
* `enableCMT` (boolean, OPTIONAL) whether to enable cache monitoring
236+
* `enableMBM` (boolean, OPTIONAL) whether to enable memory bandwidth monitoring
223237

224238
## Error Handling
225239
* Kind requested is not present in any CDI file.
@@ -231,3 +245,5 @@ The `containerEdits` field has the following definition:
231245
This is because a resource does not need to exist when the spec is written, but it needs to exist when the container is created.
232246
* Hook fails to execute.
233247
Container runtimes should surface an error when hooks fails to execute.
248+
249+
[resctrl]: https://docs.kernel.org/arch/x86/resctrl.html

pkg/cdi/container-edits.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
144144
}
145145
}
146146

147+
if e.IntelRdt != nil {
148+
// The specgen is missing functionality to set all parameters so we
149+
// just piggy-back on it to initialize all structs and the copy over.
150+
specgen.SetLinuxIntelRdtClosID(e.IntelRdt.ClosID)
151+
spec.Linux.IntelRdt = e.IntelRdt.ToOCI()
152+
}
153+
147154
return nil
148155
}
149156

@@ -171,6 +178,11 @@ func (e *ContainerEdits) Validate() error {
171178
return err
172179
}
173180
}
181+
if e.IntelRdt != nil {
182+
if err := ValidateIntelRdt(e.IntelRdt); err != nil {
183+
return err
184+
}
185+
}
174186

175187
return nil
176188
}
@@ -192,6 +204,9 @@ func (e *ContainerEdits) Append(o *ContainerEdits) *ContainerEdits {
192204
e.DeviceNodes = append(e.DeviceNodes, o.DeviceNodes...)
193205
e.Hooks = append(e.Hooks, o.Hooks...)
194206
e.Mounts = append(e.Mounts, o.Mounts...)
207+
if o.IntelRdt != nil {
208+
e.IntelRdt = o.IntelRdt
209+
}
195210

196211
return e
197212
}
@@ -202,7 +217,7 @@ func (e *ContainerEdits) isEmpty() bool {
202217
if e == nil {
203218
return false
204219
}
205-
return len(e.Env)+len(e.DeviceNodes)+len(e.Hooks)+len(e.Mounts) == 0
220+
return len(e.Env)+len(e.DeviceNodes)+len(e.Hooks)+len(e.Mounts) == 0 && e.IntelRdt == nil
206221
}
207222

208223
// ValidateEnv validates the given environment variables.
@@ -280,6 +295,15 @@ func (m *Mount) Validate() error {
280295
return nil
281296
}
282297

298+
// ValidateIntelRdt validates the IntelRdt configuration.
299+
func ValidateIntelRdt(i *specs.IntelRdt) error {
300+
// ClosID must be a valid Linux filename
301+
if len(i.ClosID) >= 4096 || i.ClosID == "." || i.ClosID == ".." || strings.ContainsAny(i.ClosID, "/\n") {
302+
return errors.New("invalid ClosID")
303+
}
304+
return nil
305+
}
306+
283307
// Ensure OCI Spec hooks are not nil so we can add hooks.
284308
func ensureOCIHooks(spec *oci.Spec) {
285309
if spec.Hooks == nil {

pkg/cdi/container-edits_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,50 @@ func TestValidateContainerEdits(t *testing.T) {
245245
},
246246
invalid: true,
247247
},
248+
{
249+
name: "valid rdt config",
250+
edits: &cdi.ContainerEdits{
251+
IntelRdt: &cdi.IntelRdt{
252+
ClosID: "foo.bar",
253+
},
254+
},
255+
},
256+
{
257+
name: "invalid rdt config, invalid closID (slash)",
258+
edits: &cdi.ContainerEdits{
259+
IntelRdt: &cdi.IntelRdt{
260+
ClosID: "foo/bar",
261+
},
262+
},
263+
invalid: true,
264+
},
265+
{
266+
name: "invalid rdt config, invalid closID (dot)",
267+
edits: &cdi.ContainerEdits{
268+
IntelRdt: &cdi.IntelRdt{
269+
ClosID: ".",
270+
},
271+
},
272+
invalid: true,
273+
},
274+
{
275+
name: "invalid rdt config, invalid closID (double dot)",
276+
edits: &cdi.ContainerEdits{
277+
IntelRdt: &cdi.IntelRdt{
278+
ClosID: "..",
279+
},
280+
},
281+
invalid: true,
282+
},
283+
{
284+
name: "invalid rdt config, invalid closID (newline)",
285+
edits: &cdi.ContainerEdits{
286+
IntelRdt: &cdi.IntelRdt{
287+
ClosID: "foo\nbar",
288+
},
289+
},
290+
invalid: true,
291+
},
248292
} {
249293
t.Run(tc.name, func(t *testing.T) {
250294
edits := ContainerEdits{tc.edits}
@@ -467,6 +511,58 @@ func TestApplyContainerEdits(t *testing.T) {
467511
},
468512
},
469513
},
514+
{
515+
name: "empty spec, rdt",
516+
spec: &oci.Spec{},
517+
edits: &cdi.ContainerEdits{
518+
IntelRdt: &cdi.IntelRdt{
519+
ClosID: "clos-1",
520+
L3CacheSchema: "L3:0=ff;1=ff",
521+
MemBwSchema: "MB:0=50;1=50",
522+
EnableCMT: true,
523+
EnableMBM: true,
524+
},
525+
},
526+
result: &oci.Spec{
527+
Linux: &oci.Linux{
528+
IntelRdt: &oci.LinuxIntelRdt{
529+
ClosID: "clos-1",
530+
L3CacheSchema: "L3:0=ff;1=ff",
531+
MemBwSchema: "MB:0=50;1=50",
532+
EnableCMT: true,
533+
EnableMBM: true,
534+
},
535+
},
536+
},
537+
},
538+
{
539+
name: "non-empty spec, overriding rdt",
540+
spec: &oci.Spec{
541+
Linux: &oci.Linux{
542+
IntelRdt: &oci.LinuxIntelRdt{
543+
ClosID: "clos-1",
544+
L3CacheSchema: "L3:0=ff",
545+
MemBwSchema: "MB:0=100",
546+
EnableCMT: true,
547+
EnableMBM: true,
548+
},
549+
},
550+
},
551+
edits: &cdi.ContainerEdits{
552+
IntelRdt: &cdi.IntelRdt{
553+
ClosID: "clos-2",
554+
L3CacheSchema: "L3:0=f",
555+
},
556+
},
557+
result: &oci.Spec{
558+
Linux: &oci.Linux{
559+
IntelRdt: &oci.LinuxIntelRdt{
560+
ClosID: "clos-2",
561+
L3CacheSchema: "L3:0=f",
562+
},
563+
},
564+
},
565+
},
470566
} {
471567
t.Run(tc.name, func(t *testing.T) {
472568
edits := ContainerEdits{tc.edits}
@@ -555,6 +651,10 @@ func TestAppend(t *testing.T) {
555651
Path: "/dev/dev1",
556652
},
557653
},
654+
IntelRdt: &cdi.IntelRdt{
655+
ClosID: "clos-1",
656+
L3CacheSchema: "L3:0=ff",
657+
},
558658
},
559659
},
560660
{
@@ -583,6 +683,9 @@ func TestAppend(t *testing.T) {
583683
Path: "/dev/dev4",
584684
},
585685
},
686+
IntelRdt: &cdi.IntelRdt{
687+
ClosID: "clos-2",
688+
},
586689
},
587690
},
588691
},
@@ -609,6 +712,9 @@ func TestAppend(t *testing.T) {
609712
Path: "/dev/dev4",
610713
},
611714
},
715+
IntelRdt: &cdi.IntelRdt{
716+
ClosID: "clos-2",
717+
},
612718
},
613719
},
614720
},

pkg/cdi/spec_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,33 @@ func TestRequiredVersion(t *testing.T) {
669669
},
670670
expectedVersion: "0.6.0",
671671
},
672+
{
673+
description: "IntelRdt requires v0.7.0",
674+
spec: &cdi.Spec{
675+
ContainerEdits: cdi.ContainerEdits{
676+
IntelRdt: &cdi.IntelRdt{
677+
ClosID: "foo",
678+
},
679+
},
680+
},
681+
expectedVersion: "0.7.0",
682+
},
683+
{
684+
description: "IntelRdt (on devices) requires v0.7.0",
685+
spec: &cdi.Spec{
686+
Devices: []cdi.Device{
687+
{
688+
Name: "device0",
689+
ContainerEdits: cdi.ContainerEdits{
690+
IntelRdt: &cdi.IntelRdt{
691+
ClosID: "foo",
692+
},
693+
},
694+
},
695+
},
696+
},
697+
expectedVersion: "0.7.0",
698+
},
672699
}
673700

674701
for _, tc := range testCases {

pkg/cdi/version.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const (
3939
v040 version = "v0.4.0"
4040
v050 version = "v0.5.0"
4141
v060 version = "v0.6.0"
42+
v070 version = "v0.7.0"
4243

4344
// vEarliest is the earliest supported version of the CDI specification
4445
vEarliest version = v030
@@ -54,6 +55,7 @@ var validSpecVersions = requiredVersionMap{
5455
v040: requiresV040,
5556
v050: requiresV050,
5657
v060: requiresV060,
58+
v070: requiresV070,
5759
}
5860

5961
// MinimumRequiredVersion determines the minimum spec version for the input spec.
@@ -118,6 +120,21 @@ func (r requiredVersionMap) requiredVersion(spec *cdi.Spec) version {
118120
return minVersion
119121
}
120122

123+
// requiresV070 returns true if the spec uses v0.7.0 features
124+
func requiresV070(spec *cdi.Spec) bool {
125+
if spec.ContainerEdits.IntelRdt != nil {
126+
return true
127+
}
128+
129+
for _, d := range spec.Devices {
130+
if d.ContainerEdits.IntelRdt != nil {
131+
return true
132+
}
133+
}
134+
135+
return false
136+
}
137+
121138
// requiresV060 returns true if the spec uses v0.6.0 features
122139
func requiresV060(spec *cdi.Spec) bool {
123140
// The v0.6.0 spec allows annotations to be specified at a spec level

schema/defs.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
"type": "string"
1818
}
1919
},
20+
"FileName": {
21+
"type": "string"
22+
},
2023
"FilePath": {
2124
"type": "string"
2225
},
@@ -134,6 +137,26 @@
134137
"items": {
135138
"$ref": "#/definitions/Hook"
136139
}
140+
},
141+
"intelRdt": {
142+
"type": "object",
143+
"properties": {
144+
"closID": {
145+
"$ref": "#/definitions/FileName"
146+
},
147+
"l3CacheSchema": {
148+
"type": "string"
149+
},
150+
"memBwSchema": {
151+
"type": "string"
152+
},
153+
"enableCMT": {
154+
"type": "boolean"
155+
},
156+
"enableMBM": {
157+
"type": "boolean"
158+
}
159+
}
137160
}
138161
}
139162
},

specs-go/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type ContainerEdits struct {
2929
DeviceNodes []*DeviceNode `json:"deviceNodes,omitempty"`
3030
Hooks []*Hook `json:"hooks,omitempty"`
3131
Mounts []*Mount `json:"mounts,omitempty"`
32+
IntelRdt *IntelRdt `json:"intelRdt,omitempty"`
3233
}
3334

3435
// DeviceNode represents a device node that needs to be added to the OCI spec.
@@ -60,3 +61,12 @@ type Hook struct {
6061
Env []string `json:"env,omitempty"`
6162
Timeout *int `json:"timeout,omitempty"`
6263
}
64+
65+
// IntelRdt describes the Linux IntelRdt parameters to set in the OCI spec.
66+
type IntelRdt struct {
67+
ClosID string `json:"closID,omitempty"`
68+
L3CacheSchema string `json:"l3CacheSchema,omitempty"`
69+
MemBwSchema string `json:"memBwSchema,omitempty"`
70+
EnableCMT bool `json:"enableCMT,omitempty"`
71+
EnableMBM bool `json:"enableMBM,omitempty"`
72+
}

0 commit comments

Comments
 (0)