@@ -383,6 +383,15 @@ type Device struct {
383383 // +listType=atomic
384384 // +featureGate=DRADeviceBindingConditions,DRAResourceClaimDeviceStatus
385385 BindingFailureConditions []string `json:"bindingFailureConditions,omitempty" protobuf:"bytes,11,rep,name=bindingFailureConditions"`
386+
387+ // AllowMultipleAllocations marks whether the device is allowed to be allocated to multiple DeviceRequests.
388+ //
389+ // If AllowMultipleAllocations is set to true, the device can be allocated more than once,
390+ // and all of its capacity is consumable, regardless of whether the requestPolicy is defined or not.
391+ //
392+ // +optional
393+ // +featureGate=DRAConsumableCapacity
394+ AllowMultipleAllocations * bool `json:"allowMultipleAllocations,omitempty" protobuf:"bytes,12,opt,name=allowMultipleAllocations"`
386395}
387396
388397// DeviceCounterConsumption defines a set of counters that
@@ -407,13 +416,28 @@ type DeviceCounterConsumption struct {
407416
408417// DeviceCapacity describes a quantity associated with a device.
409418type DeviceCapacity struct {
410- // Value defines how much of a certain device capacity is available.
419+ // Value defines how much of a certain capacity that device has.
420+ //
421+ // This field reflects the fixed total capacity and does not change.
422+ // The consumed amount is tracked separately by scheduler
423+ // and does not affect this value.
411424 //
412425 // +required
413426 Value resource.Quantity `json:"value" protobuf:"bytes,1,rep,name=value"`
414427
415- // potential future addition: fields which define how to "consume"
416- // capacity (= share a single device between different consumers).
428+ // RequestPolicy defines how this DeviceCapacity must be consumed
429+ // when the device is allowed to be shared by multiple allocations.
430+ //
431+ // The Device must have allowMultipleAllocations set to true in order to set a requestPolicy.
432+ //
433+ // If unset, capacity requests are unconstrained:
434+ // requests can consume any amount of capacity, as long as the total consumed
435+ // across all allocations does not exceed the device's defined capacity.
436+ // If request is also unset, default is the full capacity value.
437+ //
438+ // +optional
439+ // +featureGate=DRAConsumableCapacity
440+ RequestPolicy * CapacityRequestPolicy `json:"requestPolicy,omitempty" protobuf:"bytes,2,opt,name=requestPolicy"`
417441}
418442
419443// Counter describes a quantity associated with a device.
@@ -424,6 +448,86 @@ type Counter struct {
424448 Value resource.Quantity `json:"value" protobuf:"bytes,1,rep,name=value"`
425449}
426450
451+ // CapacityRequestPolicy defines how requests consume device capacity.
452+ //
453+ // Must not set more than one ValidRequestValues.
454+ type CapacityRequestPolicy struct {
455+ // Default specifies how much of this capacity is consumed by a request
456+ // that does not contain an entry for it in DeviceRequest's Capacity.
457+ //
458+ // +optional
459+ Default * resource.Quantity `json:"default" protobuf:"bytes,1,opt,name=default"`
460+
461+ // ValidValues defines a set of acceptable quantity values in consuming requests.
462+ //
463+ // Must not contain more than 10 entries.
464+ // Must be sorted in ascending order.
465+ //
466+ // If this field is set,
467+ // Default must be defined and it must be included in ValidValues list.
468+ //
469+ // If the requested amount does not match any valid value but smaller than some valid values,
470+ // the scheduler calculates the smallest valid value that is greater than or equal to the request.
471+ // That is: min(ceil(requestedValue) ∈ validValues), where requestedValue ≤ max(validValues).
472+ //
473+ // If the requested amount exceeds all valid values, the request violates the policy,
474+ // and this device cannot be allocated.
475+ //
476+ // +optional
477+ // +listType=atomic
478+ // +oneOf=ValidRequestValues
479+ ValidValues []resource.Quantity `json:"validValues,omitempty" protobuf:"bytes,3,opt,name=validValues"`
480+
481+ // ValidRange defines an acceptable quantity value range in consuming requests.
482+ //
483+ // If this field is set,
484+ // Default must be defined and it must fall within the defined ValidRange.
485+ //
486+ // If the requested amount does not fall within the defined range, the request violates the policy,
487+ // and this device cannot be allocated.
488+ //
489+ // If the request doesn't contain this capacity entry, Default value is used.
490+ //
491+ // +optional
492+ // +oneOf=ValidRequestValues
493+ ValidRange * CapacityRequestPolicyRange `json:"validRange,omitempty" protobuf:"bytes,4,opt,name=validRange"`
494+ }
495+
496+ // CapacityRequestPolicyRange defines a valid range for consumable capacity values.
497+ //
498+ // - If the requested amount is less than Min, it is rounded up to the Min value.
499+ // - If Step is set and the requested amount is between Min and Max but not aligned with Step,
500+ // it will be rounded up to the next value equal to Min + (n * Step).
501+ // - If Step is not set, the requested amount is used as-is if it falls within the range Min to Max (if set).
502+ // - If the requested or rounded amount exceeds Max (if set), the request does not satisfy the policy,
503+ // and the device cannot be allocated.
504+ type CapacityRequestPolicyRange struct {
505+ // Min specifies the minimum capacity allowed for a consumption request.
506+ //
507+ // Min must be greater than or equal to zero,
508+ // and less than or equal to the capacity value.
509+ // requestPolicy.default must be more than or equal to the minimum.
510+ //
511+ // +required
512+ Min * resource.Quantity `json:"min,omitempty" protobuf:"bytes,1,opt,name=min"`
513+
514+ // Max defines the upper limit for capacity that can be requested.
515+ //
516+ // Max must be less than or equal to the capacity value.
517+ // Min and requestPolicy.default must be less than or equal to the maximum.
518+ //
519+ // +optional
520+ Max * resource.Quantity `json:"max,omitempty" protobuf:"bytes,2,opt,name=max"`
521+
522+ // Step defines the step size between valid capacity amounts within the range.
523+ //
524+ // Max (if set) and requestPolicy.default must be a multiple of Step.
525+ // Min + Step must be less than or equal to the capacity value.
526+ //
527+ // +optional
528+ Step * resource.Quantity `json:"step,omitempty" protobuf:"bytes,3,opt,name=step"`
529+ }
530+
427531// Limit for the sum of the number of entries in both attributes and capacity.
428532const ResourceSliceMaxAttributesAndCapacitiesPerDevice = 32
429533
@@ -797,6 +901,23 @@ type ExactDeviceRequest struct {
797901 // +listType=atomic
798902 // +featureGate=DRADeviceTaints
799903 Tolerations []DeviceToleration `json:"tolerations,omitempty" protobuf:"bytes,6,opt,name=tolerations"`
904+
905+ // Capacity define resource requirements against each capacity.
906+ //
907+ // If this field is unset and the device supports multiple allocations,
908+ // the default value will be applied to each capacity according to requestPolicy.
909+ // For the capacity that has no requestPolicy, default is the full capacity value.
910+ //
911+ // Applies to each device allocation.
912+ // If Count > 1,
913+ // the request fails if there aren't enough devices that meet the requirements.
914+ // If AllocationMode is set to All,
915+ // the request fails if there are devices that otherwise match the request,
916+ // and have this capacity, with a value >= the requested amount, but which cannot be allocated to this request.
917+ //
918+ // +optional
919+ // +featureGate=DRAConsumableCapacity
920+ Capacity * CapacityRequirements `json:"capacity,omitempty" protobuf:"bytes,7,opt,name=capacity"`
800921}
801922
802923// DeviceSubRequest describes a request for device provided in the
@@ -891,6 +1012,52 @@ type DeviceSubRequest struct {
8911012 // +listType=atomic
8921013 // +featureGate=DRADeviceTaints
8931014 Tolerations []DeviceToleration `json:"tolerations,omitempty" protobuf:"bytes,6,opt,name=tolerations"`
1015+
1016+ // Capacity define resource requirements against each capacity.
1017+ //
1018+ // If this field is unset and the device supports multiple allocations,
1019+ // the default value will be applied to each capacity according to requestPolicy.
1020+ // For the capacity that has no requestPolicy, default is the full capacity value.
1021+ //
1022+ // Applies to each device allocation.
1023+ // If Count > 1,
1024+ // the request fails if there aren't enough devices that meet the requirements.
1025+ // If AllocationMode is set to All,
1026+ // the request fails if there are devices that otherwise match the request,
1027+ // and have this capacity, with a value >= the requested amount, but which cannot be allocated to this request.
1028+ //
1029+ // +optional
1030+ // +featureGate=DRAConsumableCapacity
1031+ Capacity * CapacityRequirements `json:"capacity,omitempty" protobuf:"bytes,7,opt,name=capacity"`
1032+ }
1033+
1034+ // CapacityRequirements defines the capacity requirements for a specific device request.
1035+ type CapacityRequirements struct {
1036+ // Requests represent individual device resource requests for distinct resources,
1037+ // all of which must be provided by the device.
1038+ //
1039+ // This value is used as an additional filtering condition against the available capacity on the device.
1040+ // This is semantically equivalent to a CEL selector with
1041+ // `device.capacity[<domain>].<name>.compareTo(quantity(<request quantity>)) >= 0`.
1042+ // For example, device.capacity['test-driver.cdi.k8s.io'].counters.compareTo(quantity('2')) >= 0.
1043+ //
1044+ // When a requestPolicy is defined, the requested amount is adjusted upward
1045+ // to the nearest valid value based on the policy.
1046+ // If the requested amount cannot be adjusted to a valid value—because it exceeds what the requestPolicy allows—
1047+ // the device is considered ineligible for allocation.
1048+ //
1049+ // For any capacity that is not explicitly requested:
1050+ // - If no requestPolicy is set, the default consumed capacity is equal to the full device capacity
1051+ // (i.e., the whole device is claimed).
1052+ // - If a requestPolicy is set, the default consumed capacity is determined according to that policy.
1053+ //
1054+ // If the device allows multiple allocation,
1055+ // the aggregated amount across all requests must not exceed the capacity value.
1056+ // The consumed capacity, which may be adjusted based on the requestPolicy if defined,
1057+ // is recorded in the resource claim’s status.devices[*].consumedCapacity field.
1058+ //
1059+ // +optional
1060+ Requests map [QualifiedName ]resource.Quantity `json:"requests,omitempty" protobuf:"bytes,1,rep,name=requests,castkey=QualifiedName"`
8941061}
8951062
8961063const (
@@ -930,6 +1097,8 @@ type CELDeviceSelector struct {
9301097 // (e.g. device.attributes["dra.example.com"] evaluates to an object with all
9311098 // of the attributes which were prefixed by "dra.example.com".
9321099 // - capacity (map[string]object): the device's capacities, grouped by prefix.
1100+ // - allowMultipleAllocations (bool): the allowMultipleAllocations property of the device
1101+ // (v1.34+ with the DRAConsumableCapacity feature enabled).
9331102 //
9341103 // Example: Consider a device with driver="dra.example.com", which exposes
9351104 // two attributes named "model" and "ext.example.com/family" and which
@@ -1043,6 +1212,22 @@ type DeviceConstraint struct {
10431212 // criteria.
10441213 //
10451214 // MatchExpression string
1215+
1216+ // DistinctAttribute requires that all devices in question have this
1217+ // attribute and that its type and value are unique across those devices.
1218+ //
1219+ // This acts as the inverse of MatchAttribute.
1220+ //
1221+ // This constraint is used to avoid allocating multiple requests to the same device
1222+ // by ensuring attribute-level differentiation.
1223+ //
1224+ // This is useful for scenarios where resource requests must be fulfilled by separate physical devices.
1225+ // For example, a container requests two network interfaces that must be allocated from two different physical NICs.
1226+ //
1227+ // +optional
1228+ // +oneOf=ConstraintType
1229+ // +featureGate=DRAConsumableCapacity
1230+ DistinctAttribute * FullyQualifiedName `json:"distinctAttribute,omitempty" protobuf:"bytes,3,opt,name=distinctAttribute"`
10461231}
10471232
10481233// DeviceClaimConfiguration is used for configuration parameters in DeviceClaim.
@@ -1204,6 +1389,7 @@ type ResourceClaimStatus struct {
12041389 // +listMapKey=driver
12051390 // +listMapKey=device
12061391 // +listMapKey=pool
1392+ // +listMapKey=shareID
12071393 // +featureGate=DRAResourceClaimDeviceStatus
12081394 Devices []AllocatedDeviceStatus `json:"devices,omitempty" protobuf:"bytes,4,opt,name=devices"`
12091395}
@@ -1370,6 +1556,28 @@ type DeviceRequestAllocationResult struct {
13701556 // +listType=atomic
13711557 // +featureGate=DRADeviceBindingConditions,DRAResourceClaimDeviceStatus
13721558 BindingFailureConditions []string `json:"bindingFailureConditions,omitempty" protobuf:"bytes,8,rep,name=bindingFailureConditions"`
1559+
1560+ // ShareID uniquely identifies an individual allocation share of the device,
1561+ // used when the device supports multiple simultaneous allocations.
1562+ // It serves as an additional map key to differentiate concurrent shares
1563+ // of the same device.
1564+ //
1565+ // +optional
1566+ // +featureGate=DRAConsumableCapacity
1567+ ShareID * types.UID `json:"shareID,omitempty" protobuf:"bytes,9,opt,name=shareID"`
1568+
1569+ // ConsumedCapacity tracks the amount of capacity consumed per device as part of the claim request.
1570+ // The consumed amount may differ from the requested amount: it is rounded up to the nearest valid
1571+ // value based on the device’s requestPolicy if applicable (i.e., may not be less than the requested amount).
1572+ //
1573+ // The total consumed capacity for each device must not exceed the DeviceCapacity's Value.
1574+ //
1575+ // This field is populated only for devices that allow multiple allocations.
1576+ // All capacity entries are included, even if the consumed amount is zero.
1577+ //
1578+ // +optional
1579+ // +featureGate=DRAConsumableCapacity
1580+ ConsumedCapacity map [QualifiedName ]resource.Quantity `json:"consumedCapacity,omitempty" protobuf:"bytes,10,rep,name=consumedCapacity"`
13731581}
13741582
13751583// DeviceAllocationConfiguration gets embedded in an AllocationResult.
@@ -1574,6 +1782,9 @@ const (
15741782
15751783// AllocatedDeviceStatus contains the status of an allocated device, if the
15761784// driver chooses to report it. This may include driver-specific information.
1785+ //
1786+ // The combination of Driver, Pool, Device, and ShareID must match the corresponding key
1787+ // in Status.Allocation.Devices.
15771788type AllocatedDeviceStatus struct {
15781789 // Driver specifies the name of the DRA driver whose kubelet
15791790 // plugin should be invoked to process the allocation once the claim is
@@ -1600,6 +1811,12 @@ type AllocatedDeviceStatus struct {
16001811 // +required
16011812 Device string `json:"device" protobuf:"bytes,3,rep,name=device"`
16021813
1814+ // ShareID uniquely identifies an individual allocation share of the device.
1815+ //
1816+ // +optional
1817+ // +featureGate=DRAConsumableCapacity
1818+ ShareID * string `json:"shareID,omitempty" protobuf:"bytes,7,opt,name=shareID"`
1819+
16031820 // Conditions contains the latest observation of the device's state.
16041821 // If the device has been configured according to the class and claim
16051822 // config references, the `Ready` condition should be True.
0 commit comments