DRA Network Device Discovery Design

Policy-driven network device discovery with DRA compatibility groups, local consumable capacity, and optional shared budgets

·88 min read

DRA Network Device Discovery and ResourceSlice Design

Status: Revised selected design; driver implementation has not started.
Revision: 2026-09-23 — define cold PCI and software-child discovery, effect-specific host-dependency protection, and VLAN/ipvlan/macvlan/macvtap compatibility; align NetworkPlugin capability names and OVN adapter identity; retain the KEP 5963 exclusion model.
Scope: This document defines the proposed DeviceExposurePolicy API and its translation into Kubernetes DRA objects. Custom policy fields below are our design, not upstream Kubernetes fields.

Upstream baseline and feature boundaries

The implementation observations in this revision are pinned to Kubernetes commit a255808f6c0deb6e75ce031b5804e722306e46a8, inspected on 2026-09-16. A source-level feature version is not a promise that a particular OpenShift release enables or supports that feature. Validate the actual target distribution before deployment. S1 S2

ConcernUpstream mechanismBaseline / dependency
Device inventory and claimsresource.k8s.io/v1Use the current v1 object shape.
Counter-set associationsKEP 4815 / DRAPartitionableDevicesInspected source: beta from 1.36, enabled by default. Do not label this dependency GA in 1.35.
Repeated allocations and local limitsKEP 5075 / DRAConsumableCapacityInspected source: beta from 1.36, enabled by default.
Incompatible network modesKEP 5963 / DRADeviceCompatibilityGroupsInspected source: alpha from 1.37, disabled by default; requires partitionable devices.
supportedNetworkPlugins list attributeKEP 5491 / DRAListTypeAttributesInspected source: alpha from 1.36, disabled by default. List values use strings.
Per-allocation shared budgetsKEP 5941 / PR #140084Optional follow-on work. Not required for the baseline exclusion design or reference manifests.

Important implementation caveat: KEP 5963 describes allocation-time group snapshots, but the inspected allocator reconstructs compatibility from live ResourceSlices and allocated device identities. This revision targets that actual behavior. Do not assume claim status already preserves compatibility independently of the inventory. S3 S4


1. Overview and Design Principles

This document specifies how a DRA network driver discovers host network devices and publishes them as ResourceSlices for scheduler-aware allocation.

The Cardinal Rule: The Driver Is Generic

sysfs / netlink observations
          |
          v
PCI functions + netdevices + typed dependency/ownership graph
          |
          v
DeviceExposurePolicy selection and validation
          |
          v
persona entries + scoped compatibility domains + local capacities
          |
          v
separate counter-bearing and device-bearing ResourceSlices
Diagram 1 — Device Discovery Flow: Hardware → Driver → Policy Evaluation → ResourceSlice

The discovery engine starts with PCI functions, including functions already bound to VFIO or unbound at first startup, and joins optional host netdevice, RDMA and controller observations. Software bridges, bonds and VLANs have separate inventory records. An absent host interface is not evidence that a PCI function is absent or free. Section 4.1 defines identity, observation completeness and dependency protection; the engine does not infer NetworkPlugin compatibility from plugin names.

The administrator’s policy declares which devices are exposed, which logical NetworkPlugins can use an entry, how much local capacity each allocation consumes, and which usage modes may coexist. The driver validates and compiles these declarations. The node-side execution path must enforce the compiled compatibility contract and verify the actual device identity before changing networking; being generic does not mean skipping safety checks.

A PF/VF relationship is a discovered topology fact. A declaration that PF passthrough must exclude all child allocations is a policy rule, not a universally assumed consequence of every operation on every PF. In particular, this design does not assert that every PF namespace move destroys its VFs. Independently, the driver must deny any operation whose certified effects can disrupt a protected host dependency. Exposure policy cannot override that safety check.

Other Design Decisions

  1. Real resources, not synthetic allocation slots. A PCI function, its verified network endpoint or a software interface may have multiple persona entries when it supports different allocation semantics. A persona is an alternative representation, not additional hardware; netdevice absence does not erase a function.
  2. One winning policy produces one persona. allowMultipleAllocations is the single source of truth for sharing that entry. Multiple NetworkPlugin names in one policy are alternatives with identical allocation semantics.
  3. Local capacity limits repeated allocations. A shared persona uses allowMultipleAllocations: true plus capacity. The examples reserve one unit per claim allocation, with validValues: ["1"].
  4. Compatibility groups express mode exclusion. Distinct incompatible personas consume from a common counter set and declare disjoint compatibilityGroups. No local-capacity mirroring and no cross-draining are generated.
  5. Independent constraints use independent domains. Interface mode and PF-family access are separate counter-set associations when both are needed. PF macvlan and child VFs can share a family group while PF macvlan and PF ipvlan remain incompatible in the interface domain.
  6. Bandwidth is a separate, optional budget. Link speed remains an attribute in the baseline. Do not publish a bandwidth guarantee or an invented fair-share policy just because a speed was discovered.
  7. Deny-by-default, without forgetting active allocations. Unmatched or excluded devices are not newly exposed. Existing active publication is handled through the drain protocol, not deleted immediately.
  8. NetworkPlugin selection is explicit. DeviceClasses select the driver and test supportedNetworkPlugins using exact list membership. Advertising a NetworkPlugin name is not proof that its invocation and controller integration work.
  9. Stable identities and declarations. Active device names, pool membership, counter-set associations, and groups must survive rescan, policy changes, interface moves, and driver restarts until safely drained.
  10. Protection is effect-specific. Management, primary-network and external ownership records protect their actual dependency closure. PCI ancestry, PF families, representors, IOMMU groups and reset domains are distinct relationships, not interchangeable exclusion groups.

The upstream API separates compatibility predicates from local and shared capacity accounting. Our policy compiler preserves that separation. S1 S3 S4


2. DeviceExposurePolicy CRD Schema

2.1 Proposed Custom Resource Shape

This is an example custom resource, not an apiextensions.k8s.io/v1 CRD definition. The structural OpenAPI schema, defaults, CEL validation, status schema, and admission integration will be implemented after this design is accepted.

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-macvlan
spec:
  # Optional; defaults to all nodes.
  nodeSelector:
    matchLabels:
      network.example.com/role: data

  # 0-1000, default 100. Used only among expose policies for the same suffix.
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f0"
  action: expose

  exposure:
    # One policy winner per suffix; no automatic splitting by NetworkPlugin name.
    deviceNameSuffix: "-macvlan"
    allowMultipleAllocations: true

    # Local capacity only. This does not create shared counter capacity.
    capacity:
      macvlans:
        value: "64"
        requestPolicy:
          default: "1"
          validValues: ["1"]

    supportedNetworkPlugins:
      - name: macvlan
        # Compiler validation / topology contract, not a Kubernetes field.
        consumePerAllocation:
          macvlans: "1"

    # Proposed policy API. Each binding compiles to a consumesCounters entry.
    compatibility:
      - scope: interface
        domain: interface-mode
        groups: [macvlan]
      - scope: sriovFamily
        domain: pf-access
        groups: [host-retained]

    # Selection metadata only; do not override discovered or reserved attributes.
    additionalAttributes:
      dra.networking/physicalNetworkName: data-network

2.2 Field Semantics

FieldRequired / defaultMeaning
nodeSelectorOptional; all nodesNodes on which the policy participates in resolution.
priorityOptional; 100Highest value wins within the same suffix; range 0-1000.
selector.celRequiredBoolean expression against the driver’s normalized discovered attributes.
actionOptional; exposeexpose proposes publication subject to dependency safety; exclude prevents new exposure of the selected inventory resource. An exclusion alone is not an external ownership record.
exposure.deviceNameSuffixOptional; empty stringDistinguishes persona policies for one inventory resource. Published identities are pinned after creation.
exposure.allowMultipleAllocationsOptional; falseSharing permission for this DRA device entry, not for every alias of the underlying interface.
exposure.capacityRequired for shared entries in this baselineLocal DeviceCapacity definitions. The compiler qualifies unqualified keys with dra.networking/.
exposure.supportedNetworkPluginsRequired for expose policiesNon-empty list of logical NetworkPlugin names and optional consumption declarations. All plugins on one entry must have identical allocation semantics.
consumePerAllocationOptional; use local defaultsA driver/topology consistency declaration. Baseline amounts must equal requestPolicy.default; the scheduler does not read this custom field.
exposure.compatibilityOptional unless sharing an exclusion domainUp to two domain bindings after compilation. Each binding has scope, domain, and non-empty groups.
compatibility[].scopeRequiredinterface: the stable endpoint/resource identity, including its function ownership boundary when applicable; it does not require a current ifname. sriovFamily: the PF root’s stable identity, shared with its VFs.
compatibility[].domainRequiredAdministrator-chosen DNS-label name for one independent compatibility constraint.
compatibility[].groupsRequiredOne or two unique DNS-label tokens copied into the upstream compatibilityGroups field.
exposure.additionalAttributesOptionalAdditional scalar selection attributes; string, boolean, or integer. Reserved/discovered keys cannot be overwritten.

scope and domain resolve a comparison boundary; groups expresses compatibility within that boundary. Group names have no plugin-specific interpretation in the driver.

Each supportedNetworkPlugins[].name identifies a logical plugin in the companion NetworkPlugin registry. It is not a CNI executable name, gRPC socket, deployment artifact or process name. A topology’s pluginRef.name selects that same identity and pins its contract through the immutable revision. A service may implement multiple logical plugins; publish their individual names, not the service name. Discovery capability publication does not replace whole-plan runtime readiness checks.

2.3 Policy Resolution

For each identity-verified inventory resource:
  1. Select policies whose nodeSelector applies to this node.
  2. Evaluate selector.cel against normalized discovered facts.
  3. If any matching policy says exclude: desired exposure is empty.
  4. If no expose policy matches: desired exposure is empty.
  5. Otherwise group matching expose policies by deviceNameSuffix.
  6. Pick highest priority per group; break ties by policy name.
  7. Produce exactly one candidate persona per winner.
  8. Resolve compatibility bindings against the discovered topology.
  9. Validate certified effect footprints against protection/ownership records.
     Then validate the complete interface/family publication, including retained entries.
 10. Reconcile desired publication with active allocations and the drain state.
Diagram 2 — Policy Resolution Flow: selector matching through compatibility binding to final persona output

Exclude priority is irrelevant: an exclusion always takes precedence over exposure. Two policies with different suffixes are not automatically mutually exclusive; their explicit compatibility bindings determine which combinations are allowed.

A selector compilation error rejects the policy. A selector evaluation error makes reconciliation fail closed for the affected inventory evaluation and records a diagnostic; it must not silently skip a potentially applicable exclusion policy. Previously committed active publication remains retained until its lifecycle is resolved.

2.4 Validation and Cross-Policy Checks

These are proposed driver requirements, in addition to upstream API validation:

  • An exclusive entry (allowMultipleAllocations: false) has no local request policy or consumePerAllocation in the baseline. A shared entry has positive local capacity and an explicit default for each dimension.
  • Plugin-specific amounts are positive, reference existing capacity keys after qualification, and equal those dimensions’ defaults in the initial implementation. Different plugin costs require different persona policies and suitable compatibility guards; they are not inferred at scheduling time.
  • When more than one persona aliases an interface, all aliases must participate in a common interface-scoped domain. Any exclusive persona must be incompatible there with every other alias. The compiler rejects ambiguous aliasing rather than assuming different names imply separate hardware.
  • When an exposed PF persona excludes child use, every exposed child and every competing PF persona must participate in the same family-scoped domain. This is configured in policy; topology resolution alone does not invent group membership.
  • A sriovFamily binding on an interface with no resolvable PF root is invalid. Bridges with indirect PF dependencies are not silently assigned a PF family.
  • Resolve bindings before enforcing limits: a device may consume from at most two counter sets; a counter-set consumption supports at most two compatibility groups. Reject a third independent domain instead of silently dropping it. S1
  • Conflicting domain definitions, duplicate references, invalid names, overriding reserved attributes, or exceeding upstream attribute limits invalidate the affected compilation unit.
  • supportedNetworkPlugins names must be nonempty, unique and refer to approved logical plugin contracts. Reject retired capability-field names rather than accepting ambiguous aliases. Advertised support must agree with the inventory and execution contract; the presence of a similarly named CNI binary is insufficient.
  • All initial counter-set associations generated for exclusion have non-empty groups. An empty list must never be emitted as a wildcard.
  • A matching expose policy cannot authorize unsafe effects. Every advertised plugin must pass Section 4.1’s dependency check; an unknown identity, ownership boundary or relevant effect footprint prevents new publication. The compiler rejects that persona with a diagnostic rather than silently dropping a plugin alternative.

Policy admission can validate shape and local consistency. Node reconciliation must validate topology-dependent and cross-policy rules. A future webhook must not claim it can statically validate every node’s current hardware inventory.


3. How Compatibility Domains Work: The Multi-Persona Pattern

The selected pattern remains separate DRA device entries referring to a common resource, but the enforcement mechanism changes to KEP 5963 compatibility groups.

3.1 Three Uses of the Same Compatibility Predicate

RelationshipComparison domainCompatible group assignment
Macvlan vs ipvlan on one interfaceInterface interface-modeMacvlan: [macvlan]; ipvlan: [ipvlan].
Shared macvlan vs exclusive host-device on one interfaceSame interface domainMacvlan: [macvlan]; passthrough: [passthrough].
PF passthrough vs normal PF/VF usePF family pf-accessPF passthrough: [pf-passthrough]; retained PF and VFs: [host-retained].
PF0 interface-mode:       macvlan [macvlan]  !=  passthrough [passthrough]
PF0 family pf-access:     macvlan [host-retained]
                         VF0..VF7 [host-retained]
                         passthrough [pf-passthrough]
Diagram 3 — Three Compatibility Group Patterns: interface-mode (shared vs shared), interface-mode (shared vs exclusive), family pf-access (PF passthrough vs VFs)

This allows PF macvlan and VFs together while excluding PF passthrough. Adding a PF ipvlan persona uses [ipvlan] in the interface domain and [host-retained] in the family domain. It remains compatible with VFs but not with PF macvlan.

A VF’s NetworkPlugin allocation can be exclusive for that VF entry while its family group is host-retained: the group describes access to the parent PF family, not whether that VF is shared.

3.2 Exact Upstream Compatibility Semantics

For each counter set, the scheduler maintains an intersection across the active devices’ group sets. A new candidate is compatible only if including its groups leaves a common group. A candidate associated with two counter sets must pass the predicate on both. Devices associated with different counter sets are not compared through this feature. S1 S3

{macvlan} intersection {macvlan} = {macvlan}   -> compatible
{macvlan} intersection {ipvlan}  = {}          -> incompatible

Pairwise overlap is insufficient. {a,b}, {b,c}, and {a,c} intersect pairwise, but the intersection of all three is empty. Empty/unset groups only coexist with other empty/unset groups on the same counter set; they do not mean “compatible with everything”. S3

Do not publish groups: [macvlan, shared] and groups: [ipvlan, shared] when the modes conflict: the common shared token would permit them together.

3.2.1 Upstream Two-Item Limits and Domain Scaling

The pinned Kubernetes API and its generated validation confirm two separate limits:

  • One DeviceCounterConsumption may contain at most two unique compatibilityGroups names.
  • One device may contain at most two consumesCounters entries, so it may participate in at most two counter sets and therefore at most two independent compatibility domains.

The API declarations set both maxima to two, and the generated validators call MaxItems(..., 2) for both fields. An API server rejects a third group on one consumption or a third counter-set consumption on one device. S1 S20

These limits constrain different dimensions. A counter set identifies the comparison domain. Its compatibilityGroups are alternative memberships within that domain. The two-group limit does not restrict a domain to two modes: any number of devices or personas may each publish one distinct group, such as macvlan, ipvlan, passthrough, and other mutually exclusive modes. It does restrict a single device that must be compatible through three or more alternative common memberships in the same domain.

The two-consumesCounters limit is more restrictive for this design. A PF persona that consumes from interface-mode and pf-access has used both available domain associations. It cannot also join an independent reset-domain, controller-ownership domain, or other scheduler compatibility domain. Adding that third domain name to the existing compatibilityGroups list is not equivalent: group names in one consumption are OR alternatives inside one domain, while separate counter-set checks are AND constraints. Such flattening may allow an unsafe combination.

