04_lab_4g_epc_docker

Part 4: Docker Lab - 4G LTE EPC with Open5GS

Learning Objective: Build a working 4G LTE Evolved Packet Core (EPC) using Open5GS on Docker, and understand the 4G-specific network functions, interfaces, and protocols.

Important

This lab deploys a genuine 4G EPC using 4G-specific network functions: MME, HSS, PCRF, SGW-C, SGW-U, PGW-C (SMF), and PGW-U (UPF). It uses Diameter signaling (S6a, Gx), GTP-C/GTP-U tunneling, and S1AP — the protocols defined by 3GPP for LTE. This is architecturally distinct from the 5G SA lab in Part 6.

Warning

RAN Limitation: UERANSIM only supports 5G NR (gNB + 5G UE). It cannot simulate a 4G eNB. This lab focuses on the EPC core network itself. To connect an actual eNB and UE, you need srsRAN 4G with ZMQ (software radio simulation). Instructions for connecting srsRAN are provided at the end of this lab.


Table of Contents


Prerequisites

Software

docker --version
# Docker version 24.0.0 or higher

docker compose version
# Docker Compose version v2.20.0 or higher

Disk Space

Docker Image Used

Component Image Description
MongoDB mongo:6.0 Subscriber database
Open5GS (all NFs) gradiant/open5gs:2.7.6 Monolithic image containing all Open5GS daemons (4G + 5G)
Open5GS WebUI gradiant/open5gs-webui:2.7.6 Web interface for subscriber management
Note

Unlike Part 6 (5G SA), which uses per-NF images from borieher/open5gs-<nf>, the 4G EPC lab uses the monolithic gradiant/open5gs image. This single image contains all Open5GS binaries — including 4G-specific daemons (open5gs-mmed, open5gs-hssd, open5gs-pcrfd, open5gs-sgwcd, open5gs-sgwud) that are not available as separate container images. Each container runs a different daemon via the command: directive.


4G EPC vs 5G SA — What's Different?

Before diving in, understand why this lab looks different from the 5G SA lab in Part 6:

Aspect 4G EPC (This Lab) 5G SA (Part 6)
Control Plane Hub MME (S1AP, port 36412) AMF (NGAP, port 38412)
Subscriber DB HSS (Diameter S6a) UDM/UDR (SBI HTTP/2)
Policy Engine PCRF (Diameter Gx) PCF (SBI HTTP/2)
Serving Gateway SGW-C + SGW-U (GTP-C, PFCP) Not applicable (no SGW in 5G)
PDN Gateway PGW-C/SMF + PGW-U/UPF (GTP-C, PFCP) SMF + UPF (SBI, PFCP)
Service Discovery None (point-to-point config) NRF (SBI-based registry)
Inter-NF Signaling Diameter + GTP-C SBI (HTTP/2 REST)
Auth Protocol EPS-AKA (KASME) 5G-AKA (KAUSF, SUCI)
RAN Connection eNB via S1AP (SCTP) gNB via NGAP (SCTP)

Lab Architecture

