Ce contenu n'est pas disponible dans la langue sélectionnée.

Chapter 12. NVIDIA DPF Operator


12.1. NVIDIA DPF Operator release notes

Use the release notes to learn what is new or changed in the NVIDIA DPF Operator.

12.1.1. Release notes for NVIDIA DPF Operator 26.4.1

The NVIDIA DPF Operator on OpenShift Container Platform has known limitations for uninstall, secrets, MTU, secure boot, multi-DPU hosts, and HBN, unsupported OVN-Kubernetes features, and issues that can affect Grafana and DTS metrics.

12.1.1.1. DPF Operator v26.4.1-beta.1

New features and enhancements

Enhanced observability with DTS integration
Added comprehensive DPU telemetry monitoring through the DOCA Telemetry Service (DTS) with built-in OpenShift Container Platform Console dashboard integration. DTS metrics are now accessible directly through the OpenShift Container Platform web console without requiring additional tools.
Improved hosted control planes integration
The DPF HCP Provisioner Operator provides enhanced lifecycle management for DPU hosted clusters, including automatic CSR approval, kubeconfig injection, and BlueField container image lookup.
Advanced traffic validation
A comprehensive traffic validation framework with pre-configured test pods uses nicolaka/netshoot containers to validate end-to-end DPU service chain functionality.
Enhanced troubleshooting capabilities
Expanded diagnostic tools and troubleshooting procedures cover DPU provisioning, hosted cluster management, networking issues, and comprehensive log collection.

Bug fixes

Improved BFB image handling
Fixed issues with BlueField Bootstream File (BFB) image download and verification processes.
Enhanced worker node detection
Resolved Node Feature Discovery (NFD) compatibility issues for reliable DPU hardware detection.
Networking stability improvements
Fixed OVN-Kubernetes integration issues that could cause worker nodes to remain in NotReady state.

Technology Preview features

Important

The NVIDIA DPF Operator is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.

Known issues and limitations

Only x86_64 workers are supported
Only x86_64 worker nodes are supported in this release. ARM-based DPU workers are not supported.
DPF Operator uninstall is not supported
The DPF Operator does not support an automated uninstall. If you must remove DPF, set spec.manageDPUServiceTemplates to false in the DPFHCPProvisionerConfig resource before you uninstall. This prevents the DPF HCP Provisioner Operator from continuing to manage DPUServiceTemplate resources during the uninstall process.
Secret references are immutable
The pull secret and SSH secret references are immutable after creation and cannot be modified. Ensure that each secret contains the correct data before you create it and reference it in the DPFHCPProvisioner custom resource.
Secondary pod interfaces are not supported
Secondary pod interfaces (MultiNetwork) are not supported.
MTU changes are not supported after deployment
You cannot change the MTU value after deployment.
Secure boot firmware requirement
To boot the RHCOS BFB image with secure boot enabled, the DPU firmware must be at version 3.1.0 or later. Use a BFB firmware bundle to upgrade the firmware.
Multi-DPU hosts are not supported
Hosts with more than one DPU are not supported.
Redeploying a DPUDeployment is not supported
Redeploying a DPUDeployment is not supported in this release.
Deployments cannot target all nodes in a cluster
Because of a limitation in the resource injector, a deployment can target either the DPU workers or all other nodes, but not both.
Host-Based Networking (HBN) pods stuck in FailedCreatePodSandBox
An HBN daemon set pod might remain in the FailedCreatePodSandBox state. As a workaround, delete and re-create the affected pods. For more information, see OCPBUGS-100251.
HostedCluster upgrade during an in-progress upgrade
Changing the ocpReleaseImage of a HostedCluster while an upgrade is already in progress is not supported.
Connectivity loss after a DPU reboot or upgrade

When a DPU reboots, the corresponding DPU worker node loses connectivity and a NoExecute taint is added to the host. Most pods are evicted immediately, but some daemon set pods remain and might lose connectivity until you re-create them. For example:

Example output

openshift-network-diagnostics   network-check-target-lpkp2   0/1   Running

DPU stuck in the NodeEffect or Initializing state

The NVIDIA Maintenance Operator might fail to pause the machine config pool, which leaves the DPU in the NodeEffect or Initializing state. As a workaround, pause the worker-dpu machine config pool manually:

$ oc patch mcp worker-dpu --type merge -p '{
  "spec": {"paused": true},
  "metadata": {"annotations": {"maintenance.nvidia.com/mcp-paused": "true"}}
}'
Workload pods do not recover after an IPMI reset reboot
After an IPMI reset reboot, workload pods might fail to recover because of a known kubelet bug (Kubernetes issue 128043) that prevents virtual function (VF) devices from being re-created immediately at startup. This does not break functionality, but it leaves the cluster in an inconsistent state. Standard and IPMI2 reboots recover cleanly. As a workaround, re-create the affected pods manually if needed.
The SR-IOV device plugin can report fewer virtual functions than configured
After a node reboot or DPU redeployment, the SR-IOV device plugin might publish the node’s virtual function (VF) resource count before all VFs are created. The init container unblocks when the first VF appears instead of waiting for all configured VFs, so the reported openshift.io/bf3_vfs capacity can be lower than expected. As a workaround, restart the SR-IOV device plugin pod on the affected node, after which the full count is reported.

OVN-Kubernetes feature support

The following table lists the support and hardware offload status of OVN-Kubernetes features in this Technology Preview.

Expand
Table 12.1. OVN-Kubernetes feature support and offload status
FeatureSupportedOffloaded

Administrative Network Policies (ANP)

Yes

Yes

Egress IP

Yes

No

Egress Firewall

Yes

No

Egress Quality of Service (QoS)

Yes

No

Secondary networks

No

No

User Defined Networks (UDN)

No

No

Quality of Service (QoS)

No

No

Multiple External Gateways (MEG)

No

No

OVN-Kubernetes identity

No

No

Border Gateway Protocol (BGP)

No

No

Multicast

No

No

Hybrid Overlay

No

No

Local gateway mode

No

No

IPFIX or NetFlow sampling

No

No

Grafana deployment issues

Grafana shows that the application is not available

Grafana pods might be scheduled on worker nodes that depend on DPU networking, which creates a circular dependency.

Configure Grafana to run on control plane nodes by adding nodeSelector and tolerations to the Grafana custom resource:

spec:
  deployment:
    spec:
      template:
        spec:
          nodeSelector:
            node-role.kubernetes.io/control-plane: ""
          tolerations:
          - key: node-role.kubernetes.io/master
            operator: Exists
            effect: NoSchedule
          - key: node-role.kubernetes.io/control-plane
            operator: Exists
            effect: NoSchedule

DTS metrics collection issues

DTS metrics are not appearing in Prometheus or Grafana

The ServiceMonitor might not be configured correctly, or DTS pods might not be running.

Verify that DTS pods are running:

$ oc get pods -n dpf-operator-system -l app=dts

Check the ServiceMonitor configuration:

$ oc get servicemonitor -n dpf-operator-system
$ oc describe servicemonitor <servicemonitor-name> -n dpf-operator-system

Verify that user workload monitoring is enabled:

$ oc get configmap cluster-monitoring-config -n openshift-monitoring -o yaml

Check Prometheus targets to ensure that DTS endpoints are being scraped. Access the Prometheus web console and go to Status Targets to verify that DTS endpoints are listed and healthy.

12.2. About the NVIDIA DPF Operator

The NVIDIA DOCA Platform Framework (DPF) Operator enables hardware-accelerated networking on OpenShift Container Platform by offloading OVN-Kubernetes data plane operations to NVIDIA BlueField-3 Data Processing Units (DPUs).

The DPF deployment creates a dual-cluster topology consisting of a management cluster running on x86 servers and a hosted DPU cluster running on BlueField-3 DPUs.

Important

The NVIDIA DPF Operator is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.

12.2.1. DPF architecture overview

The NVIDIA DOCA Platform Framework (DPF) v26.4.1 deployment on OpenShift Container Platform 4.22 offloads OVN-Kubernetes data plane operations to NVIDIA BlueField-3 DPUs.

In Host Trusted deployments, DPF uses BlueField DPUs as host accelerators, and the host is part of the trusted domain. Administrators can orchestrate both workloads and DPU-accelerated infrastructure by using standard OpenShift Container Platform APIs and custom resource definitions (CRDs).

By offloading critical OpenShift Container Platform networking functions, such as OVN-Kubernetes, to the DPU, the architecture frees host CPU resources for tenant applications. DPF also provides automated lifecycle management so that administrators can provision, configure, and update fleets of DPUs directly from OpenShift Container Platform.

Note

In the current release, the supported DPU services are Host-Based Networking (HBN) with OVN-Kubernetes and the DOCA Telemetry Service (DTS).

The NVIDIA DPF Operator is distinct from the Red Hat DPU Operator. The Red Hat DPU Operator manages supported non-NVIDIA DPU devices. NVIDIA BlueField-3 deployments use the DPF Operator and related components.

12.2.1.1. The topology

The DPF deployment creates a specialized networking infrastructure consisting of two distinct cluster planes that work together to deliver hardware-accelerated networking:

OpenShift Container Platform management cluster

The management cluster runs on the server’s main x86 CPU cores. It hosts the actual business logic, such as AI workloads or enterprise applications.

The management cluster serves as the primary administrative interface and the host cluster that provisions and manages both the fleet of DPUs and user workloads. In a Host Trusted deployment, the worker nodes in this cluster are the physical servers that house the BlueField DPUs.

The management cluster is responsible for the following functions:

  • Running user workloads on x86 host processors.
  • Providing a single interface for defining the required state of the infrastructure by using Kubernetes CRDs such as DPUSet, DPUDeployment, and DPUService.
  • Driving the discovery of DPUs, flashing BlueField Bootstream (BFB) images, and configuring host-to-DPU networking.
  • Coordinating the deployment of services and network flows to the DPU cluster.
OpenShift Container Platform DPU hosted cluster

The DPU hosted cluster is a dedicated, secondary Kubernetes control plane for managing the fleet of NVIDIA BlueField DPUs. The DPUs function as the worker nodes of this hosted cluster, separate from the bare-metal hosts they are physically attached to.

The DPU hosted cluster runs the following components:

  • OVN-Kubernetes running in DPU mode to offload flows.
  • DOCA services such as Host-Based Networking (HBN) for BGP routing, DOCA Telemetry Service (DTS) for monitoring, and Firefly for time synchronization.
  • System components including NVIDIA IPAM, Multus, and SR-IOV Device Plugins to manage the DPU hardware resources.

12.2.1.2. Example topology

The following diagram illustrates the physical connectivity for a reference lab environment. It serves as a baseline example to demonstrate the core components and their interactions.

DPF lab topology diagram

12.2.1.3. Architecture characteristics

Host-managed DPU lifecycle
In a Host Trusted deployment, the DPU is managed from the host. This model enables cloud operators to manage BlueField-bound services directly from their standard OpenShift Container Platform control plane. DPF automates the discovery and provisioning of DPUs: the DPF Operator detects worker nodes, creates DPU objects, and deploys the DOCA Management Service (DMS) to install the BFB firmware and configure networking between the host and DPU. This approach reduces manual low-level device configuration by using standard Kubernetes APIs and workflows.
Infrastructure service offloading
In Host Trusted mode, infrastructure services such as networking, storage, and security are offloaded from the host CPU to the DPU. This frees host CPU resources for applications. The framework routes data center traffic through dedicated ports on the BlueField DPU.
Kubernetes-native orchestration
DPF extends the Kubernetes control plane to the DPUs, enabling administrators to deploy and orchestrate NVIDIA DOCA services and third-party applications directly on the BlueField DPU by using familiar Kubernetes constructs. The architecture supports automated rolling updates, scaling, and rollbacks for services without disrupting ongoing operations.

12.2.2. DPF component placement

The software components and Operators run on the management cluster and the DPU hosted cluster to separate workload management from infrastructure acceleration.

12.2.2.1. Management cluster components

The following Operators and services run within the management cluster:

NVIDIA DPF Operator
The core Operator that manages DPU services and configurations within the hosted cluster, including DPU provisioning, networking acceleration, and DOCA service orchestration.
DPF HCP Provisioner Operator
Automates the hosted control plane’s cluster lifecycle for the DPU nodes.
MultiCluster Engine (MCE) and hosted control planes
Provide the control plane and management framework for the DPU hosted cluster.
Node Feature Discovery (NFD) Operator
Discovers and labels hardware features on the nodes, including the presence of DPUs.
MetalLB Operator
Provides load balancing services for the management cluster.
GitOps Operator
Facilitates ArgoCD-based deployment of applications and configurations.
cert-manager Operator
Automates the management, issuance, and renewal of TLS certificates within the cluster.
NVIDIA Maintenance Operator
Assists in performing maintenance tasks and gracefully draining DPU worker nodes.
LVM Storage
Provides persistent ReadWriteMany (RWX) storage required for various components, such as the etcd database of the hosted cluster.
NodeSRIOVDevicePluginConfig
A DPF-managed CRD that configures SR-IOV device plugin pods on worker nodes. It defines VF allocation ranges for management and workload traffic.
Bare Metal Operator
Provisions and adds worker nodes with DPUs to the management cluster.

12.2.3. DPF deployment flow overview

The end-to-end deployment process for the NVIDIA DPF Operator follows a series of high-level steps, from management cluster setup through workload verification.

The deployment flow consists of the following steps:

  1. Management cluster setup: Install and configure a standard OpenShift Container Platform cluster on x86 servers with control-plane nodes only.
  2. Management cluster configuration: Configure nodes and cluster-level settings, then install and configure the required Operators on the management cluster.
  3. DPF installation: Deploy the DPF Operator, controllers, DPF resources, and DPU service definitions on the management cluster.

    Important

    You must install the DPF Operator before the DPF HCP Provisioner Operator because that Operator requires DPF custom resource definitions (CRDs) such as DPUCluster, DPUFlavor, DPUDeployment, and DPFOperatorConfig.

  4. Hosted cluster creation: The DPF HCP Provisioner Operator automates the creation of a hosted DPU cluster by using hosted control planes. The Operator references the DPUDeployment resource during ignition generation.
  5. Worker node scale-out and DPU provisioning: When worker nodes with DPUs are added to the cluster, the DPF Operator flashes the DPUs with a Red Hat Enterprise Linux CoreOS (RHCOS) image and configures them to join the hosted cluster as worker nodes.
  6. Worker node integration: Approve DPU worker node certificate signing requests (CSRs) and configure security context constraint (SCC) bindings on the hosted cluster.
  7. Service deployment: After the DPU hosted cluster is operational, data plane DPU services and chains are deployed by DPF.
  8. Verification: Validate end-to-end connectivity through the DPU data plane by running ping and nc traffic tests between workload pods and services.

12.2.4. DPF hardware requirements

A DPF v26.4.1 deployment on OpenShift Container Platform 4.22 requires a workstation with CLI tools, a management cluster, at least two worker servers with NVIDIA BlueField-3 DPUs, dedicated management and DPU network switches, and a shared storage server for BFB images.

12.2.4.1. Workstation

A workstation with the following command-line interface (CLI) tools installed:

  • OpenShift CLI (oc) is installed.
  • Helm CLI (helm) is installed.

12.2.4.2. Control plane nodes

Three nodes form the control plane of the management cluster.

Expand
Table 12.2. Control plane node requirements
ComponentRequirement

Form factor

Virtual machines or physical servers

Memory

60 GB RAM

CPU

16 vCPUs (Intel or AMD x86_64)

Storage

120 GB NVMe SSD storage, plus an additional 80 GB disk for LVM Storage

Networking

1x 1GbE network interface

DPUs

DPUs must not be installed on control plane nodes

12.2.4.3. Worker nodes

Two physical x86 servers host the NVIDIA BlueField-3 DPUs and act as worker nodes for the management cluster.

Expand
Table 12.3. Worker node requirements
ComponentRequirement

Memory

256 GB RAM

CPU

16 cores (Intel or AMD x86_64)

Storage

A minimum of 500 GB NVMe SSD storage for the base operating system

DPU slot

PCIe Gen 5 x16 slot required. Each server can have multiple DPUs but only one NVIDIA BlueField-3 DPU can be provisioned.

BIOS settings

SR-IOV must be enabled. In-Band Manageability Interface must be enabled.

Note

As part of the installation process, a Linux bridge named br-ex is automatically created on the worker node’s physical management port by using a MachineConfig custom resource to facilitate control-plane traffic from the DPU through the host server.

12.2.4.4. NVIDIA BlueField-3 DPUs

One NVIDIA BlueField-3 DPU is required per worker node.

Expand
Table 12.4. BlueField-3 DPU requirements
ComponentRequirement

Model

BlueField-3: B3240, B3220, or B3210

Memory

32 GB. Dual-port DPUs with 32 GB require an external power connection to the x86 server.

Networking

Dual 200GbE ports per DPU. Both ports must be connected to the high-speed switch for ECMP routing.

Management

The out-of-band management port is not used in this configuration.

Operating system and software

The DPUs are provisioned with a BlueField Bootstream File (BFB) that bundles a Red Hat Enterprise Linux CoreOS (RHCOS) base image and the NVIDIA DOCA software stack. The DOCA software stack includes the DPU firmware (version 32.49.1014).

12.2.5. DPF network infrastructure requirements

A DPF deployment requires a management switch, a high-speed DPU switch, routable management and VTEP networks with reserved service IPs and a VIP, and a consistent MTU across all network components.

12.2.5.1. Switches

Management switch
Provides 1GbE connectivity for the control plane and worker node management interfaces.
High-speed switch
An NVIDIA SN3700 or similar switch providing 2x 200GbE connectivity per DPU.

12.2.5.2. Connectivity

  • All nodes must have full internet access, both from the host out-of-band and DPU high-speed interfaces.
  • The management network and the high-speed DPU network, which is the VTEP CIDR, must be routable to each other in both directions. Verify reachability in each direction before you begin the installation, because connectivity that works in only one direction allows the deployment to proceed partway and then fail.
  • A dedicated IP address range, which is the VTEP Classless Inter-Domain Routing (CIDR), must be allocated from the high-speed DPU network for DPU service IPs used by HBN and OVN tunnels.
  • A Virtual IP (VIP) from the management subnet must be reserved for the hosted DPU cluster control-plane services. The VIP must have a DNS A record.

12.2.5.3. MTU configuration

The deployment supports any maximum transmission unit (MTU) value, provided it is consistent across all network components, including switches, interfaces, and bridges. Common values are 1500 for standard frames and 9000 for jumbo frames. Whichever value you choose must be supported end-to-end by every component in the network path.

Important

The MTU value is set during deployment and cannot be changed later. Ensure consistency across all environment components. When using VMs for control plane nodes, ensure the hypervisor bridge MTU matches the chosen value.

12.2.6. DPF software requirements

A DPF v26.4.1 deployment requires specific versions of OpenShift Container Platform, the OpenShift CLI (oc), hosted control planes, the NVIDIA DPF Operator, and RHCOS BFB, plus cluster-admin privileges on the management cluster.

Expand
Table 12.5. Software version requirements
ComponentRequired version

OpenShift Container Platform

4.22

OpenShift CLI (oc)

4.22

Hosted control planes OpenShift Container Platform cluster

4.22

NVIDIA DPF Operator

v26.4.1

RHCOS BFB

4.22

The RHCOS BFB entry refers to the base RHCOS BlueField Bootstream (BFB) image, which is available from the OpenShift Container Platform mirror. For example:

Example BFB image URL

https://rhcos.mirror.openshift.com/art/storage/prod/streams/rhel-10.2/builds/10.2.20260715-0/aarch64/rhcos-10.2.20260715-0-nvidiabluefield.aarch64.bfb

The base BFB is layered with the NVIDIA DOCA stack at provisioning time, and the DOCA services run on the DPUs as separately deployed DPUService resources. The following versions are pinned by this deployment:

Expand
Table 12.6. NVIDIA DOCA component versions
ComponentRequired version

NVIDIA DOCA

3.4.1

Host-Based Networking (HBN)

3.4.0

DOCA Telemetry Service (DTS)

1.25.5

OVN-Kubernetes

Delivered by the DPF OVN-Kubernetes Helm chart

12.2.6.1. Required command-line tools

Install the following tools on the workstation from which you run the deployment commands:

  • oc — the OpenShift Container Platform CLI, version 4.22.
  • helm — required to install the DPF Operator and related Helm charts.
  • envsubst — substitutes environment variables into the manifest templates used throughout this documentation (the envsubst < file.yaml | oc apply -f - pattern). Provided by the gettext package.
  • jq — parses JSON output during verification and troubleshooting.

12.2.6.2. Access requirements

  • cluster-admin privileges are required for the management cluster.

12.3. Set up the environment for DPF

Before installing the NVIDIA DPF Operator, you must set up the management cluster, configure worker nodes, and install and configure the required Operators.

12.3.1. Set up the management cluster

The management cluster is a standard OpenShift Container Platform 4.22 cluster installed by using the Assisted Installer. This cluster hosts the DPF Operators and the hosted control planes for managing the hosted cluster on DPUs.

Prerequisites

Procedure

  1. Go to the Red Hat Hybrid Cloud Console cluster creation page and create a cluster with control-plane nodes only. Select Data center Assisted Installer.
  2. Optional: Configure jumbo MTU for each control plane node.

    1. Under Hosts' network configuration in the Assisted Installer wizard, select Static IP, bridges, and bonds.
    2. Set the Static network configurations section per node according to the following template, using the relevant MAC address and interface name for each node:

      interfaces:
        - ipv4:
            dhcp: true
            enabled: true
          mac-address: <xx:xx:xx:xx:xx:xx>
          mtu: 1500 # Set to 1500 for standard MTU or 9000 for jumbo frames
          name: <interface-name>
          state: up
          type: ethernet
      Note
      • You can alternatively configure MTU allocation on the DHCP server that allocates IPs to the control plane nodes.
      • If virtual machines are used for control-plane nodes, the MTU must be set on the bridge of the hypervisor used by the VMs.
      • When using MTU 9000, ensure the switch ports that connect the cluster’s control-plane nodes are set to handle jumbo frames.
  3. Select the following operators to install with the cluster:

    • Storage Logical Volume Manager Storage
    • Platform Operations & Lifecycle MultiCluster Engine
    • Scheduling Node Feature Discovery
  4. Click Add hosts to add hosts to the cluster. Only control plane nodes are required at this stage.
  5. After the installation completes, download the KUBECONFIG file and save it as mgmt-kubeconfig.