Use these workarounds only when their semantics are exact:

  1. Apply the third domain only to personas that do not already consume from two counter sets. The limit is per device, not a pool-wide limit.
  2. Merge domains only when they have the same comparison boundary and their conjunction can be encoded losslessly with composite group tokens, with no device requiring more than two tokens. For example, a token may represent the tuple (interface-mode=macvlan, pf-access=host-retained). Test whole-set intersections for every supported combination; tuple encoding can otherwise reject valid combinations or admit invalid ones.
  3. Put devices in separate pools only when no compatibility comparison is required across those pools. Different pools disable this predicate; pool splitting cannot preserve a required cross-pool exclusion.
  4. Keep external ownership and operation-safety constraints in Section 4.1’s protection graph. If a third relationship must be enforced by the scheduler between DRA consumers and cannot be encoded exactly, reject that publication profile. A node-side Prepare failure is not a scheduling-time workaround.
  5. Seek an upstream API extension when a device genuinely needs three or more independent compatibility domains or more than two alternative memberships in one domain. The current API has no general lossless encoding for either case.

3.2.2 Concrete Network Cases That Hit the Limits

The group limit is reachable with the software modes in this document. On one immediate lower, suppose macvlan/macvtap, ipvlan L2, and ipvlan L3 are three mutually incompatible mode families, while a VLAN-creation persona may coexist with any one family. The required sets are:

macvlan/macvtap: {mac-family}
ipvlan L2:       {ipvlan-l2}
ipvlan L3:       {ipvlan-l3}
VLAN:            {mac-family, ipvlan-l2, ipvlan-l3}

The VLAN set requires three groups and is rejected by API validation. This cannot be fixed by adding one common vlan-compatible token to the other personas: that token would also make the three conflicting families compatible with each other. More generally, one neutral persona that must intersect three pairwise-disjoint families needs at least three group tokens. Example 10 avoids this limit by approving only ipvlan l2/bridge, leaving two families for the VLAN persona.

The domain limit is reachable when one persona needs three independently scoped scheduler predicates. A multi-function NIC can require all of the following:

  1. An immediate-lower interface-mode domain for mac-family, ipvlan and direct handoff.
  2. A PF pf-access family domain for PF passthrough versus that PF’s VFs.
  3. A separate reset, embedded-switch or controller-mode domain spanning another set of functions or PFs.

The first two consume Example 10’s two entries. A third consumesCounters entry is rejected. Merging the third constraint into pf-access is valid only when both domains have the same members and the combined compatibility relation still needs at most two tokens per persona. Shared reset and controller scopes commonly cross PF-family boundaries, so that equivalence cannot be assumed. If the protection graph can treat the third relationship as an execution-safety boundary, reject unsafe operations there. If simultaneous DRA consumers require scheduling-time exclusion across that third boundary, the current API cannot represent the profile losslessly.

Diagram 4 — PF/VF Family Domain: compatibility groups showing host-retained vs pf-passthrough intersection

3.3 Local Capacity and the Non-Binding Membership Counter

The upstream field attaches to consumesCounters[]; a compatibility-only relationship still needs a valid counter-set association. This design generates one positive bookkeeping counter named members per compatibility domain. It is not a lock and not a per-Pod quota.

Let N be the number of distinct published persona/device identities referencing a domain, including retained active entries. Publish members = max(1, N) and a fixed consumption of members: "1" for each member. Do not shrink this bookkeeping total during an active drain transition. Normal allocation permits at most one active fixed charge per member identity, so the counter itself does not decide which modes may coexist. Compatibility groups do. S1 S4

For two macvlan/ipvlan personas, members: "2" intentionally leaves enough numerical capacity for both. Their disjoint groups still prevent coexistence.

QuantityRoleConsumption
Local capacity.macvlansNumber of macvlan allocation unitsPer allocation; examples use one.
Domain membersValid counter-set association with non-binding accountingFixed charge once per active device identity in the inspected baseline.
Optional shared bandwidthA real shared resource budgetPer allocation only with the separately supported shared-consumable feature.

A local quota applies to one persona identity. Publishing two compatible aliases with independent local quotas does not create a single aggregate hardware limit. Use one canonical persona for the same allocation contract, explicitly partition the administrator budget, or introduce a genuine shared budget in the follow-on profile. Do not represent the same 64 physical units as two independent 64-unit guarantees.

The old cross-drain model is removed. Local capacity does not automatically decrement a similarly named shared counter. In the old example, allocating macvlan drained the ipvlan mirror but left the macvlan mirror available, so ipvlan could consume that other mirror. Merely charging the fixed amount once did not create mutual exclusion.

3.4 Allocation and Release Lifecycle

With stable publication, the inspected implementation detects that a shared device remains allocated after one of its claims is released. It reconstructs the compatibility baseline using that active device and its live group declarations. The compatibility restriction is not attached to the first claim’s private counter snapshot. S4 S5

EventMacvlan allocationsIPvlan result
Initial0May allocate.
Allocate A1Blocked.
Allocate B on the same macvlan device2Blocked.
Release A; keep B1Still blocked.
Reconstruct scheduler state or restart the driver1Must remain blocked.
Release B and complete cleanup0May allocate.
Diagram 9 — Allocation Lifecycle State Progression: macvlan vs ipvlan group intersection through allocation and release cycles

“Allocation released” means the scheduler no longer considers the ResourceClaim allocation active. Pod termination or a driver-local reference count reaching zero is not, by itself, sufficient evidence. One claim may serve multiple Pods; a capacity of 64 means 64 one-unit allocation results, not necessarily 64 Pods. Prefer per-Pod ResourceClaimTemplates where a per-Pod budget is intended. S7

This is not a claim that PR #140084’s static-counter lifetime issue has been fixed. The baseline does not depend on that PR. A combined build must get its own regression tests.

3.5 Feature-Disabled and Unsupported-Cluster Behavior

The baseline requires compatibility support whenever incompatible personas are exposed. Do not remove the group field and publish the same alternatives as a fallback. The API server can strip disabled feature fields; the scheduler can skip slices containing unsupported groups, and a skipped slice can make a pool incomplete. Neither behavior is a substitute for a driver capability contract. S3 S6

Installation must verify the selected API server and scheduler configuration. An explicit deployment capability setting plus API round-trip validation and a controlled scheduler conformance test is preferable to guessing from a version string or OpenAPI schema alone. A schema can describe fields whose feature gates are disabled.

For an unsupported cluster, a separately selected reduced profile may expose only one preselected mode per actual exclusion domain. It must not expose PF passthrough together with active child uses. Node-side checks remain required. This is a deliberate reduced feature profile, not an automatic downgrade of the same policy set.


4. How the Driver Uses Policies

The driver compiles discovered facts and winning policies into a complete desired pool model, validates it, then reconciles it against active allocations.

4.1 Attribute Translation

Discovered facts use the dra.networking domain, except explicitly standardized attributes such as device.k8s.io/pcieRoot. Values below are observations, not inferred NetworkPlugin capabilities. This table defines the supported normalized attribute vocabulary; a ResourceSlice may publish a selection-relevant subset within its attribute limit. Internal inventory retains the complete observation/provenance record, including facts omitted from the illustrative slices.

Discovered factPublished attributeDiscovery input
Interface name, when attached to a verified host endpointdra.networking/ifNameNetlink joined to the inventory identity; never synthesized for VFIO/unbound functions.
MAC addressdra.networking/macCurrent verified netdevice observation; not a physical identity key.
MTUdra.networking/mtuCurrent netdevice observation; omitted when unavailable.
Link speed, when knowndra.networking/linkSpeedDriver/ethtool observation, documented in Mbps.
Operational statedra.networking/operStateNetlink.
PCI BDFdra.networking/pciAddressPCI enumeration, independent of a host netdevice; a current locator, not replacement-proof identity.
NUMA nodedra.networking/numaNodePCI sysfs topology, when meaningful.
PCIe rootdevice.k8s.io/pcieRootPCI topology walk.
Vendor and product IDsdra.networking/vendor, dra.networking/productPCI identifiers.
Bound driverdra.networking/driverSysfs driver association, including approved VFIO drivers; omitted when unbound or unknown.
Binding statedra.networking/bindingStatekernel, vfio, unbound, or unknown; failed reads do not mean unbound.
Resource classificationdra.networking/typeDiscovered pf/vf/bridge/vlan/bond/nic, or unknown until classification is established; not inferred from interface naming.
RDMA associationdra.networking/rdmaValidated netdevice/RDMA relationship.
SR-IOV capability and configured VF countdra.networking/sriovCapable, dra.networking/numVFsPF sysfs facts.
Parent PF and VF indexdra.networking/pfPCIAddress, dra.networking/vfIndex; optional dra.networking/pfNameReciprocal physfn / virtfnN relationships identify the parent/index; pfName additionally requires a verified host PF endpoint.
Bridge factsdra.networking/bridgeName, bridgeType, vlanFilteringSupported bridge discovery backend.
Master bridgedra.networking/masterBridgeMaster relationship, resolved to a bridge where appropriate.

Unknown is not zero. Omit unavailable speed, MAC, MTU, NUMA, RDMA, interface-name and parent-name attributes; normalize a reported unknown NUMA value to absence rather than node zero. rdma: false requires an authoritative negative observation, not a failed query. masterBridge: "" means a verified host endpoint has no bridge master; it does not mean no bond, controller or external owner. Omit masterBridge when the endpoint or relationship is unknown. Selectors must guard optional attributes with has(...); a cold VFIO function must not make an unrelated kernel-interface selector fail through an unguarded missing key.

Discovery must not forget a device solely because the driver moved it out of the host network namespace or changed its kernel binding. Preserve an allocation-aware inventory record and reconcile against node execution state.

4.1.1 Cold Inventory and Observation Sources

This is the proposed implementation contract resolving research finding F12. No discovery backend, host ownership adapter or hardware conformance suite is implemented by this document. Inventory visibility and permission to allocate are separate: the initial kernel execution profiles include exclusive VFs and explicitly delegated shared parents; VFIO and unbound functions are discovered but stay unavailable unless a separately certified execution profile accepts them. These hardware/effect boundaries preserve the selected alpha-capability baseline and do not introduce a static/reduced inventory fallback.

The scanner performs read-only discovery. It must not bind a driver, enable VFs, reset hardware, create links or change namespaces to make inventory easier to observe. Linux exposes PCI records independently of network interfaces and exposes PF/VF relationships through PCI sysfs. S13 S14

InputRequired observationCompleteness rule
/sys/bus/pci/devicesCanonical function path/BDF, IDs/class, driver link, parent PCI topology, available immutable hardware evidenceEnumerate network candidates and all functions needed for dependency boundaries, including non-network peers. A vanished or unreadable entry makes the affected observation incomplete.
PCI SR-IOV sysfsphysfn, reciprocal virtfnN, supported/configured VF counts where availableResolve VF identity without ifName or pfName. A missing/mismatched reciprocal link is unresolved topology, not a standalone free VF.
Rtnetlink and netdevice sysfsNamespaced link identity, kind, lower link, master membership, addresses, routes and rulesJoin endpoints to functions using observed device relationships. Distinguish a real VF endpoint from a representor. Dump interruption/event loss invalidates the affected graph until rescan.
Devlink and approved driver adaptersPort/controller/function mapping, representors, eswitch ownership and documented operation boundariesUse supported identifiers and topology, not parsing interface names. Missing adapter support prevents operations requiring those relationships.
RDMA observationsVerified device/port-to-function/netdevice mappingAbsence and query failure differ. RDMA execution remains a separate profile.
IOMMU and reset evidenceFunction group membership and operation-specific reset scopeRecord separate typed boundaries. The scanner never discovers a reset footprint by resetting hardware.
Protected host configuration and owner adaptersManagement/primary-network roots, allocated devices, external ownership and their observed revisionsRequired owner coverage must be complete for the candidate’s possible effects. Unsupported/expired ownership information is not “unowned.”

A FunctionRecord contains a durable physical-resource ID, current locator, identity/presence epoch, classification, binding state and evidence with provenance. It has zero or more EndpointRecord links. An endpoint carries its namespace incarnation, observed link identifier, kind and function/port association; a software interface has its own inventory identity without a fabricated PCI parent. Do not select the first netdevice if a function has several ports or representors. The initial one-endpoint profile rejects that ambiguity; wider profiles must declare the port and function ownership boundaries explicitly.

Each observation records Known, Unknown or Stale, the source and collection revision. A completed scan has an inventoryGeneration and a dependency-graph digest; those are internal driver values, not a kernel-wide atomic snapshot. Reconcile dumps with events and repeat reads when relationships change. Never join observations from different namespace or function incarnations merely because an ifindex or BDF matches. Kernel link/port identifiers aid correlation; they do not certify continuous ownership across disappearance or reboot. S15 S16

4.1.2 Durable Identity and Replacement Uncertainty

The durable resource ID is an opaque, persisted ID scoped to the Kubernetes Node UID and this host installation’s persisted identity. BDF, ifname, ifindex, MAC, VF index, vendor/product IDs and IOMMU group number are locators or observations; none alone proves continuity. Store the evidence used to correlate them and its uncertainty. A boot ID distinguishes observation incarnations; it does not by itself replace the physical-resource ID.

The identity record has a monotonic presenceEpoch, separate from inventoryGeneration, policy revision and ResourceSlice pool generation. Published device/pool names and active claim mappings remain pinned to their committed identity epoch. The following transition rules apply:

  1. An observed rename or an authorized, journaled namespace move/driver rebind retains the resource ID and epoch when function/endpoint continuity is verified. Update locators; keep the old allocation contract.
  2. Hardware replacement, a confirmed function removal/recreation, or VF destroy/recreate requires a new epoch. Reusing the same BDF, VF index or ifname never authorizes the new incarnation to satisfy an old allocation. Keep the old record as a tombstone while claims, cleanup or external references remain.
  3. Reboot, missed events or conflicting evidence produce IdentityUncertain until the approved hardware profile can correlate the device and reconcile outstanding ownership. Matching vendor/product/MAC values alone cannot resolve it. Where reliable continuity evidence is unavailable, require maintenance recovery; do not guess.
  4. On first installation, persist the initial identity before publication, after a complete scan and ownership check. Cold VFIO/unbound discovery must work without a prior execution journal. Their visibility does not authorize rebinding or DMA access. Lost identity storage, a new Node UID or host reinstall does not make previous allocations/reservations disappear: quarantine affected resources until recovery establishes their disposition.

Multiple aliases of one endpoint share its ownership identity. Different endpoints of one function retain a common function boundary for effects such as rebinding. Stable published names use the persisted mapping and collision-checked DNS encoding described in Section 4.3. An uncertain candidate receives no new allocatable entry; an already allocated identity remains represented under the drain contract, with new use blocked and diagnostics attached.

4.1.3 Protection Graph and Authoritative Roots

The driver maintains a typed graph separate from DRA compatibility domains. Its vertices include PCI functions, network endpoints/software links, RDMA resources, controller-managed objects and ownership records. Every edge records provenance, current identity epochs and which effects it can propagate.

Use consumer → dependency direction: a VLAN depends on its lower link; a bridge or bond depends on its member links; an endpoint depends on its PCI function; a VF depends on specified PF services. Master membership also constrains the member: detaching/moving it changes the master’s dependency. Keep representor-to-represented-function and eswitch-control edges distinct from endpoint-to-function edges. A representor is a separate network/control object, not another free alias of the represented VF. Kernel devlink and representor documentation describe this distinction. S16 S17

IOMMU ownership and reset scopes are typed membership boundaries, not directed network-dependency edges. A group may contain non-network functions. IOMMU grouping does not prove the reset footprint, PF family does not prove the IOMMU boundary, and a common PCI root does not make every operation affect every descendant. VFIO requires suitable DMA ownership; reset methods may have different scopes. S18 S19

