Skip to content

Getting Started with go-gtp5gnl: Userspace Control of GTP-U for free5GC UPF

Note

Author: Kai-Xu, Zhan
Date: 2025/11/12


Introduction

The go-gtp5gnl project bridges user-space control and kernel-space GTP-U data forwarding by providing a Go-native Netlink interface for the Linux gtp5g kernel module. This enables free5GC’s UPF—or any custom UPF implementation—to manipulate GTP-U tunnels, Packet Detection Rules (PDRs), Forwarding Action Rules (FARs), and QoS Enforcement Rules (QERs) directly from Go code.
This article provides a hands-on walkthrough of using go-gtp5gnl to observe, modify, and verify PFCP-controlled GTP-U state in free5GC. You will learn how to list, edit, and recreate rules in real time to understand how the UPF enforces 5G user-plane logic.

Goal: By the end, you will understand how go-gtp5gnl connects the 3GPP PFCP control plane to kernel-level forwarding on the N3/N6 interfaces—making it an indispensable tool for debugging and research.


Environment Setup

Prerequisites


Building go-gtp5gnl

Clone and build the project to obtain the command-line utility gtp5g-tunnel:

git clone https://github.com/free5gc/go-gtp5gnl.git
cd go-gtp5gnl/
go build -o gtp5g-tunnel ./cmd/gogtp5g-tunnel

Understanding Go-gtp5gnl Commands

Command Overview

The go-gtp5gnl library and CLI expose Netlink interfaces to manipulate kernel objects representing PDR, FAR, and QER entities.

  • PDR (Packet Detection Rule) – Identifies packets belonging to a PDU Session.
  • FAR (Forwarding Action Rule) – Specifies what action is applied.
  • QER (QoS Enforcement Rule) – Defines QoS parameters.

Each rule type supports the operations add, get, mod, del, and list.

Operation Description
add Create a new rule entry in the kernel.
get Retrieve current rule(s) from kernel.
mod Modify attributes of an existing rule.
del Delete a rule from the kernel.
list Display all rules of a given type.

Usage

  • List all PDR/FAR/QER:
    sudo ./gtp5g-tunnel list [pdr/far/qer]
    
  • Get/Del/Add/Mod PDR/FAR/QER:
    sudo ./gtp5g-tunnel [get/del/add/mod] [PDR/FAR/QER] [interface_name] [seid] [id] [option]
    

Practical Usage of Go-gtp5gnl

Before testing go-gtp5gnl, verify that you can successfully create a UE instance using UERANSIM and attach it to the free5GC core network. A successful registration and PDU Session establishment indicate that the environment is ready for go-gtp5gnl testing.

Inspecting PDRs

Use sudo ./gtp5g-tunnel list pdr to list all PDRs. The output will look like this:

{
"ID": 3,
"Precedence": 128,
"PDI": {
  "SrcIntf": null,
  "UEAddr": "10.60.0.1",
  "FTEID": {
    "TEID": 2,
    "GTPuAddr": "192.168.56.102"
  },
  "SDF": {
    "FD": {
      "Action": 1,
      "Dir": 2,
      "Proto": 255,
      "Src": {
        "IP": "0.0.0.0",
        "Mask": "AAAAAA=="
      },
      "Dst": {
        "IP": "1.1.1.1",
        "Mask": null
      },
      "SrcPorts": null,
      "DstPorts": null
    },
    "TTC": null,
    "SPI": null,
    "FL": null,
    "BID": null
  },
  "EPFs": null
},
"OuterHdrRemoval": 0,
"FARID": 3,
"QERID": [
  1,
  3
],
"URRID": [
  1,
  2,
  8,
  7
],
"SEID": 1,
"PDNType": null
}, 
{
"ID": 4,
"Precedence": 128,
"PDI": {
  "SrcIntf": null,
  "UEAddr": "10.60.0.1",
  "FTEID": null,
  "SDF": {
    "FD": {
      "Action": 1,
      "Dir": 2,
      "Proto": 255,
      "Src": {
        "IP": "1.1.1.1",
        "Mask": null
      },
      "Dst": {
        "IP": "0.0.0.0",
        "Mask": "AAAAAA=="
      },
      "SrcPorts": null,
      "DstPorts": null
    },
    "TTC": null,
    "SPI": null,
    "FL": null,
    "BID": null
  },
  "EPFs": null
},
"OuterHdrRemoval": null,
"FARID": 4,
"QERID": [
  1,
  3
],
"URRID": [
  1,
  2,
  8,
  7
],
"SEID": 1,
"PDNType": null
}

Example truncated for brevity — other PDR entries omitted.

PDR Information Elements

