Skip to content

End-to-End Network Slicing

End-to-End Network Slicing

A complete, open-source 5G network-slicing stack built around OCUDU: multi-UE OAI orchestration with independent S-NSSAIs, slice-aware DU scheduling and CU admission/mobility, a multi-slice Magma 5G Core, and standard O-RAN O1 management through an SMO, wired together so the whole slice lifecycle can be validated end to end.

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.

End-to-end network slicing ecosystem. Top row: ONAP SMO (RESTCONF/NETCONF, VES, PM) and Near-RT/Non-RT RIC. Middle: the OCUDU O1 Adapter bridging into the OCUDU DU and CU, which carry four active slices (eMBB, eMBB capped at 50%, mMTC, and a locked/URLLC slice). Left: the OAI multi-UE environment with a ZMQ proxy and per-UE network namespaces. Right: the Magma 5G Core with per-slice user-plane sessions (sessiond and pipelined) toward the data network.
The complete TOSSI network slicing ecosystem: OAI multi-UE → OCUDU RAN (CU/DU, slice-aware) → Magma 5G Core, all managed and monitored by an ONAP SMO through the OCUDU O1 Adapter. The Magma user plane is per-slice: sessiond for session management and pipelined for the data path.

Source code. The stack spans three repositories:

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 pipelined data 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.

The OCUDU UE-SIM dashboard on the Configure tab: a Running UEs table with one row per UE (UE1 to UE8), each column showing SST, SD, DNN, CELL, and the resulting slice; a Health panel for the selected UE; and a Launch bar with the plan and key bindings.
The Configure tab: each UE row carries its own SST / SD / DNN / Cell, setting that UE's slice before launch.

1.3 Per-UE isolation and slice IP mapping

Each UE runs in netns ue1ueN 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 subnetMagma session / data path
sst=1, sd=110.0.0.0/24sessiond / pipelined (sd1)
sst=1, sd=210.0.2.0/24sessiond / pipelined (sd2)
sst=1, sd=310.0.3.0/24sessiond / pipelined (sd3)
sst=1, sd=410.0.4.0/24sessiond / 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:

FeatureBehaviour
Administrative lockA slice with administrative_state: LOCKED is skipped before any candidate is generated → zero PRBs.
Max capThe slice's PRB ceiling is floor(max% × PRBs); it can never be exceeded, even on an idle cell.
Min floor + dedicated reserveA slice below its min gets a high-priority candidate first; dedicated PRBs are reserved even when the slice is idle.
Independent UL/DLDownlink and uplink limits are computed separately, so a slice can guarantee different UL vs DL shares.
Per-slice metricsEach 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 cause slice_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 ho console 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 serviceRolePer-slice?
sessiondsession management (the SMF role): sets up and tears down the per-slice user session
pipelineduser-plane data path (the UPF role): OVS pipeline, per-slice IP pools, N6 toward the DN
mobilitydIP address allocation and mobility state per session
subscriberdbsubscriber database (authentication, profiles)
PolicyDpolicy and QoS rules applied to sessions
MME / SCTPDcontrol-plane signalling and SCTP transport toward the RAN
directoryd / magmad / monitordservice 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.

The Magma NMS dashboard, Traffic to APNs page, showing the per-slice APNs internet, oai, oai2, oai3 and oai4. Each row lists the APN ID, class ID, priority level, maximum required uplink and downlink bandwidth, and pre-emption capability and vulnerability. An APN saved successfully confirmation is shown.
Slices are added and configured in the Magma Core from the Magma NMS dashboard: each slice is an APN under Traffic → APNs, carrying its own QoS profile (class ID, priority, and max UL/DL bandwidth).

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 changedWS command
ssb_block_power_dbmssb_set
RRMPolicyRatiorrm_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, dedicated is ignored there, so the slice-assurance knob is min (guaranteed share) or max (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.

Closed-loop slice assurance. The OCUDU RAN emits per-UE metrics tagged by S-NSSAI; the O1 Adapter PM path aggregates them per slice and POSTs a PM envelope (DN keys plus DL/UL kbps). An rApp detects that a premium slice is contended and issues a RESTCONF PATCH raising that slice’s minimum RRM ratio. SDNR turns the PATCH into a NETCONF edit-config on the datastore; the adapter config path sees the diff and sends one rrm_policy_ratio_set per slice back down to the gNB.
The closed loop: PM (up) → rApp decision → CM (down) → gNB applies the new per-slice min/max, slice-scoped at every hop.

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:

DemoSetupWhat you see
CU/DU admissionUE on sd1 vs UE on sd3 (sd3 unconfigured)sd1 reaches DATA; sd3 stuck REGISTERED with no IP / refused DRB
Administrative locksd4 = LOCKEDUE gets an IP but 0 Mbps / ping fails; unlocked slices carry data
Max capsd2 max 50% on a 106-PRB cellslice panel shows sd2 max_prbs = 53, never exceeded
Slice-aware mobilityneighbour cell supports sd1/sd2 onlyh on a sd1 UE → handover allowed; on a sd4 UE → suppressed
Closed looppremium slice contended, rApp activerApp raises the slice's min ratio live; throughput recovers, no restart

9. Source Repositories

ComponentRepository
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