Protected roots come from all of the following mandatory inputs for the supported host profile:

  • Administrator-protected management endpoints and the approved host routing/policy configuration used for control-plane reachability. Observed addresses/routes/rules and current route lookups supplement this configuration; a default-route-only heuristic is insufficient for policy routing, VRFs or multiple management paths.
  • Primary CNI/controller ownership, including approved uplinks, bridges, tunnels, representors and externally provisioned interfaces. br-int or any other naming convention is only a selector convenience, not ownership proof.
  • Other device plugins/DRA drivers, host bridges/bonds/VMs and approved external managers. Import authoritative ownership or reserve a static hardware partition that excludes their resources. “No ResourceClaim found for this driver” does not establish freedom from other owners.
  • This driver’s allocated/prepared/attached/uncertain resources and cleanup debt, including resources no longer visible in the host namespace.

The proposed internal ProtectionRecord contains an owner identity, root resource IDs/epochs, source revision, protected effects, any explicitly delegated operations and its completeness/freshness rule. The node’s administrator-controlled installation configuration must enumerate required sources/adapters and static partitions; tenant exposure policy cannot assert that an unknown owner is absent. Until a required adapter exists, deny the relevant exposure profile. Loss of a source retains prior protection and blocks new dependent operations; it does not expire the protection into permission.

An action: exclude policy only suppresses direct publication. The compiler does not infer that every excluded VF reserves its entire PF family. Protection propagates from actual ownership/dependency records, with the effect rules below. An operator may separately protect a selected resource against specified effects even if it is not currently allocated.

4.1.4 Effect-Specific Safety Evaluation

An approved plugin contract must describe the bounded effects it may perform in Prepare, Connect, Remove and Unprepare, including driver operations and implicit recovery/cleanup effects. A generic plugin name is not that contract. The node implementation maps those effects to a certified hardware/driver profile; unknown or broader-than-declared effects are unsupported.

For a candidate operation, first compute its impact set by following only the relationships relevant to its declared effects. Then compute the protected dependency set from each protection root along consumer → dependency edges for the same effects. Include master-membership changes explicitly. Deny when these sets intersect without an explicit, applicable owner delegation. A blocked dependency path should be reported, for example management VLAN → bond → PF ← requested rebind. Repeat to a fixed point with cycle detection; unresolved relevant edges or cycles whose impact cannot be established are DependencyUnknown, not empty sets.

Requested effectRequired expansion/checkPolicy consequence
Read-only inspectionIdentity and permitted observation scope; no mutation footprintMay inspect protected inventory without publishing or taking ownership.
Create/delete an attachment child on a retained parentParent’s delegated shared-child contract, namespace/lower relationships, local capacity and incompatible modes; include any parent configuration writesAn approved shared data parent may be usable while retained on host. Management/primary-owned parents are denied unless their owner explicitly delegates these exact effects.
Move/detach/delete a netdevice, change its master, or modify parent MTU/MAC/routesSelected endpoint, its member/master relationship and relevant dependent uppers/ownersA free kernel VF may move; a management uplink or host bridge/bond member may not. Moving one PF netdevice does not automatically equal destroying every VF.
Bind/unbind a PCI functionAll endpoints/access objects served by the function plus certified driver effects on PF services, VFs and representorsDeny if any affected object is protected, allocated elsewhere or unresolved. A host-owned representor may block VF handoff even when the VF itself has no master.
VF create/destroy, PF-wide configuration or eswitch mode changeApplicable PF family and controller/representor dependenciesDeny while any affected child/owner is active or unknown; the driver must not shrink inventory first to make the check pass.
VFIO/IOMMU ownership transitionFull DMA ownership boundary and current owners, including non-network members; separately evaluate bind/reset effectsDeny until the certified VFIO profile proves exclusive authorized ownership. IOMMU membership grants no permission to reset the group.
Function/slot/bus reset or recovery that can resetActual supported reset method and its certified impact set, with dependent ownersDeny unknown scope or overlap. Never substitute “same PF,” “same IOMMU group,” or “same NUMA node” for verified reset scope.

The initial profile denies reset, VF creation/destruction, arbitrary PCI rebinding and external-controller mutation. Later profiles must supply evidence and owner coordination before advertising them. Host-retained and destructive operations on the same hardware can therefore have different answers. Safety checks do not create scheduler reservations for external owners or extra cross-pool compatibility domains. If simultaneous DRA consumers need a constraint that the two supported scopes cannot express, reject that publication profile instead of depending on late local rejection for normal scheduling.

4.1.5 Publication, Preparation and Changed Dependencies

Before publication, compile every advertised persona/plugin against the complete identity graph, protection records and certified effect profile. Persist its identity epoch and contract fingerprint. Report IdentityUncertain, DependencyUnknown, ProtectedDependency or UnsupportedEffect with the policy, proposed operation and dependency path. The fingerprint records evidence, not a claim that Linux host changes are atomically locked.

Before Prepare and again before every later mutation, resolve the allocated resource through the committed mapping; acquire deterministic resource/domain locks; refresh relevant identity, ownership and effect-boundary observations; and compare with the permitted contract. Safe observation-only changes, such as a verified rename, may update locators. A new protected dependent, changed ownership epoch, vanished peer or unverified replacement blocks the operation before side effects. Revalidate between steps when the preceding step can alter relevant topology.

On a safety-relevant change, block new use of all affected personas, retain allocated declarations and enter PendingDrain/recovery. Do not destroy a live attachment or delete its governing compatibility groups merely because new desired policy excludes it. Cleanup must use the historical operation scope but also verify current identity/ownership; never restore settings onto replacement hardware. If safe reversal cannot be established, retain cleanup debt and quarantine.

Local locks coordinate this driver’s work only. Required host controllers must honor the configured maintenance/ownership handoff; arbitrary privileged host mutations cannot be fenced by a ResourceSlice or a netlink rescan. A deployment that cannot establish disjoint ownership or coordinate a relevant owner must reject that effect profile; it cannot silently remove requested capabilities or exclusion constraints. The separate durable publication-transition work in Section 8 remains required; this contract does not claim to solve scheduler/watch races.

4.2 Policy-Driven Fields

OutputSource / transformation
Device namePinned resource/endpoint identity and presence epoch plus winning suffix; never derived solely from a current host ifname.
allowMultipleAllocationsCopy from policy.
Local capacityPolicy quantities and request policies; qualify names consistently.
dra.networking/supportedNetworkPluginsNames from exposure.supportedNetworkPlugins[].name, serialized as {strings: [...]}.
Additional attributesValidated non-reserved policy metadata, converted to typed attribute values.
Counter-set referenceResolved (pool, scope root, domain) binding.
compatibilityGroupsCopy the binding’s groups after validation.
Domain members totalNumber of referencing published identities, including retained entries.
Fixed members consumptionOne per referencing identity.

attributes and capacity are direct fields under a v1 device entry. Do not wrap them in basic. Counter definitions and device entries belong in different ResourceSlice objects. S1

4.3 Topology Resolution and Pool Layout

One PF and its VFs form a pool. Standalone interfaces use standalone pools unless a separately supported topology relationship requires a common pool. Domain comparisons never cross pool boundaries.

For scope: interface, resolve the stable endpoint/resource identity defined in Section 4.1, even when no host ifname exists. For scope: sriovFamily, use the verified parent PF root for both the PF and all of its VFs. The driver discovers these relationships but does not invent mode groups. Profiles with several endpoints sharing a broader function mutation boundary need an explicit supported allocation guard; the initial profile rejects ambiguous multi-port exposure.

A domain key is:

(driver, pool identity, resolved scope-root identity, administrator domain name)

The counter-set name is a stable DNS-label encoding of this key within its pool. The implementation must define deterministic normalization, truncation and collision handling, for example a readable prefix with a stable hash suffix. Group names remain opaque; do not append each device’s unique identity to a shared group token.

The examples use short readable names such as pf0-interface-mode and pf0-family-pf-access. Production identity must not depend only on the current interface name or an unstable enumeration order. Persist the mapping used for active allocations under Section 4.1.2’s identity rules. PCI BDF reuse after hardware replacement must not be mistaken for continuity of the old allocated hardware. A protection graph may cross pools even though scheduler compatibility cannot; such a graph is a safety check, not an unsupported cross-pool counter association.

4.4 Translation Algorithm

INPUT:
  complete identity-verified inventory and protection graph,
  all relevant policies, certified effect profiles, deployment capabilities,
  last committed publication, allocated claims, node execution journal
OUTPUT:
  validated desired pools, status/diagnostics, staged publication operations

Phase 1 — Resolve policies and personas
  Evaluate node and device selectors.
  Apply exclude / deny-by-default rules.
  Pick one winner per (inventory resource identity, suffix).
  Build candidate persona records without publishing them.
  Resolve each advertised plugin's bounded effects and required owner coverage.

Phase 2 — Resolve compatibility domains
  Resolve each interface or sriovFamily scope root.
  Place family members in the same pool.
  Resolve each (root, domain) into one counter-set identity.
  Copy groups exactly; do not infer them from NetworkPlugin names.
  Require complete guards for aliases and any declared family-exclusive mode.

Phase 3 — Merge lifecycle state
  Retain active entries missing from desired discovery/policy results.
  Pin their identity, associations, groups and relevant allocation contract.
  Mark incompatible policy changes or hardware changes as pending drain.
  Retain identity-uncertain and newly protected active resources; block new use.
  Do not publish replacement identities that can alias still-active hardware.

Phase 4 — Build resource accounting
  Copy local capacities; never mirror them for exclusion.
  For each domain, publish members >= its distinct retained/current members.
  Add fixed members: 1 consumption to every referencing device entry.
  Do not add automatic bandwidth or fair-share defaults.

Phase 5 — Validate the entire pool
  Check names, field limits, no duplicate device or counter-set identities.
  Check one consumption entry per counter set and at most two per device.
  Check local quantities, group membership, aliases and feature capabilities.
  Check each effect footprint against protected dependencies and owner delegations.
  Reject unknown identity, incomplete relevant graph or unsupported effects.
  Fail closed on invalid compilation; report the policy and domain involved.

Phase 6 — Pack and publish
  Pack counter sets into counter-bearing slices.
  Pack devices into device-bearing slices.
  Set the same pool name, generation and total resourceSliceCount on all.
  Reconcile through the upstream ResourceSlice controller where practical.
  Retain old active declarations through transitions; reconcile partial writes.

Phase 7 — Observe and retire
  Reconcile allocated claims, host ownership and node execution state continuously.
  Remove retired declarations only after the drain/cleanup conditions pass.
Diagram 5 — Translation Algorithm: 7-phase flow from policy resolution through compatibility domains to publication

A pool.generation change allows readers to distinguish pool generations; it is not a multi-object transaction or an instruction to revoke existing claims. Publication must recover from incomplete generations and asynchronous watches. S1 S7

4.5 Optional Follow-On: Shared Bandwidth Budgets

The baseline publishes linkSpeed as a fact and makes no aggregate bandwidth reservation guarantee. The original automatic bandwidth and fair-share logic is removed from the baseline rather than presented as implemented functionality.

If bandwidth reservations are added later, use explicit administrator-supplied budgets and KEP 5941’s request-driven shared consumption. Every traffic consumer intended to participate in that budget must be included: accounting only for VFs while PF macvlan traffic is unaccounted for is not a whole-link reservation model.

The following is an experimental future wire-format fragment, not part of the initial DeviceExposurePolicy schema or baseline manifests. It follows PR #140084 at 51d78febb379ae41f7487a50b9718a4ede0e3f3c; that PR uses valueFrom.capacityName, not capacityKey. S8

# Counter-bearing ResourceSlice.spec fragment, future feature profile.
sharedCounters:
  - name: pf0-family-pf-access
    counters:
      members:
        value: "10"
      bandwidth:
        value: "100000"       # Contract: Mbps, explicitly configured by admin.
        requestPolicy:
          default: "1000"
          validRange:
            min: "100"
            max: "100000"
            step: "100"
# One member's device fragment, future feature profile.
consumesCounters:
  - counterSet: pf0-family-pf-access
    compatibilityGroups: [host-retained]
    counters:
      members:
        value: "1"
      bandwidth:
        valueFrom:
          capacityName: dra.networking/bandwidth
# ResourceClaim request fragment for that future feature profile.
exactly:
  deviceClassName: network-vf-pf0
  capacity:
    requests:
      dra.networking/bandwidth: "2500"

Reuse a compatible existing domain counter set where appropriate; do not add a third counter-set association to a device that already uses two. Define one authoritative budget specification and conflict resolution before implementing policy-to-budget translation. Capacity accounting alone also does not configure a hardware rate limit: scheduling reservation and enforcement are separate contracts.

The PR’s fixed-versus-per-share accounting, release behavior, feature transitions and combination with KEP 5963 must be retested on the actual combined code. Do not make baseline mode exclusion depend on a presumed fix in that PR.

4.6 ResourceSlice Packing Rules

In the inspected v1 API: S1

  • spec.devices and spec.sharedCounters are mutually exclusive in one object.
  • resourceSliceCount is the total number of ResourceSlices in the pool generation, including both kinds of slices.
  • A device has at most two consumesCounters entries, one per referenced counter set; each has at most two compatibility group names.
  • One counter-bearing slice has at most eight counter sets, each with at most 32 counters.
  • Use at most 64 devices per slice when counters, list attributes or other applicable advanced features are used. Validate the target API’s combined attribute/capacity and list-value limits too.

Do not duplicate a counter set in each device slice. Split the inventory into additional slices and update the total count when limits require it.

4.7 Capacity Requests and the Topology Contract

The scheduler does not execute our policies or choose an amount based on a NetworkPlugin name. It reads local requestPolicy and any ResourceClaim capacity requests. Consequently, the baseline fixes each example’s default and allowed amount to one unit and requires all listed NetworkPlugin alternatives to agree with that amount. S1 S7

A request for four units reserves four units; it does not automatically cause the execution engine to create four interfaces. Supporting variable quantities requires an explicit topology/execution contract and generated or user-authored capacity.requests. This is why the examples no longer advertise a one-to-four range while describing exactly one interface per allocation.

DeviceClass selectors select suitable devices but do not create plugin-specific capacity requests. The no-extra-capacity-fields application experience relies on consistent per-device defaults, not hidden scheduler interpretation of consumePerAllocation.


5. Examples

The nine scenarios from the original document are retained. Policy fields are the proposed API in Section 2; ResourceSlice examples use the inspected upstream v1 shape. Examples labelled fragment are not complete Kubernetes objects. Complete objects and every reference VF appear in Section 6.

Interface names, PCI addresses, capacities and speeds are illustrative inventory values from the reference scenario, not discovery defaults or vendor guarantees. The actual driver must use observed identities and administrator-selected limits. The kernel-interface policies guard optional name/master attributes; cold VFIO/unbound inventory needs a separately approved profile and PCI/identity-based selection. ResourceSlice fragments show the allocation layer, not the internal identity, protection or owner records required before publication.

5.1 Example 1: Simple SR-IOV VFs

Scenario: VFs under enp3s0f0 support sriov. Each VF is a normal, exclusively allocated DRA device. Normal use of the family is explicitly labelled host-retained.

DeviceExposurePolicy

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: sriov-vfs-pf0
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].pfName) &&
      device.attributes["dra.networking"].type == "vf" && device.attributes["dra.networking"].pfName == "enp3s0f0"
  action: expose
  exposure:
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: sriov
    compatibility:
      - scope: sriovFamily
        domain: pf-access
        groups:
          - host-retained

Resulting ResourceSlice Fragments

This scenario exposes eight VFs and no PF persona, so the family domain has eight member identities. A future PF persona must use a compatible family declaration or be drained into a new configuration before publication.

Counter-bearing ResourceSlice.spec fragment:

sharedCounters:
  - name: pf0-family-pf-access
    counters:
      members:
        value: '8'

Device-bearing ResourceSlice.spec fragment (same pool):

devices:
  - name: enp3s0f0v0
    attributes:
      dra.networking/type:
        string: vf
      dra.networking/ifName:
        string: enp3s0f0v0
      dra.networking/pfName:
        string: enp3s0f0
      dra.networking/vfIndex:
        int: 0
      dra.networking/pciAddress:
        string: '0000:03:00.2'
      dra.networking/numaNode:
        int: 0
      dra.networking/rdma:
        bool: true
      dra.networking/vendor:
        string: 15b3
      dra.networking/product:
        string: 101e
      dra.networking/driver:
        string: mlx5_core
      device.k8s.io/pcieRoot:
        string: pci0000:00
      dra.networking/supportedNetworkPlugins:
        strings:
          - sriov
    consumesCounters:
      - counterSet: pf0-family-pf-access
        compatibilityGroups:
          - host-retained
        counters:
          members:
            value: '1'

