Device Attributes and Selectors

August 25, 2026 · View on GitHub

Every CPU device the driver publishes carries topology attributes that claims can select on with CEL expressions. This page is the attribute reference, with worked selector examples and sample ResourceSlice objects for each device mode.

Note

Attribute names and semantics are not yet a stable API: they may still change between driver minor releases while the project is pre-1.0.

Attribute reference

Which attributes a device carries depends on the driver's device mode (cpuDeviceMode in Configuration): grouped exposes one device per CPU group, individual one device per CPU.

Grouped mode (default)

Currently supported attributes

AttributeTypeDescription
resource.kubernetes.io/numaNodeintStandard NUMA node of the group (published when grouping by NUMA node)
dra.cpu/socketIDintCPU socket of the group (published when grouping by NUMA node or socket)
dra.cpu/numCPUsintCPUs available in the group
dra.cpu/smtEnabledboolWhether SMT/hyper-threading is enabled on the node
resource.kubernetes.io/pcieRootstringsPCIe roots local to the group's CPUs; needs --expose-pcie-roots and the DRAListTypeAttributes feature gate

Legacy attributes (deprecated)

These compatibility attributes will be removed in a future version:

AttributeTypeDescription
dra.cpu/numaNodeIDintDriver-specific NUMA node attribute (NUMA grouping)
dra.net/numaNodeintCross-driver NUMA alignment attribute (NUMA grouping)

Grouped devices also expose the consumable capacity dra.cpu/cpu — the number of CPUs claimable from the group. With groupBy: machine, only numCPUs, smtEnabled, and — when --expose-pcie-roots is enabled — resource.kubernetes.io/pcieRoot are published.

Individual mode

Currently supported attributes

AttributeTypeDescription
dra.cpu/cpuIDintLogical CPU ID
dra.cpu/coreIDintPhysical core ID (shared by SMT siblings)
dra.cpu/coreTypestringstandard, p-core, or e-core
dra.cpu/cacheL3IDintL3 (last-level/uncore) cache group
resource.kubernetes.io/numaNodeintStandard NUMA node
dra.cpu/socketIDintCPU socket
dra.cpu/smtEnabledboolWhether SMT/hyper-threading is enabled on the node
resource.kubernetes.io/pcieRootstringsPCIe roots local to the CPU; needs --expose-pcie-roots and the DRAListTypeAttributes feature gate

Legacy attributes (deprecated)

These compatibility attributes will be removed in a future version:

AttributeTypeDescription
dra.cpu/numaNodeIDintDriver-specific NUMA node attribute
dra.net/numaNodeintCross-driver NUMA alignment attribute

resource.kubernetes.io/pcieRoot is intended for cross-driver co-location via matchAttribute — see Feature Support for details and current limitations.

Use resource.kubernetes.io/numaNode for new workloads. The driver-specific dra.cpu/numaNodeID and dra.net/numaNode attributes are retained as deprecated compatibility attributes while the migration timeline is decided in #299.

Example ResourceSlices

Here's how the ResourceSlice objects might look for each mode.

Grouped mode (default; grouping by NUMA node)

CPUs are grouped, and the device entry shows consumable capacity.

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: 00000-dra.cpu-dra-driver-cpu-worker-tp869
  # ... other metadata
spec:
  driver: dra.cpu
  nodeName: dra-driver-cpu-worker
  pool:
    generation: 1
    name: dra-driver-cpu-worker
    resourceSliceCount: 1
  devices:
  - allowMultipleAllocations: true
    attributes:
      dra.cpu/smtEnabled:
        bool: true
      dra.cpu/numCPUs:
        int: 64
      resource.kubernetes.io/numaNode:
        int: 0
      dra.cpu/socketID:
        int: 0
      dra.net/numaNode:
        int: 0
      dra.cpu/numaNodeID:
        int: 0
      # Only populated if the driver is run with --expose-pcie-roots=true
      resource.kubernetes.io/pcieRoot:
        strings:
        - pci0000:00
        - pci0000:10
    capacity:
      dra.cpu/cpu:
        value: "64"
    name: cpudevnuma000
  - allowMultipleAllocations: true
    attributes:
      dra.cpu/smtEnabled:
        bool: true
      dra.cpu/numCPUs:
        int: 64
      resource.kubernetes.io/numaNode:
        int: 1
      dra.cpu/socketID:
        int: 0
      dra.net/numaNode:
        int: 1
      dra.cpu/numaNodeID:
        int: 1
      # Only populated if the driver is run with --expose-pcie-roots=true
      resource.kubernetes.io/pcieRoot:
        strings:
        - pci0000:40
        - pci0000:50
    capacity:
      dra.cpu/cpu:
        value: "64"
    name: cpudevnuma001

Individual mode

Each CPU is listed as a separate device with detailed attributes.

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: dra-driver-cpu-worker-dra.cpu-qskwf
  # ... other metadata