graph TB
    subgraph "Docker Host"
        subgraph "Control Plane Network (172.22.0.0/24)"
            MongoDB[(MongoDB
172.22.0.2)] WebUI[WebUI
172.22.0.3
:9999] MME[MME
172.22.0.10
S1AP :36412
S6a Diameter
S11 GTP-C] HSS[HSS
172.22.0.11
S6a Diameter] PCRF[PCRF
172.22.0.12
Gx Diameter] SGWC[SGW-C
172.22.0.13
S11 GTP-C
S5-C GTP-C
Sxa PFCP] SMF[SMF / PGW-C
172.22.0.14
S5-C GTP-C
Gx Diameter
Sxb PFCP] end subgraph "User Plane Network (172.23.0.0/24)" SGWU[SGW-U
172.23.0.10
S1-U GTP-U
S5-U GTP-U] UPF[UPF / PGW-U
172.23.0.11
S5-U GTP-U
SGi to Internet] end end eNB[eNB
srsRAN 4G
External] Internet[Internet
via ogstun] eNB <-->|S1-MME
S1AP / SCTP
port 36412| MME eNB <-->|S1-U
GTP-U| SGWU MME <-->|S6a
Diameter| HSS MME <-->|S11
GTP-C| SGWC SGWC <-->|Sxa
PFCP| SGWU SGWC <-->|S5-C
GTP-C| SMF SMF <-->|Gx
Diameter| PCRF SMF <-->|Sxb
PFCP| UPF SGWU <-->|S5-U
GTP-U| UPF UPF <-->|SGi / N6
ogstun| Internet HSS <-->|MongoDB| MongoDB WebUI <-->|HTTP| MongoDB style MME fill:#ffe1e1 style HSS fill:#f0e1ff style PCRF fill:#e1ffe1 style SGWC fill:#ffe1f0 style SGWU fill:#ffe1f0 style SMF fill:#fff0e1 style UPF fill:#fff0e1 style MongoDB fill:#f9f style WebUI fill:#9ff

Docker Network Design

Network Subnet Purpose
open5gs_cp 172.22.0.0/24 Control plane: Diameter (S6a, Gx), GTP-C (S11, S5-C), PFCP (Sxa, Sxb), MongoDB
open5gs_up 172.23.0.0/24 User plane: GTP-U (S1-U, S5-U), SGi to Internet
Note

The control plane and user plane are on separate Docker networks, mirroring CUPS (Control/User Plane Separation) as described in Part 1. The MME, SGW-C, and SMF are on the control plane network. The SGW-U and UPF are on the user plane network. SGW-C and SMF bridge both networks via PFCP to program their respective user plane counterparts.


Step 1: Project Setup

mkdir -p ~/open5gs_4g_lab/{config,freeDiameter,log}
cd ~/open5gs_4g_lab

Step 2: Docker Compose Configuration

Create docker-compose.yml:

version: '3.8'

