Help, what's wrong with the P4 program?

I modified the code and added a telemetry in the header. After the first switch added telemetry, the second switch could not recognize telemetry. I searched for a day and couldn’t figure out the reason.Hope someone can help me.Thank you so much.

/*************************************************************************
*********************** H E A D E R S  ***********************************
*************************************************************************/

const bit<16> TYPE_IPV4 = 0x800;
const bit<16> TELE = 0x7777;

typedef bit<9>  egressSpec_t;
typedef bit<48> macAddr_t;
typedef bit<32> ip4Addr_t;
typedef bit<16> enq_qdepth_t;
typedef bit<16> nextHeaderType_t;


header ethernet_t {
    macAddr_t dstAddr;
    macAddr_t srcAddr;
    bit<16>   etherType;
}

header ipv4_t {
    bit<4>    version;
    bit<4>    ihl;
    bit<6>    dscp;
    bit<2>    ecn;
    bit<16>   totalLen;
    bit<16>   identification;
    bit<3>    flags;
    bit<13>   fragOffset;
    bit<8>    ttl;
    bit<8>    protocol;
    bit<16>   hdrChecksum;
    ip4Addr_t srcAddr;
    ip4Addr_t dstAddr;
}

header tcp_t{
    bit<16> srcPort;
    bit<16> dstPort;
    bit<32> seqNo;
    bit<32> ackNo;
    bit<4>  dataOffset;
    bit<4>  res;
    bit<1>  cwr;
    bit<1>  ece;
    bit<1>  urg;
    bit<1>  ack;
    bit<1>  psh;
    bit<1>  rst;
    bit<1>  syn;
    bit<1>  fin;
    bit<16> window;
    bit<16> checksum;
    bit<16> urgentPtr;
}

header udp_t{
    bit<16> srcPort;
    bit<16> dstPort;
    bit<16> len;
    bit<16> checksum;
}

header telemetry_t{
    enq_qdepth_t enq_qdepth;
    nextHeaderType_t nextHeaderType;
}

struct metadata {
    bit<14> ecmp_hash;
    bit<14> ecmp_group_id;
}

struct headers {
    ethernet_t   ethernet;
    telemetry_t  telemetry;
    ipv4_t       ipv4;
    tcp_t        tcp;
    udp_t        udp;
}
/*************************************************************************
*********************** P A R S E R  *******************************
*************************************************************************/

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

    state start {

        transition parse_ethernet;

    }

    state parse_ethernet {

        packet.extract(hdr.ethernet);
        transition select(hdr.ethernet.etherType){
            TYPE_IPV4: parse_ipv4;
            TELE: parse_telemetry;
            default: accept;
        }
    }
    
    state parse_telemetry{
    	packet.extract(hdr.telemetry);
    	transition select(hdr.telemetry.nextHeaderType){
    	TYPE_IPV4: parse_ipv4;
    	default: accept;
    	}
    }

    state parse_ipv4 {
        packet.extract(hdr.ipv4);
        transition select(hdr.ipv4.protocol){
           17: parse_udp;
            default: accept;
        }
    }

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

}

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

control MyDeparser(packet_out packet, in headers hdr) {
    apply {
    	

        //parsed headers have to be added again into the packet.
        packet.emit(hdr.ethernet);
        packet.emit(hdr.telemetry);
        packet.emit(hdr.ipv4);

        //Only emited if valid
        packet.emit(hdr.udp);
    }
}
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

//My includes
#include "include/headers.p4"
#include "include/parsers.p4"

/*************************************************************************
************   C H E C K S U M    V E R I F I C A T I O N   *************
*************************************************************************/

control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
    apply {  }
}

/*************************************************************************
**************  I N G R E S S   P R O C E S S I N G   *******************
*************************************************************************/

control MyIngress(inout headers hdr,
                  inout metadata meta,
                  inout standard_metadata_t standard_metadata) {
    action drop() {
        mark_to_drop(standard_metadata);
    }

    action ecmp_group(bit<14> ecmp_group_id, bit<16> num_nhops){
        hash(meta.ecmp_hash,
	    HashAlgorithm.crc16,
	    (bit<1>)0,
	    { hdr.ipv4.srcAddr,
	      hdr.ipv4.dstAddr,
              hdr.udp.srcPort,
              hdr.udp.dstPort,
              hdr.ipv4.protocol},
	      num_nhops);

	    meta.ecmp_group_id = ecmp_group_id;
    }

    action set_nhop(macAddr_t dstAddr, egressSpec_t port) {

        //set the src mac address as the previous dst, this is not correct right?
        hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;

       //set the destination mac address that we got from the match in the table
        hdr.ethernet.dstAddr = dstAddr;

        //set the output port that we also get from the table
        standard_metadata.egress_spec = port;

        //decrease ttl by 1
        hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
    }

    table ecmp_group_to_nhop {
        key = {
            meta.ecmp_group_id:    exact;
            meta.ecmp_hash: exact;
        }
        actions = {
            drop;
            set_nhop;
        }
        size = 1024;
    }

    table ipv4_lpm {
        key = {
            hdr.ipv4.dstAddr: lpm;
        }
        actions = {
            set_nhop;
            ecmp_group;
            drop;
        }
        size = 1024;
        default_action = drop;
    }

    apply {
        if (hdr.ipv4.isValid()){
            switch (ipv4_lpm.apply().action_run){
                ecmp_group: {
                    ecmp_group_to_nhop.apply();
                }
            }
        }
    }

}
/*************************************************************************
****************  E G R E S S   P R O C E S S I N G   *******************
*************************************************************************/

control MyEgress(inout headers hdr,
                 inout metadata meta,
                 inout standard_metadata_t standard_metadata) {
    action add_telemetry_header(){
    	     hdr.telemetry.nextHeaderType = TYPE_IPV4;
    	     hdr.ethernet.etherType = TELE;
    	     hdr.telemetry.enq_qdepth = (bit<16>)standard_metadata.enq_qdepth;
    	     hdr.telemetry.setValid();
    	}
    	
    action update_telemetry_header(){
    	     if((bit<16>)standard_metadata.enq_qdepth > hdr.telemetry.enq_qdepth){
    	     	hdr.telemetry.enq_qdepth = (bit<16>)standard_metadata.enq_qdepth;
    	     }}
    
    apply {
    	if(hdr.udp.isValid() && hdr.udp.dstPort == 7777){
    		if(hdr.telemetry.isValid()){
    			update_telemetry_header();
    		}else{
    			add_telemetry_header();
    		}
    	}
    	
    }

   }
   


/*************************************************************************
*************   C H E C K S U M    C O M P U T A T I O N   **************
*************************************************************************/

control MyComputeChecksum(inout headers hdr, inout metadata meta) {
     apply {
	update_checksum(
	    hdr.ipv4.isValid(),
            { hdr.ipv4.version,
	      hdr.ipv4.ihl,
              hdr.ipv4.dscp,
              hdr.ipv4.ecn,
              hdr.ipv4.totalLen,
              hdr.ipv4.identification,
              hdr.ipv4.flags,
              hdr.ipv4.fragOffset,
              hdr.ipv4.ttl,
              hdr.ipv4.protocol,
              hdr.ipv4.srcAddr,
              hdr.ipv4.dstAddr },
              hdr.ipv4.hdrChecksum,
              HashAlgorithm.csum16);
    }
}

/*************************************************************************
***********************  S W I T C H  *******************************
*************************************************************************/

//switch architecture
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;

Are you familiar with the debug logs that are optionally generated by the simple_switch_grpc program while it processes packets? It shows a line of output for just about every line of P4 code executed while processing the packets it receives, and can thus tell you all of the branches taken during parsing transition select statements, all if statement condition values, and all table lookup keys and results, i.e. all of the things that decide which path through your program it takes.

Use these command line options, if they are not already there. If they are already there, learn where the log files are written:

--log-file ss-log --log-flush

It can also optionally dump the full byte sequence of all packets sent and received, if you use these command line options when starting it:

--dump-packet-data 10000 
I checked the log and found that I had changed the nextHeaderType to TYPE_IPV4 on the previous switch, but it showed 0X0000 when parsed on the next switch. What is the reason? Below is my running log and key code
[16:46:50.925] [bmv2] [D] [thread 3567] [1010.0] [cxt 0] Pipeline 'egress': start
[16:46:50.925] [bmv2] [T] [thread 3567] [1010.0] [cxt 0] /home/yyj/桌面/conga/p4src/conga.p4(113) Condition "hdr.udp.isValid() && hdr.udp.dstPort == 7777" (node_7) is true
[16:46:50.925] [bmv2] [T] [thread 3567] [1010.0] [cxt 0] /home/yyj/桌面/conga/p4src/conga.p4(114) Condition "hdr.telemetry.isValid()" (node_8) is false
[16:46:50.925] [bmv2] [T] [thread 3567] [1010.0] [cxt 0] Applying table 'tbl_add_telemetry_header'
[16:46:50.925] [bmv2] [D] [thread 3567] [1010.0] [cxt 0] Looking up key:

[16:46:50.925] [bmv2] [D] [thread 3567] [1010.0] [cxt 0] Table 'tbl_add_telemetry_header': miss
[16:46:50.925] [bmv2] [D] [thread 3567] [1010.0] [cxt 0] Action entry is MyEgress.add_telemetry_header - 
[16:46:50.925] [bmv2] [T] [thread 3567] [1010.0] [cxt 0] Action MyEgress.add_telemetry_header
[16:46:50.925] [bmv2] [T] [thread 3567] [1010.0] [cxt 0] /home/yyj/桌面/conga/p4src/include/headers.p4(5) Primitive 0x800; ...
[16:46:50.925] [bmv2] [T] [thread 3567] [1010.0] [cxt 0] /home/yyj/桌面/conga/p4src/include/headers.p4(6) Primitive 0x7777; ...
[16:46:50.925] [bmv2] [T] [thread 3567] [1010.0] [cxt 0] /home/yyj/桌面/conga/p4src/conga.p4(103) Primitive hdr.telemetry.enq_qdepth = (bit<16>)standard_metadata.enq_qdepth
[16:46:50.925] [bmv2] [T] [thread 3567] [1010.0] [cxt 0] /home/yyj/桌面/conga/p4src/conga.p4(104) Primitive hdr.telemetry.setValid()
[16:46:50.925] [bmv2] [D] [thread 3567] [1010.0] [cxt 0] Pipeline 'egress': end
[16:46:49.637] [bmv2] [D] [thread 3576] [267.0] [cxt 0] Parser 'parser': start
[16:46:49.637] [bmv2] [D] [thread 3576] [267.0] [cxt 0] Parser 'parser' entering state 'start'
[16:46:49.637] [bmv2] [D] [thread 3576] [267.0] [cxt 0] Extracting header 'ethernet'
[16:46:49.637] [bmv2] [D] [thread 3576] [267.0] [cxt 0] Parser state 'start': key is 7777
[16:46:49.637] [bmv2] [T] [thread 3576] [267.0] [cxt 0] Bytes parsed: 14
[16:46:49.638] [bmv2] [D] [thread 3576] [267.0] [cxt 0] Parser 'parser' entering state 'parse_telemetry'
[16:46:49.638] [bmv2] [D] [thread 3576] [267.0] [cxt 0] Extracting header 'telemetry'
[16:46:49.638] [bmv2] [D] [thread 3576] [267.0] [cxt 0] Parser state 'parse_telemetry': key is 0000
[16:46:49.638] [bmv2] [T] [thread 3576] [267.0] [cxt 0] Bytes parsed: 18
[16:46:49.638] [bmv2] [D] [thread 3576] [267.0] [cxt 0] Parser 'parser': end
control MyEgress(inout headers hdr,
                 inout metadata meta,
                 inout standard_metadata_t standard_metadata) {
    action add_telemetry_header(){
    	     hdr.telemetry.nextHeaderType = TYPE_IPV4;
    	     hdr.ethernet.etherType = TELE;
    	     hdr.telemetry.enq_qdepth = (bit<16>)standard_metadata.enq_qdepth;
    	     hdr.telemetry.setValid();
    	}
    	
    action update_telemetry_header(){
    	     if((bit<16>)standard_metadata.enq_qdepth > hdr.telemetry.enq_qdepth){
    	     	hdr.telemetry.enq_qdepth = (bit<16>)standard_metadata.enq_qdepth;
    	     }}
    
    apply {
    	if(hdr.udp.isValid() && hdr.udp.dstPort == 7777){
    		if(hdr.telemetry.isValid()){
    			update_telemetry_header();
    		}else{
    			add_telemetry_header();
    		}
    	}
    	
    }

   }
   

Hi @997879324 ,

Imho your problem is there :

action add_telemetry_header(){
hdr.telemetry.nextHeaderType = TYPE_IPV4;
hdr.ethernet.etherType = TELE;
hdr.telemetry.enq_qdepth = (bit<16>)standard_metadata.enq_qdepth; hdr.telemetry.setValid();

}

You should call setValid() at the beginning of your action because, at the moment, you are writing values to hdr.telemetry, which does not exist yet. As a result, your values are not being written to the header. Then after that you are adding the hdr.telemetry which is empty.

In more detail, P4~16~ Language Specification