Verification

  1. Set the KUBECONFIG environment variable:

    $ export KUBECONFIG="$(pwd)/mgmt-kubeconfig"
  2. Verify that all nodes are in a Ready state:

    $ oc get nodes

12.3.2. Configure worker nodes for DPU operation

You must deploy the dpu-worker-config Helm chart to configure worker nodes with DPUs before adding those nodes to the management cluster. The dpu-worker-config Helm chart creates the MachineConfigPool, dpu-worker-configuration MachineConfig, and other required resources that configure the bridge, OVS services, and IP routing on worker nodes. The MachineConfigPool groups DPU-equipped worker nodes so that the Machine Config Operator can apply DPU-specific configurations to them.

The MachineConfig resource performs several configuration tasks required by DPF:

  • Bridge Configuration: Creates a br-ex bridge interface that enables communication between the DPU and the hosted cluster control plane running on the management cluster. This name must match the dpuNodeOOBBridgeName value in the DPFOperatorConfig resource, or DPU provisioning fails. For more information refer to DPF Operator Prerequisites.
  • OVS Service Management: Disables OpenShift’s default OVS services on x86 worker nodes. This is required for OVN-Kubernetes DPU Host mode operation, where networking functions are offloaded to the DPU rather than running on the host CPU.
  • IP Rules Configuration: Sets routing rules required for pod-to-host control-plane traffic.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • The Helm CLI (helm) is installed on your workstation.
  • You have a pull secret file that includes credentials for registry.redhat.io. Helm reads its registry credentials from this file, which is separate from the container runtime configuration.

Procedure

  1. Set the OPENSHIFT_PULL_SECRET environment variable to the path of your pull secret file:

    $ export OPENSHIFT_PULL_SECRET="/root/pull-secret.txt"
  2. Deploy the dpu-worker-config Helm chart to create the worker node MachineConfig:

    $ helm upgrade --install dpu-worker-config \
        oci://registry.redhat.io/dpu-kit-for-nvidia/dpu-worker-config-chart \
        --version 4.22.0 \
        --registry-config "${OPENSHIFT_PULL_SECRET}" \
        --namespace dpf-hcp-provisioner-system \
        --create-namespace \
        --disable-openapi-validation

Verification

  • Verify that the dpu-worker-config Helm release is deployed:

    $ helm list -n dpf-hcp-provisioner-system
  • Verify that the MachineConfigPool was created automatically:

    $ oc get mcp worker-dpu

    Example output

    NAME         CONFIG                                                 UPDATED   UPDATING   DEGRADED   MACHINECOUNT   READYMACHINECOUNT   UPDATEDMACHINECOUNT   DEGRADEDMACHINECOUNT   AGE
    worker-dpu   rendered-worker-dpu-b4a44cc606c2ffcf07067d1e943a8758   True      False      False      0              0                   0                     0                      2m

  • Verify that the dpu-worker-configuration MachineConfig is created:

    $ oc get machineconfig dpu-worker-configuration

    Example output

    NAME                       GENERATEDBYCONTROLLER   IGNITIONVERSION   AGE
    dpu-worker-configuration                           3.2.0             2m

Note

The Machine Config Operator automatically reboots worker nodes to apply DPU-specific configurations after nodes with the worker-dpu label are added to the cluster.

12.3.3. Create the DPF namespace

You must create a dedicated namespace for the DPF Operator and its components before installing the Operator.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).

Procedure

  • Create the dpf-operator-system namespace:

    $ oc create namespace dpf-operator-system

Verification

  • Verify that the namespace was created:

    $ oc get namespace dpf-operator-system

12.3.4. Required Operators

Before you install the DPF Operator, you must install the cert-manager Operator for Red Hat OpenShift, MetalLB Operator, Red Hat OpenShift GitOps, and NVIDIA Maintenance Operator.

The multicluster engine Operator and the Node Feature Discovery Operator can be installed during management cluster creation by using the Assisted Installer. After installation, configure those Operators, MetalLB, GitOps, and the Cluster Network Operator as described in "Configure the required Operators".

12.3.4.1. Install the NVIDIA Maintenance Operator

The NVIDIA Maintenance Operator assists in performing maintenance tasks and gracefully draining DPU worker nodes. You install this operator by using Helm.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • You have installed the Helm CLI (helm).

Procedure

  1. Create a Helm values file named maintenance-operator-values.yaml with the following content:

    operatorConfig:
      deploy: true
      maxParallelOperations: 60%
    operator:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: "node-role.kubernetes.io/master"
                    operator: Exists
              - matchExpressions:
                  - key: "node-role.kubernetes.io/control-plane"
                    operator: Exists
      tolerations:
        - key: node-role.kubernetes.io/master
          operator: Exists
          effect: NoSchedule
        - key: node-role.kubernetes.io/control-plane
          operator: Exists
          effect: NoSchedule
  2. Install the Operator by using Helm:

    $ helm upgrade --install maintenance-operator oci://ghcr.io/mellanox/maintenance-operator-chart \
      --namespace dpf-operator-system \
      --create-namespace \
      --disable-openapi-validation \
      --version 0.3.0 \
      --values maintenance-operator-values.yaml \
      --wait

Verification

  • Verify that the Operator pod is running:

    $ oc get pods -n dpf-operator-system

    Example output

    maintenance-operator-585767f779-kps9c   1/1     Running   0          2d23h

12.3.5. Configure the required Operators

After the required Operators are installed, configure Node Feature Discovery, MetalLB, GitOps, and Cluster Network Operator for the DPF environment. This procedure also verifies that the multicluster engine and hosted control planes components are ready.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • You have installed the cert-manager Operator for Red Hat OpenShift, MetalLB Operator, Red Hat OpenShift GitOps, and NVIDIA Maintenance Operator.
  • You have installed the Logical Volume Manager Storage Operator, multicluster engine operator, and the Node Feature Discovery Operator. You can install them by using the Assisted Installer during cluster creation. For manual installation, see Installing multicluster engine operator and ensure that the hosted control planes component is enabled.

Procedure

  1. Define the cluster variables used by Node Feature Discovery:

    $ export CLUSTER_NAME="doca-mgmt"
    $ export BASE_DOMAIN="example.com"
    $ export HOST_CLUSTER_API="api.${CLUSTER_NAME}.${BASE_DOMAIN}"

    where:

    CLUSTER_NAME
    Specifies the management cluster name.
    BASE_DOMAIN
    Specifies the management cluster base domain.
    HOST_CLUSTER_API
    Specifies the management cluster API endpoint.
  2. Create a file named nfd-instance.yaml with the following NodeFeatureDiscovery resource definition:

    apiVersion: nfd.openshift.io/v1
    kind: NodeFeatureDiscovery
    metadata:
      name: nfd-instance
      namespace: openshift-nfd
    spec:
      operand:
        workerEnvs:
          - name: KUBERNETES_SERVICE_HOST
            value: $HOST_CLUSTER_API
          - name: KUBERNETES_SERVICE_PORT
            value: "6443"
      workerConfig:
        configData: |
          sources:
            pci:
              deviceClassWhitelist:
                - "0200"
                - "03"
                - "12"
                - "0207"
              deviceLabelFields:
                - "vendor"
                - "device"
                - "class"
  3. Apply the file by using envsubst to substitute the environment variables:

    $ envsubst < nfd-instance.yaml | oc apply -f -
  4. Create a file named nfd-rule.yaml with the following NodeFeatureRule resource definition to detect worker nodes with DPUs and label them with a dpu-enabled label:

    apiVersion: nfd.openshift.io/v1alpha1
    kind: NodeFeatureRule
    metadata:
      name: dpu-detection-rule
      namespace: openshift-nfd
    spec:
      rules:
        - labels:
            dpu-enabled: ""
          matchFeatures:
            - feature: pci.device
              matchExpressions:
                device:
                  op: In
                  value:
                    - a2d6
                    - a2dc
                vendor:
                  op: In
                  value:
                    - 15b3
          name: DPU-detection-rule
  5. Apply the file:

    $ oc apply -f nfd-rule.yaml
  6. Ensure that the MetalLB Operator Subscription schedules Operator pods on control-plane nodes. When you install the MetalLB Operator, include the following spec.config settings, or patch an existing Subscription to add them:

    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: metallb-operator
      namespace: openshift-operators
    spec:
      channel: "stable"
      name: metallb-operator
      source: redhat-operators
      sourceNamespace: openshift-marketplace
      installPlanApproval: Automatic
      config:
        tolerations:
        - key: "node-role.kubernetes.io/control-plane"
          operator: "Exists"
          effect: "NoSchedule"
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: "node-role.kubernetes.io/control-plane"
                  operator: "Exists"
  7. Create a file named metallb-config.yaml with the following MetalLB resource definition:

    apiVersion: metallb.io/v1beta1
    kind: MetalLB
    metadata:
      name: metallb
      namespace: openshift-operators
    spec:
      nodeSelector:
        node-role.kubernetes.io/control-plane: ""
      speakerTolerations:
        - key: node-role.kubernetes.io/control-plane
          operator: Exists
          effect: NoSchedule
  8. Apply the MetalLB resource file:

    $ oc apply -f metallb-config.yaml
  9. Ensure that the Red Hat OpenShift GitOps Subscription includes the DPF-required environment variables. When you install the Operator, set the following spec.config.env values, or patch an existing Subscription to add them so that Argo CD can manage the dpf-operator-system namespace:

    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: openshift-gitops-operator
      namespace: openshift-gitops-operator
    spec:
      channel: gitops-1.21
      config:
        env:
        - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES
          value: "openshift-gitops,dpf-operator-system"
        - name: CONTROLLER_CLUSTER_ROLE
          value: "cluster-admin"
        - name: SERVER_CLUSTER_ROLE
          value: "cluster-admin"
      installPlanApproval: Automatic
      name: openshift-gitops-operator
      source: redhat-operators
      sourceNamespace: openshift-marketplace
      startingCSV: openshift-gitops-operator.v1.21.3
  10. Create a file named argocd-instance.yaml with the following ArgoCD resource definition:

    apiVersion: argoproj.io/v1beta1
    kind: ArgoCD
    metadata:
      name: argocd
      namespace: dpf-operator-system
    spec:
      nodePlacement:
        nodeSelector:
          node-role.kubernetes.io/control-plane: ""
        tolerations:
        - key: node-role.kubernetes.io/master
          operator: Exists
          effect: NoSchedule
        - key: node-role.kubernetes.io/control-plane
          operator: Exists
          effect: NoSchedule
      server:
        route:
          enabled: true
      controller: {}
      repo: {}
      applicationSet:
        enabled: false
      resourceExclusions: |
        - apiGroups:
          - packages.operators.coreos.com
          kinds:
          - PackageManifest
      sso:
        provider: dex
        dex:
          openShiftOAuth: true
      notifications:
        enabled: false
  11. Apply the Argo CD file:

    $ oc apply -f argocd-instance.yaml
  12. Wait for the ArgoCD Redis deployment to be ready:

    $ oc wait deployment argocd-redis -n dpf-operator-system \
      --for=condition=Available --timeout=120s
  13. Enable global IP forwarding on the OVN-Kubernetes configuration:

    This command enables IP packet forwarding between different networks managed by OVN-Kubernetes.

    $ oc patch network.operator.openshift.io cluster --type=merge -p \
      '{"spec":{"defaultNetwork":{"ovnKubernetesConfig":{"gatewayConfig":{"ipForwarding":"Global"}}}}}'

Verification

  • Verify that the MultiClusterEngine instance is created:

    $ oc get multiclusterengine mce

    Example output

    NAME   STATUS      AGE     CURRENTVERSION   DESIREDVERSION   MESSAGE
    mce    Available   4m58s   2.17.2           2.17.2           All components available

  • Verify that the hosted control planes component is enabled:

    $ oc get multiclusterengine mce -o jsonpath='{.spec.overrides.components[?(@.name=="hypershift")].enabled}{"\n"}'
    Note

    If the previous command returns false or an empty result, hosted control planes is not enabled and DPU provisioning fails.

    To continue, you must enable the hypershift component on the MultiClusterEngine resource. In current multicluster engine Operator versions the component is named hypershift; earlier versions use hypershift-preview.

    • If the result is empty, no hypershift entry exists. Run the following command to add the entry and enable it:

      $ oc patch mce multiclusterengine --type=json \
          -p='[{"op":"add","path":"/spec/overrides/components/-","value":{"name":"hypershift","enabled":true}}]'
    • If the result is false, an entry exists but is disabled. Edit the resource and set the hypershift component to enabled: true:

      $ oc edit multiclusterengine mce
    Important

    Do not use oc patch --type=merge to enable the component, because a merge patch replaces the entire components array and removes the other components. Use the JSON add patch when no entry exists, or oc edit when an entry exists but is disabled.

  • Verify that the NodeFeatureDiscovery instance and NodeFeatureRule are configured:

    $ oc get nodefeaturediscovery,nodefeaturerule -n openshift-nfd
  • Verify that the MetalLB instance was created:

    $ oc get metallb -n openshift-operators
  • Verify that the Argo CD pods are running:

    $ oc get pods -n dpf-operator-system -l app.kubernetes.io/part-of=argocd
  • Verify that IP forwarding is set to Global:

    $ oc get network.operator.openshift.io cluster -o jsonpath='{.spec.defaultNetwork.ovnKubernetesConfig.gatewayConfig.ipForwarding}'

    Example output

    Global

12.4. Install and configure the DPF Operator

After setting up the environment, install the NVIDIA DPF Operator and create the required DPF resources and DPU services.

Important

You must install the DPF Operator before the DPF HCP Provisioner Operator because that Operator requires DPF CRDs such as DPUCluster, DPUFlavor, DPUDeployment, and DPFOperatorConfig.

12.4.1. DPF Operator installation environment variables

Set the following required environment variables before you install and configure the DPF Operator on OpenShift Container Platform. The values of these variables are used in multiple DPF Operator installation and configuration procedures.

Expand
Table 12.7. DPF Operator environment variables
VariableDescriptionExample value

CLUSTER_NAME

The name of the management cluster.

<YOUR_CLUSTER_NAME>

BASE_DOMAIN

The base domain for the management cluster.

example.com

HOST_CLUSTER_API

The API server hostname of the management cluster. Derived from CLUSTER_NAME and BASE_DOMAIN.

api.mycluster.example.com

TAG

The version tag for the DPF Operator Helm chart.

v26.4.1

TARGETCLUSTER_API_SERVER_PORT

The port number of the hosted cluster API server.

6443

VTEP_CIDR

The CIDR range for the VTEP (tunnel endpoint) network. Used as the OVN vtepCIDR and the DPUServiceIPAM network. Must be a dedicated range from the DPU high-speed network, routable between DPUs and host systems.

10.0.120.0/22

DPU_HOST_CIDR

The CIDR range of the subnet where the DPU host nodes reside. Used as the OVN hostCIDR. You must set this to your actual host subnet; the example value is illustrative only and is not a usable default.

10.0.110.0/24

NUM_VFS

Number of SR-IOV VFs per physical function. Sets NUM_OF_VFS in the DPUFlavor nvconfig. The NodeSRIOVDevicePluginConfig allocates these VFs as VF0 (DPF communication channel), VF1 (OVN-Kubernetes management), and the remainder (workload and RDMA).

46

OVN_TEMPLATE_CHART_URL

The OCI chart URL for the OVN-Kubernetes Helm chart.

oci://ghcr.io/mellanox/charts

OVN_CHART_VERSION

The version of the OVN-Kubernetes Helm chart.

v26.4.1-ocp-release-v4.22

OVN_MTU

The MTU value for OVN-Kubernetes overlay networking. Set to 1400 for standard MTU (NODES_MTU of 1500) or 8940 for jumbo frames (NODES_MTU of 9000). Must be kept consistent with NODES_MTU.

1400

BFB_URL

The download URL for the BlueField Bootstream File image used to provision DPUs.

https://rhcos.mirror.openshift.com/art/storage/prod/streams/rhel-10.2/builds/10.2.20260715-0/aarch64/rhcos-10.2.20260715-0-nvidiabluefield.aarch64.bfb

BFB_FILENAME

The local file name for the BFB image, which is typically the base name of BFB_URL.

rhcos-10.2.20260715-0-nvidiabluefield.aarch64.bfb

HOSTED_CLUSTER_NAME

The name of the hosted cluster running on the DPUs.

dpf-hosted

REGISTRY

The Helm chart registry URL for the DPF Operator.

https://helm.ngc.nvidia.com/nvidia/doca

NODES_MTU

The MTU value for the node network interfaces. Use 1500 for standard MTU environments or 9000 for jumbo frame environments. This value must be consistent across all DPF networking configuration.

1500 (standard) or 9000 (jumbo frames)

FLANNEL_POD_CIDR

The pod CIDR for the Flannel network in the hosted cluster. Required for OpenShift Container Platform 4.22 and later.

10.132.0.0/14

12.4.2. Install the DPF Operator

You can install the DPF Operator by using Helm to deploy the Operator into the dpf-operator-system namespace on your management cluster.

Important

You must install the DPF Operator before the DPF HCP Provisioner Operator because that Operator requires the following DPF custom resource definitions to be available: DPUCluster, DPUFlavor, DPUDeployment, and DPFOperatorConfig.

Prerequisites

  • You have access to the management cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • You have installed the helm CLI.
  • You have set the DPF Operator environment variables. For details, see "DPF Operator installation environment variables".

Procedure

  1. Add the DPF Helm repository and update the local cache:

    $ helm repo add --force-update dpf-repository ${REGISTRY}
    $ helm repo update
  2. Install the DPF Operator by using Helm:

    $ helm upgrade --install dpf-operator dpf-repository/dpf-operator \
        --namespace dpf-operator-system \
        --version "${TAG}" \
        --set kamajiEtcdDefrag.enabled=false \
        --set isOpenshift=true \
        --set enableNodeFeatureRules=false \
        --wait

Verification

  1. Verify that the Operator controller manager deployment has rolled out successfully:

    $ oc rollout status deployment --namespace dpf-operator-system dpf-operator-controller-manager

    Example output

    deployment "dpf-operator-controller-manager" successfully rolled out

  2. Verify that all pods in the dpf-operator-system namespace are ready:

    $ oc wait --for=condition=ready --namespace dpf-operator-system pods --all

    Example output

    pod/argocd-application-controller-0 condition met
    pod/argocd-dex-server-6dd56c8469-bhsq4 condition met
    pod/argocd-redis-b4f94bb8d-wr86b condition met
    pod/argocd-repo-server-96765f997-79k9q condition met
    pod/argocd-server-648c7ff85f-7frtg condition met
    pod/dpf-operator-controller-manager-7bf9744c5f-cwrgc condition met
    pod/maintenance-operator-585767f779-8k2lx condition met

12.4.3. Create the DPFOperatorConfig custom resource

Create a DPFOperatorConfig custom resource to configure the DPF Operator components, including the provisioning controller, static cluster manager, and SR-IOV device plugin controller.

Prerequisites

  • You have installed the DPF Operator.
  • You have set the DPF Operator environment variables. For details, see "DPF Operator installation environment variables".

Procedure

  1. Create a file named dpfoperatorconfig.yaml with the following content:

    Note

    MTU Configuration: Set NODES_MTU to 1500 for standard MTU environments or 9000 for jumbo frame environments. This value must be consistent across:

    • Assisted Installer host configuration
    • DPFOperatorConfig networking section (this step)
    • DPUServiceNAD configuration

    Choose based on your network infrastructure capabilities.

    apiVersion: operator.dpu.nvidia.com/v1alpha1
    kind: DPFOperatorConfig
    metadata:
      name: dpfoperatorconfig
      namespace: dpf-operator-system
    spec:
      kamajiClusterManager:
        disable: true
      multus:
        disable: true
      cniInstaller:
        disable: true
      networking:
        controlPlaneMTU: $NODES_MTU      # management/OOB MTU (= NODES_MTU: 1500 standard, 9000 jumbo)
        highSpeedMTU: $NODES_MTU         # high-speed fabric MTU (= NODES_MTU; must match controlPlaneMTU)
        dpuNodeOOBBridgeName: br-ex      # OOB bridge for DPU provisioning; br-ex on OpenShift
      overrides:
        dpuCNIBinPath: /var/lib/cni/bin/
        dpuCNIPath: /run/multus/cni/net.d/
        dpuOpenvSwitchSystemSharedLib64Path: /lib64
        flannelSkipCNIConfigInstallation: false
        kubernetesAPIServerPort: $TARGETCLUSTER_API_SERVER_PORT
        kubernetesAPIServerVIP: $HOST_CLUSTER_API
        dpuLinkerCachePath: /etc/ld.so.cache
        dpuOptLibraryPath: /usr/opt
      provisioningController:
        enableDynamicBFCFGTemplates: true
        hostAgentDNSPolicy: Default
        dmsTimeout: 900
      nodeSRIOVDevicePluginController:
        devicePlugin:
          defaultResourcePrefix: openshift.io
        disable: false
        replicas: 1
      staticClusterManager:
        disable: false
      dpuServiceController:
        disableHostNetworkReadyNoExecuteTaints: false
      flannel:
        podCIDR: $FLANNEL_POD_CIDR
  2. Apply the resource file:

    $ envsubst < dpfoperatorconfig.yaml | oc apply -f -