services:
  # === Infrastructure ===
  mongodb:
    image: mongo:6.0
    container_name: open5gs_mongodb
    networks:
      open5gs_cp:
        ipv4_address: 172.22.0.2
    volumes:
      - mongodb_data:/data/db
    restart: unless-stopped

  webui:
    image: gradiant/open5gs-webui:2.7.6
    container_name: open5gs_webui
    networks:
      open5gs_cp:
        ipv4_address: 172.22.0.3
    ports:
      - "9999:9999"
    environment:
      - DB_URI=mongodb://172.22.0.2/open5gs
    depends_on:
      - mongodb
    restart: unless-stopped

  # === 4G EPC (Evolved Packet Core) - Control Plane ===
  hss:
    image: gradiant/open5gs:2.7.6
    container_name: open5gs_hss
    command: open5gs-hssd
    volumes:
      - ./config/hss.yaml:/opt/open5gs/etc/open5gs/hss.yaml
      - ./freeDiameter/hss.conf:/opt/open5gs/etc/freeDiameter/hss.conf
    networks:
      open5gs_cp:
        ipv4_address: 172.22.0.11
    environment:
      - DB_URI=mongodb://172.22.0.2/open5gs
    depends_on:
      - mongodb
    restart: unless-stopped

  pcrf:
    image: gradiant/open5gs:2.7.6
    container_name: open5gs_pcrf
    command: open5gs-pcrfd
    volumes:
      - ./config/pcrf.yaml:/opt/open5gs/etc/open5gs/pcrf.yaml
      - ./freeDiameter/pcrf.conf:/opt/open5gs/etc/freeDiameter/pcrf.conf
    networks:
      open5gs_cp:
        ipv4_address: 172.22.0.12
    environment:
      - DB_URI=mongodb://172.22.0.2/open5gs
    depends_on:
      - mongodb
    restart: unless-stopped

  mme:
    image: gradiant/open5gs:2.7.6
    container_name: open5gs_mme
    command: open5gs-mmed
    volumes:
      - ./config/mme.yaml:/opt/open5gs/etc/open5gs/mme.yaml
      - ./freeDiameter/mme.conf:/opt/open5gs/etc/freeDiameter/mme.conf
    networks:
      open5gs_cp:
        ipv4_address: 172.22.0.10
    ports:
      - "36412:36412/sctp"
    depends_on:
      - hss
    cap_add:
      - NET_ADMIN
    restart: unless-stopped

  sgwc:
    image: gradiant/open5gs:2.7.6
    container_name: open5gs_sgwc
    command: open5gs-sgwcd
    volumes:
      - ./config/sgwc.yaml:/opt/open5gs/etc/open5gs/sgwc.yaml
    networks:
      open5gs_cp:
        ipv4_address: 172.22.0.13
    depends_on:
      - mme
    restart: unless-stopped

  smf:
    image: gradiant/open5gs:2.7.6
    container_name: open5gs_smf
    command: open5gs-smfd
    volumes:
      - ./config/smf.yaml:/opt/open5gs/etc/open5gs/smf.yaml
      - ./freeDiameter/smf.conf:/opt/open5gs/etc/freeDiameter/smf.conf
    networks:
      open5gs_cp:
        ipv4_address: 172.22.0.14
      open5gs_up:
        ipv4_address: 172.23.0.14
    depends_on:
      - pcrf
    restart: unless-stopped

  # === 4G EPC (Evolved Packet Core) - User Plane ===
  sgwu:
    image: gradiant/open5gs:2.7.6
    container_name: open5gs_sgwu
    command: open5gs-sgwud
    volumes:
      - ./config/sgwu.yaml:/opt/open5gs/etc/open5gs/sgwu.yaml
    networks:
      open5gs_cp:
        ipv4_address: 172.22.0.15
      open5gs_up:
        ipv4_address: 172.23.0.10
    ports:
      - "2152:2152/udp"
    depends_on:
      - sgwc
    restart: unless-stopped

  upf:
    image: gradiant/open5gs:2.7.6
    container_name: open5gs_upf
    command: open5gs-upfd
    volumes:
      - ./config/upf.yaml:/opt/open5gs/etc/open5gs/upf.yaml
    networks:
      open5gs_cp:
        ipv4_address: 172.22.0.16
      open5gs_up:
        ipv4_address: 172.23.0.11
    cap_add:
      - NET_ADMIN
    privileged: true
    sysctls:
      - net.ipv4.ip_forward=1
    depends_on:
      - smf
    restart: unless-stopped

networks:
  open5gs_cp:
    driver: bridge
    ipam:
      config:
        - subnet: 172.22.0.0/24
  open5gs_up:
    driver: bridge
    ipam:
      config:
        - subnet: 172.23.0.0/24

volumes:
  mongodb_data:
Tip

Notice the key differences from a 5G SA compose file:

  • No NRF, SCP, AUSF, UDM, UDR, NSSF, BSF — these are 5G SA-only NFs
  • HSS and PCRF are 4G-specific, using Diameter (not SBI)
  • SGW-C and SGW-U exist only in 4G (5G SA has no serving gateway)
  • MME replaces AMF, listening on S1AP port 36412 (not NGAP 38412)
  • The command: directive tells the monolithic image which daemon to run

Step 3: Open5GS EPC Configurations

Create each config file in config/:

MME (config/mme.yaml)

The MME is the central control plane hub — it handles UE attach, authentication (via HSS), bearer setup (via SGW-C), and paging.

logger:
  level: info

mme:
  freeDiameter: /opt/open5gs/etc/freeDiameter/mme.conf
  s1ap:
    server:
      - address: 172.22.0.10
  gtpc:
    server:
      - address: 172.22.0.10
    client:
      sgwc:
        - address: 172.22.0.13
      smf:
        - address: 172.22.0.14
  gummei:
    - plmn_id:
        mcc: 001
        mnc: 01
      mme_gid: 2
      mme_code: 1
  tai:
    - plmn_id:
        mcc: 001
        mnc: 01
      tac: 1
  security:
    integrity_order: [EIA2, EIA1, EIA0]
    ciphering_order: [EEA2, EEA1, EEA0]
Tip

S1AP listens on port 36412 (SCTP) by default. This is the 4G control plane entry point — the equivalent of NGAP port 38412 in 5G SA. The gtpc.client section tells MME where SGW-C and PGW-C/SMF are, using GTP-C (not SBI). There is no NRF-based discovery in 4G — all peer addresses are configured explicitly.

Warning

Notice ciphering_order puts EEA2 first (AES-128). Never put EEA0 (null cipher) first in production — that enables the downgrade attack discussed in Part 8.

HSS (config/hss.yaml)

The HSS is the subscriber database — it stores IMSI, K, OPc, and subscriber profiles. It communicates with MME over the S6a Diameter interface.

logger:
  level: info

hss:
  freeDiameter: /opt/open5gs/etc/freeDiameter/hss.conf

db_uri: mongodb://172.22.0.2/open5gs

PCRF (config/pcrf.yaml)

The PCRF enforces QoS policies and charging rules. It communicates with PGW-C/SMF over the Gx Diameter interface.

logger:
  level: info

pcrf:
  freeDiameter: /opt/open5gs/etc/freeDiameter/pcrf.conf

db_uri: mongodb://172.22.0.2/open5gs

SGW-C (config/sgwc.yaml)

The Serving Gateway Control Plane manages bearer contexts and acts as the mobility anchor for inter-eNB handovers. It communicates with MME over S11 (GTP-C), with PGW-C/SMF over S5-C (GTP-C), and programs SGW-U over Sxa (PFCP).

logger:
  level: info

sgwc:
  gtpc:
    server:
      - address: 172.22.0.13
  pfcp:
    server:
      - address: 172.22.0.13
    client:
      sgwu:
        - address: 172.22.0.15

SGW-U (config/sgwu.yaml)

The Serving Gateway User Plane forwards user data between the eNB (S1-U) and PGW-U (S5-U). It is programmed by SGW-C over Sxa (PFCP).

logger:
  level: info

sgwu:
  pfcp:
    server:
      - address: 172.22.0.15
  gtpu:
    server:
      - address: 172.23.0.10
Note

The SGW-U's GTP-U address (172.23.0.10) is on the user plane network — this is where the eNB sends S1-U user data. In a real deployment, this address would be reachable from the RAN.

SMF / PGW-C (config/smf.yaml)

In Open5GS, the SMF binary handles both the 5G SMF role and the 4G PGW-C role. In this 4G lab, it acts as PGW-C — managing PDN sessions, IP allocation, and policy enforcement (via PCRF over Gx Diameter). It programs the UPF/PGW-U over Sxb (PFCP).

logger:
  level: info

smf:
  freeDiameter: /opt/open5gs/etc/freeDiameter/smf.conf
  gtpc:
    server:
      - address: 172.22.0.14
  pfcp:
    server:
      - address: 172.23.0.14
    client:
      upf:
        - address: 172.23.0.11
  subnet:
    - addr: 10.45.0.1/16
      dnn: internet
  dns:
    - 8.8.8.8
    - 8.8.4.4
Important

The SMF receives S5-C GTP-C from SGW-C (not SBI from AMF like in 5G SA). It also uses Diameter Gx to talk to PCRF (not SBI to PCF). This is the key architectural difference — 4G uses legacy protocols, not HTTP/2.

UPF / PGW-U (config/upf.yaml)

In Open5GS, the UPF binary handles both 5G UPF and 4G PGW-U roles. In this 4G lab, it acts as PGW-U — forwarding user data to the Internet via the ogstun TUN interface. It is programmed by PGW-C/SMF over Sxb (PFCP).

logger:
  level: info

upf:
  pfcp:
    server:
      - address: 172.23.0.11
  gtpu:
    server:
      - address: 172.23.0.11
  subnet:
    - addr: 10.45.0.1/16
      dnn: internet

Step 4: freeDiameter Configuration

4G EPC uses Diameter for signaling between MME↔HSS (S6a) and PGW-C↔PCRF (Gx). These require freeDiameter configuration files. Create each file in freeDiameter/:

Note

What is freeDiameter? It is the open-source Diameter protocol stack used by Open5GS. In 5G SA, NFs communicate over SBI (HTTP/2 REST APIs) and don't need Diameter at all. In 4G, Diameter is the backbone of control plane signaling — this is one of the fundamental protocol differences between generations.

MME Diameter (freeDiameter/mme.conf)

Identity = "mme.localdomain";
Realm = "localdomain";
TLS_Cred = "/opt/open5gs/etc/freeDiameter/default.cert.pem",
            "/opt/open5gs/etc/freeDiameter/default.key.pem";
TLS_CA = "/opt/open5gs/etc/freeDiameter/default.cacert.pem";
No_SCTP;

ConnectPeer = "hss.localdomain" { ConnectTo = "172.22.0.11"; Port = 3868; No_TLS; };

LoadExtension = "dbg_msg_dumps.fdx" : "0x8888";
LoadExtension = "dict_rfc5777.fdx";
LoadExtension = "dict_mip6i.fdx";
LoadExtension = "dict_nasreq.fdx";
LoadExtension = "dict_nas_mipv6.fdx";
LoadExtension = "dict_dcca.fdx";
LoadExtension = "dict_dcca_3gpp.fdx";
LoadExtension = "dict_s6a.fdx";

HSS Diameter (freeDiameter/hss.conf)

Identity = "hss.localdomain";
Realm = "localdomain";
TLS_Cred = "/opt/open5gs/etc/freeDiameter/default.cert.pem",
            "/opt/open5gs/etc/freeDiameter/default.key.pem";
TLS_CA = "/opt/open5gs/etc/freeDiameter/default.cacert.pem";
No_SCTP;

ConnectPeer = "mme.localdomain" { ConnectTo = "172.22.0.10"; Port = 3868; No_TLS; };

LoadExtension = "dbg_msg_dumps.fdx" : "0x8888";
LoadExtension = "dict_rfc5777.fdx";
LoadExtension = "dict_mip6i.fdx";
LoadExtension = "dict_nasreq.fdx";
LoadExtension = "dict_nas_mipv6.fdx";
LoadExtension = "dict_dcca.fdx";
LoadExtension = "dict_dcca_3gpp.fdx";
LoadExtension = "dict_s6a.fdx";

SMF / PGW-C Diameter (freeDiameter/smf.conf)

Identity = "smf.localdomain";
Realm = "localdomain";
TLS_Cred = "/opt/open5gs/etc/freeDiameter/default.cert.pem",
            "/opt/open5gs/etc/freeDiameter/default.key.pem";
TLS_CA = "/opt/open5gs/etc/freeDiameter/default.cacert.pem";
No_SCTP;

ConnectPeer = "pcrf.localdomain" { ConnectTo = "172.22.0.12"; Port = 3868; No_TLS; };

LoadExtension = "dbg_msg_dumps.fdx" : "0x8888";
LoadExtension = "dict_rfc5777.fdx";
LoadExtension = "dict_mip6i.fdx";
LoadExtension = "dict_nasreq.fdx";
LoadExtension = "dict_nas_mipv6.fdx";
LoadExtension = "dict_dcca.fdx";
LoadExtension = "dict_dcca_3gpp.fdx";
LoadExtension = "dict_dcca_3gpp/dict_gx.fdx";

PCRF Diameter (freeDiameter/pcrf.conf)

