DOCA Documentation v3.2.0

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.

Copy
Copied!
            

/* * 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;

© Copyright 2025, NVIDIA. Last updated on Nov 20, 2025