Verification

  1. Verify that the provisioning controller manager deployment has rolled out:

    $ oc rollout status deployment --namespace dpf-operator-system dpf-provisioning-controller-manager

    Example output

    deployment "dpf-provisioning-controller-manager" successfully rolled out

  2. Verify that the DPU service controller manager deployment has rolled out:

    $ oc rollout status deployment --namespace dpf-operator-system dpuservice-controller-manager

    Example output

    deployment "dpuservice-controller-manager" successfully rolled out

  3. Verify that all Operator deployments in the dpf-operator-system namespace have rolled out:

    Note

    You might need to run this command more than once, because the deployments become available at different times as the Operator reconciles its resources.

    $ oc rollout status deployment --namespace dpf-operator-system
  4. Optional: List the pods in the dpf-operator-system namespace to review their status:

    $ oc get pods -n dpf-operator-system

    Example output

    NAME                                                    READY   STATUS    RESTARTS   AGE
    argocd-application-controller-0                          1/1     Running   0          64m
    argocd-dex-server-9dd99cc6c-pkl6j                       1/1     Running   0          64m
    argocd-redis-6749d85f98-mw9rc                           1/1     Running   0          64m
    argocd-repo-server-5fd79d655c-9rl26                     1/1     Running   0          64m
    argocd-server-5cc4f69c45-hzgm9                          1/1     Running   0          64m
    bfb-registry                                            1/1     Running   0          98s
    dpf-nodesriovdeviceplugin-controller-7c7bb889f6-xk6nm   1/1     Running   0          107s
    dpf-operator-controller-manager-6969c6d8bc-4njxd        1/1     Running   0          4m54s
    dpf-provisioning-controller-manager-54b6bdc57f-69lr7    1/1     Running   0          109s
    dpf-provisioning-controller-manager-54b6bdc57f-fg9f6    1/1     Running   0          109s
    dpuservice-controller-manager-5d9c4f6f67-wsdzt          1/1     Running   0          108s
    maintenance-operator-68c794b549-pp2dp                   1/1     Running   0          74m
    static-cm-controller-manager-745c8fd7d5-n8d2z           1/1     Running   0          110s

12.4.4. Create the NodeSRIOVDevicePluginConfig custom resource

You can create a NodeSRIOVDevicePluginConfig custom resource to define how SR-IOV virtual functions on the management cluster worker nodes are allocated to DPF components.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.

Procedure

  1. Create a file named nodesriovdevicepluginconfig.yaml with the following content:

    apiVersion: noderesources.dpu.nvidia.com/v1alpha1
    kind: NodeSRIOVDevicePluginConfig
    metadata:
      name: bf3-vfs
      namespace: dpf-operator-system
    spec:
      devicePluginResources:
        - name: bf3-p0-vfs-mgmt
          type: vf
          ranges:
            - pfIndex: 0
              start: 1
              end: 1
        - name: bf3_vfs
          type: vf
          options:
            isRdma: true
          ranges:
            - pfIndex: 0
              start: 2
              end: 45
            - pfIndex: 1
              start: 0
              end: 45

    where:

    bf3-p0-vfs-mgmt
    Reserves VF index 1 on PF0 for DPU management connectivity.
    bf3_vfs
    Allocates VF indices 2-45 on PF0 and VF indices 0-45 on PF1 for workload traffic with RDMA enabled.
    pfIndex
    The pfIndex values refer to the first (0) and second (1) physical functions of the BlueField-3 DPU.
  2. Apply the resource file:

    $ oc apply -f nodesriovdevicepluginconfig.yaml

Verification

  • Verify that the NodeSRIOVDevicePluginConfig resource is created:

    $ oc get nodesriovdevicepluginconfig -n dpf-operator-system

    Example output

    bf3-vfs    30s

12.4.5. Create the DPUFlavor custom resource

You can create a DPUFlavor custom resource to define the DPU configuration, including NVConfig parameters, kernel arguments, hugepages settings, and the OVS initialization script. The DPUFlavor also supports an optional configFiles field for custom DPU configuration files.

The nvconfig section contains BlueField-3 firmware parameters that the DPU agent applies by using mlxconfig during provisioning. If any parameter differs from the current firmware configuration, the provisioning controller triggers a system-level reset so that the changes take effect. The following parameters are required for DPF operation:

Expand
Table 12.8. Required BlueField-3 NVConfig parameters
ParameterValueDescription

INTERNAL_CPU_MODEL

1

Switches the BlueField-3 to DPU mode where the ARM cores are active. A value of 0 keeps the card in NIC-only mode, which does not support DPF.

SRIOV_EN

1

Enables SR-IOV on both physical functions. The host agent creates Virtual Functions (VFs) that carry tenant traffic between the host and the DPU.

NUM_OF_VFS

Variable

Number of VFs per physical function. Set this value by using the $NUM_VFS environment variable. The default is 46.

LINK_TYPE_P1 / LINK_TYPE_P2

ETH

Sets both ports to Ethernet mode. DPF requires Ethernet. InfiniBand (IB) mode is not supported.

Note

If BlueField-3 already has the correct values, the DPU agent reports that no action is required and does not trigger a reset.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.
  • You have set the DPF Operator environment variables. For details, see "DPF Operator installation environment variables".

Procedure

  1. Create a file named dpuflavor.yaml for your MTU configuration and apply it.

    • For Standard MTU (1500):

      apiVersion: provisioning.dpu.nvidia.com/v1alpha1
      kind: DPUFlavor
      metadata:
        name: hbn-ovnk
        namespace: dpf-operator-system
        annotations:
          provisioning.dpu.nvidia.com/skip-bfcfg-size-check: ""
      spec:
        grub:
          kernelParameters:
            - console=hvc0
            - console=ttyAMA0
            - earlycon=pl011,0x13010000
            - iommu.passthrough=1
            - cgroup_no_v1=net_prio,net_cls
            - hugepagesz=2048kB
            - hugepages=250
        nvconfig:
          - device: '*'
            parameters:
              - PF_BAR2_ENABLE=0
              - PER_PF_NUM_SF=1
              - PF_TOTAL_SF=20
              - PF_SF_BAR_SIZE=10
              - NUM_PF_MSIX_VALID=0
              - PF_NUM_PF_MSIX_VALID=1
              - PF_NUM_PF_MSIX=228
              - INTERNAL_CPU_MODEL=1
              - INTERNAL_CPU_OFFLOAD_ENGINE=0
              - SRIOV_EN=1
              - NUM_OF_VFS=$NUM_VFS
              - LAG_RESOURCE_ALLOCATION=1
              - LINK_TYPE_P1=ETH
              - LINK_TYPE_P2=ETH
        ovs:
          rawConfigScript: |
            #!/bin/bash
            set -e
      
            _ovs-vsctl() {
              ovs-vsctl --timeout 15 "$@"
            }
      
            restart_ovs=false
      
            _ovs-get-other-config() {
              _ovs-vsctl --if-exists get Open_vSwitch . "other_config:$1" 2>/dev/null | tr -d '"'
            }
      
            _ovs-set-other-config() {
              if [ "$(_ovs-get-other-config "$1")" != "$2" ]; then
                _ovs-vsctl set Open_vSwitch . "other_config:$1=$2"
                restart_ovs=true
              fi
            }
      
            _ovs-remove-other-config() {
              if [ -n "$(_ovs-get-other-config "$1")" ]; then
                _ovs-vsctl remove Open_vSwitch . other_config "$1"
                restart_ovs=true
              fi
            }
      
            _ovs-set-other-config doca-init true
            _ovs-set-other-config dpdk-max-memzones 50000
            _ovs-set-other-config hw-offload true
            _ovs-set-other-config pmd-quiet-idle true
            _ovs-set-other-config max-idle 20000
            _ovs-set-other-config max-revalidator 5000
            _ovs-set-other-config doca-congestion-threshold 60
            _ovs-set-other-config flow-limit 500000
            _ovs-set-other-config hw-offload-ct-unidir-udp-enabled true
            _ovs-remove-other-config default-datapath-type
      
            if [ "$restart_ovs" = true ]; then
              if systemctl list-unit-files openvswitch-switch.service &>/dev/null; then
                systemctl restart openvswitch-switch
              elif systemctl list-unit-files openvswitch.service &>/dev/null; then
                systemctl restart openvswitch
              fi
            fi
      
            _ovs-vsctl --may-exist add-br br-sfc
            _ovs-vsctl set bridge br-sfc datapath_type=netdev
            _ovs-vsctl set bridge br-sfc fail_mode=secure
            _ovs-vsctl --if-exists del-br br-hbn
            _ovs-vsctl --may-exist add-br br-hbn
            _ovs-vsctl set bridge br-hbn datapath_type=netdev
            _ovs-vsctl set bridge br-hbn fail_mode=secure
            _ovs-vsctl --may-exist add-port br-sfc p0
            _ovs-vsctl set Interface p0 type=dpdk
            _ovs-vsctl set Interface p0 mtu_request=9216
            _ovs-vsctl set Port p0 external_ids:dpf-type=physical
      
            # Activate DOCA for OVNK
            _ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-datapath-type=netdev
            # setup ovnkube managed bridge, br-dpu (this corresponds to br-ex on ovnk docs)
            _ovs-vsctl --may-exist add-br br-dpu
            _ovs-vsctl br-set-external-id br-dpu bridge-id br-dpu
            _ovs-vsctl br-set-external-id br-dpu bridge-uplink pbrdputobrovn
            _ovs-vsctl set bridge br-dpu datapath_type=netdev
            _ovs-vsctl --may-exist add-port br-dpu pf0hpf
            _ovs-vsctl set Interface pf0hpf type=dpdk
      
            # Create OVS bridge (br-ovn) in between the SC managed bridge and OVNK
            _ovs-vsctl --may-exist add-br br-ovn
            _ovs-vsctl set bridge br-ovn datapath_type=netdev
            _ovs-vsctl --may-exist add-port br-ovn pbrovntobrdpu
            _ovs-vsctl --may-exist add-port br-dpu pbrdputobrovn
      
            # Patch br-ovn and br-dpu together
            _ovs-vsctl set Interface pbrovntobrdpu type=patch options:peer=pbrdputobrovn
            _ovs-vsctl set Interface pbrdputobrovn type=patch options:peer=pbrovntobrdpu
    • For Jumbo frames (MTU 9000):

      apiVersion: provisioning.dpu.nvidia.com/v1alpha1
      kind: DPUFlavor
      metadata:
        name: hbn-ovnk
        namespace: dpf-operator-system
        annotations:
          provisioning.dpu.nvidia.com/skip-bfcfg-size-check: ""
      spec:
        grub:
          kernelParameters:
            - console=hvc0
            - console=ttyAMA0
            - earlycon=pl011,0x13010000
            - iommu.passthrough=1
            - cgroup_no_v1=net_prio,net_cls
            - hugepagesz=2048kB
            - hugepages=250
        nvconfig:
          - device: '*'
            parameters:
              - PF_BAR2_ENABLE=0
              - PER_PF_NUM_SF=1
              - PF_TOTAL_SF=20
              - PF_SF_BAR_SIZE=10
              - NUM_PF_MSIX_VALID=0
              - PF_NUM_PF_MSIX_VALID=1
              - PF_NUM_PF_MSIX=228
              - INTERNAL_CPU_MODEL=1
              - INTERNAL_CPU_OFFLOAD_ENGINE=0
              - SRIOV_EN=1
              - NUM_OF_VFS=$NUM_VFS
              - LAG_RESOURCE_ALLOCATION=1
              - NUM_VF_MSIX=30
              - LINK_TYPE_P1=ETH
              - LINK_TYPE_P2=ETH
        ovs:
          rawConfigScript: |
            #!/bin/bash
            set -e
      
            _ovs-vsctl() {
              ovs-vsctl --timeout 15 "$@"
            }
      
            restart_ovs=false
      
            _ovs-get-other-config() {
              _ovs-vsctl --if-exists get Open_vSwitch . "other_config:$1" 2>/dev/null | tr -d '"'
            }
      
            _ovs-set-other-config() {
              if [ "$(_ovs-get-other-config "$1")" != "$2" ]; then
                _ovs-vsctl set Open_vSwitch . "other_config:$1=$2"
                restart_ovs=true
              fi
            }
      
            _ovs-remove-other-config() {
              if [ -n "$(_ovs-get-other-config "$1")" ]; then
                _ovs-vsctl remove Open_vSwitch . other_config "$1"
                restart_ovs=true
              fi
            }
      
            _ovs-set-other-config doca-init true
            _ovs-set-other-config dpdk-max-memzones 50000
            _ovs-set-other-config hw-offload true
            _ovs-set-other-config pmd-quiet-idle true
            _ovs-set-other-config max-idle 20000
            _ovs-set-other-config max-revalidator 5000
            _ovs-set-other-config doca-congestion-threshold 60
            _ovs-set-other-config flow-limit 500000
            _ovs-set-other-config hw-offload-ct-unidir-udp-enabled true
            _ovs-remove-other-config default-datapath-type
      
            if [ "$restart_ovs" = true ]; then
              if systemctl list-unit-files openvswitch-switch.service &>/dev/null; then
                systemctl restart openvswitch-switch
              elif systemctl list-unit-files openvswitch.service &>/dev/null; then
                systemctl restart openvswitch
              fi
            fi
      
            _ovs-vsctl --may-exist add-br br-sfc
            _ovs-vsctl set bridge br-sfc datapath_type=netdev
            _ovs-vsctl set bridge br-sfc fail_mode=secure
            _ovs-vsctl --if-exists del-br br-hbn
            _ovs-vsctl --may-exist add-br br-hbn
            _ovs-vsctl set bridge br-hbn datapath_type=netdev
            _ovs-vsctl set bridge br-hbn fail_mode=secure
            _ovs-vsctl --may-exist add-port br-sfc p0
            _ovs-vsctl set Interface p0 type=dpdk
            _ovs-vsctl set Interface p0 mtu_request=9216
            _ovs-vsctl set Port p0 external_ids:dpf-type=physical
      
            # Activate DOCA for OVNK
            _ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-datapath-type=netdev
            # setup ovnkube managed bridge, br-dpu (this corresponds to br-ex on ovnk docs)
            _ovs-vsctl --may-exist add-br br-dpu
            _ovs-vsctl br-set-external-id br-dpu bridge-id br-dpu
            _ovs-vsctl br-set-external-id br-dpu bridge-uplink pbrdputobrovn
            _ovs-vsctl set bridge br-dpu datapath_type=netdev
            _ovs-vsctl set Interface br-dpu mtu_request=9000
            _ovs-vsctl --may-exist add-port br-dpu pf0hpf
            _ovs-vsctl set Interface pf0hpf type=dpdk
      
            # Create OVS bridge (br-ovn) in between the SC managed bridge and OVNK
            _ovs-vsctl --may-exist add-br br-ovn
            _ovs-vsctl set bridge br-ovn datapath_type=netdev
            _ovs-vsctl set Interface br-ovn mtu_request=9000
            _ovs-vsctl --may-exist add-port br-ovn pbrovntobrdpu
            _ovs-vsctl --may-exist add-port br-dpu pbrdputobrovn
      
            # Patch br-ovn and br-dpu together
            _ovs-vsctl set Interface pbrovntobrdpu type=patch options:peer=pbrdputobrovn
            _ovs-vsctl set Interface pbrdputobrovn type=patch options:peer=pbrovntobrdpu
  2. Apply the resource file:

    $ envsubst < dpuflavor.yaml | oc apply -f -

Verification

  • Verify that the DPUFlavor resource is created:

    $ oc get dpuflavor -n dpf-operator-system

12.4.6. Create the BFB resource

You can create a BFB custom resource to define the DPU image, known as a BlueField Bootstream File, that is downloaded and placed on shared storage for DPU provisioning.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.
  • You have set the DPF Operator environment variables. For details, see "DPF Operator installation environment variables".

Procedure

  1. Create a file named bfb.yaml with the following content:

    apiVersion: provisioning.dpu.nvidia.com/v1alpha1
    kind: BFB
    metadata:
      name: bf-bundle
      namespace: dpf-operator-system
    spec:
      fileName: $BFB_FILENAME
      url: $BFB_URL
      versions:
        atf: 4.15.0-4-g419fbf393
        bsp: 4.15.0.13998
        doca: 3.4.1
        uefi: 4.15.0-19-g37c6f5adb2
  2. Set the BFB_FILENAME environment variable to the file name of the BFB image, which is the base name of BFB_URL:

    $ export BFB_FILENAME=$(basename "$BFB_URL")
  3. Apply the resource file:

    $ envsubst < bfb.yaml | oc apply -f -

Verification

  • Verify that the BFB image phase is Ready:

    $ oc get bfb -n dpf-operator-system bf-bundle

    Example output

    NAME        PHASE   AGE
    bf-bundle   Ready   3m

12.4.7. Create the DPUDeployment custom resource

You can create a DPUDeployment custom resource as the main orchestration object that connects DPU services with specific BFB images and DPU flavors. The DPUDeployment defines DPU sets for DPU provisioning and configures service chains to deploy services across DPUs.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.
  • You have created the NodeSRIOVDevicePluginConfig resource.
  • You have created the DPUFlavor resource.
  • You have created the BFB resource and it is in the Ready phase.

Procedure

  1. Create a file named dpudeployment.yaml with the following content:

    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUDeployment
    metadata:
      name: dpudeployment
      namespace: dpf-operator-system
    spec:
      dpus:
        nodeEffect:
          drain: true
        dpuSetStrategy:
          type: RollingUpdate
        bfb: bf-bundle
        flavor: hbn-ovnk
        dpuSets:
          - nameSuffix: "dpuset1"
            dpuNodeSelector:
              matchLabels:
                feature.node.kubernetes.io/dpu-enabled: ""
            dpuAnnotations:
              noderesources.dpu.nvidia.com/nodesriovdevicepluginconfig: bf3-vfs
      services:
        hbn:
          serviceTemplate: hbn
          serviceConfiguration: hbn
        ovn:
          serviceTemplate: ovn
          serviceConfiguration: ovn
        doca-telemetry-service:
          serviceTemplate: doca-telemetry-service
          serviceConfiguration: doca-telemetry-service
      serviceChains:
        switches:
          - ports:
              - serviceInterface:
                  matchLabels:
                    uplink: p0
              - service:
                  name: hbn
                  interface: p0_if
          - ports:
              - serviceInterface:
                  matchLabels:
                    uplink: p1
              - service:
                  name: hbn
                  interface: p1_if
          - ports:
              - serviceInterface:
                  matchLabels:
                    port: ovn
              - service:
                  name: hbn
                  interface: pf2dpu2_if
  2. Apply the resource file:

    $ oc apply -f dpudeployment.yaml

Verification

  • Verify the DPUDeployment state:

    $ oc get DPUDeployment -n dpf-operator-system

    Example output

    NAME            READY   PHASE     AGE
    dpudeployment   False   Pending   2m32s

    Note

    A Pending phase is expected at this stage. The DPUDeployment transitions to Ready after DPU provisioning is complete and all services are deployed.

12.4.8. Create the HBN DPU service configuration

You can create a DPUServiceConfiguration custom resource for the Host-Based Networking (HBN) DPU service. The HBN service provides BGP-based networking on the DPU with ECMP routing support.

Note

HBN and OVN-Kubernetes are currently the only supported DPU network services. The DOCA Telemetry Service (DTS), which you configure in a later step, is deployed for observability and is not a network service.

Note

The DPUServiceTemplate resources are automatically created and managed by the dpf-hcp-provisioner-operator. You only need to create the DPUServiceConfiguration resources.

Prerequisites

  • The DPF Operator is installed.
  • The DPFOperatorConfig resource is created.
  • The DPF Operator environment variables are set. For details, see "DPF Operator installation environment variables".

Procedure

  1. Create a file named hbn.yaml with the following content:

    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceConfiguration
    metadata:
      name: hbn
      namespace: dpf-operator-system
    spec:
      deploymentServiceName: "hbn"
      serviceConfiguration:
        serviceDaemonSet:
          annotations:
            k8s.v1.cni.cncf.io/networks: |-
              [
              {"name": "iprequest", "interface": "ip_lo", "cni-args": {"poolNames": ["loopback"], "poolType": "cidrpool"}},
              {"name": "iprequest", "interface": "ip_pf2dpu2", "cni-args": {"poolNames": ["pool1"], "poolType": "cidrpool", "allocateDefaultGateway": true}}
              ]
        helmChart:
          values:
            configuration:
              perDPUValuesYAML: |
                - hostnamePattern: "*"
                  values:
                    bgp_peer_group: hbn
              startupYAMLJ2: |
                - header:
                    model: BLUEFIELD
                    nvue-api-version: nvue_v1
                    rev-id: 1.0
                    version: HBN 2.4.0
                - set:
                    interface:
                      lo:
                        ip:
                          address:
                            {{ ipaddresses.ip_lo.ip }}/32: {}
                        type: loopback
                      p0_if,p1_if:
                        type: swp
                        link:
                          mtu: 9216
                      pf2dpu2_if:
                        ip:
                          address:
                            {{ ipaddresses.ip_pf2dpu2.cidr }}: {}
                        type: swp
                        link:
                          mtu: 9216
                    router:
                      bgp:
                        autonomous-system: {{ ( ipaddresses.ip_lo.ip.split(".")[3] | int ) + 65101 }}
                        enable: on
                        graceful-restart:
                          mode: full
                        router-id: {{ ipaddresses.ip_lo.ip }}
                    vrf:
                      default:
                        router:
                          bgp:
                            address-family:
                              ipv4-unicast:
                                enable: on
                                redistribute:
                                  connected:
                                    enable: on
                              ipv6-unicast:
                                enable: on
                                redistribute:
                                  connected:
                                    enable: on
                            enable: on
                            neighbor:
                              p0_if:
                                peer-group: {{ config.bgp_peer_group }}
                                type: unnumbered
                              p1_if:
                                peer-group: {{ config.bgp_peer_group }}
                                type: unnumbered
                            path-selection:
                              multipath:
                                aspath-ignore: on
                            peer-group:
                              {{ config.bgp_peer_group }}:
                                remote-as: external
      interfaces:
        - name: p0_if
          network: mybrhbn
        - name: p1_if
          network: mybrhbn
        - name: pf2dpu2_if
          network: mybrhbn
  2. Apply the resource file:

    $ oc apply -f hbn.yaml

    Example output

    dpuserviceconfiguration.svc.dpu.nvidia.com/hbn created

12.4.9. Create the OVN-Kubernetes DPU service configuration

