Skip to content

Nephio-Orchestrated Private 5G: Sdcore-OCUDU

This guide describes how a complete private 5G network, an SD-Core control plane, a BESS user plane and an OCUDU-RAN gNB, is deployed onto bare-metal edge servers from a single declarative intent object, with no imperative per-site scripting.

A management cluster runs Nephio; an operator turns a short EdgeSite or Fleet intent into Nephio PackageVariants; Porch renders them, Config Sync delivers them, and Cluster API provisions a fresh Kubernetes cluster on each target server. The addressing, the network slice, the subscriber records and the N2/N3/N4/N6 datapath are all derived from the intent rather than hand-configured. The result is a reproducible, one-command-per-site deployment where adding, changing or removing a 5G edge is a change to a single Kubernetes object.

The Nephio 5G edge automation and deployment flow in three tiers. Tier one, intent, authored once and applied by one command: a platform operator applies an EdgeSite or Fleet custom resource carrying server, role (cp+upf or upf-only), ran device and subscribers. Tier two, the management cluster running the Nephio control plane, bootstrapped once: the Kubernetes API server stores the custom resources and is watched by an SD-Core operator written in Go, which reconciles EdgeSite, Fleet, MeshLink, Network and UPFDataPath controllers. The operator claims IPClaims from an IPAM called sdcore-vpc that allocates uePool, N3, N4 and N6 CIDRs; creates PackageVariants that Porch clones from a blueprint catalog holding sdcore-cp, sdcore-upf, ocudu-gnb, multus and datapath-actuator packages; passes draft PackageRevisions to an auto-approver that promotes them from Draft through Proposed to Published into Gitea, an in-cluster Git deployment repository that is the source of truth; and creates ByoHost and Cluster resources for Cluster API with the BYOH provider, which onboards a bare server and bootstraps Canonical Kubernetes with Cilium CNI, SCTP for N2 and ClusterMesh. Tier three, the edge site on a bare server running Canonical Kubernetes, repeated N times: Config Sync as a RootSync GitOps agent pulls the deploy repo and applies the SD-Core control plane (AMF, SMF, NRF, AUSF, NSSF, PCF, UDM, UDR, WebUI and Mongo), the OCUDU gNB combining CU and DU with RRC, NGAP, GTP-U, scheduler and RF, Multus with network attachment definitions attaching n3, core and radio0 to pods, and the BESS UPF in af_packet mode doing GTP-U encapsulation and decapsulation with PDR and FAR across N3, N4 and N6. A datapath actuator DaemonSet on each node programs host routes, N6 NAT and the downlink next-hop MAC.

The end-to-end control flow. Everything below the intent is Kubernetes-native and continuously reconciled; there is no SSH-driven configuration on the data path.

Nephio treats a 5G network the way Kubernetes treats an application: as desired state expressed in declarative objects, reconciled by controllers, and version-controlled in Git. This document focuses on the automation, how one intent object becomes a running multi-cluster 5G deployment, rather than on the internals of the individual network functions, which are covered in their own pages.

Overview

Standing up a private 5G network by hand is a sequence of tightly-coupled, error-prone steps: prepare a host, install Kubernetes, lay down a CNI, deploy a control plane, wire a user plane, attach a radio, allocate IP ranges that do not collide, provision subscribers, and stitch the N2/N3/N4/N6 reference points across the whole thing. Every one of those steps is a place to drift. Repeat it across several edge sites and the configuration becomes impossible to reason about, and impossible to reproduce.

Nephio is a Kubernetes-based automation platform, built in the Linux Foundation, for exactly this problem: deploying and managing cloud-native network functions across large numbers of clusters using intent and GitOps rather than imperative tooling. Its model is that the operator declares what they want, a 5G edge on this server with this radio, and the platform continuously reconciles the world to match, generating the per-cluster configuration automatically and delivering it through Git.

