Skip to content

Configuration

The RIC server is configured from a single YAML file, schema-validated at load time by libcyaml. Mandatory fields are checked and the process fails loudly at startup on a missing or malformed value.

Default path: /etc/airpuls/nrtric.yml (override with -c <path>). The in-tree src/nrtric.yml is the annotated reference — every field below is documented there and, field-by-field, in src/ric/config.h.

Minimal config

Only ric.plmn and ric.ric_id are mandatory; everything else has a default:

ric:
  plmn:
    mcc: "001"           # Mobile Country Code (3 decimal digits)
    mnc: "01"            # Mobile Network Code (2 or 3 decimal digits)
  ric_id: 1              # 20-bit RIC identifier

transport: — every connection

All addressing, ports, socket tuning and TLS material live here, grouped by direction. The ric: block below carries identity and RAN behaviour only.

transport.southbound: — E2 / SCTP toward RAN nodes

Field Default Meaning
bind_addrs ["0.0.0.0"] SCTP bind address(es). All bound addresses are advertised to the peer (SCTP multihoming)
port 36421 SCTP listen port
heartbeat_ms 0 (disabled) SCTP heartbeat interval; 0/negative disables
recv_bufsize 1114112 (1 MB + envelope) Largest single indication the RIC will accept, bytes — sizes the southbound recvmmsg slot. The socket SO_RCVBUF is this plus 1 MiB of queueing headroom. Clamped to [65536, 16 MiB]
worker_threads min(nproc/2, 4) Southbound worker pool size. Clamped [1, 16]; 0 = default; set 1 for serial

SCTP multihoming and Docker

SCTP advertises all bound addresses to the peer, which may pick any of them. On a host with virtual interfaces (Docker bridges, VMs, VPNs), set bind_addrs to the specific IPs the E2 agents can actually reach — otherwise the peer may select an unreachable address and the association drops silently after E2 Setup. Heartbeats are disabled by default for the same reason: a Dockerised gNB advertising bridge IPs can trigger a spurious SCTP ABORT around t+3s. Enable heartbeats only on flat L3 deployments.

Sizing recv_bufsize for raw-SRS traffic

This is an airpuls userspace slot size, not an SCTP protocol limit — SCTP reassembles larger messages transparently. The RIC keeps no reassembly buffer, so a message that exceeds the slot is partial-delivered and dropped, logged once per message as Dropping oversized SCTP message ... raise transport.southbound.recv_bufsize.

An E2SM-AIR channelEstimateFreq estimate is antennas × ports × symbols × fft × 4 bytes, and one indication carries exactly one UE — so UE count scales the rate, never the message size:

antennas × ports 1 symbol @ FFT 4096 4 symbols
4 × 4 256 KB 1 MB
8 × 4 512 KB 2 MB
8 × 8 1 MB — the default covers this 4 MB

The default is that 1 MB plus 64 KB of headroom for the message envelope, so it covers an 8×8 occasion at one symbol. Raise it for higher symbol counts:

transport:
  southbound:
    recv_bufsize: 4194304   # 4 MB — 8×8 at four symbols
Each southbound worker pre-allocates 16 slots of this size, so the default costs ~17 MB per worker and 4 MB would cost 64 MB.

The socket SO_RCVBUF is requested as recv_bufsize + 1 MiB of queueing headroom, but net.core.rmem_max caps whatever is asked for — the headroom does not slip past it. SCTP has to buffer a whole message before it can reassemble and deliver it, so if that cap leaves less than recv_bufsize, messages the slot is sized for can still be partial-delivered. The RIC checks the buffer it actually got at startup and warns only in that case:

SO_RCVBUF holds ~212992 bytes, less than the 1114112-byte largest
indication (transport.southbound.recv_bufsize) — raise
net.core.rmem_max on this host ...

If you see it, raise net.core.rmem_max on the RIC host.

transport.northbound: — xApp IPC

Field Default Meaning
socket tcp://127.0.0.1:36422 xApp IPC endpoint. tcp://<ip>:<port>, tls://<ip>:<port> or unix://<path> — the scheme is mandatory. Empty string disables the listener
cert_file PEM listener certificate. Required with a tls:// endpoint
key_file PEM private key for cert_file
client_ca_file PEM CA that connecting xApps' certificates must chain to
require_cn_match true Treat the client certificate's CN as the xApp identity and reject a Hello claiming a different deployment_name
max_payload_bytes 16777216 (16 MiB) Max xApp ↔ RIC wire payload. Both peers must agree on a value ≥ the largest message exchanged
worker_threads min(nproc/2, 4) Northbound worker pool size. Clamped [1, 16]; a unix:// endpoint clamps this to 1 with a startup WARNING
tcp_quickack true Set TCP_QUICKACK on each xApp socket and re-arm after every recv; removes the ~40 ms delayed-ACK floor. Leave on

The three tls paths travel as a unit — a partial block is a startup error, as is a tls:// endpoint without them. See Security for the full procedure.

Binding for cross-host xApps

tcp://127.0.0.1:36422 accepts loopback xApps only. For xApps on other hosts, bind all interfaces: socket: "tcp://0.0.0.0:36422". The bind host must be an IP literal, not a hostname. A cross-host deployment should use tls:// — see Security.

ric: — identity and RAN behaviour

Identity (mandatory)

Field Type Meaning
plmn.mcc string Mobile Country Code, 3 decimal digits
plmn.mnc string Mobile Network Code, 2 or 3 decimal digits
ric_id int 20-bit RIC identifier

PLMN is decimal

mcc / mnc are decimal digit strings ("001" / "01"), not the BCD-hex form. The RIC BCD-encodes them on the wire and surfaces the decoded decimal PLMN as a metrics label.

Procedure timers and behaviour

Field Default Meaning
control_timeout_ms 5000 RIC Control (TRICcontrol) timer; 0 = no timeout
send_ran_functions_rejected false Include the RANfunctionsRejected IE in the E2 Setup Response

logging: — log level

logging:
  level: "info"     # verbose | info | warning | error

The CLI flags -v (verbose) and -q (warnings + errors) override this; default is info if neither is set.

telemetry: — metrics tier

The Prometheus listener lives here alongside the tier knob:

Field Default Meaning
port 0 (source) / 9095 (container) Prometheus HTTP port; 0 disables
listen_backlog 128 Listen backlog on the metrics port (capped by net.core.somaxconn)

See Observability for the metric catalogue.

telemetry:
  mode: "production"        # production | profile
  endpoint_enabled: true    # false suppresses the HTTP listener even if metrics_port > 0
  • production (default) — aggregate atomic counters + registry-walk gauges; constant-sized scrape body. The ship-mode tier.
  • profile — adds per-(deployment, node) E2SM-EPI latency histograms. Essentially free for small deployments (keep it on to get the EPI latency breakdown); for large deployments the per-(deployment, node) cardinality grows the scrape body and adds a mutex per probe — switch back to production.

disable_ran_function: — SM denylist

Quarantine a misbehaving SM plugin at startup without rebuilding. A listed RAN Function ID is created and immediately destroyed, so the RIC neither accepts agent advertisements for it nor dispatches to it:

disable_ran_function:
  - 100     # example: quarantine E2SM-EPI

Known in-tree plugin IDs: 2 KPM, 3 RC, 4 CCC, 5 LLC, 100 EPI, 101 AIR.

Container configuration

The release image bakes a config with placeholders the entrypoint substitutes at startup (e.g. auto-discovering the container eth0 IP for bind_addrs). Selected values are overridable via environment variables — see Docker Deployment for the full list.