Skip to content

Commit 026fdce

Browse files
committed
Add IntelRdt to CDI spec
Add support for specifying the OCI Linux.IntelRdt configuration that is the control point for cache and memory bandwidth allocation technologies sucn as Intel RDT (Resource Director Technology). There can only be one IntelRdt configuration per container so in case multiple specs happened to specify it the last one applied prevails. Also, the IntelRdt configuration is always applied as a whole - editing specific sub-fields is not supported. Signed-off-by: Markus Lehtonen <[email protected]>
1 parent 1f83d84 commit 026fdce

File tree

6 files changed

+133
-4
lines changed

6 files changed

+133
-4
lines changed

SPEC.md

Lines changed: 18 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,7 @@ 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. Add `IntelRdt`field. |
3131

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

8383
```
8484
{
85-
"cdiVersion": "0.6.0",
85+
"cdiVersion": "0.7.0",
8686
"kind": "<name>",
8787
8888
// This field contains a set of key-value pairs that may be used to provide
@@ -150,6 +150,13 @@ The keywords "must", "must not", "required", "shall", "shall not", "should", "sh
150150
"timeout": <int> (optional)
151151
}
152152
]
153+
"intelRdt": { (optional)
154+
"closID": "<name>", (optional)
155+
"l3CacheSchema": "string" (optional)
156+
"memBwSchema": "string" (optional)
157+
"enableCMT": "<boolean>" (optional)
158+
"enableMBM": "<boolean>" (optional)
159+
}
153160
}
154161
]
155162
}
@@ -220,6 +227,12 @@ The `containerEdits` field has the following definition:
220227
* `args` (array of strings, OPTIONAL) with the same semantics as IEEE Std 1003.1-2008 execv's argv.
221228
* `env` (array of strings, OPTIONAL) with the same semantics as IEEE Std 1003.1-2008's environ.
222229
* `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.
230+
* `intelRdt` (object, OPTIONAL) describes the Linux [resctrl][resctrl] settings for the container (object, OPTIONAL)
231+
* `closID` (string, OPTIONAL) name of the `CLOS` (Class of Service).
232+
* `l3CacheSchema` (string, OPTIONAL) L3 cache allocation schema for the `CLOS`.
233+
* `memBwSchema` (string, OPTIONAL) memory bandwidth allocation schema for the `CLOS`.
234+
* `enableCMT` (boolean, OPTIONAL) whether to enable cache monitoring
235+
* `enableMBM` (boolean, OPTIONAL) whether to enable memory bandwidth monitoring
223236

224237
## Error Handling
225238
* Kind requested is not present in any CDI file.
@@ -231,3 +244,5 @@ The `containerEdits` field has the following definition:
231244
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.
232245
* Hook fails to execute.
233246
Container runtimes should surface an error when hooks fails to execute.
247+
248+
[resctrl]: https://docs.kernel.org/arch/x86/resctrl.html

pkg/cdi/container-edits.go

Lines changed: 30 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,20 @@ func (m *Mount) Validate() error {
280295
return nil
281296
}
282297

298+
// IntelRdt a wrapper used for validating IntelRdt configuration.
299+
type IntelRdt struct {
300+
*specs.IntelRdt
301+
}
302+
303+
// ValidateIntelRdt validates the IntelRdt configuration.
304+
func ValidateIntelRdt(i *specs.IntelRdt) error {
305+
// ClosID must be a valid Linux filename
306+
if len(i.ClosID) >= 4096 || i.ClosID == "." || i.ClosID == ".." || strings.ContainsAny(i.ClosID, "/\n") {
307+
return errors.New("invalid ClosID")
308+
}
309+
return nil
310+
}
311+
283312
// Ensure OCI Spec hooks are not nil so we can add hooks.
284313
func ensureOCIHooks(spec *oci.Spec) {
285314
if spec.Hooks == nil {

pkg/cdi/container-edits_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,23 @@ 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",
258+
edits: &cdi.ContainerEdits{
259+
IntelRdt: &cdi.IntelRdt{
260+
ClosID: "foo/bar",
261+
},
262+
},
263+
invalid: true,
264+
},
248265
} {
249266
t.Run(tc.name, func(t *testing.T) {
250267
edits := ContainerEdits{tc.edits}
@@ -467,6 +484,30 @@ func TestApplyContainerEdits(t *testing.T) {
467484
},
468485
},
469486
},
487+
{
488+
name: "empty spec, rdt",
489+
spec: &oci.Spec{},
490+
edits: &cdi.ContainerEdits{
491+
IntelRdt: &cdi.IntelRdt{
492+
ClosID: "clos-1",
493+
L3CacheSchema: "L3:0=ff;1=ff",
494+
MemBwSchema: "MB:0=50;1=50",
495+
EnableCMT: true,
496+
EnableMBM: true,
497+
},
498+
},
499+
result: &oci.Spec{
500+
Linux: &oci.Linux{
501+
IntelRdt: &oci.LinuxIntelRdt{
502+
ClosID: "clos-1",
503+
L3CacheSchema: "L3:0=ff;1=ff",
504+
MemBwSchema: "MB:0=50;1=50",
505+
EnableCMT: true,
506+
EnableMBM: true,
507+
},
508+
},
509+
},
510+
},
470511
} {
471512
t.Run(tc.name, func(t *testing.T) {
472513
edits := ContainerEdits{tc.edits}

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+
}

specs-go/oci.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,14 @@ func (d *DeviceNode) ToOCI() spec.LinuxDevice {
3636
GID: d.GID,
3737
}
3838
}
39+
40+
// ToOCI returns the opencontainers runtime Spec LinuxIntelRdt for this IntelRdt config.
41+
func (i *IntelRdt) ToOCI() *spec.LinuxIntelRdt {
42+
return &spec.LinuxIntelRdt{
43+
ClosID: i.ClosID,
44+
L3CacheSchema: i.L3CacheSchema,
45+
MemBwSchema: i.MemBwSchema,
46+
EnableCMT: i.EnableCMT,
47+
EnableMBM: i.EnableMBM,
48+
}
49+
}

0 commit comments

Comments
 (0)