P4 Cheat Sheet - 2022.2 English

Vitis Networking P4 User Guide (UG1308)

Document ID
UG1308
Version
2022.2 English
Revision

Data Types

// Basic data Types:
bool flag; // two values: true & false
int sigData; // signed integer
bit bitData; // unsigned int (bit-string)
varbit varData; // variable-size bit-str.

// typedef: introduces alternate type name
typedef bit<48> macAddr_t;
typedef bit<32> ip4Addr_t;

// const: constant value definition
const bit<16> IPV4_TYPE = 0x0800;
const bit<8> UDP_PROT = 0x11;

// headers: ordered collection of members
// operations test and set validity bits:
// isValid(), setValid(), setInvalid()
header ethernet_t {
 macAddr_t dstAddr;
 macAddr_t srcAddr;
 bit<16> type;
}

// struct: unordered collection of members
// use to define header structures
struct headers_t {
 ethernet_t ethernet;
 vlan_t[2] vlan; // stack
}

// structs can also be used to define
// metadata structures
struct meta_out_t {
 macAddr_t dstAddr;
 bit<16> offset;
}

// error: contains opaque values that 
// can be used to signal errors
error { 
 InvalidEthernetType, 
 IPv4VersionNotSupported,
 }

Compiler Directives

// define macros (without arguments)
#define NULL 0

// undefine existing macros
#undef NULL

// conditional directives
#if #else #endif #ifdef #ifndef #elif

// include contents from other files 
#include <file.p4> // can use quotes ‘”’

Statements and Expressions

// local metadata declaration 
bit<16> tmp1, tmp2, tmp3, tmp4; 
bit<16> tmp5 = 0; // default value

// variable assignment and member access
tmp1 = hdr.ethernet.type;

// bit slicing, concatenation (++)
tmp2 = tmp1[7:0] ++ tmp1[15:8];

// data type casting
tmp3 = (bit<16>)tmp2;

// arithmetic operators: 
// +, -, *, <<, >>
tmp4 = 2*tmp1 + tmp3 - (bit<16>)tmp1[7:0];

// bitwise operators:
// and, or, not, &, |, ^, ~
tmp5 = (~tmp1 & tmp2) | (tmp3 ^ tmp4);

// conditional statement
// expression output requires a bool
// logical operators: ==, !=, >, >=, <, <=
if (next_hop == 0) {
    metadata.next_hop = hdr.ipv4.dst;
} else {
    metadata.next_hop = next_hop;
}

Tables

table ipv4_lpm {
    // key match kinds: exact, ternary, 
    // lpm, range, field_mask & unusued
    key = {
        hdr.ipv4.dstAddr : lpm;
        hdr.ipv4.srcAddr : exact;
    }
    // actions that can be invoked
    actions = {
        ipv4_forward;
        drop_packet;
    }
    // table properties:
    // maximum number of entries
    size = 1024;
    // enable direct match 
   // (for exact keys only) 
    direct_match = true;
    // number of supported unique masks:
    // ternary and lpm only 
    num_masks = 256;
    // action invoked when table fails
    // to find a match for the key used
    // default_action = drop_packet();
}

Actions

// action declaration:
action ipv4_forward(bit<9> port) {
    // local variable and assignment
    bit<48> tmpAddr  = hdr.ipv4.srcAddr;

    // in/out values from/to data plane
    hdr.ipv4.srcAddr = hdr.ipv4.dstAddr;
    hdr.ipv4.dstAddr = tmpAddr;

    // inputs provided by control plane
    meta.port = port; // stored in table
}

// explicit action invocation:
ipv4_forward(0x123); // constant arg. value 

Parsing

// parser: must always begin with the 
// special state "start"
state start {
    transition parse_ethernet;
}

// User-defined parser state
state parse_ethernet {
    // fixed length extraction
    packet.extract(hdr.ethernet);
    // assignment to metadata
    meta.eth_dmac = hdr.ethernet.dstAddr;
    // select transition to next state
    transition select(hdr.ethernet.type) {
        0x0800  : parse_ipv4;
        0x8100  : parse_vlan;
        default : accept;
    }
}

