Is it possible to modify the metadata variable before storing it in the register?

I want to write a program to calculate the minimum tcp/udp header length for each network flow. To achieve this goal,I am using three registers to simulate a count min sketch.
Since the header length that needs to be stored in the register is the header length of a TCP packet, I need to multiply the header length in the packet header by 4 to get the actual header length in bytes. But doing so causes a compilation error. The architecture I am using is Intel’s Tofino architecture.

I got an error while compileing the program:

The following fields were not allocated: 
    ingress::meta.header_len2<16b>[3:0]
    ingress::meta.header_len<16b>[3:0]
    ingress::meta.header_len4<16b>[3:0]
    ingress::meta.header_len2<16b>[15:4]
    ingress::meta.header_len<16b>[15:4]
    ingress::meta.header_len4<16b>[15:4]

Here’s the program

#include <core.p4>
#include <tna.p4>


typedef bit<48> mac_addr_t;

const bit<32> STAGE_SIZE = 1 << 16;

typedef bit<16> stage_length_t;

enum bit<16> ether_type_t {
    TPID       = 0x8100,
    IPV4       = 0x0800
}

/*************************************************************************
 ***********************  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;
    ether_type_t  ether_type;
}

header ipv4_h {
    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;
    bit<8>   protocol;
    bit<16>  hdr_checksum;
    bit<32>  src_addr;
    bit<32>  dst_addr;
}

header udp_h {
    bit<16>  src_port;
    bit<16>  dst_port;
    bit<16>  len;
    bit<16>  checksum;
}

header tcp_h {
    bit<16>  src_port;
    bit<16>  dst_port;
    bit<32>  seq_no;
    bit<32>  ack_no;
    bit<4>   data_offset;
    bit<4>   res;
    bit<8>   flags;
    bit<16>  window;
    bit<16>  checksum;
    bit<16>  urgent_ptr;
}

/*************************************************************************
 **************  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 {
    ethernet_h         ethernet;

    ipv4_h             ipv4;
    tcp_h              tcp;
    udp_h              udp;
}

    /******  G L O B A L   I N G R E S S   M E T A D A T A  *********/

struct flow_id_t
{
    bit<32>  ipsrc;
    bit<32> ipdst;
    bit<16>  src_port;
    bit<16>  dst_port;
}

struct pair_32
{
    bit<32>     left;
    bit<32>     right;
}

