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);
}
}