spec:
  driver: dra.cpu
  nodeName: dra-driver-cpu-worker
  pool:
    generation: 1
    name: dra-driver-cpu-worker
    resourceSliceCount: 1
  devices:
  - attributes:
      dra.cpu/cacheL3ID:
        int: 0
      dra.cpu/coreID:
        int: 1
      dra.cpu/coreType:
        string: standard
      dra.cpu/cpuID:
        int: 1
      resource.kubernetes.io/numaNode:
        int: 0
      dra.cpu/smtEnabled:
        bool: true
      dra.cpu/socketID:
        int: 0
      dra.net/numaNode:
        int: 0
      dra.cpu/numaNodeID:
        int: 0
      # Only populated if the driver is run with --expose-pcie-roots=true
      resource.kubernetes.io/pcieRoot:
        strings:
        - pci0000:00
    name: cpudev000
  - attributes:
      dra.cpu/cacheL3ID:
        int: 0
      dra.cpu/coreID:
        int: 1
      dra.cpu/coreType:
        string: standard
      dra.cpu/cpuID:
        int: 33
      resource.kubernetes.io/numaNode:
        int: 0
      dra.cpu/smtEnabled:
        bool: true
      dra.cpu/socketID:
        int: 0
      dra.net/numaNode:
        int: 0
      dra.cpu/numaNodeID:
        int: 0
      # Only populated if the driver is run with --expose-pcie-roots=true
      resource.kubernetes.io/pcieRoot:
        strings:
        - pci0000:00
    name: cpudev001
  # ... other CPU devices

With node allocatable mapping

When the driver runs with publishNodeAllocatableResourceMapping: true (requires the DRANodeAllocatableResources feature gate, alpha in 1.37+), every device additionally carries a nodeAllocatableResources entry translating its DRA allocation into node allocatable cpu.

Grouped mode maps the consumed dra.cpu/cpu capacity 1:1:

  devices:
  - allowMultipleAllocations: true
    capacity:
      dra.cpu/cpu:
        value: "64"
    name: cpudevnuma000
    nodeAllocatableResources:
      cpu:
        mapping:
          capacityKey: dra.cpu/cpu
          capacityMultiplier: "1"

Individual mode maps each device to one CPU:

  devices:
  - name: cpudev000
    nodeAllocatableResources:
      cpu:
        mapping:
          deviceMultiplier: "1"

Selecting CPUs based on properties with CEL

A selector is a CEL expression over the attributes above; the scheduler only allocates devices for which every selector is true.

In the default grouped mode, CPUs are requested as dra.cpu/cpu capacity from a group device, and selectors pick the group. A complete claim for 8 CPUs from NUMA node 0:

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: cpus-on-numa0
spec:
  devices:
    requests:
    - name: cpus
      exactly:
        deviceClassName: dra.cpu
        capacity:
          requests:
            dra.cpu/cpu: "8"
        selectors:
        - cel:
            expression: device.attributes["resource.kubernetes.io"].numaNode == 0

In individual mode, each CPU is its own device, so claims request a count of devices and selectors pick individual CPUs. A complete claim for 4 performance cores:

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: performance-cores
spec:
  devices:
    requests:
    - name: cpus
      exactly:
        deviceClassName: dra.cpu
        count: 4
        selectors:
        - cel:
            expression: device.attributes["dra.cpu"].coreType == "p-core"

Any attribute works the same way — for example, swap the expression for device.attributes["dra.cpu"].smtEnabled == false to avoid nodes with SMT/hyper-threading enabled (e.g. for side-channel isolation).

Selectors filter each request independently; to make multiple requests land on matching topology, add a matchAttribute constraint. A complete claim requesting two CPU sets that must share a socket:

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: same-socket-cpus
spec:
  devices:
    requests:
    - name: cpus-a
      exactly:
        deviceClassName: dra.cpu
        capacity:
          requests:
            dra.cpu/cpu: "4"
    - name: cpus-b
      exactly:
        deviceClassName: dra.cpu
        capacity:
          requests:
            dra.cpu/cpu: "4"
    constraints:
    - requests: ["cpus-a", "cpus-b"]
      matchAttribute: dra.cpu/socketID

The inverse is distinctAttribute: every request must get a different value. A complete claim spreading two CPU sets across two different NUMA nodes — without hardcoding which nodes, so the same claim works on any machine:

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: numa-spread-cpus
spec:
  devices:
    requests:
    - name: cpus-a
      exactly:
        deviceClassName: dra.cpu
        capacity:
          requests:
            dra.cpu/cpu: "8"
    - name: cpus-b
      exactly:
        deviceClassName: dra.cpu
        capacity:
          requests:
            dra.cpu/cpu: "8"
    constraints:
    - requests: ["cpus-a", "cpus-b"]
      distinctAttribute: resource.kubernetes.io/numaNode

distinctAttribute is gated by DRAConsumableCapacity — the same feature gate the default grouped mode uses, enabled by default from Kubernetes 1.36.

Similarly, for equal-sized slices you can use a single request with count > 1. This repeats the same per-result capacity request multiple times. By itself, count does not guarantee spreading, but combined with distinctAttribute it can force the scheduler to place those results on different devices:

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: numa-spread-cpus
spec:
  devices:
    requests:
    - name: cpus-multi
      exactly:
        deviceClassName: dra.cpu
        count: 2
        capacity:
          requests:
            dra.cpu/cpu: "8"
    constraints:
    - requests: ["cpus-multi"]
      distinctAttribute: resource.kubernetes.io/numaNode

For a longer discussion of the trade-offs of using count + distinctAttribute for NUMA spreading, see Feature Support.

NOTE: An important point to stress is the role of the distinctAttribute constraint. In grouped mode, all the exposed devices support multiple allocations. Therefore, without the constraint, the scheduler can pick the same device multiple times to fulfil the allocation request, if that device has enough remaining capacity. In turn, the driver supports this request shape and will honor the request, because it is valid and legal.