Skip to content

Traffic Steering with OAI NWDAF

Extending the OpenAirInterface 5G core so that an NWDAF measures each data-network path and the SMF acts on that measurement, moving a live PDU session from one N6 path to another. The session is not re-established, no signalling reaches the handset, and the UE keeps its IP address. Only the interface the traffic leaves on changes.

NWDAF-driven DNAI traffic steering in OAI CN5G. On the left, a test harness of gnbsim containers each holding one gNB and one UE from pool 12.1.1.0/24, generating 60 Mbit per second of iperf3 UDP load, with a tc token bucket qdisc impairing one path at a time on veth n6-3 or n6-4 inside the UPF network namespace. Below it the OAI 5G core control plane: oai-amf handling mobility, registration and N2 termination; oai-smf, the only network function that decides and acts, carrying an NWDAF analytics consumer, policy-gated DNAI selection, PFCP Update FAR plus Update PDR actuation and a one-steer-per-cycle budget; oai-pcf which authorizes a DNAI set per session but does not choose within it; oai-nrf which makes the NWDAF discoverable by NF type; and unpatched AUSF, UDM, UDR and MySQL. Below that the user plane: a VPP UPF forwarding with one FIB per network instance across N6-3 internet.oai.org.pri and N6-4 internet.oai.org.sec, feeding two data networks, internet-primary on 192.168.73.0/24 and internet-secondary on 192.168.74.0/24, both terminating on a single external data network container with per-UE return routes synchronised. On the right, the NWDAF: a four-stage pipeline of collect over SBI with a 5 second poll, store in Mongo, compute analytics IDs, and serve on port 6059. Its components are a southbound event-exposure collector taking SMF usage and path events plus AMF mobility events, a host-process UPF metrics collector polling the UPF container every 5 seconds for per-DNAI N6 counters, CPU and memory, a Mongo database holding usage reports and per-DNAI path telemetry, an engine computing DN_PERFORMANCE, NF_LOAD, QOS_SUSTAINABILITY, NETWORK_PERFORMANCE, UE_COMM and UE_MOBILITY, and two northbound interfaces, analytics on 6059 and events on 6060 which is deployed but has no consumer on the steering path. A panel records that the NWDAF proposes, holding no session state, no N4 or PFCP, and never touching the UPF. A footer notes that a steer moves a live PDU session between N6 network instances with the same SUPI, same UE IP, no N1 or N2 signalling and no re-attachment, over interfaces N2, N3, N4, N6, N7, N11, Nnrf and Nnwdaf.
Figure 1. Project architecture, showing the modified network functions, the NWDAF services, the telemetry path and the enforcement path.

Overview

A 5G core selects the exit point towards a data network when a PDU session is established and then leaves it alone. That exit point is a DNAI, a Data Network Access Identifier, which labels one way out of the user plane towards a particular data network. The SMF selects a DNAI, tells the UPF over N4/PFCP, and the UPF programs its forwarding rules accordingly. Nothing in that exchange is periodic, and the UPF has no way to report that the path has degraded, so a session keeps using a failing path until something tears it down.

3GPP already defines the analytic that would inform a better decision. DN Performance, in TS 23.288 clause 6.14, reports performance per data network and per DNAI, and clause 6.14.4 names the SMF as its consumer. In a stock OAI deployment neither half exists: the NWDAF does not compute the analytic, and the SMF has no code that would read it. This project builds both halves and connects them through interfaces 3GPP already defines.

Traffic steering in OAI today

OAI CN5G already steers traffic across multiple N6 interfaces, and this work builds on that mechanism rather than replacing it. The UPF is configured with more than one N6 interface, each carrying a network instance and a DNAI, and each network instance is an independent forwarding table. The PCF holds provisioned policy in three linked parts: PCC rules describing which traffic a rule covers, traffic control data listing the DNAIs a rule permits, and policy decisions mapping a subscriber to a rule. At session establishment the SMF requests policy over N7, resolves the returned DNAI to a UPF network instance, and installs the forwarding rules over N4. The same machinery supports an uplink classifier deployment and redirection.

The property that matters here is that the decision is taken once. UPF and DNAI selection runs inside the establishment procedure only, and the result is immutable for the life of the session. Changing it means editing provisioned policy and re-establishing the session. There is no feedback from the user plane and no analytics consumer anywhere in the core.

What this project adds

The project turns that static selection into a closed loop. The NWDAF gained a DN_PERFORMANCE analytic, along with NF load and QoS sustainability, and now registers with the NRF so a consumer can discover it. The SMF became that consumer: it requests the analytic on a timer, ranks the DNAIs authorized for each session, and issues a PFCP session modification that rebinds a live session to a different N6 network instance. The PCF supplies the set of DNAIs the SMF may choose from, and the SMF may never select outside it.

The division of responsibility follows from that: the NWDAF proposes, the PCF authorizes, the SMF decides, and the UPF enforces. The NWDAF holds no session state and never contacts the UPF, the PCF never chooses from the set it publishes, and the SMF is the only network function that both decides and acts.

Architecture

The deployment gives one VPP UPF two N6 network instances, and those two paths are what steering moves a session between.

PathDNAIUPF network instanceInterfaceSubnet
Primaryinternet-primaryinternet.oai.org.prin6-3192.168.73.0/24
Secondaryinternet-secondaryinternet.oai.org.secn6-4192.168.74.0/24

Because the UPF keeps a separate forwarding table per network instance, the two paths are genuinely independent rather than two labels for the same egress. A single data network container sits on both subnets, and load comes from gnbsim containers holding one gNB and one UE each.

The interfaces carrying the control loop are all standard. The one part that is not an interface at all, the collection of telemetry from the UPF, is described next.

InterfaceBetweenCarries
N4, PFCPUPF and SMFUsage reports from the UPF, and the rule updates that move a session
N7PCF to SMFThe authorized DNAI set, delivered at session establishment
Nsmf_EventExposureSMF to NWDAFUsage reports and user-plane path change events
Namf_EventExposureAMF to NWDAFRegistration and mobility events, collected but not used by the steering decision
Nnwdaf_AnalyticsInfoNWDAF to SMFThe DN_PERFORMANCE result, polled by the SMF
Nnrf_NFManagementAll NFs and the NRFRegistration and discovery

Telemetry and analytics

The NWDAF side is four services and one host process. The southbound service subscribes to SMF and AMF event exposure and stores what it receives; the engine computes the analytics; the analytics northbound interface serves Nnwdaf_AnalyticsInfo and is what the SMF polls. The events northbound interface is deployed but nothing on the steering path consumes it. DN_PERFORMANCE is computed by joining the PFCP usage reports arriving through event exposure to the DNAI each session was on when the report was produced, and averaging the traffic rate over a configurable window, five minutes by default.

Fields that cannot be measured are reported as absent rather than as zero. Delay and loss are not produced: the UPF plugin used here does not implement the TS 29.244 QoS-monitoring information elements, and usage reports carry volume, packet counts and duration but no loss counter. TS 23.288 Table 6.4.2-2 Note 1 records that collection of this data from the UPF is undefined in the release concerned, so the gap is not specific to OAI.

Path degradation is therefore derived from the UPF's own per-DNAI N6 interface counters. A host process polls the UPF every five seconds and reads those counters and the container's resource accounting directly, running outside any container because the UPF exposes no service interface of its own. This is the one part of the loop that is not a 3GPP interface, and the part least likely to transfer to another deployment unchanged.

The resulting value counts transmit stalls rather than discarded packets, so it is not packet loss, and it is carried under a vendor-prefixed key outside the standard analytics object so that no consumer can mistake it for one. Being path-scoped rather than session-scoped, it exists for a DNAI carrying no session.

A second host process keeps the data network's per-UE return routes in step with the path each session is on. This is lab scaffolding: a real deployment would advertise the UE prefix out of the active N6 interface and let routing converge.

The control loop

The steering control loop as nine numbered stages arranged around a circle. One, measure: the VPP UPF produces PFCP reports and N6 counters. Two, collect: the NWDAF southbound service takes event exposure plus a 5 second counter poll. Three, store: the NWDAF database joins reports to their DNAI. Four, analyse: the NWDAF engine computes the rate analytic over a 300 second window and path health every 5 seconds. Five, expose: the northbound analytics interface serves one DN_PERFORMANCE answer. Six, decide: the SMF applies one of two rules, RATE or HEALTH. Seven, authorize: the PCF requires the chosen DNAI to be in the authorized set. Eight, actuate: the SMF issues Update FAR for the uplink and Update PDR for the downlink. Nine, forward: the VPP UPF rebinds N6 to the other network instance, which feeds back into stage one.
Figure 2. The closed control loop, from user-plane observation through analytics and decision to enforcement, and back to observation.

The loop closes because enforcement changes what the next measurement sees.

Between a decision and an actual steer sit four gates, each of which can only withhold a move. The target DNAI is re-checked against the session's PCF decision at execution time, since the authorization may have been revoked since the decision was taken. A per-cycle budget allows at most one steer across the whole engine, preventing every session on a degraded path from migrating together, and a per-session cooldown stops one session moving twice in quick succession. Where the target carries path health, that health must have been observed after the previous steer took effect, which is what makes the loop closed rather than merely rate limited.

The cadences are short except one. The UPF reports usage roughly every ten seconds, the collector polls every five, and the SMF requests analytics every ten. The exception is the five-minute averaging window, which dominates the rate rule: a step change in offered load is diluted by older samples still inside it. Path health is a verdict per collection interval, accepted only while fresh, which is why the health rule reacts within a polling cycle where the rate rule takes minutes.

Steering rules

The SMF implements two ranking rules. One is selected when the SMF container starts and is fixed for the life of that container.

RATEHEALTH
Ranks onOffered load, from the standard avgTrafficRate fieldObserved path state, from the vendor path-health extension
Moves a sessionToward the busier authorized pathAway from a path observed to be degraded
Reaction timeBounded by the 300 s averaging windowWithin a polling cycle
ReversibleNoYes
DefaultYesNo
RATE-based steering, showing what the rule reads, decides and enforces. Rule inputs are two required signals: avgTrafficRate per DNAI from TS 23.288 Table 6.14.3-1, averaged over a 300 second window with one value per DNAI, representing offered load or bits actually carried; and the PCF-authorized DNAIs from the SmPolicyDecision, where the lowest precedence rule wins and sets the candidate list the rule may select within. The steering decision logic picks the DNAI with the highest average traffic rate through five steps: drop any DNAI with no measured rate, drop predictions below confidence 50, exit if fewer than two DNAIs have data, take the highest average traffic rate, and require a 10 percent margin over the current choice. Passing all five sends the candidate to the select check; exiting at step 3 or 5 holds the current path. Enforcement, identical for both rules, re-checks PCF authorization on the SMF application thread because the decision was taken on another thread and policy may have been revoked, then issues one PFCP session modification carrying both an Update FAR for the uplink egress network instance and an Update PDR for the downlink match on the same N6 edge, noting that a FAR-only update silently drops return traffic, and finally the VPP UPF rebinds the N6 path with no N1 or N2 sent, the same PDU session, same SEID and same UE IP, so only the N6 egress moves. A decision outcome panel lists SELECT, which steers the session only if the DNAI is PCF-authorized, the per-session cooldown has expired and the cycle's steering budget is free; and HOLD, which keeps the current path when there is no usable data, only one DNAI has data, the margin is not met, the DNAI is not authorized, or the budget is already spent.
Figure 3. Rate-based steering: how per-DNAI traffic rate produces a selection and how the selected path is enforced.

RATE ranks offered load rather than path quality, so it steers toward the busier path and can never win an emptied path back. It is retained because it is the straightforward interpretation of the standard field, not because it is the better rule.

HEALTH-based steering, showing degradation detection and enforcement. Rule inputs and signals are three: path health per DNAI carried in a vendor extension called oaiPathHealthExt, one verdict per 5 second interval and rejected if older than 30 seconds; the confirmed DNAI, meaning what the UPF acknowledged rather than what the SMF intended, so a failed steer cannot look like success; and the PCF-authorized DNAIs the rule may only ever select within. Path health state over a 5 second interval is one of three values: OBSERVED_HEALTHY, at least 1000 transmit attempts and no stalls; OBSERVED_DEGRADED, at least 1000 attempts and one or more stalls; or UNKNOWN, covering no traffic, too few samples, no sample or stale data, because an idle impaired path is byte-for-byte identical to an idle healthy one, so the ratio is reported as null and never as zero. The steering decision logic steers away from observed-degraded paths, evaluated per session against its confirmed DNAI: degraded means move, healthy and unknown both mean hold; candidates degraded now or in the last 120 seconds are excluded; a path known healthy is preferred over an unknown one; and within a tier the least loaded is taken. Steering cadence and recovery logic covers three mechanisms: one steer per evaluation cycle as a budget global to the steering engine, because path health is a property of the path so every session on it reaches the same verdict in the same poll, measured at 4 of 5 sessions moving at once without it; a freshness gate where the next cycle waits for the target's health to be observed after the previous steer took effect, which is what makes the loop closed rather than merely rate-limited; and a 120 second decaying memory so a degraded path is re-entered only on positive evidence of health. A signal scope panel explains that the metric is a transmit-stall indicator, not packet loss, read from the UPF's own N6 interface counters by a host collector, and that under every impairment measured VPP drops and Linux tx_dropped and tx_errors all read exactly zero, so it is not avgPacketLossRate and is not a 3GPP metric; it also notes hard failures are not observable because no transmit is attempted, so the path reads UNKNOWN. A policy enforcement panel shows the common procedure: PCF authorization re-checked at execution time, a PFCP session modification carrying Update FAR and Update PDR together on the same N6 edge, and the UPF path reconfigured with the same PDU session, same UE IP and no re-attachment, with detection to actuation measured at 10 seconds or less.
Figure 4. Health-based steering: how a degraded path is detected and how traffic is moved away from it.

