GTP Full Tunnel Application
This DPL program implements a complete GTP tunnel handler on Bluefield, providing parsing, encapsulation, decapsulation, and flexible forwarding for mobile network traffic. Incoming packets are processed to:
extract GTP tunnel information
encapsulate plain IP packets into GTP tunnels
decapsulate GTP-tunneled packets to deliver the inner payload
The program supports both user equipment (UE)-to-core uplink and core-to-UE downlink paths, as well as plain IP and GTP transit forwarding. Each operation is hardware-accelerated and leverages programmable match-action tables and tunnel header templates for optimal performance.
Custom Header and Metadata Structures
GTP Header (
gtp_v1_h): Defines GTPv1 protocol fields, enabling extraction and manipulation of GTP tunnel information.Custom Metadata (
metadata_t): Stores flags and tunnel parameters to guide encapsulation or decapsulation during pipeline execution.
Parser
Flexible Parsing: Leverages the fixed parser for standard headers, and adds a GTP-specific parsing state that triggers when the UDP destination port is GTP-U (2152). When detected, it extracts the GTP header and transitions to parsing the inner IP payload.
Tunnel Header Template
Header Composition (
tunnel_headers_t): Specifies the exact order and content of Ethernet, IPv4, UDP, and GTP headers for encapsulation, using variables for fields filled at runtime (e.g., TEID, address fields).
Main Control Block – Actions
Drop Action: Immediately drops non-conforming or unwanted packets.
Encapsulation (
encapsulate_gtp): Encapsulates an IP packet within GTP, UDP, IPv4, and Ethernet outer headers, using the DPL extern for L3 tunnel offload.Decapsulation (
decapsulate_gtp): Removes the GTP tunnel header and the outer headers, then rewrites the Ethernet header for the inner packet.Forwarding: Directs packets to their designated output port.
Main Control Block – Tables
Uplink Encapsulation Table: Matches on input port and source IP to select the correct GTP tunnel for encapsulation (UE to core network).
Downlink Decapsulation Table: Matches on input port and TEID, applying decapsulation to GTP packets for delivery to the user side (core network to UE).
GTP Forwarding Table: Forwards GTP packets by TEID for nodes that act as GTP relays without terminating or modifying the tunnel.
Plain IP Forwarding Table: Routes non-GTP IP traffic using destination address longest prefix match.
Packet Processing Logic (apply block)
Non-IPv4 Packets: Dropped immediately, ensuring pipeline only processes valid IPv4.
GTP Packets: Processed through downlink decapsulation and, if appropriate, GTP forwarding tables.
Non-GTP Packets: Subject to uplink encapsulation (for new tunnel flows) or regular IP forwarding.
See below for the complete DPL example.
/*
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LicenseRef-NvidiaProprietary
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*
* Complete GTP Tunnel Handler - Parse, Encapsulate, and Decapsulate
*
* This P4 program provides comprehensive GTP tunnel handling:
* 1. Parse incoming GTP packets and extract tunnel information
* 2. Encapsulate plain IP packets into GTP tunnels
* 3. Decapsulate GTP packets to extract inner payload
* 4. Forward packets based on TEID or IP addresses
*/
#include <doca_model.p4>
#include <doca_headers.p4>
#include <doca_externs.p4>
#include <doca_parser.p4>
// Constants
#define GTP_U_PORT 2152
#define GTP_VERSION 1
#define GTP_PROTOCOL_TYPE 1
#define GTP_MESSAGE_TYPE_GPDU 0xFF
// Port definitions - must align with DPL RTD port configuration file
const bit<32> WIRE_PORT = 32w0;
const bit<32> UPLINK_PORT = 32w1; // Port for uplink traffic (to core network)
const bit<32> DOWNLINK_PORT = 32w2; // Port for downlink traffic (to RAN)
const bit<32> DEFAULT_PORT = 32w3; // Default forwarding port
const bit<32> DROP_PORT = 32w4; // Drop port
// GTP v1 Header Definition
header gtp_v1_h {
bit<3> version;
bit protocol_type;
bit reserved;
bit extension_header_flag;
bit seq_number_flag;
bit n_pdu_number_flag;
bit<8> message_type;
bit<16> message_length;
bit<32> teid;
bit<16> sequence_number;
bit<8> n_pdu_number;
bit<8> next_extension_hdr_type;
}
// Metadata for GTP processing
struct metadata_t {
bit<1> needs_encap; // Flag: packet needs GTP encapsulation
bit<1> needs_decap; // Flag: packet needs GTP decapsulation
bit<32> tunnel_teid; // TEID for encapsulation
bit<32> tunnel_dst_ip; // Destination IP for tunnel
bit<48> tunnel_dst_mac; // Destination MAC for tunnel
bit<48> tunnel_src_mac; // Source MAC for tunnel
bit<32> tunnel_src_ip; // Source IP for tunnel
}
// Complete header stack
struct headers_t {
NV_FIXED_HEADERS
gtp_v1_h gtpv1;
}
// Parser - handles both outer and inner packets
parser packet_parser(packet_in packet, out headers_t headers) {
NV_FIXED_PARSER(packet, headers)
@nv_transition_from("nv_parse_udp", GTP_U_PORT)
state parse_gtp {
packet.extract(headers.gtpv1);
transition nv_parse_inner_ipv4; // Continue parsing inner IP
}
}
// Tunnel header template for encapsulation
struct tunnel_headers_t {
nv_ethernet_h ethernet;
nv_ipv4_h ipv4;
nv_udp_h udp;
gtp_v1_h gtpv1;
}
// Main control block
control gtp_processor(
inout headers_t headers,
in nv_standard_metadata_t std_meta,
inout metadata_t user_meta,
inout nv_empty_metadata_t pkt_out_meta
) {
// Counters for statistics
NvDirectCounter(NvCounterType.PACKETS_AND_BYTES) encap_counter;
NvDirectCounter(NvCounterType.PACKETS_AND_BYTES) decap_counter;
NvDirectCounter(NvCounterType.PACKETS_AND_BYTES) gtp_forward_counter;
NvDirectCounter(NvCounterType.PACKETS_AND_BYTES) ip_forward_counter;
// GTP Tunnel template for encapsulation
@nv_header_data_fields(
ethernet = {
dst_addr = "variable",
src_addr = "variable",
ether_type = 0x0800
},
ipv4 = {
version = 0x4,
ihl = 0x5,
diffserv = 0,
ecn = "ignore",
total_len = "ignore",
identification = "ignore",
flags = 0,
frag_offset = 0,
ttl = 64,
protocol = 17,
hdr_checksum = "ignore",
src_addr = "variable",
dst_addr = "variable"
},
udp = {
src_port = "ignore",
dst_port = GTP_U_PORT,
length = "ignore",
checksum = "ignore"
},
gtpv1 = {
version = GTP_VERSION,
protocol_type = GTP_PROTOCOL_TYPE,
reserved = 0,
extension_header_flag = 1,
seq_number_flag = 1,
n_pdu_number_flag = 1,
message_type = GTP_MESSAGE_TYPE_GPDU,
message_length = "ignore",
teid = "variable",
sequence_number = 0,
n_pdu_number = 0,
next_extension_hdr_type = 0
}
)
NvHeaderDataTemplate<tunnel_headers_t>() gtp_tunnel_template;
// ========== ACTIONS ==========
action drop() {
nv_drop();
}
action forward_to_port(nv_logical_port_t port) {
nv_send_to_port(port);
}
// Encapsulation action - wrap packet in GTP tunnel
action encapsulate_gtp(
bit<48> dst_mac,
bit<48> src_mac,
bit<32> src_ip,
bit<32> dst_ip,
bit<32> teid,
nv_logical_port_t port
) {
encap_counter.count();
// Parameters must match the "variable" fields in template order:
// ethernet.dst_addr, ethernet.src_addr, ipv4.src_addr, ipv4.dst_addr, teid
nv_set_l3tunnel_underlay(headers, gtp_tunnel_template, {
dst_mac, // Ethernet dst_addr
src_mac, // Ethernet src_addr
src_ip, // IPv4 src_addr
dst_ip, // IPv4 dst_addr
teid // GTP teid
});
nv_send_to_port(port);
}
// Decapsulation action - remove GTP tunnel headers and forward inner packet
action decapsulate_gtp(
bit<48> dst_mac,
bit<48> src_mac,
nv_logical_port_t port
) {
decap_counter.count();
// Strip outer tunnel headers (Ethernet/IP/UDP/GTP) and rewrite L2 header
// 0x0800 = IPv4 EtherType, no VLAN tag
nv_l3_decap(
headers = headers,
dst_mac = dst_mac,
src_mac = src_mac,
l3_ether_type = 16w0x0800
);
// Forward the decapsulated inner packet
nv_send_to_port(port);
}
// ========== TABLES ==========
// Table 1: Uplink encapsulation (UE -> Core Network)
// Match on source IP address to determine which GTP tunnel to use
table uplink_encap_table {
key = {
std_meta.ingress_port: exact;
headers.ipv4.src_addr: exact;
}
actions = {
encapsulate_gtp;
forward_to_port;
drop;
NoAction;
}
size = 1024;
default_action = NoAction;
direct_counter = encap_counter;
}
// Table 2: Downlink decapsulation and forwarding (Core Network -> UE)
// Match on GTP TEID to determine forwarding
table downlink_decap_table {
key = {
std_meta.ingress_port: exact;
headers.gtpv1.teid: exact;
}
actions = {
decapsulate_gtp;
forward_to_port;
drop;
NoAction;
}
size = 1024;
default_action = NoAction;
direct_counter = decap_counter;
}
// Table 3: GTP tunnel forwarding (no decap, just forward GTP packets)
// For transit nodes that don't terminate the tunnel
table gtp_forward_table {
key = {
std_meta.ingress_port: exact;
headers.gtpv1.teid: exact;
}
actions = {
forward_to_port;
drop;
NoAction;
}
size = 1024;
default_action = NoAction;
direct_counter = gtp_forward_counter;
}
// Table 4: Plain IP forwarding (for non-GTP traffic)
table ip_forward_table {
key = {
headers.ipv4.dst_addr: lpm;
}
actions = {
forward_to_port;
drop;
NoAction;
}
size = 512;
default_action = NoAction;
direct_counter = ip_forward_counter;
}
// ========== APPLY LOGIC ==========
apply {
// Path 1: Invalid IPv4 - drop
if (!headers.ipv4.isValid()) {
drop();
}
// Path 2: GTP packet received (potential decapsulation or forwarding)
else if (headers.gtpv1.isValid()) {
downlink_decap_table.apply();
gtp_forward_table.apply();
}
// Path 3: Non-GTP packet (potential encapsulation or IP forwarding)
else {
uplink_encap_table.apply();
ip_forward_table.apply();
}
}
}
// Pipeline instantiation
NvDocaPipeline(
packet_parser(),
gtp_processor()
) main;