You can create a DPUServiceConfiguration custom resource for the OVN-Kubernetes DPU service. The OVN-Kubernetes service provides pod networking on the DPU.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.
  • You have created the HBN DPUServiceConfiguration resource.
  • You have set the DPF Operator environment variables. For details, see "DPF Operator installation environment variables".

Procedure

  1. Create a file named ovn-k.yaml with the following content:

    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceConfiguration
    metadata:
      name: ovn
      namespace: dpf-operator-system
    spec:
      deploymentServiceName: "ovn"
      serviceConfiguration:
        helmChart:
          values:
            global:
              enableOvnKubeIdentity: false
            k8sAPIServer: https://$HOST_CLUSTER_API:6443
            podNetwork: 10.128.0.0/14/23
            serviceNetwork: 172.30.0.0/16
            hostNetworkNamespace: "openshift-host-network"
            mtu: $OVN_MTU
            dpuManifests:
              kubernetesSecretName: "ovn-dpu"
              vtepCIDR: $VTEP_CIDR
              hostCIDR: $DPU_HOST_CIDR
              ipamPool: "pool1"
              ipamPoolType: "cidrpool"
              ipamVTEPIPIndex: 0
              ipamPFIPIndex: 1
              cniBinDir: "/var/lib/cni/bin/"
              cniConfDir: "/run/multus/cni/net.d"
  2. Apply the resource file:

    $ envsubst < ovn-k.yaml | oc apply -f -

Verification

  • Verify that the HBN and OVN-Kubernetes service configurations are created:

    $ oc get dpuserviceconfiguration -n dpf-operator-system

You can create a DPUServiceConfiguration custom resource for the DOCA Telemetry Service. The DOCA Telemetry Service provides metrics collection from the DPUs by using Prometheus.

Note

The DPUServiceTemplate for DOCA Telemetry Service is automatically created and managed by the dpf-hcp-provisioner-operator controller. The operator uses the correct chart and image versions for the installed DPF version. You only need to create the DPUServiceConfiguration resource.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.
  • You have set the DPF Operator environment variables. For details, see "DPF Operator installation environment variables".

Procedure

  1. Create a file named dts.yaml with the following content:

    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceConfiguration
    metadata:
      name: doca-telemetry-service
      namespace: dpf-operator-system
    spec:
      deploymentServiceName: "doca-telemetry-service"
      serviceConfiguration:
        configPorts:
          ports:
            - name: httpserverport
              port: 9189
              protocol: TCP
          serviceType: None
  2. Apply the resource file:

    $ oc apply -f dts.yaml

Verification

  • Verify that the DOCA Telemetry Service configuration is created:

    $ oc get dpuserviceconfiguration -n dpf-operator-system doca-telemetry-service

To authenticate with the management cluster API server, create a DPUServiceCredentialRequest custom resource and the associated role bindings to enable the OVN-Kubernetes DPU service on the hosted cluster. The ClusterRoleBinding grants the required permissions for OVN node network operations.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.

Procedure

  1. Create a file named dpucredentialreq.yaml with the following content:

    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceCredentialRequest
    metadata:
      name: ovn-dpu
      namespace: dpf-operator-system
    spec:
      serviceAccount:
        name: ovn-kubernetes-node-dpu-service
        namespace: openshift-ovn-kubernetes
      duration: 24h
      type: tokenFile
      secret:
        name: ovn-dpu
        namespace: dpf-operator-system
      metadata:
        labels:
          dpu.nvidia.com/image-pull-secret: ""
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: openshift-ovn-kubernetes-node-limited-dpu-service
      namespace: openshift-ovn-kubernetes
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: openshift-ovn-kubernetes-node-limited
    subjects:
    - kind: ServiceAccount
      name: ovn-kubernetes-node-dpu-service
      namespace: openshift-ovn-kubernetes
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: ovn-kubernetes-node-limited-binding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: openshift-ovn-kubernetes-node-limited
    subjects:
    - kind: ServiceAccount
      name: ovn-kubernetes-node-dpu-service
      namespace: openshift-ovn-kubernetes
  2. Apply the resource file:

    $ oc apply -f dpucredentialreq.yaml

Verification

  • Verify that the credential request and role bindings are created:

    $ oc get dpuservicecredentialrequest -n dpf-operator-system
    $ oc get clusterrolebinding ovn-kubernetes-node-limited-binding

12.4.12. Create the DPUServiceInterface custom resources

You can create DPUServiceInterface custom resources to define interface objects that are specified in service chains. You must create physical interface resources for the DPU ports and an OVN-Kubernetes interface resource for host workloads.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.

Procedure

  1. Create a file named physical-if.yaml with the following content to define the physical DPU port interfaces:

    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceInterface
    metadata:
      name: p0
      namespace: dpf-operator-system
    spec:
      template:
        spec:
          template:
            metadata:
              labels:
                uplink: "p0"
            spec:
              interfaceType: physical
              physical:
                interfaceName: p0
    ---
    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceInterface
    metadata:
      name: p1
      namespace: dpf-operator-system
    spec:
      template:
        spec:
          template:
            metadata:
              labels:
                uplink: "p1"
            spec:
              interfaceType: physical
              physical:
                interfaceName: p1
  2. Apply the physical interface resource file:

    $ oc apply -f physical-if.yaml
  3. Create a file named ovnk-if.yaml with the following content to define the OVN-Kubernetes interface:

    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceInterface
    metadata:
      name: ovn
      namespace: dpf-operator-system
    spec:
      template:
        spec:
          template:
            metadata:
              labels:
                port: ovn
            spec:
              interfaceType: ovn
  4. Apply the OVN-Kubernetes interface resource file:

    $ oc apply -f ovnk-if.yaml

Verification

  • Verify that all DPUServiceInterface resources are created:

    $ oc get dpuserviceinterface -n dpf-operator-system

12.4.13. Create the DPUServiceNAD resource

Create a DPUServiceNAD custom resource to define the network attachment available to DPU services on the hosted cluster. The DPUServiceNAD resource maps to an Open vSwitch (OVS) bridge on the DPU and specifies the resource type, IP address management (IPAM) mode, and maximum transmission unit (MTU) configuration:

  • mybrhbn maps to the br-hbn bridge, used by the HBN service. IPAM is disabled because IP allocation is handled by DPUServiceIPAM.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.
  • You have set the DPF Operator environment variables. For details, see "DPF Operator installation environment variables".

Procedure

  1. Create a file named dpuservice-nad.yaml with the following content:

    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceNAD
    metadata:
      name: mybrhbn
      namespace: dpf-operator-system
    spec:
      resourceType: sf
      ipam: false
      bridge: "br-hbn"
      serviceMTU: $NODES_MTU
  2. Apply the resource file:

    $ envsubst < dpuservice-nad.yaml | oc apply -f -

Verification

  • Verify that the DPUServiceNAD resource is created:

    $ oc get dpuservicenad mybrhbn -n dpf-operator-system

    Example output

    NAME       READY   AGE
    mybrhbn    True    2m

12.4.14. Create the DPUServiceIPAM resources

You can create DPUServiceIPAM custom resources to configure IP address management for DPU services. Two IPAM pools are required: one for the VTEP network used by the high-speed data plane, and one for loopback addresses used by the HBN service.

Prerequisites

  • You have installed the DPF Operator.
  • You have created the DPFOperatorConfig resource.
  • You have set the DPF Operator environment variables. For details, see "DPF Operator installation environment variables".

Procedure

  1. Create a file named dpuservice-ipam.yaml with the following content:

    ---
    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceIPAM
    metadata:
      name: pool1
      namespace: dpf-operator-system
    spec:
      ipv4Network:
        network: $VTEP_CIDR
        gatewayIndex: 3
        prefixSize: 29
    ---
    apiVersion: svc.dpu.nvidia.com/v1alpha1
    kind: DPUServiceIPAM
    metadata:
      name: loopback
      namespace: dpf-operator-system
    spec:
      ipv4Network:
        network: "11.0.0.0/24"
        prefixSize: 32
  2. Apply the resource file:

    $ envsubst < dpuservice-ipam.yaml | oc apply -f -

Verification

  • Verify that the DPUServiceIPAM resources are created:

    $ oc get dpuserviceipam -n dpf-operator-system

12.5. Provision the DPU hosted cluster

The DPF HCP Provisioner Operator automates the creation and lifecycle management of a hosted control plane cluster for DPU nodes.

The DPF HCP Provisioner Operator abstracts hosted control plane complexity for DPF by orchestrating the full lifecycle of hosted clusters for DPU environments. The Operator treats the hosted control plane as a black box and maintains a 1:1:1 relationship: each DPFHCPProvisioner custom resource maps to exactly one DPUCluster and one HostedCluster.

The Operator provides the following capabilities:

HostedCluster lifecycle management
Creates, updates, and deletes HostedCluster, NodePool, and associated secret resources.
Automatic CSR approval
Approves Certificate Signing Requests from DPU worker nodes joining the hosted cluster.
BlueField OpenShift Container Platform layer image lookup
Matches OpenShift Container Platform release images to corresponding BlueField container images by using container registry tag lookup.
Kubeconfig provisioning
Extracts the hosted cluster admin kubeconfig, stores it in a secret, and sets the spec.kubeconfig field of the DPUCluster custom resource to reference that secret, enabling the management cluster to communicate with the DPU hosted cluster.
MetalLB configuration
Deploys IPAddressPool and L2Advertisement resources for LoadBalancer service exposure.
Ignition generation
Generates BlueField-specific ignition configurations from hosted control plane ignition for DPU node provisioning.
Status translation
Mirrors HostedCluster conditions to DPFHCPProvisioner status without exposing hosted control plane internals.

12.5.2. Install the DPF HCP Provisioner Operator

You can install the DPF HCP Provisioner Operator by using a Helm chart. The operator manages the lifecycle of hosted clusters for DPU environments.

Prerequisites

  • The Multicluster Engine (MCE) Operator is installed and hosted control planes is enabled.
  • The MetalLB Operator is installed and a MetalLB instance is created.
  • A storage class is available for etcd persistent volumes, such as LVM Storage or an equivalent.
  • The DPF Operator is installed and DPF CRDs are available.
  • The Helm CLI (helm) is installed on your workstation.
  • You have a pull secret file that includes credentials for registry.redhat.io. Helm reads its registry credentials from this file, which is separate from the container runtime configuration.

Procedure

  1. Set the OPENSHIFT_PULL_SECRET environment variable to the path of your pull secret file:

    $ export OPENSHIFT_PULL_SECRET="/root/pull-secret.txt"
  2. Install the operator by using Helm:

    $ helm upgrade --install dpf-hcp-provisioner-operator \
        oci://registry.redhat.io/dpu-kit-for-nvidia/dpf-hcp-provisioner-chart \
        --registry-config "${OPENSHIFT_PULL_SECRET}" \
        --version 4.22.0 \
        --namespace dpf-hcp-provisioner-system \
        --create-namespace \
        --set provisionerConfig.manageDPUServiceTemplates=true

    Example output

    NAME: dpf-hcp-provisioner-operator
    LAST DEPLOYED: ...
    NAMESPACE: dpf-hcp-provisioner-system
    STATUS: deployed

    Note

    The Helm chart creates a DPFHCPProvisionerConfig singleton custom resource named default that defines the Operator-wide configuration. This resource controls settings such as the BlueField OpenShift Container Platform layer image repository, MetalLB integration, and DPUServiceTemplate management. To customize these settings, modify the provisionerConfig section in your Helm values.yaml file before running the helm upgrade --install command.

Verification

  • Verify that the Operator pod is running:

    $ oc get pods -n dpf-hcp-provisioner-system

    Example output

    NAME                                            READY   STATUS    RESTARTS   AGE
    dpf-hcp-provisioner-operator-xxx-yyy            1/1     Running   0          1m

  • Verify that the DPFHCPProvisionerConfig singleton resource was created and that manageDPUServiceTemplates is set to true:

    $ oc get dpfhcpprovisionerconfigs.provisioning.dpu.hcp.io default -o yaml

    Example output

    apiVersion: provisioning.dpu.hcp.io/v1alpha1
    kind: DPFHCPProvisionerConfig
    metadata:
      name: default
      labels:
        app.kubernetes.io/managed-by: Helm
        helm.sh/chart: dpf-hcp-provisioner-chart-4.22.0
    spec:
      blueFieldOCPLayerRepo: registry.redhat.io/dpu-kit-for-nvidia/bluefield-ocp-layer-rhel10 
    1
    
      disableMetalLB: false 
    2
    
      manageDPUServiceTemplates: true 
    3

    where:

    blueFieldOCPLayerRepo
    The container registry repository for BlueField OpenShift Container Platform layer images. The operator queries this repository for an image tag that matches the OpenShift Container Platform version.
    disableMetalLB
    Disables MetalLB configuration even when a virtual IP is specified.
    manageDPUServiceTemplates
    Controls whether the operator creates and manages the DPUServiceTemplate resources for OVN-Kubernetes, DTS, and HBN in the DPUCluster namespace. This value must be true otherwise DPU provisioning fails because the required DPUServiceTemplate resources are missing. This field is deprecated and will be removed in a future release, at which point DPUServiceTemplate management is always enabled.

12.5.3. Hosted cluster provisioning environment variables

The following environment variables are used throughout the hosted cluster provisioning procedures. These environment variables must be set before you create secrets, the DPUCluster resource, or the DPFHCPProvisioner resource.

Expand
Table 12.9. Hosted cluster provisioning environment variables
VariableDescriptionExample value

HOSTED_CLUSTER_NAME

The name of the hosted DPU cluster.

dpf-hosted

OPENSHIFT_VERSION

The OpenShift Container Platform version for the hosted cluster.

4.22.7

CLUSTERS_NAMESPACE

The namespace where hosted cluster resources are created.

clusters

BASE_DOMAIN

The base DNS domain for the hosted cluster.

example.com

BLUEFIELD_OCP_IMAGE

Optional. The BlueField OpenShift Container Platform layer container image URL. When set, this value is used as machineOSURL in the DPFHCPProvisioner resource and skips automatic image lookup. If left unset, the Operator resolves the image automatically. This image will be available on registry.redhat.io for GA release.

<GA-BLUEFIELD-OCP-IMAGE>

ETCD_STORAGE_CLASS

The storage class used for etcd persistent volume claims.

lvms-vg1

OCP_RELEASE_IMAGE

The OpenShift Container Platform release image for the hosted cluster. Derived from OPENSHIFT_VERSION.

quay.io/openshift-release-dev/ocp-release:4.22.7-multi

PULL_SECRET_NAME

The name of the Kubernetes secret that contains the pull secret for the hosted cluster.

pull-secret

OPENSHIFT_PULL_SECRET

The file path to the pull secret JSON file on your workstation.

/root/pull-secret.txt

SSH_KEY_SECRET_NAME

The name of the Kubernetes secret that contains the SSH public key for the hosted cluster.

ssh-key

SSH_KEY

The file path to the SSH public key file on your workstation. Use ed25519 keys for better security.

/root/.ssh/id_ed25519.pub

HOSTED_CLUSTER_VIP

The virtual IP address for the hosted cluster API server, allocated from the management cluster subnet.

192.168.1.200

You must set all environment variables in your terminal session before you proceed.

$ export HOSTED_CLUSTER_NAME="dpf-hosted"
$ export OPENSHIFT_VERSION="4.22.7"
$ export CLUSTERS_NAMESPACE="clusters"
$ export BASE_DOMAIN="example.com"
$ export BLUEFIELD_OCP_IMAGE="<GA-BLUEFIELD-OCP-IMAGE>"
$ export ETCD_STORAGE_CLASS="lvms-vg1"
$ export OCP_RELEASE_IMAGE="quay.io/openshift-release-dev/ocp-release:${OPENSHIFT_VERSION}-multi"
$ export PULL_SECRET_NAME="my-pull-secret"
$ export OPENSHIFT_PULL_SECRET="/root/pull-secret.txt"
$ export SSH_KEY_SECRET_NAME="my-ssh-key"
$ export SSH_KEY="/root/.ssh/id_ed25519.pub"
$ export HOSTED_CLUSTER_VIP="192.168.1.200"
$ export DPU_HOST_CIDR="10.0.110.0/24"
$ export VTEP_CIDR="10.0.120.0/22"
$ export NODES_MTU="1500"      # Use 1500 for standard MTU, 9000 for jumbo frames
$ export FLANNEL_POD_CIDR="10.132.0.0/14"

12.5.4. Create secrets for the hosted cluster

You must create a pull secret and an SSH key secret in the clusters namespace before provisioning the hosted cluster. The DPFHCPProvisioner resource references these secrets during hosted cluster creation.

Note

The BlueField OpenShift Container Platform layer image referenced by BLUEFIELD_OCP_IMAGE might require authentication to the Quay or Red Hat registry. Ensure that the pull secret includes credentials for that image registry.

Prerequisites

  • You have set the environment variables described in "Hosted cluster provisioning environment variables".
  • You have a valid OpenShift Container Platform pull secret file at the path specified by OPENSHIFT_PULL_SECRET.
  • You have an SSH public key file at the path specified by SSH_KEY.

Procedure

  1. Create the clusters namespace:

    $ oc create namespace $CLUSTERS_NAMESPACE
  2. Create the pull secret:

    $ oc create secret generic $PULL_SECRET_NAME \
        --from-file=.dockerconfigjson=$OPENSHIFT_PULL_SECRET \
        --type=Opaque \
        -n $CLUSTERS_NAMESPACE
  3. Create the SSH key secret:

    $ oc create secret generic $SSH_KEY_SECRET_NAME \
        --from-file=id_rsa.pub=$SSH_KEY \
        --type=Opaque \
        -n $CLUSTERS_NAMESPACE
    Note

    The id_rsa.pub secret data key is a fixed name that the provisioner expects and it does not require an RSA key. The SSH_KEY variable can point to any supported public key file, such as an Ed25519 key.

Verification

  • Verify that the secrets were created in the clusters namespace:

    $ oc get secrets -n $CLUSTERS_NAMESPACE

    Example output

    NAME             TYPE     DATA   AGE
    my-pull-secret   Opaque   1      10s
    my-ssh-key       Opaque   1      5s

12.5.5. Create the DPUCluster custom resource

The DPUCluster resource tells the DPF Operator about the hosted cluster where DPU services will run.

Do not set the spec.kubeconfig field. After you create the hosted cluster, the DPF HCP Provisioner Operator automatically creates the admin kubeconfig secret in the dpf-operator-system namespace and sets the spec.kubeconfig field of this resource to reference it.

Prerequisites

  • You have set the environment variables described in "Hosted cluster provisioning environment variables".
  • You have installed the DPF Operator.

Procedure

  1. Create a file named dpucluster.yaml with the following content:

    apiVersion: provisioning.dpu.nvidia.com/v1alpha1
    kind: DPUCluster
    metadata:
      name: $HOSTED_CLUSTER_NAME
      namespace: dpf-operator-system
    spec:
      type: static
      maxNodes: 10
  2. Apply the resource with variable substitution:

    $ envsubst < dpucluster.yaml | oc apply -f -

Verification

  • Verify that the DPUCluster resource was created:

    $ oc get dpucluster -n dpf-operator-system

12.5.6. Create the DPFHCPProvisioner custom resource

The DPFHCPProvisioner custom resource triggers the creation of the complete hosted cluster infrastructure. This includes the HostedCluster, the MetalLB IPAddressPool, the L2Advertisement, and kubeconfig injection into the DPUCluster.

Prerequisites

  • You have set the environment variables described in "Hosted cluster provisioning environment variables".
  • You have installed the DPF HCP Provisioner Operator and it is running.
  • You have created the pull secret and SSH key secret in the clusters namespace.
  • You have created the DPUCluster resource in the dpf-operator-system namespace.

Procedure

  1. Create a file named dpfhcpprovisioner.yaml with the following content:

    apiVersion: provisioning.dpu.hcp.io/v1alpha1
    kind: DPFHCPProvisioner
    metadata:
      name: $HOSTED_CLUSTER_NAME
      namespace: $CLUSTERS_NAMESPACE
    spec:
      baseDomain: $BASE_DOMAIN
      dpuClusterRef:
        name: $HOSTED_CLUSTER_NAME
        namespace: dpf-operator-system
      dpuDeploymentRef:
        name: dpudeployment
        namespace: dpf-operator-system
      etcdStorageClass: $ETCD_STORAGE_CLASS
      ocpReleaseImage: $OCP_RELEASE_IMAGE
      pullSecretRef:
        name: $PULL_SECRET_NAME
      sshKeySecretRef:
        name: $SSH_KEY_SECRET_NAME
      virtualIP: $HOSTED_CLUSTER_VIP

    where:

    baseDomain
    Specifies the base DNS domain for the hosted cluster.
    dpuClusterRef
    Specifies a reference to the DPUCluster resource that represents the DPU hosted cluster.
    dpuDeploymentRef
    Specifies a reference to the DPUDeployment resource in the dpf-operator-system namespace.
    etcdStorageClass
    Specifies the storage class for etcd persistent volume claims.
    ocpReleaseImage
    Specifies the OpenShift Container Platform release image for the hosted cluster.
    pullSecretRef
    Specifies the name of the pull secret in the same namespace.
    sshKeySecretRef
    Specifies the name of the SSH key secret in the same namespace.
    virtualIP
    Specifies the virtual IP address for the hosted cluster API server, allocated from the management cluster subnet.

    The following optional fields use working defaults and do not need to be specified unless you want to override them:

    controlPlaneAvailabilityPolicy
    Specifies the availability policy for the hosted cluster control plane. This optional parameter defaults to HighlyAvailable. Set it to SingleReplica for a single-node control plane, in which case virtualIP is not required.
    flannelEnabled
    Specifies whether to enable Flannel networking in the hosted cluster. This optional parameter defaults to true.
    clusterNetwork
    Specifies the pod network CIDR for the hosted cluster. This optional parameter defaults to 10.128.0.0/14.
    serviceNetwork
    Specifies the service network CIDR for the hosted cluster. This optional parameter defaults to 172.30.0.0/16.
    machineNetwork
    Specifies the machine network CIDR for the hosted cluster. This optional parameter uses the management cluster network by default.
    nodeSelector
    Specifies a node selector for scheduling the hosted control plane pods. This optional parameter uses default scheduling by default.
  2. Apply the resource with variable substitution:

    $ envsubst < dpfhcpprovisioner.yaml | oc apply -f -

