SoloRAN Guide
SoloRAN takes an approved CCI xG Testbed researcher from account sign-in
through deployment of a RAN VM and a Near-RT RIC VM, component integration,
traffic generation, Python xApp execution, monitoring, recovery, and cleanup.
This guide uses the prepared transfer-ran and transfer-ric-srsran images.
SoloRAN application: https://soloran.ccixgtestbed.org
OpenStack dashboard: https://portal.ccixgtestbed.org
Source guide version: 1.0, 25 August 2026.
For general project, network, quota, and instance concepts, read the OpenStack Guide first.
Important
This SoloRAN workflow uses floating IPs so the SoloRAN server can reach the prepared VMs over SSH. The general OpenStack Guide describes ZeroTier access for users. Before deploying, ask the testbed administrator to confirm that your project supports the SoloRAN management path, floating-IP pool, and security-group rules described here.
Video Tutorial
Watch the SoloRAN user walkthrough alongside the step-by-step instructions below.
Using SoloRAN on the CCI xG Testbed
Workflow at a Glance
Authenticate → deploy RIC → deploy RAN → associate floating IPs → enter runtime addresses → start Core, RIC, gNB, and UE → validate traffic → run an xApp → observe → stop or recover → clean up.
SoloRAN provisions cloud resources, controls the runtime lifecycle, generates traffic, and executes Python xApps against a personal or approved shared Near-RT RIC.
Resource |
Prepared image |
What runs there |
|---|---|---|
RAN VM |
|
Open5GS Core, O-CUDU gNB, srsUE, UE namespace, and ping/iPerf client. |
RIC VM |
|
Dockerized O-RAN SC Near-RT RIC and |
SoloRAN server |
Managed service |
Identity/session handling, OpenStack API access, deployment, SSH orchestration, logs, and charts. |
Important
Wait for the success gate in each terminal before clicking the next control. A button click starts an asynchronous operation. Repeated clicks can create duplicate stacks or overlapping startup tasks.
Before You Start
Access and Quotas
Confirm that you have:
An approved authentik identity with access to SoloRAN.
A correctly mapped OpenStack project with enough compute, RAM, disk, port, and floating-IP quota for two instances.
Visibility of the
transfer-ranandtransfer-ric-srsranimages in your project.A tenant network and security group that let the SoloRAN management path reach SSH/TCP port
22on each VM.Internal RAN-to-RIC connectivity, including SCTP port
36421for E2. Ask the testbed administrator to confirm project security policy; avoid unnecessarily broad public ingress.
Know Your Account Path
Account type |
SoloRAN sign-in |
OpenStack connection |
Typical project |
|---|---|---|---|
Lion |
Continue with Authentik |
Established through federated sign-in; no second OpenStack password. |
|
Hummingbird |
Authenticate identity, then enter Keystone credentials. |
Keystone password validated for the current server-side session. |
|
Important
Open the profile menu immediately after sign-in. Confirm that the displayed OpenStack project belongs to you. If it is missing or unexpected, sign out and contact the administrator before deploying.
Authenticate to SoloRAN
Lion User
Click Lion: Continue with Authentik and complete the authentik prompt.
If Connect OpenStack with Authentik appears, click it once and allow the redirect to finish.
Verify that the profile menu shows your verified email, an
External-Project-*project, and an active OpenStack connection.
Hummingbird User
Complete the authentik identity step used to enter SoloRAN.
On the Hummingbird form, verify the read-only username and enter your OpenStack/Keystone password.
Click Continue to dashboard. The password is retained only in encrypted server-side session memory.
Verify that the profile menu shows your
Internal-Project-*project and an active OpenStack connection.
Note
If OpenStack calls begin returning 401 or resource lists become
unavailable, use Profile → Manage session. Use Sign out when
finished, especially on a shared workstation. Never include credentials
in screenshots or support logs.
Deploy the Near-RT RIC Instance
Choose Near RT RIC Deployment in the left navigation.
Select My Personal Project for a new personal RIC. The shared RIC project is reserved for approved shared experiments; normal users cannot deploy into it.
Enter a short, unique instance name, such as
alice-ric, and record it in the experiment worksheet below.Select image
transfer-ric-srsran, an allowed availability zone, a flavor that satisfies the image requirements, the project network, and the project key name if required by policy. Keep visibility Private unless your experiment explicitly requires otherwise.Click DEPLOY INSTANCE once. Follow the Deployment Terminal while Heat creates the stack.
Continue only when the terminal reports
CREATE_COMPLETE/Deployment Finished Successfullyand the instance is Active in OpenStack.
Note
The first runtime start on a new RIC may take longer while SoloRAN seeds the verified Docker image cache and initializes Redis, E2 Manager, E2Term, and Subscription Manager. Do not click Start RIC repeatedly.
Deploy the RAN Instance
Choose RAN Deployment in the left navigation.
Enter a different unique name, such as
alice-ran.Select image
transfer-ran, the testbed-approved availability zone and flavor, the same tenant network used by the RIC, and an allowed key name.Click DEPLOY INSTANCE once and monitor the Heat output.
Continue only after
CREATE_COMPLETE/Deployment Finished Successfullyand Active status in OpenStack.
The prepared transfer-ran VM normally hosts the Open5GS Core, O-CUDU gNB,
and srsUE together. Therefore, Core VM IP and RAN/gNB/UE VM IP usually
point to the same floating IP.
Associate Floating IPs in OpenStack
Each instance receives a fixed tenant IP, typically 10.0.0.x. SoloRAN
uses a floating IP to reach the VM over SSH, while the runtime automatically
resolves fixed addresses for internal E2 traffic.
Open https://portal.ccixgtestbed.org and select the same project shown in your SoloRAN profile menu.
Go to Project → Compute → Instances.
On the RIC row, open Actions → Associate Floating IP.
Select an unused address. If none is available, use the + control, select the administrator-provided external pool, and allocate an address to the project.
Select the port whose fixed IP belongs to the RIC instance, then click Associate.
Repeat for the RAN instance, using a different floating IP and its corresponding port.
Refresh Instances. Confirm that each row shows both its fixed and floating address, and record the mappings.
Component |
Instance name |
Fixed IP |
Floating IP |
|---|---|---|---|
RIC |
Your RIC name |
Assigned RIC fixed IP |
Assigned RIC floating IP |
RAN/Core/gNB/UE |
Your RAN name |
Assigned RAN fixed IP |
Assigned RAN floating IP |
Tip
If Associate Floating IP is unavailable, confirm that the instance
is not in ERROR, floating-IP quota and an external pool are
available, and you selected the correct project. Do not associate an
address with an unrelated port. If the problem persists, send instance
and port IDs, never passwords, to the administrator.
Enter the Runtime Addresses
Return to SoloRAN → RAN Deployment → RAN Runtime Control.
Field |
Recommended value |
Reason |
|---|---|---|
Core VM IP |
RAN floating IP |
Open5GS runs on the prepared RAN VM. |
RAN/gNB/UE VM IP |
RAN floating IP |
SSH target for O-CUDU, srsUE, the namespace, and traffic. |
Near-RT RIC VM IP |
RIC floating IP |
SSH target for the Dockerized RIC. |
gNB Bind IP |
Leave blank unless instructed. |
SoloRAN selects the guest’s local fixed address on the route to the RIC. |
Directories/configuration |
Keep the supplied defaults. |
They match |
UE Namespace |
|
Default isolated UE dataplane namespace. |
Ping Target |
|
Open5GS UE tunnel gateway. |
Tip
For an immediate SSH timeout or unauthorized-target error, verify the floating-IP mapping and project in Profile → My Deployments. Then check that the project security group permits SSH from the SoloRAN management network.
Start and Integrate the Components
Use the manual sequence for a new deployment. Move forward only after the readiness evidence below appears. Start Sequence uses timers and is best reserved for a configuration already validated manually.
Order |
Control |
Wait for this evidence |
|---|---|---|
1 |
Start Core |
|
2 |
Start RIC |
|
3 |
Start gNB |
|
4 |
Start UE |
|
5 |
Start Dataplane Ping |
Replies from the Open5GS gateway. Stop ping after validation. |
6 |
Start iPerf |
Sender/receiver bitrate summary and exit code |
Click Start Core once. Installation messages are normal on first use; wait for the Core readiness line.
Click Start RIC once and wait for readiness. Use Check E2 if you want a status snapshot before starting the gNB.
Click Start gNB. The dashboard resolves the RIC floating IP to its fixed tenant address. Confirm both AMF/N2 and RIC/E2 connections.
Click Start UE. Wait for the PDU session and assigned
10.45.1.xaddress before generating traffic.Validate the dataplane with a short ping, then stop ping before a controlled iPerf experiment.
Generate Controlled iPerf Traffic
Setting |
Available choices |
Guidance |
|---|---|---|
UDP bandwidth |
1, 2, 5, 10, or 30 Mbit/s |
Begin at 1 or 2 Mbit/s. Rates above 10 Mbit/s can be unstable. |
Duration |
30, 60, 120, 300, or 600 seconds |
Use 30–60 seconds for validation and longer runs for approved measurements. |
30 Mbit/s profile |
Stress/DoS |
Use only in an authorized, isolated experiment. The UI requires confirmation. |
Choose bandwidth and duration. Record both with the experiment timestamp.
Click Start iPerf. SoloRAN starts the server inside Open5GS and the UDP client inside the UE namespace.
Observe the Dataplane / Cleanup terminal for sender and receiver rates. Some loss and a lower receive rate are possible at high load.
If necessary, use Stop iPerf. Clear does not stop traffic.
Sample Experiment with PRB-Allocator
Prerequisites
The RIC terminal reports
Near-RT RIC is ready.The gNB terminal reports an E2AP connection to the Near-RT RIC.
The UE is attached if the xApp needs UE-level measurements.
iPerf or another controlled workload is running when non-zero throughput values are expected.
Run and Observe
Open xApp Deployment and set RIC Host IP to the RIC floating IP.
Select the publicly available PRB-Allocator xApp.
Click Run xApp once. The runner uploads the file, installs declared or detected dependencies into a persistent directory for that xApp, resets only the Python runner, and starts Python unbuffered.
Read xApp Logs and Metrics for stdout, stderr, Python tracebacks, subscription messages, and printed measurements.
Under Live E2 Metric, select a supported KPM measurement. The x-axis uses local time, the y-axis follows the metric unit, and the latest 120 samples are retained.
Click Stop xApp and wait for the stopped state/terminal clear before running another xApp on the same RIC.
Upload and Run a Python xApp
Prerequisites
Use the same RIC, E2, UE, and traffic readiness checks as the PRB-Allocator experiment above.
Upload
In xApp Deployment, choose + Upload New.
Upload exactly one
.pyfile. Enter a clear name and description.Choose visibility: Private is visible only to you; Public is visible to other users, but only the original uploader can delete it.
Click Upload Python xApp, then select the new xApp card.
Run and Observe
Set RIC Host IP to the RIC floating IP, not the RAN IP.
Confirm the filename in Selected Python xApp.
Click Run xApp once. The runner uploads the file, installs declared or detected dependencies into its persistent directory, resets only the Python runner, and starts Python unbuffered.
Read xApp Logs and Metrics for output, exceptions, subscriptions, and measurements.
Select a supported measurement under Live E2 Metric. The chart uses local time and retains the latest 120 samples.
Click Stop xApp and wait for the stopped state/terminal clear before switching xApps on the same RIC.
Important
The minimal python_xapp_runner uses fixed REST and RMR ports. Run
one uploaded Python xApp at a time per RIC. Separate users should
use their own project RIC unless a shared experiment is explicitly
coordinated.
Write an xApp Whose Logs Appear in SoloRAN
Logging Contract
Text written to stdout or stderr appears in the xApp terminal. Use
print(..., flush=True)for immediate feedback.Exceptions and tracebacks also appear. Do not suppress them while developing.
To feed Live E2 Metric, print KPM lines in the form
Metric: <name>, Value: [<number>].Supported chart examples include
DRB.UEThpUl,DRB.UEThpDl,RRU.PrbUsedUl,RRU.PrbUsedDl,RRU.PrbAvailUl, andRRU.PrbAvailDl.A custom decision line such as
CONTROL: allocated_prb=70%appears in the terminal even when it is not a chart metric.Never print passwords, tokens, private keys, or other users’ data.
Minimal E2SM-KPM Monitor
The following single-file template subscribes to uplink and downlink
throughput. Change METRICS only to measurements supported by the
connected E2 node. It uses the lib.xAppBase SDK supplied by the prepared
RIC runtime.
#!/usr/bin/env python3
import argparse
import signal
from lib.xAppBase import xAppBase
METRICS = ["DRB.UEThpUl", "DRB.UEThpDl"]
class SoloRANMonitor(xAppBase):
def __init__(self, config, http_port, rmr_port):
super(SoloRANMonitor, self).__init__(config, http_port, rmr_port)
def on_indication(self, agent, subscription, header, message):
hdr = self.e2sm_kpm.extract_hdr_info(header)
data = self.e2sm_kpm.extract_meas_data(message)
print("RIC Indication: {}".format(hdr.get("colletStartTime")),
flush=True)
for metric_name, value in data.get("measData", {}).items():
# This exact format is recognized by the Live E2 Metric chart.
print("Metric: {}, Value: {}".format(metric_name, value),
flush=True)
@xAppBase.start_function
def start(self, e2_node_id):
callback = lambda agent, sub, hdr, msg: self.on_indication(
agent, sub, hdr, msg
)
print("Subscribing to {} for {}".format(e2_node_id, METRICS),
flush=True)
self.e2sm_kpm.subscribe_report_service_style_1(
e2_node_id, 1000, METRICS, 1000, callback
)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--config", default="")
parser.add_argument("--http_server_port", type=int, default=8092)
parser.add_argument("--rmr_port", type=int, default=4562)
parser.add_argument("--e2_node_id",
default="gnbd_001_001_00019b_0")
args = parser.parse_args()
app = SoloRANMonitor(args.config,
args.http_server_port,
args.rmr_port)
signal.signal(signal.SIGINT, app.signal_handler)
signal.signal(signal.SIGTERM, app.signal_handler)
signal.signal(signal.SIGQUIT, app.signal_handler)
app.start(args.e2_node_id)
Note
The default E2 node ID, gnbd_001_001_00019b_0, matches the prepared
demonstration configuration. If the gNB node identity changes, update
--e2_node_id or the default in the uploaded file.
Third-party Python Dependencies
SoloRAN automatically detects common imports such as NumPy, pandas, SciPy, Matplotlib, requests, PyYAML, scikit-learn, Pillow, seaborn, joblib, and plotext. For another package, declare it near the top of the same uploaded file:
# SoloRAN-Requires: package-name>=1.2 another-package
Dependencies are installed in an isolated directory for that xApp on the RIC host and reused after the Python runner or RIC containers are recreated. Use only trusted, pinned dependencies approved for the testbed; replace the illustrative package names and version constraint above with approved values.
If the xApp Shows No Values
What you see |
Meaning |
Action |
|---|---|---|
Indications with |
Subscription works, but there is no measurable traffic. |
Start controlled iPerf traffic and keep the UE attached. |
|
RIC Subscription Manager or its dependencies are not ready. |
Stop the xApp; verify RIC readiness, Redis/DBaaS, SubMgr, and E2; then rerun. |
No E2 connection / connection refused |
The gNB is not associated with E2Term. |
Restart RIC, wait for readiness, then restart gNB and confirm E2AP completion. |
No |
UE is not attached or its namespace/tunnel is stale. |
Stop UE, clean stale runtime state if needed, restart UE, and wait for the PDU session. |
|
A previous xApp still owns fixed REST/RMR ports. |
Stop the xApp and wait before rerunning. Restart RIC only if the stale owner persists. |
|
A dependency is not detected or declared. |
Add |
Python traceback |
xApp code error. |
Use the final exception and referenced line number to fix the code, upload it, and rerun. |
Invalid license during first RIC start |
External registry/cache seed problem. |
Do not modify the image. Retain the terminal log and contact the SoloRAN administrator. |
Full Recovery Sequence
Warning
Clear is not Stop. It only removes text from the browser terminal. It does not stop an xApp, iPerf, ping, UE, gNB, Core, RIC container, or OpenStack instance.
When logs are stale, subscriptions return 503, or values do not recover,
use this controlled reset:
Click Stop xApp and wait for the stopped state.
Click Stop iPerf and Stop Ping if those workloads are active.
Click Stop UE and wait for
srsUE stopped.Click Stop gNB and wait for
gNB stopped.Click Stop RIC and wait for
Near-RT RIC stopped.Click Stop Core and wait for
Open5GS Core stopped.Use Cleanup All only if a namespace, tunnel, container, or process remains. It is not required between healthy experiments.
Restart manually: Core → RIC → gNB → UE, waiting for every readiness gate.
Validate ping, stop it, then start the desired iPerf profile.
Run the xApp only after E2 and UE readiness evidence is present.
Stop, Delete, and Sign Out
End an Experiment Without Deleting VMs
Stop the xApp and wait for its stopped state.
Stop iPerf/ping, UE, and gNB.
Stop RIC and Core.
Sign out through the profile menu. The OpenStack instances remain deployed for a later session.
Delete Deployed Infrastructure
SoloRAN deployments are Heat stacks. Deleting only the Nova instance can leave ports or other stack resources. To remove a deployment completely, delete the stack that owns it:
Stop runtime components in the reverse order described above.
In Horizon, open Project → Orchestration → Stacks in the correct project.
Match the RAN or RIC stack to the instance name. Inspect its Resources tab if uncertain.
Choose Delete Stack. Confirm only after verifying the target; stack deletion cannot be undone.
After disassociation, release an unused floating IP to the project pool when policy permits.
Delete an Uploaded xApp
Stop the xApp if it is running.
Select an xApp card uploaded by your account.
Choose Delete selected xApp and confirm the prompt. You can delete your own private or public xApp, never another user’s public xApp or a system xApp.
Troubleshoot Deployment Failures
Failure |
Likely area |
What to collect or do |
|---|---|---|
Image missing or not visible |
Glance sharing/visibility |
Confirm the prepared image is visible to the current project; ask the image owner or administrator. |
|
Capacity, image transfer, or compute scheduling |
Wait for the testbed’s normal window. Inspect Heat Events and the instance Task. Avoid repeated deployments. |
|
Neutron port binding / host scheduling |
Capture instance ID, port ID, timestamp, project, and fault. Contact the OpenStack administrator. |
No valid host / quota exceeded |
Flavor capacity or quota |
Choose an approved flavor/availability zone or request a quota and capacity review. |
SSH timeout after Active |
Floating IP, security group, or route |
Verify the floating-IP-to-port mapping and TCP port |
|
Expired or incomplete session |
Use Profile → Manage session, reconnect OpenStack, and refresh resources. |
Experiment Record and Support Checklist
Keep a record of the following values for each experiment:
Record |
Values to capture |
|---|---|
User / OpenStack project |
Your user identity and project name. |
RIC instance / fixed IP / floating IP |
Instance name and both assigned addresses. |
RAN instance / fixed IP / floating IP |
Instance name and both assigned addresses. |
Images and flavors |
Image and flavor used for each VM. |
Readiness timestamps |
Core, RIC, gNB, and UE readiness times. |
iPerf configuration and result |
Bandwidth, duration, and measured result. |
xApp identity |
Name, visibility, filename, and version. |
E2 / KPM configuration |
E2 node ID and requested KPM metrics. |
Failure details |
First error line and timestamp. |
A useful support report includes the time in UTC, your project, instance/stack/port IDs, the control clicked, the last successful readiness gate, and the first error line. Include Heat Events for deployment faults. Follow the Support Guide to report an issue.
Never include an authentik password, Keystone password, session cookie, token, SSH private key, or full environment file.
Security and Responsible Use
Upload only Python code and dependencies you trust. The xApp runner is a controlled research runtime, not a sandbox for hostile code.
Keep xApp visibility private until the code is ready to share. Public visibility does not transfer deletion rights to other users.
Use the smallest security-group source ranges and ports permitted by testbed policy.
Treat 30 Mbit/s as a stress/DoS profile. Run it only with authorization and stop immediately if it affects shared infrastructure.
Keep experiments within your project. Coordinate explicitly before using a shared RIC or shared dataset.
Delete unused Heat stacks and release unused floating IPs to conserve shared capacity.
For CCI-specific quotas, availability zones, image access, and network policy, follow current testbed administrator guidance when it differs from generic OpenStack documentation.