User plane
User-plane testing is a separate concern from signalling testing. This page explains why dflux Runner treats GTP-U as its own subsystem with its own backends, what the two backends measure, and when to pick each one.
Why split signalling from user plane
5G procedures split clean across a control / user-plane line. Signalling — registration, PDU session establishment, handover — runs over NGAP and NAS5G with carefully timed interactions and per-step assertions. The whole flow takes hundreds of milliseconds and produces tens of bytes per UE. The user plane — the actual GTP-U traffic on N3 once the session is up — takes microseconds per packet and produces megabits per second.
Mixing the two into one process model would be a mistake. Signalling needs deterministic FSM dispatch with checks at every step; the user plane needs a tight packet loop with no per-frame dispatch overhead. dflux Runner keeps them separate: signalling drives an FSM that sets up the PDU session; the user plane is a separate component that uses the session.
What the user-plane subsystem does
A successful PDU session establishment leaves the gNB knowing two things: the UPF-side GTP-U tunnel parameters (TEID, IP) and the UE-side IP address. The gNB-side traffic generator then sends real IP packets through the GTP-U tunnel at whatever rate the test is asking for. On the other end of the tunnel the UPF strips GTP-U and forwards plain IP onto the data network — where a receiver running d3x-run server uspace or server dpdk echoes the traffic back. The round-trip latency, throughput, jitter, and loss are the user-plane test's actual measurements.
The uplane_start flow action is the bridge between the two subsystems. It runs once the PDU session is up: it arms the configured user-plane sender (userspace or DPDK) with the parameters from the PduSessionResourceSetupRequest and returns immediately. The flow then holds in a uplane_running state until the traffic duration expires, at which point a UplaneComplete event advances the FSM to its final state.
Two backend modes
| Backend | When to pick |
|---|---|
uspace (userspace) | Functional checks, low rates (≤ a few hundred Mbps), no privileged NIC binding. Runs on any Linux. |
dpdk | Throughput / latency benchmarks. Requires huge pages + a NIC bound to a DPDK-compatible driver. |
Userspace
The userspace backend uses kernel sockets:
- UDP: one listener per port; echoes each datagram.
- TCP: one listener per port. The kernel completes the SYN/SYN-ACK handshake so a SYN-only client gets its RTT reply even before the application accepts the connection. Application-layer echo runs after a full 3-way handshake.
- ICMP: raw ICMP socket; replies to echo requests.
It caps at a few hundred kpps on a typical NIC, depending on per-packet overhead. That's fine for functional tests where you're confirming the tunnel terminates and traffic flows. It's not enough for line-rate benchmarks.
DPDK
The DPDK backend uses an accelerated listener that ships inside the dflux Runner binary. The helper is extracted to a temp dir on first use and run with the configured arguments. It uses DPDK's poll-mode drivers to bypass the kernel network stack entirely, going from the userspace few-hundred-kpps ceiling to multi-Mpps line rate.
Cost: DPDK requires huge pages allocated in advance, the NIC bound to a DPDK-compatible driver (vfio-pci or igb_uio), and (typically) root or CAP_SYS_ADMIN. The setup is heavier than userspace but the difference in measurement quality is the difference between "the tunnel works" and "the tunnel can sustain N Mpps with P95 latency under M ms".
What each measures
Both backends report the same metric shape:
- Packets in / out — cumulative counts at the receiver
- Bytes in / out — cumulative volume, reported alongside transmit and receive throughput in bits per second
- Round-trip latency on echo — average, minimum, and maximum time a packet spent in the tunnel plus the receiver
- Jitter on echo — RFC 3550 smoothed jitter (the mean deviation of consecutive round-trip times), the variability metric that matters for real-time traffic
- Loss rate — sent vs echoed; non-zero loss on a clean network indicates UPF, receiver, or tunnel saturation
The userspace backend measures these in-process; DPDK measures them in the accelerated listener and forwards summaries back.
Why receiver-side support matters
A UE-side traffic generator is easy. A receiver that can absorb the traffic, echo it cleanly, and report metrics is what makes the test loop closed. Most labs don't have a clean way to terminate GTP-U traffic — either you put a real CN box behind the UPF, or you write a stub. dflux Runner's server uspace / server dpdk is the stub; it terminates the post-UPF plain IP traffic on N6, echoes it, and reports metrics — eliminating the need for an external traffic terminator in lab setups.
DPDK with -gtp extends this to terminating GTP tunnels themselves, which is useful when there's no UPF in the path at all (gNB-direct testing, UPF replacement scenarios).
When to skip user-plane testing entirely
Plenty of tests don't need it. NGAP procedure conformance, Diameter S6a behaviour, SBI service interactions — all signalling-only. The user-plane subsystem has zero overhead when no flow triggers uplane_start; flows without it run as fast as they always would.
Reach for user-plane testing when the question is "does the data path work" or "how fast can it go". For the procedural questions ("does the UE register"), signalling-only is the right tool.
Where to go next
To set up and run a user-plane test end to end — starting a receiver, arming uplane_start, and reading the results — see User-plane testing.