Skip to main content

OmniSCP Operations Guide

Table of Contents

  1. Component Overview
  2. 3GPP Role and Spec References
  3. SBI Endpoints
  4. Configuration Reference
  5. Key Procedures
  6. Observability
  7. Known Limitations
  8. Troubleshooting

Component Overview

OmniSCP implements the Service Communication Proxy (SCP) network function defined in 3GPP TS 29.500 and TS 23.501. The SCP acts as an HTTP reverse proxy between NF consumers and NF producers in the 5G Service Based Architecture (SBA). It provides delegated NRF discovery, load balancing across NF producer instances, retry on failure, and NRF discovery result caching.

Routing Modes

The SCP supports three routing modes, evaluated in priority order on each incoming request:

  1. Direct forwarding3gpp-Sbi-Target-apiRoot header is present. The request is forwarded directly to the specified base URI without NRF lookup.
  2. Delegated discovery3gpp-Sbi-Discovery-target-nf-type and 3gpp-Sbi-Discovery-service-names headers are present. The SCP queries the NRF (or hits the cache) and selects an instance via the configured load balancing strategy.
  3. Path-based inference — No routing headers present. The SCP infers the target NF type from the path prefix (e.g., /nudm- → UDM) and performs delegated discovery.

3GPP Role and Spec References

ItemReference
SCP NF definition3GPP TS 23.501 Section 7.3
SCP indirect communication model3GPP TS 29.500 Section 6.10
3gpp-Sbi-Discovery-* headers3GPP TS 29.500 Section 6.10.3
3gpp-Sbi-Target-apiRoot header3GPP TS 29.500 Section 6.10.3.2
3gpp-Sbi-Producer-Id header3GPP TS 29.500 Section 6.10.3.3
SCP load balancing3GPP TS 29.500 Section 6.10.4
NF discovery service3GPP TS 29.510 Section 6.2
NRF NF Status Notification3GPP TS 29.510 Section 6.3
SBI common framework3GPP TS 29.500

SBI Endpoints

OmniSCP operates as a transparent proxy. There is only one locally-handled endpoint; all other paths are proxied to the appropriate NF producer.