12.5.7. Verify hosted cluster creation

After creating the DPFHCPProvisioner resource, you can monitor its status to verify that the hosted cluster is provisioned and becomes ready. The provisioning process can take up to 30 minutes.

Prerequisites

  • You have created the DPFHCPProvisioner resource in the clusters namespace.

Procedure

  1. Monitor the DPFHCPProvisioner status:

    $ oc get dpfhcpprovisioner -n ${CLUSTERS_NAMESPACE}

    Example output

    NAME         PHASE          READY   HOSTEDCLUSTER   AGE
    dpf-hosted   Provisioning   False   dpf-hosted      2m

  2. Wait for the DPFHCPProvisioner to reach the Ready phase:

    $ oc wait dpfhcpprovisioner ${HOSTED_CLUSTER_NAME} -n ${CLUSTERS_NAMESPACE} \
        --for=jsonpath='{.status.phase}'=Ready --timeout=30m

    Example output

    dpfhcpprovisioner.provisioning.dpu.hcp.io/dpf-hosted condition met

Verification

  • Confirm that the DPUCluster is ready:

    $ oc get dpucluster ${HOSTED_CLUSTER_NAME} -n dpf-operator-system

    A Ready status indicates that the operator created the admin kubeconfig secret referenced by the DPUCluster resource and that the hosted cluster API is reachable, which is the prerequisite for DPU worker nodes to join:

  • Confirm that the admin kubeconfig secret referenced by the DPUCluster was created in the dpf-operator-system namespace:

    $ oc get secret ${HOSTED_CLUSTER_NAME}-admin-kubeconfig -n dpf-operator-system

    Example output

    NAME                          TYPE     DATA   AGE
    dpf-hosted-admin-kubeconfig   Opaque   1      10m

12.5.8. Verify DPU service reconciliation

After the DPU hosted cluster and DPUCluster are ready, verify that the DPU services, IPAM pools, service interfaces, and service chains created for the DPUDeployment are reconciled.

Prerequisites

  • You have created the DPF custom resources: DPFOperatorConfig, NodeSRIOVDevicePluginConfig, DPUFlavor, BFB, and DPUDeployment.
  • You have created the HBN, OVN-Kubernetes, and DTS DPU service resources.
  • The DPUCluster is ready.
  • You have access to the management cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
Note

You might need to run the commands multiple times to ensure that the condition is met, because the DPU services can take time to converge.

Procedure

  1. Verify that the DPUService resources are created and reconciled:

    $ oc wait --for=condition=ApplicationsReconciled \
      --namespace dpf-operator-system dpuservices \
      -l svc.dpu.nvidia.com/owned-by-dpudeployment=dpf-operator-system_dpudeployment
  2. Verify that the DPUServiceIPAM resources are reconciled:

    $ oc wait --for=condition=DPUIPAMObjectReconciled \
      --namespace dpf-operator-system dpuserviceipam --all
  3. Verify that the DPUServiceInterface resources are reconciled:

    $ oc wait --for=condition=ServiceInterfaceSetReconciled \
      --namespace dpf-operator-system dpuserviceinterface --all
  4. Verify that the DPUServiceChain resources are reconciled:

    $ oc wait --for=condition=ServiceChainSetReconciled \
      --namespace dpf-operator-system dpuservicechain --all

12.6. Add worker nodes and provision DPUs

After the DPF Operator and the hosted cluster are configured, adjust the OVN-Kubernetes CNI settings, add DPU-equipped worker nodes to the management cluster, and provision the DPUs.

12.6.1. Enable the OVN-Kubernetes resource injector

You can install the OVN-Kubernetes resource injector by using Helm to deploy a mutating admission webhook that automatically injects SR-IOV virtual function resource requests and network attachment annotations into each pod scheduled to a worker node.

Note

Virtual function resource capacity on worker nodes is provided by the NodeSRIOVDevicePluginConfig resource, which replaces the manual SR-IOV device plugin DaemonSet and control plane node patching used in earlier DPF versions.

Prerequisites

  • You have access to the management cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • You have installed the helm CLI.
  • You have set the DPF Operator environment variables. For details, see "DPF Operator installation environment variables".
  • You have created the NodeSRIOVDevicePluginConfig resource.

Procedure

  1. Install the OVN-Kubernetes resource injector by using Helm:

    $ helm upgrade --install -n openshift-ovn-kubernetes ovn-kubernetes \
      "$OVN_TEMPLATE_CHART_URL/ovn-kubernetes-chart" \
      --version "${OVN_CHART_VERSION}" \
      --skip-crds \
      --set ovn-kubernetes-resource-injector.enabled=true \
      --set ovn-kubernetes-resource-injector.resourceName="openshift.io/bf3_vfs" \
      --set ovn-kubernetes-resource-injector.prioritizeOffloading=false \
      --set ovn-kubernetes-resource-injector.controllerManager.hostNetwork=true \
      --set ovn-kubernetes-resource-injector.controllerManager.webhookPort="19443" \
      --set ovn-kubernetes-resource-injector.controllerManager.healthProbeBindAddress=":18081" \
      --set ovn-kubernetes-resource-injector.controllerManager.webhook.image.pullPolicy=IfNotPresent \
      --set "ovn-kubernetes-resource-injector.controllerManager.webhook.args={--leader-elect,--metrics-bind-address=:29091}" \
      --set nodeWithDPUManifests.enabled=false \
      --set nodeWithoutDPUManifests.enabled=false \
      --set dpuManifests.enabled=false \
      --set controlPlaneManifests.enabled=false \
      --set commonManifests.enabled=false

    Example output

    NAME: ovn-kubernetes
    LAST DEPLOYED: Sun Nov  2 17:10:29 2025
    NAMESPACE: openshift-ovn-kubernetes
    STATUS: deployed
    REVISION: 1
    DESCRIPTION: Install complete
    TEST SUITE: None

Verification

  • Verify the resource injector mutating webhook configuration was applied:

    $ oc get mutatingwebhookconfiguration | grep ovn

    Example output

    NAME                                                WEBHOOKS   AGE
    ovn-kubernetes-ovn-kubernetes-resource-injector     1          22h

12.6.2. OVN-Kubernetes DPU-Host mode

DPU-Host mode on worker nodes with accelerated OVN-Kubernetes CNI is automatically configured by the DPF provisioning controller.

When the DPFOperatorConfig resource is created and worker nodes with the worker-dpu label are provisioned, the DPF provisioning controller automatically configures the required settings for DPU-Host mode, including the network node identity and hardware offload configuration.

12.6.3. Add worker nodes by using the Bare Metal Operator

You can add DPU-equipped worker nodes to the management cluster by creating BareMetalHost resources that the Bare Metal Operator provisions.

Prerequisites

  • You have access to the management cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • You have installed the Bare Metal Operator on the management cluster.
  • Physical worker servers with Redfish-compatible BMC, iDRAC, or iLO access are available.
  • Network connectivity exists from the management cluster to the worker BMC interfaces.
  • You have the BMC IP address and access credentials for each server.
  • You have the MAC address of the management network interface for each server.
  • You have the name of the root disk device for each server.

Procedure

  1. Set the following environment variables for the worker node:

    $ export BMC_IP=<bmc_ip_address>
    $ export BMC_USER=<bmc_username>
    $ export BMC_PASSWORD=<bmc_password>
    $ export WORKER_NAME=<worker_name>
    $ export BOOT_MAC=<management_interface_mac>
    $ export ROOT_DEVICE=<root_device_path>

    where:

    <bmc_ip_address>
    Specifies the IP address of the worker node BMC interface.
    <bmc_username>
    Specifies the username for BMC access.
    <bmc_password>
    Specifies the password for BMC access.
    <worker_name>
    Specifies a name for the worker node, such as worker-01.
    <management_interface_mac>
    Specifies the MAC address of the out-of-band management interface, such as 00:00:5E:00:53:01.
    <root_device_path>
    Specifies the path to the root disk device, such as /dev/nvme0n1.
  2. Verify BMC connectivity from one of the control plane nodes:

    $ ping $BMC_IP
    $ curl -k https://$BMC_IP/redfish/v1/
    $ curl -k -u $BMC_USER:$BMC_PASSWORD https://$BMC_IP/redfish/v1/Systems
  3. Verify that the Bare Metal Operator is available:

    $ oc get clusteroperator baremetal
  4. Create a file named provisioning.yaml with the following content to disable the provisioning network:

    apiVersion: metal3.io/v1alpha1
    kind: Provisioning
    metadata:
      name: provisioning-configuration
    spec:
      provisioningNetwork: "Disabled"
      watchAllNamespaces: false
    Important

    When provisioningNetwork is set to Disabled, servers boot by using Redfish virtual media instead of PXE.

  5. Apply the Provisioning resource:

    $ oc apply -f provisioning.yaml
  6. Create a file named bmc-secret.yaml with the following content to store the BMC credentials:

    apiVersion: v1
    kind: Secret
    metadata:
      name: ${WORKER_NAME}-bmc-secret
      namespace: openshift-machine-api
    type: Opaque
    stringData:
      username: ${BMC_USER}
      password: ${BMC_PASSWORD}
  7. Apply the BMC credentials secret:

    $ envsubst < bmc-secret.yaml | oc apply -f -
  8. Create a file named baremetalhost.yaml. The userData secret determines the node type:

    • For a DPU-equipped worker node, reference the worker-dpu-user-data-managed secret:

      apiVersion: metal3.io/v1alpha1
      kind: BareMetalHost
      metadata:
        name: $WORKER_NAME
        namespace: openshift-machine-api
      spec:
        online: true
        bootMACAddress: $BOOT_MAC
        rootDeviceHints:
          deviceName: $ROOT_DEVICE
        bmc:
          address: redfish-virtualmedia+https://$BMC_IP
          credentialsName: $WORKER_NAME-bmc-secret
          disableCertificateVerification: true
        customDeploy:
          method: install_coreos
        userData:
          name: worker-dpu-user-data-managed
          namespace: openshift-machine-api
    • For a regular worker node without a DPU, reference the worker-user-data-managed secret instead:

      apiVersion: metal3.io/v1alpha1
      kind: BareMetalHost
      metadata:
        name: $WORKER_NAME
        namespace: openshift-machine-api
      spec:
        online: true
        bootMACAddress: $BOOT_MAC
        rootDeviceHints:
          deviceName: $ROOT_DEVICE
        bmc:
          address: redfish-virtualmedia+https://$BMC_IP
          credentialsName: $WORKER_NAME-bmc-secret
          disableCertificateVerification: true
        customDeploy:
          method: install_coreos
        userData:
          name: worker-user-data-managed
          namespace: openshift-machine-api
      Important

      Adding a regular worker node without a DPU is a Technology Preview feature.

  9. Apply the BareMetalHost resource:

    $ envsubst < baremetalhost.yaml | oc apply -f -

Verification

  • Monitor the provisioning progress:

    $ oc get bmh -n openshift-machine-api -w

    Example output

    NAME        STATE          CONSUMER   ONLINE   ERROR   AGE
    worker-01   registering               true             10s
    worker-01   inspecting                true             15s
    worker-01   preparing                 true             20s
    worker-01   available                 true             30s
    worker-01   provisioning              true             1m
    worker-01   provisioned               true             10m

12.6.4. Approve worker node CSRs

You must approve the pending certificate signing requests (CSRs) for worker nodes that join the management cluster.

Note

Worker nodes provisioned by using a BareMetalHost resource do not have an associated Machine object, so the default OpenShift machine approver does not automatically approve their certificate signing requests (CSRs). You must manually approve the kube-apiserver-client-kubelet CSR from the node-bootstrapper service account and the kubelet-serving CSR from the node for each worker node.

Prerequisites

  • You have access to the management cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • Worker nodes are booted and attempting to join the management cluster.

Procedure

  1. Watch for pending CSRs:

    $ oc get csr -w
  2. Approve all pending CSRs:

    $ oc get csr -o go-template='{{range .items}}{{if not .status}}{{.metadata.name}}{{"\n"}}{{end}}{{end}}' | xargs oc adm certificate approve

    Example output

    certificatesigningrequest.certificates.k8s.io/csr-27bgq approved
    certificatesigningrequest.certificates.k8s.io/csr-69g65 approved
    certificatesigningrequest.certificates.k8s.io/csr-7r862 approved
    certificatesigningrequest.certificates.k8s.io/csr-f5vk7 approved

    Repeat this step until no pending CSRs remain. Each node typically generates multiple CSRs.

  3. Verify that the worker nodes joined the cluster:

    $ oc get nodes

    Example output

    NAME               STATUS     ROLES                         AGE     VERSION
    host-worker1       NotReady   worker                        68s     v1.35.6
    host-worker2       NotReady   worker                        75s     v1.35.6
    master-0           Ready      control-plane,master,worker   4d22h   v1.35.6
    master-1           Ready      control-plane,master,worker   4d21h   v1.35.6
    master-2           Ready      control-plane,master,worker   4d22h   v1.35.6

    Note

    The worker nodes show a status of NotReady until the DPU provisioning process is fully completed and all OVN-Kubernetes CNI components on the host and the DPU are running. Do not proceed to the next steps until all pending CSRs are approved.

12.6.5. Verify DPU provisioning

After the worker nodes join the management cluster, the DPUSet controller automatically detects nodes with the feature.node.kubernetes.io/dpu-enabled label, which the Node Feature Discovery Operator applies to DPU-equipped nodes. The controller then creates a DPU object for each node and starts the provisioning process. You can monitor the provisioning stages to verify progress.

Prerequisites

  • You have access to the management cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • The worker node CSRs are approved and the nodes have joined the management cluster.

Procedure

  1. Watch for DPU object creation:

    $ oc get dpu -n dpf-operator-system -w

    Example output

    NAME                     READY   OPERATIONAL   PHASE                        AGE
    <node-name>-<dpu-id>             Unknown       Node Effect                  25s
    <node-name>-<dpu-id>             Unknown       Initialize Interface         26s
    <node-name>-<dpu-id>             Unknown       Config FW Parameters         28s
    <node-name>-<dpu-id>             Unknown       Prepare BFB                  28s
    <node-name>-<dpu-id>             Unknown       OS Installing                5m28s
    <node-name>-<dpu-id>             Unknown       DPU Config                   15m
    <node-name>-<dpu-id>             Unknown       Rebooting                    26m
    <node-name>-<dpu-id>             Unknown       Host Network Configuration   27m
    <node-name>-<dpu-id>             False         DPU Cluster Config           64m
    <node-name>-<dpu-id>             Unknown       Node Effect Removal          71m
    <node-name>-<dpu-id>     True    True          Ready                        71m

    The DPU objects progress through the following provisioning stages:

    Initializing
    The DPU object is created.
    OS Installing
    The BFB installation is in progress.
    Rebooting
    The host and DPU are resetting.
    DPU Cluster Config
    The DPU Kubernetes node join procedure is in progress. Manual CSR approval is required during this stage.
    Host Network Configuration
    Networking configuration adjustments are applied on the host.
    Ready
    The DPU is successfully provisioned and ready to use.
    Error
    Provisioning failed. Check events and conditions for details.
    Important

    When the provisioning stage reaches DPU Cluster Config, proceed to "Configure authorization for the hosted cluster" and "Approve DPU node CSRs" to complete the DPU node join process.

  2. Monitor detailed provisioning progress:

    $ oc -n dpf-operator-system exec deploy/dpf-operator-controller-manager -- /dpfctl describe dpudeployments
  3. Optional: View detailed status for a specific DPU object:

    In the following command, replace <dpu_name> with the name of the DPU resource:

    $ oc describe dpu -n dpf-operator-system <dpu_name>
  4. Optional: Follow the provisioning controller logs for a specific DPU:

    In the following command, replace <dpu_name> with the name of the DPU resource:

    $ oc logs -n dpf-operator-system -l dpu.nvidia.com/component=dpf-provisioning-controller-manager --tail=-1 -f | grep <dpu_name>

12.6.6. Configure authorization for the hosted cluster

DPF services running on DPU nodes require privileged access to host networking and devices. You must create a ClusterRoleBinding on the hosted cluster that grants the privileged security context constraint (SCC) to all service accounts in the dpf-operator-system namespace.

Prerequisites

  • You have access to the hosted cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • The hosted cluster kubeconfig file is available.
  • DPU provisioning has reached the DPU Cluster Config stage.

Procedure

  1. Get the hosted cluster kubeconfig:

    $ oc get secret $HOSTED_CLUSTER_NAME-admin-kubeconfig -n $CLUSTERS_NAMESPACE -o jsonpath='{.data.kubeconfig}' | base64 -d > $HOSTED_CLUSTER_NAME.kubeconfig
  2. Switch to the hosted cluster context:

    $ export KUBECONFIG=$HOSTED_CLUSTER_NAME.kubeconfig
  3. Create a file named dpu-cluster-scc.yaml with the following content:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: dpf-system-scc-privileged
      labels:
        app.kubernetes.io/component: rbac
        app.kubernetes.io/part-of: dpu-services
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:openshift:scc:privileged
    subjects:
    - kind: Group
      apiGroup: rbac.authorization.k8s.io
      name: system:serviceaccounts:dpf-operator-system
  4. Apply the resource file on the hosted cluster:

    $ oc apply -f dpu-cluster-scc.yaml

12.6.7. Approve hosted cluster CSRs for DPU provisioning

You must approve the pending certificate signing requests (CSRs) for DPU nodes on the hosted cluster so that the DPU nodes can join the hosted cluster and complete provisioning.

Note

When you use the DPF HCP Provisioner Operator, DPU CSR approval is handled automatically. Manual approval is provided as a fallback if automatic approval is not functioning.

Prerequisites

  • You have access to the hosted cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • You have set the KUBECONFIG environment variable to the hosted cluster kubeconfig file.
  • DPU provisioning has reached the DPU Cluster Config stage.

Procedure

  1. Watch for pending CSRs from the DPU nodes:

    $ oc get csr -w

    The DPU node name typically follows the pattern <host_worker_node_name>-<dpu_serial_number>.

  2. Approve all pending CSRs:

    $ oc get csr -o go-template='{{range .items}}{{if not .status}}{{.metadata.name}}{{"\n"}}{{end}}{{end}}' | xargs oc adm certificate approve

    Example output

    certificatesigningrequest.certificates.k8s.io/csr-6jx22 approved
    certificatesigningrequest.certificates.k8s.io/csr-tb6nd approved

    Repeat this step until no pending CSRs remain.

Verification

  • Verify that the DPU nodes joined the hosted cluster and are in a Ready state:

    $ oc get nodes

    Example output

    NAME                          STATUS   ROLES    AGE     VERSION
    host-worker1-mt0000000001    Ready    worker   2m48s   v1.35.6
    host-worker2-mt0000000002    Ready    worker   2m45s   v1.35.6

    Note

    After the DPU nodes join the hosted cluster, the DPU provisioning process continues to the remaining stages.

12.6.8. Verify full system readiness

After the DPU provisioning process completes, you can verify that all worker nodes, SR-IOV virtual functions, and DPU services are operational on the management cluster.

Prerequisites

  • You have access to the management cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • DPU provisioning has completed.

Procedure

  1. Switch back to the management cluster context:

    $ export KUBECONFIG="$(pwd)/mgmt-kubeconfig"
  2. Verify that all worker nodes are in a Ready state:

    $ oc get node

    Example output

    NAME               STATUS   ROLES                         AGE     VERSION
    host-worker1       Ready    worker                        57m     v1.35.6
    host-worker2       Ready    worker                        57m     v1.35.6
    master-0           Ready    control-plane,master,worker   4d23h   v1.35.6
    master-1           Ready    control-plane,master,worker   4d22h   v1.35.6
    master-2           Ready    control-plane,master,worker   4d23h   v1.35.6

  3. Verify that SR-IOV virtual functions are registered as Kubernetes node resources on the worker nodes:

    $ oc get nodes -l 'node-role.kubernetes.io/worker,!node-role.kubernetes.io/control-plane' -o json | \
      jq '.items[] | {name: .metadata.name, capacity: .status.capacity."openshift.io/bf3_vfs", allocatable: .status.allocatable."openshift.io/bf3_vfs"}'

    Example output

    {
      "name": "host-worker1",
      "capacity": "90",
      "allocatable": "90"
    }
    {
      "name": "host-worker2",
      "capacity": "90",
      "allocatable": "90"
    }

  4. Verify that all DPU services are in a Success phase:

    $ oc get dpuservices -n dpf-operator-system

    Example output

    NAME                            READY   PHASE     AGE
    doca-telemetry-service-7s8pb    True    Success   42m
    flannel                         True    Success   26h
    hbn-gffmv                       True    Success   25m
    kube-state-metrics-rbac         True    Success   4h10m
    node-problem-detector           True    Success   4h10m
    nvidia-k8s-ipam-node            True    Success   4h10m
    ovn-f49zx                       True    Success   17m
    ovs-cni                         True    Success   26h
    servicechainset-rbac-and-crds   True    Success   138m
    sfc-controller                  True    Success   26h
    sriov-device-plugin             True    Success   26h

  5. Optional: View detailed DPU service status:

    $ oc -n dpf-operator-system exec deploy/dpf-operator-controller-manager -- /dpfctl describe all --show-resources=dpuservice --grouping=false

12.7. Validate traffic and configure telemetry

After provisioning the DPUs and verifying system readiness, validate end-to-end traffic flow and configure DPU telemetry observability.

12.7.1. Deploy traffic test pods and services

You can deploy traffic test pods and services across the management cluster to validate end-to-end connectivity through the DPU data plane. The test workloads include a server pod on a control plane node and worker pods on DPU-enabled nodes, with both standard and host-network configurations.

Note

These test workloads use the nicolaka/netshoot container image, a community networking-troubleshooting image that is not officially supported by Red Hat or NVIDIA. Use it only for connectivity validation and testing, not in production workloads.

Prerequisites

  • You have installed the DPF Operator and provisioned the DPU hosted cluster.
  • At least one DPU-enabled worker node is available.
  • You have access to the management cluster as a user with the cluster-admin role.

Procedure

  1. Create a file named traffic-pods.yaml with the following content:

    # 1. Namespace
    ---
    apiVersion: v1
    kind: Namespace
    metadata:
      name: workload
    
    # 2. SCC RoleBinding (grants 'default' ServiceAccount in 'workload' NS access to 'privileged' SCC)
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: privileged-scc-default-sa
      namespace: workload
    subjects:
    - kind: ServiceAccount
      name: default
      namespace: workload
    roleRef:
      kind: ClusterRole
      name: system:openshift:scc:privileged
      apiGroup: rbac.authorization.k8s.io
    
    # 3. Deployments and Services
    # Deployment: traffic-test-master
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: traffic-test-master
      namespace: workload
      labels:
        app: traffic-test-master
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: traffic-test-master
      template:
        metadata:
          labels:
            app: traffic-test-master
        spec:
          topologySpreadConstraints:
          - maxSkew: 1
            topologyKey: kubernetes.io/hostname
            whenUnsatisfiable: DoNotSchedule
            labelSelector:
              matchLabels:
                app: traffic-test-master
          nodeSelector:
            node-role.kubernetes.io/control-plane: ""
          tolerations:
          - key: node-role.kubernetes.io/master
            operator: Exists
            effect: NoSchedule
          - key: node-role.kubernetes.io/control-plane
            operator: Exists
            effect: NoSchedule
          containers:
          - name: nginx
            securityContext:
              privileged: true
              capabilities:
                add:
                - NET_ADMIN
            image: nicolaka/netshoot
            command: ["nc", "-kl", "5000"]
            ports:
            - containerPort: 5000
              name: tcp-server
            resources:
              requests:
                cpu: 1
                memory: 1Gi
              limits:
                cpu: 1
                memory: 1Gi
    ---
    # Service: traffic-test-master
    apiVersion: v1
    kind: Service
    metadata:
      name: traffic-test-master
      namespace: workload
      labels:
        app: traffic-test-master
    spec:
      selector:
        app: traffic-test-master
      ports:
      - protocol: TCP
        port: 5000
        targetPort: 5000
    ---
    # Service: traffic-test-master-nodeport
    apiVersion: v1
    kind: Service
    metadata:
      name: traffic-test-master-nodeport
      namespace: workload
      labels:
        app: traffic-test-master
    spec:
      type: NodePort
      selector:
        app: traffic-test-master
      ports:
      - protocol: TCP
        port: 5000
        targetPort: 5000
    ---
    # Deployment: traffic-test-worker
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: traffic-test-worker
      namespace: workload
      labels:
        app: traffic-test-worker
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: traffic-test-worker
      template:
        metadata:
          labels:
            app: traffic-test-worker
        spec:
          topologySpreadConstraints:
          - maxSkew: 1
            topologyKey: kubernetes.io/hostname
            whenUnsatisfiable: DoNotSchedule
            labelSelector:
              matchLabels:
                app: traffic-test-worker
          nodeSelector:
            feature.node.kubernetes.io/dpu-enabled: ""
          containers:
          - name: nginx
            securityContext:
              privileged: true
              capabilities:
                add:
                - NET_ADMIN
            image: nicolaka/netshoot
            command: ["nc", "-kl", "5000"]
            ports:
            - containerPort: 5000
              name: tcp-server
            resources:
              requests:
                cpu: 16
                memory: 6Gi
              limits:
                cpu: 16
                memory: 6Gi
    ---
    # Service: traffic-test-worker
    apiVersion: v1
    kind: Service
    metadata:
      name: traffic-test-worker
      namespace: workload
      labels:
        app: traffic-test-worker
    spec:
      selector:
        app: traffic-test-worker
      ports:
      - protocol: TCP
        port: 5000
        targetPort: 5000
    ---
    # Service: traffic-test-worker-nodeport
    apiVersion: v1
    kind: Service
    metadata:
      name: traffic-test-worker-nodeport
      namespace: workload
      labels:
        app: traffic-test-worker
    spec:
      type: NodePort
      selector:
        app: traffic-test-worker
      ports:
      - protocol: TCP
        port: 5000
        targetPort: 5000
    ---
    # Deployment: traffic-test-worker-hostnetwork
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: traffic-test-worker-hostnetwork
      namespace: workload
      labels:
        app: traffic-test-worker-hostnetwork
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: traffic-test-worker-hostnetwork
      template:
        metadata:
          labels:
            app: traffic-test-worker-hostnetwork
        spec:
          topologySpreadConstraints:
          - maxSkew: 1
            topologyKey: kubernetes.io/hostname
            whenUnsatisfiable: DoNotSchedule
            labelSelector:
              matchLabels:
                app: traffic-test-worker-hostnetwork
          nodeSelector:
            feature.node.kubernetes.io/dpu-enabled: ""
          hostNetwork: true
          containers:
          - name: nginx
            securityContext:
              privileged: true
              capabilities:
                add:
                - NET_ADMIN
            image: nicolaka/netshoot
            command: ["nc", "-kl", "5000"]
            ports:
            - containerPort: 5000
              name: tcp-server
            resources:
              requests:
                cpu: 1
                memory: 1Gi
              limits:
                cpu: 1
                memory: 1Gi
    ---
    # Service: traffic-test-worker-hostnetwork
    apiVersion: v1
    kind: Service
    metadata:
      name: traffic-test-worker-hostnetwork
      namespace: workload
      labels:
        app: traffic-test-worker-hostnetwork
    spec:
      selector:
        app: traffic-test-worker-hostnetwork
      ports:
      - protocol: TCP
        port: 5000
        targetPort: 5000
    ---
    # Service: traffic-test-worker-hostnetwork-nodeport
    apiVersion: v1
    kind: Service
    metadata:
      name: traffic-test-worker-hostnetwork-nodeport
      namespace: workload
      labels:
        app: traffic-test-worker-hostnetwork
    spec:
      type: NodePort
      selector:
        app: traffic-test-worker-hostnetwork
      ports:
      - protocol: TCP
        port: 5000
        targetPort: 5000

    The manifest creates the following resources:

    • A workload namespace for the test pods.
    • A RoleBinding resource that grants the default service account in the workload namespace access to the privileged security context constraint.
    • A traffic-test-master deployment and ClusterIP and NodePort services on a control plane node.
    • A traffic-test-worker deployment and ClusterIP and NodePort services on DPU-enabled worker nodes.
    • A traffic-test-worker-hostnetwork deployment that uses host networking on DPU-enabled worker nodes, with ClusterIP and NodePort services.

      Note

      The worker deployments set replicas: 1 for a single DPU worker node. Set the replica count of the traffic-test-worker and traffic-test-worker-hostnetwork deployments to the number of DPU-enabled worker nodes so that the topologySpreadConstraints place one pod on each node.

  2. Apply the manifest:

    $ oc apply -f traffic-pods.yaml

Verification

  1. Verify that the test pods are running:

    $ oc get pods -n workload -o wide

    Example output

    NAME                                               READY   STATUS    RESTARTS   AGE     IP             NODE               NOMINATED NODE   READINESS GATES
    traffic-test-master-7448bb5cc-mdftd                1/1     Running   0          2m10s   10.129.0.145   master-2           <none>           <none>
    traffic-test-worker-776486fb68-krz54               1/1     Running   0          2m10s   10.128.2.9     host-worker1       <none>           <none>
    traffic-test-worker-776486fb68-lz8vf               1/1     Running   0          2m10s   10.131.0.9     host-worker2       <none>           <none>
    traffic-test-worker-hostnetwork-596d569d99-cjpns   1/1     Running   0          2m10s   10.0.110.11    host-worker1       <none>           <none>
    traffic-test-worker-hostnetwork-596d569d99-x6m7r   1/1     Running   0          2m10s   10.0.110.12    host-worker2       <none>           <none>

    Confirm that the traffic-test-master pod is on a control plane node and that the traffic-test-worker pods are distributed across different DPU-enabled worker nodes.

  2. Verify that the services are created:

    $ oc get svc -n workload

    Example output

    NAME                                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
    traffic-test-master                        ClusterIP   172.30.102.123   <none>        5000/TCP         13m
    traffic-test-master-nodeport               NodePort    172.30.98.22     <none>        5000:31368/TCP   13m
    traffic-test-worker                        ClusterIP   172.30.187.147   <none>        5000/TCP         13m
    traffic-test-worker-hostnetwork            ClusterIP   172.30.122.242   <none>        5000/TCP         13m
    traffic-test-worker-hostnetwork-nodeport   NodePort    172.30.122.214   <none>        5000:30209/TCP   13m
    traffic-test-worker-nodeport               NodePort    172.30.108.72    <none>        5000:32570/TCP   13m

12.7.2. Run traffic validation tests

You can run connectivity tests between the traffic test pods and services to verify that the DPU services and service chains are configured correctly. A successful test confirms that end-to-end traffic flows through the DPU data plane as expected.

Prerequisites

  • The traffic test pods and services are deployed in the workload namespace and all pods are in a Running state.
  • You have access to the management cluster as a user with the cluster-admin role.

Procedure

  1. Run a ping connectivity test between pods on different worker nodes.

    In the following example, replace <worker_pod_name> with the name of a traffic-test-worker pod and replace <target_pod_ip> with the IP address of a traffic-test-worker pod on a different worker node:

    $ oc -n workload exec -it <worker_pod_name> -- ping -c 4 <target_pod_ip>

    Example output

    PING 10.131.0.9 (10.131.0.9) 56(84) bytes of data.
    64 bytes from 10.131.0.9: icmp_seq=1 ttl=62 time=1.61 ms
    64 bytes from 10.131.0.9: icmp_seq=2 ttl=62 time=0.876 ms
    64 bytes from 10.131.0.9: icmp_seq=3 ttl=62 time=0.510 ms
    64 bytes from 10.131.0.9: icmp_seq=4 ttl=62 time=0.421 ms
    
    --- 10.131.0.9 ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 3028ms
    rtt min/avg/max/mdev = 0.421/0.853/1.606/0.466 ms

    Verify that all 4 packets are received with 0% packet loss.

  2. Run a service connectivity test from a worker pod to a service on a control plane node.

    In the following example, replace <worker_pod_name> with the name of a traffic-test-worker pod and replace <service_cluster_ip> with the cluster IP address of the traffic-test-master service:

    $ oc -n workload exec -it <worker_pod_name> -- nc -vz <service_cluster_ip> 5000

    A succeeded message confirms that the service is reachable through the DPU-accelerated network.

  3. Run a service connectivity test from a worker pod to another worker pod.

    In the following example, replace <worker_pod_name> with the name of a traffic-test-worker pod and replace <service_cluster_ip> with the cluster IP address of the traffic-test-worker service:

    $ oc -n workload exec -it <worker_pod_name> -- nc -vz <service_cluster_ip> 5000

    A succeeded message confirms end-to-end connectivity through the DPU-accelerated service chain between worker pods.

  4. Optional: Run an external service connectivity test.

    In the following example, replace <worker_pod_name> with the name of a traffic-test-worker pod, replace <node_ip> with the IP address of a cluster node, and replace <nodeport> with the NodePort for one of the services:

    $ oc -n workload exec -it <worker_pod_name> -- nc -vz <node_ip> <nodeport>

    A succeeded message confirms that NodePort services are reachable through the DPU networking stack.

The DOCA Telemetry Service (DTS) exposes DPU hardware telemetry, such as PCIe link speed, uplink throughput, packets, errors, and NIC channel activity, as Prometheus metrics. You can view these metrics by using the OpenShift Container Platform web console or a Grafana dashboard.

Note

In a standard DPF installation, the DTS deployment objects are applied automatically during the postinstallation step. Apply them manually only when you are adding DTS to an existing cluster.

Note

Neither the DPF Operator nor the DTS DPUService installs Grafana on OpenShift Container Platform. Red Hat does not offer a certified Grafana Operator. The community Grafana Operator from OperatorHub is the standard way to run Grafana on OpenShift Container Platform.

DTS runs on every DPU in the hosted cluster and collects counters from sysfs and ethtool providers. OpenShift Container Platform includes a built-in Prometheus instance, so you do not need to deploy a separate monitoring stack to scrape DTS metrics.

DTS runs on the DPU hosted cluster, but Prometheus runs on the management cluster. DPF bridges this gap with a built-in port-mirroring mechanism.

When a DPUService resource declares a port in its configPorts field, DPF performs the following actions:

  • Publishes the service port as a NodePort on the DPU hosted cluster.
  • Creates a mirror Service on the management cluster, labeled with dpu.nvidia.com/exposed-port-for-dpucluster.

The management-cluster Prometheus then scrapes the mirror service. This mechanism requires no additional configuration beyond the standard DTS deployment objects.

12.7.3.2. DTS deployment objects

DTS is deployed through three standard DPF resources:

DPUServiceTemplate
Defines the Helm chart for the DOCA Telemetry Service, the DTS container image, and the metrics port. The configMapData.prometheus.port field is set to 9189.
DPUServiceConfiguration
Declares the service port httpserverport: 9189 under configPorts. This declaration triggers the management-cluster port-mirroring mechanism described previously.
DPUDeployment
References the template and configuration so that DTS is rolled out to the DPUs as a DaemonSet on the DPU hosted cluster. DTS defaults to the sysfs and ethtool providers.

12.7.4. Enable user workload monitoring for DTS

OpenShift Container Platform includes Prometheus, but by default it only monitors OpenShift Container Platform platform components. You must enable user workload monitoring so that Prometheus can scrape user namespaces where DPF and DTS run, such as dpf-operator-system.

Prerequisites

  • A DPF cluster is deployed with at least one provisioned DPU.
  • You have access to the management cluster as a user with the cluster-admin role.

Procedure

  1. Create a ConfigMap to enable user workload monitoring in the openshift-monitoring namespace:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: cluster-monitoring-config
      namespace: openshift-monitoring
    data:
      config.yaml: |
        enableUserWorkload: true
    Note

    If the cluster-monitoring-config ConfigMap already exists with other settings, edit it instead of replacing it, and add only the enableUserWorkload: true line to the existing config.yaml data:

    $ oc -n openshift-monitoring edit configmap cluster-monitoring-config
  2. Apply the ConfigMap:

    $ oc apply -f cluster-monitoring-config.yaml

Verification

  • Verify that the user workload monitoring pods are running in the openshift-user-workload-monitoring namespace:

    $ oc -n openshift-user-workload-monitoring get pods

    Example output

    NAME                                   READY   STATUS    RESTARTS   AGE
    prometheus-operator-...                1/1     Running   0          ...
    prometheus-user-workload-0             ...     Running   0          ...
    thanos-ruler-user-workload-0           ...     Running   0          ...

    Confirm that pods named prometheus-user-workload, thanos-ruler-user-workload, and prometheus-operator are all in a Running state.

12.7.5. Configure the DTS ServiceMonitor

Create a ServiceMonitor resource to instruct the user workload monitoring Prometheus instance to scrape the DOCA Telemetry Service (DTS) metrics endpoint. The ServiceMonitor selects the mirrored DTS service in the dpf-operator-system namespace and scrapes its /metrics path on the httpserverport every 30 seconds.

Prerequisites

  • User workload monitoring is enabled in OpenShift Container Platform.
  • The DTS DPUServiceConfiguration and DPUDeployment resources are applied.

    For details, see "DPU telemetry observability with DTS".

  • You have access to the management cluster as a user with the cluster-admin role.

Procedure

  1. Create a file named dts-servicemonitor.yaml with the following content:

    apiVersion: monitoring.coreos.com/v1
    kind: ServiceMonitor
    metadata:
      name: doca-telemetry-service-monitor
      namespace: dpf-operator-system
    spec:
      selector:
        matchExpressions:
          - key: dpu.nvidia.com/dpuservice-name
            operator: Exists
      endpoints:
        - port: httpserverport
          interval: 30s
          path: /metrics
          relabelings:
            - sourceLabels:
                - __meta_kubernetes_service_label_dpu_nvidia_com_dpuservice_name
              regex: doca-telemetry-service.*
              action: keep
      namespaceSelector:
        matchNames:
          - dpf-operator-system
  2. Apply the ServiceMonitor:

    $ oc apply -f dts-servicemonitor.yaml

Verification

  • Verify that the ServiceMonitor is created in the dpf-operator-system namespace:

    $ oc -n dpf-operator-system get servicemonitor doca-telemetry-service-monitor

    Example output

    NAME                               AGE
    doca-telemetry-service-monitor     ...

12.7.6. Install the DTS console dashboard

You can install a DTS dashboard that integrates directly into the OpenShift Container Platform web console. This dashboard provides visibility of DPU telemetry metrics without requiring Grafana or additional tools.

Prerequisites

  • User workload monitoring is enabled in OpenShift Container Platform.
  • The DTS ServiceMonitor is configured and collecting metrics.
  • You have access to the management cluster as a user with the cluster-admin role.

Procedure

  1. Create a file named dts-console-dashboard.yaml with the following content to define a console dashboard ConfigMap in the openshift-config-managed namespace:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: dpf-dts-console-dashboard
      namespace: openshift-config-managed
      labels:
        console.openshift.io/dashboard: "true"
    data:
      doca-dpu-telemetry-dts.json: |
        {
          "title": "DOCA DPU Telemetry (DTS)",
          "uid": "doca-dpu-telemetry-dts-console",
          "editable": false,
          "schemaVersion": 16,
          "tags": ["dpf", "dpu", "dts", "telemetry"],
          "timezone": "browser",
          "time": {"from": "now-1h", "to": "now"},
          "refresh": "30s",
          "templating": {"list": []},
          "rows": [
            {
              "title": "PCIe / Link",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "PCIe Link Speed (GT/s)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true},
                  "yaxes": [{"format": "none", "show": true}, {"format": "none", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "current_link_speed", "legendFormat": "{{source}} {{hca}}"}
                  ]
                },
                {
                  "type": "graph", "title": "PCIe Link Width (lanes)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true},
                  "yaxes": [{"format": "none", "show": true}, {"format": "none", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "current_link_width", "legendFormat": "{{source}} {{hca}}"}
                  ]
                }
              ]
            },
            {
              "title": "Uplink Throughput (p0/p1)",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "Uplink RX (bits/s)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "values": true, "avg": true, "max": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "bps", "show": true}, {"format": "bps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_bytes\"}[5m])) * 8",
                     "legendFormat": "{{source}}"}
                  ]
                },
                {
                  "type": "graph", "title": "Uplink TX (bits/s)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "values": true, "avg": true, "max": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "bps", "show": true}, {"format": "bps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_tx_bytes\"}[5m])) * 8",
                     "legendFormat": "{{source}}"}
                  ]
                }
              ]
            },
            {
              "title": "Uplink Packets & Errors",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "Uplink packets/s (rx + tx)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "pps", "show": true}, {"format": "pps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_packets\"}[5m]))",
                     "legendFormat": "{{source}} rx"},
                    {"refId": "B", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_tx_packets\"}[5m]))",
                     "legendFormat": "{{source}} tx"}
                  ]
                },
                {
                  "type": "graph", "title": "Uplink errors & drops/s", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "cps", "show": true}, {"format": "cps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_errors\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_tx_errors\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_rx_dropped\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_tx_dropped\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_rx_crc_errors\"}[5m]))",
                     "legendFormat": "{{source}}"}
                  ]
                }
              ]
            },
            {
              "title": "NIC Channel Activity",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "NIC channel poll/s", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "cps", "show": true}, {"format": "cps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate(ch_poll[5m]))", "legendFormat": "{{source}}"}
                  ]
                },
                {
                  "type": "graph", "title": "NIC channel events/s", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "cps", "show": true}, {"format": "cps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate(ch_events[5m]))", "legendFormat": "{{source}}"}
                  ]
                }
              ]
            }
          ]
        }
  2. Apply the console dashboard:

    $ oc apply -f dts-console-dashboard.yaml

Verification

  1. Verify that the dashboard ConfigMap is created:

    $ oc -n openshift-config-managed get configmap dpf-dts-console-dashboard

    Example output

    NAME                        DATA   AGE
    dpf-dts-console-dashboard   1      ...

  2. Access the dashboard in the OpenShift Container Platform web console:

    1. Navigate to Observe Dashboards.
    2. In the Dashboard dropdown menu, select DOCA DPU Telemetry (DTS).

      The dashboard displays PCIe link speed and width, uplink throughput, packets per second, errors and drops per second, and NIC channel activity, with each DPU as its own line.

Note

The DTS console dashboard renders against the platform Thanos or user workload monitoring Prometheus instance. No Grafana dependency is required for basic DPU telemetry viewing.

12.7.7. Install Grafana for DTS metrics visualization

You can install the Grafana Operator and a Grafana instance to provide enhanced visualization for DPU telemetry metrics, including per-DPU filtering and customizable dashboards. You can also deploy a dashboard ConfigMap that adds DTS metrics to the OpenShift Container Platform web console.

Prerequisites

  • You have enabled user workload monitoring in OpenShift Container Platform.
  • You have configured the DTS ServiceMonitor and it is collecting metrics.
  • You have access to the management cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • You have installed the helm CLI.