This integration applies that model to a specific, validated stack:

  • The control plane is SD-Core. AMF, SMF, NRF, AUSF, NSSF, PCF, UDM, UDR, a web console and a MongoDB backing store, deployed as a Nephio package.
  • The user plane is a BESS UPF in af_packet mode, deployed as its own package and wired to the control plane over N4.
  • The radio is an OCUDU-RAN gNB, an integrated CU/DU, deployed as a package and auto-wired to the site's AMF, PLMN, TAC and slice.
  • The glue is a purpose-built operator that expresses all of the above as a single EdgeSite or Fleet intent and expands it into Nephio packages.

The practical outcome is that a new 5G edge, a full self-contained core plus radio, or a lightweight user-plane-only site steered by a central control plane, is created, changed or torn down by editing one Kubernetes object.

Why a Helm chart is not enough

The obvious way to package a 5G core is a Helm chart, applied per cluster. That works for a single, hand-built cluster, but it does not address the parts that actually make multi-site 5G hard:

  • It assumes the cluster already exists. A Helm chart cannot turn a bare server into a Kubernetes cluster. Something still has to provision the node, the CNI and the runtime before any chart runs.
  • It does not allocate addressing. Every site needs a non-overlapping UE pool and distinct N3/N4/N6 subnets. A static chart either hard-codes these, which does not scale past one site, or pushes the problem back onto the operator.
  • It does not specialise per site. The gNB must be told this site's AMF address, PLMN, TAC and slice; the UPF must be told this site's UE pool. That specialisation is per-cluster and derived, not templated once.
  • It is not continuously reconciled across clusters. A chart is applied and forgotten. Drift on a remote edge is invisible until something breaks.

Nephio closes these gaps by treating the whole deployment, cluster included, as reconciled intent. Package specialisation (rendering per-site values into each package) and package delivery (GitOps reconciliation onto each cluster) are first-class, and cluster provisioning is driven by the same declarative loop. The Helm charts do not disappear; they become blueprints that Nephio renders and places, rather than artefacts an operator applies by hand.

Concepts

A handful of Nephio and Kubernetes building blocks carry the whole design. Each is standard; the integration is in how they are composed.

Building blockRole in this design
KRM and CRDsEverything is a Kubernetes Resource Model object. The intent is expressed with two CRDs, EdgeSite and Fleet, under the sdcore.nephio.io API group. Declaring intent is kubectl apply of a small YAML document.
The operator patternA controller watches those CRDs and drives the world toward the declared state. A single Go operator hosts several controllers, one per concern (site expansion, fleet fan-out, cross-cluster mesh, datapath), each reconciling continuously.
Porch and PackageVariantsPorch is a Kubernetes extension API server managing the lifecycle of kpt configuration packages. A PackageVariant is intent to take an upstream blueprint and render a specialised copy with per-site values injected. The operator emits PackageVariants; Porch produces the concrete package revisions.
BlueprintsUpstream, reusable packages, one each for the SD-Core control plane, the BESS UPF, the OCUDU gNB, Multus and the datapath actuator, held in a catalog. A blueprint is specialised, not edited, so moving to a newer network-function release is a change to the blueprint rather than to the operator.
Config Sync and GitOpsConfig Sync continuously reconciles a cluster to the contents of a Git repository. Published packages land in an in-cluster Gitea repository; each edge cluster's Config Sync pulls its own packages and keeps applying them, so drift self-heals.
Cluster API and BYOHCluster API is the Kubernetes-standard way to provision clusters declaratively. The Bring-Your-Own-Host provider lets it provision onto an already-running bare-metal or VM host that has registered an agent. The bootstrap target is Canonical Kubernetes, with Cilium as the CNI (SCTP enabled for N2, ClusterMesh available for cross-cluster reference points).
IPAMA Nephio-managed address pool hands out non-overlapping ranges, the UE pool and the N3/N4/N6 subnets, as IP claims, so no two sites collide and no addressing is hand-assigned.

Architecture

The deployment has two tiers: one management cluster that runs Nephio and the operator, and any number of edge clusters, one per bare-metal server, that run the actual 5G network functions.

The intent API: EdgeSite and Fleet

An EdgeSite describes a single site. It is deliberately small, because the operator derives everything else.

apiVersion: sdcore.nephio.io/v1alpha1
kind: EdgeSite
metadata:
  name: edge-01
spec:
  server: 192.168.1.111     # a registered bare-metal host
  role: cp+upf              # self-contained core + UPF  (or: upf-only)
  ran:
    device: n310            # OCUDU gNB radio: n310 | b210 | zmq

role: cp+upf yields a self-contained site: an SD-Core control plane, a BESS UPF and, because ran is present, an OCUDU gNB, all on the one cluster, with N2 and N4 kept local. role: upf-only yields a lightweight site whose UPF is steered by a control plane on another cluster, with N2/N4 carried over Cilium ClusterMesh. The ran.device selects the radio the OCUDU gNB drives: a networked USRP N310, a USB b210, or the ZMQ RF simulator for hardware-free validation.

A Fleet is a list of sites, reconciled as a unit:

apiVersion: sdcore.nephio.io/v1alpha1
kind: Fleet
metadata:
  name: fleet
spec:
  sites:
    - server: 192.168.1.111
      role: cp+upf
      ran: { device: n310 }
    - server: 192.168.1.112
      role: upf-only

Adding, changing or removing a site is an edit to this one object. Each entry is expanded into an owned EdgeSite; removing an entry garbage-collects the site.

The management cluster

The management cluster is bootstrapped once. It runs the Kubernetes API server, the operator, Porch, the in-cluster Gitea, the Config Sync source, the IPAM pool, and the Cluster API stack with the BYOH provider and the Canonical Kubernetes bootstrap provider. Nothing about a 5G network function lives here: the management cluster's job is to produce and place configuration, not to run the network.

An intent-driven 5G stack with Nephio, presented as a C4-style architecture view. On the left, actors as each view names them: personas including a designer who creates the network function packages and a network engineer who implements and instantiates them; a person, the administrator of networks, cloud infrastructure or both; Porch view actors comprising a network administrator and external automation systems; service orchestration covering a core service orchestrator and an O-RAN service orchestrator; and an external system for GitOps and CI/CD. Edge labels describe the relationships: create and generate network topology, Kubernetes cluster and network function intent; manage the lifecycle of Nephio blueprints and packages; reconcile, integrate or deploy external artefacts; and manage package variants and package variant sets. On the right, the Nephio system container view shows five containers inside the boundary and two external ones it depends on: a Backstage-based Web UI, the Kubernetes API server, Porch as kpt-as-a-service managing the lifecycle of KRM config packages, Nephio Core as Kubernetes operators for workload and cluster specialisation and actuation, network function controllers as Kubernetes operators handling network function lifecycle for OAI Core, RAN and free5GC, plus an external reconciliation engine as the GitOps engine and an external Git repository manager. A Porch component view shows two custom resource definitions, PackageVariantSet and PackageVariant, living in the Kubernetes API server, with their two matching controllers living in Porch and reconciling package variants against what is in Git. A Nephio Core component view lists five custom resource definition APIs, Resources, Inventory, Infrastructure, Config and Workload, alongside six Kubernetes reconciler controllers, Resource Backend, Token, K8s Cluster, Repository, Network and Bootstrap Package, each drawing an arrow to the API it manages, with an inventory datastore beneath them. Controller actuation targets are the Git repository manager, supported network functions, cloud providers and the network fabric. At the bottom, an infrastructure boundary contains cloud providers such as GCP, OpenShift and local kind clusters, and network fabric elements such as Nokia SR Linux.

Nephio itself, in C4 form: the actors, the containers inside the system boundary, the Porch component view and the Nephio Core APIs and controllers.

Package generation and delivery

When an EdgeSite is applied, the operator reconciles it into a set of Nephio packages:

  1. It claims addressing from IPAM, a UE pool and N3/N4/N6 subnets, so the site's ranges are unique by construction.
  2. It emits one PackageVariant per network function: the SD-Core control plane, the BESS UPF, the OCUDU gNB (when ran is set), Multus with the site's network-attachment definitions, and the datapath actuator.
  3. Porch clones the matching blueprint from the catalog and renders each variant with the site's derived values: AMF address, PLMN, TAC, slice identifiers, and the claimed subnets.
  4. An auto-approver promotes each rendered package revision from Draft to Published.
  5. The published packages land in Gitea, the deployment repository that is the single source of truth for what each site should run.