// header stack extraction
state parse_vlan {
    packet.extract(hdr.vlan.next);
    transition select(hdr.vlan.last.tpid) {
        VLAN_TYPE : parse_vlan; // loop
        IPV4_TYPE : parse_ipv4;
        default   : accept;        
    }
}

// advanced parsing
state parse_ipv4 {
    // fixed length extraction
    packet.extract(hdr.ipv4);
    // custom form of error handling
    // false causes transition to reject
    verify(hdr.ipv4.version == 4,
           error.IpVersionNotSupported); 
   // variable length extraction
    packet.extract(hdr.ipv4opt, 
    ((bit<32>)hdr.ipv4.hdr_len - 5) * 32);
   // constant transition (end of packet)
    transition accept; // fixed transition
}

Deparsing

// the inverse of parsing is deparsing,
// or packet reconstruction
apply {
    // insert headers into packet(if valid)
    packet.emit(hdr.ethernet);
    packet.emit(hdr.vlan); // stack
    packet.emit(hdr.ipv4);
    packet.emit(hdr.ipv4opt); //varbit
}

Processing

// all variables, tables and actions 
// definitions outside apply methodapply {
    // unconditional table search
    ipv6_lpm.appply();

    // branch on header validity
    // conditional table search
    if (hdr.ipv4.isValid()) {
        ipv4_lpm.apply();
    }

    // branch on table hit result
    if (local_ip_table.apply().hit) {
        send_to_cpu();
    } else {
        drop_packet();
    }
 
    // branch on error
    if (smeta.parser_error ==    
        error.InvalidEthernetType)
        drop_packet();

    // header manipulation
    hdr.new_vlan = hdr_vlan;
    hdr.vlan.setInvalid();
    if (hdr.ipv4.isValid()) 
        hdr.new_vlan.tpid = 0x0800
}

Vitis Networking P4 Architecture

// standard metadata format
struct standard_metadata_t {
    bit<1>  drop;
    bit<64> ingress_timestamp;
    bit<16> parsed_bytes;
    error   parser_error;
}

// Pipeline elements
parser Parser<H, M>(
    packet_in b, 
    out H hdr,
    inout M meta,
    inout standard_metadata_t smeta
);

control MatchAction<H, M>(
    inout H hdr,
    inout M meta,
    inout standard_metadata_t smeta
);

control Deparser<H, M>(
    packet_out b,
    in H hdr,
    inout M meta,
    inout standard_metadata_t smeta
);

// architecture’s main package
package XilinxPipeline<H, M>(
    Parser<H, M> p,
    MatchAction<H, M> ma,
    Deparser<H, M> dep
);

Built-In Externs

User Externs

const bit<32> NUM_COUNTERS = 8192; // up to 65536 supported
typedef bit<13> CounterIndex_t; // CounterIndex type should correspond with the number of counters

// Instantiation of Counter Externs
// 3 modes supported, as shown here
Counter<bit<64>, CounterIndex_t>(NUM_COUNTERS, CounterType_t.PACKETS) PacketCounter;
Counter<bit<64>, CounterIndex_t>(NUM_COUNTERS, CounterType_t.BYTES) ByteCounter;
Counter<bit<64>, CounterIndex_t>(NUM_COUNTERS, CounterType_t.PACKETS_AND_BYTES) ComboCounter;

// The "count" method can only be called once per counter instance per packet
PacketCounter.count(counter_index);
ByteCounter.count(counter_index);
ComboCounter.count(counter_index);
// Structure Definitions
struct divider_input {
    bit<32> divisor;
    bit<32> dividend;
}

struct divider_output {
    bit<32> remainder;
    bit<32> quotient;
}

divider_input div_in;
divider_output div_out;

// Instantiation of UserExtern Object
UserExtern<divider_input, divider_output>(34) calc_divide;

// Interface to User Extern
calc_divide.apply(div_in, div_out);