Identity = "pcrf.localdomain";
Realm = "localdomain";
TLS_Cred = "/opt/open5gs/etc/freeDiameter/default.cert.pem",
            "/opt/open5gs/etc/freeDiameter/default.key.pem";
TLS_CA = "/opt/open5gs/etc/freeDiameter/default.cacert.pem";
No_SCTP;

ConnectPeer = "smf.localdomain" { ConnectTo = "172.22.0.14"; Port = 3868; No_TLS; };

LoadExtension = "dbg_msg_dumps.fdx" : "0x8888";
LoadExtension = "dict_rfc5777.fdx";
LoadExtension = "dict_mip6i.fdx";
LoadExtension = "dict_nasreq.fdx";
LoadExtension = "dict_nas_mipv6.fdx";
LoadExtension = "dict_dcca.fdx";
LoadExtension = "dict_dcca_3gpp.fdx";
LoadExtension = "dict_dcca_3gpp/dict_gx.fdx";
Warning

These configs use No_TLS for simplicity in the lab. In production, Diameter links must use TLS/DTLS — unencrypted Diameter is a critical vulnerability (see Part 8: Diameter Exploitation threat).


Step 5: Launch the EPC

# Start infrastructure first
docker compose up -d mongodb
sleep 3

# Start HSS and PCRF (Diameter servers must be up before clients)
docker compose up -d hss pcrf
sleep 3

# Start remaining control plane NFs
docker compose up -d mme sgwc smf
sleep 2

# Start user plane NFs
docker compose up -d sgwu upf

# Start WebUI
docker compose up -d webui

# Verify all containers are running
docker compose ps

Expected Output

NAME             IMAGE                        STATUS
open5gs_hss      gradiant/open5gs:2.7.6       Up
open5gs_mme      gradiant/open5gs:2.7.6       Up
open5gs_mongodb  mongo:6.0                    Up
open5gs_pcrf     gradiant/open5gs:2.7.6       Up
open5gs_sgwc     gradiant/open5gs:2.7.6       Up
open5gs_sgwu     gradiant/open5gs:2.7.6       Up
open5gs_smf      gradiant/open5gs:2.7.6       Up
open5gs_upf      gradiant/open5gs:2.7.6       Up
open5gs_webui    gradiant/open5gs-webui:2.7.6 Up

Check Diameter Associations

Verify that MME has established a Diameter S6a connection to HSS:

docker compose logs mme | grep -i "diameter\|s6a\|connected"

Verify that SMF/PGW-C has established a Diameter Gx connection to PCRF:

docker compose logs smf | grep -i "diameter\|gx\|connected"

Check PFCP Associations

Verify SGW-C ↔ SGW-U (Sxa) and SMF ↔ UPF (Sxb) PFCP sessions:

docker compose logs sgwc | grep -i "pfcp\|associated"
docker compose logs smf | grep -i "pfcp\|associated"

Check S1AP Readiness

Verify MME is listening for eNB connections on S1AP:

docker compose logs mme | grep -i "s1ap\|sctp"

Expected: MME is listening on 172.22.0.10:36412 (SCTP).


Step 6: Register a Subscriber

  1. Open browser: http://localhost:9999
  2. Login:
    • Username: admin
    • Password: 1423
  3. Click Subscribers -> + (Add)
  4. Fill in subscriber details:
    • IMSI: 001010000000001
    • K: 465B5CE8B199B49FAA5F0A2EE238A6BC
    • OPc: E8ED289DEBA952E4283B54E88E6183CA
    • APN/DNN: internet
  5. Click SAVE
Caution

These credentials are stored in the HSS (MongoDB). When an eNB sends an Attach Request, MME queries HSS over Diameter S6a to retrieve authentication vectors (RAND, AUTN, XRES, KASME). Any mismatch in K/OPc between the HSS and the SIM/UE causes authentication failure.


Step 7: Verify EPC Health

Even without an eNB connected, you can verify the EPC is functioning correctly:

Check All Diameter Peers

