From 0f8862716e762c291fd05e85370490a67df50d33 Mon Sep 17 00:00:00 2001 From: Alkama Hasan Date: Mon, 12 Jan 2026 12:31:35 +0530 Subject: [PATCH] This commit adds comprehensive sequence diagrams that illustrate the end-to-end integration of DpuNetworkCR with the Disruptive option, covering DPU network creation, update, deletion, NF provisioning, and pod creation flows Signed-off-by: Alkama Hasan --- doc/dpuNetworkCR_Create.pdf | Bin 0 -> 33604 bytes doc/dpuNetworkCR_Delete.pdf | Bin 0 -> 15219 bytes doc/dpuNetworkCR_Update.pdf | Bin 0 -> 15913 bytes doc/dpunetwork_cr_create.puml | 175 ++++++++++++++++++++++++++++++++++ doc/dpunetwork_cr_delete.puml | 116 ++++++++++++++++++++++ doc/dpunetwork_cr_update.puml | 119 +++++++++++++++++++++++ doc/nf_Create.pdf | Bin 0 -> 25197 bytes doc/nf_create.puml | 104 ++++++++++++++++++++ doc/pod_Create.pdf | Bin 0 -> 24599 bytes doc/pod_create.puml | 165 ++++++++++++++++++++++++++++++++ 10 files changed, 679 insertions(+) create mode 100644 doc/dpuNetworkCR_Create.pdf create mode 100644 doc/dpuNetworkCR_Delete.pdf create mode 100644 doc/dpuNetworkCR_Update.pdf create mode 100644 doc/dpunetwork_cr_create.puml create mode 100644 doc/dpunetwork_cr_delete.puml create mode 100644 doc/dpunetwork_cr_update.puml create mode 100644 doc/nf_Create.pdf create mode 100644 doc/nf_create.puml create mode 100644 doc/pod_Create.pdf create mode 100644 doc/pod_create.puml diff --git a/doc/dpuNetworkCR_Create.pdf b/doc/dpuNetworkCR_Create.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c63ce246d9714ea7e1f24459fc5833e8a0c3c678 GIT binary patch literal 33604 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 mUgaMvPsP&9^sgL2^v!~ZXoZBh;Z literal 0 HcmV?d00001 diff --git a/doc/dpuNetworkCR_Delete.pdf b/doc/dpuNetworkCR_Delete.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0638515d2adec936ad92a813ab44c2af2f98cf25 GIT binary patch literal 15219 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 literal 0 HcmV?d00001 diff --git a/doc/dpunetwork_cr_create.puml b/doc/dpunetwork_cr_create.puml new file mode 100644 index 000000000..3b99590f0 --- /dev/null +++ b/doc/dpunetwork_cr_create.puml @@ -0,0 +1,175 @@ +@startuml dpunetwork_cr_creation + +actor user +box "Kubernetes Control Plane" +participant k8s_api +participant dpu_network_controller +participant configmap as "ConfigMap\ndpu-device-plugin-config" +end box + +box "Host Node" +participant kubelet_host as "kubelet (Host)" +participant dpu_daemon_host as "dpu-daemon (Host)\n(Device Plugin Manager + Device Plugin)" +participant vsp_host as "vsp (Host)" +end box + +box "DPU Node" +participant kubelet_dpu as "kubelet (DPU)" +participant dpu_daemon_dpu as "dpu-daemon (DPU)\n(Device Plugin Manager + Device Plugin)" +participant vsp_dpu as "vsp (DPU)" +end box + +autonumber + +== DpuNetwork CR Creation (Multiple Networks) == + +user -> k8s_api: Create DpuNetwork CR 1 +activate k8s_api +note right: **DpuNetwork 1: "dpu-network-1"**\n\napiVersion: networking.example.com/v1\nkind: DpuNetwork\nmetadata:\n name: dpu-network-1\nspec:\n nodeSelector:\n matchLabels:\n node-role: dpu-node\n dpuSelector:\n matchExpressions:\n - key: dpu-type\n operator: In\n values: ["IPU Adapter E2100"]\n - key: vfId\n operator: In\n values: ["0-3", "5-7"]\n IsDisruptive: true + +k8s_api -> dpu_network_controller: Reconcile Event +activate dpu_network_controller + +== DpuNetwork Controller Reconciliation == + +dpu_network_controller -> k8s_api: List Nodes (match nodeSelector) +activate k8s_api +k8s_api -> dpu_network_controller: Matching Nodes +deactivate k8s_api + +dpu_network_controller -> k8s_api: List Dpu CRs +activate k8s_api +k8s_api -> dpu_network_controller: All Dpu CRs +note right: Dpu CR contains:\n netdevs:\n - name: "ens2f0v0" vfId: 0\n - name: "ens2f0v1" vfId: 1\n - name: "ens2f0v2" vfId: 2\n - name: "ens2f0v3" vfId: 3\n - name: "ens2f0v4" vfId: 4\n - name: "ens2f0v5" vfId: 5\n - name: "ens2f0v6" vfId: 6\n - name: "ens2f0v7" vfId: 7 +deactivate k8s_api + +dpu_network_controller -> dpu_network_controller: Evaluate dpuSelector\n(match dpu-type and vfId) + +dpu_network_controller -> dpu_network_controller: Parse vfId ranges\n("0-3" -> [0,1,2,3]\n"5-7" -> [5,6,7]) + +dpu_network_controller -> dpu_network_controller: Filter VFs from Dpu CRs\n(match selected VFs: 0,1,2,3,5,6,7) + +dpu_network_controller -> dpu_network_controller: Generate ResourceName\n"openshift.io/dpunetwork-" + +== ConfigMap-Based Device Plugin Registration == + +dpu_network_controller -> dpu_network_controller: Aggregate all DpuNetwork CRs\nfor this node + +dpu_network_controller -> dpu_network_controller: Generate ConfigMap data\n(config.json with resource definitions) + +dpu_network_controller -> k8s_api: Create/Update ConfigMap\ndpu-device-plugin-config +activate k8s_api +note right: **ConfigMap Approach (Single Source of Truth)**\n\n**One ConfigMap describes resources for both Host and DPU nodes.**\n**Each entry carries a nodeSelector so local daemons only advertise their slice.**\n\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: dpu-device-plugin-config\n namespace: dpu-operator-system\ndata:\n config.json: |\n {\n "resources": [\n {\n "resourceName": "openshift.io/dpunetwork-dpu-network-1",\n "dpuNetworkName": "dpu-network-1",\n "nodeSelector": {"matchLabels": {"node-role": "host"}},\n "vfRanges": ["0-3", "5-7"]\n },\n {\n "resourceName": "openshift.io/dpunetwork-dpu-network-1",\n "dpuNetworkName": "dpu-network-1",\n "nodeSelector": {"matchLabels": {"node-role": "dpu"}},\n "vfRanges": ["0-3", "5-7"],\n "rpmRanges": ["0-0"],\n "vethRanges": ["0-1"]\n }\n // Additional resources per DpuNetwork CR\n ]\n } +k8s_api -> configmap: ConfigMap Created/Updated +activate configmap +k8s_api -> dpu_network_controller: ConfigMap Updated +deactivate k8s_api + +== Host dpu-daemon Watches ConfigMap == + +configmap -> dpu_daemon_host: ConfigMap Change Event\n(watch notification) +activate dpu_daemon_host + +dpu_daemon_host -> k8s_api: Get ConfigMap\ndpu-device-plugin-config +activate k8s_api +k8s_api -> dpu_daemon_host: ConfigMap with config.json +deactivate k8s_api + +dpu_daemon_host -> dpu_daemon_host: Parse config.json\nFilter entries where node-role = host + +note over dpu_daemon_host: **Per-Node Architecture Decision:**\n**Single device plugin instance per node**\n- Host instance only advertises host-scoped resources\n- Reads shared ConfigMap, filters via nodeSelector\n- Updates in-place on ConfigMap changes + +alt Host Device Plugin Not Running + dpu_daemon_host -> dpu_daemon_host: Start Device Plugin Instance\n(read host resources) +else Host Device Plugin Already Running + dpu_daemon_host -> dpu_daemon_host: Reload Config\n(apply new host resource set) +end + +dpu_daemon_host -> vsp_host: GetDevices() +activate vsp_host +vsp_host -> vsp_host: Return host-visible devices\n(VF repr set shared with DPU) +vsp_host -> dpu_daemon_host: Host device inventory +deactivate vsp_host + +dpu_daemon_host -> dpu_daemon_host: Build device list\nApply vfRanges [0-3,5-7] +note right: Host Resource\n"openshift.io/dpunetwork-dpu-network-1"\nDevices: VFs 0,1,2,3,5,6,7 (no RPM/veth) + +dpu_daemon_host -> dpu_daemon_host: ListAndWatch()\n(advertise host resource only) + +dpu_daemon_host -> kubelet_host: Register Device Plugin\nResource "openshift.io/dpunetwork-dpu-network-1" +activate kubelet_host +kubelet_host -> dpu_daemon_host: Registration Accepted +kubelet_host -> kubelet_host: Add node capacity\n"openshift.io/dpunetwork-dpu-network-1": 7 (host) +deactivate kubelet_host + +deactivate dpu_daemon_host + +== DPU dpu-daemon Watches ConfigMap == + +configmap -> dpu_daemon_dpu: ConfigMap Change Event\n(watch notification) +activate dpu_daemon_dpu + +dpu_daemon_dpu -> k8s_api: Get ConfigMap\ndpu-device-plugin-config +activate k8s_api +k8s_api -> dpu_daemon_dpu: ConfigMap with config.json +deactivate k8s_api + +dpu_daemon_dpu -> dpu_daemon_dpu: Parse config.json\nFilter entries where node-role = dpu + +note over dpu_daemon_dpu: **Per-Node Architecture Decision:**\n**Single DPU-side device plugin instance**\n- Reads same ConfigMap, filters for node-role=dpu\n- Advertises VF + RPM + veth resources\n- No restart required on updates + +alt DPU Device Plugin Not Running + dpu_daemon_dpu -> dpu_daemon_dpu: Start Device Plugin Instance\n(read DPU resources) +else DPU Device Plugin Already Running + dpu_daemon_dpu -> dpu_daemon_dpu: Reload Config\n(apply new DPU resource set) +end + +dpu_daemon_dpu -> vsp_dpu: GetDevices() +activate vsp_dpu +vsp_dpu -> vsp_dpu: Return devices by type\n(VF repr, RPM, veth) +vsp_dpu -> dpu_daemon_dpu: DPU device inventory +deactivate vsp_dpu + +dpu_daemon_dpu -> dpu_daemon_dpu: Build device lists\n- VF repr filtered by vfRanges\n- RPM list via rpmRanges\n- veth list via vethRanges +note right: DPU Resources Advertised\n1. "openshift.io/dpunetwork-dpu-network-1" (VF x7)\n2. "openshift.io/rpm-disruptive" (rpmRange 0-0)\n3. "openshift.io/veth-nondisruptive" (vethRange 0-1) + +dpu_daemon_dpu -> dpu_daemon_dpu: ListAndWatch()\n(advertise three resources) + +dpu_daemon_dpu -> kubelet_dpu: Register Device Plugin\nAll DPU resources +activate kubelet_dpu +kubelet_dpu -> dpu_daemon_dpu: Registration Accepted +kubelet_dpu -> kubelet_dpu: Add node capacity\nVF=7, RPM=1, veth=2 +deactivate kubelet_dpu + +deactivate dpu_daemon_dpu +deactivate configmap + +== BridgeID and NAD Generation (1 NAD per DpuNetwork CR) == + +dpu_network_controller -> dpu_network_controller: Create BridgeID + +dpu_network_controller -> dpu_network_controller: Create single NAD\nfor all VFs in network\n(shared config: IsDisruptive, IPAM) + +dpu_network_controller -> k8s_api: Create NetworkAttachmentDefinition +activate k8s_api +note right: **NAD 1 for DpuNetwork 1**\n\nmetadata:\n name: dpunetwork-1-nad\n namespace: default\n annotations:\n dpu.config.openshift.io/dpu-network: dpu-network-1\n k8s.v1.cni.cncf.io/resourceName: openshift.io/dpunetwork-dpu-network-1\nspec:\n config: {\n "type": "dpu-cni",\n "cniVersion": "0.4.0",\n "name": "dpu-cni",\n "BridgeID": "",\n "IsDisruptive": "true",\n "ipam": {...}\n }\n\n**VFs (0,1,2,3,5,6,7) use this NAD**\n**Multiple pods can use this NAD**\n**Each pod gets allocated a VF from the pool** +k8s_api -> dpu_network_controller: NAD Created +deactivate k8s_api + +note over dpu_network_controller: **About NRI (Network Resources Injector):**\nNRI webhook is installed once (via DpuOperatorConfig) and is not re-registered per DpuNetwork.\nDpuNetwork creation only needs to create NAD(s) and (optionally) publish a mapping (e.g., in DpuNetwork.status)\nso NRI can translate `dpu.config.openshift.io/dpu-network: ` into\n`k8s.v1.cni.cncf.io/networks: ` during Pod CREATE. + +dpu_network_controller -> k8s_api: Update DpuNetwork 1 Status +activate k8s_api +note right: status:\n conditions:\n - type: Ready\n status: True\n message: NAD and Device Plugin created\n resourceName: "openshift.io/dpunetwork-dpu-network-1"\n selectedVFs: [0,1,2,3,5,6,7]\n excludedVFs: [4] +k8s_api -> dpu_network_controller: Status Updated +deactivate k8s_api + +deactivate dpu_network_controller +deactivate k8s_api + +note over k8s_api: **Architecture Summary:**\n**Single ConfigMap, per-node device plugin instances**\n**- Host dpu-daemon filters node-role=host resources**\n**- DPU dpu-daemon filters node-role=dpu resources (VF+RPM+veth)**\n**- Each node runs exactly one device plugin instance**\n**- Entries share resourceName when devices overlap**\n**- NAD per DpuNetwork CR stays unchanged**\n\n**When new DpuNetwork CR created:**\n**- Controller updates ConfigMap with host + DPU entries**\n**- Both daemons detect change and reload in-place**\n**- No new pods/daemons required, only ListAndWatch updates** + +note right of user: **See:**\n- pod_creation_regular.puml for pod creation flow\n- pod_creation_nf_disruptive.puml for NF pod flow\n- dpunetwork_cr_update.puml for update flow\n- dpunetwork_cr_deletion.puml for deletion flow + +@enduml + diff --git a/doc/dpunetwork_cr_delete.puml b/doc/dpunetwork_cr_delete.puml new file mode 100644 index 000000000..00acb5ab5 --- /dev/null +++ b/doc/dpunetwork_cr_delete.puml @@ -0,0 +1,116 @@ +@startuml dpunetwork_cr_deletion + +actor user +box "Kubernetes Control Plane" +participant k8s_api +participant dpu_network_controller +participant configmap as "ConfigMap\\ndpu-device-plugin-config" +end box + +box "Host Node" +participant kubelet_host as "kubelet (Host)" +participant dpu_daemon_host as "dpu-daemon (Host)\\n(Device Plugin Manager + Device Plugin)" +participant vsp_host as "vsp (Host)" +end box + +box "DPU Node" +participant kubelet_dpu as "kubelet (DPU)" +participant dpu_daemon_dpu as "dpu-daemon (DPU)\\n(Device Plugin Manager + Device Plugin)" +participant vsp_dpu as "vsp (DPU)" +end box + +autonumber + +== DpuNetwork Deletion (ConfigMap Approach) == + +note right of user: **Prerequisites:**\nDpuNetwork CR already created\nSee: dpunetwork_cr_creation.puml + +user -> k8s_api: Delete DpuNetwork CR +activate k8s_api + +k8s_api -> dpu_network_controller: Reconcile Event (Deletion) +activate dpu_network_controller + +dpu_network_controller -> dpu_network_controller: Aggregate remaining DpuNetwork CRs\n(remove deleted network from list) + +dpu_network_controller -> dpu_network_controller: Generate updated ConfigMap data\n(remove network-1 resource definition) + +dpu_network_controller -> k8s_api: Update ConfigMap\ndpu-device-plugin-config +activate k8s_api +note right: **ConfigMap Updated**\n\nconfig.json updated:\n "resources": [\n // network-1 removed\n {\n "resourceName": "openshift.io/dpunetwork-dpu-network-2",\n ...\n }\n ] +k8s_api -> configmap: ConfigMap Updated +activate configmap +k8s_api -> dpu_network_controller: ConfigMap Updated +deactivate k8s_api + +== ConfigMap Change Propagates to Host and DPU Nodes == + +configmap -> dpu_daemon_host: ConfigMap Change Event\\n(resource removed) +activate dpu_daemon_host + +dpu_daemon_host -> k8s_api: Get Updated ConfigMap +activate k8s_api +k8s_api -> dpu_daemon_host: ConfigMap without network-1 +deactivate k8s_api + +dpu_daemon_host -> dpu_daemon_host: Parse config.json\\nDetect removed resource "openshift.io/dpunetwork-dpu-network-1" + +dpu_daemon_host -> dpu_daemon_host: Update single device plugin instance\\n(reload config, rebuild advertised list) + +dpu_daemon_host -> vsp_host: ReleaseHostVfPool(bridge_id="x1") +activate vsp_host +vsp_host -> vsp_host: Remove VF entries bound to host pods +vsp_host -> dpu_daemon_host: VF pool released +deactivate vsp_host + +dpu_daemon_host -> kubelet_host: ListAndWatch Update\\n(unregister CR-specific resource) +activate kubelet_host +kubelet_host -> kubelet_host: Remove node capacity\\n"openshift.io/dpunetwork-dpu-network-1" +kubelet_host -> dpu_daemon_host: Resource Removed +deactivate kubelet_host + +deactivate dpu_daemon_host + +configmap -> dpu_daemon_dpu: ConfigMap Change Event\\n(resource removed) +activate dpu_daemon_dpu + +dpu_daemon_dpu -> k8s_api: Get Updated ConfigMap +activate k8s_api +k8s_api -> dpu_daemon_dpu: ConfigMap without network-1 +deactivate k8s_api + +dpu_daemon_dpu -> dpu_daemon_dpu: Parse config.json\\nDetect removal of VF, RPM, veth entries for bridge "x1" + +dpu_daemon_dpu -> dpu_daemon_dpu: Update device plugin instance\\n(stop advertising VF resource, adjust RPM/Veth counts) + +dpu_daemon_dpu -> vsp_dpu: DeleteNetworkResources(bridge_id="x1") +activate vsp_dpu +vsp_dpu -> vsp_dpu: Tear down NF map entry\\nremove VF + RPM interfaces +vsp_dpu -> vsp_dpu: Delete flow rules and bridge br-x1 +vsp_dpu -> dpu_daemon_dpu: Network resources deleted +deactivate vsp_dpu + +dpu_daemon_dpu -> kubelet_dpu: ListAndWatch Update\\n(unregister VF resource, update RPM/veth counts) +activate kubelet_dpu +kubelet_dpu -> kubelet_dpu: Remove node capacity\\n"openshift.io/dpunetwork-dpu-network-1" on DPU node +kubelet_dpu -> dpu_daemon_dpu: Resource Removed +deactivate kubelet_dpu + +deactivate dpu_daemon_dpu +deactivate configmap + +dpu_network_controller -> k8s_api: Delete NetworkAttachmentDefinition +activate k8s_api +k8s_api -> dpu_network_controller: NAD Deleted +deactivate k8s_api + +dpu_network_controller -> k8s_api: Remove Finalizer +deactivate dpu_network_controller + +k8s_api -> k8s_api: DpuNetwork CR Deleted +deactivate k8s_api + +note right of user: **Related Diagrams:**\n- dpunetwork_cr_creation.puml (host setup)\n- dpunetwork_cr_creation-dpu.puml (DPU setup)\n- dpunetwork_cr_update.puml (update flow) + +@enduml + diff --git a/doc/dpunetwork_cr_update.puml b/doc/dpunetwork_cr_update.puml new file mode 100644 index 000000000..aa58464c3 --- /dev/null +++ b/doc/dpunetwork_cr_update.puml @@ -0,0 +1,119 @@ +@startuml dpunetwork_cr_update + +actor user +box "Kubernetes Control Plane" +participant k8s_api +participant dpu_network_controller +participant configmap as "ConfigMap\ndpu-device-plugin-config" +end box + +box "Host Node" +participant kubelet_host as "kubelet (Host)" +participant dpu_daemon_host as "dpu-daemon (Host)\n(Device Plugin Manager + Device Plugin)" +participant vsp_host as "vsp (Host)" +end box + +box "DPU Node" +participant kubelet_dpu as "kubelet (DPU)" +participant dpu_daemon_dpu as "dpu-daemon (DPU)\n(Device Plugin Manager + Device Plugin)" +participant vsp_dpu as "vsp (DPU)" +end box + +autonumber + +== DpuNetwork Update (ConfigMap Approach) == + +note right of user: **Prerequisites:**\nDpuNetwork CR already created\nSee: dpunetwork_cr_creation.puml + +user -> k8s_api: Update DpuNetwork CR\n(change vfId ranges: "0-2", "5-7") +activate k8s_api + +k8s_api -> dpu_network_controller: Reconcile Event +activate dpu_network_controller + +dpu_network_controller -> dpu_network_controller: Re-evaluate VF selection\n(new ranges: [0,1,2,5,6,7]) + +dpu_network_controller -> dpu_network_controller: Generate updated ConfigMap data\n(update network-1 resource definition) + +dpu_network_controller -> k8s_api: Update ConfigMap\ndpu-device-plugin-config +activate k8s_api +note right: **ConfigMap Updated**\n\nconfig.json updated:\n "resources": [\n {\n "resourceName": "openshift.io/dpunetwork-dpu-network-1",\n "vfRanges": ["0-2", "5-7"],\n ...\n }\n ] +k8s_api -> configmap: ConfigMap Updated +activate configmap +k8s_api -> dpu_network_controller: ConfigMap Updated +deactivate k8s_api + +== Host dpu-daemon Reloads ConfigMap == + +configmap -> dpu_daemon_host: ConfigMap Change Event\n(resource definition updated) +activate dpu_daemon_host + +dpu_daemon_host -> k8s_api: Get Updated ConfigMap +activate k8s_api +k8s_api -> dpu_daemon_host: ConfigMap with updated host entry +deactivate k8s_api + +dpu_daemon_host -> dpu_daemon_host: Parse config.json\nFilter node-role = host +note right: Host entry still only lists VF ranges\nOld: [0,1,2,3,5,6,7]\nNew: [0,1,2,5,6,7] (VF 3 removed) + +dpu_daemon_host -> vsp_host: GetDevices() +activate vsp_host +vsp_host -> vsp_host: Return host-visible VF devices +vsp_host -> dpu_daemon_host: Device inventory +deactivate vsp_host + +dpu_daemon_host -> dpu_daemon_host: Rebuild device list\nApply new vfRanges (remove VF 3) + +dpu_daemon_host -> dpu_daemon_host: Update ListAndWatch\n(advertise host resource only) + +dpu_daemon_host -> kubelet_host: ListAndWatch Update\n(device-3 removed from resource) +activate kubelet_host +kubelet_host -> kubelet_host: Update node capacity\n"openshift.io/dpunetwork-dpu-network-1": 6 (host) +deactivate kubelet_host + +deactivate dpu_daemon_host + +== DPU dpu-daemon Reloads ConfigMap == + +configmap -> dpu_daemon_dpu: ConfigMap Change Event\n(resource definition updated) +activate dpu_daemon_dpu + +dpu_daemon_dpu -> k8s_api: Get Updated ConfigMap +activate k8s_api +k8s_api -> dpu_daemon_dpu: ConfigMap with updated DPU entry +deactivate k8s_api + +dpu_daemon_dpu -> dpu_daemon_dpu: Parse config.json\nFilter node-role = dpu +note right: DPU entry mirrors host VF change\n(and may include RPM/veth adjustments) + +dpu_daemon_dpu -> vsp_dpu: GetDevices() +activate vsp_dpu +vsp_dpu -> vsp_dpu: Return VF/RPM/veth inventory +vsp_dpu -> dpu_daemon_dpu: Device inventory +deactivate vsp_dpu + +dpu_daemon_dpu -> dpu_daemon_dpu: Rebuild device lists\n- VF repr filtered with new ranges\n- RPM/veth unchanged (if not in diff) + +dpu_daemon_dpu -> dpu_daemon_dpu: Update ListAndWatch\n(advertise VF + RPM + veth) + +dpu_daemon_dpu -> kubelet_dpu: ListAndWatch Update\n(update capacities per resource) +activate kubelet_dpu +kubelet_dpu -> kubelet_dpu: Update node capacity\n"openshift.io/dpunetwork-dpu-network-1": 6 (DPU VF)\n(RPM/veth counts unchanged) +deactivate kubelet_dpu + +deactivate dpu_daemon_dpu +deactivate configmap + +dpu_network_controller -> k8s_api: Update NetworkAttachmentDefinition +activate k8s_api +k8s_api -> dpu_network_controller: NAD Updated +deactivate k8s_api + +dpu_network_controller -> k8s_api: Update DpuNetwork Status +deactivate dpu_network_controller +deactivate k8s_api + +note right of user: **Related Diagrams:**\n- dpunetwork_cr_creation.puml (initial setup)\n- dpunetwork_cr_deletion.puml (cleanup flow) + +@enduml + diff --git a/doc/nf_Create.pdf b/doc/nf_Create.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0f685aed801623658e57d50dfbc9de145e38232b GIT binary patch literal 25197 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 Io+|nO1IY|z@Bjb+ literal 0 HcmV?d00001 diff --git a/doc/pod_create.puml b/doc/pod_create.puml new file mode 100644 index 000000000..ddce80892 --- /dev/null +++ b/doc/pod_create.puml @@ -0,0 +1,165 @@ +@startuml pod_creation_regular + +actor user +box "Kubernetes Control Plane" +participant k8s_api +participant nri as "network-resources-injector (NRI)\nMutating Webhook" +end box + +box "Host Node" +participant kubelet +participant device_plugin as "device_plugin" +participant cni_plugin +participant cni_server +participant host_side_manager +end box + +box "DPU Node" +participant dpu_side_manager +participant vendor_plugin +end box + +autonumber + +== Pod Creation Using Different DpuNetworks == + +note right of user: **Prerequisites:**\nDpuNetwork CR created and ready\nDevice Plugin registered\nNetwork Resources Injector (NRI) deployed (via DpuOperatorConfig)\nSee: dpunetwork_cr_creation.puml + +user -> k8s_api: Create Pod 1 with DpuNetwork annotation +activate k8s_api +note right: **Pod 1 → DpuNetwork 1**\nannotations:\n dpu.config.openshift.io/dpu-network: dpu-network-1\n\nresources:\n requests:\n openshift.io/dpunetwork-dpu-network-1: "1"\n\n**User references DpuNetwork; NRI injects Multus NAD annotation** + +== Admission (Mutating Webhook) == + +k8s_api -> nri: AdmissionReview (Pod CREATE)\ncheck dpu-network annotation +activate nri +nri -> k8s_api: Patch Pod annotation\nk8s.v1.cni.cncf.io/networks = default/dpunetwork-1-nad +deactivate nri + +note right of k8s_api: After mutation, the stored Pod has\nk8s.v1.cni.cncf.io/networks pointing to the NAD\nso Multus will act on it. + +k8s_api -> kubelet: Pod Scheduled to Node +activate kubelet + +kubelet -> kubelet: Check Resource Request\n"openshift.io/dpunetwork-dpu-network-1": 1 + +kubelet -> device_plugin: Allocate(AllocateRequest)\nResource: "openshift.io/dpunetwork-dpu-network-1" +activate device_plugin +note right: ContainerRequests:\n DevicesIDs: ["device-2"]\n (Kubelet selects from\n available devices in pool) + +device_plugin -> device_plugin: Lookup resource in ConfigMap\n"openshift.io/dpunetwork-dpu-network-1" + +device_plugin -> device_plugin: Validate DeviceID\n(device-2 maps to VF 2) + +device_plugin -> device_plugin: Check VF in allowed range\n(VF 2 is in [0,1,2,3,5,6,7] ✓)\n(from ConfigMap resource definition) + +device_plugin -> device_plugin: Allocate device\nSet NF-DEV env var\nNF-DEV="0000:00:07.2" +device_plugin -> kubelet: AllocateResponse\n(NF-DEV env var) +deactivate device_plugin + +kubelet -> cni_plugin: Execute dpu-cni\n(NAD config with BridgeID & IsDisruptive) +activate cni_plugin + +cni_plugin -> cni_server: POST /cni\n(NAD config) +activate cni_server + +cni_server -> host_side_manager: cniCmdAddHandler\n(PodRequest with BridgeID & IsDisruptive) +activate host_side_manager + +== Bridge Port Creation == + +host_side_manager -> dpu_side_manager: CreateBridgePort(gRPC{BridgePortID,IsDisruptive,Bridge}) +activate dpu_side_manager +note right: CreateBridgePortRequest:\n BridgePortID: "x1"\n IsDisruptive:true BridgePort:\n Name: "host0-1"\n Spec:\n MacAddress: "..."\n + +dpu_side_manager -> vendor_plugin: CreateBridgePort(OPI API) +activate vendor_plugin + +vendor_plugin -> vendor_plugin: Check IsDisruptive flag\nfrom CreateBridgePortRequest + +alt IsDisruptive = true + vendor_plugin -> vendor_plugin: Lookup NF in local registry\nby BridgeID (BridgePortID="x1") + + alt NF not found in registry + vendor_plugin -> dpu_side_manager: Error: NF not created yet\nPlease use non-Disruptive mode to Host + deactivate vendor_plugin + dpu_side_manager -> host_side_manager: Error Response + deactivate dpu_side_manager + host_side_manager -> cni_server: CNI Error + deactivate host_side_manager + cni_server -> cni_plugin: HTTP Error Response + deactivate cni_server + cni_plugin -> kubelet: CNI Error + deactivate cni_plugin + kubelet -> k8s_api: Update Pod Status (Failed) + deactivate kubelet + deactivate k8s_api + note right: **Error Flow:**\nNF must be created first\nusing CreateNetworkFunction\nbefore host side can connect\nin disruptive mode + else NF found in registry + vendor_plugin -> vendor_plugin: Fetch PodNetworkFunctionInfo from VSP map\nKey = BridgePortID "x1" + note right: **VSP Map Structure (Keyed by BridgeID)**\n\nVSP Maintains:\nMap\n\nKey: "x1"\nValue: PodNetworkFunctionInfo {\n pod_name: "my-nf"\n pod_namespace: "openshift-dpu-operator"\n pod_uid: "abc-123-def-456"\n bridge_id: "x1"\n is_disruptive: true\n entries: [\n {type: "VF", vf_index: 1, input_mac: "aa:bb:cc:dd:ee:01", input_device: "0000:00:07.1", netns: "/proc/1234/ns/net"},\n ...\n {type: "VF", vf_index: 7, input_mac: "aa:bb:cc:dd:ee:07", input_device: "0000:00:07.7", netns: "/proc/1234/ns/net"},\n {type: "RPM", input_mac: "aa:bb:cc:dd:ee:ff", input_device: "rpm-0", netns: "/proc/1234/ns/net"}\n ]\n} + vendor_plugin -> vendor_plugin: Determine vf_index from host VF\n(using NF-DEV mapping) + vendor_plugin -> vendor_plugin: Check VF entry exists in NF map\n(BridgeID "x1", vf_index) + alt VF entry exists in NF map + vendor_plugin -> dpu_side_manager: BridgePort Verified\n(VF already part of NF map) + deactivate vendor_plugin + + dpu_side_manager -> host_side_manager: BridgePort Response + deactivate dpu_side_manager + + host_side_manager -> cni_server: CNI Result + deactivate host_side_manager + + cni_server -> cni_plugin: HTTP Response + deactivate cni_server + + cni_plugin -> kubelet: CNI Success + deactivate cni_plugin + else VF entry missing in NF map + vendor_plugin -> dpu_side_manager: Error: Device not added to NF (Disruptive) + deactivate vendor_plugin + dpu_side_manager -> host_side_manager: Error Response + deactivate dpu_side_manager + host_side_manager -> cni_server: CNI Error + deactivate host_side_manager + cni_server -> cni_plugin: HTTP Error Response + deactivate cni_server + cni_plugin -> kubelet: CNI Error + deactivate cni_plugin + kubelet -> k8s_api: Update Pod Status (Failed) + deactivate kubelet + deactivate k8s_api + note right: **Error Flow:**\nHost VF must match an entry\ncreated during NF registration + end + end +else IsDisruptive = false (Non-Disruptive Mode) + vendor_plugin -> vendor_plugin: Select/Create bridge\nbr-x1 (from bridge_id) + + vendor_plugin -> vendor_plugin: AddPortToDataPlane\n(bridge=br-x1, vfName) + + vendor_plugin -> vendor_plugin: AddFlowRuleToDataPlane\n(bridge=br-x1, ...) + + vendor_plugin -> dpu_side_manager: BridgePort Created + deactivate vendor_plugin + + dpu_side_manager -> host_side_manager: BridgePort Response + deactivate dpu_side_manager + + host_side_manager -> cni_server: CNI Result + deactivate host_side_manager + + cni_server -> cni_plugin: HTTP Response + deactivate cni_server + + cni_plugin -> kubelet: CNI Success + deactivate cni_plugin +end + +kubelet -> k8s_api: Update Pod 1 Status (Running) +deactivate kubelet +deactivate k8s_api + +note right of user: **Related Diagrams:**\n- pod_creation_nf_disruptive.puml for NF pods\n- dpunetwork_cr_creation.puml for CR setup + +@enduml +

sX|NRb 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 lMSjm k8s_api: Create NF Pod with DpuNetwork annotation +activate k8s_api +note right: **NF Pod YAML (Disruptive Mode)**\n\napiVersion: v1\nkind: Pod\nmetadata:\n name: "my-nf"\n namespace: openshift-dpu-operator\n annotations:\n dpu.config.openshift.io/dpu-network: dpu-network-1 # controller fills NAD list\nspec:\n nodeSelector:\n dpu.config.openshift.io/dpuside: "dpu"\n containers:\n - name: "my-nf"\n image: "ghcr.io/ovn-kubernetes/kubernetes-traffic-flow-tests:latest"\n resources:\n requests:\n openshift.io/dpunetwork-dpu-network-1: "7" # all VF representors from CR\n openshift.io/rpm-disruptive: "1" # 1 RPM when IsDisruptive=true\n limits:\n openshift.io/dpunetwork-dpu-network-1: "7"\n openshift.io/rpm-disruptive: "1"\n\n**Only DpuNetwork annotation provided by user**\n**Controller patches k8s.v1.cni.cncf.io/networks** + +== Admission (Mutating Webhook) == + +k8s_api -> nri: AdmissionReview (Pod CREATE)\ncheck dpu-network annotation + dpuside nodeSelector +activate nri +note right of nri: NRI logic (high-level):\n- Read DpuNetwork CR (dpu-network-1)\n- Determine side from nodeSelector\n dpuside=dpu → DPU-side injection\n- Determine required VF count (e.g., from resource request)\n- If IsDisruptive=true: inject VF NAD repeated N times + rpm-disruptive NAD\n- Else: inject single non-disruptive NAD +nri -> k8s_api: Patch Pod annotation\nk8s.v1.cni.cncf.io/networks = [dpunetwork-1-nad x7, rpm-disruptive] +deactivate nri + +note right of k8s_api: After mutation, the stored Pod has a NAD list.\nMultus will call CNI ADD once per NAD entry.\n(Repeating the VF NAD N times yields N CNI cmdADD calls.) + +k8s_api -> kubelet: Pod Scheduled to Node +activate kubelet + +kubelet -> kubelet: Check Resource Requests\n"openshift.io/dpunetwork-dpu-network-1": 7 (all VFs from CR)\n"openshift.io/rpm-disruptive": 1 (RPM port) + +kubelet -> dpu_daemon: Allocate(AllocateRequest)\nContainerRequests for 7 VF devices + 1 RPM device\nResource: "openshift.io/dpunetwork-dpu-network-1" (x7)\nResource: "openshift.io/rpm-disruptive" (x1) +activate dpu_daemon + +dpu_daemon -> dpu_daemon: Lookup resources in ConfigMap\n"openshift.io/dpunetwork-dpu-network-1"\n"openshift.io/rpm-disruptive" + +dpu_daemon -> dpu_daemon: Allocate devices from resource pool\nDevice-1 (VF 1)\nDevice-2 (VF 2)\nDevice-3 (VF 3)\nDevice-4 (VF 4)\nDevice-5 (VF 5)\nDevice-6 (VF 6)\nDevice-7 (VF 7)\nDevice-RPM (RPM interface) + +dpu_daemon -> kubelet: AllocateResponse\n(NF-DEV env var for all 8 devices) +deactivate dpu_daemon + +note right of kubelet: **NAD processing order**\n1. VF NAD (`dpunetwork-1`) triggers 7 CNI cmdADD calls (one per VF)\n2. rpm-disruptive NAD triggers 1 CNI cmdADD call for RPM port\n3. Total: 8 CNI cmdADD calls, each triggers a createNetworkFunction call to VSP + +== Multiple CNI cmdADD Calls == + +loop for each of 7 VF representors from CR (Device-1 to Device-7) +kubelet -> dpu_daemon: Execute dpu-cni (cmdADD)\nNAD config: dpunetwork-1\nVF index: 1..7 +activate dpu_daemon + +dpu_daemon -> dpu_daemon: cniCmdNfAddHandler\n(PodRequest with VF info) + +dpu_daemon -> dpu_daemon: Prepare NFRequest\nExtract BridgeID from DpuNetwork CR\nVF MAC address\nVF device info + +dpu_daemon -> vendor_plugin: CreateNetworkFunction(gRPC)\nNFRequest{\n input: "aa:bb:cc:dd:ee:0X" (VF MAC),\n output: "",\n bridge_id: "x1",\n is_disruptive: true,\n vf_index: X\n} +activate vendor_plugin + +vendor_plugin -> vendor_plugin: Validate BridgeID="x1"\nEntry in VSP Map:\n Key: "x1"\n Value: {\n pod_name: "my-nf",\n pod_uid: "abc-123-def-456",\n entries: [\n {vf_index: X, input_mac, device, ...}\n ]\n } + +vendor_plugin -> dpu_daemon: NetworkFunction Created +deactivate vendor_plugin + +dpu_daemon -> kubelet: CNI Success (VF) +deactivate dpu_daemon +end + +== RPM Port CNI cmdADD Call == + +kubelet -> dpu_daemon: Execute dpu-cni (cmdADD)\nNAD config: rpm-disruptive +activate dpu_daemon + +dpu_daemon -> dpu_daemon: cniCmdNfAddHandler\n(PodRequest with RPM info) +note right: **PodRequest**\n\nPodRequest:\n PodName: "my-nf"\n PodNamespace: "openshift-dpu-operator"\n PodUID: "abc-123-def-456"\n Netns: "/proc/1234/ns/net"\n CNIConf:\n BridgeID: "x1"\n IsDisruptive: true\n MAC: "aa:bb:cc:dd:ee:ff" (RPM MAC) + +dpu_daemon -> dpu_daemon: Check IsDisruptive flag\nIsDisruptive = true\nPrepare NFRequest for RPM + +dpu_daemon -> vendor_plugin: CreateNetworkFunction(gRPC)\nNFRequest{\n input: "aa:bb:cc:dd:ee:ff" (RPM MAC),\n output: "",\n bridge_id: "x1",\n is_disruptive: true,\n is_rpm: true\n} +activate vendor_plugin + +vendor_plugin -> vendor_plugin: Update VSP Map Entry\n Key: "x1"\n Value: {\n pod_name: "my-nf",\n pod_uid: "abc-123-def-456",\n entries: [\n {vf_index: 1, input_mac, device, ...},\n {vf_index: 2, input_mac, device, ...},\n ...\n {vf_index: 7, input_mac, device, ...},\n {is_rpm: true, input_mac: "aa:bb:cc:dd:ee:ff", ...}\n ]\n } + +vendor_plugin -> vendor_plugin: Configure Flow Rules for all entries\nBridge: br-x1\nAll VF interfaces + RPM interface\nDisruptive mode: traffic via single RPM + +vendor_plugin -> dpu_daemon: NetworkFunction Created +deactivate vendor_plugin + +dpu_daemon -> kubelet: CNI Success (RPM) +deactivate dpu_daemon + +kubelet -> k8s_api: Update Pod Status (Running) +deactivate kubelet +deactivate k8s_api + +note right of user: **VSP Map Structure (Keyed by BridgeID)**\n\nVSP Maintains:\n Map\n\n Key: "x1"\n Value: PodNetworkFunctionInfo {\n pod_name: "my-nf"\n pod_namespace: "openshift-dpu-operator"\n pod_uid: "abc-123-def-456"\n bridge_id: "x1"\n is_disruptive: true\n entries: [\n {\n type: "VF",\n vf_index: 1,\n input_mac: "aa:bb:cc:dd:ee:01",\n input_device: "0000:00:07.1",\n netns: "/proc/1234/ns/net"\n },\n ... (6 more VF entries) ...\n {\n type: "VF",\n vf_index: 7,\n input_mac: "aa:bb:cc:dd:ee:07",\n input_device: "0000:00:07.7",\n netns: "/proc/1234/ns/net"\n },\n {\n type: "RPM",\n input_mac: "aa:bb:cc:dd:ee:ff",\n input_device: "rpm-0\",\n netns: "/proc/1234/ns/net"\n }\n ]\n }\n\n**Summary:**\n- 8 total CNI cmdADD calls (7 VFs + 1 RPM)\n- 8 createNetworkFunction calls to VSP\n- 1 VSP map entry per pod, keyed by BridgeID\n- All NF interfaces (VFs + RPM) tracked in single entry\n\n**Related Diagrams:**\n- pod_creation_regular.puml for regular pods\n- dpunetwork_cr_creation.puml for CR setup + +@enduml + diff --git a/doc/pod_Create.pdf b/doc/pod_Create.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4839de7928c46878bddbb6fdda13f038f9845128 GIT binary patch literal 24599 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