The remaining seven VF entries use the same family group and each consume one member. VFs are independently allocatable because they are distinct devices with the same group. A VF is exclusive because allowMultipleAllocations is false/omitted, not because its plugin declaration has a custom exclusive flag. There is no automatic numVFs + 1 lock counter.

5.2 Example 2: SR-IOV VFs with Multiple NetworkPlugin Options

Scenario: A VF may be selected for sriov or host-device. The two names are execution alternatives for one exclusive entry, not permission to allocate the VF twice. The scenario assumes the execution path validates each plugin’s configuration requirements.

DeviceExposurePolicy

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-vfs
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].pfName) &&
      device.attributes["dra.networking"].type == "vf" && device.attributes["dra.networking"].pfName == "enp3s0f0"
  action: expose
  exposure:
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: sriov
      - name: host-device
    compatibility:
      - scope: sriovFamily
        domain: pf-access
        groups:
          - host-retained

Resulting ResourceSlice Fragments

Counter-bearing ResourceSlice.spec fragment:

sharedCounters:
  - name: pf0-family-pf-access
    counters:
      members:
        value: '8'

Device-bearing ResourceSlice.spec fragment (same pool):

devices:
  - name: enp3s0f0v0
    attributes:
      dra.networking/type:
        string: vf
      dra.networking/ifName:
        string: enp3s0f0v0
      dra.networking/pfName:
        string: enp3s0f0
      dra.networking/vfIndex:
        int: 0
      dra.networking/pciAddress:
        string: '0000:03:00.2'
      dra.networking/numaNode:
        int: 0
      dra.networking/rdma:
        bool: true
      dra.networking/vendor:
        string: 15b3
      dra.networking/product:
        string: 101e
      dra.networking/driver:
        string: mlx5_core
      device.k8s.io/pcieRoot:
        string: pci0000:00
      dra.networking/supportedNetworkPlugins:
        strings:
          - sriov
          - host-device
    consumesCounters:
      - counterSet: pf0-family-pf-access
        compatibilityGroups:
          - host-retained
        counters:
          members:
            value: '1'

The supported-NetworkPlugin list is serialized with strings. A generated DeviceClass can use device.attributes["dra.networking"].supportedNetworkPlugins.includes("sriov") or the corresponding host-device selection. .includes() is the DRA list-aware CEL helper; it does not reserve resources or invoke the plugin. S7

5.3 Example 3: PF as Macvlan Parent

Scenario: enp3s0f1 has no exposed VFs or competing persona in this example. It provides 64 one-unit macvlan allocations. This isolated, single-persona case does not need a compatibility domain.

DeviceExposurePolicy

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf1-macvlan-parent
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f1"
  action: expose
  exposure:
    allowMultipleAllocations: true
    capacity:
      macvlans:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    supportedNetworkPlugins:
      - name: macvlan
        consumePerAllocation:
          macvlans: '1'

Resulting Device Entry

name: enp3s0f1
allowMultipleAllocations: true
attributes:
  dra.networking/type:
    string: pf
  dra.networking/ifName:
    string: enp3s0f1
  dra.networking/pciAddress:
    string: '0000:03:00.1'
  dra.networking/mac:
    string: 04:3f:72:b0:d4:61
  dra.networking/mtu:
    int: 1500
  dra.networking/linkSpeed:
    int: 25000
  dra.networking/numVFs:
    int: 0
  dra.networking/rdma:
    bool: true
  dra.networking/numaNode:
    int: 0
  dra.networking/vendor:
    string: 15b3
  dra.networking/product:
    string: 101d
  dra.networking/driver:
    string: mlx5_core
  device.k8s.io/pcieRoot:
    string: pci0000:00
  dra.networking/supportedNetworkPlugins:
    strings:
      - macvlan
capacity:
  dra.networking/macvlans:
    value: '64'
    requestPolicy:
      default: '1'
      validValues:
        - '1'

Each claim allocation consumes one local unit. A 65th one-unit allocation cannot fit. The capacity is an administrator-defined quota, not an automatically discovered macvlan maximum. Adding another persona later requires a common interface domain and a safe migration of any already-active entry; do not silently attach new groups to existing allocations.

5.4 Example 4: Parent-Interface Software Modes

Scenario: The administrator declares macvlan and ipvlan incompatible on enp3s0f1, as motivated by the original document’s receive-handler conflict. The compiler does not contain that plugin-specific rule. Both modes have independent local limits of 64 allocations.

DeviceExposurePolicy — Macvlan Persona

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf1-macvlan
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f1"
  action: expose
  exposure:
    deviceNameSuffix: -macvlan
    allowMultipleAllocations: true
    capacity:
      macvlans:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    supportedNetworkPlugins:
      - name: macvlan
        consumePerAllocation:
          macvlans: '1'
    compatibility:
      - scope: interface
        domain: interface-mode
        groups:
          - macvlan

DeviceExposurePolicy — Ipvlan Persona

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf1-ipvlan
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f1"
  action: expose
  exposure:
    deviceNameSuffix: -ipvlan
    allowMultipleAllocations: true
    capacity:
      ipvlans:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    supportedNetworkPlugins:
      - name: ipvlan
        consumePerAllocation:
          ipvlans: '1'
    compatibility:
      - scope: interface
        domain: interface-mode
        groups:
          - ipvlan

Resulting ResourceSlices — Two Objects in One Pool

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: worker-1-pf1-mode-example-counters
spec:
  driver: dra.networking
  pool:
    name: worker-1-pf1-mode-example
    generation: 1
    resourceSliceCount: 2
  nodeName: worker-1
  sharedCounters:
    - name: pf1-interface-mode
      counters:
        members:
          value: '2'
---
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: worker-1-pf1-mode-example-devices
spec:
  driver: dra.networking
  pool:
    name: worker-1-pf1-mode-example
    generation: 1
    resourceSliceCount: 2
  nodeName: worker-1
  devices:
    - name: enp3s0f1-macvlan
      allowMultipleAllocations: true
      attributes:
        dra.networking/type:
          string: pf
        dra.networking/ifName:
          string: enp3s0f1
        dra.networking/pciAddress:
          string: '0000:03:00.1'
        dra.networking/mac:
          string: 04:3f:72:b0:d4:61
        dra.networking/mtu:
          int: 1500
        dra.networking/linkSpeed:
          int: 25000
        dra.networking/numVFs:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/numaNode:
          int: 0
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101d
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - macvlan
      capacity:
        dra.networking/macvlans:
          value: '64'
          requestPolicy:
            default: '1'
            validValues:
              - '1'
      consumesCounters:
        - counterSet: pf1-interface-mode
          compatibilityGroups:
            - macvlan
          counters:
            members:
              value: '1'
    - name: enp3s0f1-ipvlan
      allowMultipleAllocations: true
      attributes:
        dra.networking/type:
          string: pf
        dra.networking/ifName:
          string: enp3s0f1
        dra.networking/pciAddress:
          string: '0000:03:00.1'
        dra.networking/mac:
          string: 04:3f:72:b0:d4:61
        dra.networking/mtu:
          int: 1500
        dra.networking/linkSpeed:
          int: 25000
        dra.networking/numVFs:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/numaNode:
          int: 0
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101d
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - ipvlan
      capacity:
        dra.networking/ipvlans:
          value: '64'
          requestPolicy:
            default: '1'
            validValues:
              - '1'
      consumesCounters:
        - counterSet: pf1-interface-mode
          compatibilityGroups:
            - ipvlan
          counters:
            members:
              value: '1'

Walkthrough

EventRemaining numerical membersLocal macvlan units remainingGroup state / outcome
Initial264No active mode.
First macvlan claim163Active group is macvlan.
Second macvlan claim162Same device; no new fixed member charge.
Try ipvlan162Numerical member capacity is sufficient, but groups do not intersect: rejected.
Release the first macvlan claim163Second claim keeps macvlan active; ipvlan remains rejected.
Release the last macvlan claim264No active mode; ipvlan can allocate.

These are expected outcomes from the model, not a report of a cluster test performed for this document. The acceptance suite must verify them across successive allocation cycles and state reconstruction.

5.4.1 Linux Constraints for VLAN, Ipvlan, Macvlan and Macvtap

The NetworkPlugin name alone is not enough to determine compatibility. Compatibility depends on the lower netdevice and the requested mode. For the same immediate lower netdevice, the initial certified profile uses this matrix:

Active child typeVLAN childIpvlan childMacvlan childMacvtap child
VLAN childCompatible when (protocol, VLAN ID) ownership does not conflictCompatibleCompatibleCompatible
Ipvlan childCompatibleCompatible only when all children use the same approved port-wide mode and flagsIncompatibleIncompatible
Macvlan childCompatibleIncompatibleCompatible for approved non-passthru modes and unique MAC addressesCompatible for approved non-passthru modes and unique MAC addresses
Macvtap childCompatibleIncompatibleCompatible for approved non-passthru modes and unique MAC addressesCompatible for approved non-passthru modes and unique MAC addresses

Linux permits only one receive handler on a netdevice. Ipvlan rejects a new port when the selected lower already has a receive handler. Macvlan installs its receive handler on that same lower. Therefore ipvlan cannot share one immediate lower with macvlan or macvtap. Macvtap is implemented through macvlan_common_newlink, so normal macvlan and macvtap children share the macvlan port rather than competing for separate lower-device receive handlers. S21 S22 S23

This compatibility is conditional:

  • Ipvlan mode and flags belong to the ipvlan port on the lower device. A profile must pin one combination, such as l2/bridge, for all concurrent ipvlan children. Separate l2, l3, or l3s personas on the same lower are mutually exclusive.
  • Macvlan/macvtap passthru is an exclusive port mode and must not share the normal mac-family group. Publish it as an exclusive persona with a disjoint group. Other mode combinations still require target-kernel tests.
  • A VLAN child is a stacked netdevice and does not consume the lower’s sole receive-handler slot. Distinct VLAN IDs can coexist, but the plugin must serialize and journal (lower identity, 802.1Q/802.1ad protocol, VLAN ID) ownership. It must not assume that two requests can independently create the same VLAN link. S24
  • NIC unicast-filter limits, switch policy, MTU, offload support, tap-minor availability and administrator quotas remain platform or policy limits. Discovery cannot derive a portable maximum for these child types.

5.4.2 Four Personas on One Discovered PF

Assume discovery observes one verified parent and no pre-existing software children:

FunctionRecord pf1: 0000:03:00.1, mlx5_core, presenceEpoch 7
  EndpointRecord: enp3s0f1, ifindex incarnation 12, Ethernet, MTU 1500
  Existing uppers: none
  Receive-handler owner: none

Discovery publishes facts about the parent. Policy supplies child-creation permission, approved modes and quotas. It does not discover 64 VLANs, ipvlans, macvlans, or macvtaps from the NIC. The compiler may produce these four persona entries when the execution profile approves VLAN creation, ipvlan l2/bridge, macvlan bridge, and macvtap bridge:

Persona suffixLogical pluginPinned execution contractInterface group membership
-vlanvlanCreate an authorized 802.1Q/802.1ad child with journaled protocol and VLAN ID ownership[mac-family, ipvlan-l2]
-ipvlan-l2ipvlanl2/bridge on this lower[ipvlan-l2]
-macvlanmacvlanbridge, non-passthru[mac-family]
-macvtapmacvtapbridge, non-passthru, with tap lifecycle management[mac-family]
sharedCounters:
  - name: pf1-interface-mode
    counters:
      members:
        value: '4'
---
devices:
  - name: enp3s0f1-vlan
    allowMultipleAllocations: true
    attributes:
      dra.networking/supportedNetworkPlugins:
        strings: [vlan]
    capacity:
      dra.networking/vlans:
        value: '64'
        requestPolicy: {default: '1', validValues: ['1']}
    consumesCounters:
      - counterSet: pf1-interface-mode
        compatibilityGroups: [mac-family, ipvlan-l2]
        counters:
          members: {value: '1'}

  - name: enp3s0f1-ipvlan-l2
    allowMultipleAllocations: true
    attributes:
      dra.networking/supportedNetworkPlugins:
        strings: [ipvlan]
      dra.networking/ipvlanMode:
        string: l2
      dra.networking/ipvlanFlags:
        string: bridge
    capacity:
      dra.networking/ipvlans:
        value: '64'
        requestPolicy: {default: '1', validValues: ['1']}
    consumesCounters:
      - counterSet: pf1-interface-mode
        compatibilityGroups: [ipvlan-l2]
        counters:
          members: {value: '1'}

  - name: enp3s0f1-macvlan
    allowMultipleAllocations: true
    attributes:
      dra.networking/supportedNetworkPlugins:
        strings: [macvlan]
      dra.networking/macvlanMode:
        string: bridge
    capacity:
      dra.networking/macvlans:
        value: '64'
        requestPolicy: {default: '1', validValues: ['1']}
    consumesCounters:
      - counterSet: pf1-interface-mode
        compatibilityGroups: [mac-family]
        counters:
          members: {value: '1'}

  - name: enp3s0f1-macvtap
    allowMultipleAllocations: true
    attributes:
      dra.networking/supportedNetworkPlugins:
        strings: [macvtap]
      dra.networking/macvlanMode:
        string: bridge
    capacity:
      dra.networking/macvtaps:
        value: '64'
        requestPolicy: {default: '1', validValues: ['1']}
    consumesCounters:
      - counterSet: pf1-interface-mode
        compatibilityGroups: [mac-family]
        counters:
          members: {value: '1'}

ipvlanMode, ipvlanFlags, and macvlanMode in this example are compiled contract-selection attributes. They come from the approved policy/NetworkPlugin revision, not from physical-device discovery. A production schema must reserve and validate these keys before emitting them.

The VLAN persona needs both permitted-family tokens. This uses the upstream maximum of two groups on one counter-set consumption. Resulting intersections are:

Active setCommon groupResult
VLAN + ipvlan L2ipvlan-l2Permit.
VLAN + macvlanmac-familyPermit.
VLAN + macvtapmac-familyPermit.
Macvlan + macvtapmac-familyPermit.
Ipvlan + macvlan or macvtapNoneReject.
VLAN + ipvlan + macvlan or macvtapNoneReject because the child families conflict.

This encoding stops scaling when the VLAN persona must be neutral across three incompatible child families. It also stops scaling if multiple incompatible ipvlan port modes must coexist as alternatives: VLAN would need mac-family, ipvlan-l2, and ipvlan-l3, exceeding the two-group limit. Select one ipvlan contract per lower, use separate real lower netdevices, or reject the profile. Splitting one physical parent into synthetic DRA names does not remove the kernel conflict.

The four local capacities are independent administrator quotas. They do not prove that the parent supports 256 simultaneous children or impose one aggregate child limit. Use a genuine shared budget when an aggregate limit is required.

5.4.3 Pre-existing VLAN Lowers

Discovery may instead observe two administrator-owned VLAN netdevices:

enp3s0f1 (PF endpoint, 0000:03:00.1)
  +-- enp3s0f1.100 (kind vlan, protocol 802.1Q, id 100)
  `-- enp3s0f1.200 (kind vlan, protocol 802.1Q, id 200)

The inventory creates separate endpoint records for both VLAN devices and dependency edges from each VLAN endpoint to enp3s0f1. A policy may expose macvlan/macvtap personas rooted at VLAN 100 and an ipvlan persona rooted at VLAN 200:

domain(root=enp3s0f1.100, interface-mode): macvlan [mac-family], macvtap [mac-family]
domain(root=enp3s0f1.200, interface-mode): ipvlan-l2 [ipvlan-l2]

These children use different immediate lower netdevices, so they do not contend for one receive-handler slot. They need no common interface-mode counter set. They still share the physical PF dependency. Any operation that changes PF MTU, binding, reset state, VLAN offload state, or ownership must pass the protection graph and any required PF-family compatibility domain.

When the driver creates a child after allocation, it records that child in the allocation journal and dependency graph. It does not publish the created child as new free capacity. On restart, discovery correlates the observed child with the journal, allocation identity and lower endpoint before treating it as managed. An unjournaled pre-existing child is external inventory until policy and ownership sources explicitly authorize it.

5.5 Example 5: PF with Macvlan AND Host-Device Passthrough

Scenario: The same interface supports shared macvlan and a normal exclusive passthrough persona. Keep separate entries to make allocation semantics explicit. It is not necessary to claim that capacity can never model a fixed full-capacity request; the selected design simply does not encode mode compatibility through plugin-specific capacity tricks.

DeviceExposurePolicies

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-macvlan
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f0"
  action: expose
  exposure:
    deviceNameSuffix: -macvlan
    allowMultipleAllocations: true
    capacity:
      macvlans:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    supportedNetworkPlugins:
      - name: macvlan
        consumePerAllocation:
          macvlans: '1'
    compatibility:
      - scope: interface
        domain: interface-mode
        groups:
          - macvlan
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-passthrough
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f0"
  action: expose
  exposure:
    deviceNameSuffix: -passthrough
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: host-device
    compatibility:
      - scope: interface
        domain: interface-mode
        groups:
          - passthrough

Resulting ResourceSlice Fragments

Counter-bearing ResourceSlice.spec fragment:

sharedCounters:
  - name: pf0-interface-mode
    counters:
      members:
        value: '2'

Device-bearing ResourceSlice.spec fragment (same pool):

devices:
  - name: enp3s0f0-macvlan
    allowMultipleAllocations: true
    attributes:
      dra.networking/type:
        string: pf
      dra.networking/ifName:
        string: enp3s0f0
      dra.networking/pciAddress:
        string: '0000:03:00.0'
      dra.networking/mac:
        string: 04:3f:72:b0:d4:60
      dra.networking/mtu:
        int: 1500
      dra.networking/linkSpeed:
        int: 100000
      dra.networking/numVFs:
        int: 0
      dra.networking/rdma:
        bool: true
      dra.networking/numaNode:
        int: 0
      dra.networking/vendor:
        string: 15b3
      dra.networking/product:
        string: 101d
      dra.networking/driver:
        string: mlx5_core
      device.k8s.io/pcieRoot:
        string: pci0000:00
      dra.networking/supportedNetworkPlugins:
        strings:
          - macvlan
    capacity:
      dra.networking/macvlans:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    consumesCounters:
      - counterSet: pf0-interface-mode
        compatibilityGroups:
          - macvlan
        counters:
          members:
            value: '1'
  - name: enp3s0f0-passthrough
    attributes:
      dra.networking/type:
        string: pf
      dra.networking/ifName:
        string: enp3s0f0
      dra.networking/pciAddress:
        string: '0000:03:00.0'
      dra.networking/mac:
        string: 04:3f:72:b0:d4:60
      dra.networking/mtu:
        int: 1500
      dra.networking/linkSpeed:
        int: 100000
      dra.networking/numVFs:
        int: 0
      dra.networking/rdma:
        bool: true
      dra.networking/numaNode:
        int: 0
      dra.networking/vendor:
        string: 15b3
      dra.networking/product:
        string: 101d
      dra.networking/driver:
        string: mlx5_core
      device.k8s.io/pcieRoot:
        string: pci0000:00
      dra.networking/supportedNetworkPlugins:
        strings:
          - host-device
    consumesCounters:
      - counterSet: pf0-interface-mode
        compatibilityGroups:
          - passthrough
        counters:
          members:
            value: '1'
Diagram 6 — Dual Device Pattern: macvlan vs host-device passthrough with compatibility group exclusion

Macvlan and passthrough use disjoint groups in the same domain. Passthrough does not drain a mirrored macvlan quota. The same exclusion applies in either allocation order. A second allocation of the passthrough entry is rejected by ordinary device exclusivity.

Multiple exclusive aliases are not safe just because each is individually exclusive. They must also be disjoint from each other in the shared interface domain. Prefer one exclusive entry with several valid NetworkPlugin alternatives when the allocation contract is identical.

5.6 Example 6: PF with VFs + Macvlan + Host-Device

Scenario: PF0 has eight VFs. Shared PF macvlan and child VF use are permitted concurrently. PF passthrough is declared incompatible with either. This is a policy assumption for the reference node, not a blanket hardware claim.

DeviceExposurePolicies

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-macvlan
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f0"
  action: expose
  exposure:
    deviceNameSuffix: -macvlan
    allowMultipleAllocations: true
    capacity:
      macvlans:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    supportedNetworkPlugins:
      - name: macvlan
        consumePerAllocation:
          macvlans: '1'
    compatibility:
      - scope: interface
        domain: interface-mode
        groups:
          - macvlan
      - scope: sriovFamily
        domain: pf-access
        groups:
          - host-retained
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-passthrough
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f0"
  action: expose
  exposure:
    deviceNameSuffix: -passthrough
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: host-device
    compatibility:
      - scope: interface
        domain: interface-mode
        groups:
          - passthrough
      - scope: sriovFamily
        domain: pf-access
        groups:
          - pf-passthrough
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-vfs
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].pfName) &&
      device.attributes["dra.networking"].type == "vf" && device.attributes["dra.networking"].pfName == "enp3s0f0"
  action: expose
  exposure:
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: sriov
      - name: host-device
    compatibility:
      - scope: sriovFamily
        domain: pf-access
        groups:
          - host-retained

Resulting ResourceSlice Fragments

PF0 has ten published member identities in the family: two PF personas and eight VFs. Only the two PF personas belong to its interface-mode domain. The following fragment shows both personas and VF0; Section 6 includes all eight VFs in complete objects.

Counter-bearing ResourceSlice.spec fragment:

sharedCounters:
  - name: pf0-interface-mode
    counters:
      members:
        value: '2'
  - name: pf0-family-pf-access
    counters:
      members:
        value: '10'

Device-bearing ResourceSlice.spec fragment (same pool):

devices:
  - name: enp3s0f0-macvlan
    allowMultipleAllocations: true
    attributes:
      dra.networking/type:
        string: pf
      dra.networking/ifName:
        string: enp3s0f0
      dra.networking/pciAddress:
        string: '0000:03:00.0'
      dra.networking/mac:
        string: 04:3f:72:b0:d4:60
      dra.networking/mtu:
        int: 1500
      dra.networking/linkSpeed:
        int: 100000
      dra.networking/numVFs:
        int: 8
      dra.networking/rdma:
        bool: true
      dra.networking/numaNode:
        int: 0
      dra.networking/vendor:
        string: 15b3
      dra.networking/product:
        string: 101d
      dra.networking/driver:
        string: mlx5_core
      device.k8s.io/pcieRoot:
        string: pci0000:00
      dra.networking/supportedNetworkPlugins:
        strings:
          - macvlan
    capacity:
      dra.networking/macvlans:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    consumesCounters:
      - counterSet: pf0-interface-mode
        compatibilityGroups:
          - macvlan
        counters:
          members:
            value: '1'
      - counterSet: pf0-family-pf-access
        compatibilityGroups:
          - host-retained
        counters:
          members:
            value: '1'
  - name: enp3s0f0-passthrough
    attributes:
      dra.networking/type:
        string: pf
      dra.networking/ifName:
        string: enp3s0f0
      dra.networking/pciAddress:
        string: '0000:03:00.0'
      dra.networking/mac:
        string: 04:3f:72:b0:d4:60
      dra.networking/mtu:
        int: 1500
      dra.networking/linkSpeed:
        int: 100000
      dra.networking/numVFs:
        int: 8
      dra.networking/rdma:
        bool: true
      dra.networking/numaNode:
        int: 0
      dra.networking/vendor:
        string: 15b3
      dra.networking/product:
        string: 101d
      dra.networking/driver:
        string: mlx5_core
      device.k8s.io/pcieRoot:
        string: pci0000:00
      dra.networking/supportedNetworkPlugins:
        strings:
          - host-device
    consumesCounters:
      - counterSet: pf0-interface-mode
        compatibilityGroups:
          - passthrough
        counters:
          members:
            value: '1'
      - counterSet: pf0-family-pf-access
        compatibilityGroups:
          - pf-passthrough
        counters:
          members:
            value: '1'
  - name: enp3s0f0v0
    attributes:
      dra.networking/type:
        string: vf
      dra.networking/ifName:
        string: enp3s0f0v0
      dra.networking/pfName:
        string: enp3s0f0
      dra.networking/vfIndex:
        int: 0
      dra.networking/pciAddress:
        string: '0000:03:00.2'
      dra.networking/numaNode:
        int: 0
      dra.networking/rdma:
        bool: true
      dra.networking/vendor:
        string: 15b3
      dra.networking/product:
        string: 101e
      dra.networking/driver:
        string: mlx5_core
      device.k8s.io/pcieRoot:
        string: pci0000:00
      dra.networking/supportedNetworkPlugins:
        strings:
          - sriov
          - host-device
    consumesCounters:
      - counterSet: pf0-family-pf-access
        compatibilityGroups:
          - host-retained
        counters:
          members:
            value: '1'

Compatibility Matrix

Candidate combinationInterface-mode resultPF-family resultAllowed?
PF macvlan + another share of PF macvlanSame persona/groupHost-retainedYes, within local capacity.
PF macvlan + VF0VF0 is outside interface domainBoth host-retainedYes.
VF0 + VF1Neither uses PF interface domainBoth host-retainedYes.
PF passthrough + PF macvlanDisjointDisjointNo.
PF passthrough + any VFVF outside interface domainDisjointNo.
Another allocation of the same VFNot relevantCompatible groupNo; the VF entry itself is exclusive.

An optional PF ipvlan persona would use [ipvlan] on pf0-interface-mode and [host-retained] on pf0-family-pf-access. VFs need no extra macvlan/ipvlan token. This two-domain construction avoids treating an empty VF group as a wildcard or forcing every VF to enumerate all PF modes.

Diagram 10 — Two-Domain Construction: PF0 with interface-mode and family pf-access domains showing combined compatibility results

All exclusion in this example is group-based. The baseline has no exclusion-slots, no mirrored macvlan capacity and no bandwidth reservation counter. linkSpeed is still published as an attribute.

Scenario: A free VF is directly allocatable after ownership and effect checks. A VF pre-enslaved to a host bridge is not directly allocatable; the bridge is the shared device offered to Pods only when its host owner delegates the approved child-port operations. Bridge ownership is host preconfiguration, not a DRA claim for the hidden VF. The required protection record contains bridge → member VF → relevant PF services; the VF’s empty/nonempty masterBridge attribute is a useful selector, not the whole ownership check.

DeviceExposurePolicies

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: free-vfs-sriov
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].pfName) &&
      has(device.attributes["dra.networking"].masterBridge) &&
      device.attributes["dra.networking"].type == "vf" && device.attributes["dra.networking"].pfName == "enp3s0f0" && device.attributes["dra.networking"].masterBridge == ""
  action: expose
  exposure:
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: sriov
      - name: host-device
    compatibility:
      - scope: sriovFamily
        domain: pf-access
        groups:
          - host-retained
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: exclude-bridge-slave-vfs
spec:
  priority: 900
  selector:
    cel: >-
      has(device.attributes["dra.networking"].masterBridge) &&
      device.attributes["dra.networking"].type == "vf" && device.attributes["dra.networking"].masterBridge != ""
  action: exclude
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: bridge-sriov-data
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "bridge" && device.attributes["dra.networking"].ifName == "br-sriov-data"
  action: expose
  exposure:
    allowMultipleAllocations: true
    capacity:
      ports:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    supportedNetworkPlugins:
      - name: bridge
        consumePerAllocation:
          ports: '1'
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: exclude-pf0-host-bridge-uplink
spec:
  priority: 900
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f0"
  action: exclude

Resulting Bridge Entry

name: br-sriov-data
allowMultipleAllocations: true
attributes:
  dra.networking/type:
    string: bridge
  dra.networking/ifName:
    string: br-sriov-data
  dra.networking/bridgeName:
    string: br-sriov-data
  dra.networking/bridgeType:
    string: linux
  dra.networking/mtu:
    int: 9000
  dra.networking/supportedNetworkPlugins:
    strings:
      - bridge
capacity:
  dra.networking/ports:
    value: '64'
    requestPolicy:
      default: '1'
      validValues:
        - '1'

The final policy deliberately excludes every PF0 persona in this conservative bridge profile. Do not combine it with PF passthrough while the host bridge depends on a child VF. Free sibling VFs can still be exposed under the family policy.

For a free sibling VF, the kernel-interface handoff must be certified not to rebind/reset the PF, reconfigure the eswitch or disturb the bridge-owned VF. If that footprint is unknown or broader, deny publication despite the selector match. Conversely, the PF exclusion does not mean every read or every host-retained operation intrinsically destroys VFs; this example chooses a conservative publication profile.

A hidden VF does not contribute a scheduler compatibility group or consume a counter merely because it is busy outside DRA. Removing one from an advertised quota is not a substitute for an active compatibility declaration. This design does not fabricate a DRA allocation for it. Supporting host reservations with simultaneous PF exposure requires a separate, explicit reservation model; it is outside the baseline.

The node execution path must recheck host ownership before a destructive operation using Section 4.1.5. A newly observed bridge dependency blocks further conflicting use and triggers drain/recovery while active declarations remain pinned. Host-network configuration must be coordinated with DRA: an administrator attaching a bridge to hardware already allocated to a workload is outside the scheduler’s view and cannot be made safe by updating a slice after the fact.

5.8 Example 8: Excluding Cluster CNI and Management Interfaces

Scenario: Named cluster-network and management interfaces are excluded from direct workload allocation. Actual protection also requires owner records and the effect-specific dependency check in Section 4.1; these name filters alone do not protect a lower PF or VF.

DeviceExposurePolicies

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: exclude-cluster-cni
spec:
  priority: 1000
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].ifName in ["br-int", "ovn-k8s-mp0", "breth0", "ovn-k8s-gw0"]
  action: exclude
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: exclude-management
spec:
  priority: 1000
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].ifName == "eno1"
  action: exclude

Unallocated matching interfaces are absent from desired publication. Exclusions win regardless of priority. In addition, protect the administrator-approved management/primary-network roots and resolve their dependencies independently of these filters. If management lives on mgmt.100 → bond0 → enp3s0f0, moving the PF or rebinding its function is denied even when only mgmt.100 is named in an exclusion. A primary-CNI-owned representor requires its controller’s ownership record; an unfamiliar name is not free inventory. Missing relevant route/controller coverage makes the candidate unavailable.

If a newly added exclusion or protected dependency affects an already-allocated device, transition it to drain handling and preserve the active declaration; do not interpret the policy as permission to destroy the running workload’s inventory or network state. A verified rename follows the persisted identity so it does not escape protection.

A hard emergency shutdown is an explicit administrative recovery action, not the ordinary reconciliation behavior.

5.9 Example 9: OVN-Kubernetes Networks via the Generic Driver

Scenario retained as a proposed integration, not an established capability. The examples use ovn as the logical NetworkPlugin identity for a proposed gRPC adapter handling an exclusive VF or shared localnet uplink. Advertise that capability only after the adapter implements and validates the required control-plane and execution contract. The existing ovn-k8s-cni-overlay binary is not the identity or protocol of this adapter.

DeviceExposurePolicy — Candidate Accelerated VF Integration

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: ovnk-accelerated-vfs
spec:
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].pfName) &&
      device.attributes["dra.networking"].type == "vf" && device.attributes["dra.networking"].pfName == "enp4s0f0"
  action: expose
  exposure:
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: ovn
    compatibility:
      - scope: sriovFamily
        domain: pf-access
        groups:
          - host-retained
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: ovnk-localnet-uplink
spec:
  priority: 150
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp6s0f0"
  action: expose
  exposure:
    deviceNameSuffix: -localnet
    allowMultipleAllocations: true
    capacity:
      connections:
        value: '128'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    supportedNetworkPlugins:
      - name: ovn
        consumePerAllocation:
          connections: '1'
    additionalAttributes:
      dra.networking/physicalNetworkName: localnet1

Resulting Device Fragments

devices:
  - name: enp4s0f0v0
    attributes:
      dra.networking/type:
        string: vf
      dra.networking/ifName:
        string: enp4s0f0v0
      dra.networking/pfName:
        string: enp4s0f0
      dra.networking/pciAddress:
        string: '0000:04:00.2'
      dra.networking/numaNode:
        int: 0
      device.k8s.io/pcieRoot:
        string: pci0000:00
      dra.networking/supportedNetworkPlugins:
        strings:
          - ovn
    consumesCounters:
      - counterSet: pf4-family-pf-access
        compatibilityGroups:
          - host-retained
        counters:
          members:
            value: '1'
  - name: enp6s0f0-localnet
    allowMultipleAllocations: true
    attributes:
      dra.networking/type:
        string: pf
      dra.networking/ifName:
        string: enp6s0f0
      dra.networking/numaNode:
        int: 1
      dra.networking/physicalNetworkName:
        string: localnet1
      device.k8s.io/pcieRoot:
        string: pci0000:00
      dra.networking/supportedNetworkPlugins:
        strings:
          - ovn
    capacity:
      dra.networking/connections:
        value: '128'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
Diagram 7 — OVN-Kubernetes Integration via Generic Driver: accelerated VF and localnet uplink paths

These entries belong in their respective pools. The VF’s pool must also publish the referenced family counter set with a non-binding membership total for its complete inventory; the standalone localnet example has no competing persona and needs no domain.

Network selection metadata such as physicalNetworkName belongs in published attributes. Strict ovn NetworkPlugin configuration and typed inputs belong to the companion NetworkTopology/execution contract. The integration work must separately verify network-controller provisioning, required annotations and identities, representor ownership, VF handoff, namespace timing, input/output types, effect ownership, cleanup and restart behavior. Reusing existing OVN or CNI implementation code does not change the adapter’s public contract.

Until those checks pass, remove claims such as “no separate OVN-K DRA driver is needed” or “our driver invokes it just like any other plugin” from the implementation guarantees. The discovery policy remains generic; external control-plane integration is not automatically generic.

5.10 Example 10: Maximal PF and VF Multi-Persona Pool

Scenario: PF enp3s0f0 has two VFs. The PF supports shared macvlan, ipvlan, vlan, and macvtap child creation, plus exclusive whole-PF passthrough through the logical host-device plugin. Each VF supports exclusive sriov handoff or shared macvlan, ipvlan, vlan, and macvtap child creation. All ipvlan personas use the pinned l2/bridge contract; all macvlan/macvtap personas use non-passthru bridge mode.

This example uses every available domain association on every persona:

  1. An interface domain protects alternative uses of the immediate lower netdevice.
  2. One PF-family domain makes PF passthrough incompatible with every host-retained PF or VF persona.

The example models two VFs to keep the complete output reviewable. Additional VFs repeat the five VF policies and device entries with their own interface counter set, while joining the same family counter set.

Discovered Inventory

PF0  enp3s0f0    0000:03:00.0  presenceEpoch 11
 +-- VF0 enp3s0f0v0  0000:03:00.2  presenceEpoch 4
 `-- VF1 enp3s0f0v1  0000:03:00.3  presenceEpoch 6

Verified relationships:
  enp3s0f0v0 -> PF0 family
  enp3s0f0v1 -> PF0 family
  no existing software uppers
  no receive-handler owner on any of the three immediate lowers

The scanner discovers three hardware-backed endpoints and their PF/VF relationship. Policies create fifteen personas; discovery does not mistake those personas for fifteen physical devices.

Complete Policy Set

Five PF policies select type == "pf" && ifName == "enp3s0f0". Five VF policies select type == "vf" && pfName == "enp3s0f0". Each VF policy produces one persona for each matching VF.

The matrix below is normative shorthand for the ten DeviceExposurePolicy objects. All have priority: 200, action: expose, and the selector for their target row. Each shared row sets allowMultipleAllocations: true, the shown capacity with default: "1" and validValues: ["1"], and matching consumePerAllocation: "1". Exclusive rows set allowMultipleAllocations: false and no local capacity. Mode values are validated additionalAttributes tied to the immutable NetworkPlugin revision.

TargetSuffix / pluginSharing and local quotaInterface groupsFamily group
PF-vlan / vlanShared, 64[mac-family, ipvlan-l2][host-retained]
PF-ipvlan-l2 / ipvlanShared, 64; fixed l2/bridge[ipvlan-l2][host-retained]
PF-macvlan / macvlanShared, 64; fixed bridge[mac-family][host-retained]
PF-macvtap / macvtapShared, 64; fixed bridge[mac-family][host-retained]
PF-passthrough / host-deviceExclusive[passthrough][pf-passthrough]
Each VF-sriov / sriovExclusive[sriov][host-retained]
Each VF-vlan / vlanShared, 16[mac-family, ipvlan-l2][host-retained]
Each VF-ipvlan-l2 / ipvlanShared, 16; fixed l2/bridge[ipvlan-l2][host-retained]
Each VF-macvlan / macvlanShared, 16; fixed bridge[mac-family][host-retained]
Each VF-macvtap / macvtapShared, 16; fixed bridge[mac-family][host-retained]

PF policies bind scope: interface plus scope: sriovFamily. VF policies do the same: interface resolves to that VF endpoint, while sriovFamily resolves to PF0. Mode attributes shown below come from the approved policy/NetworkPlugin revision.

Complete Resulting ResourceSlices

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: worker-1-pf0-maximal-counters
spec:
  driver: dra.networking
  pool:
    name: worker-1-pf0-maximal
    generation: 1
    resourceSliceCount: 2
  nodeName: worker-1
  sharedCounters:
    - name: pf0-interface-mode
      counters:
        members:
          value: '5'
    - name: pf0vf0-interface-mode
      counters:
        members:
          value: '5'
    - name: pf0vf1-interface-mode
      counters:
        members:
          value: '5'
    - name: pf0-family-pf-access
      counters:
        members:
          value: '15'
---
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: worker-1-pf0-maximal-devices
spec:
  driver: dra.networking
  pool:
    name: worker-1-pf0-maximal
    generation: 1
    resourceSliceCount: 2
  nodeName: worker-1
  devices:
    - name: enp3s0f0-vlan
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: pf}
        dra.networking/ifName: {string: enp3s0f0}
        dra.networking/supportedNetworkPlugins: {strings: [vlan]}
      capacity:
        dra.networking/vlans:
          value: '64'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0-interface-mode
          compatibilityGroups: [mac-family, ipvlan-l2]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0-ipvlan-l2
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: pf}
        dra.networking/ifName: {string: enp3s0f0}
        dra.networking/ipvlanMode: {string: l2}
        dra.networking/ipvlanFlags: {string: bridge}
        dra.networking/supportedNetworkPlugins: {strings: [ipvlan]}
      capacity:
        dra.networking/ipvlans:
          value: '64'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0-interface-mode
          compatibilityGroups: [ipvlan-l2]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0-macvlan
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: pf}
        dra.networking/ifName: {string: enp3s0f0}
        dra.networking/macvlanMode: {string: bridge}
        dra.networking/supportedNetworkPlugins: {strings: [macvlan]}
      capacity:
        dra.networking/macvlans:
          value: '64'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0-interface-mode
          compatibilityGroups: [mac-family]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0-macvtap
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: pf}
        dra.networking/ifName: {string: enp3s0f0}
        dra.networking/macvlanMode: {string: bridge}
        dra.networking/supportedNetworkPlugins: {strings: [macvtap]}
      capacity:
        dra.networking/macvtaps:
          value: '64'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0-interface-mode
          compatibilityGroups: [mac-family]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0-passthrough
      attributes:
        dra.networking/type: {string: pf}
        dra.networking/ifName: {string: enp3s0f0}
        dra.networking/supportedNetworkPlugins: {strings: [host-device]}
      consumesCounters:
        - counterSet: pf0-interface-mode
          compatibilityGroups: [passthrough]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [pf-passthrough]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v0-sriov
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v0}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 0}
        dra.networking/supportedNetworkPlugins: {strings: [sriov]}
      consumesCounters:
        - counterSet: pf0vf0-interface-mode
          compatibilityGroups: [sriov]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v0-vlan
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v0}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 0}
        dra.networking/supportedNetworkPlugins: {strings: [vlan]}
      capacity:
        dra.networking/vlans:
          value: '16'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0vf0-interface-mode
          compatibilityGroups: [mac-family, ipvlan-l2]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v0-ipvlan-l2
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v0}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 0}
        dra.networking/ipvlanMode: {string: l2}
        dra.networking/ipvlanFlags: {string: bridge}
        dra.networking/supportedNetworkPlugins: {strings: [ipvlan]}
      capacity:
        dra.networking/ipvlans:
          value: '16'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0vf0-interface-mode
          compatibilityGroups: [ipvlan-l2]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v0-macvlan
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v0}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 0}
        dra.networking/macvlanMode: {string: bridge}
        dra.networking/supportedNetworkPlugins: {strings: [macvlan]}
      capacity:
        dra.networking/macvlans:
          value: '16'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0vf0-interface-mode
          compatibilityGroups: [mac-family]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v0-macvtap
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v0}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 0}
        dra.networking/macvlanMode: {string: bridge}
        dra.networking/supportedNetworkPlugins: {strings: [macvtap]}
      capacity:
        dra.networking/macvtaps:
          value: '16'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0vf0-interface-mode
          compatibilityGroups: [mac-family]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v1-sriov
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v1}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 1}
        dra.networking/supportedNetworkPlugins: {strings: [sriov]}
      consumesCounters:
        - counterSet: pf0vf1-interface-mode
          compatibilityGroups: [sriov]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v1-vlan
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v1}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 1}
        dra.networking/supportedNetworkPlugins: {strings: [vlan]}
      capacity:
        dra.networking/vlans:
          value: '16'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0vf1-interface-mode
          compatibilityGroups: [mac-family, ipvlan-l2]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v1-ipvlan-l2
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v1}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 1}
        dra.networking/ipvlanMode: {string: l2}
        dra.networking/ipvlanFlags: {string: bridge}
        dra.networking/supportedNetworkPlugins: {strings: [ipvlan]}
      capacity:
        dra.networking/ipvlans:
          value: '16'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0vf1-interface-mode
          compatibilityGroups: [ipvlan-l2]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v1-macvlan
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v1}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 1}
        dra.networking/macvlanMode: {string: bridge}
        dra.networking/supportedNetworkPlugins: {strings: [macvlan]}
      capacity:
        dra.networking/macvlans:
          value: '16'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0vf1-interface-mode
          compatibilityGroups: [mac-family]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

    - name: enp3s0f0v1-macvtap
      allowMultipleAllocations: true
      attributes:
        dra.networking/type: {string: vf}
        dra.networking/ifName: {string: enp3s0f0v1}
        dra.networking/pfName: {string: enp3s0f0}
        dra.networking/vfIndex: {int: 1}
        dra.networking/macvlanMode: {string: bridge}
        dra.networking/supportedNetworkPlugins: {strings: [macvtap]}
      capacity:
        dra.networking/macvtaps:
          value: '16'
          requestPolicy: {default: '1', validValues: ['1']}
      consumesCounters:
        - counterSet: pf0vf1-interface-mode
          compatibilityGroups: [mac-family]
          counters: {members: {value: '1'}}
        - counterSet: pf0-family-pf-access
          compatibilityGroups: [host-retained]
          counters: {members: {value: '1'}}

The output stays within the pinned API limits: four shared counter sets in the counter slice, fifteen advanced-feature devices in the device slice, exactly two counter-set consumptions per device, and at most two groups per consumption. The family members: 15 total counts published identities: five PF personas plus five personas for each of two VFs.

Kubernetes 1.37 Feasibility

The manifests fit the Kubernetes 1.37 API limits, but they do not work on an unmodified default 1.37 installation. DRADeviceCompatibilityGroups is alpha and disabled by default. DRAListTypeAttributes, used by supportedNetworkPlugins.strings, is also alpha and disabled by default. DRAPartitionableDevices and DRAConsumableCapacity are beta and enabled by default in 1.37. The API server and scheduler must enable the two alpha gates consistently; the target distribution must expose and support that configuration. S25

Upstream limit or dependencyExample 10 usageResult
Counter sets per counter-bearing slice: 84Fits.
Advanced-feature devices per device-bearing slice: 6415Fits.
consumesCounters entries per device: 22Fits exactly; no third independent domain remains.
compatibilityGroups per consumption: 2VLAN personas use 2; all others use 1Fits exactly; another neutral compatibility family would not fit.
Counters per consumption: 321Fits.
Attributes plus capacities per device: 32At most 8 in the shown entriesFits.
DRADeviceCompatibilityGroupsRequiredAlpha, disabled by default.
DRAListTypeAttributesRequired by the list-valued plugin attributeAlpha, disabled by default.
DRAPartitionableDevicesRequired by sharedCounters/consumesCountersBeta, enabled by default.
DRAConsumableCapacityRequired by shared persona capacityBeta, enabled by default.

Example 10 therefore sits on both semantic ceilings without crossing them:

  • Every persona already uses both domain entries. Adding a third independent reset/controller/eswitch domain fails validation unless an exact merge removes another domain.
  • Every VLAN persona already uses both group tokens. Supporting both ipvlan L2 and ipvlan L3 as separate incompatible alternatives would require a third VLAN token and fails validation.
  • Adding more VFs does not consume more domains or groups per device. It does create one extra interface counter set and five extra device identities per VF. For N VFs this example has N + 2 counter sets and 5(N + 1) devices. Once either per-slice limit is exceeded, the driver can shard counter sets and devices across more ResourceSlices in the same pool; that is a packing change, not a semantic workaround.

There is also a current allocator correctness risk outside static API validation. Kubernetes issue #140802 reports that removing an allocated device from a republished pool, or changing its counter associations, can make its counter and compatibility contribution disappear from allocator state. This design’s stable-publication and drain rules avoid that mutation during normal operation, but operational discipline is not proof that the alpha implementation is fixed. Production use requires a Kubernetes build where the issue is resolved or an explicit conformance test showing the selected build fails closed for removal, mutation, restart and partial-generation cases. S26

Therefore the API encoding is feasible, but the complete system is conditional: required gates enabled, no unsupported downstream field stripping, stable publication preserved, the allocator issue addressed or proven contained, and the driver/NetworkPlugin execution paths implemented and tested. Kubernetes only schedules the declared identities; it does not create VLAN, ipvlan, macvlan, macvtap or passthrough links for this custom design.

Compatibility Outcomes

Active allocationCandidateResult and enforcing domain
PF macvlanPF macvtapPermit; both retain mac-family and host-retained.
PF macvlanPF ipvlanReject in pf0-interface-mode.
PF VLANPF macvlan or PF ipvlanPermit through VLAN’s matching alternative group.
VF0 sriovAny other VF0 personaReject in pf0vf0-interface-mode.
VF0 macvlanVF0 macvtapPermit in VF0 interface domain.
VF0 macvlanVF0 ipvlanReject in VF0 interface domain.
VF0 macvlanVF1 ipvlanPermit; different immediate lowers and interface domains.
PF ipvlanVF0 macvlan and VF1 sriovPermit; all share host-retained in the family domain.
Any PF non-passthru or VF personaPF passthroughReject in pf0-family-pf-access.
PF passthroughAny PF non-passthru personaReject in both PF interface and family domains.
PF passthroughAny VF personaReject in the family domain.

The family predicate blocks PF passthrough while any VF persona remains allocated, including a shared child persona with one or more live claims. Releasing one share does not unblock passthrough while another share remains.

Published but idle VF personas do not block PF passthrough: compatibility groups constrain active allocations, not mere inventory. If policy requires PF passthrough to remain unavailable whenever VFs are configured or published, omit the PF passthrough persona or reject it during compilation. Do not rely on compatibility groups for that stronger rule.

Allocation-time compatibility is only the scheduler guard. Before preparing PF passthrough, the execution profile must verify zero active VF/PF-child allocations, complete cleanup, external ownership, configured VF teardown requirements, representors, reset effects and identity continuity. If safe PF takeover cannot be certified, do not publish the passthrough persona.


6. Complete Reference Node

6.1 Node Inventory

Node worker-1 uses the same illustrative inventory as the original design:

DeviceInterfaceTypePCI / topologySpeedNUMARole
PF0enp3s0f0PF0000:03:00.0100 GbE0Two personas, eight VFs.
PF1enp3s0f1PF0000:03:00.125 GbE0Passthrough persona, four VFs.
PF0 VFsenp3s0f0v0 through enp3s0f0v7VFEnumerated addresses belowShared link0Exclusive sriov/host-device alternatives.
PF1 VFsenp3s0f1v0 through enp3s0f1v3VFEnumerated addresses belowShared link0Exclusive sriov/host-device alternatives.
Data bridgebr-dataLinux bridgeNo PCI identity in this exampleNot specifiedNot specifiedShared bridge ports.
Managementeno1NICNot exposedNot relevantNot specifiedExcluded.
Cluster networkingbr-int, ovn-k8s-mp0InfrastructureNot exposedNot relevantNot specifiedExcluded.
Diagram 8 — Complete Reference Node Topology: worker-1 with PF0, PF1, bridge, excluded interfaces, 5 ResourceSlices, 16 device entries

Before publishing this reference state, Section 4.1’s ownership sources and effect checks must verify that no protected host dependency intersects the passthrough footprints. A complete graph and explicit data-bridge child-port delegation are prerequisites, not facts established by the sample interface names or YAML. Unknown coverage prevents publication. The host-bridge/VF profile in Example 7 has different ownership/exclusion inputs and must not be blindly merged into this reference profile.

6.2 Complete DeviceExposurePolicy Set

These eight proposed policy resources are scoped to the reference node. The policy API itself must be installed by the future implementation; these are not replacements for a CRD manifest.

apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: exclude-cluster-cni
spec:
  nodeSelector:
    matchLabels:
      kubernetes.io/hostname: worker-1
  priority: 1000
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].ifName in ["br-int", "ovn-k8s-mp0", "breth0", "ovn-k8s-gw0"]
  action: exclude
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: exclude-management
spec:
  nodeSelector:
    matchLabels:
      kubernetes.io/hostname: worker-1
  priority: 1000
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].ifName == "eno1"
  action: exclude
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-macvlan
spec:
  nodeSelector:
    matchLabels:
      kubernetes.io/hostname: worker-1
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f0"
  action: expose
  exposure:
    deviceNameSuffix: -macvlan
    allowMultipleAllocations: true
    capacity:
      macvlans:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    supportedNetworkPlugins:
      - name: macvlan
        consumePerAllocation:
          macvlans: '1'
    compatibility:
      - scope: interface
        domain: interface-mode
        groups:
          - macvlan
      - scope: sriovFamily
        domain: pf-access
        groups:
          - host-retained
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-passthrough
spec:
  nodeSelector:
    matchLabels:
      kubernetes.io/hostname: worker-1
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f0"
  action: expose
  exposure:
    deviceNameSuffix: -passthrough
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: host-device
    compatibility:
      - scope: interface
        domain: interface-mode
        groups:
          - passthrough
      - scope: sriovFamily
        domain: pf-access
        groups:
          - pf-passthrough
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf0-vfs
spec:
  nodeSelector:
    matchLabels:
      kubernetes.io/hostname: worker-1
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].pfName) &&
      device.attributes["dra.networking"].type == "vf" && device.attributes["dra.networking"].pfName == "enp3s0f0"
  action: expose
  exposure:
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: sriov
      - name: host-device
    compatibility:
      - scope: sriovFamily
        domain: pf-access
        groups:
          - host-retained
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf1-passthrough
spec:
  nodeSelector:
    matchLabels:
      kubernetes.io/hostname: worker-1
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f1"
  action: expose
  exposure:
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: host-device
    compatibility:
      - scope: sriovFamily
        domain: pf-access
        groups:
          - pf-passthrough
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: pf1-vfs
spec:
  nodeSelector:
    matchLabels:
      kubernetes.io/hostname: worker-1
  priority: 200
  selector:
    cel: >-
      has(device.attributes["dra.networking"].pfName) &&
      device.attributes["dra.networking"].type == "vf" && device.attributes["dra.networking"].pfName == "enp3s0f1"
  action: expose
  exposure:
    allowMultipleAllocations: false
    supportedNetworkPlugins:
      - name: sriov
      - name: host-device
    compatibility:
      - scope: sriovFamily
        domain: pf-access
        groups:
          - host-retained
---
apiVersion: networking.dra.io/v1alpha1
kind: DeviceExposurePolicy
metadata:
  name: bridge-br-data
spec:
  nodeSelector:
    matchLabels:
      kubernetes.io/hostname: worker-1
  priority: 150
  selector:
    cel: >-
      has(device.attributes["dra.networking"].ifName) &&
      device.attributes["dra.networking"].type == "bridge" && device.attributes["dra.networking"].ifName == "br-data"
  action: expose
  exposure:
    allowMultipleAllocations: true
    capacity:
      ports:
        value: '64'
        requestPolicy:
          default: '1'
          validValues:
            - '1'
    supportedNetworkPlugins:
      - name: bridge
        consumePerAllocation:
          ports: '1'

6.3 Resulting ResourceSlices

There are five ResourceSlice objects, not three. Each PF pool has one counter-bearing slice and one device-bearing slice. The standalone bridge needs only a device-bearing slice. Every VF is included; there are no omitted placeholder devices in this reference output.

PF0 Pool — Counter Slice and Device Slice

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: worker-1-sriov-pf0-counters
spec:
  driver: dra.networking
  pool:
    name: worker-1-sriov-pf0
    generation: 1
    resourceSliceCount: 2
  nodeName: worker-1
  sharedCounters:
    - name: pf0-interface-mode
      counters:
        members:
          value: '2'
    - name: pf0-family-pf-access
      counters:
        members:
          value: '10'
---
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: worker-1-sriov-pf0-devices
spec:
  driver: dra.networking
  pool:
    name: worker-1-sriov-pf0
    generation: 1
    resourceSliceCount: 2
  nodeName: worker-1
  devices:
    - name: enp3s0f0-macvlan
      allowMultipleAllocations: true
      attributes:
        dra.networking/type:
          string: pf
        dra.networking/ifName:
          string: enp3s0f0
        dra.networking/pciAddress:
          string: '0000:03:00.0'
        dra.networking/mac:
          string: 04:3f:72:b0:d4:60
        dra.networking/mtu:
          int: 1500
        dra.networking/linkSpeed:
          int: 100000
        dra.networking/numVFs:
          int: 8
        dra.networking/rdma:
          bool: true
        dra.networking/numaNode:
          int: 0
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101d
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - macvlan
      capacity:
        dra.networking/macvlans:
          value: '64'
          requestPolicy:
            default: '1'
            validValues:
              - '1'
      consumesCounters:
        - counterSet: pf0-interface-mode
          compatibilityGroups:
            - macvlan
          counters:
            members:
              value: '1'
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f0-passthrough
      attributes:
        dra.networking/type:
          string: pf
        dra.networking/ifName:
          string: enp3s0f0
        dra.networking/pciAddress:
          string: '0000:03:00.0'
        dra.networking/mac:
          string: 04:3f:72:b0:d4:60
        dra.networking/mtu:
          int: 1500
        dra.networking/linkSpeed:
          int: 100000
        dra.networking/numVFs:
          int: 8
        dra.networking/rdma:
          bool: true
        dra.networking/numaNode:
          int: 0
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101d
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - host-device
      consumesCounters:
        - counterSet: pf0-interface-mode
          compatibilityGroups:
            - passthrough
          counters:
            members:
              value: '1'
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - pf-passthrough
          counters:
            members:
              value: '1'
    - name: enp3s0f0v0
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f0v0
        dra.networking/pfName:
          string: enp3s0f0
        dra.networking/vfIndex:
          int: 0
        dra.networking/pciAddress:
          string: '0000:03:00.2'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f0v1
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f0v1
        dra.networking/pfName:
          string: enp3s0f0
        dra.networking/vfIndex:
          int: 1
        dra.networking/pciAddress:
          string: '0000:03:00.3'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f0v2
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f0v2
        dra.networking/pfName:
          string: enp3s0f0
        dra.networking/vfIndex:
          int: 2
        dra.networking/pciAddress:
          string: '0000:03:00.4'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f0v3
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f0v3
        dra.networking/pfName:
          string: enp3s0f0
        dra.networking/vfIndex:
          int: 3
        dra.networking/pciAddress:
          string: '0000:03:00.5'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f0v4
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f0v4
        dra.networking/pfName:
          string: enp3s0f0
        dra.networking/vfIndex:
          int: 4
        dra.networking/pciAddress:
          string: '0000:03:00.6'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f0v5
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f0v5
        dra.networking/pfName:
          string: enp3s0f0
        dra.networking/vfIndex:
          int: 5
        dra.networking/pciAddress:
          string: '0000:03:00.7'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f0v6
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f0v6
        dra.networking/pfName:
          string: enp3s0f0
        dra.networking/vfIndex:
          int: 6
        dra.networking/pciAddress:
          string: '0000:03:01.0'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f0v7
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f0v7
        dra.networking/pfName:
          string: enp3s0f0
        dra.networking/vfIndex:
          int: 7
        dra.networking/pciAddress:
          string: '0000:03:01.1'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf0-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'

PF1 Pool — Counter Slice and Device Slice

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: worker-1-sriov-pf1-counters
spec:
  driver: dra.networking
  pool:
    name: worker-1-sriov-pf1
    generation: 1
    resourceSliceCount: 2
  nodeName: worker-1
  sharedCounters:
    - name: pf1-family-pf-access
      counters:
        members:
          value: '5'
---
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: worker-1-sriov-pf1-devices
spec:
  driver: dra.networking
  pool:
    name: worker-1-sriov-pf1
    generation: 1
    resourceSliceCount: 2
  nodeName: worker-1
  devices:
    - name: enp3s0f1
      attributes:
        dra.networking/type:
          string: pf
        dra.networking/ifName:
          string: enp3s0f1
        dra.networking/pciAddress:
          string: '0000:03:00.1'
        dra.networking/mac:
          string: 04:3f:72:b0:d4:61
        dra.networking/mtu:
          int: 1500
        dra.networking/linkSpeed:
          int: 25000
        dra.networking/numVFs:
          int: 4
        dra.networking/rdma:
          bool: true
        dra.networking/numaNode:
          int: 0
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101d
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - host-device
      consumesCounters:
        - counterSet: pf1-family-pf-access
          compatibilityGroups:
            - pf-passthrough
          counters:
            members:
              value: '1'
    - name: enp3s0f1v0
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f1v0
        dra.networking/pfName:
          string: enp3s0f1
        dra.networking/vfIndex:
          int: 0
        dra.networking/pciAddress:
          string: '0000:03:01.2'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf1-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f1v1
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f1v1
        dra.networking/pfName:
          string: enp3s0f1
        dra.networking/vfIndex:
          int: 1
        dra.networking/pciAddress:
          string: '0000:03:01.3'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf1-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f1v2
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f1v2
        dra.networking/pfName:
          string: enp3s0f1
        dra.networking/vfIndex:
          int: 2
        dra.networking/pciAddress:
          string: '0000:03:01.4'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf1-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'
    - name: enp3s0f1v3
      attributes:
        dra.networking/type:
          string: vf
        dra.networking/ifName:
          string: enp3s0f1v3
        dra.networking/pfName:
          string: enp3s0f1
        dra.networking/vfIndex:
          int: 3
        dra.networking/pciAddress:
          string: '0000:03:01.5'
        dra.networking/numaNode:
          int: 0
        dra.networking/rdma:
          bool: true
        dra.networking/vendor:
          string: 15b3
        dra.networking/product:
          string: 101e
        dra.networking/driver:
          string: mlx5_core
        device.k8s.io/pcieRoot:
          string: pci0000:00
        dra.networking/supportedNetworkPlugins:
          strings:
            - sriov
            - host-device
      consumesCounters:
        - counterSet: pf1-family-pf-access
          compatibilityGroups:
            - host-retained
          counters:
            members:
              value: '1'

Standalone Bridge Pool

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: worker-1-bridge-br-data
spec:
  driver: dra.networking
  pool:
    name: worker-1-bridge-br-data
    generation: 1
    resourceSliceCount: 1
  nodeName: worker-1
  devices:
    - name: br-data
      allowMultipleAllocations: true
      attributes:
        dra.networking/type:
          string: bridge
        dra.networking/ifName:
          string: br-data
        dra.networking/bridgeName:
          string: br-data
        dra.networking/bridgeType:
          string: linux
        dra.networking/mtu:
          int: 9000
        dra.networking/vlanFiltering:
          bool: true
        dra.networking/supportedNetworkPlugins:
          strings:
            - bridge
      capacity:
        dra.networking/ports:
          value: '64'
          requestPolicy:
            default: '1'
            validValues:
              - '1'

6.4 Summary

PoolResourceSlice objectsDevice entriesCompatibility domains
worker-1-sriov-pf0210: two PF personas and eight VFspf0-interface-mode has members=2; pf0-family-pf-access has members=10.
worker-1-sriov-pf125: one PF persona and four VFspf1-family-pf-access has members=5.
worker-1-bridge-br-data11None.
Total516Three counter sets across the two PF counter slices.

Not published: management and cluster-network interfaces selected by exclusion policies. Speeds remain attributes; there is no bandwidth reservation in these baseline manifests.

The numerical member totals accommodate all published identities, including incompatible alternatives. They are deliberately not the source of mutual exclusion.

6.5 App Developer Experience

The platform administers exposure policy and DeviceClasses. Applications reference a class, normally through a ResourceClaimTemplate. The companion NetworkTopology controller may generate those classes, but the discovery implementation does not rely on unverified hidden capacity injection.

The following DeviceClass shows the actual selection logic for the reference PF0 macvlan entry. The VF class is included for the optional bandwidth fragment and future examples. Driver and attribute domains are illustrative; a production project must select its owned driver domain consistently.

apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
  name: network-macvlan-pf0
spec:
  selectors:
    - cel:
        expression: device.driver == "dra.networking" && has(device.attributes["dra.networking"].ifName) && device.allowMultipleAllocations == true && device.attributes["dra.networking"].type
          == "pf" && device.attributes["dra.networking"].ifName == "enp3s0f0" && device.attributes["dra.networking"].supportedNetworkPlugins.includes("macvlan")
---
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
  name: network-vf-pf0
spec:
  selectors:
    - cel:
        expression: device.driver == "dra.networking" && has(device.attributes["dra.networking"].pfName) && device.allowMultipleAllocations == false && device.attributes["dra.networking"].type
          == "vf" && device.attributes["dra.networking"].pfName == "enp3s0f0" && device.attributes["dra.networking"].supportedNetworkPlugins.includes("sriov")
---
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: my-app-network
  namespace: default
spec:
  spec:
    devices:
      requests:
        - name: net
          exactly:
            deviceClassName: network-macvlan-pf0
            allocationMode: ExactCount
            count: 1

No explicit capacity request is needed for this baseline: the selected device’s local policy reserves one macvlan unit. Class-origin TopologyRootConfiguration and NetworkPlugin configuration belong to the companion topology integration contract, not new standard fields on a ResourceClaim. The selectors above demonstrate the allocation layer only; they do not provide the complete root bindings or execution configuration from the companion proposal. S7 S9

Claims that combine two VF requests, as in the original bonded-RDMA application example, follow the same class-reference pattern. Their network topology and distinct-device/topology constraints must be generated and tested by the companion controller rather than assumed from request names.


7. Decisions and Remaining Questions

The original consume-once question is no longer a blocker: mode exclusion uses compatibility groups. Remaining implementation choices are recorded separately from resolved API behavior.