# MME should show HSS as a connected peer
docker compose logs mme 2>&1 | grep -i "peer\|hss"

# SMF should show PCRF as a connected peer
docker compose logs smf 2>&1 | grep -i "peer\|pcrf"

Check PFCP Sessions

# SGW-C should show SGW-U as an associated UPF
docker compose logs sgwc 2>&1 | grep -i "pfcp\|sgwu\|associated"

# SMF should show UPF as an associated UPF
docker compose logs smf 2>&1 | grep -i "pfcp\|upf\|associated"

Check UPF TUN Interface

docker exec -it open5gs_upf ip addr show ogstun

Expected:

ogstun: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1400
    inet 10.45.0.1/16 scope global ogstun

Test MongoDB Subscriber Data

docker exec -it open5gs_mongodb mongosh --eval \
  'db = db.getSiblingDB("open5gs"); db.subscribers.find().pretty()'

You should see the subscriber record with IMSI, K, OPc, and APN.


Step 8: Packet Capture and Protocol Analysis

Even without a connected eNB, you can capture and analyze the 4G-specific signaling between core NFs.

Capture Diameter S6a (MME <-> HSS)

docker exec -it open5gs_mme tcpdump -i any -w /tmp/diameter_s6a.pcap tcp port 3868
# Let it run for 30 seconds to capture Diameter keepalives (CER/CEA, DWR/DWA)
# Ctrl+C to stop
docker cp open5gs_mme:/tmp/diameter_s6a.pcap .

Wireshark filter: diameter

You should see:

Capture Diameter Gx (SMF/PGW-C <-> PCRF)

docker exec -it open5gs_smf tcpdump -i any -w /tmp/diameter_gx.pcap tcp port 3868
docker cp open5gs_smf:/tmp/diameter_gx.pcap .

Wireshark filter: diameter

Capture PFCP (Control <-> User Plane)

# Sxa: SGW-C <-> SGW-U
docker exec -it open5gs_sgwc tcpdump -i any -w /tmp/pfcp_sxa.pcap udp port 8805
docker cp open5gs_sgwc:/tmp/pfcp_sxa.pcap .

# Sxb: SMF <-> UPF
docker exec -it open5gs_smf tcpdump -i any -w /tmp/pfcp_sxb.pcap udp port 8805
docker cp open5gs_smf:/tmp/pfcp_sxb.pcap .

Wireshark filter: pfcp

You should see:

Tip

Comparison with 5G SA: In 5G SA (Part 6), inter-NF communication uses SBI HTTP/2 on port 7777. Here in 4G, you see Diameter on port 3868 and GTP-C on port 2123 instead. Capturing these protocol differences is a key learning objective of this lab.


Connecting srsRAN 4G (Reference)

To complete the end-to-end 4G data path, you need a 4G eNB and UE simulator. srsRAN 4G with ZMQ (zero-message-queue) enables software-only LTE simulation without radio hardware.

Building srsRAN 4G

# Clone srsRAN 4G
git clone https://github.com/srsran/srsRAN_4G.git
cd srsRAN_4G

# Build with ZMQ support (software radio)
mkdir build && cd build
cmake .. -DENABLE_ZMQ=ON
make -j$(nproc)

# Key binaries:
# ./srsepc/src/srsepc   - Standalone EPC (not needed, we use Open5GS)
# ./srsenb/src/srsenb   - LTE eNB
# ./srsue/src/srsue     - LTE UE

srsRAN eNB Configuration (Connecting to Open5GS MME)

Key settings in enb.conf:

[enb]
mcc = 001
mnc = 01
mme_addr = 172.22.0.10    # Open5GS MME IP
gtp_bind_addr = 127.0.1.1 # Local GTP-U bind
s1c_bind_addr = 127.0.1.1 # Local S1AP bind
n_prb = 50

[rf]
device_name = zmq
device_args = fail_on_disconnect=true,tx_port=tcp://*:2000,rx_port=tcp://localhost:2001,id=enb,base_srate=23.04e6

