Skip to content
Docs / dflux Runner
ContactGet started

User-plane testing

User-plane testing is separate from signalling. Once a UE has its PDU session established, the gNB drives real IP traffic through the UPF on N3 and measures throughput, latency, jitter, and drop. dflux Runner has two user-plane receiver backends: userspace kernel sockets for portability, and DPDK for line rate. This guide covers both.

Two backends

BackendWhen to pick
uspace (userspace)Functional checks, low rates (≤ a few hundred Mbps), no privileged NIC binding. Runs on any Linux.
dpdkThroughput / latency benchmarks. Requires huge pages + a NIC bound to a DPDK-compatible driver.

Both backends terminate the receiver side. They sit behind the UPF on N6/N9 (plain IP, GTP-U already stripped) or, in DPDK mode with -gtp, terminate GTP tunnels themselves.

The sender side is a flow action. The shipped templates/gnb/uplane_traffic.yaml flow runs the registration and PDU session sequence, then triggers uplane_start, which arms the gNB-side traffic generator using parameters from the inbound PDUSessionResourceSetupRequest and the gNB's uplane: configuration block. The GTP-U generator encapsulates ICMP or UDP packets. For the concepts behind this, see user plane.

Configure the gNB sender

In your env's gNB block:

YAML

type: USPACE runs a userspace generator over kernel sockets. type: DPDK uses the DPDK-accelerated backend for line-rate sends.

local_gtpu on the NGAP transport is the IP the gNB advertises to the UPF as its N3 endpoint. The UPF tunnels return traffic there.

server uspace — userspace receiver

Bash

Per-protocol behaviour:

  • UDP: binds one listener per port and echoes each datagram back to the sender.
  • TCP: listens per port. The kernel completes the SYN/SYN-ACK, so a SYN-only client sees its RTT reply; application-layer echo runs after the full three-way handshake.
  • ICMP: opens a raw ICMP socket and replies to echo requests. Most Linux kernels also reply automatically, so set net.ipv4.icmp_echo_ignore_all=1 to let this server be the responder.

Flags:

FlagDefaultPurpose
-protocol icmp|udp|tcp(required)Protocol to serve
-listen <ip>0.0.0.0Bind IP
-port-start <n>5001First port for UDP/TCP
-port-num <n>1How many sequential ports to bind
-duration <duration>foreverRun for this then exit
-payload-size <n>0Echo payload size override
-metrics-port <n>0 (off)Prometheus metrics endpoint

ICMP needs CAP_NET_RAW; either run as root or grant the capability.

server dpdk — DPDK receiver

Bash

Flags specific to DPDK:

FlagRequiredPurpose
-protocol icmp|udp|tcpyesProtocol to serve
-port-pci <pci>yesNIC PCI address bound to a DPDK driver
-port-addr <ip>yesIP for the PCI port
-port-gateway <ip>yesGateway IP for the PCI port
-listen <ip>yesServer's own bind IP (passed through to the embedded DPDK listener)
-port-start <port>yesFirst listen port
-port-num <n>no (default 1)Number of listen ports
-cpu <n>no (default 0)CPU index for the DPDK lcore
-duration <duration>noRun for this then exit (clamped to ≥ 5s)
-payload-size <n>noResponse payload size
-keepalive <duration>noTCP keepalive interval (e.g. 1s)
-client-allow <ip> + -client-num <n>noPermitted client IP range
-gtpnoEnable GTP tunnel termination
-metrics-port <n>noPrometheus metrics endpoint

The DPDK backend uses an accelerated listener that ships inside the dflux Runner binary. It requires huge pages allocated and the chosen NIC bound to a DPDK-compatible driver (typically vfio-pci or igb_uio).

DPDK prerequisites:

  1. Allocate huge pages: echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
  2. Bind the NIC to a DPDK driver: dpdk-devbind.py --bind=vfio-pci 0000:00:09.0
  3. Run server dpdk as root (or with CAP_SYS_ADMIN)

Driving traffic from a flow

The uplane_start action arms the sender. In uplane_traffic.yaml it fires on the same transition that sends the PDUSessionResourceSetupResponse, once the PDU session is established:

YAML

When an uplane_start action fires during a run, the flow result carries a uplane_report field with the per-flow metric snapshot. Read the full sender flow in the templates repository.

What each backend measures

Both backends report the same metric shape:

  • Packets in / out per second
  • Bytes in / out per second
  • Bidirectional latency on echo (RTT)
  • Jitter on echo (stddev of RTT)
  • Drop rate (sent vs echoed)

Userspace tops out at a few hundred kpps on a typical NIC; DPDK reaches line rate up to the per-core packet budget.

Troubleshooting

ICMP server receives nothing — kernel is auto-replying. Set net.ipv4.icmp_echo_ignore_all=1.

DPDK EAL: Cannot mbuf errors — huge pages aren't allocated, or the process can't see them. Verify with grep Huge /proc/meminfo.

Sender never fires uplane_start — the flow's preceding states didn't reach the action. Run with -trace to see which state the flow landed in.

N3 traffic returns to the wrong addresslocal_gtpu on the NGAP transport must be an IP the UPF can route packets to. NAT in between will break the return path.

Where to go next