A detailed component diagram of the Nephio system. Inside the Nephio Core container, a Nephio Core APIs container holds five custom resource definition components: Resources, which defines IPClaim, IPPrefix, NetworkInstances, VlanClaims, VlanIndices and Vlans; Inventory, which defines endpoints, links, nodes and targets; Infrastructure, which defines workload cluster, tokens, repositories, networks and network configs; Config, which defines networks configuration; and Workload, which defines NFConfigs, NFDeployments and the AMF, UPF and SMF network functions. Below, a Nephio Core Controllers container holds six Kubernetes reconciler components: Resource Backend, which manages resource assignment and creates and manages IP and VLAN index, claim and assignment; Token, for handling security tokens used to authenticate against systems; K8S Cluster, responsible for reconciling cluster definitions with running clusters; Repository, for reconciling repository definitions; Network, responsible for reconciling network attachment definitions; and Bootstrap Package, for bootstrapping onboarded packages and deploying initial kpt packages upon cluster creation. An inventory datastore container sits beneath them. To the left, an external Git repository manager container hosts Git repositories and supports remote branch management and merging. To the right, the Kubernetes API server exposes the custom resource definitions, and network function controllers manage the lifecycle of network functions, currently supporting OAI Core, RAN and free5GC. At the lower right, an infrastructure boundary contains network fabric elements such as Nokia SR Linux and cloud providers such as GCP, OpenShift and local kind clusters.

Nephio Core in detail: the five CRD groups, the six reconciler controllers, and what each one actuates.

Cluster provisioning

In parallel with package generation, the operator declares the infrastructure the packages will run on. It creates a ByoHost for the registered server and a Cluster object; Cluster API with the BYOH provider bootstraps Canonical Kubernetes on that host, with Cilium as the CNI. This is the step a Helm chart cannot do: it turns a bare server into a Kubernetes cluster, declaratively, from the same reconcile loop that produced the packages.

Once the new cluster is up, its Config Sync agent registers against the Gitea repository and pulls the packages destined for that site. From here the edge cluster is self-driving: Config Sync applies the SD-Core control plane, the BESS UPF, the OCUDU gNB and Multus, and keeps them reconciled.

The edge site

Each edge cluster runs the 5G network itself: the SD-Core control plane (AMF, SMF, NRF, AUSF, NSSF, PCF, UDM, UDR, web console, MongoDB), the BESS UPF in af_packet mode, and, for a cp+upf site with a radio, the OCUDU-RAN gNB, an integrated CU/DU that drives the selected USRP and terminates N2 at the AMF and N3 at the UPF. Multus attaches the N3 and radio interfaces to the pods that need them.

The datapath actuator

The one part of a running 5G network that lives below Kubernetes is the host packet path: the routes, the N6 egress NAT, and the Layer-2 next-hop the UPF stamps onto downlink traffic. These cannot be expressed as ordinary pod manifests, so a small datapath actuator runs as a DaemonSet on each edge node. It watches a UPFDataPath object the operator emits and programs the host to match, installing the downlink route to the gNB, the N6 egress NAT out the real uplink NIC, and the correct next-hop MAC, so the automation extends all the way to the wire rather than stopping at the pod boundary.

How it works

End to end, a single kubectl apply becomes a running 5G edge through a continuous reconcile loop:

  1. Declare. The operator applies an EdgeSite, or edits a Fleet, on the management cluster.
  2. Reconcile intent. The operator controller picks up the object, claims addressing from IPAM, and computes the site's derived values: AMF address, PLMN, TAC, slice, subnets.
  3. Generate packages. It emits one PackageVariant per network function; Porch clones each blueprint and renders it with those values.
  4. Publish. The auto-approver promotes the rendered revisions to Published; they land in Gitea.
  5. Provision. In parallel, CAPI with the BYOH provider bootstraps Canonical Kubernetes on the target server.
  6. Deliver. The new cluster's Config Sync pulls its packages and applies the SD-Core control plane, BESS UPF, OCUDU gNB and Multus.
  7. Wire the datapath. The datapath actuator programs the host routes, N6 NAT and downlink next-hop so the N3/N6 user plane forwards.
  8. Serve. The OCUDU gNB drives its radio; a UE attaches to the SD-Core control plane, establishes a PDU session, and user traffic egresses via the UPF's N6.

Because every step is a reconciler, the loop is self-healing: if a package drifts, Config Sync re-applies it; if a host is re-onboarded, provisioning starts from a clean state. And because the intent is a single object, teardown is symmetric. Deleting the EdgeSite, or removing a Fleet entry, garbage-collects the packages, Config Sync prunes the workloads, and CAPI deprovisions the cluster. There is no per-host teardown script.

What this delivers

  • One-object-per-site 5G. A complete edge, core, user plane and radio, from a single EdgeSite, or a whole estate from a single Fleet.
  • Automatic specialisation. UE pool, N3/N4/N6 subnets, AMF address, PLMN, TAC and slice are derived from intent and IPAM, not hand-assigned.
  • Declarative cluster provisioning. Bare servers become Kubernetes clusters through CAPI/BYOH, inside the same reconcile loop that produces the workloads.
  • GitOps delivery and self-healing. Every site's configuration is version-controlled in Git and continuously reconciled by Config Sync.
  • Two topologies from one API. cp+upf self-contained cores and upf-only user-plane edges, steered over ClusterMesh, share the same intent surface.
  • Datapath automation to the wire. The host N3/N6 path is programmed by a controller, not by SSH.
  • Symmetric teardown. Deleting intent releases the cluster; no imperative decommissioning.

Why this matters

The value is in the separation of concerns. Intent is authored once, in one small object, by whoever owns the service. Specialisation, turning that intent into per-site configuration, is done by controllers, deterministically, so two sites never drift apart by accident. Delivery is GitOps, so the source of truth is a repository rather than the live state of a remote cluster. Provisioning is declarative, so the cluster is as reproducible as the workloads on it.

This is the same architectural discipline Kubernetes brought to applications, applied to a 5G network: desired state, reconciled continuously, version-controlled, and composed from reusable blueprints. A network function release is a blueprint bump. A new site is a line of YAML. An estate is a Fleet.

What it is, and what it is not

What it is. A reproducible, intent-driven method for deploying SD-Core, a BESS UPF and an OCUDU-RAN gNB across one or many bare-metal edge sites, using Nephio for specialisation and delivery and Cluster API for provisioning. It automates the full path from a single intent object to a running, self-healing 5G edge, including the host datapath.

What it is not. It is not a fork of Nephio, SD-Core or OCUDU-RAN: the network functions are deployed as blueprints and specialised, not modified. It is not a claim of conformance certification; it is a deployment and lifecycle-automation method, and the network functions carry their own conformance posture. It does not replace an SMO or a service orchestrator above it; it presents a Kubernetes-native intent surface that such a system can drive.

Roadmap

  • Broader radio and split support. Further OCUDU-RAN configurations beyond the USRP (split 8) and Open Fronthaul (7.2) paths documented below, including additional O-RU vendors and band profiles.
  • Richer topology intent. Declarative expression of multi-site meshes and control-plane sharing beyond the current cp+upf and upf-only split.
  • Blueprint currency. Continuous tracking of upstream SD-Core and OCUDU-RAN releases as blueprint revisions, so a version bump is a package change.
  • Observability as intent. Per-site metrics and datapath health surfaced through the same reconciled model.

Deployment

A complete edge is a single command chain. On the management server:

# 1. Clone
git clone https://github.com/TOSSI-Foundation/Nephio-Stack.git && cd Nephio-Stack

# 2. Bootstrap the management plane (once)
make prereqs        # pinned toolchain (go, kustomize, clusterctl, kpt)
make mgmt           # Canonical K8s + CAPI + BYOH + Nephio (Porch) + in-cluster Gitea
make publish        # operator + blueprints + auto-approver + IPAM pool

# 3. Build the OCUDU gNB image (any radio site needs it)
make gnb-image OCUDU_SRC=<path-to-ocudu-clone>