srsRAN UE Configuration

Key settings in ue.conf:

[usim]
mode = soft
algo = milenage
opc  = E8ED289DEBA952E4283B54E88E6183CA
k    = 465B5CE8B199B49FAA5F0A2EE238A6BC
imsi = 001010000000001

[rf]
device_name = zmq
device_args = tx_port=tcp://*:2001,rx_port=tcp://localhost:2000,id=ue,base_srate=23.04e6
Note

The K, OPc, and IMSI values in the srsRAN UE config must match what you registered in the Open5GS WebUI (Step 6).

Expected Flow When Connected

UE ──[Uu/ZMQ]──> eNB ──[S1-MME/SCTP:36412]──> MME
                                                  │
                              MME ──[S6a/Diameter]──> HSS (auth vectors)
                              MME ──[S11/GTP-C]──> SGW-C
                              SGW-C ──[S5-C/GTP-C]──> SMF/PGW-C
                              SMF ──[Gx/Diameter]──> PCRF (QoS policy)
                              SMF ──[Sxb/PFCP]──> UPF/PGW-U (forwarding rules)
                              SGW-C ──[Sxa/PFCP]──> SGW-U (forwarding rules)

UE ──[Uu/ZMQ]──> eNB ──[S1-U/GTP-U]──> SGW-U ──[S5-U/GTP-U]──> UPF/PGW-U ──[SGi]──> Internet

Resources

Resource URL
srsRAN 4G GitHub https://github.com/srsran/srsRAN_4G
Open5GS + srsRAN Tutorial https://open5gs.org/open5gs/docs/tutorial/02-srsran-4g/
srsRAN ZMQ Guide https://docs.srsran.com/projects/4g/en/latest/app_notes/source/zeromq/source/index.html

Troubleshooting

Diameter Peers Not Connecting

docker compose logs hss | grep -i "error\|failed\|diameter"
docker compose logs mme | grep -i "error\|failed\|diameter"

Common causes:

PFCP Association Failed

docker compose logs sgwc | grep -i "pfcp\|error"
docker compose logs smf | grep -i "pfcp\|error"

Common causes:

UPF Cannot Create ogstun

docker exec -it open5gs_upf ip addr show ogstun

Fix: UPF needs privileged: true and NET_ADMIN capability for TUN device creation. Verify these are set in docker-compose.yml.

No Internet from UPF

# Check NAT rules
docker exec -it open5gs_upf iptables -t nat -L

# Add NAT if missing
docker exec -it open5gs_upf iptables -t nat -A POSTROUTING \
  -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE

Cleanup

docker compose down -v  # -v removes volumes (subscriber data)

Exercises

  1. Diameter Analysis: Capture Diameter traffic on port 3868 between MME and HSS. Open in Wireshark and identify the CER/CEA handshake. What Application-ID is used for S6a? (Answer: 16777251 — 3GPP S6a/S6d)

  2. PFCP Inspection: Capture PFCP traffic on port 8805 between SGW-C and SGW-U. Find the PFCP Association Setup Request. What node ID does SGW-C advertise?

  3. Compare Protocols: In the 5G SA lab (Part 6), inter-NF communication uses SBI HTTP/2 on port 7777. In this 4G lab, which ports and protocols carry the equivalent signaling? Fill in:

    • AMF ↔ UDM (5G) maps to ______ using ___ protocol on port ___ (4G)
    • AMF ↔ SMF (5G SBI) maps to ______ using ___ protocol on port ___ (4G)
  4. Security Gap Analysis: Examine the freeDiameter configs. What setting makes the Diameter links insecure? What would you change for production? (Hint: look at No_TLS)

  5. GTP-C Inspection: Capture GTP-C traffic (UDP port 2123) between MME and SGW-C. This is the S11 interface that carries bearer management signaling. Compare this to SBI in 5G SA.


Summary

You have successfully:

Next: Part 5: 5G NSA Concepts ->