UPF Certification
This is the complete, deployable guide to UPF Certification — Stage 1 of CNTC. It certifies a 5G User Plane Function as a black box over its N3 (GTP-U) and N4 (PFCP) interfaces: you point the framework at any open-source UPF, run it, and get a graded verdict and — on a clean pass — a certificate.
What it certifies
Section titled “What it certifies”A UPF Certification PASS asserts that the UPF, on the stated rig:
- conforms to the PFCP / N4 control interface (3GPP TS 29.244) — association, and session establish / modify / delete;
- is robust on N3 — it does not crash on malformed GTP-U, unknown TEIDs, or PSC (0x85) extension headers;
- forwards user traffic at the measured throughput and latency reported in the scorecard; and
- holds the reported number of concurrent PFCP sessions (UEs).
How it works
Section titled “How it works”CNTC has two decoupled layers: an engine (upfbench) that measures, and an umbrella (cntc) that judges the serialized results.json against a requirement catalog. Because they are decoupled, any past run can be re-graded without re-running it.
The engine drives four test suites over the UPF’s interfaces (N3 GTP-U, N4 PFCP, N6 upstream):
- performance — throughput (NDR/PDR), latency/jitter, burst, and multi-flow on a single tunnel.
- load — many UEs at once: session capacity plus aggregate and per-UE throughput under load.
- pfcp — N4 conformance to TS 29.244 (association, establish / modify / delete, error handling).
- n3neg — N3 robustness: malformed GTP-U, unknown TEID, PSC ext-header — crash detection and recovery.
Requirements are grouped into profiles. The conformance profile is hardware-independent and binary pass/fail (PFCP + N3 robustness) — certifiable on any rig. The performance profile is hardware-dependent and graded relative to a baseline on the same rig class, never as an absolute number.
Prerequisites
Section titled “Prerequisites”- An open-source UPF under test — e.g. SD-Core BESS-UPF, OAI-UPF, or Open5GS-UPF — reachable on its N4 (PFCP) endpoint and N3 (GTP-U) access interface.
- A Linux traffic node (the “rig”) with Python 3.10+,
tcpreplay,scapy, and passwordless sudo (raw send needs it). - L2/L3 reachability from the rig to the UPF’s access interface and N4 endpoint.
- Optional, for line-rate throughput: DPDK + TRex with SR-IOV NICs.
Install the framework
Section titled “Install the framework”Clone the repository and install the dependencies. make prereqs installs system packages, builds the bundled pfcpsim, and runs a readiness check.
git clone https://github.com/TOSSI-Foundation/CNTC.git
cd CNTC
make prereqs # deps + pfcpsim + doctor (uses sudo)
# (or, Python only: pip install -e . -> installs the `cntc` and `upfbench` CLIs)Confirm the rig is ready:
make doctor # preflight: deps, sudo, interfaces, (TRex/hugepages/VFs if DPDK)Configure your UPF
Section titled “Configure your UPF”Describe the UPF under test in a campaign config. The wizard writes one for you, or copy and edit configs/my-upf.yaml.
make configure # interactive wizard -> configs/<campaign>.yamlThe key fields are:
- adapter — the UPF plugin:
sdcore_bess,oai_upf, oropen5gs_upf. - mode — the traffic path:
af_packet(portable) ordpdk/af_xdp/cndp(line-rate). - N4 / PFCP address of the UPF, and the N3 access interface (plus gNB/UPF IPs and TEID).
- baseline — a reference
results.json, required only for the performance profile.
Run the certification
Section titled “Run the certification”The full end-to-end run — every suite plus N3 robustness, then grade, then certify — is a single command:
make run CONFIG=configs/my-upf.yaml CAMPAIGN=MY-UPF-001Or run just the certification set (the hardware-independent conformance suites), or one suite at a time:
make run-conformance CONFIG=configs/my-upf.yaml CAMPAIGN=MY-UPF-001 # pfcp + n3neg, then grade
make run-perf CONFIG=configs/my-upf.yaml CAMPAIGN=MY-UPF-001 # performance + load + pfcp
make run-n3neg CONFIG=configs/my-upf.yaml CAMPAIGN=MY-UPF-001 # N3 robustness onlyRead the verdict and scorecard
Section titled “Read the verdict and scorecard”Every run writes campaigns/<id>/scorecard.md (and .html) and embeds a verdict block in results.json. The exit code is non-zero unless the result is PASS, so it drops straight into CI. Re-grade any past run with make verdict CAMPAIGN=<id>.
CNTC VERDICT - profile: conformance (catalog v0.2.0)
[PASS] * CF-01 PFCP association setup / release status == pass
[PASS] * CF-02 Session establishment status == pass
...
[PASS] * NT-01 Malformed GTP-U robustness (no crash) status == pass
[PASS] * NT-02 Unknown-TEID handling status == pass
essential gate (all): 7 passed / 0 failed / 0 na (of 7)
RESULT: PASSPASS— every essential test passed.FAIL— an essential test failed (for example, the UPF crashed on malformed N3 input).INCOMPLETE— an essential test did not run; it is never silently promoted to a pass.
The certificate
Section titled “The certificate”A CNTC certificate is issued automatically only when every essential test passes:
make certify CAMPAIGN=MY-UPF-001 # writes certificate.md / .html / .json (PASS only)It records exactly what was verified — the profile, catalog version, the standards covered (TS 29.244 for PFCP/N4 and TS 29.281 for GTP-U/N3), and the essential-gate result — so it is auditable against the campaign that produced it. A run that fails or skips an essential test yields no certificate.
Live dashboard
Section titled “Live dashboard”A live, view-only web dashboard renders every campaign — scorecards, per-suite charts, findings, and the certificate:
make dashboard # http://<host>:8050 (or: make dashboard-bg to run detached)Run in Kubernetes
Section titled “Run in Kubernetes”The dashboard (and, optionally, the test runner) ship as Kubernetes manifests:
make k8s-deploy # live dashboard as a Deployment + Service (NodePort 30850)
make k8s-run # run the whole suite in-cluster as a Job
make k8s-clean # tear both downSupported UPFs
Section titled “Supported UPFs”One adapter per UPF keeps them comparable. Validated today:
- SD-Core BESS-UPF — DPDK / AF_XDP / CNDP / AF_PACKET.
- OAI-UPF — simpleswitch.
- Open5GS-UPF — adapter present.
Troubleshooting
Section titled “Troubleshooting”doctorflags a missing dependency — re-runmake prereqs.tcpreplayhangs or is denied — the generator runssudo tcpreplay; add a passwordless-sudo (NOPASSWD) rule for it.- Throughput looks tiny (~0.002 Mpps) — that is the
af_packetgenerator ceiling, not the UPF; switch to DPDK/TRex for real numbers. - N3 forwarding is zero — the UPF access MAC can change on pod restart (macvlan); leave the N3 remote MAC blank so it is resolved live.