Declare a site in fleet.yaml, an SD-Core control plane with a BESS UPF and an OCUDU gNB:

apiVersion: sdcore.nephio.io/v1alpha1
kind: Fleet
metadata: { name: fleet, namespace: default }
spec:
  sites:
    - server: <edge-ip>
      user: <login>
      role: cp+upf
      ran:
        split: "8"
        device: n310        # n310 | b210 | x310 | zmq (RF simulator)

Reconcile the whole fleet. This provisions the cluster and deploys the stack:

make sites
kubectl get edgesites,clusters      # wait until the site's cluster is Ready

Tear the whole fabric down. This is declarative too: CAPI deprovisions the clusters and the hosts are wiped pristine.

make down

Step-by-step guides, for RF-sim at 50-UE scale and for split-8 with a real SDR, are in the TI repository.

Validation with the rfsimulator

This stack has been validated end to end: an SD-Core control plane, a BESS edge UPF and an OCUDU-RAN gNB, all deployed from a single intent, serving 50 simulated UEs, which attached, established PDU sessions and passed traffic through the Nephio-deployed core and UPF.

Real radios: Split-8 and Split-7.2

Everything above is validated against the rfsimulator, which proves the orchestration. A real radio proves the product. Real hardware adds a second world of state: a software-defined radio to drive, or an O-RU to reach over Open Fronthaul with sub-microsecond timing, DPDK fast-path NICs, VLANs and compression windows, and a user plane that must forward real packets to the internet in both directions. Every one of those is a place a hand-built deployment drifts.

The same platform drives both. The intent surface does not grow when the radio gets real: the radio architecture is one field, and the core, the UPF, the addressing, the slice, the subscriber records and the datapath are untouched between them.

The Nephio SD-Core and OCUDU Split-8 and Split-7.2 specialization and actuation flow, in ten numbered stages across three columns. The stages along the top are: zero, provision, where CAPI and BYOH build the management and edge Canonical Kubernetes clusters; one, watch, where the sdcore-operator reads the EdgeSite or Fleet custom resource; two, variant, one PackageVariant custom resource per site and function; three, clone, where Porch clones the blueprint at an immutable version into a draft revision; four, specialize, where kpt mutators render the per-cluster package; five, approve, where auto-approve moves draft to proposed to published; six, commit, where the published package goes to the deployment repository; seven, pull, where RootSync pulls only its own cluster directory; eight, apply, where KRM reaches on-cluster controllers and becomes pods; and nine, connect, where network functions interconnect over N2, N3, N4 and N6. Column A, the management cluster, holds the intent custom resources, the sdcore-operator, the Porch and PackageVariant controller, the kpt function pipeline that injects PLMN, TAC, slice, N2 VIP from IPAM and SIM data, and an auto-approve controller acting as a publish gate. Column B, Gitea, holds an upstream blueprint repository with reusable network function kinds including sdcore-cp, sdcore-upf, ocudu-gnb-split8, edge-site and cluster-ck8s-byoh, and a downstream deployment repository holding specialized published KRM with one directory per cluster. Column C, workload clusters, shows a management workload cluster running the SD-Core control plane, an OCUDU gNB on Split-8 over UHD with a USRP B210, and a BESS UPF forwarding N3 in and N6 out to the internet; and an edge workload cluster running Config Sync, an OCUDU gNB with its DU and CU protocol stacks, a radio unit or SDR reached through a fronthaul switch with PTP grandmaster, the SD-Core control plane functions AMF, SMF, AUSF, UDM, UDR and NRF, and an edge BESS UPF acting as the local user plane.

One intent, two radio architectures

A complete self-contained edge on a real radio is the same few lines shown under Deployment, with the radio selected by one field:

  ran:
    split: "8"              # "8" = USRP driven directly | "7.2" = Open Fronthaul to an O-RU
    device: n310            # b210 | n310 | x310 (USRP), or an O-RU under split 7.2

Change split: "8" to split: "7.2" and the operator renders an entirely different RAN, a different image, container profile and set of interfaces. The RAN is a blueprint specialised by Porch, never forked, so the orchestration is indifferent to which radio hangs off the intent.

Split-8: a monolithic gNB driving a USRP

Under split: "8", the operator renders a monolithic OCUDU gNB, with CU, DU and PHY in one process, that drives a USRP directly over UHD. USB SDRs (b210) need only the device; networked SDRs (n310 and x310) stream at jumbo MTU, so the operator attaches a dedicated radio0 macvlan on the host's radio NIC at MTU 9000 and passes the SDR's address through intent. N2 goes to the AMF and N3 rides a dedicated access-net interface to the BESS UPF. There is no fronthaul, no PTP and no DPDK: the RF-PHY split is at the antenna, and the SDR does the conversion.

The Nephio SD-Core and OCUDU Split-8 specialization and actuation flow. The same ten-stage pipeline runs from provision through watch, variant, clone, specialize, approve, commit, pull, apply and connect. The management cluster column shows the intent custom resources with ran.split set to 8, the sdcore-operator, the Porch and PackageVariant controller, and a kpt function pipeline whose specialization rule reads that ran.split equals 8 implies the ocudu-gnb-split8 blueprint with the UHD image. The Gitea column shows the upstream blueprint repository and the downstream deployment repository with one directory per cluster. The workload clusters column shows the management workload cluster running the SD-Core control plane, an OCUDU gNB on Split-8 as a monolithic CU and DU over UHD with a USRP B210, and a BESS UPF forwarding N3 in and N6 out to the internet. The edge workload cluster shows a 5G UE and a USRP NI B210 software-defined radio connected to an OCUDU gNB on Split-8, whose DU layer holds SSB, PRACH, PDCCH, PDSCH, PUSCH, PUCCH, MAC, RLC, scheduler and DU manager blocks, and whose CU layer holds RRC, PDCP, F1AP, NGAP, SDAP and GTP-U, alongside the SD-Core control plane and an edge BESS UPF.

Split-7.2: an Open-Fronthaul gNB driving an O-RU

Under split: "7.2", the operator renders an integrated CU and DU gNB with the Open Fronthaul interface, connected to an O-RU over eCPRI. The fronthaul rides a DPDK fast-path: the gNB runs with the fronthaul VF passed through (vfio-pci), huge pages mounted, and the eCPRI transport, covering RU and DU MAC, VLAN, BFP compression, t1a and ta4 timing windows and eAxC port maps, taken from the RAN spec. PTP keeps the DU and the O-RU on a common clock. As with Split-8, N2 goes to the AMF and N3 to the UPF; everything above the fronthaul is identical.

The Nephio SD-Core and OCUDU Split-7.2 specialization and actuation flow. The pipeline and the management cluster and Gitea columns are identical to the Split-8 variant, showing that only the radio changes. The workload clusters column differs in the edge cluster: an OCUDU gNB on Split-7.2 reaches a radio unit through a fronthaul switch with a PTP grandmaster, rather than driving a USRP directly. The gNB's DU layer holds SSB, PRACH, PDCCH, PDSCH, PUSCH, PUCCH, MAC, RLC, scheduler and DU manager blocks, and its CU layer holds RRC, PDCP, F1AP, NGAP, SDAP and GTP-U. The SD-Core control plane functions and the edge BESS UPF are unchanged from the Split-8 deployment.

Actuation to the radio, and to the wire

Real radios need the user plane to actually forward, and part of that lives below Kubernetes. Two pieces are handled as data rather than by hand.

The gNB's downlink address. A pod-network gNB left to default advertises 0.0.0.0 as its N3 endpoint, the UPF encapsulates downlink to a black hole, and the UE attaches with 5G and an IP but nothing comes back. The operator pins the gNB's NG-U socket to its real N3 address, for every split, so the UPF's forwarding rule points at the actual radio.

The host datapath. The datapath actuator described above, driven by a UPFDataPath object, programs the host routes, the N6 egress NAT and the downlink next-hop MAC, resolving the gNB's live neighbour address so the route survives restarts. Actuation reaches all the way to the wire.

Host prerequisites

A real radio has genuine hardware prerequisites, and the platform is explicit about the boundary. Everything that can be data, is; the irreducibly physical is documented rather than hidden inside a controller.

SplitWhat the host must provide
Split-8The USRP connected and powered, its UHD firmware present, and isolated (isolcpus) real-time CPUs.
Split-7.2The fronthaul VF bound to vfio-pci, huge pages reserved, PTP (ptp4l and phc2sys) running and locked to the O-RU's clock, the O-RU powered and on its fronthaul VLAN, and isolated CPUs.
The Nephio 5G edge automation and deployment flow in three tiers, with the radio rendered per split. Tier one, intent, authored once and applied by one command: a platform operator applies an EdgeSite or Fleet custom resource under sdcore.nephio.io, carrying server, role, ran device and subscriber fields. Tier two, the management cluster running the Nephio control plane: the Kubernetes API server stores the custom resources and acts as the watch source for the SD-Core operator written in Go, which reconciles EdgeSite, Fleet, MeshLink, Network and UPFDataPath controllers. That operator creates PackageVariants for Porch, which clones blueprints from a catalogue containing sdcore-cp, sdcore-upf, ocudu-gnb, multus and datapath-actuator; claims addressing from an IPAM component that allocates UE pool and N3, N4 and N6 CIDRs; drives an auto-approver that moves packages from draft through proposed to published into an in-cluster Gitea repository; and drives Cluster API with the BYOH provider to bootstrap Canonical Kubernetes with Cilium CNI and SCTP for N2. Tier three, the edge site on a bare server: Config Sync reconciles that site's packages, applying the SD-Core control plane, an OCUDU gNB rendered as either the 8 split with RF over UHD or the 7.2 split with linuxptp for Open Fronthaul, Multus with network attachment definitions, and a BESS UPF in af_packet mode. A datapath actuator DaemonSet programs host routes, N6 NAT and the downlink next-hop MAC.

Declaring real-radio sites

A Split-8 site, a Split-7.2 site, or both, in the same fleet.yaml:

spec:
  sites:
    - server: <edge-ip-1>          # Split-8: USRP
      user: <login>
      role: cp+upf
      ran:
        split: "8"
        device: n310
        radioNic: <sdr-data-nic>
        radioAddr: <sdr-ip>
    - server: <edge-ip-2>          # Split-7.2: O-RU over Open Fronthaul
      user: <login>
      role: cp+upf
      ran:
        split: "7.2"
        device: <o-ru-model>
        ofh:
          interface: "<fronthaul-vf-pci>"
          ruMac: "<o-ru-mac>"
          duMac: "<du-vf-mac>"
          vlanTag: <fronthaul-vlan>

Split-7.2 also needs the host-side fronthaul preparation listed above. Beyond that, make sites and make down behave exactly as for a simulated radio.

Validation on real hardware

This stack has been validated end to end on real hardware: a real COTS phone attached and browsed the internet through the Nephio-deployed SD-Core and BESS UPF, first over a USRP (Split-8), then over a LiteON O-RU (Split-7.2), from the same intent, with the core, UPF, addressing and slice untouched between the two runs.

An RF simulator answers "does the orchestration work?"; a real radio answers "is it a product?", because it forces the automation to survive a physical layer with a timing budget, a fronthaul that must be reached exactly, a fast-path NIC, and a user plane that has to deliver real bytes both ways. Doing that while keeping the intent to one line, the same line whether the radio is simulated, a USRP or an O-RU, is the point. The radio became real; the operator's job did not change.

Conclusion

A private 5G network does not have to be assembled by hand. Expressed as intent and reconciled by controllers, an entire edge, control plane, user plane and radio, becomes a single Kubernetes object, and an estate becomes a list of them. The radio architecture is one field within that object, whether it is simulated, a USRP or an O-RU over Open Fronthaul. The platform handles the specialisation, the provisioning, the delivery and the datapath; the operator handles the intent.

Resources

The network functions deployed here are documented separately: SD-Core with eUPF covers the XDP datapath and usage metering, and the rfsimulator multi-UE testbed covers hardware-free validation with the ZMQ and rfsimulator radio paths. For certification of the deployed functions, see Cloud Native Telecom Certification.