mobility-5g-core
Mobility — The 5G Core, End to End
A hands-on handbook: what the 5G mobility core is, how each piece works, and how to watch it happen in your own lab. Concept on the page,
makecommand in the terminal.This began as a UDM/AUSF deep-dive; the lab (
~/code/mobility_lab) grew to cover the whole mobility core — auth, sessions, slicing, handover, roaming — so this did too. Read top-to-bottom for the story, or jump to a Part and run its 🔬 In the lab box. Pairs with the lab'sdocs/LEARN.md. Routing note: cellular-auth/RF dual-use → Fable-locked.
Orientation — five ideas + the map
If mobile-network internals are new territory, these five load-bearing ideas make the rest read like a system instead of alphabet soup:
- RAN vs. Core. Your phone doesn't talk to "the network" as one blob. The RAN (Radio Access Network — the cell tower, a gNB in 5G) is just the radio link. The Core is a data center full of software services that decide who you are, what you're allowed, and how your data routes. RAN is the doorway; Core is everything inside.
- Control plane vs. user plane. User plane = your actual data (the video, the webpage). Control plane = the signaling that sets it up and manages it ("who are you," "are you allowed," "which tower now"). Most of this handbook lives in the control plane.
- "NF" = Network Function. In 5G the core is independent software services, each with one job — AMF, AUSF, UDM, SMF, UPF, PCF, NSSF… Think microservices calling each other over an API. That's why there are so many acronyms.
- Home vs. visited network. The carrier whose SIM you pay is your home network (HPLMN). Roam abroad and you're on a visited network (VPLMN) — but your identity and secret key never leave home (Part 4).
- Why anything needs proving. A phone claiming "I'm subscriber #12345" over radio is an unverified claim. So before doing anything, the network answers two questions cryptographically: is this really them? and what are they entitled to? That split runs through the whole system.
The map
flowchart LR
UE["UE"]
RAN["gNB (RAN)"]
UE -->|"air interface (RF / Uu)"| RAN
subgraph CP["CONTROL PLANE — signaling only, no user bytes (SBA / HTTP-2)"]
AMF["AMF (SEAF)"]
AUSF["AUSF
(trust anchor)"]
UDM["UDM
(subscriber authority)"]
UDR["UDR
(storage)"]
SMF["SMF"]
PCF["PCF (policy)"]
NSSF["NSSF (slice selection)"]
AMF --> AUSF
AUSF --> UDM
UDM --> UDR
AMF --> SMF
AMF --> PCF
PCF -.reads.-> UDR
AMF --> NSSF
end
subgraph UP["USER PLANE — your actual data"]
UPF["UPF"]
end
RAN -->|"N2 (control signaling)"| AMF
RAN ==>|"N3 (your data)"| UPF
SMF -.->|"N4 (controls the path, carries no data)"| UPF
UPF ==> DN["Data Network (internet)"]
classDef control fill:#e8eefc,stroke:#4a6fd4,color:#1a2b4c
classDef userplane fill:#fdece8,stroke:#d4603f,color:#4c1a1a
class AMF,AUSF,UDM,UDR,SMF,PCF,NSSF control
class UPF,DN userplaneBlue = control plane (signaling/decisions only). Pink = user plane (your bytes, RAN→UPF→internet over N3/N6, the thick arrows). Note SMF (control) only controls the UPF over N4 (dashed) — like a control tower directing planes without flying any. Auth (AUSF/UDM) never touches the pink box.
🔬 In the lab — stand up your own copy of this map
./install.sh(first run), ormake up && make provision.make psshows ~13 NFs — every box above is one Linux process. Nothing works until the control plane is up. (LEARN.md Lesson 0.)
Part 1 — Identity & Trust: proving who you are · UDM + AUSF
The two questions
Every time a phone touches the network, two questions come first:
- Can we cryptographically prove they're genuine (and can they prove the network is genuine)? → AUSF
- Who is this subscriber and what are they entitled to? → UDM
Both live in your home network and are 3GPP-defined 5G-Core control-plane NFs. In plain terms: AUSF is the bouncer checking ID at the door; UDM is the membership database the bouncer checks against. Neither is the door (that's the RAN) or the manager inside (the AMF) — they're the two services that gate entry.
If UDM answers "who" and AUSF answers "can we prove it," shouldn't traffic hit UDM first? The flow is
AMF → AUSF → UDMon purpose:
- AUSF is the trust boundary, UDM isn't. AUSF is the only NF the serving side (AMF/SEAF) may talk to for authentication — critical in roaming, where the AMF belongs to a different carrier. AUSF is the exposed front door; UDM stays behind it.
- It's one nested transaction. The AMF opens
Nausf_UEAuthenticationwith AUSF; inside that, AUSF calls UDM (Nudm_UEAuthentication) to de-conceal SUCI→SUPI and build the challenge, then closes by verifying. AUSF bookends the whole exchange.
Lineage — why the split exists
In 4G the HSS was one monolith (subscriber data + the AuC crypto). 5G split it along a compute-vs-storage seam so each piece scales/patches/replaces independently — the "break the monolith into services" move, applied to telecom a decade after backend engineering did it.
| 4G / LTE | 5G Core | Role |
|---|---|---|
| HSS (data) | UDM (compute) + UDR (storage) | who you are, what you get |
| HSS / AuC (crypto) | AUSF + ARPF (behind UDM) | prove it |
| MME | AMF | registration, handover, connection |
| — (new) | SEAF (inside AMF) | visited-network security anchor |
What each does
UDM — the subscriber authority. Given an identity, what does it get?
- Owns subscription data — allowed slices, QoS, roaming rules (your account's entitlements).
- Identity management — the permanent SUPI (≈ the old IMSI) and de-conceals the SUCI (its encrypted over-the-air form) via the SIDF — the only place in the network that can.
- Registration management — tracks which AMF currently serves the UE (the home mobility anchor).
- Generates auth material via the ARPF, which holds the long-term key K and runs the AKA crypto.
- Stateless — the data lives in the UDR behind it.
AUSF — the trust anchor. Is this identity who it claims, right now, cryptographically?
- Runs the home-network side of 5G-AKA (or EAP-AKA′).
- Sits between the AMF/SEAF (asks) and UDM/ARPF (does the K-math).
- Verifies the response and seeds the key hierarchy (
K_AUSF → K_SEAF → …). - Nothing proceeds until AUSF says yes — no registration, no session, no data.
Supporting cast: UDR (storage) · ARPF (holds K, runs AKA) · SIDF (SUCI→SUPI) · SEAF (visited security anchor, inside AMF) · AMF (access/mobility) · SMF/UPF (session/data) · PCF (policy) · NRF (service registry) · NSSF (slice selection) · SEPP (roaming edge).
How authentication actually works (5G-AKA)
sequenceDiagram
participant UE as UE (USIM)
participant AMF as AMF / SEAF
participant AUSF as AUSF
participant UDM as UDM / ARPF
Note over UE: Power on — USIM holds K, SUPI
UE->>AMF: Registration (SUCI = encrypted SUPI)
AMF->>AUSF: Nausf_UEAuthentication (SUCI)
AUSF->>UDM: Nudm_UEAuthentication
Note over UDM: SIDF: SUCI → SUPI
ARPF: generate AV
UDM-->>AUSF: Auth Vector (RAND, AUTN, XRES*, K_AUSF)
AUSF-->>AMF: RAND, AUTN
AMF-->>UE: Auth challenge (RAND, AUTN)
Note over UE: USIM checks AUTN (network is real)
computes RES*
UE->>AMF: RES*
AMF->>AUSF: RES*
Note over AUSF: verify RES* vs XRES*
AUSF-->>AMF: K_SEAF
AMF-->>UE: Security Mode Command- UE powers on — USIM holds K and SUPI (a secret only it and your carrier know).
- Registration — UE sends SUCI (SUPI encrypted with the home public key) so nobody sniffing radio reads who you are.
- AMF → AUSF → UDM — the claim goes to the bouncer, who forwards to the membership DB.
- UDM runs SIDF (SUCI→SUPI), and via ARPF builds the auth vector (
RAND,AUTN,XRES*,K_AUSF) — a one-time challenge/answer, math-derived from K. - AUSF relays
RAND/AUTNdown to the UE ("solve this"). - USIM checks
AUTN(so the network proves itself too — mutual auth), computesRES*, sends it up. - AUSF verifies
RES* == XRES*. Match ⇒ keys cascadeK_SEAF → K_AMF → radio/NAS keys. - UDM records the serving AMF; subscription/policy fetched → session setup begins.
Net: mutual auth + a fresh key hierarchy, all before any user byte moves.
Where does K live? Exactly two places, nowhere else — that constraint is the security model.
- Your side — inside the SIM's tamper-resistant secure element. You can hand it a
RANDand get an answer; there is no command to read K out.- Carrier side — a mirror copy in the home ARPF, usually in an HSM (same "computes internally, won't export").
K is never transmitted during authentication — it's a pre-shared symmetric key; only derived outputs (
RAND,AUTN,RES*,K_AUSF…) ever move. That's why roaming works as it does: a visited network can't be handed your K — it must ask your home ARPF to run the K-math for it.(How does the same K get onto both ends? Physical SIM: burned in at a secure facility, offline. eSIM: downloaded into the eUICC as an encrypted, device-bound package via GSMA RSP — travels the network, but only as ciphertext locked to that one chip. After that, identical to a physical SIM: sealed, never transmitted.)
The eight steps as data (what's held where, what's never sent):
USIM = { K, SUPI, HN_pubkey } HOME = { K, SUPI, HN_privkey } # SAME K, two ends. K never travels.
SUCI = ECIES_encrypt(SUPI, HN_pubkey) # permanent ID never in clear
AMF ─Nausf{SUCI, SN_name}→ AUSF ─Nudm{SUCI, SN_name}→ UDM # SN_name = "who's asking"
SUPI = ECIES_decrypt(SUCI, HN_privkey) # SIDF — only home can do this
RAND=random(); AUTN=f1(K,RAND,SQN); XRES=f2(K,RAND) # challenge + expected answer
CK=f3(K,RAND); IK=f4(K,RAND); XRES*=KDF(CK,IK,SN_name,RAND,XRES) # 5G: bind answer to THIS network
AUSF.store(XRES*, K_AUSF); AUSF ─{RAND,AUTN}→ UE # only RAND+AUTN go down the radio
assert f1(K,RAND,SQN)==AUTN # UE checks the NETWORK is real (step 6)
RES*=KDF(...,f2(K,RAND)); UE ─RES*→ AUSF
assert RES*==XRES* # NETWORK checks the UE is real (step 7 — THE decision; mismatch ⇒ stop)
K_SEAF=KDF(K_AUSF,SN_name) → K_AMF → K_gNB,K_NAS # keys cascade down the layers
UDM.store(SUPI → serving_AMF); policy = UDR.fetch(SUPI) # only NOW does the data path build
Those two asserts are the protocol: step 6 = UE checks the network is real; step 7 = network checks the UE is real. Both must pass. (f1–f5, HRES/HXRES* fast-check, and f5/AK/SQN elided for clarity; see 3GPP TS 33.501.)*
SUCI concealment — the part visible over the air
- The SUPI is never sent in clear; the UE encrypts it into a SUCI using ECIES with the home network's public key.
- Profiles: Profile A (Curve25519), Profile B (secp256r1).
- Only the home UDM/SIDF can de-conceal it — and it's fresh per registration, so an eavesdropper can't even link two attempts.
- This closes the LTE-era IMSI-catcher gap. (Not a total fix — downgrade/side channels remain research areas, squarely the iseeLora/CellScope lens.)
🔬 In the lab — watch auth, then watch privacy
- Auth (§this Part): terminal A
make cap-cp, terminal Bmake ran. You'll see the UE logAuthentication Request → Security Mode → Registration accept, and on the wire/nausf-auth/…then/nudm-ueau/suci-…/generate-auth-datathen…/5g-aka-confirmation. That's this exact sequence, live.- SUCI:
make suci— the SUCI flips from cleartext…-0-0-0000000001to encrypted…-1-1-<ciphertext>, and changes every run (ECIES). Only the UDM resolves it. (Mainline UERANSIM never encrypts the SUCI — a lesson about tooling; the lab uses PacketRusher for this.)
(LEARN.md Lessons 1–2.)
Part 2 — Sessions & Data: what you're allowed, and where it goes · SMF · UPF · DNN · Slice
Once you're authenticated, the second question kicks in: what are you entitled to, and how do your bytes actually flow? This is the UDM's other door and the whole user plane.
The UDM has two doors
flowchart TB
UE["UE"] --> AMF["AMF"]
subgraph UDMBOX["UDM"]
D1["Door 1 — Nudm_UEAuthentication
‘is this really them?’"]
D2["Door 2 — Nudm_SDM
‘what is this subscriber allowed?’
→ slices, DNNs, QoS, roaming"]
end
AMF -->|"AUSF ↔ Nudm_UEAuthentication"| D1 --> AUSF["AUSF"]
AMF -->|"Nudm_SDM (after auth)"| D2 --> SMF["SMF → PDU session on the allowed DNN/slice"]
SMF --> UPF["UPF → carries that DNN's traffic"] --> DN["Data Network (the DNN)"]
D1 --> UDR[("UDR")]
D2 --> UDR
classDef auth fill:#e8eefc,stroke:#4a6fd4,color:#1a2b4c
classDef sess fill:#fdece8,stroke:#d4603f,color:#4c1a1a
class D1,AUSF auth
class D2,SMF,UPF,DN sessDoor 1 is the auth path from Part 1 — identity only. Door 2 (Nudm_SDM) is fetched after auth and hands the AMF/SMF your subscription profile: which slices, DNNs, and QoS you get. Slices and DNNs are stored entitlements behind Door 2, then used by SMF/UPF. That's why they never appear in the auth flow — different door.
The two planes, concretely
- SMF (Session Management Function) — control plane. Decides your session: which DNN, which IP pool, which QoS, and tells the UPF how to route it over N4 (PFCP). Carries no user data itself.
- UPF (User Plane Function) — the only box your actual bytes touch. Receives your traffic from the gNB over N3 (GTP-U tunnel), applies rules, and forwards to the Data Network over N6.
DNN — which data network (the 5G "APN")
A DNN (Data Network Name) names the network a session exits to: internet, ims (voice/VoNR), iot, an enterprise net. One subscriber can have several. It's declared in the SMF + UPF (a name + IP pool) and allowed per-subscriber behind Door 2. Purely a core/session concept — not radio (people confuse it with RAT/RAN; it isn't either).
Slice — a separate virtual network (S-NSSAI)
A network slice is a logically isolated virtual network over the same physical core, with its own QoS/isolation — eMBB (broadband), URLLC (low-latency), mMTC (IoT). Identified by SST (+ optional SD), selected by the NSSF. A subscriber can be entitled to several; each slice can carry its own DNNs.
Why a second slice/DNN is "invasive": the identity is threaded through components that must all agree — AMF (plmn_support), NSSF, SMF, UPF, the subscriber record, and the UE's requested NSSAI — and the SD must match everywhere. Any mismatch and the UE is rejected. High blast radius; that's the whole reason it's fiddly, not conceptually hard.
🔬 In the lab — the two planes, then DNNs, then slices
- Planes:
make ran, thenmake cap-cp(HTTP/2 signaling) vsmake cap-up(GTP-U on N3, with TEIDs) —make testpings the DN through the UPF.- DNN:
make provision && make ran→ the UE gets two interfaces (uesimtun0internet 10.45,uesimtun1ims 10.46); the dashboard's "QoS by DNN" shows both.- Slice:
make slice2→ a UE onsst:2; AMF logsS_NSSAI[SST:2], the per-S-NSSAI panel shows sst 1 and sst 2. (Getting it working surfaced the SD-must-match gotcha first-hand.)
(LEARN.md Lessons 3–5.)
Part 3 — Mobility in Motion · the AMF state machine
This is the "mobility" in the name. After attach, the AMF runs the state machine that keeps you connected as you move — and every transition references the identity/subscription state UDM/AUSF established:
- Registered ⇄ Deregistered, Connected ⇄ Idle — the UE drops to idle to save power; the network pages it when downlink data arrives.
- Handover — moving an active session between gNBs (Xn between gNBs, or N2/NGAP via the AMF) without dropping it.
- Tracking-Area Update (TAU) — the UE tells the network it moved to a new area.
- Periodic registration — a keep-alive so the network knows you're still there.
The AMF executes these; UDM holds the anchor (which AMF serves you now), and none of it re-runs full auth — it all keys off the K-hierarchy from Part 1.
🔬 In the lab — actually move a subscriber
- Handover:
make handover— two gNBs; the UE hands over between them; the AMF logsHandoverRequired → Successful handover. The MOBILITY row on the dashboard lights up.- Load/churn:
make load(UES=N) — many UEs registering, idling, reconnecting → realistic signaling (paging, periodic reg) to watch.
(LEARN.md Lesson 6.)
Part 4 — Roaming: identity that travels · SEPP · N32
The cleanest illustration of "home holds your trust":
- UDM / AUSF / UDR stay in the home network (HPLMN).
- The visited network (VPLMN) runs its own AMF / SMF / SEAF.
- When you roam, the visited SEAF reaches back to your AUSF/UDM to authenticate you — over the N32 inter-operator link, secured by a SEPP (Security Edge Protection Proxy) at each carrier's edge.
- The visited network never holds your K; it relays the challenge/response from Part 1 and gets a yes/no. A roaming agreement is a business relationship — technically it's still your home UDM/AUSF doing the identity work, no matter which country's towers you're near.
🔬 In the lab — two carriers, one SIM
make roam(two PLMNs joined only by a SEPP pair) thenmake roam-pr(a home999/70subscriber attaches to the visited001/01network). Watchlogs h-sepp v-sepp | grep established(the N32/TLS edge) and the home SUCI arriving at the visited AMF. (Seeroaming/README.mdfor exactly how far the cross-operator auth gets.) (LEARN.md Lesson 7.)
Part 5 — Observe & Build · the SBA, your lab, and real RF
Service-Based Architecture (SBA). 5GC control-plane NFs talk HTTP/2 + JSON on service interfaces, discovering each other through the NRF (the service registry) — often via an SCP proxy. That's why you can literally packet-capture auth as REST-ish calls (Part 1's lab box). There's no consumer socket to "dial into" — you reach these NFs via their SBI APIs inside a core you operate.
The hands-on ladder (how to go from reading to knowing):
- Software core + simulated UE (Open5GS + UERANSIM/PacketRusher) — register a UE, no radio.
- Provision a subscriber (SUPI + K + OPc) into the UDR.
- Packet-capture the SBA — watch
Nausf/Nudmexchange the vector. - Add an SDR + srsRAN — the same auth over a real air interface, in a Faraday cage.
🔬 In the lab — dashboards, then real radio
- Observe:
make observe→ Grafana atlocalhost:3000— registrations, auth req/fail, paging, sessions per slice/DNN, N3 throughput. The difference between reading one message and watching the network behave.- Real RF (ready, off):
rf/README.md— swap the simulated RAN for SDR + srsRAN. The core doesn't change (srsRAN attaches over the same N2), and Part 1's SUCI becomes an over-the-air observation. Faraday cage only — the CellScope/iseeLora crossover.
(LEARN.md Lesson 8 + the RF rung.)
TL;DR
- The Core answers two questions before anything else: AUSF (are you real?) and UDM (what are you allowed?) — home-network, control-plane, root of trust for all of mobility.
- Auth (Part 1) is 5G-AKA over the SBA; the key K lives in exactly two places and never travels; SUCI encrypts your identity over the air.
- Sessions (Part 2) are the UDM's other door — DNN (which network) and slice (which virtual lane), enforced by SMF/UPF; adding a second of either is "invasive" because six components must agree.
- Mobility (Part 3) is the AMF state machine — handover, paging, TAU — all keyed off the trust auth established.
- Roaming (Part 4) keeps UDM/AUSF at home; the visited network borrows them over SEPP/N32.
- You learn it by building it (Part 5): software core → simulated UE → SBA capture → real SDR. Every concept here has a
maketarget in~/code/mobility_lab— seedocs/LEARN.md.
Cheat sheet
| Concept | Part | Lab command | 3GPP |
|---|---|---|---|
| Auth (AUSF/UDM, 5G-AKA) | 1 | make ran + make cap-cp |
TS 33.501 |
| SUCI concealment | 1 | make suci |
TS 33.501 §6.12 |
| Control vs user plane | 2 | make cap-cp / make cap-up |
— |
| DNN | 2 | make provision && make ran |
TS 23.501 |
| Slice (S-NSSAI) | 2 | make slice2 |
TS 23.501 §5.15 |
| Handover / mobility | 3 | make handover / make load |
TS 23.502 |
| Roaming (SEPP/N32) | 4 | make roam / make roam-pr |
TS 33.501 §13 |
| Observability | 5 | make observe |
— |
| Real RF | 5 | rf/README.md |
— |