Skip to content

M5 — CU + coordinated scheduling (tools/ran-controller/) #259

Closed

Description

@josephnef

Part of the 5G-NR RAN EPIC #254. Phase B.

Goal: a CU owns the facility-wide slot map and coordinates cell-edge resources — the disaggregated-RAN control plane over the F1 backhaul.

5G mapping (terminology corrected from the review)

CU / DU split (the CU half); F1 interface = the DU↔CU control link (Xn is inter-gNB — used here for any direct DU↔DU coordination); coordinated scheduling / dynamic-TDD alignment (5G ICIC successor). This is an NR-inspired centralized facility scheduler, not a faithful 3GPP CU (it owns scheduling, not PDCP/RRC).

Deliverables (tools/ran-controller/ — the CU app; never touches the radio)

  • tools/ran-controller/ — collects per-DU UeRegistry + link quality over the F1 socket (UDP/gRPC over LAN), pushes per-DU grant maps back.
  • coordination planner — for an edge UE heard by two DUs, allocate disjoint time slots (cheapest, tight-sync tier only) or different channels via FastRetune (slots ≫ retune time); a coarse-sync (USB) DU is restricted to frequency separation, not same-channel time slots (M4 tiers).
  • each DU exposes a local F1 control socket (accepts a pushed grant map; publishes registry + link quality).
  • control-plane failure model (from the review) — a late CU update must never alter a frame already in progress. Grant distribution carries: a monotonically increasing schedule epoch/version, an effective_at network-frame number, a minimum control-plane lead time, DU acknowledgement of a staged schedule, stale-update rejection, and autonomous DU fallback on CU/backhaul outage.

Reuses

M1 grant map, FastRetune, SetCcaMode, M4's synced TSF (so a CU-assigned slot index means the same instant at every DU).

Dependencies

M4 (#254 tracks) — coordination is meaningless without a shared clock.

Test — tests/ran_coord.sh

An edge UE hearing both DUs: uncoordinated → collisions on the shared airtime; enable the CU coordination planner → the edge UE's airtime goes clean. Headless selftest: the planner's slot/channel-assignment logic in the selftests aggregate.

Status (2026-11-05)

  • Done: cell M5 core: coordination planner + F1 control link (failure model) #525 (src/cell/Coord.h planner, src/cell/F1.h messages and the DU Stager) and cell M5: F1 DU link, ran-controller CU, rig coordination test #526 (the DU F1 link in examples/cell, tools/ran-controller, the multi-cell witness, tests/ran_coord_analyze.py). Details in docs/cell-m5.md.
  • Control-plane failure model: monotone versions, effective_net_sf (one network-wide instant from the PTP clock), a minimum lead time, DU acks, stale and replay rejection (authenticated freshness seq), abandonment instead of an off-instant apply, and autonomous DU fallback on CU outage.
  • Rig (testrig scripts/m5_ran_coord.sh): two co-channel PTP-locked DUs and one UE each, with the CU on n300-1. At a stagger where cell 2's DL airs on cell 1's UE uplink:
    • baseline (the CU keeps default positions): cell 1 UL 62.6 %, 361 DL retx;
    • coordinated: 100 %, 0 retx, both DUs on one instant;
    • CU outage: the DUs go autonomous within 3 s and re-apply on one instant when a new CU appears.
  • Planner deliverable (partly done, left unchecked): disjoint time slots are applied, and the tier rule (a coarse DU gets frequency separation only) is implemented and selftested. Channel separation via FastRetune is proposed and logged, not applied at runtime. A running cell and its UEs moving channel is open, and there is no USB coarse-tier DU on the rig.

Activity

  1. josephnef commented on Nov 12, 2026

    @josephnef
    CollaboratorAuthor

    Rescoped to the PCIe tier, as agreed. The coarse-tier (USB) part, a coarse DU getting frequency separation on air, moves to #565.

    Done and verified on the rig: tools/ran-controller (#526), the disjoint-slot planner (src/cell/Coord.h, #525; edge UE 62.6 % → 100 % with 0 retx), per-DU F1 sockets, the control-plane failure model (CU outage → autonomous, then a shared instant on the new CU), and the planner selftest (ctest cell_m5). The handover test lives in testrig (m5_ran_coord.sh + tests/ran_coord_analyze.py), not tests/ran_coord.sh.

    One PCIe item keeps this open: channel separation applied at runtime. The planner computes the spare channel, but the CU only logs it (ran.retune); no running DU, nor its UEs, moves channel with FastRetune.

  2. josephnef commented on Nov 12, 2026

    @josephnef
    CollaboratorAuthor

    Closing on the PCIe tier, as agreed. The last item, applying channel separation at runtime, is in: #567 (7faeb67).

    • The CU moves the planner's DU (RAN_RETUNE_APPLY=1, F1 v15 ChannelSwitch).
    • The DU announces the move in its beacon, and it and its UEs retune together in the idle part of the superframe.
    • Only an announced move is made. The outcome is acked (Applied/Invalid). A DU that can't make it refuses, and is backed off.

    Rig (testrig m5_retune.sh, cell 2's DL on UE1's uplink):

    • moved; 0–1 uplinks and 0 DL frames lost across the switch, uplinks in slot from the first superframe on 157;
    • the on-air cross-cell overlaps stop (baseline 68–80).

    At this rig's levels the overlap cost UE1 only a few uplinks, so the gain shown is the conflict removed.

    The coarse-tier (USB) rule moves to #565.

  3. josephnef commented on Nov 12, 2026

    @josephnef
    CollaboratorAuthor

    Note for the record: the M6 regression ran alongside this. On 2026-11-12 the rig's RF levels changed with no code change in between, and the M6 suites built on a standing handover margin stopped finding one; an A/B on master failed the same way. The cause is not established. Those suites are being made placement-independent: the UE's measured level per cell is pinned to each suite's design levels (CELL_UE_MEAS_LEVEL). With that, all eight M6 suites pass on the changed rig. PR to follow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions