Carmelo Cascone | 9ab4061 | 2017-09-19 16:31:55 +0900 | [diff] [blame] | 1 | // Copyright (c) 2017, Google Inc. |
| 2 | // |
| 3 | // P4_16 specification for a packet parser. |
| 4 | // Note: This code has not been tested and is expected to contain bugs. |
| 5 | |
| 6 | #ifndef P4_SPEC_PARSER_P4_ |
| 7 | #define P4_SPEC_PARSER_P4_ |
| 8 | |
| 9 | #include <v1model.p4> |
| 10 | #include "headers.p4" |
| 11 | |
| 12 | //------------------------------------------------------------------------------ |
| 13 | // Global defines |
| 14 | //------------------------------------------------------------------------------ |
| 15 | |
| 16 | #define ETHERTYPE_VLAN1 0x8100 |
| 17 | #define ETHERTYPE_VLAN2 0x9100 |
| 18 | #define ETHERTYPE_VLAN3 0x9200 |
| 19 | #define ETHERTYPE_VLAN4 0x9300 |
| 20 | |
| 21 | #define ETHERTYPE_IPV4 0x0800 |
| 22 | #define ETHERTYPE_IPV6 0x86dd |
| 23 | #define ETHERTYPE_ARP 0x0806 |
| 24 | #define ETHERTYPE_ND 0x6007 |
| 25 | #define ETHERTYPE_LLDP 0x88CC |
| 26 | |
| 27 | #define IP_PROTOCOLS_TCP 6 |
| 28 | #define IP_PROTOCOLS_UDP 17 |
| 29 | #define IP_PROTOCOLS_ICMP 1 |
| 30 | #define IP_PROTOCOLS_ICMPv6 58 |
| 31 | |
| 32 | #ifndef CPU_PORT |
| 33 | // TODO(samarabdi) Change once we move from 9 to 32 bits |
| 34 | #define CPU_PORT 0xFD // 0xFFFFFFFD |
| 35 | #endif |
| 36 | #define VLAN_DEPTH 2 |
| 37 | |
| 38 | //------------------------------------------------------------------------------ |
| 39 | // List of all recognized headers |
| 40 | //------------------------------------------------------------------------------ |
| 41 | |
| 42 | struct parsed_packet_t { |
| 43 | ethernet_t ethernet; |
| 44 | ipv4_base_t ipv4_base; |
| 45 | ipv6_base_t ipv6_base; |
| 46 | icmp_header_t icmp_header; |
| 47 | tcp_t tcp; |
| 48 | udp_t udp; |
| 49 | vlan_tag_t[VLAN_DEPTH] vlan_tag; // header stack |
| 50 | arp_t arp; |
| 51 | packet_in_header_t packet_in; |
| 52 | packet_out_header_t packet_out; |
| 53 | } |
| 54 | |
| 55 | //------------------------------------------------------------------------------ |
| 56 | // Parser |
| 57 | //------------------------------------------------------------------------------ |
| 58 | |
| 59 | parser pkt_parser(packet_in pk, out parsed_packet_t hdr, |
| 60 | inout local_metadata_t local_metadata, |
| 61 | inout standard_metadata_t standard_metadata) { |
| 62 | state start { |
| 63 | transition select(standard_metadata.ingress_port) { |
| 64 | CPU_PORT : parse_cpu_header; |
| 65 | _ : parse_ethernet; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | state parse_ethernet { |
| 70 | pk.extract(hdr.ethernet); |
| 71 | transition select(hdr.ethernet.ether_type) { |
| 72 | ETHERTYPE_VLAN1: parse_vlan; |
| 73 | ETHERTYPE_VLAN2: parse_vlan; |
| 74 | ETHERTYPE_VLAN3: parse_vlan; |
| 75 | ETHERTYPE_VLAN4: parse_vlan; |
| 76 | ETHERTYPE_IPV4: parse_ipv4; |
| 77 | ETHERTYPE_IPV6: parse_ipv6; |
| 78 | ETHERTYPE_ARP: parse_arp; |
| 79 | _ : accept; |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | state parse_vlan { |
| 84 | // reference the next element in header stack |
| 85 | pk.extract(hdr.vlan_tag.next); |
| 86 | transition select(hdr.vlan_tag.last.ether_type) { |
| 87 | ETHERTYPE_VLAN1: parse_vlan; |
| 88 | ETHERTYPE_VLAN2: parse_vlan; |
| 89 | ETHERTYPE_VLAN3: parse_vlan; |
| 90 | ETHERTYPE_VLAN4: parse_vlan; |
| 91 | ETHERTYPE_IPV4 : parse_ipv4; |
| 92 | ETHERTYPE_IPV6 : parse_ipv6; |
| 93 | _ : accept; |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | state parse_ipv4 { |
| 98 | pk.extract(hdr.ipv4_base); |
| 99 | // TODO(samarabdi): confirm if below concats the two fields |
| 100 | transition select(hdr.ipv4_base.frag_offset ++ hdr.ipv4_base.protocol) { |
| 101 | IP_PROTOCOLS_ICMP : parse_icmp; |
| 102 | IP_PROTOCOLS_TCP : parse_tcp; |
| 103 | IP_PROTOCOLS_UDP : parse_udp; |
| 104 | _ : accept; |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | state parse_ipv6 { |
| 109 | pk.extract(hdr.ipv6_base); |
| 110 | transition select(hdr.ipv6_base.next_header) { |
| 111 | IP_PROTOCOLS_ICMPv6: parse_icmp; |
| 112 | IP_PROTOCOLS_TCP : parse_tcp; |
| 113 | IP_PROTOCOLS_UDP : parse_udp; |
| 114 | _ : accept; |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | state parse_tcp { |
| 119 | pk.extract(hdr.tcp); |
| 120 | // Normalize TCP port metadata to common port metadata |
| 121 | local_metadata.l4_src_port = hdr.tcp.src_port; |
| 122 | local_metadata.l4_dst_port = hdr.tcp.dst_port; |
| 123 | transition accept; |
| 124 | } |
| 125 | |
| 126 | state parse_udp { |
| 127 | pk.extract(hdr.udp); |
| 128 | // Normalize UDP port metadata to common port metadata |
| 129 | local_metadata.l4_src_port = hdr.udp.src_port; |
| 130 | local_metadata.l4_dst_port = hdr.udp.dst_port; |
| 131 | transition accept; |
| 132 | } |
| 133 | |
| 134 | state parse_icmp { |
| 135 | pk.extract(hdr.icmp_header); |
| 136 | transition accept; |
| 137 | } |
| 138 | |
| 139 | state parse_arp { |
| 140 | pk.extract(hdr.arp); |
| 141 | transition accept; |
| 142 | } |
| 143 | |
| 144 | state parse_cpu_header { |
| 145 | pk.extract(hdr.packet_out); |
| 146 | transition parse_ethernet; |
| 147 | } |
| 148 | } // end pkt_parser |
| 149 | |
| 150 | control pkt_deparser(packet_out b, in parsed_packet_t hdr) { |
| 151 | apply { |
| 152 | // packet_out is not a valid header in a packet destined to CPU_PORT |
| 153 | b.emit(hdr.packet_in); |
| 154 | b.emit(hdr.ethernet); |
| 155 | b.emit(hdr.vlan_tag); |
| 156 | b.emit(hdr.ipv4_base); |
| 157 | b.emit(hdr.ipv6_base); |
| 158 | b.emit(hdr.arp); |
| 159 | b.emit(hdr.icmp_header); |
| 160 | b.emit(hdr.tcp); |
| 161 | b.emit(hdr.udp); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | #endif // P4_SPEC_PARSER_P4_ |