Skip to content

Control xApps

xApps that act on the RAN — they issue RC control to steer UEs or gate gNB-initiated decisions. Both center on handover, exercising two RC control patterns: KPM-driven CONTROL and INSERT gating.

ho-trigger

Intelligent KPM-driven handover trigger. Python.

  • SMs: E2SM-KPM Style 4 (per-UE throughput) + Style 1 (cell-level PRB), with an S-NSSAI SST condition; E2SM-RC CONTROL Style 3 / Action 1 for the handover.
  • What it does: tracks per-UE KPM measurements over a sliding history window and cell PRB utilisation. A pure decision engine (ho_policy.py) fires when min_thp_dl_kbps is breached for consecutive_reports, gated by prb_usage_pct, with per-UE and global cooldowns to prevent ping-pong. On a positive decision it sends an RC CONTROL to the configured target cell, records the handover for cooldown, and stops once max_handovers is reached.
  • Config: xapp.kpm.{report_period_ms, granularity_ms, snssai_sst}, xapp.target.{plmn, nr_cell_id}, xapp.thresholds.{min_thp_dl_kbps (1000), consecutive_reports (3), prb_usage_pct (80)}, xapp.cooldown.{per_ue_seconds (30), global_min_interval_s (2.0)}, xapp.history_window (10), xapp.max_handovers (0 = unlimited).

Trigger immediately

Set min_thp_dl_kbps: 0 to fire on the first indication — the simplest way to end-to-end test the KPM → decision → RC CONTROL path against a live UE.

The modular structure (config.py, kpm_monitor.py, ho_policy.py, ho_executor.py, ue_state.py) makes it a good template for any "measure → decide → control" xApp.

ho-cell-block

A handover gate that blocks or redirects handovers targeting a configured cell. Ships in Python and C — the C variant is the canonical RC INSERT wire exerciser; the Python variant adds telemetry and a periodic UE snapshot.

  • SM: E2SM-RC INSERT Style 3 / Action 1 (Handover Control) with a target-cell filter; answers with an RC CONTROL echoing the Call Process ID. The Python variant additionally issues RC QUERY Style 2 for connected-UE snapshots.
  • What it does: subscribes to RC INSERT filtered on target_cell_id. On each matching INSERT it decodes the handover context (header fmt2, message fmt5, call-process-id fmt1) and replies with a CONTROL: decision=reject in block mode, or decision=accept with the redirect target packed into the NR CGI in redirect mode. The agent enforces the verdict — the gNB's handover is dropped, allowed, or steered to a different cell. The Python variant publishes ho_decision and ue_snapshot records to the sinks.
  • Config: xapp.ho_cell_block.{target_cell_id, plmn, target_nr_cell_id, amf_region_id, amf_set_id, amf_pointer, redirect_to_cell_id, ue_query_interval_ms (5000)}; Redis + InfluxDB sinks on by default.

The reference implementation for the RC INSERT drop / accept / manipulate loop — see the E2SM-RC INSERT guide.