Procedure

  1. Install the Grafana Operator by using Helm:

    $ helm upgrade -i grafana-operator oci://ghcr.io/grafana/helm-charts/grafana-operator \
        --version 5.24.0 \
        --namespace grafana-operator \
        --create-namespace

    Example output

    Pulled: ghcr.io/grafana/helm-charts/grafana-operator:5.24.0
    Digest: sha256:4f69cdaecfed2cc61d4e5f4a8e7142795e9b00997e4bcbd37a8c154a225a2f1f
    Release "grafana-operator" has been upgraded. Happy Helming!
    NAME: grafana-operator
    LAST DEPLOYED: Tue Aug  4 08:51:36 2026
    NAMESPACE: grafana-operator
    STATUS: deployed
    REVISION: 2
    TEST SUITE: None

  2. Grant OpenShift Route permissions to the Grafana Operator:

    The community Grafana Operator requires additional RBAC permissions to manage OpenShift Container Platform routes. Create a file named grafana-operator-route-rbac.yaml with the following content:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: grafana-operator-route-manager
    rules:
    - apiGroups:
      - route.openshift.io
      resources:
      - routes
      - routes/custom-host
      verbs:
      - create
      - delete
      - get
      - list
      - patch
      - update
      - watch
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: grafana-operator-route-manager
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: grafana-operator-route-manager
    subjects:
    - kind: ServiceAccount
      name: grafana-operator
      namespace: grafana-operator

    Apply the file:

    $ oc apply -f grafana-operator-route-rbac.yaml

    Example output

    clusterrole.rbac.authorization.k8s.io/grafana-operator-route-manager created
    clusterrolebinding.rbac.authorization.k8s.io/grafana-operator-route-manager created

  3. Create Grafana RBAC for Prometheus access:

    Create a ServiceAccount with a long-lived token and bind it to the cluster-monitoring-view ClusterRole so Grafana can query the platform Prometheus:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: grafana-prometheus-reader
      namespace: dpf-operator-system
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: grafana-prometheus-reader-token
      namespace: dpf-operator-system
      annotations:
        kubernetes.io/service-account.name: grafana-prometheus-reader
    type: kubernetes.io/service-account-token
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: grafana-prometheus-reader-cluster-monitoring
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-monitoring-view
    subjects:
      - kind: ServiceAccount
        name: grafana-prometheus-reader
        namespace: dpf-operator-system

    Apply the YAML:

    $ oc apply -f grafana-rbac.yaml
  4. Deploy the Grafana instance with control-plane scheduling:

    apiVersion: grafana.integreatly.org/v1beta1
    kind: Grafana
    metadata:
      name: dpf-grafana
      namespace: dpf-operator-system
      labels:
        dashboards: "dpf-grafana"
    spec:
      route:
        spec:
          port:
            targetPort: grafana
          tls:
            termination: edge
      config:
        log:
          mode: "console"
          level: "info"
        auth.anonymous:
          enabled: "true"
          org_role: "Viewer"
        security:
          admin_user: "admin"
          admin_password: "admin"
      deployment:
        spec:
          template:
            spec:
              nodeSelector:
                node-role.kubernetes.io/control-plane: ""
              tolerations:
              - key: node-role.kubernetes.io/master
                operator: Exists
                effect: NoSchedule
              - key: node-role.kubernetes.io/control-plane
                operator: Exists
                effect: NoSchedule

    Apply the YAML:

    $ oc apply -f grafana-cr.yaml
    Warning

    The default credentials (admin/admin) are suitable for lab environments only. Change the admin_password for non-lab deployments.

  5. Configure the Prometheus datasource:

    apiVersion: grafana.integreatly.org/v1beta1
    kind: GrafanaDatasource
    metadata:
      name: prometheus
      namespace: dpf-operator-system
    spec:
      instanceSelector:
        matchLabels:
          dashboards: "dpf-grafana"
      valuesFrom:
        - targetPath: "secureJsonData.httpHeaderValue1"
          valueFrom:
            secretKeyRef:
              name: grafana-prometheus-reader-token
              key: token
      datasource:
        name: prometheus
        type: prometheus
        uid: prometheus
        access: proxy
        url: https://thanos-querier.openshift-monitoring.svc.cluster.local:9091
        isDefault: true
        jsonData:
          tlsSkipVerify: true
          httpHeaderName1: "Authorization"
          timeInterval: "30s"
        secureJsonData:
          httpHeaderValue1: "Bearer ${token}"

    Apply the YAML:

    $ oc apply -f grafana-datasource.yaml
  6. Deploy the DTS console dashboard for OpenShift Container Platform web console integration:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: dpf-dts-console-dashboard
      namespace: openshift-config-managed
      labels:
        console.openshift.io/dashboard: "true"
    data:
      doca-dpu-telemetry-dts.json: |
        {
          "title": "DOCA DPU Telemetry (DTS)",
          "uid": "doca-dpu-telemetry-dts-console",
          "editable": false,
          "schemaVersion": 16,
          "tags": ["dpf", "dpu", "dts", "telemetry"],
          "timezone": "browser",
          "time": {"from": "now-1h", "to": "now"},
          "refresh": "30s",
          "templating": {"list": []},
          "rows": [
            {
              "title": "PCIe / Link",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "PCIe Link Speed (GT/s)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true},
                  "yaxes": [{"format": "none", "show": true}, {"format": "none", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "current_link_speed", "legendFormat": "{{source}} {{hca}}"}
                  ]
                },
                {
                  "type": "graph", "title": "PCIe Link Width (lanes)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true},
                  "yaxes": [{"format": "none", "show": true}, {"format": "none", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "current_link_width", "legendFormat": "{{source}} {{hca}}"}
                  ]
                }
              ]
            },
            {
              "title": "Uplink Throughput (p0/p1)",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "Uplink RX (bits/s)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "values": true, "avg": true, "max": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "bps", "show": true}, {"format": "bps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_bytes\"}[5m])) * 8",
                     "legendFormat": "{{source}}"}
                  ]
                },
                {
                  "type": "graph", "title": "Uplink TX (bits/s)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "values": true, "avg": true, "max": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "bps", "show": true}, {"format": "bps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_tx_bytes\"}[5m])) * 8",
                     "legendFormat": "{{source}}"}
                  ]
                }
              ]
            },
            {
              "title": "Uplink Packets & Errors",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "Uplink packets/s (rx + tx)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "pps", "show": true}, {"format": "pps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_packets\"}[5m]))",
                     "legendFormat": "{{source}} rx"},
                    {"refId": "B", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_tx_packets\"}[5m]))",
                     "legendFormat": "{{source}} tx"}
                  ]
                },
                {
                  "type": "graph", "title": "Uplink errors & drops/s", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "cps", "show": true}, {"format": "cps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_errors\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_tx_errors\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_rx_dropped\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_tx_dropped\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_rx_crc_errors\"}[5m]))",
                     "legendFormat": "{{source}}"}
                  ]
                }
              ]
            },
            {
              "title": "NIC Channel Activity",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "NIC channel poll/s", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "cps", "show": true}, {"format": "cps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate(ch_poll[5m]))", "legendFormat": "{{source}}"}
                  ]
                },
                {
                  "type": "graph", "title": "NIC channel events/s", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "cps", "show": true}, {"format": "cps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate(ch_events[5m]))", "legendFormat": "{{source}}"}
                  ]
                }
              ]
            }
          ]
        }

    Apply the YAML:

    $ oc apply -f dts-console-dashboard.yaml
  7. Deploy the complete DTS Grafana dashboard:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: dpf-dts-grafana-dashboard
      namespace: dpf-operator-system
      labels:
        app.kubernetes.io/part-of: dpf
    data:
      doca-dpu-telemetry-dts.json: |
        {
          "title": "DOCA DPU Telemetry (DTS)",
          "uid": "doca-dpu-telemetry-dts",
          "tags": ["dpf", "dpu", "dts", "telemetry"],
          "timezone": "browser",
          "schemaVersion": 39,
          "editable": true,
          "time": {"from": "now-1h", "to": "now"},
          "refresh": "30s",
          "templating": {
            "list": [
              {
                "name": "source",
                "label": "DPU (source)",
                "type": "query",
                "datasource": {"type": "prometheus", "uid": "prometheus"},
                "query": "label_values(current_link_speed, source)",
                "refresh": 2,
                "includeAll": true,
                "multi": true,
                "current": {"text": "All", "value": "$__all"},
                "sort": 1
              }
            ]
          },
          "panels": [
            {
              "type": "stat",
              "title": "PCIe Link Speed (GT/s)",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 4, "w": 6, "x": 0, "y": 0},
              "fieldConfig": {"defaults": {"unit": "none"}, "overrides": []},
              "options": {"reduceOptions": {"calcs": ["lastNotNull"]}, "colorMode": "value", "graphMode": "none"},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "current_link_speed{source=~\"$source\"}", "legendFormat": "{{source}} {{hca}}"}
              ]
            },
            {
              "type": "stat",
              "title": "PCIe Link Width (lanes)",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 4, "w": 6, "x": 6, "y": 0},
              "fieldConfig": {"defaults": {"unit": "none"}, "overrides": []},
              "options": {"reduceOptions": {"calcs": ["lastNotNull"]}, "colorMode": "value", "graphMode": "none"},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "current_link_width{source=~\"$source\"}", "legendFormat": "{{source}} {{hca}}"}
              ]
            },
            {
              "type": "stat",
              "title": "Max PCIe Link Speed (GT/s)",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 4, "w": 6, "x": 12, "y": 0},
              "fieldConfig": {"defaults": {"unit": "none"}, "overrides": []},
              "options": {"reduceOptions": {"calcs": ["lastNotNull"]}, "colorMode": "value", "graphMode": "none"},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "max_link_speed{source=~\"$source\"}", "legendFormat": "{{source}} {{hca}}"}
              ]
            },
            {
              "type": "stat",
              "title": "Max PCIe Link Width (lanes)",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 4, "w": 6, "x": 18, "y": 0},
              "fieldConfig": {"defaults": {"unit": "none"}, "overrides": []},
              "options": {"reduceOptions": {"calcs": ["lastNotNull"]}, "colorMode": "value", "graphMode": "none"},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "max_link_width{source=~\"$source\"}", "legendFormat": "{{source}} {{hca}}"}
              ]
            },
            {
              "type": "timeseries",
              "title": "Uplink RX throughput (p0/p1)",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 8, "w": 12, "x": 0, "y": 4},
              "fieldConfig": {"defaults": {"unit": "bps", "custom": {"drawStyle": "line", "fillOpacity": 10}}, "overrides": []},
              "options": {"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["mean", "max"]}, "tooltip": {"mode": "multi"}},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_bytes\", source=~\"$source\"}[5m])) * 8",
                 "legendFormat": "{{source}}"}
              ]
            },
            {
              "type": "timeseries",
              "title": "Uplink TX throughput (p0/p1)",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 8, "w": 12, "x": 12, "y": 4},
              "fieldConfig": {"defaults": {"unit": "bps", "custom": {"drawStyle": "line", "fillOpacity": 10}}, "overrides": []},
              "options": {"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["mean", "max"]}, "tooltip": {"mode": "multi"}},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_tx_bytes\", source=~\"$source\"}[5m])) * 8",
                 "legendFormat": "{{source}}"}
              ]
            },
            {
              "type": "timeseries",
              "title": "Uplink packets/s (p0/p1 rx+tx)",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 8, "w": 12, "x": 0, "y": 12},
              "fieldConfig": {"defaults": {"unit": "pps", "custom": {"drawStyle": "line", "fillOpacity": 10}}, "overrides": []},
              "options": {"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["mean", "max"]}, "tooltip": {"mode": "multi"}},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_packets\", source=~\"$source\"}[5m]))",
                 "legendFormat": "{{source}} rx"},
                {"refId": "B", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_tx_packets\", source=~\"$source\"}[5m]))",
                 "legendFormat": "{{source}} tx"}
              ]
            },
            {
              "type": "timeseries",
              "title": "Uplink errors & drops/s (p0/p1)",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 8, "w": 12, "x": 12, "y": 12},
              "fieldConfig": {"defaults": {"unit": "cps", "custom": {"drawStyle": "line", "fillOpacity": 10}}, "overrides": []},
              "options": {"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["max"]}, "tooltip": {"mode": "multi"}},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_errors\", source=~\"$source\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_tx_errors\", source=~\"$source\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_rx_dropped\", source=~\"$source\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_tx_dropped\", source=~\"$source\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_rx_crc_errors\", source=~\"$source\"}[5m]))",
                 "legendFormat": "{{source}}"}
              ]
            },
            {
              "type": "timeseries",
              "title": "NIC channel poll/s",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 8, "w": 12, "x": 0, "y": 20},
              "fieldConfig": {"defaults": {"unit": "cps", "custom": {"drawStyle": "line", "fillOpacity": 10}}, "overrides": []},
              "options": {"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["mean", "max"]}, "tooltip": {"mode": "multi"}},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "rate(ch_poll{source=~\"$source\"}[5m])",
                 "legendFormat": "{{source}} {{device_name}}"}
              ]
            },
            {
              "type": "timeseries",
              "title": "NIC channel events/s",
              "datasource": {"type": "prometheus", "uid": "prometheus"},
              "gridPos": {"h": 8, "w": 12, "x": 12, "y": 20},
              "fieldConfig": {"defaults": {"unit": "cps", "custom": {"drawStyle": "line", "fillOpacity": 10}}, "overrides": []},
              "options": {"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["mean", "max"]}, "tooltip": {"mode": "multi"}},
              "targets": [
                {"refId": "A", "datasource": {"type": "prometheus", "uid": "prometheus"},
                 "expr": "rate(ch_events{source=~\"$source\"}[5m])",
                 "legendFormat": "{{source}} {{device_name}}"}
              ]
            }
          ]
        }
    ---
    apiVersion: grafana.integreatly.org/v1beta1
    kind: GrafanaDashboard
    metadata:
      name: doca-dpu-telemetry-dts
      namespace: dpf-operator-system
    spec:
      instanceSelector:
        matchLabels:
          dashboards: "dpf-grafana"
      configMapRef:
        name: dpf-dts-grafana-dashboard
        key: doca-dpu-telemetry-dts.json

    Apply the YAML:

    $ oc apply -f dts-grafana-dashboard.yaml

Verification

  1. Verify that the Grafana Operator is running:

    $ oc get pods -n grafana-operator

    Example output

    NAME                               READY   STATUS    RESTARTS   AGE
    grafana-operator-66d8c8c7b-xyz12   1/1     Running   0          5m42s

  2. Verify that the Grafana instance is running:

    $ oc get grafana -n dpf-operator-system

    Example output

    NAME          AGE
    dpf-grafana   3m15s

  3. Verify that the Grafana pod is running on a control plane node:

    $ oc get pods -n dpf-operator-system -l app.kubernetes.io/name=grafana -o wide

    Example output

    NAME                             READY   STATUS    RESTARTS   AGE     IP             NODE            NOMINATED NODE   READINESS GATES
    grafana-deployment-7c8b9d-xyz12  1/1     Running   0          2m38s   10.128.0.45   master-node-1   <none>           <none>

  4. Verify the Grafana route exists:

    $ oc get route -n dpf-operator-system

    Example output

    NAME                HOST/PORT                               PATH   SERVICES      PORT      TERMINATION   WILDCARD
    dpf-grafana-route   dpf-grafana-route-dpf-operator-system.apps.cluster.example.com          dpf-grafana   grafana   edge          None

  5. Verify that the console dashboard ConfigMap exists:

    $ oc get configmap dpf-dts-console-dashboard -n openshift-config-managed
  6. Access the Grafana web interface:

    Get the Grafana URL:

    $ echo "https://$(oc -n dpf-operator-system get route dpf-grafana-route -o jsonpath='{.spec.host}')"

    Open the returned URL in a web browser. Use anonymous access (read-only) or sign in with the default credentials (admin/admin) for editing capabilities.

  7. Navigate to the DTS dashboard:

    1. In Grafana, go to Dashboards and open DOCA DPU Telemetry (DTS).
    2. Use the DPU (source) dropdown menu to focus on a specific DPU or select All.
    3. Adjust the time range by using the time-range control on the dashboard toolbar. The dashboard refreshes every 30 seconds.
    4. Optional: In the OpenShift Container Platform web console, go to Observe Dashboards and open DOCA DPU Telemetry (DTS) to view the console-integrated dashboard.
    5. Review the following metrics:

      • PCIe status: current and maximum link speed and width
      • Throughput: receive (RX) and transmit (TX) data rates for uplink ports p0 and p1
      • Packet rates: packets-per-second statistics with RX and TX breakdown
      • Error monitoring: combined error, drop, and CRC error rates

12.7.8. View DTS metrics and dashboards

After you configure the DTS ServiceMonitor, you can view DPU telemetry metrics by using the OpenShift Container Platform web console, PromQL queries, or Grafana dashboards.

Prerequisites

  • You have configured the DTS ServiceMonitor.
  • You have access to the management cluster as a user with the cluster-admin role.
  • You have installed the oc CLI.
  • Optional: You have installed Grafana for DTS metrics visualization.

Procedure

  1. Verify that the DTS DPUService is ready on the management cluster. The object name carries a generated suffix, so select it by its stable label:

    $ oc -n dpf-operator-system get dpuservice \
      -l svc.dpu.nvidia.com/dpudeployment-service=doca-telemetry-service

    Example output

    NAME                           READY   PHASE     AGE
    doca-telemetry-service-89p28   True    Success   ...

    A status of READY: True and PHASE: Success confirms that DTS is deployed and running.

  2. Deploy the DTS console dashboard for the OpenShift Container Platform web console:

    The console dashboard provides in-console visibility of DPU performance without requiring Grafana:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: dpf-dts-console-dashboard
      namespace: openshift-config-managed
      labels:
        console.openshift.io/dashboard: "true"
    data:
      doca-dpu-telemetry-dts.json: |
        {
          "title": "DOCA DPU Telemetry (DTS)",
          "uid": "doca-dpu-telemetry-dts-console",
          "editable": false,
          "schemaVersion": 16,
          "tags": ["dpf", "dpu", "dts", "telemetry"],
          "timezone": "browser",
          "time": {"from": "now-1h", "to": "now"},
          "refresh": "30s",
          "templating": {"list": []},
          "rows": [
            {
              "title": "PCIe / Link",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "PCIe Link Speed (GT/s)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true},
                  "yaxes": [{"format": "none", "show": true}, {"format": "none", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "current_link_speed", "legendFormat": "{{source}} {{hca}}"}
                  ]
                },
                {
                  "type": "graph", "title": "PCIe Link Width (lanes)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true},
                  "yaxes": [{"format": "none", "show": true}, {"format": "none", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "current_link_width", "legendFormat": "{{source}} {{hca}}"}
                  ]
                }
              ]
            },
            {
              "title": "Uplink Throughput (p0/p1)",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "Uplink RX (bits/s)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "values": true, "avg": true, "max": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "bps", "show": true}, {"format": "bps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_bytes\"}[5m])) * 8",
                     "legendFormat": "{{source}}"}
                  ]
                },
                {
                  "type": "graph", "title": "Uplink TX (bits/s)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "values": true, "avg": true, "max": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "bps", "show": true}, {"format": "bps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_tx_bytes\"}[5m])) * 8",
                     "legendFormat": "{{source}}"}
                  ]
                }
              ]
            },
            {
              "title": "Uplink Packets & Errors",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "Uplink packets/s (rx + tx)", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "pps", "show": true}, {"format": "pps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_packets\"}[5m]))",
                     "legendFormat": "{{source}} rx"},
                    {"refId": "B", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_tx_packets\"}[5m]))",
                     "legendFormat": "{{source}} tx"}
                  ]
                },
                {
                  "type": "graph", "title": "Uplink errors & drops/s", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "cps", "show": true}, {"format": "cps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate({__name__=~\"p[01]_eth_rx_errors\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_tx_errors\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_rx_dropped\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_tx_dropped\"}[5m])) + sum by(source)(rate({__name__=~\"p[01]_eth_rx_crc_errors\"}[5m]))",
                     "legendFormat": "{{source}}"}
                  ]
                }
              ]
            },
            {
              "title": "NIC Channel Activity",
              "showTitle": true,
              "height": "250px",
              "panels": [
                {
                  "type": "graph", "title": "NIC channel poll/s", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "cps", "show": true}, {"format": "cps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate(ch_poll[5m]))", "legendFormat": "{{source}}"}
                  ]
                },
                {
                  "type": "graph", "title": "NIC channel events/s", "span": 6,
                  "datasource": "prometheus", "nullPointMode": "null",
                  "legend": {"show": true, "alignAsTable": true, "rightSide": true},
                  "yaxes": [{"format": "cps", "show": true}, {"format": "cps", "show": false}],
                  "targets": [
                    {"refId": "A", "format": "time_series", "intervalFactor": 2,
                     "expr": "sum by(source)(rate(ch_events[5m]))", "legendFormat": "{{source}}"}
                  ]
                }
              ]
            }
          ]
        }

    Create a file named dts-console-dashboard.yaml with the preceding content and apply it:

    $ oc apply -f dts-console-dashboard.yaml
  3. View metrics in the OpenShift Container Platform web console.

    Note

    The OpenShift Container Platform web console reads from the cluster Prometheus instance through Thanos and user workload monitoring. Grafana is not required for basic metric viewing.

    To run an ad hoc query, go to Observe Metrics in the web console, enter a DTS PromQL query, and click Run queries.

    Example query to validate DTS metrics:

    current_link_speed{job=~"doca-telemetry-service.*"}

    You should get one series per DPU. Hover over a line to see its labels. Note the source label, which is the DPU node name that identifies each DPU.

    Expand
    Table 12.10. DTS PromQL queries
    QueryDescription

    current_link_speed{job=~"doca-telemetry-service.*"}

    Returns the current PCIe link speed for each DPU. Each series includes a source label that identifies the DPU node name.

    rate(p0_eth_rx_bytes{job=~"doca-telemetry-service.*"}[5m]) * 8

    Calculates the uplink receive throughput in bits per second over a 5-minute window.

    rate(ch_poll{job=~"doca-telemetry-service.*"}[5m])

    Calculates the NIC channel polling activity rate over a 5-minute window.

    To view the console dashboard, go to Observe Dashboards, then in the Dashboard dropdown menu, select DOCA DPU Telemetry (DTS). The dashboard displays PCIe link speed and width, uplink throughput, packets per second, errors and drops per second, and NIC channel activity, with each DPU as its own line.

  4. Optional: View metrics in Grafana.

    Grafana provides richer dashboards with per-DPU dropdown filters and customizable panels. After you install the Grafana Operator and Grafana instance, retrieve the route URL:

    $ echo "https://$(oc -n dpf-operator-system get route dpf-grafana-route -o jsonpath='{.spec.host}')"

    Open the outputted URL in a browser. Anonymous access provides read-only viewer permissions. To edit dashboards, click Sign in and use admin / admin as the default credentials set in the Grafana custom resource.

    Important

    Change the default Grafana credentials for non-lab clusters.

    In Grafana, go to Dashboards and open DOCA DPU Telemetry (DTS). Use the DPU (source) dropdown menu to focus on a specific DPU or select All. Adjust the time range by using the time-range control on the dashboard toolbar. The dashboard refreshes every 30 seconds.

  5. Optional: Review DPF framework dashboards in Grafana.

    The DPF Operator installs framework dashboards that track DPU lifecycle and control-plane health separately from the DTS hardware telemetry dashboard. These dashboards are loaded into Grafana automatically through GrafanaDashboard resources created from ConfigMaps.

    Expand
    Table 12.11. DPF framework dashboards
    DashboardDescription

    DOCA Platform DPU Fleet Health

    Fleet-wide DPU health, provisioning state, and version distribution.

    DOCA Platform DPU Health Detail

    Per-DPU status, conditions, and history timelines.

    DOCA Platform Framework State

    Inventory and readiness of every DPF resource type.

    DOCA Platform Framework Performance

    Time for DPF resources to reach their conditions, including reconcile and provisioning timings.

    Controller Runtime

    DPF controller internals: CPU and memory usage, reconcile rates, queues, and errors.

