summaryrefslogtreecommitdiff
path: root/vlan_aggregation/p4src/vlan_aggregation.p4
diff options
context:
space:
mode:
Diffstat (limited to 'vlan_aggregation/p4src/vlan_aggregation.p4')
-rw-r--r--vlan_aggregation/p4src/vlan_aggregation.p4821
1 files changed, 821 insertions, 0 deletions
diff --git a/vlan_aggregation/p4src/vlan_aggregation.p4 b/vlan_aggregation/p4src/vlan_aggregation.p4
new file mode 100644
index 0000000..a2a33f8
--- /dev/null
+++ b/vlan_aggregation/p4src/vlan_aggregation.p4
@@ -0,0 +1,821 @@
+/* -*- P4_16 -*- */
+
+#include <core.p4>
+#include <tna.p4>
+
+
+/*************************************************************************
+ ************* C O N S T A N T S A N D T Y P E S *******************
+**************************************************************************/
+enum bit<16> ether_type_t {
+ IPV4 = 0x0800,
+ ARP = 0x0806,
+ TPID = 0x8100,
+ TPID2 = 0x9100,
+ IPV6 = 0x86DD
+}
+
+enum bit<8> ip_protocol_t {
+ ICMP = 1,
+ IGMP = 2,
+ TCP = 6,
+ UDP = 17
+}
+
+enum bit<16> arp_opcode_t {
+ REQUEST = 1,
+ REPLY = 2
+}
+
+enum bit<8> icmp_type_t {
+ ECHO_REPLY = 0,
+ ECHO_REQUEST = 8
+}
+
+typedef bit<48> mac_addr_t;
+typedef bit<32> ipv4_addr_t;
+const int NEXTHOP_ID_WIDTH = 14;
+typedef bit<(NEXTHOP_ID_WIDTH)> nexthop_id_t;
+
+const int MAC_TABLE_SIZE = 65536;
+const int VLAN_PORT_TABLE_SIZE = 1 << (7 + 12);
+const int NEXTHOP_TABLE_SIZE = 1 << NEXTHOP_ID_WIDTH;
+const int SUBVLAN_CHECK_TABLE_SIZE = 12288;
+
+const int IPV4_HOST_SIZE = 65536;
+const int IPV4_LPM_SIZE = 12288;
+const int IPV6_HOST_SIZE = 12000;
+const int IPV6_LPM_SIZE = 6000;
+
+/* We can use up to 8 different digest types */
+const bit<3> L2_LEARN_DIGEST = 1;
+
+/*************************************************************************
+ *********************** H E A D E R S *********************************
+ *************************************************************************/
+
+/* Define all the headers the program will recognize */
+/* The actual sets of headers processed by each gress can differ */
+
+/* Standard ethernet header */
+header ethernet_h {
+ mac_addr_t dst_addr;
+ mac_addr_t src_addr;
+}
+
+header vlan_tag_h {
+ bit<16> tpid;
+ bit<3> pcp;
+ bit<1> dei;
+ bit<12> vid;
+}
+
+header etherII_h {
+ ether_type_t ether_type;
+}
+
+header ipv4_t {
+ bit<4> version;
+ bit<4> ihl;
+ bit<8> diffserv;
+ bit<16> total_len;
+ bit<16> identification;
+ bit<3> flags;
+ bit<13> frag_offset;
+ bit<8> ttl;
+ ip_protocol_t protocol;
+ bit<16> hdr_checksum;
+ ipv4_addr_t src_addr;
+ ipv4_addr_t dst_addr;
+}
+
+header ipv4_options_t {
+ varbit<320> options;
+}
+
+header ipv6_t {
+ bit<4> version;
+ bit<8> traffic_class;
+ bit<20> flow_label;
+ bit<16> payload_len;
+ bit<8> next_hdr;
+ bit<8> hop_limit;
+ bit<128> src_addr;
+ bit<128> dst_addr;
+}
+
+header arp_h {
+ bit<16> hw_type;
+ ether_type_t proto_type;
+ bit<8> hw_addr_len;
+ bit<8> proto_addr_len;
+ arp_opcode_t opcode;
+}
+
+header arp_payload_h {
+ mac_addr_t src_hw_addr;
+ ipv4_addr_t src_proto_addr;
+ mac_addr_t dst_hw_addr;
+ ipv4_addr_t dst_proto_addr;
+}
+
+header icmp_h {
+ icmp_type_t msg_type;
+ bit<8> msg_code;
+ bit<16> checksum;
+}
+
+/*** Internal Headers ***/
+
+typedef bit<4> header_type_t; /* These fields can be coombined into one */
+typedef bit<4> header_info_t; /* 8-bit field as well. Exercise for the brave */
+
+const header_type_t HEADER_TYPE_BRIDGE = 0xB;
+const header_type_t HEADER_TYPE_MIRROR_INGRESS = 0xC;
+const header_type_t HEADER_TYPE_MIRROR_EGRESS = 0xD;
+const header_type_t HEADER_TYPE_RESUBMIT = 0xA;
+
+/*
+ * This is a common "preamble" header that must be present in all internal
+ * headers. The only time you do not need it is when you know that you are
+ * not going to have more than one internal header type ever
+ */
+#define INTERNAL_HEADER \
+ header_type_t header_type; \
+ header_info_t header_info
+
+
+header inthdr_h {
+ INTERNAL_HEADER;
+}
+
+/* Bridged metadata */
+header bridge_h {
+ INTERNAL_HEADER;
+
+ bit<7> pad0;
+ PortId_t ingress_port;
+
+ bit<3> pcp;
+ bit<1> dei;
+ bit<12> vid;
+}
+
+/*************************************************************************
+ ************** I N G R E S S P R O C E S S I N G *******************
+ *************************************************************************/
+
+ /*********************** H E A D E R S ************************/
+
+struct my_ingress_headers_t {
+ bridge_h bridge;
+ ethernet_h ethernet;
+ vlan_tag_h vlan_tag;
+ etherII_h etherII;
+ arp_h arp;
+ arp_payload_h arp_payload;
+ ipv4_t ipv4;
+ ipv4_options_t ipv4_options;
+ ipv6_t ipv6;
+ icmp_h icmp;
+}
+
+ /****** G L O B A L I N G R E S S M E T A D A T A *********/
+
+struct port_metadata_t {
+ bit<3> port_pcp;
+ bit<12> port_vid;
+ bit<9> l2_xid;
+}
+
+struct my_ingress_metadata_t {
+
+ bool ipv4_checksum_err;
+ ipv4_addr_t dst_ipv4;
+ port_metadata_t port_properties;
+
+ bit<3> pcp;
+ bit<1> dei;
+ bit<12> vid;
+ bit<12> dvid;
+ bit<9> mac_move; /* Should have the same size as PortId_t */
+ bit<1> is_static;
+ bit<1> smac_hit;
+ PortId_t ingress_port;
+}
+
+ /*********************** P A R S E R **************************/
+parser IngressParser(packet_in pkt,
+ /* User */
+ out my_ingress_headers_t hdr,
+ out my_ingress_metadata_t meta,
+ /* Intrinsic */
+ out ingress_intrinsic_metadata_t ig_intr_md)
+{
+
+ Checksum() ipv4_checksum;
+ /* This is a mandatory state, required by Tofino Architecture */
+ state start {
+ pkt.extract(ig_intr_md);
+ meta.port_properties = port_metadata_unpack<port_metadata_t>(pkt);
+ transition meta_init;
+ }
+
+ state meta_init {
+ meta.pcp = 0;
+ meta.dei = 0;
+ meta.vid = 0;
+ meta.dvid = 0;
+ meta.mac_move = 0;
+ meta.is_static = 0;
+ meta.smac_hit = 0;
+ meta.ingress_port = ig_intr_md.ingress_port;
+ meta.ipv4_checksum_err = false;
+ meta.dst_ipv4 = 0;
+ transition parse_ethernet;
+ }
+
+ state parse_ethernet {
+ pkt.extract(hdr.ethernet);
+ transition select(pkt.lookahead<bit<16>>()) {
+ (bit<16>)ether_type_t.TPID &&& 0xEFFF: parse_vlan_tag;
+ default: parse_etherII;
+ }
+ }
+
+ state parse_vlan_tag {
+ pkt.extract(hdr.vlan_tag);
+ meta.pcp = hdr.vlan_tag.pcp;
+ meta.dei = hdr.vlan_tag.dei;
+ meta.vid = hdr.vlan_tag.vid;
+ transition parse_etherII;
+ }
+
+ state parse_etherII {
+ pkt.extract(hdr.etherII);
+ transition select(hdr.etherII.ether_type) {
+ ether_type_t.IPV4 : parse_ipv4;
+ ether_type_t.IPV6 : parse_ipv6;
+ ether_type_t.ARP : parse_arp;
+ default: accept;
+ }
+ }
+
+ state parse_ipv4 {
+ pkt.extract(hdr.ipv4);
+ meta.dst_ipv4 = hdr.ipv4.dst_addr;
+ ipv4_checksum.add(hdr.ipv4);
+ transition select(hdr.ipv4.ihl) {
+ 0x5 : parse_ipv4_no_options;
+ 0x6 &&& 0xE : parse_ipv4_options;
+ 0x8 &&& 0x8 : parse_ipv4_options;
+ default: reject;
+ }
+ }
+
+ state parse_ipv4_options {
+ pkt.extract(
+ hdr.ipv4_options,
+ ((bit<32>)hdr.ipv4.ihl - 32w5) * 32);
+
+ ipv4_checksum.add(hdr.ipv4_options);
+ transition parse_ipv4_no_options;
+ }
+
+ state parse_ipv4_no_options {
+ meta.ipv4_checksum_err = ipv4_checksum.verify();
+
+ transition select(
+ hdr.ipv4.ihl,
+ hdr.ipv4.frag_offset,
+ hdr.ipv4.protocol) {
+ (5, 0, ip_protocol_t.ICMP) : parse_icmp;
+ default: accept;
+ }
+ }
+
+ state parse_icmp {
+ pkt.extract(hdr.icmp);
+ transition accept;
+ }
+
+ state parse_arp {
+ pkt.extract(hdr.arp);
+ transition select(hdr.arp.hw_type, hdr.arp.proto_type) {
+ (0x0001, ether_type_t.IPV4) : parse_arp_payload;
+ default: reject; // Currently the same as accept
+ }
+ }
+
+ state parse_arp_payload {
+ pkt.extract(hdr.arp_payload);
+ meta.dst_ipv4 = hdr.arp_payload.dst_proto_addr;
+ transition accept;
+ }
+
+ state parse_ipv6 {
+ pkt.extract(hdr.ipv6);
+ transition accept;
+ }
+}
+
+ /***************** M A T C H - A C T I O N *********************/
+
+control Ingress(
+ /* User */
+ inout my_ingress_headers_t hdr,
+ inout my_ingress_metadata_t meta,
+ /* Intrinsic */
+ in ingress_intrinsic_metadata_t ig_intr_md,
+ in ingress_intrinsic_metadata_from_parser_t ig_prsr_md,
+ inout ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md,
+ inout ingress_intrinsic_metadata_for_tm_t ig_tm_md)
+{
+
+ nexthop_id_t nexthop_id = 0;
+ PortId_t dst_sub_port = 0;
+ bit<16> src_sid = 0;
+ mac_addr_t dst_mac = 0;
+ bit<8> ttl_dec = 0;
+ bit<1> is_to_l3 = 0;
+ bit<1> is_same_vlan = 0;
+
+/************************ Common Action *************************/
+ action drop() {
+ ig_dprsr_md.drop_ctl = 1;
+ }
+
+ action send(PortId_t port) {
+ ig_tm_md.ucast_egress_port = port;
+ }
+/************************* Port VLAN Table *************************/
+
+ action vlan_port_miss() { }
+
+ action get_sid_vid(bit<16> superid, bit<12> subid){
+ meta.vid = subid;
+ src_sid = superid;
+ }
+
+ table vlan_port {
+ key = { ig_intr_md.ingress_port : exact; }
+ actions = {
+ get_sid_vid;
+ vlan_port_miss;
+ }
+ size = MAC_TABLE_SIZE;
+ const default_aciotn = vlan_port_miss();
+ }
+
+/*************************** Smac **********************************/
+ action smac_hit(PortId_t port, bit<1> is_static) {
+ meta.mac_move = ig_intr_md.ingress_port ^ port;
+ meta.smac_hit = 1;
+ meta.is_static = is_static;
+ }
+
+ action smac_miss() { }
+
+ action smac_drop() {
+ drop(); exit;
+ }
+
+ //@idletime_precision(3)
+ table smac {
+ key = {
+ meta.vid : exact;
+ hdr.ethernet.src_addr : exact;
+ }
+ actions = {
+ smac_hit; smac_miss; smac_drop;
+ }
+ size = MAC_TABLE_SIZE;
+ const default_action = smac_miss();
+ //idle_timeout = true;
+ }
+
+/*************************** Smac Result **************************/
+ action mac_learn_notify() {
+ ig_dprsr_md.digest_type = L2_LEARN_DIGEST;
+ }
+
+ table smac_results {
+ key = {
+ meta.mac_move : ternary;
+ meta.is_static : ternary;
+ meta.smac_hit : ternary;
+ }
+ actions = {
+ mac_learn_notify; NoAction; smac_drop;
+ }
+ const entries = {
+ ( _, _, 0) : mac_learn_notify();
+ ( 0, _, 1) : NoAction();
+ ( _, 0, 1) : mac_learn_notify();
+ ( _, 1, 1) : smac_drop();
+ }
+ }
+
+/************************** Dmac ****************************/
+
+ action change_to_l3(bit<1> to_l3) {
+ is_to_l3 = to_l3;
+ }
+
+ action dmac_unicast(PortId_t port) {
+ send(port);
+ }
+
+ action dmac_miss() {
+ ig_tm_md.mcast_grp_a = (MulticastGroupId_t)src_sid;
+ ig_tm_md.rid = src_sid;
+ /* Set the exclusion id here, since parser can't acces ig_tm_md */
+ ig_tm_md.level2_exclusion_id = meta.port_properties.l2_xid;
+ }
+
+ action dmac_sub_multicast(MulticastGroupId_t mcast_grp) {
+ ig_tm_md.mcast_grp_a = mcast_grp;
+ ig_tm_md.rid = (bit<16>)meta.vid;
+ /* Set the exclusion id here, since parser can't acces ig_tm_md */
+ ig_tm_md.level2_exclusion_id = meta.port_properties.l2_xid;
+ }
+
+ action dmac_super_multicast(MulticastGroupId_t mcast_grp) {
+ ig_tm_md.mcast_grp_a = mcast_grp;
+ ig_tm_md.rid = src_sid;
+ /* Set the exclusion id here, since parser can't acces ig_tm_md */
+ ig_tm_md.level2_exclusion_id = meta.port_properties.l2_xid;
+ }
+
+ action dmac_drop() {
+ drop();
+ exit;
+ }
+
+ table dmac {
+ key = {
+ meta.vid : exact;
+ hdr.ethernet.dst_addr : exact;
+ }
+ actions = {
+ dmac_unicast; dmac_miss; dmac_sub_multicast; dmac_super_multicast; dmac_drop; change_to_l3;
+ }
+ size = MAC_TABLE_SIZE;
+ default_action = dmac_miss();
+ }
+
+
+/**************************** Ipv4/Ipv6 Table*******************************/
+ action set_nexthop(nexthop_id_t id) {
+ nexthop_id = id;
+ }
+
+ table ipv4_host {
+ key = {
+ hdr.ipv4.dst_addr : exact;
+ }
+ actions = {
+ set_nexthop;
+ @defaultonly NoAction;
+ }
+ const default_action = NoAction();
+ size = IPV4_HOST_SIZE;
+ }
+
+ table ipv4_lpm {
+ key = {
+ hdr.ipv4.dst_addr : lpm;
+ }
+ actions = { set_nexthop; }
+ default_action = set_nexthop(0);
+ size = IPV4_LPM_SIZE;
+ }
+
+ table ipv6_host {
+ key = { hdr.ipv6.dst_addr : exact; }
+ actions = {
+ set_nexthop;
+ @defaultonly NoAction;
+ }
+ const default_action = NoAction();
+ size = IPV6_HOST_SIZE;
+ }
+
+ table ipv6_lpm {
+ key = { hdr.ipv6.dst_addr : lpm; }
+ actions = { set_nexthop; }
+
+ default_action = set_nexthop(0);
+ size = IPV6_LPM_SIZE;
+ }
+
+
+/******************************** Nexthop ***********************************/
+
+
+ action l3_switch(PortId_t port, mac_addr_t new_mac_da, mac_addr_t new_mac_sa) {
+ hdr.ethernet.dst_addr = new_mac_da;
+ hdr.ethernet.src_addr = new_mac_sa;
+ ttl_dec = 1;
+ send(port);
+ }
+
+
+ table nexthop {
+ key = { nexthop_id : exact; }
+ actions = { send; drop; l3_switch; }
+ default_action = send(64);
+ size = NEXTHOP_TABLE_SIZE;
+ }
+
+/************************** SubVlan_check table *************************/
+
+
+ action subvlan_send(PortId_t port){
+ dst_sub_port = port;
+ send(port);
+ }
+
+ table subvlan_check{
+ key = {
+ meta.dst_ipv4:exact;
+ meta.vid: exact;
+ }
+ actions = {
+ subvlan_send;
+ change_to_l3;
+ }
+ default_action = change_to_l3(1);
+ size = SUBVLAN_CHECK_TABLE_SIZE;
+ }
+
+
+/************************** ARP Response ********************************/
+ action send_back() {
+ ig_tm_md.ucast_egress_port = ig_intr_md.ingress_port;
+ }
+
+ action send_arp_reply(mac_addr_t gate_mac) {
+ hdr.ethernet.dst_addr = hdr.arp_payload.src_hw_addr;
+ hdr.ethernet.src_addr = gate_mac;
+ hdr.arp.opcode = arp_opcode_t.REPLY;
+
+ hdr.arp_payload.dst_hw_addr = hdr.arp_payload.src_hw_addr;
+ hdr.arp_payload.dst_proto_addr = hdr.arp_payload.src_proto_addr;
+ hdr.arp_payload.src_hw_addr = gate_mac;
+ hdr.arp_payload.src_proto_addr = meta.dst_ipv4;
+
+ send_back();
+ }
+
+ table arp_reply {
+ key = {
+ //hdr.arp.isValid() : exact;
+ //hdr.arp_payload.isValid() : exact;
+ hdr.arp.opcode : exact;
+ }
+ actions = {
+ send_arp_reply;
+ drop;
+ }
+ default_action = drop();
+ }
+
+/****************************** Apply *******************************/
+
+ apply {
+
+ /* Assign Port-based VLAN to untagged/priority-tagged packets */
+ if (meta.vid == 0) {
+ meta.vid = meta.port_properties.port_vid;
+ }
+
+ if (!hdr.vlan_tag.isValid()) {
+ meta.pcp = meta.port_properties.port_pcp;
+ }
+
+ vlan_port.apply();
+ smac.apply();
+ smac_results.apply();
+ switch (dmac.apply().action_run) {
+ dmac_unicast: {
+ if (ig_intr_md.ingress_port ==
+ ig_tm_md.ucast_egress_port) {
+ drop();
+ }
+ }
+ }
+
+ subvlan_check.apply();
+
+ if(is_to_l3 == 1) {
+ if(hdr.arp.isValid() && hdr.arp_payload.isValid()){
+ arp_reply.apply();
+ }
+ else {
+ if (hdr.ipv4.isValid()) {
+ if (meta.ipv4_checksum_err == false) {
+ if (!ipv4_host.apply().hit) {
+ ipv4_lpm.apply();
+ }
+ }
+ }
+ else if (hdr.ipv6.isValid()) {
+ if (hdr.ipv6.hop_limit > 1) {
+ if (!ipv6_host.apply().hit) {
+ ipv6_lpm.apply();
+ }
+ }
+ }
+ nexthop.apply();
+ if (hdr.ipv4.isValid()) {
+ hdr.ipv4.ttl = hdr.ipv4.ttl |-| ttl_dec;
+ }
+ else if (hdr.ipv6.isValid()) {
+ hdr.ipv6.hop_limit = hdr.ipv6.hop_limit |-| ttl_dec;
+ }
+ }
+ }
+
+
+ /* Bridge metadata to the egress pipeline */
+ hdr.bridge.setValid();
+ hdr.bridge.header_type = HEADER_TYPE_BRIDGE;
+ hdr.bridge.header_info = 0; /* Ignore */
+ hdr.bridge.ingress_port = ig_intr_md.ingress_port;
+ hdr.bridge.pcp = meta.pcp;
+ hdr.bridge.dei = meta.dei;
+ hdr.bridge.vid = meta.vid;
+ }
+}
+
+ /********************* D E P A R S E R ************************/
+
+/* This struct is needed for proper digest receive API generation */
+struct l2_digest_t {
+ bit<12> vid;
+ bit<48> src_mac;
+ bit<9> ingress_port;
+ bit<9> mac_move;
+ bit<1> is_static;
+ bit<1> smac_hit;
+}
+
+control IngressDeparser(packet_out pkt,
+ /* User */
+ inout my_ingress_headers_t hdr,
+ in my_ingress_metadata_t meta,
+ /* Intrinsic */
+ in ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md)
+{
+ Checksum() ipv4_checksum;
+ Digest <l2_digest_t>() l2_digest;
+
+ apply {
+ if (ig_dprsr_md.digest_type == L2_LEARN_DIGEST) {
+ l2_digest.pack({
+ meta.vid,
+ hdr.ethernet.src_addr,
+ meta.ingress_port,
+ meta.mac_move,
+ meta.is_static,
+ meta.smac_hit });
+ }
+ hdr.ipv4.hdr_checksum = ipv4_checksum.update({
+ hdr.ipv4.version,
+ hdr.ipv4.ihl,
+ hdr.ipv4.diffserv,
+ hdr.ipv4.total_len,
+ hdr.ipv4.identification,
+ hdr.ipv4.flags,
+ hdr.ipv4.frag_offset,
+ hdr.ipv4.ttl,
+ hdr.ipv4.protocol,
+ hdr.ipv4.src_addr,
+ hdr.ipv4.dst_addr,
+ hdr.ipv4_options.options
+ });
+ pkt.emit(hdr);
+ }
+}
+
+
+/*************************************************************************
+ **************** E G R E S S P R O C E S S I N G *******************
+ *************************************************************************/
+
+ /*********************** H E A D E R S ************************/
+
+struct my_egress_headers_t {
+ ethernet_h ethernet;
+ vlan_tag_h vlan_tag;
+ etherII_h etherII;
+}
+
+ /******** G L O B A L E G R E S S M E T A D A T A *********/
+
+struct my_egress_metadata_t {
+ bridge_h bridge;
+
+ PortId_t ingress_port;
+ bit<3> pcp;
+ bit<1> dei;
+ bit<12> vid;
+}
+
+ /*********************** P A R S E R **************************/
+
+parser EgressParser(packet_in pkt,
+ /* User */
+ out my_egress_headers_t hdr,
+ out my_egress_metadata_t meta,
+ /* Intrinsic */
+ out egress_intrinsic_metadata_t eg_intr_md)
+{
+ inthdr_h inthdr;
+
+ /* This is a mandatory state, required by Tofino Architecture */
+ state start {
+ pkt.extract(eg_intr_md);
+ inthdr = pkt.lookahead<inthdr_h>();
+ transition select(inthdr.header_type, inthdr.header_info) {
+ ( HEADER_TYPE_BRIDGE, _ ) : parse_bridge;
+ default : reject;
+ }
+ }
+
+ state parse_bridge {
+ pkt.extract(meta.bridge);
+ meta.ingress_port = meta.bridge.ingress_port;
+ meta.pcp = meta.bridge.pcp;
+ meta.dei = meta.bridge.dei;
+ meta.vid = meta.bridge.vid;
+ transition parse_ethernet;
+ }
+
+ state parse_ethernet {
+ pkt.extract(hdr.ethernet);
+ transition select(pkt.lookahead<bit<16>>()) {
+ (bit<16>)ether_type_t.TPID &&& 0xEFFF: parse_vlan_tag;
+ default: parse_etherII;
+ }
+ }
+
+ state parse_vlan_tag {
+ pkt.extract(hdr.vlan_tag);
+ transition parse_etherII;
+ }
+
+ state parse_etherII {
+ pkt.extract(hdr.etherII);
+ transition accept;
+ }
+}
+
+ /***************** M A T C H - A C T I O N *********************/
+
+/* This program is written in a modular fashion using multiple different
+ * implementations of the Egress control. You can try to see which ones are
+ * more efficient
+ */
+
+control Egress(
+ /* User */
+ inout my_egress_headers_t hdr,
+ inout my_egress_metadata_t meta,
+ /* Intrinsic */
+ in egress_intrinsic_metadata_t eg_intr_md,
+ in egress_intrinsic_metadata_from_parser_t eg_prsr_md,
+ inout egress_intrinsic_metadata_for_deparser_t eg_dprsr_md,
+ inout egress_intrinsic_metadata_for_output_port_t eg_oport_md)
+{
+ apply{
+ }
+}
+
+ /********************* D E P A R S E R ************************/
+
+control EgressDeparser(packet_out pkt,
+ /* User */
+ inout my_egress_headers_t hdr,
+ in my_egress_metadata_t meta,
+ /* Intrinsic */
+ in egress_intrinsic_metadata_for_deparser_t eg_dprsr_md)
+{
+ apply {
+ pkt.emit(hdr);
+ }
+}
+
+
+/************ F I N A L P A C K A G E ******************************/
+Pipeline(
+ IngressParser(),
+ Ingress(),
+ IngressDeparser(),
+ EgressParser(),
+ Egress(),
+ EgressDeparser()
+) pipe;
+
+Switch(pipe) main;