header_type ethernet_t { fields { dstAddr : 48; srcAddr : 48; etherType : 16; } } header_type ipv4_base_t { fields { version : 4; ihl : 4; diffserv : 8; totalLen : 16; identification : 16; flags : 3; fragOffset : 13; ttl : 8; protocol : 8; hdrChecksum : 16; srcAddr : 32; dstAddr : 32; } } // End of Option List #define IPV4_OPTION_EOL_VALUE 0x00 header_type ipv4_option_EOL_t { fields { value : 8; } } // No operation #define IPV4_OPTION_NOP_VALUE 0x01 header_type ipv4_option_NOP_t { fields { value : 8; } } #define IPV4_OPTION_SECURITY_VALUE 0x82 header_type ipv4_option_security_t { fields { value : 8; len : 8; security : 72; } } #define IPV4_OPTION_TIMESTAMP_VALUE 0x44 header_type ipv4_option_timestamp_t { fields { value : 8; len : 8; data : *; } length : len; max_length : 40; } header_type intrinsic_metadata_t { fields { mcast_grp : 4; egress_rid : 4; mcast_hash : 16; lf_field_list: 32; } } header_type my_metadata_t { fields { parse_ipv4_counter : 8; } } header ethernet_t ethernet; header ipv4_base_t ipv4_base; header ipv4_option_EOL_t ipv4_option_EOL[3]; header ipv4_option_NOP_t ipv4_option_NOP[3]; header ipv4_option_security_t ipv4_option_security; header ipv4_option_timestamp_t ipv4_option_timestamp; metadata intrinsic_metadata_t intrinsic_metadata; metadata my_metadata_t my_metadata; @pragma header_ordering ethernet ipv4_base ipv4_option_security ipv4_option_NOP ipv4_option_timestamp ipv4_option_EOL parser start { return parse_ethernet; } #define ETHERTYPE_IPV4 0x0800 parser parse_ethernet { extract(ethernet); return select(ethernet.etherType) { ETHERTYPE_IPV4 : parse_ipv4; default: ingress; } } parser parse_ipv4 { extract(ipv4_base); set_metadata(my_metadata.parse_ipv4_counter, ipv4_base.ihl * 4 - 20); return select(ipv4_base.ihl) { 0x05 : ingress; default : parse_ipv4_options; } } parser parse_ipv4_options { // match on byte counter and option value return select(my_metadata.parse_ipv4_counter, current(0, 8)) { 0x0000 mask 0xff00 : ingress; 0x0000 mask 0x00ff : parse_ipv4_option_EOL; 0x0001 mask 0x00ff : parse_ipv4_option_NOP; 0x0082 mask 0x00ff : parse_ipv4_option_security; 0x0044 mask 0x00ff : parse_ipv4_option_timestamp; } } parser parse_ipv4_option_EOL { extract(ipv4_option_EOL[next]); set_metadata(my_metadata.parse_ipv4_counter, my_metadata.parse_ipv4_counter - 1); return parse_ipv4_options; } parser parse_ipv4_option_NOP { extract(ipv4_option_NOP[next]); set_metadata(my_metadata.parse_ipv4_counter, my_metadata.parse_ipv4_counter - 1); return parse_ipv4_options; } parser parse_ipv4_option_security { extract(ipv4_option_security); // security option must have length 11 bytes set_metadata(my_metadata.parse_ipv4_counter, my_metadata.parse_ipv4_counter - 11); return parse_ipv4_options; } parser parse_ipv4_option_timestamp { extract(ipv4_option_timestamp); set_metadata(my_metadata.parse_ipv4_counter, my_metadata.parse_ipv4_counter - ipv4_option_timestamp.len); return parse_ipv4_options; } field_list ipv4_checksum_list { ipv4_base.version; ipv4_base.ihl; ipv4_base.diffserv; ipv4_base.totalLen; ipv4_base.identification; ipv4_base.flags; ipv4_base.fragOffset; ipv4_base.ttl; ipv4_base.protocol; ipv4_base.srcAddr; ipv4_base.dstAddr; ipv4_option_security; ipv4_option_NOP[0]; ipv4_option_timestamp; } field_list_calculation ipv4_checksum { input { ipv4_checksum_list; } algorithm : csum16; output_width : 16; } calculated_field ipv4_base.hdrChecksum { update ipv4_checksum; } action _drop() { drop(); } action _nop() { } control ingress { } action format_options_security() { pop(ipv4_option_NOP, 3); pop(ipv4_option_EOL, 3); push(ipv4_option_EOL, 1); modify_field(ipv4_base.ihl, 8); } action format_options_timestamp() { pop(ipv4_option_NOP, 3); pop(ipv4_option_EOL, 3); // timestamp option is word-aligned so no need for NOP or EOL modify_field(ipv4_base.ihl, 5 + (ipv4_option_timestamp.len >> 3)); } action format_options_both() { pop(ipv4_option_NOP, 3); pop(ipv4_option_EOL, 3); push(ipv4_option_NOP, 1); modify_field(ipv4_option_NOP[0].value, IPV4_OPTION_NOP_VALUE); modify_field(ipv4_base.ihl, 8 + (ipv4_option_timestamp.len >> 2)); } table format_options { reads { ipv4_option_security : valid; ipv4_option_timestamp : valid; } actions { format_options_security; format_options_timestamp; format_options_both; _nop; } size : 4; } control egress { apply(format_options); }