HEALTH acts only on a path it has observed to be degraded, reads the DNAI the UPF has confirmed rather than the one the SMF intended, and treats an unobservable path as unknown rather than as bad. Its short memory of recent degradation is what makes it reversible: an emptied path goes idle, and an idle path reads the same as an idle healthy one, so without that memory sessions would steer straight back into the path they just left.

Both rules are project-specific. TS 23.288 defines the analytic, not how a consumer ranks DNAIs on it.

Changes to the network functions

Three OAI network functions carry patches, kept as diffs against pinned upstream commits rather than as vendored source. The AMF, the VPP UPF, AUSF, UDM and UDR are used unmodified.

SMF. It gained an NWDAF analytics consumer, per-session DNAI selection within the PCF-authorized set, and the actuation path from an internal decision to a PFCP session modification. Upstream declares an SMF-requested modification procedure but never constructs or triggers one, so there was nothing on which to hang an internally generated decision. Two details of the actuation matter architecturally. The uplink forwarding rule and the downlink detection rule live on the same N6 edge and must be updated together, since moving only the first leaves returning traffic matching the old path, where it is silently dropped; and upstream's Update FAR builder omitted the network instance, without which an update cannot move a session between N6 instances at all. The SMF also tracks the DNAI the UPF has confirmed rather than the one it intended, and rolls back on failure, so its view of the user plane cannot drift from reality.

PCF. It remains the authorization authority and never selects. Its provisioned policy already supports a rule listing several DNAIs, so giving the SMF a set is configuration rather than a code change. The patch addresses the other way a set can arrive: upstream, the policy authorization path built a decision object and never populated it, so a routing requirement from an application function was silently dropped. A second patch restores NRF heartbeats and is not optional. Without it the PCF disappears from the NRF about a minute after every start while still logging a successful registration, after which no session receives a policy rule and steering silently never happens.

NRF. TS 23.288 clause 5.2 expects a consumer to find an NWDAF through the NRF by NF type, but upstream never assigned the NWDAF type when converting a registration into its internal profile, so profiles were stored as unknown and discovery returned nothing. A smaller change accepts the service-name spelling the published OAI AMF image registers with, without which the AMF's registration is rejected and retried indefinitely.

Standard concepts and project-specific extensions

ElementPosition
DNAI as the identifier of an N6 path, and DNAI-based UPF selection3GPP, TS 23.501 and TS 23.502
PCC rule with traffic control data listing permitted DNAIs3GPP, TS 23.503 and TS 29.512
DN_PERFORMANCE analytic, the SMF as its consumer, and NWDAF discovery by NF type3GPP, TS 23.288 clauses 6.14 and 5.2
Nnwdaf_AnalyticsInfo, SMF and AMF event exposure, NRF management3GPP, TS 29.520, TS 29.508, TS 29.518, TS 29.510
PFCP session modification updating the forwarding and detection rules3GPP, TS 29.244
The rule used to rank DNAIs, and its thresholds, margins and timersProject-specific
The path-health metric derived from UPF interface countersProject-specific vendor extension, carried outside the standard object
Collection of UPF telemetry by a host-side pollerProject-specific, compensating for the absence of a UPF exposure interface
Synchronisation of data-network return routesLab scaffolding, not part of traffic steering

The work should be read as standards-shaped rather than standards-compliant. Each network function boundary uses the service or protocol 3GPP specifies for it, and the analytic travelling between them is the one defined for this purpose, but the decision logic, the health metric and the means of collecting UPF telemetry are project choices the specifications either leave open or do not cover.

Deployment

Validated on Ubuntu 22.04 with Docker Engine 24 or newer and the Compose v2 plugin, roughly 8 GB of RAM and 40 GB of free disk. The host pollers start non-interactively, so passwordless sudo is required. No Go or C++ toolchain is needed; every compiler runs in a container.

1. Clone and check the tree. make verify compiles the services, confirms every patch still applies to the commit it names, and parses the scripts and configuration in temporary directories, so it is safe to run against a live deployment.

git clone -b dnai_traffic_steering   https://github.com/TOSSI-Foundation/oai-nwdaf-ts.git
cd oai-nwdaf-ts
make verify

2. Build the images. Nothing is published to a registry. The NWDAF services and the UE simulator build in minutes; the three patched C++ network functions are from-source builds and take considerably longer. make build-fed clones oai-cn5g-fed at a pinned commit, which supplies the subscriber database and the compose baseline.

make build-nwdaf      # the four NWDAF Go services
make build-gnbsim     # the UE simulator
make build-fed        # oai-cn5g-fed at a pinned commit, plus this project's configuration
make build-nfs        # SMF, PCF and NRF from source

3. Bring the system up, in order. Each step checks the previous one. The ranking rule is fixed on the SMF container, so switching rules means recreating the core.

make core RULE=HEALTH     # the 5G core, the PCF and the steering SMF
make nwdaf                # the NWDAF stack and the two host processes
make ues UES=5 ANCHORS=1  # attach the UEs and start the NWDAF southbound service

The last ANCHORS UEs are pinned to the secondary path and never steered. An anchor keeps that path measurable, because a path carrying no session reports unknown and neither rule then has two paths to compare.

Verification

Start traffic, then impair the path carrying the most sessions and watch a session move. The test applies the impairment inside the UPF's network namespace and removes it on every exit path.

make load MBPS=60 SECS=1800 PROTO=udp
make test-health
make status
make unsteer

A pass requires four assertions: the impaired path was reported degraded, the SMF selected the expected alternative, at least one session changed network instance in the UPF, and no more than one steer occurred in any cycle. A companion make test-rate exercises the rate rule, additionally requiring the move to have gone toward the highest-rate path.

Verification does not rely on log lines, because a log records what the SMF decided rather than what the user plane did. The authority is the UPF's own session table, which make status reads directly. For a genuine steer two things must hold for the same session: the network instance must change, and the UE's IP address must not. If the address changed, the session was re-established rather than steered.

make status
curl -s "http://127.0.0.1:6059/nnwdaf-analyticsinfo/v1/analytics?event-id=DN_PERFORMANCE"

Feasibility and limitations

The loop works, and it works through interfaces a 5G core already has: the analytic is the one the specification defines for this decision, the consumer is the network function it names, and the boundary between policy and analytics is respected. The NWDAF analytic, the SMF decision logic and the PFCP actuation would transfer to another deployment largely unchanged. Two parts would not. Path health is read out of a specific user plane by a host-side process, and the downlink return path is maintained by a helper rather than by routing. This is a working demonstrator with standards-shaped interfaces, not a production feature.

Its scope is narrow in four ways. Telemetry is limited to interface counters, resource accounting and relayed usage reports, so delay, jitter and loss are unavailable. Visibility is historical rather than counterfactual, since with one UPF the analytic can only measure the path a session is already on, and an idle path cannot be assessed at all. Prediction is a least-squares extrapolation of offered load whose confidence value is an unvalidated heuristic. Movement is per session between network instances of a single UPF, paced at one session per cycle but not bounded in total, and purely reactive: the system responds only to degradation it has already observed, and cannot yet tell a broken path from an overloaded one.

Source and references

The steering work is published at TOSSI-Foundation/oai-nwdaf-ts, which carries the deployment instructions, the tunable parameters and the patches showing what changed against which upstream commit.

Built on OpenAirInterface CN5G. The NWDAF services are modified from oai-cn5g-nwdaf; the SMF, PCF and NRF are patched from their own upstream repositories at pinned commits. The existing OAI steering capability this work builds on is documented in DEPLOY_SA5G_STEERING.md.

Specifications referenced: TS 23.501 and TS 23.502 (DNAI and user-plane path management), TS 23.503 and TS 29.512 (policy and traffic control data), TS 23.288 (NWDAF architecture and the DN Performance analytic), TS 29.520 (Nnwdaf_AnalyticsInfo), TS 29.508 and TS 29.518 (SMF and AMF event exposure), TS 29.510 (NRF management), TS 29.244 (PFCP) and TS 29.564 (UPF event exposure).

The UE credentials used in the deployment are OpenAirInterface's public tutorial test vectors and are not secrets.

Related core integration work: SD-Core with eUPF covers an eBPF/XDP user plane with in-kernel usage metering, and SETU Release 1 covers IMS voice, video and messaging on a 5G SA core.