Introduction - Anuka Hettiarachchi - GSoC2026

52 views
Skip to first unread message

Anuka Hettiarachchi

unread,
Jun 16, 2026, 2:35:59 PMJun 16
to ns-developers

Dear all,

I am Anuka Hettiarachchi, a final-year undergraduate student pursuing a BSc. Hons. degree in Computer Science at the Faculty of Science, University of Peradeniya, Sri Lanka.

For GSoC 2026, I am working on the project Integrating 5G NR module with ns-3-ai. The primary objective of this work is to implement a high-performance, zero-serialization bridge between the 5G-LENA NR MAC scheduler and Python-based ML frameworks via the ns-3-ai Message Interface. This implementation aims to minimize communication latency, support rich observation spaces, and enable framework-independent ML integration for radio resource management.

Further details regarding the project scope, objectives, and ongoing progress reports are available on my project WIKI page.

I look forward to collaborating with the community, receiving feedback on my implementation strategy, and contributing effectively to the ns-3 ecosystem.

Best regards,

Anuka Hettiarachchi

Anuka Hettiarachchi

unread,
Jun 18, 2026, 4:36:50 PMJun 18
to ns-developers
Dear all,

As a first Merge Request, I have created MR!387, which lays the groundwork for connecting the 5G NR MAC scheduler to a Python agent through the ns3-ai Message Interface. It contains two related, self-contained pieces. The Observation/Action structs,  and an opt-in RRC change that makes per-bearer uplink buffer information available to those observations. 

1. Observation and Action structs
A new header, defines three plain-old-data structs placed byte-for-byte in shared memory (ns3-ai vector-based interface, one element per UE).
  • NrSchedulerObservation (C++ -> Python) - per-UE observation, wide band CQI, historical average throughput, instantaneous achievable throughput, bytes assigned in the previous allocation (feedback), RNTI, and an array of up to 4 per-bearer entries.
  • NrSchedulerLcObservation - per-bearer (logical channel) QoS - HOL delay, 5QI delay budget, LC id, 5QI, priority, resource type (non-GBR/GBR/DC-GBR), and buffer size (BSR).
  • NrSchedulerAction (Python -> C++) - the agent's per-UE scheduling weight, matched to UE's by RNTI.
Key design decisions:
  • Per-UE, not per-flow. The vector length is dynamic, so there is no fixed maximum UE count.
  • Only the per-UE bearer list is bounded(MAX_LCS_PER_UE = 4) and the agent emits one weight per UE, since the NR scheduler allocates resources per UE - distributing the transport block among a UE's bearers stays the job of the configured LC algorithm.
  • Bearers are reported most-urgent-first , so the agent sees the QoS-relevant bearers even when a UE has more than 4.
The layout is a binary contract with the future pybind11 bindings, so the MR adds a test suite (nr-mac-scheduler-ai-msg-structs-test-suite.cc) verifying every field offset, size,  the overall struct size, and copyability. All fields are fully Doxygen-documented.

2. Opt-in per-bearer UL LCG mapping (nr-gnb-rrc)
On the uplink, only the static QoS fields and the per-LCG Buffer Status Report are meaningful, and the stock LCG mapping lumps all GBR (or all non-GBR) bearers into a single group,  so the BSR cannot report per-bearer buffer sizes. To make the per-bearer UL observations possible, I added a new boolean RRC attribute PerBearerUlLcg.
  • When enabled, NrGnbRrc::GetLogicalChannelGroupPerBearer() maps each data radio bearer to its own LCG (1..3, with LCG 0 reserved for SRBs) so the UL BSR carries per-bearer buffer sizes.
  • It is opt-in, therefore, the stock GetLogicalChannelGroup() mapping is left untouched, so default behaviour is unchanged for everyone not using the AI scheduler 
I would very much appreciate feedback on the field set, the per-UE design, and the per-bearer LCG approach before I wire these into the scheduler in the next MR.

Regards,
Anuka

Anuka Hettiarachchi

unread,
Jun 30, 2026, 2:46:23 PMJun 30
to ns-developers
Hi all,

Following up on my earlier post and the foundational work in MR !387, I've now opened the second merge request for this GSoC project.

MR !395 - Runtime AI scheduling decisions over the ns3-ai Message Interface

Where MR !387 introduced the shared-memory observation/action structs and the opt-in per-bearer UL LCG support, this MR wires them into the live scheduling loop so a Python agent can actually drive scheduling decisions at runtime. The main additions are:

