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, make command 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's docs/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:

  1. 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.
  2. 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.
  3. "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.
  4. 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).
  5. 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 userplane

Blue = 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), or make up && make provision. make ps shows ~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:

  1. Can we cryptographically prove they're genuine (and can they prove the network is genuine)?AUSF
  2. 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 → UDM on purpose:

  1. 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.
  2. It's one nested transaction. The AMF opens Nausf_UEAuthentication with 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?

AUSF — the trust anchor. Is this identity who it claims, right now, cryptographically?

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
  1. UE powers on — USIM holds K and SUPI (a secret only it and your carrier know).
  2. Registration — UE sends SUCI (SUPI encrypted with the home public key) so nobody sniffing radio reads who you are.
  3. AMF → AUSF → UDM — the claim goes to the bouncer, who forwards to the membership DB.
  4. 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.
  5. AUSF relays RAND/AUTN down to the UE ("solve this").
  6. USIM checks AUTN (so the network proves itself too — mutual auth), computes RES*, sends it up.
  7. AUSF verifies RES* == XRES*. Match ⇒ keys cascade K_SEAF → K_AMF → radio/NAS keys.
  8. 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.

  1. Your side — inside the SIM's tamper-resistant secure element. You can hand it a RAND and get an answer; there is no command to read K out.
  2. 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

🔬 In the lab — watch auth, then watch privacy


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 sess

Door 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

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


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:

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


Part 4 — Roaming: identity that travels · SEPP · N32

The cleanest illustration of "home holds your trust":

🔬 In the lab — two carriers, one SIM
make roam (two PLMNs joined only by a SEPP pair) then make roam-pr (a home 999/70 subscriber attaches to the visited 001/01 network). Watch logs h-sepp v-sepp | grep established (the N32/TLS edge) and the home SUCI arriving at the visited AMF. (See roaming/README.md for 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):

  1. Software core + simulated UE (Open5GS + UERANSIM/PacketRusher) — register a UE, no radio.
  2. Provision a subscriber (SUPI + K + OPc) into the UDR.
  3. Packet-capture the SBA — watch Nausf/Nudm exchange the vector.
  4. Add an SDR + srsRAN — the same auth over a real air interface, in a Faraday cage.

🔬 In the lab — dashboards, then real radio


TL;DR

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