A UPF is programmed over N4 (or a 4G user-plane node over Sxa/Sxb) with PFCP on UDP port 8805. Before any subscriber traffic can pass, two things have to happen in order: the control-plane and user-plane nodes form an association, then they create a session (Session Establishment) that installs packet rules. If you skip the association, a well-formed Session Establishment Request is often rejected with Cause 72, "No established PFCP Association".
This article is about that handshake, in a lab, against a file, a fake UPF, or a real lab UPF. An earlier article covers generating PFCP traffic without a live core; another covers a broader PASS/FAIL conformance suite. Here the procedure itself is the test. Keep every live exchange on an authorized, isolated network. Never point these tools at a production or third-party system.
Association first, then the session
PFCP node messages (3GPP TS 29.244, as cited in the Mobile Core CLI Reference) are exchanged between a CP function (SMF, SGW-C, PGW-C) and a UP function (UPF, SGW-U, PGW-U) as nodes, not per subscriber. Their header has S=0 and no SEID:
- Association Setup (types 5/6) carries Node ID, Recovery Time Stamp and function features. A PFCP session belongs to an association.
- Heartbeat (types 1/2) is the liveness check; a changed Recovery Time Stamp means the peer restarted and lost its sessions.
- Association Release (types 9/10) ends the association and every session in it.
Only then come the per-session messages, with S=1 and a SEID: Session Establishment, Modification and Deletion (TS 29.244 clauses 7.5.2–7.5.7 in the same reference). The first Establishment Request uses SEID 0 in the header; later messages use the SEIDs the peers exchanged. PDR, FAR, QER and URR in that Establishment are what the UPF will actually forward and count.
A useful N4 test therefore checks more than "a PFCP packet was sent":
- Association Setup succeeds before any Establishment.
- Establishment is accepted (or is rejected with the Cause you intended).
- Heartbeat keeps the association alive; a restart is visible.
- Modification and Deletion, when you use them, refer to the same SEID.
- After a release, a new Establishment without a new association fails as the node specifies.
Option 1: Watch a real SMF and UPF
Deploy an open-source SMF and UPF (for example Open5GS), attach a UE, and capture UDP 8805.
Good for: seeing the stack your lab already runs, including vendor-specific IEs.
Limits: you get the messages that implementation sends, in the order it sends them. Forcing a missing association, a wrong SEID, or a precise Establishment fault usually means extra tooling. You also have to correlate the capture yourself.
Option 2: Craft PFCP in Scapy
Scapy has contributed PFCP layers, so you can build an Association Setup or a Session Establishment by hand and write a pcap or send it.
Good for: one carefully inspected message, or a single IE you want to break.
Limits: you own sequence numbers, Node IDs, SEIDs, Recovery Time Stamps and the rule set. That is fine for a few frames and becomes a state machine for a realistic N4 dialogue.
Option 3: Mobile Core Generator — offline, then live
Mobile Core Generator can write a correctly ordered N4 capture, explain it, and, in Full Edition, play the SMF towards a UPF. According to the product page, User Manual and CLI Reference (1.19.2):
Offline (all editions, Community session cap applies):
gtpcore -scenario pfcp-nodewrites Association Setup, Heartbeat and Association Release for each CP/UP pair in a sessions file. With-pfcp-node-sessions(default true) the Session Establishment, Modification and Deletion of every session sit between Setup and Release — the order a DUT sees on a live N4/Sxb interface.gtpcore -scenario pfcp-lifecyclewrites only the per-session Establishment / Modification / Deletion pairs for PFCP-owned sessions.- Teaching labs
pfcp-associationandpfcp-errorswalk the same ideas: compare a node message (S=0, no SEID) with the first Establishment (S=1, header SEID 0); read Recovery Time Stamp on Setup and Heartbeat; open the error lab's CSV next to the capture for Cause and Offending IE. - Tools > Protocol Conformance can generate further negative Establishment cases (types starting with
pfcp_establishment_, andpfcp_modify_unknown_seid) for your own sessions.
gtpcore -scenario pfcp-node -sessions-json sessions.json -output n4.pcap
gtpcore -scenario pfcp-lifecycle -sessions-json sessions.json -output pfcp_sessions.pcap
Use Generate > Subscribers with PFCP ownership (or the PFCP session tutorial) to obtain sessions.json first. Explain Packets and GTP Sessions will decode and group the result.
Live (Full Edition):
gtpcore fake-upf -listen 127.0.0.1:8805is a built-in UPF for tests (all editions). Optional-reject-every Nand-delayhelp you rehearse loss and rejects.gtpcore pfcp-liveacts as an SMF: Association Setup, Heartbeat, then per-session Establishment, optional Modification and Deletion, and finally Association Release. It is Full Edition (Community exits with code 3). Association failure is exit code 4.
gtpcore fake-upf -listen 127.0.0.1:8805
gtpcore pfcp-live -upf 127.0.0.1:8805 -sessions 20 -rate 10 -summary-json summary.json -pcap n4-live.pcap -report-html kpi.html
Towards a lab UPF on a real interface, add -allow-remote and -node-ip, and start with a low -rate-start / -rate / -ramp. Loopback is the safe default; the flag is the consent to leave it. The summary and loosha-kpi/1 report give attempts, successes, failures, no-response, setup rate and Cause. Running gtpcore -scenario kpi-report on the -pcap gives the same numbers.
If you already have a captured N4 exchange, Full Edition probe can send the requests and match responses by PFCP sequence number, preferring a Session Establishment reply whose SEID equals the request's CP F-SEID. Outer IP/MAC rewrite does not change F-SEID or other IE contents — build those for the lab.
The built-in conformance suite (gtpcore suite) is a broader PASS/FAIL pack against a lab SGW, PGW or UPF, including cases you can list with gtpcore suite -list and rehearse with -self-test. Use it when you want a whole gate; use pfcp-live or a probe of an N4 pcap when the question is this handshake.
A practical N4 workflow
- Learn the two layers offline. Run the
pfcp-associationlab, orpfcp-nodepluspfcp-lifecycleon a small sessions file. Filterpfcpin Wireshark and compare S=0 node messages with S=1 session messages. - Add a negative case. Run
pfcp-errors, or a Protocol Conformance Establishment fault, and read the Cause. - Rehearse live on loopback. Start
fake-upf, thenpfcp-livewith a handful of sessions. Confirm exit 0 and the summary. - Only then, on an isolated lab NIC, aim at a real UPF.
-allow-remote, a finite session count, a modest rate. If Establishment fails with Cause 72, the association did not succeed — fix that before you raise the rate. - Keep the evidence. The pcap,
summary.jsonand the HTML KPI report are what you will compare after a UPF change.
open5GS notes from the CLI Reference are practical here too: raise global.max.ue if you need more than about 1800 concurrent sessions; that UPF may not answer Association Release (reported as one no-response).
Which tool when?
| Need | Good fit |
|---|---|
| See whatever your lab SMF already sends | Capture UDP 8805 on the existing core |
| One hand-built PFCP message | Scapy |
| Ordered N4 pcap: association, then sessions | pfcp-node (optional -pfcp-node-sessions) |
| Learn association vs session, and error Causes | Teaching labs pfcp-association / pfcp-errors |
| Live SMF towards a UPF, with a summary | Full: pfcp-live; start with fake-upf |
| Replay a captured N4 exchange and match replies | Full: gtpcore probe on that pcap |
| Broader PASS/FAIL pack on a lab node | Full: gtpcore suite (-self-test first) |
Editions
Mobile Core Generator Community Edition is free for non-commercial evaluation and compact labs (up to 100 subscribers/sessions, send capped at 1000 packets/s). Offline pfcp-node, pfcp-lifecycle, teaching labs, Explain Packets and fake-upf are included. pfcp-live, probe and the conformance suite are Full Edition (one-time $89). The current release runs on Windows 10/11 64-bit; a Linux build is available on request. Npcap is required for live send.
Explore Mobile Core Generator →
Limitations
- Community Edition cannot run
pfcp-live, probe orsuite(exit code 3). - Replay and probe rewrite outer IP/MAC only; F-SEID and other PFCP IEs stay as generated.
fake-upfis a test double, not a substitute for your DUT's feature set.- A successful Association Setup is not a guarantee that user-plane forwarding works; add GTP-U or
-user-plane http(Full, onpfcp-live) only after the session is accepted. - Never point
pfcp-liveor probe at a production or third-party UPF.
FAQ
Why does Session Establishment fail with Cause 72?
The UP function has no association with this CP peer yet. Send Association Setup first (pfcp-node in a file, or pfcp-live, which does that before any session).
Why is the SEID 0 in the first Establishment Request?
The requester does not yet know the peer's SEID. The User Manual's association tutorial asks you to compare that header with later messages.
Can I try this without a UPF?
Yes. gtpcore fake-upf -listen 127.0.0.1:8805 works in every edition. pfcp-live against it needs Full Edition. Offline, pfcp-node and the teaching labs need no network.
Is this the same as the conformance suite?
No. The suite is a set of built-in cases with PASS/FAIL/ERROR/SKIP. pfcp-live is a live association-and-session driver with a KPI/summary for the run you configured. You can use both.