1. Per-iteration scheduler state callback - a new NotifyCbMsg callback that hands the bridge the active-UE vector, so the agent sees the complete per-UE scheduler state on each assignment iteration.
2. TDMA & OFDMA AI scheduler integration - both variants now expose the message-interface callback via new attributes (NotifyCbDlMsg / NotifyCbUlMsg) and setter methods, keeping the AI path entirely opt-in.
3. Shared-memory environment - NrMacSchedulerAiNs3MsgInterfaceEnv exchanges observations and AI decisions over shared memory, packaging per-UE metrics (CQI, throughput, TB size) and ordering logical channels by urgency.

I'd really appreciate feedback on the callback design and on how the per-UE/per-LC state is laid out for the agent before I move on to the end-to-end example and the training loop.

Regards,
Anuka Hettiarachchi
University of Peradeniya

Anuka Hettiarachchi

unread,
Jul 11, 2026, 12:48:56 PMJul 11
to ns-developers

Hi all,

Following up on MR !395, I've opened the next merge request for this GSoC project.

MR !407 - Python bindings for the ns3-ai message-interface scheduler bridge

Where MR !387 introduced the shared-memory observation/action structs and MR !395 wired them into the live scheduling loop, this MR adds the Python-side access layer - a pybind11 module through which any agent can read scheduler observations and write scheduling weights over shared memory. I've deliberately kept it bindings-only since the end-to-end example scenario (C++ simulation and Agent) will follow in the next MR, so that the Python APIs can be reviewed on its own. The main additions are:

1. ns3ai_nr_sched_py pybind11 module - mirrors the observation/action structs field-for-field (per-UE CQI, throughput, TB size, plus the urgency-ordered per-bearer QoS array) and exposes the vector-mode Ns3AiMsgInterfaceImpl handshake, so observations and actions cross the C++/Python boundary with no serialisation.
2. CMake integration - the module builds only when the ai module is enabled, and is placed next to its sources so it is directly importable by the agent.
3. Binding tests - a stdlib-only test suite that parses the msg-structs header and fails if any field is missing from the bindings, guarding against the two sides drifting apart, plus round-trip and bounds checks. A requirements.txt has the single build-time dependency (pybind11).

I'd really appreciate feedback on the exposed Python APIs before I submit the end-to-end example that builds on it.


Regards,
Anuka Hettiarachchi
University of Peradeniya

Anuka Hettiarachchi

unread,
Jul 29, 2026, 10:29:28 AMJul 29
to ns-developers
Hi all,

Following up on MR !407, I've opened the next merge request for this GSoC project.

MR !421 - End-to-end example driving the NR scheduler over the ns3-ai message interface

This is the example scenario I held back from MR !407, and it completes the bridge: MR !387 introduced the shared-memory structs, MR !395 wired them into the live scheduling loop, MR !407 added the Python access layer, and this MR puts the whole path to work in a runnable example. It reproduces the gsoc-nr-rl-based-sched.cc scenario (GSoC 2024, Hyerin Kim) with a single change: when the scheduler algorithm is "Ai", the observation/action exchange goes through the ns3-ai shared memory instead of OpenGym (ZMQ + Protobuf).  The main additions are:

1. nr-ai-sched.cc - the scenario, binding NrMacSchedulerAiNs3MsgInterfaceEnv to the scheduler's NotifyCbDlMsg attribute. The AI path is behind HAVE_NS3_AI, so without the ai module the Qos/PF/RR baselines still build and run standalone. Knobs, seed handling and the per-flow FlowMonitor output match gsoc-nr-rl-based-sched.cc, so the two transports are comparable flow by flow.

2. nr-ai-sched.py - the driver. It creates the shared memory, launches the simulation, and answers each handshake with one weight per UE through the MR !407 bindings. It is a smoke test rather than an RL agent: the default heuristic weights each UE by its total bearer backlog, --constant weights all UEs equally, and --verbose N dumps the first N exchanges as JSON for checking the shared-memory layout.

3. CMake integration - built only when the ai module is enabled, with the example depending on the binding target so one build produces both halves. The setup documentation covers the build steps and the failure modes worth knowing about.

With this merged, the message-interface path is complete end to end and can be compared against the OpenGym baseline on identical scenarios. I'd welcome feedback on the example structure and the knobs exposed to the Python side.



Regards,
Anuka Hettiarachchi
University of Peradeniya

Reply all
Reply to author
Forward
0 new messages