Skip to main content

Deploy Cells

Declare cells on real radios, one per radio, on the nodes you choose; check them, change them, remove them. The examples follow the reference deployment: a control node running the CU planes and the core, and two radio nodes each with a USRP B210. A control node that is itself rf-ready carries a radio too; the same declaration then names it. For an end-to-end walkthrough with a phone, see the tutorials Attach a Phone to a Live Cell and Hand Over Between Two Cells.

Before You Declare​

  • The platform is installed and dormant. kubectl get deploy -n centralized-unit shows cu-cp, cu-up and cuip at 0/0. (Install the Control Node)

  • Each real radio has a node. The host is provisioned and joined, carries racora.io/rf-ready=true, and advertises the radio:

    kubectl get nodes -L racora.io/rf-ready
    kubectl get node <node> -o jsonpath='{.status.allocatable.ettus\.com/usrp}{"\n"}' # 1 per USRP

    If either is missing, see Add a Radio Node and Connect a Radio.

  • The network identity. Every cell declares spec.plmn and spec.tac, and both must be in the identity the network serves (global.network: PLMN 90170, tracking area 7 by default — what the cells below and every example in these docs use). A cell outside it is refused with the condition ConfigGenerated=False (PlmnNotServed / TacNotServed) and never reaches the core; to run another identity, change it in one place (Configure the 5G Core).

  • A radio plan. Band, ARFCN, bandwidth and subcarrier spacing per cell, under your own spectrum authorization. The PCI is optional: leave it out and the controller assigns a temporary one, which the Intelligence Plane replaces with a planned one.

  • Timing, if there is more than one cell. Handover needs frame-aligned cells, which on USRPs means a GPSDO with GPS lock on every radio; decide this before you buy antennas (How Mobility Reaches the CU-CP).

One Cell on a USRP B210​

A 10 MHz n78 carrier on a B210 over USB 3. The lines that are yours to change are the radio's serial, the node and, once the cell has a neighbor to hand over to, the clock:

apiVersion: racora.io/v1alpha1
kind: NRCell
metadata:
name: nr-n78-b210
namespace: racora-system
spec:
band: 78
dlArfcn: 632628
channelBandwidthMHz: 10
commonScs: 30
plmn: "90170"
tac: 7
pci: 1
radioBackend:
ruType: uhd
uhd:
deviceArgs: "type=b200,serial=35912B3,num_recv_frames=64,num_send_frames=64" # your radio's serial
clockSource: internal # gpsdo once cells hand over (needs GPS lock)
otwFormat: sc12
srate: 23.04
txGain: 80
rxGain: 40
duAssignment:
nodeName: radio-node-2 # your radio node
position:
xCoord: 0
yCoord: 0
heightM: 1
azimuthDeg: 0

The four carrier fields, plmn and tac are the only required ones; pci is optional (the controller assigns one when it is missing); duAssignment.nodeName pins the DU to a node; position and azimuthDeg are read by the Intelligence Plane for its graph geometry and never reach the gNB. What every radio field does is Connect a Radio; the full list with defaults and ranges is the NRCell API.

kubectl apply -f nr-n78-b210.yaml

What the Controller Does with It​

It assigns the cell's identity (sectorId, gnbDuId, gnbId, the resulting nci), fills in a temporary PCI when you left pci out, generates the DU (a ConfigMap and a Deployment in distributed-unit, scheduled onto rf-ready nodes and the one you named, requesting one USRP), scales the CU plane 0 → 1 on the first cell, and regenerates the CU-CP's overlay with every cell's identity and mobility configuration. The DU connects to the CU-CP over F1 and the cell goes on air, unless you declared it adminState: Locked. The identity rules are Cell Identity; what lands in status is NRCell Status and Conditions. A PCI you set yourself is kept unless the Intelligence Plane finds it in a two-hop confusion with another cell, in which case it retunes it.

Check It​

kubectl get nrcell -n racora-system
# NAME PCI PCI-SOURCE SECTOR DU-ID NCI BAND PHASE AGE
# nr-n78-b210 1 spec 0 0 0x66C000 78 ConfigGenerated 3m
kubectl get pods -n distributed-unit # du-nr-n78-b210 Running
kubectl get deploy -n centralized-unit # cu-cp / cu-up / cuip 1/1 (cuip needs the control node's GPU)
kubectl get nrcell nr-n78-b210 -n racora-system -o jsonpath='{.status.conditions}{"\n"}'

Phase is Pending while a temporary PCI is being assigned, ConfigGenerated once the DU exists, Error with a condition saying why otherwise (NRCell Status and Conditions). cuip reaches 1/1 only on a node with a GPU (Requirements). Whether the cell is actually on the air is the CU-CP's answer, not Kubernetes'; ask it with the cell's decimal NCI (status.nciDecimal) over the Runtime Commands:

{"cmd": "cell_status", "cgi": {"plmn": "90170", "nci": 6733824}}

The reply says operational_state: enabled for a cell on the air; how to reach the command surface is the runtime commands reference.

A DU that is Running but restarting is usually waiting on the radio's GPS lock; that and every other way a cell fails to come up is in Troubleshoot.

A Second Cell on Another Radio Node​

The same declaration with its own radio and node; nothing else has to be coordinated — identity is assigned, the PCI is planned apart from the first cell's, and the CU-CP's configuration grows to hold both:

apiVersion: racora.io/v1alpha1
kind: NRCell
metadata:
name: nr-n78-b210-node1
namespace: racora-system
spec:
band: 78
dlArfcn: 632628
channelBandwidthMHz: 10
commonScs: 30
plmn: "90170"
tac: 7
radioBackend:
ruType: uhd
uhd:
deviceArgs: "type=b200,serial=3591266,num_recv_frames=64,num_send_frames=64"
clockSource: internal # gpsdo once cells hand over (needs GPS lock)
otwFormat: sc12
srate: 23.04
txGain: 80
rxGain: 40
duAssignment:
nodeName: radio-node-1

No pci this time: the controller assigns a temporary one and the Intelligence Plane replaces it with a planned one that does not collide with the first cell's (status.pciSource: controller-retuned).

Two cells that can hand UEs over to each other need two more things: frame alignment (both clockSource: gpsdo with GPS lock), and the neighbor relations, declared on each cell toward the other (Configure Mobility and Cell State); automatic neighbor relations can also discover them for you. The tutorial Hand Over Between Two Cells walks through both.

Change a Cell​

Edit the NRCell and the controller reconciles it. Which changes cost what:

  • Radio parameters (band, dlArfcn, bandwidth, SCS, the radioBackend block, pci) change the DU's rendered configuration, so the DU pod rolls — the cell leaves the air for the restart. The DU rolls only when its rendered configuration actually changed.
  • Mobility and administrative state (neighbors, mobility, periodicReportCfgId, adminState, cellBarred) are applied to the running CU-CP; no restart.
  • pci: when the Intelligence Plane retunes it, the controller does it behind a cell lock and unlocks after the DU rolled; when you change it by hand, only the DU roll happens.
  • duAssignment.nodeName moves the DU to another node: a new pod there, the old one gone.

Remove a Cell​

kubectl delete nrcell nr-n78-b210-node1 -n racora-system

The DU Deployment and ConfigMap (and a zmq DU's Service) go with it, its identity is freed for the next cell, and the CU-CP's configuration is regenerated without it. Deleting the last cell dissolves the CU plane back to 0/0.

Virtual Cells​

For a pipeline or a lab without radios, radioBackend.ruType: dummy runs a DU with no radio (what the example cell uses), and ruType: zmq exchanges IQ samples with a UE simulator over ZeroMQ. Both schedule on any node; neither needs rf-ready. Their fields are in Connect a Radio.

When It Does Not Come Up​

Every symptom, its cause and its fix: Troubleshoot. The conditions the controller sets are listed in NRCell Status and Conditions.