12.8. Troubleshoot DPF

You can diagnose and resolve common NVIDIA DPF Operator issues with DPU provisioning, hosted cluster readiness, networking, and collect diagnostic logs for support. These procedures complement the official NVIDIA debugging tools and guides.

12.8.1. DPU provisioning does not start

If DPU provisioning does not start immediately after you add worker nodes to the management cluster, verify that certificate signing requests (CSRs), controller pods, Node Feature Discovery (NFD) labels, and DPF resource objects are in the correct state.

Verify that all worker CSRs are approved

Run the following command to list the CSR status on the management cluster:

$ oc get csr

Ensure that all CSRs for the worker nodes show an Approved status.

Verify that all DPF controller pods are running

Run the following command to check the status of the DPF Operator pods:

$ oc get pod -n dpf-operator-system

Ensure that all pods are in a Running state.

Verify that worker nodes are labeled for DPU provisioning by NFD

Run the following command to confirm that the dpu-enabled label is present on the worker nodes:

$ oc get nodes -l feature.node.kubernetes.io/dpu-enabled=""

The output lists the worker nodes that NFD has labeled for DPU provisioning. For example:

Example output

NAME           STATUS     ROLES               AGE   VERSION
host-worker1   NotReady   worker,worker-dpu   62s   v1.35.6
host-worker2   NotReady   worker,worker-dpu   66s   v1.35.6

Check BFB object status

Run the following command to verify that the BlueField Bootstream File (BFB) image is downloaded and ready:

$ oc describe bfb -n dpf-operator-system bf-bundle

Check the status.conditions field for download progress and any error messages.

Verify that the BFB image URL is reachable

If the BFB download fails, run the following command to confirm that the image URL is reachable, replacing $BFB_URL with the image URL:

$ curl -I $BFB_URL

Ensure that the response returns a 200 OK status code. If the download fails, verify network connectivity to the image registry, check for firewall or proxy restrictions, and ensure that sufficient disk space is available on the node.

Monitor DPU provisioning progress

Run the following command to watch the DPU objects progress through provisioning:

$ oc get dpu -n dpf-operator-system -w

Wait for each DPU to progress from Pending to Provisioning to Ready.

Verify that the DPU hardware is detected on the worker node

Open a debug shell on the worker node:

$ oc debug node/<worker-node-name>

Inside the debug shell, run the following commands to confirm that a BlueField device is present:

sh-5.1# chroot /host
sh-5.1# lspci | grep -i mellanox

If the DPU is not listed, verify that it is properly seated in the PCIe slot and that it is not disabled in the server BIOS.

Verify DPU firmware and software compatibility

Inside the debug shell, run the following command to check the DPU firmware version:

sh-5.1# mlxfwmanager --query

Confirm that the BlueField firmware and DOCA software versions on the DPU are compatible with the DPF Operator version that you deployed.

Check DPUDeployment object status

Inspect the DPUDeployment object for information about the following resources:

  • BFB object state
  • DPUServiceTemplate objects state
  • DPUServiceConfiguration objects state

Run the following command to view the full DPUDeployment status:

$ oc get dpudeployments -n dpf-operator-system dpudeployment -o yaml

Alternatively, run the following dpfctl command for a summarized view:

$ oc -n dpf-operator-system exec deploy/dpf-operator-controller-manager -- /dpfctl describe dpudeployments

12.8.2. DPU objects remain in the DPU Cluster Config state

If DPU objects remain in a DPU Cluster Config state and do not progress, the hosted cluster might have pending certificate signing requests (CSRs) that must be approved.

Check for pending CSRs in the hosted cluster

Switch to the hosted cluster context and check for any pending CSRs:

$ export KUBECONFIG=<path_to_hosted_cluster_kubeconfig>
$ oc get csr

Review the output and approve any CSRs that show a Pending status.

12.8.3. Management cluster nodes do not become ready

If management cluster nodes do not reach a Ready state after DPU provisioning completes, the OVN-Kubernetes CNI pods might not be running correctly on the management cluster or the hosted cluster.

Check OVN-Kubernetes pods on the management cluster

Switch to the management cluster context and verify that all OVN-Kubernetes pods are running on the x86_64 worker nodes and control plane nodes:

$ export KUBECONFIG=<path_to_management_cluster_kubeconfig>
$ oc get pods -n openshift-ovn-kubernetes -o wide
Check OVN-Kubernetes pods on the hosted cluster

Switch to the hosted cluster context and verify that all OVN-Kubernetes pods are running on the DPU workers:

$ export KUBECONFIG=<path_to_hosted_cluster_kubeconfig>
$ oc get pods -n openshift-ovn-kubernetes -o wide

Ensure that all pods in the openshift-ovn-kubernetes namespace are in a Running state on both clusters.

12.8.4. DPU provisioning fails with BMC certificate errors

If DPU provisioning fails with certificate errors when you add worker nodes by using the Bare Metal Operator, the baseboard management controller (BMC) certificates might be untrusted or expired, or the BareMetalHost credentials might be incorrect.

Verify BMC certificate validity

Run the following command to inspect the BMC TLS certificate, replacing <bmc_ip> with the BMC IP address and <bmc_hostname> with the BMC hostname:

$ openssl s_client -connect <bmc_ip>:443 -servername <bmc_hostname>

Update the certificates in the BMC configuration if they are expired or untrusted.

Verify BareMetalHost BMC credentials
Ensure that the BareMetalHost resource references the correct BMC secret and connection details, including the Redfish address and credentials for the worker server.

12.8.5. Worker node CSR approval fails

If certificate signing request (CSR) approval for worker nodes fails, network connectivity between the management cluster and the DPU or hosted cluster path might be incomplete.

Check Host-Based Networking pods on worker nodes

Run the following command to verify that HBN pods are running:

$ oc get pods -n openshift-hbn -o wide
Verify DPU management network connectivity

From a management cluster node, ping the DPU management IP address:

$ ping <dpu_management_ip>
Verify the br-ex bridge on worker nodes
Confirm that the br-ex bridge that the worker MachineConfig resource creates is present and that required firewall rules allow traffic on the DPU management and high-speed networks.

12.8.6. DPU nodes remain NotReady in the hosted cluster

If DPU nodes remain in a NotReady state in the hosted cluster, DPU provisioning might be incomplete, or the DPU firmware and DOCA software versions might be incompatible with the DPF Operator version.

Check DPU and DPU service status on the management cluster

Run the following commands:

$ oc get dpu -n dpf-operator-system
$ oc get dpuservice -n dpf-operator-system
Verify node status in the hosted cluster

Switch to the hosted cluster kubeconfig and list the nodes:

$ export KUBECONFIG=<path_to_hosted_cluster_kubeconfig>
$ oc get nodes
Check DPF Operator and related pod logs

On the management cluster, inspect logs from DPF-related pods for provisioning or networking errors:

$ oc logs -n dpf-operator-system <dpu_related_pod_name>
Verify firmware and software compatibility
Confirm that the BlueField firmware and DOCA software versions on the DPU are compatible with the DPF Operator version that you deployed.

12.8.7. Troubleshoot hosted cluster issues

You can diagnose and resolve DPU hosted cluster issues, including CSR approval failures, kubeconfig access problems, and worker node join failures.

Prerequisites

  • The DPF HCP Provisioner is installed and configured.
  • DPU provisioning has completed on the management cluster.
  • You have access to kubeconfig files for both the management cluster and the hosted cluster.

Procedure

  1. Verify that the hosted cluster is accessible by running the following commands:

    $ export KUBECONFIG=/path/to/hosted-cluster.kubeconfig
    $ oc cluster-info

    If the hosted cluster API server is not accessible, check the hosted control planes status on the management cluster.

  2. Switch to the management cluster context and verify that the hosted control plane components are running:

    $ export KUBECONFIG=/path/to/management-cluster.kubeconfig
    $ oc get pods -n clusters-$HOSTED_CLUSTER_NAME

    Verify that the etcd, kube-apiserver, kube-controller-manager, and kube-scheduler pods are all in a Running state.

  3. Check the DPF HCP Provisioner status for any error conditions:

    $ oc get dpfhcpprovisioner -n dpf-operator-system -o yaml

    Review the status.conditions field for any conditions that indicate a failure.

  4. Return to the hosted cluster context and check for pending CSRs:

    $ export KUBECONFIG=/path/to/hosted-cluster.kubeconfig
    $ oc get csr --sort-by=.metadata.creationTimestamp

    Example output

    NAME        AGE   SIGNERNAME                                    REQUESTOR                  CONDITION
    csr-abc12   30s   kubernetes.io/kubelet-serving                 system:node:dpu-worker1    Pending
    csr-def34   25s   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abc123    Pending

  5. Approve any pending CSRs. To approve a single CSR, run the following command, replacing <csr-name> with the CSR name:

    $ oc adm certificate approve <csr-name>

    To approve all pending CSRs in a single command, run:

    $ oc get csr -o name | xargs oc adm certificate approve
  6. Verify that the DPU workers are joining the hosted cluster:

    $ oc get nodes

    Example output

    NAME                 STATUS   ROLES    AGE   VERSION
    dpu-worker1          Ready    worker   5m    v1.35.6
    dpu-worker2          Ready    worker   5m    v1.35.6

  7. If nodes are not joining, check whether the bootstrap token is still valid by running the following command on the hosted cluster:

    $ oc get secrets -n kube-system | grep bootstrap-token

    Bootstrap tokens have a limited lifetime. The DPF HCP Provisioner should create new tokens automatically. If tokens are expired and not being renewed, check the provisioner logs for errors.

  8. Check the kubelet logs on the DPU for authentication or certificate errors. Switch to the management cluster context and open a debug shell on the DPU-enabled worker node:

    $ export KUBECONFIG=/path/to/management-cluster.kubeconfig
    $ oc debug node/<dpu-enabled-worker-node>

    Inside the debug shell, run the following commands to stream the kubelet logs:

    sh-5.1# chroot /host
    sh-5.1# journalctl -u kubelet -f

    Look for authentication errors or certificate-related failures in the log output.

  9. Verify that OVN-Kubernetes is running correctly on the hosted cluster. Switch to the hosted cluster context and run the following command:

    $ export KUBECONFIG=/path/to/hosted-cluster.kubeconfig
    $ oc get pods -n openshift-ovn-kubernetes -o wide

    Ensure that OVN-Kubernetes pods are running on the DPU ARM cores.

Troubleshooting

CSR approval failures: Verify that the DPF HCP Provisioner has the required RBAC permissions to approve CSRs, check the provisioner logs for certificate-related errors, and ensure that the cluster CA is configured correctly.

Node join failures: Verify that the bootstrap kubeconfig was correctly generated by the provisioner, check network connectivity between the DPUs and the hosted control plane API server, and ensure that the kubelet configuration includes the correct API server endpoint.

Control plane access issues: Verify that the hosted cluster virtual IP address is configured and accessible, check the LoadBalancer service status for the hosted API server, and ensure that MetalLB is correctly configured and announcing the VIP.

Network connectivity problems: Verify the VTEP network configuration between DPUs, check that the DPU high-speed network interfaces are operational, and ensure that the required ports are open for inter-DPU communication.

12.8.8. Troubleshoot DPF networking issues

You can diagnose and resolve DPF networking issues, including OVN-Kubernetes configuration problems, MTU mismatches, and connectivity failures.

Prerequisites

  • DPU provisioning completed successfully.
  • The hosted cluster is accessible with DPU worker nodes joined.
  • You have access to both management and hosted cluster contexts.

Procedure

  1. Verify OVN-Kubernetes pod status on the management cluster:

    $ export KUBECONFIG=/path/to/management-cluster.kubeconfig
    $ oc get pods -n openshift-ovn-kubernetes -o wide

    Check that the following pods are running:

    • ovnkube-control-plane-* pods are running on control plane nodes only.
    • ovnkube-node-* pods are running on all nodes.
    • ovs-node-* pods are running on all nodes.
  2. Check OVN-Kubernetes configuration on the hosted cluster:

    $ export KUBECONFIG=/path/to/hosted-cluster.kubeconfig
    $ oc get pods -n openshift-ovn-kubernetes -o wide

    Verify that OVN-Kubernetes pods are running on DPU ARM cores, not on host x86 CPUs.

  3. Verify the network MTU configuration:

    $ oc get network.operator.openshift.io cluster -o yaml | grep -A 5 defaultNetwork

    Check the following MTU values:

    • Standard networks: MTU 1400 for pods, 1500 for nodes.
    • Jumbo frame networks: MTU 8940 for pods, 9000 for nodes.
  4. Test basic pod-to-pod connectivity:

    $ export KUBECONFIG=/path/to/hosted-cluster.kubeconfig
    $ oc run test-pod-1 --image=nicolaka/netshoot --rm -it -- /bin/bash

    From another terminal, run:

    $ oc run test-pod-2 --image=nicolaka/netshoot --rm -it -- /bin/bash

    Test connectivity between the pods by using cluster IP addresses.

  5. Check VTEP network configuration:

    $ export KUBECONFIG=/path/to/management-cluster.kubeconfig
    $ oc debug node/<dpu-enabled-worker-node>

    In the debug shell, run:

    $ chroot /host
    $ ip addr show | grep $VTEP_CIDR

    Verify that VTEP interfaces are configured with the correct IP addresses from the VTEP_CIDR range.

  6. Test VTEP connectivity:

    $ ping -c 4 <other-dpu-vtep-ip>

    If the ping fails, check routing and firewall rules between DPU nodes.

  7. Verify OVN database connectivity:

    $ export KUBECONFIG=/path/to/hosted-cluster.kubeconfig
    $ oc exec -n openshift-ovn-kubernetes <ovnkube-node-pod> -- ovn-nbctl show

    The output should display the OVN logical network topology.

  8. Check OVN-Kubernetes log errors:

    $ oc logs -n openshift-ovn-kubernetes <ovnkube-node-pod> -c ovn-controller

    Look for the following error types:

    • Database connectivity issues
    • Port binding failures
    • Flow programming errors
  9. Verify service mesh connectivity:

    $ export KUBECONFIG=/path/to/hosted-cluster.kubeconfig
    $ oc create service clusterip test-svc --tcp=80:80
    $ oc run test-client --image=nicolaka/netshoot --rm -it -- nc -vz test-svc 80

    A successful connection indicates that service traffic is flowing through the DPU data plane.

  10. Check the SR-IOV network device plugin:

    $ export KUBECONFIG=/path/to/management-cluster.kubeconfig
    $ oc get sriovnetworknodepolicy -n openshift-sriov-network-operator

    Verify that SR-IOV policies are correctly applied to DPU-enabled worker nodes.

Troubleshooting

OVN-Kubernetes pod failures

Check that the OVN Helm chart version is compatible with your OpenShift Container Platform version. Verify that the CNI configuration matches the DPU acceleration requirements. Ensure that OVN databases are accessible from the DPU worker nodes.

MTU mismatch issues

Verify that all network components use consistent MTU values. Check that the physical network infrastructure supports the configured MTU. Update MTU values if the network environment has changed.

VTEP connectivity problems

Verify that the VTEP CIDR does not conflict with existing network ranges. Check that routing is configured between DPU nodes. Ensure that firewalls allow VTEP traffic on the required ports.

Service connectivity failures

Verify that kube-proxy is correctly configured on DPU nodes. Check that iptables rules are correctly programmed. Ensure that DPU acceleration is correctly handling service traffic.

SR-IOV configuration issues

Verify that the SR-IOV Operator is compatible with the DPU firmware. Check that the VF count matches the configured value. Ensure that VFs are correctly allocated to the correct namespaces.

12.8.9. DPF diagnostic commands and log collection

You can run diagnostic commands and collect logs to investigate DPF component status, DPU provisioning failures, and hosted cluster issues when troubleshooting or opening support cases.

12.8.9.1. Quick status overview commands

The following commands provide a quick overview of DPF component status:

DPF resource status

$ oc get dpudeployment,dpuservicetemplate,dpuserviceconfiguration,bfb,dpu -n dpf-operator-system

DPF Operator pod status

$ oc get pods -n dpf-operator-system -l app.kubernetes.io/part-of=dpf-operator

DPU-enabled worker node status

$ oc get nodes -l feature.node.kubernetes.io/dpu-enabled="" \
  -o custom-columns=NAME:.metadata.name,STATUS:.status.conditions[?(@.type=="Ready")].status,AGE:.metadata.creationTimestamp

Hosted cluster status (if using HCP Provisioner)

$ oc get hostedcluster -n clusters-$HOSTED_CLUSTER_NAME

+

$ oc get nodepool -n clusters-$HOSTED_CLUSTER_NAME

12.8.9.2. Detailed diagnostic commands

DPU provisioning status

$ oc describe dpu -n dpf-operator-system

+

$ oc describe bfb -n dpf-operator-system bf-bundle

DPF Operator configuration

$ oc get dpfoperatorconfig -n dpf-operator-system -o yaml

Service template and configuration status

$ oc describe dpuservicetemplate -n dpf-operator-system

+

$ oc describe dpuserviceconfiguration -n dpf-operator-system

DPU service status

$ oc get dpuservice -n dpf-operator-system -o wide

+

$ oc describe dpuservice -n dpf-operator-system

Node Feature Discovery status

$ oc get nodefeaturerule -n openshift-nfd

+

$ oc describe node <worker-node> | grep -A 20 "Labels:"

12.8.9.3. Log collection commands

DPF Operator logs

$ oc logs -n dpf-operator-system -l app.kubernetes.io/name=dpf-operator --tail=200 > dpf-operator.log

HCP Provisioner logs (if using hosted clusters)

$ oc logs -n dpf-operator-system -l app.kubernetes.io/name=dpfhcp-provisioner-operator --tail=200 > dpfhcp-provisioner.log

Worker node kubelet logs

$ oc debug node/<dpu-worker-node>

+ In the debug shell, run:

+

$ chroot /host

+

$ journalctl -u kubelet --since "1 hour ago" > kubelet.log

OVN-Kubernetes logs

$ oc logs -n openshift-ovn-kubernetes -l app=ovnkube-node --tail=100 > ovn-kubernetes.log

SR-IOV Network Operator logs

$ oc logs -n openshift-sriov-network-operator -l app=sriov-network-operator --tail=100 > sriov-operator.log

Node Feature Discovery logs

$ oc logs -n openshift-nfd -l app=nfd-worker --tail=100 > nfd.log

12.8.9.4. System information collection

Hardware information

$ oc debug node/<dpu-worker-node>

+ In the debug shell, run:

+

$ lspci | grep -i mellanox

+

$ lshw -class network

+

$ dmidecode -t system

DPU firmware information

$ mlxfwmanager --query

+

$ mst status

Network interface information

$ ip addr show

+

$ ip route show

+

$ ethtool -i <interface>

12.8.9.5. Performance monitoring commands

DPU service metrics

$ oc exec -n dpf-operator-system <dts-service-pod> -- \
  curl -s localhost:9189/metrics | grep -E "(current_link_speed|p[01]_eth_)"

Container resource usage

$ oc adm top pods -n dpf-operator-system --containers

+

$ oc adm top nodes -l feature.node.kubernetes.io/dpu-enabled=""

12.8.9.6. Support information package

When opening a support case, collect the following information:

Environment information

  • OpenShift Container Platform cluster version and build
  • DPF Operator version and configuration
  • Hardware specifications (server model, DPU model, firmware versions)
  • Network topology and configuration

Configuration files

  • DPF Operator configuration (dpfoperatorconfig)
  • Service templates and configurations
  • Network policies and configurations
  • Environment variables used during installation

Log files

  • DPF Operator logs (past 24 hours)
  • Worker node system logs (past 4 hours)
  • Kubernetes event logs related to DPF resources
  • Application logs for affected services

12.8.9.7. Common log analysis patterns

Look for the following patterns in logs when troubleshooting:

DPU provisioning issues:

  • Error downloading BFB image
  • Failed to detect DPU hardware
  • Provisioning timeout exceeded

Networking issues:

  • OVN database connection failed
  • Failed to program flows
  • Interface binding failed

Service deployment issues:

  • Image pull failed
  • Insufficient resources
  • ConfigMap not found

Authentication issues:

  • Certificate signing request denied
  • Unauthorized access to API server
  • Token validation failed
Red Hat logoGithubredditYoutubeTwitter

Apprendre

Essayez, achetez et vendez

Communautés

À propos de Red Hat

Nous proposons des solutions renforcées qui facilitent le travail des entreprises sur plusieurs plates-formes et environnements, du centre de données central à la périphérie du réseau.

Rendre l’open source plus inclusif

Red Hat s'engage à remplacer le langage problématique dans notre code, notre documentation et nos propriétés Web. Pour plus de détails, consultez le Blog Red Hat.

À propos de la documentation Red Hat

Legal Notice

Theme

© 2026 Red Hat
Retour au début