MethodPathHandled LocallyDescription
POST/nnrf-nfm/v1/nf-status-notifyYesReceives NRF NF status change notifications. On NF_DEREGISTERED or NF_PROFILE_CHANGED events, invalidates the entire discovery cache. Returns 204 No Content.
*/* (all other paths)No — proxiedAny method and path not matching the above is proxied to the resolved NF producer according to the active routing mode.

Proxy Error Responses

When the SCP cannot complete a proxy operation, it returns a ProblemDetails body per TS 29.500.

HTTP StatusCauseCondition
400 Bad RequestMANDATORY_IE_MISSINGNo routing information available: no 3gpp-Sbi-Target-apiRoot, no discovery headers, and path cannot be mapped to a known service.
502 Bad GatewayTARGET_NF_NOT_REACHABLEAll selected NF producer instances returned 5xx or connection errors after retries, or no SBI URI could be resolved for a discovered instance.
504 Gateway TimeoutNF_DISCOVERY_FAILURENRF discovery returned zero NF instances for the requested service.
500 Internal Server ErrorSYSTEM_FAILUREUnexpected internal error in the SCP proxy.

3gpp-Sbi Headers Consumed

HeaderDescription
3gpp-Sbi-Target-apiRootDirect routing target. Stripped before forwarding.
3gpp-Sbi-Discovery-target-nf-typeNF type to discover (e.g., UDM). Used for delegated discovery. Stripped before forwarding.
3gpp-Sbi-Discovery-service-namesComma-separated list of service names. First value is used as the primary. Stripped before forwarding.
3gpp-Sbi-Discovery-requester-nf-typeRequester NF type for NRF query scoping. Stripped before forwarding.
3gpp-Sbi-Discovery-target-plmn-listTarget PLMN list. Passed to NRF discovery. Stripped before forwarding.
3gpp-Sbi-Discovery-requester-snssai-listRequester S-NSSAI list. Passed to NRF discovery. Stripped before forwarding.
3gpp-Sbi-Discovery-nf-set-idNF set ID filter for discovery. Stripped before forwarding.
3gpp-Sbi-Discovery-target-nf-instance-idSpecific NF instance ID to target. Stripped before forwarding.
3gpp-Sbi-Discovery-requester-nf-instance-idRequester instance ID. Stripped before forwarding.

3gpp-Sbi Headers Produced

HeaderDescription
3gpp-Sbi-Producer-IdAdded to every proxied response. Contains the nfInstanceId of the NF producer that handled the request, enabling consumer-to-producer binding per TS 29.500 Section 6.10.3.3.

Configuration Reference

All parameters are set via the application environment (typically config/runtime.exs).

config :omniscp,
sbi_scheme: "http",
sbi_addr: "127.0.0.200",
sbi_port: 7777,
nrf_uri: "http://127.0.0.10:7777",
mcc: "999",
mnc: "70",
heartbeat_interval: 10_000,
discovery_cache_ttl: 60_000,
lb_strategy: :round_robin,
max_retries: 1,
upstream_timeout: 5_000

Parameter Table

ParameterDefaultTypeDescription
sbi_scheme"http"stringTransport scheme for the SBI listener.
sbi_addr"127.0.0.200"stringIP address the SBI HTTP server binds to. NF consumers must route SBI traffic to this address.
sbi_port7777integerTCP port the SBI HTTP server listens on.
nrf_uri"http://127.0.0.10:7777"stringBase URI of the NRF. Used for NF registration, heartbeat, and NF discovery queries on behalf of consumers.
mcc"999"stringMobile Country Code. Included in the SCP NF profile registered with the NRF.
mnc"70"stringMobile Network Code. Included in the SCP NF profile registered with the NRF.
heartbeat_interval10_000integer (ms)Interval between NRF heartbeat requests.
discovery_cache_ttl60_000integer (ms)Time-to-live for NRF discovery cache entries, keyed by {target_nf_type, service_name}. Expired entries are evicted lazily on lookup and by a background cleanup task every 30 seconds. Increase for stable deployments; decrease when NF profiles change frequently.
lb_strategy:round_robinatomLoad balancing strategy for NF producer selection. Valid values: :round_robin, :weighted, :priority. See Load Balancing section for semantics.
max_retries1integerMaximum number of retry attempts when an NF producer returns 5xx or a connection error. A value of 1 means one original attempt plus one retry. Set to 0 to disable retries.
upstream_timeout5_000integer (ms)Timeout for upstream HTTP requests to NF producers (receive timeout). Requests that exceed this timeout are treated as failures and may trigger a retry.

Load Balancing Strategies

StrategyDescription
:round_robinCycles through healthy instances in order. State is maintained per {nf_type, service_name} pair. This is the default and recommended strategy for uniform NF deployments.
:weightedSelects the instance with the lowest load - capacity score. Uses the load and capacity fields from the NRF NF profile. Prefers instances with high capacity and low current load.
:prioritySelects the instance with the lowest priority value (highest priority). Useful for active/standby deployments.

An instance is marked unhealthy after 3 consecutive failures and automatically recovers after a 30-second cooldown. When all instances are unhealthy, the load balancer falls back to the full instance list.


Key Procedures

Direct Forwarding (Mode 1)

Delegated Discovery and Forwarding (Mode 2)

NRF Status Notification (Cache Invalidation)

Path-Based Service Inference (Mode 3)

When no routing headers are present, the SCP extracts the service name from the request path prefix and maps it to an NF type using the following built-in table:

Path PrefixNF Type
nudm-UDM
nausf-AUSF
namf-AMF
nsmf-SMF
npcf-PCF
nudr-UDR
nnssf-NSSF
nbsf-BSF
nnrf-NRF

Note: nchf-, nnef-, and naf- prefixes are not in the built-in map (limitation SCP-L1). Requests to CHF, NEF, or AF services require explicit discovery headers when using mode 3.


Observability

Telemetry Events

EventMeasurementsTagsDescription
[:omniscp, :proxy, :requests]count, duration_mstarget_nf_type, resultPer-request proxy outcome
[:omniscp, :proxy, :result]count, duration_mstarget_nf_type, resultSame event used for distribution histogram
[:omniscp, :discovery, :cache]hits, missestarget_nf_type, service_namePer-service cache hit/miss
[:omniscp, :cache, :hit]countAggregate cache hit counter
[:omniscp, :cache, :miss]countAggregate cache miss counter
[:omniscp, :associations, :active]countGauge: active proxy associations
[:omni5g, :nrf, :registration]statusnf_typeNRF registration status (1=registered, 0=not)

Result tag values: success (2xx/3xx), client_error (4xx), server_error (5xx), error (connection/timeout).

Prometheus Metrics

SCP Proxy Metrics

MetricTypeTagsDescription
omni_scp.proxy.requests.countcountertarget_nf_type, resultPer-request proxy count
omni_scp.proxy.requests.duration_mssummarytarget_nf_typePer-request proxy duration
omni_scp.proxy_requests.totalcountertarget_nf_type, resultTotal proxy requests
omni_scp.proxy_request.duration_msdistributiontarget_nf_typeProxy request duration in ms (buckets: 1, 5, 10, 25, 50, 100, 250, 500, 1000)
omni_scp.active_associations.countgauge--Number of active NF associations

Cache Metrics

MetricTypeTagsDescription
omni_scp.discovery.cache.hitscountertarget_nf_type, service_namePer-service cache hits
omni_scp.discovery.cache.missescountertarget_nf_type, service_namePer-service cache misses
omni_scp.cache_hits.totalcounter--Aggregate cache hit counter
omni_scp.cache_misses.totalcounter--Aggregate cache miss counter

NRF Metrics

MetricTypeTagsDescription
omni_scp.nrf.registration.statusgaugenf_typeNRF registration status (1=registered, 0=not)

BEAM VM Metrics

MetricTypeDescription
beam.memory.totalgaugeTotal BEAM memory in bytes
beam.memory.processesgaugeMemory used by Erlang processes
beam.memory.processes_usedgaugeMemory actually used by processes
beam.memory.systemgaugeSystem memory
beam.memory.atomgaugeTotal atom memory
beam.memory.atom_usedgaugeUsed atom memory
beam.memory.binarygaugeBinary memory
beam.memory.codegaugeCode memory
beam.memory.etsgaugeETS table memory
beam.processes.countgaugeNumber of Erlang processes
beam.ports.countgaugeNumber of Erlang ports
beam.atom.countgaugeNumber of atoms
beam.vm.uptimegaugeVM uptime in seconds

Log Patterns

LevelPatternMeaning
infoReceived NRF status notificationNF status notify received
infoNRF notification: event=<E> nf=<URI>Parsed notification event
debugSCP direct forward: <METHOD> <URL>Mode 1 forwarding
debugSCP delegated forward: <METHOD> <URL> (attempt <N>)Mode 2/3 forwarding attempt
warningSCP retrying after <STATUS> from <ID>...Retry triggered by 5xx
warningSCP retrying after error from <ID>...Retry triggered by connection error
warningSCP cannot determine target for <METHOD> <PATH>Mode 3 path not in service map
warningNRF discovery returned no instances for <NF>/<SVC>Discovery returned empty list
warningAll NF instances unhealthy, falling back to full listLB health fallback
errorNRF discovery failed: ...NRF query error
errorSCP proxy error: ...Unexpected proxy failure
infoNF instance <ID> recovered after cooldownInstance health restored

Known Limitations

IDSeverityDescription
SCP-H4HighECIES SUCI de-concealment is not implemented. RESOLVED. ECIES Profile A (X25519) and Profile B (secp256r1) de-concealment is now implemented in Omni5gEx.Crypto.SUPI per TS 33.501 Annex C. OmniUDM performs de-concealment before UDR lookup using home network private keys configured via hnet_key_dir. The SCP does not need to de-conceal SUCIs in the standard direct communication model.
SCP-M1MediumOverload control is not implemented. The 3gpp-Sbi-Oci (Overload Control Information) header is not generated or consumed. In overload scenarios the SCP will continue forwarding requests without shedding load or back-pressuring consumers.
SCP-M2MediumLoad control indication is not implemented. The 3gpp-Sbi-Lci (Load Control Information) header is not generated. Consumers cannot use OmniSCP to obtain NF load hints for their own load control decisions.
SCP-L1LowThe path-based service inference map (Mode 3) is missing nchf- (CHF), nnef- (NEF), and naf- (AF) prefix entries. Requests to these services without explicit discovery headers will receive a 400 Bad Request with cause MANDATORY_IE_MISSING. Workaround: configure consumers to send 3gpp-Sbi-Discovery-* headers for these services.
SCP-L3LowNRF status notifications with event NF_DEREGISTERED or NF_PROFILE_CHANGED clear the entire discovery cache rather than only the affected {nf_type, service_name} entry. In deployments with frequent NF profile changes, this causes a burst of NRF re-discovery queries.

Troubleshooting

400 Bad Request — MANDATORY_IE_MISSING

The SCP could not determine a routing target. Check:

  1. Is the consumer sending 3gpp-Sbi-Target-apiRoot or both 3gpp-Sbi-Discovery-target-nf-type and 3gpp-Sbi-Discovery-service-names?
  2. If relying on path-based inference (Mode 3), does the path prefix appear in the built-in service map? Note that nchf-, nnef-, and naf- are absent (SCP-L1). Add explicit headers for those services.

504 Gateway Timeout — NF_DISCOVERY_FAILURE

NRF returned no NF instances. Check:

  1. Is the NRF reachable from OmniSCP? Verify nrf_uri and network connectivity.
  2. Is the target NF type registered in the NRF? Query the NRF directly: GET {nrf_uri}/nnrf-disc/v1/nf-instances?target-nf-type=<TYPE>.
  3. Check if an NRF status notification just cleared the cache (NF_DEREGISTERED event) and the NF has not re-registered.

502 Bad Gateway — TARGET_NF_NOT_REACHABLE

All NF producer instances failed. Check:

  1. Are the NF producers running and reachable on the SBI addresses reported in their NRF profiles?
  2. Check upstream_timeout. If NF producers are slow to respond, increase this value.
  3. Review max_retries. If set to 0, a single failure becomes an immediate 502.
  4. Check load balancer health status in logs: look for NF instance <ID> marked unhealthy after N failures.

Discovery cache causing stale routing

If NF producers change addresses or restart without proper NRF deregistration, the cache may hold stale SBI URIs until the TTL expires. Options:

  1. Reduce discovery_cache_ttl to limit the staleness window.
  2. Ensure NF producers deregister from the NRF on shutdown; this triggers an NRF status notification that clears the OmniSCP cache.
  3. A process restart of OmniSCP clears all cache state.

High proxy latency

  1. Check omni_scp.proxy_request.duration_ms histogram for latency distribution.
  2. Compare cache hit rate (omni_scp.cache_hits.total vs omni_scp.cache_misses.total). High miss rate means frequent NRF queries. Increase discovery_cache_ttl.
  3. Check upstream_timeout — requests that timeout add the full timeout duration to latency before triggering a retry.

NRF registration not maintained

Check omni_scp.nrf.registration.status metric. If it reads 0:

  1. Verify nrf_uri is correct and the NRF is reachable.
  2. Check mcc and mnc match the NRF PLMN configuration.
  3. Look for NRF registration errors in application logs at startup.