TopicDecision / remaining work
Mode exclusionResolved: KEP 5963 with explicit scoped group bindings. No mirrored-capacity cross-drain.
PF/VF interactionExplicit family policy. The reference permits host-retained PF macvlan plus VFs and excludes PF passthrough. Hardware support and cleanup remain platform test requirements.
Macvlan/bridge capacity discoveryAdministrator supplied. The driver does not invent maximum counts.
Default local consumptionExplicit local request policies provide one-unit defaults. Validate round-trip behavior and actual allocator results in tests.
Shared-allocation identityLog the claim’s metadata UID, request, driver/pool/device and result shareID when present. Do not claim that a claim UID is a field inside every AllocationResult.
Cross-pool associationsNot supported by this design. A common compatibility domain must be placed in one pool.
Dynamic VF count / device disappearanceNeeds allocation-aware drain and identity retention. Generation changes alone do not make hardware reconfiguration safe.
Bridge creationDiscovery-only in the initial implementation. Host topology changes require coordination.
List-attribute fallbackInitial list-based profile requires its feature gate. No substring-based comma-separated fallback. A reduced exact-scalar profile would need a separate schema/selector contract.
Policy validationLocal admission validation plus node-level whole-pool checks. Normal exclusive policies without capacity are valid.
Shared bandwidthFollow-on feature requiring an explicit budget policy schema, target PR/version integration and accounting/enforcement tests.
OVN-K integrationProposed example only; requires end-to-end control-plane and execution validation.
Cold inventory and identitySection 4.1 defines PCI-first records, optional endpoints, presence epochs and uncertainty/recovery rules. Implement storage/correlation and collision-checked DNS encoding; hardware continuity is not inferred from BDF/MAC.
Protected host dependenciesSection 4.1 defines owner inputs, typed graph direction and effect-specific checks. Implement adapters and certify each profile before publication; incomplete relevant coverage denies new use.
Deployment targetPin Kubernetes/client libraries and determine supported OpenShift feature configuration. Do not infer support from generic Kubernetes version numbers.

8. Lifecycle, Reconciliation and Safety Contract

8.1 Why Active Publication Must Be Preserved

The inspected KEP 5963 implementation reads groups from live device declarations. Removing an allocated device from the inventory removes its contribution to the compatibility baseline. Changing its groups changes the baseline used for future allocations. These are implementation facts, not behavior this driver should rely on to switch a mode in use. S3 S4

The driver must pin the active publication contract: device and pool identities, domain associations, group tokens, sharing semantics, NetworkPlugin alternatives and relevant execution/capacity configuration. Store enough committed publication and node execution state to recover this contract after restart; a fresh scan of the host namespace is insufficient when devices have been moved.

Policy state is desired state. It is not permission to mutate the meaning of an already allocated device. A new desired contract becomes active only after a safe transition.

8.2 Drain Protocol

A change that removes a persona, changes its groups, switches sharing semantics, changes a scope root, renames an active identity, or replaces physical hardware enters a drain workflow:

  1. Record the desired change and keep the previous active declaration.
  2. Prevent new admissions into the affected transition through the deployment’s maintenance/admission mechanism; optionally mark retained devices NoSchedule without evicting running Pods.
  3. Wait for allocated claims, in-flight preparation and node cleanup to reconcile. Recheck before committing a new generation.
  4. Publish the new complete model and retire the old one only when safe.
Diagram 11 — Drain Protocol Flow: safe transition steps from trigger through record, block, wait, and publish

A NoSchedule taint can be tolerated by a claim. It is an operational aid, not a security boundary or proof that there are no in-flight allocations. Preventing bypass requires appropriate admission/RBAC policy, and scheduler/watch races still require node-side verification. A poll observing zero claims is not an atomic lock against a concurrent allocator.

For a policy exclusion on an active interface, report PendingDrain rather than immediately deleting the device. For unexpected hardware disappearance, retain the allocation record, fail new preparation clearly, and require recovery; do not expose a replacement under an identity still in use.

8.3 Node-Side Enforcement

The execution path must maintain a persistent, idempotent allocation journal and serialize conflicting work by resolved resource/domain. Acquire multiple locks in deterministic order. Apply Section 4.1.5’s identity-epoch, protection-graph and effect checks before NetworkPlugin or device operations, including the actual networking hook if it occurs after NodePrepareResources. A successful earlier check does not authorize later mutation after ownership or dependency changes.

Preparation, retries, cleanup failures, kubelet reconnect and process restarts must not release a domain prematurely. A local cleanup completion does not remove scheduler allocation state, and scheduler deallocation does not justify forgetting hardware cleanup that is still pending.

The journal must distinguish claim identity, allocation result/share identity and Pod consumers. Count claim allocations separately from Pod references when a claim can be reused. Track external host ownership explicitly where supported; otherwise exclude unsafe exposure profiles, as in Example 7.

8.4 Capability and Authorization Boundaries

The installation profile requires DRAPartitionableDevices, DRAConsumableCapacity, DRADeviceCompatibilityGroups and DRAListTypeAttributes for the full examples. DRASharedConsumableCapacity is not part of the baseline. S2

Use a deployment capability contract and verification, not a fictional generic runtime API for reading all feature-gate values. API write/read tests must detect stripped fields. Scheduler behavior needs its own controlled test. Loss of a required capability must not trigger a fallback that removes exclusion constraints from still-published alternatives.

Restrict writes to driver ResourceSlices, exposure policies and relevant claim status. Compatibility is an allocation predicate, not a tenant authorization system or protection against arbitrary privileged host reconfiguration. Administrative-access claims and custom schedulers require an explicit support policy; the baseline guarantees target normal scheduler-managed allocations.


9. Required Acceptance Tests

The following are implementation acceptance criteria. They have not been run against Kubernetes as part of preparing this document.

TestRequired result
Policy priority and exclusionsOne winner per suffix; lexical tie break; any exclusion wins; no match publishes nothing new.
Selector failureInvalid CEL is rejected; runtime evaluation errors fail closed with diagnostics.
Policy-to-v1 serializationNo basic, no stringSlice; attributes/capacity at device level; quantities and attribute types preserved.
Slice separation and limitsCounter and device objects separated; consistent total count and generation; third consumption or third group rejected.
Counter-set resolutionPF/VF members resolve to the same family domain; different interfaces/pools stay independent.
Alias coverageMultiple personas without a common guard rejected; exclusive aliases cannot coexist.
Macvlan repeated allocationsA and B on one device both allocate, consuming two local units and one fixed member.
Cross-mode rejectionIPvlan rejected while any macvlan claim remains, in either allocation order.
First-share releaseRelease A while B remains; reconstruct allocator state; incompatible mode stays rejected.
Last-share releaseRelease B, reconcile cleanup and allocation state; the alternate mode can allocate.
Driver/scheduler state reconstructionRestarts preserve compatible outcomes and cannot unlock an active mode.
Local capacity boundary64 one-unit allocations fit; 65th does not. Releasing one restores exactly one unit.
Shared versus exclusiveBoth orderings blocked; second allocation of a normal exclusive entry rejected.
PF family combinationsPF macvlan plus all eligible VFs permitted; PF passthrough rejected until all incompatible family members are released.
Independent interface and family domainsAdding PF ipvlan does not block VFs but does block PF macvlan; all two-domain checks apply.
Maximal PF/VF persona poolAll fifteen Example 10 identities obey two-domain/two-group limits; PF passthrough conflicts with every active host-retained PF/VF persona.
Third independent domainA persona already in interface and PF-family domains is rejected when a distinct reset/controller domain is required; no association is silently dropped.
Neutral VLAN across three familiesMac-family, ipvlan L2 and ipvlan L3 remain mutually incompatible; compilation rejects the VLAN persona because three alternative groups cannot be encoded.
Whole-set intersectionPairwise-overlapping but globally disjoint group sets cannot all allocate.
Empty group behaviorEmpty only matches empty; missing groups never treated as a wildcard.
VLAN/ipvlan/macvlan/macvtap matrixVLAN coexists with either approved child family; macvlan and macvtap coexist; ipvlan is rejected with either on the same immediate lower.
Ipvlan port contractConcurrent ipvlan allocations use one pinned mode/flag combination; incompatible mode personas cannot overlap.
VLAN lower separationMac-family children on one VLAN lower and ipvlan children on another do not share an interface domain; PF-wide effects remain guarded.
Child recoveryJournaled software children correlate to their allocations after restart; unjournaled children are not published as free capacity.
Single allocation search and backtrackingIncompatible requests in one claim/Pod rejected; failed candidates restore group and capacity search state.
Policy / identity mutationActive rename, group change, suffix replacement, sharing change and VF-count shrink require drain; no early retirement.
Host namespace move / rebindingRescan does not forget a still-allocated device after a supported operation moves or rebinds it.
Hidden bridge-owned VFExclusion alone creates no reservation; unsafe PF passthrough is unavailable in the selected host-bridge profile.
Feature disabled / stripped / skewedRequired fields missing or unenforced prevents unsafe publication; no silent downgrade to unconstrained alternatives.
Partial ResourceSlice updatesIncomplete generations and retry/restart converge without exposing conflicting new aliases.
Claim reused by PodsPod reference changes do not double-charge local capacity or release the claim’s device early.
Prepare/unprepare retries and failuresIdempotent journal replay; deterministic domain locking; cleanup failure retains safety state.
Optional shared-bandwidth profileOnly on a combined supported build: per-share accounting, release order, defaults, policy changes, feature transitions and compatibility all tested.
OVN-K profileAdvertised support is promoted to an implementation guarantee only after provisioning, handoff and cleanup tests pass.

9.1 Cold Inventory and Dependency Protection Matrix

These cases are the F12 contract acceptance matrix. “Permit” means the identity/protection check passes; normal policy, scheduler allocation, capacity and execution authorization must also pass. They are specified cases, not executed hardware results. Pure graph fixtures can verify traversal and deny decisions; PCI/netlink fixtures and real hardware/controller tests must separately validate the observations and certified effect footprints.

CaseObserved state and requested actionRequired inventory/publication and execution outcome
F12-01First startup; VF already bound to VFIO; no host netdevice or prior journalDiscover the function and PF/index from PCI. Omit unavailable name/MAC/MTU fields. Deny kernel-netdevice publication; only a separately certified VFIO profile may publish after complete ownership checks. No automatic rebind.
F12-02First startup; unbound network functionRetain a function record with bindingState: unbound. Distinguish unreadable driver link from proven absence. Deny execution in the initial kernel-bound profile.
F12-03Free, identity-verified kernel VF; complete graph; move its endpointPermit when the certified effect set affects only the authorized free resources. An unrelated protected PF on the node does not block it.
F12-04Authorized rename, namespace move or rebind; stable function continuityKeep the committed resource ID/epoch and allocation mapping; update verified locators. Rescan cannot republish the same resource as free.
F12-05VF destroyed/recreated at the same BDF/index, or replacement hardware reuses BDF/MACNew incarnation cannot satisfy the old allocation. Retain old tombstone/cleanup references, block conflicting new publication and require recovery/drain.
F12-06Reboot, missed PCI events or lost identity store; continuity cannot be provedIdentityUncertain; no new preparation or automatic reuse. Recovery reconciles persisted/API/external ownership before accepting the candidate.
F12-07Management VLAN over bond over PF; move/rebind the PFDeny with the dependency path even if the PF name matches an expose policy and no PF exclusion exists. Retain active declarations if protection was added later.
F12-08VF is a host bridge member; direct VF handoffDeny because the operation removes a protected member. Excluding the bridge from direct allocation is insufficient.
F12-09Same host bridge uses VF0; free VF1 has a certified isolated endpoint-move operationPermit VF1 if it changes neither PF/representor service nor bridge-owned resources. A reset/rebind with unknown or overlapping impact is denied.
F12-10Primary CNI owns a representor; proposed VF/eswitch operation affects itDeny without the required controller delegation. Never classify the representor as a spare VF by ifname/PCI association alone.
F12-11Approved shared data parent; one child-creation entitlement; owner delegates exact effectsPermit within the certified shared profile and quota; deletion removes only that attachment’s child. A protected management/primary parent with no such delegation is denied.
F12-12VFIO transition; IOMMU peer is host-owned/non-network, or peer ownership is unknownDiscover the peer and deny the transition. Absence from network inventory or DRA claims does not make it free.
F12-13Reset method affects a protected peer outside the PF family/IOMMU group, or scope is unknownDeny. Reset footprint must be independently established; sharing an IOMMU group neither proves nor authorizes reset scope.
F12-14Function has several netdevices/ports and a representor; selected endpoint unresolvedDiscover all observations but reject ambiguous initial-profile publication. Never choose the first interface or infer ownership from its name.
F12-15Required controller source stale, netlink dump interrupted, or relevant graph edge unresolvedRetain existing protection; block affected new use with DependencyUnknown. A verified independent inventory component may still reconcile.
F12-16Ownership/protected dependency changes after publication or Prepare, before ConnectRefresh under local locks, reject mutation, keep active inventory contract and enter drain/recovery. A tolerated scheduling taint cannot bypass this check.
F12-17Unprepare sees replacement device or a new external ownerDo not restore historical settings onto it. Keep cleanup debt and quarantine pending proven safe recovery.
F12-18PCI-only candidate evaluated against the kernel-interface example policiesGuarded missing ifName/pfName/masterBridge expressions return non-match, not runtime error. Missing ownership evidence independently blocks unsafe exposure.

Use both upstream structured-allocator tests with published fixtures and integration/e2e tests exercising real claim transitions. A mathematical model can check desired combinations, but it does not prove the actual scheduler, API server, feature gates or node driver implement them.


10. Implementation Handoff

The first implementation should deliver cold inventory and protection checks for the selected kernel execution profiles, including exclusive VFs and explicitly delegated shared parents, before enabling optional VFIO/rebind/reset profiles. Preserve the full baseline’s declared feature dependencies and exclusion semantics. The policy examples remain target compiler/allocation fixtures, not a claim that every hardware/effect profile is initially supported:

Inventory and protection. Implement Section 4.1’s PCI/function and endpoint records, completeness/provenance tracking, identity persistence and typed graph. Configure authoritative management/primary/external ownership sources. Read VFIO/unbound inventory without rebinding it; reject unsupported effects or missing adapters. Implement F12-01 through F12-18 as source fixtures, graph checks and hardware/controller conformance cases appropriate to each profile.

Policy API and compiler. Implement the proposed schema and admission rules, optional-attribute normalization, guarded selectors, deterministic policy resolution, scoped domain resolution, stable identity mapping, effect-footprint checks and whole-pool validation. Pure compiler tests should use the examples in this document as fixtures and must not treat a policy match as ownership authority.

Publication and allocation-aware state. Integrate the upstream ResourceSlice publishing machinery, correct packing/counts, committed inventory state, allocated-claim observation and drain handling. Add failure/restart tests before allowing automatic destructive transitions.

Node enforcement and topology integration. Implement the journal and resource/domain safety checks, then connect the companion NetworkTopology/NetworkPlugin execution path. Revalidate identity epochs, dependencies and ownership before each mutation and historical cleanup. Keep plugin-specific arguments separate from exposure metadata. Confirm the one-allocation/one-interface baseline contract and claim-sharing behavior.

Target-cluster verification. Run API validation, CEL evaluation and allocator/e2e acceptance on the exact Kubernetes or OpenShift target. Alpha source availability is not production support approval.

Follow-ons. Add an explicit shared-budget policy API and KEP 5941 integration only after the baseline works. Treat OVN-K and host-managed reservations as separately tested integrations, not assumed consequences of the generic discovery engine.

Suggested initial interfaces are conceptual boundaries, not preselected Go APIs: Discover, CorrelateIdentity, BuildProtectionGraph, CheckEffectFootprint, ResolvePolicies, CompilePools, ReconcilePublication, ObserveAllocations, and EnforceDomainContract. Their concrete signatures should be designed against the actual driver repository in the implementation phase.

This revision closes F12’s missing design contract. It does not claim implementation, successful hardware conformance, a complete durable publication fence or a live site update. Unknown reset/representor/external-owner behavior remains an explicit profile blocker until an adapter and its evidence exist.


11. Source Notes

The uploaded design provides the original scope, terminology, nine scenarios and reference inventory. This revision replaces the exclusion model and adds explicitly proposed policy/lifecycle rules. The custom compatibility schema, non-binding members counters, PCI identity records, protection graph and compiler checks are design decisions in this document, not features supplied automatically by Kubernetes or Linux.

Upstream facts were checked against the following primary sources. Prefer the pinned implementation over older prose when the two disagree. Linux source documentation for the F12 revision was checked on 2026-09-23; supported kernels/drivers still require conformance evidence. The OVN integration remains unvalidated.

ON THIS PAGE