Parameter Description
ID Unique identifier of the PDR.
Must be unique within the same SEID.
Precedence Rule priority (smaller numbers have higher priority).
SEID Session Endpoint ID that identifies the PFCP Session this rule belongs to.
All PDRs for the same UE PDU Session share the same SEID.
PDI Packet Detection Information defines which packets match this rule.

PDI Details

Parameter Description
SrcIntf The source interface of the incoming packet.
UEAddr UE IPv4 address.
This PDR handles traffic to or from this IP.
FTEID Defines the GTP-U tunnel endpoint by combining a TEID and an IP address
SDF Specifies the service data flow filter(s) used for packet detection.

FTEID (Fully Qualified Tunnel Endpoint Identifier) Details

Parameter Description
TEID Tunnel Endpoint ID is an identifier for the GTP-U tunnel.
Used to recognize packets received from the gNB.
GTPuAddr Local GTP-U address.
The N3 interface IP address of the UPF that listens for GTP-U packets from the gNB.

Important Rule:

  • FTEID present → Uplink traffic (GTP-U packets from gNB/UE).
  • FTEID null → Downlink traffic (plain IP packets from N6/Internet).

SDF (Service Data Flow) Details

Parameter Description
Action SDF action.
1 = This rule permits matching traffic.
Dir Traffic direction.
2 = Out
Proto IP protocol number
Src Source Address
  • IP
  • Mask
    Dst Destination Address
    • IP
    • Mask

      Inspecting FARs

      The PDR defines which packets are detected by the UPF. Packets that match this PDR are then handled according to their associated Forwarding Action Rule (FAR), which specifies how the UPF should process or forward them. Now, let’s use sudo ./gtp5g-tunnel list far to examine the configured FARs and see how these packets are processed.

      {
      "ID": 3,
      "Action": 2,
      "Param": null,
      "PDRIDs": [
        3
      ],
      "BARID": null,
      "SEID": 1
      },
      {
      "ID": 1,
      "Action": 2,
      "Param": null,
      "PDRIDs": [
        1
      ],
      "BARID": null,
      "SEID": 1
      },
      {
      "ID": 4,
      "Action": 2,
      "Param": {
        "Creation": {
          "Desc": 256,
          "TEID": 1,
          "PeerAddr": "192.168.56.101",
          "Port": 2152
        },
        "Policy": null,
        "TosTc": 0
      },
      "PDRIDs": [
        4
      ],
      "BARID": null,
      "SEID": 1
      },
      

      Example truncated for brevity — other FAR entries omitted.

      FAR Information Elements

      Parameter Description
      ID Unique identifier of the FAR.
      Must be unique within the same SEID.
      Action Apply action.
      1 = drop the pakcets
      2 = Forward the packets.
      SEID Session Endpoint ID that identifies the PFCP Session this rule belongs to.
      All FARs for the same UE PDU Session share the same SEID.
      Param Forwarding Parameters.

      From the above demonstration, PDR with ID 3 is an uplink rule, matching GTP-U packets arriving from the RAN. Its corresponding FAR (FAR ID 3) has no forwarding parameters, meaning the packets are decapsulated and delivered locally toward the data network. Conversely, PDR with ID 4 is a downlink rule, where the associated FAR (FAR ID 4) contains forwarding parameters (TEID and peer address) used to encapsulate and send packets back to the gNB through GTP-U.


      Inspecting QERs

      Next, let's use sudo ./gtp5g-tunnel list qer to examine the configured QERs.

      {
      "ID": 3,
      "Gate": 0,
      "MBR": {
        "ULHigh": 812,
        "ULLow": 128,
        "UL_Kbps": 208000,
        "DLHigh": 812,
        "DLLow": 128,
        "DL_Kbps": 208000
      },
      "GBR": {
        "ULHigh": 0,
        "ULLow": 0,
        "UL_Kbps": 0,
        "DLHigh": 0,
        "DLLow": 0,
        "DL_Kbps": 0
      },
      "CorrID": 0,
      "RQI": 0,
      "QFI": 2,
      "PPI": 0,
      "PDRIDs": [
        4,
        3
      ],
      "SEID": 1
      },
      

      Example truncated for brevity — other QER entries omitted.

      QER Information Elements

      Parameter Description
      ID Unique identifier of the QER.
      Must be unique within the same SEID.
      QFI QoS Flow Identifier.
      Identifies the QoS Flow within a PDU Session.
      Value range: (0 ~ 63)
      RQI Reflective QoS Indicator.
      Indicates whether reflective QoS is triggered.
      0 = Not triggered.
      1 = Triggered.
      PPP Packet Per Flow presence flag.
      Specifies whether the Packet Per Flow Indicator (PPI) is included in the QER.
      0 = Not present.
      1 = Present.
      PPI Packet Per Flow Indicator.
      Marks packets with a priority level or DSCP value for differentiated handling.
      Value range: (0 ~ 7)
      SEID Session Endpoint Identifier identifying the PFCP session this QER belongs to.

      MBR and GBR Details

      Parameter Description
      ULHigh / ULLow Encoded uplink maximum (or guaranteed) bit rate split into two fields per 3GPP spec (High/Low octets).
      UL_Kbps Readable uplink bit rate in Kbps derived from the encoded values.
      DLHigh / DLLow Encoded downlink maximum (or guaranteed) bit rate.
      DL_Kbps Readable downlink bit rate in Kbps derived from the encoded values.

      Modifying FAR

      After understanding how to inspect PDRs, FARs, and QERs, let’s move on to modify an existing FAR (Forwarding Action Rule) to block traffic and then restore it.

      Step 1: Verify initial state (UE should be reachable)

      # Executed on UERANSIM
      ping 1.1.1.1 -I ueransim0 -c 5
      

      If the UPF and UERANSIM are properly connected, you should see successful ping replies from 1.1.1.1.

      Step 2: Modify FAR 3 – change action from 2 (Forward) to 1 (Drop)

      # Executed on free5GC
      sudo ./gtp5g-tunnel mod far upfgtp 1:3 --action 1
      

      This updates FAR ID 3 under SEID 1 to drop packets instead of forwarding them.

      Step 3: Re-test connectivity (ping should fail or timeout)

      # Executed on UERANSIM
      ping 1.1.1.1 -I ueransim0 -c 5
      

      Since this PDR defines the uplink traffic path from the UE (via gNB) toward the data network, removing it prevents packets from reaching the external destination.

      Step 4: Restore FAR 3 to forwarding state

      # Executed on free5GC
      sudo ./gtp5g-tunnel mod far upfgtp 1:3 --action 2
      

      Step 5: Test again (connectivity should be restored)

      # Executed on UERANSIM
      ping 1.1.1.1 -I ueransim0 -c 5
      

      If pings succeed again, it confirms that the mod operation has correctly re-applied the forwarding rule.

      Deleting and Re-Adding PDRs

      Next, you’ll experiment with removing and re-adding PDRs (Packet Detection Rules) to observe how the UPF handles missing or re-created rules.

      Step 1: Delete PDR 1 and PDR 3

      These rules typically correspond to the uplink flow for your UE session.

      # Executed on free5GC
      sudo ./gtp5g-tunnel del pdr upfgtp 1:1
      sudo ./gtp5g-tunnel del pdr upfgtp 1:3
      

      Step 2: Test connectivity again (should fail)

      # Executed on UERANSIM
      ping 1.1.1.1 -I ueransim0 -c 5
      

      With no matching uplink PDRs, the UPF cannot identify sending traffic, causing packet drops or timeouts.

      Step 3: Re-add PDR 3 based on its original configuration

      # Executed on free5GC
      sudo ./gtp5g-tunnel add pdr upfgtp 1:3 \
        --pcd 128 \
        --hdr-rm 0 \
        --far-id 3 \
        --ue-ipv4 10.60.0.1 \
        --f-teid 2 192.168.56.102 \
        --qer-id 1 \
        --qer-id 3
      

      This command recreates PDR ID 3 with its corresponding parameters — linking it again to FAR 3 and QER 1/3 for the same UE.

      Step 4: Test once more (connectivity should recover)

      # Executed on UERANSIM
      ping 1.1.1.1 -I ueransim0 -c 5
      

      A successful ping confirms that the add operation has restored proper forwarding behavior.

      Conclusion

      The go-gtp5gnl framework offers full userspace visibility and control of kernel-based GTP-U tunnels. Through the experiments above, you have:

      • Inspected PFCP-translated kernel rules (PDR, FAR, QER).
      • Modified actions and observed instant traffic impact.
      • Re-created rules to validate real-time UPF behavior.

      By unifying Go’s ease of use with Netlink’s power, go-gtp5gnl becomes an ideal platform for 5G UPF debugging, QoS experimentation, and academic research on user-plane optimization.


      References

      About

      Hello, I'm Kai-Xu Zhan. I'm honored to be a new member of the free5GC project under the Linux Foundation. As someone who is still learning and growing in the field of 5G core network development, I'm enthusiastic about contributing to the community and expanding my knowledge in telecommunications technologies. I welcome any guidance or feedback as I continue to familiarize myself with the project.

      Connect with Me