diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 5c4d903c7ed..3af1f1f15c2 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -370,6 +370,14 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, "quiet", "q", false, "Suppress output information when pulling images", ) + rdtClassFlagName := "rdt-class" + createFlags.StringVar( + &cf.IntelRdtClosID, + rdtClassFlagName, cf.IntelRdtClosID, + "Class of Service (COS) that the container should be assigned to", + ) + _ = cmd.RegisterFlagCompletionFunc(rdtClassFlagName, AutocompletePullOption) + createFlags.BoolVar( &cf.ReadOnly, "read-only", podmanConfig.ContainersConfDefaultsRO.Containers.ReadOnly, diff --git a/docs/source/markdown/options/rdt-class.md b/docs/source/markdown/options/rdt-class.md new file mode 100644 index 00000000000..8a58be528e8 --- /dev/null +++ b/docs/source/markdown/options/rdt-class.md @@ -0,0 +1,7 @@ +####> This option file is used in: +####> podman create, run +####> If file is edited, make sure the changes +####> are applicable to all of those. +#### **--rdt-class**=*intel-rdt-class-of-service* + +Rdt-class sets the class of service (CLOS or COS) for the container to run in. Based on the Cache Allocation Technology (CAT) feature that is part of Intel's Resource Director Technology (RDT) feature set, all container processes will run within the pre-configured COS, representing a part of the cache. The COS has to be created and configured using a pseudo file system (usually mounted at `/sys/fs/resctrl`) that the resctrl kernel driver provides. Assigning the container to a COS requires root privileges and thus doesn't work in a rootless environment. Currently, the feature is only supported using `runc` as a runtime. See for more details on creating a COS before a container can be assigned to it. diff --git a/docs/source/markdown/podman-create.1.md.in b/docs/source/markdown/podman-create.1.md.in index 0576675c5ae..0c0b325b85c 100644 --- a/docs/source/markdown/podman-create.1.md.in +++ b/docs/source/markdown/podman-create.1.md.in @@ -304,6 +304,8 @@ by having one container bind to localhost in the pod, and another connect to tha Suppress output information when pulling images +@@option rdt-class + @@option read-only @@option read-only-tmpfs diff --git a/docs/source/markdown/podman-run.1.md.in b/docs/source/markdown/podman-run.1.md.in index 018d8fe0454..76e5ea5351e 100644 --- a/docs/source/markdown/podman-run.1.md.in +++ b/docs/source/markdown/podman-run.1.md.in @@ -330,6 +330,8 @@ by having one container bind to localhost in the pod, and another connect to tha Suppress output information when pulling images +@@option rdt-class + @@option read-only @@option read-only-tmpfs diff --git a/libpod/container_inspect_linux.go b/libpod/container_inspect_linux.go index 2dae35922f7..53fb04034bb 100644 --- a/libpod/container_inspect_linux.go +++ b/libpod/container_inspect_linux.go @@ -21,8 +21,14 @@ func (c *Container) platformInspectContainerHostConfig(ctrSpec *spec.Spec, hostC // there are things that require a major:minor to path translation. var deviceNodes map[string]string - // Resource limits if ctrSpec.Linux != nil { + if ctrSpec.Linux.IntelRdt != nil { + if ctrSpec.Linux.IntelRdt.ClosID != "" { + // container is assigned to a ClosID + hostConfig.IntelRdtClosID = ctrSpec.Linux.IntelRdt.ClosID + } + } + // Resource limits if ctrSpec.Linux.Resources != nil { if ctrSpec.Linux.Resources.CPU != nil { if ctrSpec.Linux.Resources.CPU.Shares != nil { diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go index de4f700fa47..879dd139595 100644 --- a/libpod/define/container_inspect.go +++ b/libpod/define/container_inspect.go @@ -567,6 +567,9 @@ type InspectContainerHostConfig struct { IOMaximumBandwidth uint64 `json:"IOMaximumBandwidth"` // CgroupConf is the configuration for cgroup v2. CgroupConf map[string]string `json:"CgroupConf"` + // IntelRdtClosID defines the Intel RDT CAT Class Of Service (COS) that + // all processes of the container should run in. + IntelRdtClosID string `json:"IntelRdtClosID,omitempty"` } // Address represents an IP address. diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index 5c882a5ed3a..c6bdc0f5531 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -224,6 +224,7 @@ type ContainerCreateOptions struct { Init bool InitContainerType string InitPath string + IntelRdtClosID string Interactive bool IPC string Label []string diff --git a/pkg/specgen/generate/oci_linux.go b/pkg/specgen/generate/oci_linux.go index 6dc1dc28bbf..fa8cd4c24dd 100644 --- a/pkg/specgen/generate/oci_linux.go +++ b/pkg/specgen/generate/oci_linux.go @@ -216,6 +216,12 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt g.AddAnnotation(key, val) } + if s.IntelRdt != nil { + if s.IntelRdt.ClosID != "" { + g.SetLinuxIntelRdtClosID(s.IntelRdt.ClosID) + } + } + if s.ResourceLimits != nil { out, err := json.Marshal(s.ResourceLimits) if err != nil { diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index eca9a9bcc3d..9568ddc0484 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -514,6 +514,10 @@ type ContainerNetworkConfig struct { // ContainerResourceConfig contains information on container resource limits. type ContainerResourceConfig struct { + // IntelRdt defines the Intel RDT CAT Class of Service (COS) that all processes + // of the container should run in. + // Optional. + IntelRdt *spec.LinuxIntelRdt `json:"intelRdt,omitempty"` // ResourceLimits are resource limits to apply to the container., // Can only be set as root on cgroups v1 systems, but can be set as // rootless as well for cgroups v2. diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 3f6475a7e4d..c15c560314b 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -491,6 +491,12 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions s.Labels = labels } + // Intel RDT CAT + if c.IntelRdtClosID != "" { + s.IntelRdt = &specs.LinuxIntelRdt{} + s.IntelRdt.ClosID = c.IntelRdtClosID + } + // ANNOTATIONS annotations := make(map[string]string) diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index cfd9d6e7ef0..2ec49b27945 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -75,6 +75,18 @@ var _ = Describe("Podman create", func() { Expect(session).Should(Exit(125)) }) + It("podman create adds rdt-class", func() { + session := podmanTest.Podman([]string{"create", "--rdt-class", "COS1", "--name", "rdt_test", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(ExitCleanly()) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + check := podmanTest.Podman([]string{"inspect", "rdt_test"}) + check.WaitWithDefaultTimeout() + data := check.InspectContainerToJSON() + Expect(data[0].HostConfig.IntelRdtClosID).To(Equal("COS1")) + }) + It("podman create adds annotation", func() { session := podmanTest.Podman([]string{"create", "--annotation", "HELLO=WORLD", "--name", "annotate_test", ALPINE, "ls"}) session.WaitWithDefaultTimeout()