DOCA SDK Documentation

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.

Sample Code

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.

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



Last updated: