End-to-End Network Slicing
End-to-End Network Slicing
Network slicing lets one physical 5G network carry multiple logical networks (eMBB, URLLC, mMTC), each with its own performance treatment. Most demonstrations validate slicing inside a single component, usually the scheduler. This stack validates it across the entire network: the UE requests a slice, the RAN enforces per-slice radio policy and admission, the Magma Core selects a per-slice session (sessiond) and data path (pipelined), and the SMO monitors and re-tunes each slice live over standard O-RAN interfaces.
A slice is one S-NSSAI (SST + SD) end to end. Throughout this stack SST = 1 for all slices and SD = 1..4 distinguishes the four slices.
sessiond for session management and pipelined for the data path.Source code. The stack spans three repositories:
- OCUDU RAN (CU/DU + slicing): github.com/TOSSI-Foundation/OCUDU-RAN
- OAI UE (multi-UE slicing harness): github.com/TOSSI-Foundation/OAI-RAN
- O1 Adapter (SMO bridge): github.com/TOSSI-Foundation/OCUDU-O1-Adaptor
Overview
True slice validation requires coordination across every layer of the network. This stack integrates all of them:
- User Equipment (UE): multiple OAI software UEs, each on its own S-NSSAI.
- Radio Access Network (RAN): OCUDU CU/DU with per-slice radio resource management, admission, and mobility.
- Magma 5G Core: a multi-slice deployment with one session (
sessiond) and one data path (pipelined) per slice. - Service Management & Orchestration (SMO): ONAP SDNR mounting the gNB over NETCONF, driving live slice config.
- O-RAN RICs: Near-RT and Non-RT RICs hosting rApps for closed-loop slice assurance.
Two architectural "splits" structure the gNB and decide where each slicing function lives:
- F1 splits the DU from the CU. The per-slice radio-resource logic lives in the DU MAC scheduler.
- E1 splits CU-CP from CU-UP. Slice admission and mobility decisions live in the CU-CP; the per-slice user plane runs CU-UP ↔ per-slice Magma
pipelineddata paths.
1. OAI Multi-UE Environment
Each UE is a full software 5G NR UE (nr-uesoftmodem: PHY + MAC/RLC/PDCP + RRC + NAS), one process per UE, each isolated in its own Linux network namespace. There is no real RF: the oai_zmqdevif radio plugin carries IQ samples over ZMQ to a proxy that emulates the shared air interface.
For realistic slicing experiments the OAI UE environment was extended well beyond a single connected UE:
- Multi-UE orchestration: launch and manage many UEs simultaneously from one place.
- Multi-slice support: each UE carries its own independent S-NSSAI (
SD_LIST,SST_LIST,DNN_LIST). - Traffic generation: per-UE idle / speedtest / video / gaming profiles keep bearers alive and create measurable per-slice load.
- Unified dashboard: a Rust/ratatui TUI to configure, launch, monitor, and drive handovers.
- Per-UE network namespaces: each UE gets its own
netns+ veth + NAT, so flows are isolated and independently measurable.
1.1 ZMQ proxy: single-thread slot-lockstep bridge
The gNB makes roughly 30 uplink requests per downlink frame. A naïve two-thread proxy lets DL and UL drift, the UE's slot counter diverges, PRACH lands in the wrong slot (z_corr = 0), no RAR arrives, and attach fails. The proxy is therefore a single event loop driven by the gNB's UL request rate, with DL serviced non-blocking inside the same loop. It also:
- Mixes all UEs' UL into one stream per slot and fans the gNB DL out to each UE.
- Applies DL backpressure so samples are never dropped (a single lost sample breaks PBCH decode permanently).
- Keeps exactly one poll request in flight per UE (an
ue_ul_waiting[]state machine) to avoid stale-sample skew. - Supports staged "wave" admission and per-UE / per-cell gain files for handover routing.
1.2 Launchers, traffic engine, and dashboard
The multi-UE launchers (run_nue.sh, run_eight_slice_ue.sh) create the netns + veth + NAT per UE, launch each UE with the right ZMQ ports and its own S-NSSAI, pin UEs and proxy to isolated cores, and tear everything down on --stop. run_eight_slice_ue.sh brings up 8 UEs (2 per slice) in one shot. The per-UE traffic engine (traffic/ue_traffic.py) generates the per-slice load.
The Rust/ratatui dashboard has three pages:
- Monitor: a live per-UE table (slice, cell, IP, attach stage, DL/UL Mbps, RTT) plus per-slice PRB metrics parsed straight from the DU log (min/max/dedicated PRBs, avg RBs/slot, utilisation, the G1 output).
- Configure: compose a plan table where each UE row has its own SST / SD / DNN / Cell, then launch (r) or stop (k) all UEs without touching the shell.
- Advanced (handover): launch the CU with a FIFO console (c), auto-detect the UE RNTI (R), pick UE and target cell, and fire
ho <pci> <rnti> <target_pci>(h); live CU and DU log panes show the handover decision and radio arrival.
From the dashboard you can configure the slice per UE in the Configure tab, test handover from the Advanced tab, and monitor the status of all UEs from the Monitor tab.
1.3 Per-UE isolation and slice IP mapping
Each UE runs in netns ue1…ueN with a veth pair + iptables NAT. On PDU-session success, oaitun_ue1 receives a 5GC IP whose subnet reveals the slice:
| Slice (S-NSSAI) | UE tunnel subnet | Magma session / data path |
|---|---|---|
| sst=1, sd=1 | 10.0.0.0/24 | sessiond / pipelined (sd1) |
| sst=1, sd=2 | 10.0.2.0/24 | sessiond / pipelined (sd2) |
| sst=1, sd=3 | 10.0.3.0/24 | sessiond / pipelined (sd3) |
| sst=1, sd=4 | 10.0.4.0/24 | sessiond / pipelined (sd4) |
2. OCUDU O-DU: Slice-Aware Scheduling
The DU (odu) is a monolithic L1+L2 node, split from the CU over F1, with a ZMQ radio toward the proxy. DU-low is the upper/lower PHY + ZMQ RU; the MAC talks to it via FAPI. DU-high holds F1AP (DU side), the DU manager, RLC, and the MAC + scheduler: where slicing happens.
2.1 The inter-slice scheduler
Every slot, the inter-slice scheduler partitions the cell's PRBs across the configured slices using 3GPP TS 28.541 RRMPolicyRatio (the rule dedicated ≤ min ≤ max, applied per direction). For a 40 MHz cell that is 106 PRBs. The slicing features map onto the scheduler as follows:
| Feature | Behaviour |
|---|---|
| Administrative lock | A slice with administrative_state: LOCKED is skipped before any candidate is generated → zero PRBs. |
| Max cap | The slice's PRB ceiling is floor(max% × PRBs); it can never be exceeded, even on an idle cell. |
| Min floor + dedicated reserve | A slice below its min gets a high-priority candidate first; dedicated PRBs are reserved even when the slice is idle. |
| Independent UL/DL | Downlink and uplink limits are computed separately, so a slice can guarantee different UL vs DL shares. |
| Per-slice metrics | Each slice instance accumulates PDSCH/PUSCH RB sums; a snapshot is collected on the report boundary and logged per S-NSSAI. |
2.2 DU admission control
With strict_slice_admission: true, a DRB whose S-NSSAI is not in the configured slice list is refused at the DU, with a log line like Refused DRB1 on unauthorised slice (sst=1 sd=0x3). The Magma Core may still have a sessiond/pipelined path for that slice, the RAN simply won't carry it. At startup the DU also validates ded ≤ min ≤ max per slice and Σmin ≤ 100 for both directions.
2.3 DU slicing config
strict_slice_admission: true # refuse DRBs for unconfigured slices
slicing:
- sst: 1, sd: 1 # eMBB - independent UL/DL, dedicated reserve
min/max/ded = 40/100/20 DL, 25/80/10 UL, UNLOCKED
- sst: 1, sd: 2 # capped at 50%
min/max/ded = 20/50/15, UNLOCKED
- sst: 1, sd: 4 # mMTC - admin-lock demo
min/max/ded = 20/60/10, LOCKED
# sd3 deliberately OMITTED → DU admission rejects it
3. OCUDU O-CU: Slice Admission & Mobility
The CU is split into CU-CP and CU-UP over E1.
3.1 CU-CP: NGAP admission and slice-aware mobility
- NGAP slice admission. The CU-CP rejects a PDU session whose S-NSSAI is not in the node's
tai_slice_support_list, with causeslice_not_supported. The supported list is threaded through the session-setup procedure into the validator. - Slice-aware mobility. On a handover the CU checks whether the target cell can serve all of the UE's active slices before proceeding (TS 23.501 §5.15.2):
- Collect the S-NSSAIs of the UE's active DRBs.
- Look up the target cell's
supported_slices(from the cell-meas config) and match: SST must match; a wildcard SD on the cell covers any UE SD; an empty cell list means "no restriction." - This veto is wired into every mobility path, measurement-triggered, conditional handover (per-candidate filter), and the forced
hoconsole path. A vetoed handover is suppressed and counted.
On a successful handover the CU propagates the real S-NSSAI to the target DU over F1 (the UE Context Setup carries e.g. sst=1/sd=1 instead of the default wildcard), so the target DU can apply per-slice policy after handover.
3.2 CU-UP: per-slice user plane
The CU-UP runs SDAP (QoS-flow → DRB mapping), PDCP, and GTP-U on two interfaces: F1-U toward the DU and N3 toward the per-slice Magma pipelined data paths.
3.3 CU slicing config
amf.supported_tracking_areas[].tai_slice_support_list, the slices this node advertises on NGAP (sd1–sd4).mobility.cells[].supported_slices, which S-NSSAIs each cell can serve. In the demo the serving cell supports all four slices while a neighbour supports only a subset, so a UE on an unsupported slice is vetoed at handover.
4. Multi-Slice Magma Core
The stack integrates Magma Core as the production-oriented, open-source 5G core, validating both control-plane and user-plane functions. Magma uses its own service-oriented decomposition rather than the textbook SBA NFs: session management is handled by sessiond (the SMF role) and the user-plane data path by pipelined (the UPF role). The slicing demo runs one sessiond session and one pipelined data path per slice.
| Magma service | Role | Per-slice? |
|---|---|---|
sessiond | session management (the SMF role): sets up and tears down the per-slice user session | ✅ |
pipelined | user-plane data path (the UPF role): OVS pipeline, per-slice IP pools, N6 toward the DN | ✅ |
mobilityd | IP address allocation and mobility state per session | – |
subscriberdb | subscriber database (authentication, profiles) | – |
PolicyD | policy and QoS rules applied to sessions | – |
| MME / SCTPD | control-plane signalling and SCTP transport toward the RAN | – |
directoryd / magmad / monitord | service directory, orchestration agent, and health monitoring | – |
Slice selection flow. The UE requests a session with an S-NSSAI → Magma's control plane authenticates the subscriber (subscriberdb) and selects the per-slice sessiond session → sessiond programs the matching pipelined data path and (via mobilityd) allocates the UE IP from that slice's pool → the session is brought up so the gNB can carry the slice's user plane to the DN over N6.
4.1 Configuring slices in the Magma dashboard
Slices are added and configured directly in the Magma Core through the Magma NMS dashboard. Each slice is provisioned as its own APN under Traffic → APNs, with a per-slice QoS profile (class ID, priority level, and maximum required uplink/downlink bandwidth). In the demo the four slices map to the APNs oai, oai2, oai3, and oai4 (alongside the default internet APN), and the same S-NSSAI bound to each APN is what the RAN scheduler and the O1 management plane act on downstream.
5. O1 Adapter & SMO
The OCUDU O1 Adapter is the bridge between the gNB and the SMO (ONAP SDNR). It exposes the gNB as a standard 3GPP-NRM NETCONF node so the SMO can configure and monitor slices over standard O-RAN management interfaces, with no service restarts for runtime changes.
Two roles the adapter bridges:
- Southbound to the gNB: a JSON WebSocket control/metrics channel (the gNB remote-control service on
:8001). The adapter is the WS client. - Northbound model: a NETCONF datastore holding the 3GPP NRM (ManagedElement / GNBxFunction / NRCellDU / RRMPolicyRatio / PerfMetricJob …). The adapter is the NETCONF client and reacts to datastore changes. The SMO (SDNR) writes that datastore over RESTCONF.
Net effect: config flows down (SMO → datastore → adapter → gNB) and telemetry flows up (gNB → adapter → SMO), with the NETCONF datastore as the shared model in the middle.
5.1 Configuration Management: the down path
On every datastore change notification the adapter GETs the running config, diffs it against the last known config, and classifies the change:
- Runtime-updatable parameters,
ssb_block_power_dbm,RRMPolicyRatio,PerfMetricJob, are applied live via a WebSocket command, with no restart. - Anything else triggers a full config re-render and a DU restart (the adapter runs as a sidecar and signals restart over a small REST interface).
Runtime deltas map to gNB WebSocket commands:
| Datastore object changed | WS command |
|---|---|
ssb_block_power_dbm | ssb_set |
RRMPolicyRatio | rrm_policy_ratio_set (one per slice) |
PerfMetricJob (newly active) | metrics_subscribe |
Multi-slice RRMPolicyRatio (the key extension). The adapter extracts a list of per-slice policy dicts, one per RRMPolicyRatio, and sends one rrm_policy_ratio_set command per slice, because the gNB parses one policy per command and merges each policy into the matching slice by S-NSSAI. Slices not named in a command are left untouched (so every slice must already exist in the gNB's slicing config). Each rendered policy carries the PLMN, sst/sd member list, and min / max / dedicated ratios.
3GPP rule.
dedicated ≤ min ≤ max(TS 28.541). At runtime the gNB applies min/max only over the WS path,dedicatedis ignored there, so the slice-assurance knob ismin(guaranteed share) ormax(cap).
5.2 Performance Management: the up path (per-slice)
A PerfMetricJob is active when its administrativeState is UNLOCKED and it has a streamTarget. For each active job the adapter consumes gNB metrics off the WebSocket, aggregates them per UE by S-NSSAI into {(sst, sd): {dl_kbps, ul_kbps, nof_ues}}, and POSTs one PM envelope per (sst, sd) to the job's stream target (e.g. the rApp's :8080/pm). This requires the gNB to tag each UE's metrics with its S-NSSAI, the per-slice metric tagging done in the RAN.
The envelope carries the 3GPP Distinguished Name components of the cell (meId / gnbduId / nrCellDuId) alongside sst/sd and the DL/UL throughput. This is the key design point: the rApp uses those DN keys to address the exact RRMPolicyRatio object back over RESTCONF, …/ManagedElement=<meId>/GNBDUFunction=<gnbduId>/NRCellDU=<nrCellDuId>/RRMPolicyRatio=…, without a discovery GET or hardcoding, closing the loop from a PM reading straight to the writable CM object.
5.3 Fault Management: VES
An alarm manager maintains a 3GPP/O-RAN alarm registry and per-instance state machine. On a severity transition it POSTs to the VES collector (/eventListener/v7): PNF plug-and-play registration, fault (alarm) events, and admin/operational state-change events. VES events land in the SMO's DCAE / fault handling.
6. Closed-Loop Slice Assurance
Putting the up path and down path together yields a fully automated, slice-scoped control loop. Per-UE metrics flow up from the RAN, an rApp decides whether a premium slice is contended, and a single targeted RRM change flows back down, all addressed by the DN keys carried in the PM envelope, and all without a service restart.
Per-slice everywhere: the PM envelope is slice-scoped, the rApp acts on only the premium slice (others skipped), and the adapter sends one command per slice, so the gNB's merge-by-S-NSSAI leaves the non-targeted slices untouched.
7. End-to-End Call Flow
1. UE powers on → SSB sync → MIB/SIB1 → PRACH (Msg1-4) over ZMQ via the proxy.
2. RRC: RRCSetup → SecurityModeCommand → capabilities.
3. NAS Registration to the AMF (N2/NGAP).
4. NAS PDU Session Establishment (S-NSSAI sst=1/sd=N, DNN=oai):
- CU-CP admission: is sd=N in tai_slice_support_list? no → slice_not_supported.
- Magma Core (sd=N): sessiond_N brings up the per-slice session, pipelined_N
programs the data path, mobilityd assigns an IP from that slice's pool.
5. CU sends N2 PDU Session Resource Setup → CU-CP drives F1 UE Context Setup/Mod to the DU.
- DU admission: is sd=N in the DU slicing list? no → refuse the DRB.
6. DU MAC scheduler applies the slice's RRMPolicyRatio; LOCKED → 0 PRBs.
7. User plane: pipelined_N ──N3 GTP-U──► CU-UP (SDAP/PDCP) ──F1-U GTP-U──► DU (RLC/MAC, slice-aware)
──► PHY ──► ZMQ ──► proxy ──► UE (oaitun_ue1 gets 10.0.<slice>.x).
8. Mobility: on a handover the CU-CP vetoes any target cell that cannot serve the
UE's active slices; on success it propagates the S-NSSAI to the target DU over F1.
8. The Slice Lifecycle You Can Validate
Within this single stack you can exercise every stage of the network slice lifecycle:
- Slice creation and configuration
- UE attachment to multiple S-NSSAIs
- Traffic generation across multiple slices
- Admission control validation (DU and CU)
- Radio resource allocation (min / max / dedicated, UL/DL independent)
- Slice isolation analysis
- Core network slice selection
- O1-based management and monitoring
- Per-slice telemetry collection
- Automation and rApp development
Some end-to-end demonstrations and what they show:
| Demo | Setup | What you see |
|---|---|---|
| CU/DU admission | UE on sd1 vs UE on sd3 (sd3 unconfigured) | sd1 reaches DATA; sd3 stuck REGISTERED with no IP / refused DRB |
| Administrative lock | sd4 = LOCKED | UE gets an IP but 0 Mbps / ping fails; unlocked slices carry data |
| Max cap | sd2 max 50% on a 106-PRB cell | slice panel shows sd2 max_prbs = 53, never exceeded |
| Slice-aware mobility | neighbour cell supports sd1/sd2 only | h on a sd1 UE → handover allowed; on a sd4 UE → suppressed |
| Closed loop | premium slice contended, rApp active | rApp raises the slice's min ratio live; throughput recovers, no restart |
9. Source Repositories
| Component | Repository |
|---|---|
| OCUDU RAN (CU/DU + slicing changeset) | TOSSI-Foundation/OCUDU-RAN |
| OAI UE (multi-UE slicing harness, proxy, dashboard) | TOSSI-Foundation/OAI-RAN |
| O1 Adapter (SMO / NETCONF bridge) | TOSSI-Foundation/OCUDU-O1-Adaptor |