/* -*- P4_16 -*- */
#ifndef PARSERS_P4
#define PARSERS_P4

#include <core.p4>
#include <v1model.p4>

#include "headers.p4"

parser MyParser(packet_in packet,
                out       headers hdr,
                inout     metadata meta,
                inout     standard_metadata_t standard_metadata) {

    state start {
        packet.extract(hdr.ethernet);
        transition select(hdr.ethernet.ethertype){
            TYPE_IPV4: ipv4;
            TYPE_IPV6: ipv6;
            default: accept;
        }
    }

    state ipv4 {
        packet.extract(hdr.ipv4);
		meta.tcp_length = hdr.ipv4.totalLen - 16w20;

        transition select(hdr.ipv4.protocol){
            PROTO_TCP: tcp;
            PROTO_UDP: udp;
            PROTO_ICMP: icmp;

            default: accept;
        }
    }

    state ipv6 {
        packet.extract(hdr.ipv6);
		meta.tcp_length = hdr.ipv6.payload_length;

        transition select(hdr.ipv6.next_header){
            PROTO_TCP: tcp;
            PROTO_UDP: udp;
            PROTO_ICMP6: icmp6;
            default: accept;
        }
    }

    /* Leaf */
    state tcp {
       packet.extract(hdr.tcp);
       transition accept;
    }

    state udp {
       packet.extract(hdr.udp);
       transition accept;
    }

    state icmp6 {
       packet.extract(hdr.icmp6);
       transition accept;
    }

    state icmp {
       packet.extract(hdr.icmp);
       transition accept;
    }

}

/*************************************************************************
************************  D E P A R S E R  *******************************
*************************************************************************/

control MyDeparser(packet_out packet, in headers hdr) {
    apply {
        /* always */
        packet.emit(hdr.ethernet);

        /* only if information is sent to the controller */
        packet.emit(hdr.cpu);

        /* either */
        packet.emit(hdr.ipv4);
        packet.emit(hdr.ipv6);

        /* either */
        packet.emit(hdr.tcp);
        packet.emit(hdr.udp);
        packet.emit(hdr.icmp);
        packet.emit(hdr.icmp6);
    }
}


#endif