struct my_ingress_metadata_t {
    flow_id_t           flow_id;
    stage_length_t      stage1_index;
    stage_length_t      stage2_index;
    stage_length_t      stage3_index;
    bit<16>             header_len;
    bit<16>             header_len2;
    bit<16>             header_len4;
    bit<16>             total_len;
    bit<16>             ihl;
    bit<16>             payload;
}


    /***********************  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)
{
    /* This is a mandatory state, required by Tofino Architecture */
    state start {
        pkt.extract(ig_intr_md);
        pkt.advance(PORT_METADATA_SIZE);
        transition parse_ethernet;
    }

    state parse_ethernet {
        pkt.extract(hdr.ethernet);
        /* 
         * The explicit cast allows us to use ternary matching on
         * serializable enum
         */        
        transition select((bit<16>)hdr.ethernet.ether_type) {
            (bit<16>)ether_type_t.IPV4            :  parse_ipv4;
            default :  accept;
        }
    }

    state parse_ipv4 {
        pkt.extract(hdr.ipv4);
        meta.flow_id.ipsrc=hdr.ipv4.src_addr;
        meta.flow_id.ipdst=hdr.ipv4.dst_addr;
        meta.total_len = hdr.ipv4.total_len;
        meta.ihl = (bit<16>)hdr.ipv4.ihl;
        transition select(hdr.ipv4.protocol) {
            6   : parse_tcp;
            17 : parse_udp;
            default : accept;
	    }
    }

    state parse_tcp {
        pkt.extract(hdr.tcp);
        meta.header_len = (bit<16>)hdr.tcp.data_offset;
        meta.flow_id.src_port = hdr.tcp.src_port;
        meta.flow_id.dst_port = hdr.tcp.dst_port;
        transition accept;
    }

    state parse_udp {
        pkt.extract(hdr.udp);
        meta.header_len = (bit<16>)8;
        meta.flow_id.src_port = hdr.udp.src_port;
        meta.flow_id.dst_port = hdr.udp.dst_port;
        transition accept;
	}

}


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) 
{

	CRCPolynomial<bit<32>>(0x11111111,true,false,false,32w0xFFFFFFFF,32w0xFFFFFFFF) crc32_stage1;
    Hash<stage_length_t>(HashAlgorithm_t.CRC32,crc32_stage1) hash_stage1;
    CRCPolynomial<bit<32>>(0x12222222,true,false,false,32w0xFFFFFFFF,32w0xFFFFFFFF) crc32_stage2;
    Hash<stage_length_t>(HashAlgorithm_t.CRC32,crc32_stage2) hash_stage2;
    CRCPolynomial<bit<32>>(0x13333333,true,false,false,32w0xFFFFFFFF,32w0xFFFFFFFF) crc32_stage3;
    Hash<stage_length_t>(HashAlgorithm_t.CRC32,crc32_stage3) hash_stage3;

	bit<32> result_stage1;
    bit<32> result_stage2;
    bit<32> result_stage3;
    bit<32> min_1;
    bit<32> min_2;

    Register<bit<32>, stage_length_t>(0x4000) stage1_register;
	RegisterAction<bit<32>, stage_length_t, bit<32>>(stage1_register) stage1_insert=
    {
        void apply(inout bit<32> data, out bit<32> result) 
        {
            data = min(data, (bit<32>)meta.header_len4);
            result = data;
        }
    };

    Register<bit<32>, stage_length_t>(0x4000) stage2_register;
    RegisterAction<bit<32>, stage_length_t, bit<32>>(stage2_register) stage2_insert=
    {
        void apply(inout bit<32> data, out bit<32> result) 
        {
            data = min(data, (bit<32>)meta.header_len4);
            result = data;
        }
    };


    Register<bit<32>, stage_length_t>(0x4000) stage3_register;
    RegisterAction<bit<32>, stage_length_t, bit<32>>(stage3_register) stage3_insert=
    {
        void apply(inout bit<32> data, out bit<32> result) 
        {
            data = min(data, (bit<32>)meta.header_len4);
            result = data;
        }
    };

    action cal_index_stage1()
    {
        meta.stage1_index = hash_stage1.get({meta.flow_id.ipsrc,meta.flow_id.ipdst,meta.flow_id.src_port,meta.flow_id.dst_port});        
    }
    table cal_index_stage1_t
    {
        actions={cal_index_stage1;}
        default_action=cal_index_stage1;
    }

	action cal_index_stage2()
    {
        meta.stage2_index = hash_stage2.get({meta.flow_id.ipsrc,meta.flow_id.ipdst,meta.flow_id.src_port,meta.flow_id.dst_port});        
    }
	table cal_index_stage2_t
    {
        actions={cal_index_stage2;}
        default_action=cal_index_stage2;
    }

    action cal_index_stage3()
    {
        meta.stage3_index = hash_stage3.get({meta.flow_id.ipsrc,meta.flow_id.ipdst,meta.flow_id.src_port,meta.flow_id.dst_port});        
    }
    table cal_index_stage3_t
    {
        actions={cal_index_stage3;}
        default_action=cal_index_stage3;
    }


    action get_min1()
    {
        min_1=min(result_stage1,result_stage2);
    }
@stage(5)    table get_min1_t
    {
        actions={get_min1;}
        default_action=get_min1;
    }
    action get_min2()//计算index
    {
        min_2=min(result_stage3,min_1);
    }
@stage(5)    table get_min2_t
    {
        actions={get_min2;}
        default_action=get_min2;
    }
    
    action cal_header2()
    {
        meta.header_len2 = meta.header_len + meta.header_len;
    }
 @stage(2)   table cal_header2_t
    {
        actions={cal_header2;}
        default_action=cal_header2;
    }

    action cal_header4()
    {
        meta.header_len4 = meta.header_len2 + meta.header_len2;
    }
 @stage(3)   table cal_header4_t
    {
        actions={cal_header4;}
        default_action=cal_header4;
    }

    apply 
    {
        if (hdr.ipv4.isValid() && (hdr.udp.isValid() || hdr.tcp.isValid()) )
        {
            if (hdr.tcp.isValid())
            {
                cal_header2_t.apply();
                cal_header4_t.apply();
            }
            meta.ihl = meta.ihl * 4;

            cal_index_stage1_t.apply();
            cal_index_stage2_t.apply();
            cal_index_stage3_t.apply();
            
            result_stage1 = stage1_insert.execute(meta.stage1_index);
            result_stage2 = stage2_insert.execute(meta.stage2_index);
            result_stage3 = stage3_insert.execute(meta.stage3_index);
            
            get_min1_t.apply();
            get_min2_t.apply();
        }
    }
    
    
}

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)
{
    apply {
        pkt.emit(hdr);
    }
}

Hi @eason2018 ,

Please find this thread on the forum when it comes to asking question about the Intel Tofino.

Cheers,

I am sorry. Is it poiisble to move this post to intel tofino forum?

Unfortunately, it is not possible to move this post to another forum. Please create it in the forum posted above :slight_smile: