blob: e9b0c77d166a99a6c71de95d898f4d3f36df65a5 [file] [log] [blame]
// Copyright (c) 2017, Google Inc.
//
// P4_16 specification for a packet parser.
// Note: This code has not been tested and is expected to contain bugs.
#ifndef P4_SPEC_PARSER_P4_
#define P4_SPEC_PARSER_P4_
#include <v1model.p4>
#include "headers.p4"
//------------------------------------------------------------------------------
// Global defines
//------------------------------------------------------------------------------
#define ETHERTYPE_VLAN1 0x8100
#define ETHERTYPE_VLAN2 0x9100
#define ETHERTYPE_VLAN3 0x9200
#define ETHERTYPE_VLAN4 0x9300
#define ETHERTYPE_IPV4 0x0800
#define ETHERTYPE_IPV6 0x86dd
#define ETHERTYPE_ARP 0x0806
#define ETHERTYPE_ND 0x6007
#define ETHERTYPE_LLDP 0x88CC
#define IP_PROTOCOLS_TCP 6
#define IP_PROTOCOLS_UDP 17
#define IP_PROTOCOLS_ICMP 1
#define IP_PROTOCOLS_ICMPv6 58
#ifndef CPU_PORT
// TODO(samarabdi) Change once we move from 9 to 32 bits
#define CPU_PORT 0xFD // 0xFFFFFFFD
#endif
#define VLAN_DEPTH 2
//------------------------------------------------------------------------------
// List of all recognized headers
//------------------------------------------------------------------------------
struct parsed_packet_t {
ethernet_t ethernet;
ipv4_base_t ipv4_base;
ipv6_base_t ipv6_base;
icmp_header_t icmp_header;
tcp_t tcp;
udp_t udp;
vlan_tag_t[VLAN_DEPTH] vlan_tag; // header stack
arp_t arp;
packet_in_header_t packet_in;
packet_out_header_t packet_out;
}
//------------------------------------------------------------------------------
// Parser
//------------------------------------------------------------------------------
parser pkt_parser(packet_in pk, out parsed_packet_t hdr,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata) {
state start {
transition select(standard_metadata.ingress_port) {
CPU_PORT : parse_cpu_header;
_ : parse_ethernet;
}
}
state parse_ethernet {
pk.extract(hdr.ethernet);
transition select(hdr.ethernet.ether_type) {
ETHERTYPE_VLAN1: parse_vlan;
ETHERTYPE_VLAN2: parse_vlan;
ETHERTYPE_VLAN3: parse_vlan;
ETHERTYPE_VLAN4: parse_vlan;
ETHERTYPE_IPV4: parse_ipv4;
ETHERTYPE_IPV6: parse_ipv6;
ETHERTYPE_ARP: parse_arp;
_ : accept;
}
}
state parse_vlan {
// reference the next element in header stack
pk.extract(hdr.vlan_tag.next);
transition select(hdr.vlan_tag.last.ether_type) {
ETHERTYPE_VLAN1: parse_vlan;
ETHERTYPE_VLAN2: parse_vlan;
ETHERTYPE_VLAN3: parse_vlan;
ETHERTYPE_VLAN4: parse_vlan;
ETHERTYPE_IPV4 : parse_ipv4;
ETHERTYPE_IPV6 : parse_ipv6;
_ : accept;
}
}
state parse_ipv4 {
pk.extract(hdr.ipv4_base);
// TODO(samarabdi): confirm if below concats the two fields
transition select(hdr.ipv4_base.frag_offset ++ hdr.ipv4_base.protocol) {
IP_PROTOCOLS_ICMP : parse_icmp;
IP_PROTOCOLS_TCP : parse_tcp;
IP_PROTOCOLS_UDP : parse_udp;
_ : accept;
}
}
state parse_ipv6 {
pk.extract(hdr.ipv6_base);
transition select(hdr.ipv6_base.next_header) {
IP_PROTOCOLS_ICMPv6: parse_icmp;
IP_PROTOCOLS_TCP : parse_tcp;
IP_PROTOCOLS_UDP : parse_udp;
_ : accept;
}
}
state parse_tcp {
pk.extract(hdr.tcp);
// Normalize TCP port metadata to common port metadata
local_metadata.l4_src_port = hdr.tcp.src_port;
local_metadata.l4_dst_port = hdr.tcp.dst_port;
transition accept;
}
state parse_udp {
pk.extract(hdr.udp);
// Normalize UDP port metadata to common port metadata
local_metadata.l4_src_port = hdr.udp.src_port;
local_metadata.l4_dst_port = hdr.udp.dst_port;
transition accept;
}
state parse_icmp {
pk.extract(hdr.icmp_header);
transition accept;
}
state parse_arp {
pk.extract(hdr.arp);
transition accept;
}
state parse_cpu_header {
pk.extract(hdr.packet_out);
transition parse_ethernet;
}
} // end pkt_parser
control pkt_deparser(packet_out b, in parsed_packet_t hdr) {
apply {
// packet_out is not a valid header in a packet destined to CPU_PORT
b.emit(hdr.packet_in);
b.emit(hdr.ethernet);
b.emit(hdr.vlan_tag);
b.emit(hdr.ipv4_base);
b.emit(hdr.ipv6_base);
b.emit(hdr.arp);
b.emit(hdr.icmp_header);
b.emit(hdr.tcp);
b.emit(hdr.udp);
}
}
#endif // P4_SPEC_PARSER_P4_