Sum QoS throughout

Hi,

I’m trying to assign a value to each packet, and eventually I want to hold a counter that sums this value for every packet that passes through my switch. ( I want to measure the throughput kind of)
I tried reading and implementing the code in the specification file but it didn’t work for some reason.

Note I use DPDK as switch - psa arch.


action update_pkt_count (inout bit<8> counter, in psa_ingress_output_metadata_t ostd )
{	
	counter = counter + (bit<8>)ostd.class_of_service;
}

control ingress(
	inout my_ingress_headers_t hdr,
	inout my_ingress_metadata_t meta,
	in psa_ingress_input_metadata_t ig_intr_md,
	inout psa_ingress_output_metadata_t ostd
)
{

	Register<bit<8>, bit<8>>(5) reg_counter;

	/*
	 * If got match -> egress
	 * to port 1 else drop
	 */
	action send(PortId_t port, ClassOfService_t class) {
		bit<8> tmp;
		
		tmp = reg_counter.read(0);
		update_pkt_count(tmp, class);
		reg_counter.write(0, tmp);

		ostd.egress_port = (PortId_t) port;
		ostd.drop = false;
		ostd.class_of_service = (ClassOfService_t) class;


	}

By the way, our main goal is build buffer overflow algorithm is is possible?
since I red in the spec file that we can’t configure the buffering Q by P4, but is there is another way to impact this Q?

Thanks in advance

GUY

From looking at your P4 code, it appears you are using a PSA register extern correctly, for maintaining a sum of “class” values for each packet in index 0 of the register array.

You say “it did not work for some reason”. That isn’t much information for us to go on. If you can provide significantly more detail similar to “I ran these commands, sent in packet A, the value of the register was X before the packet went in (which I know because of reason Y), but it did not change when the packet was processed (which I know for reason Z). Why didn’t it change?” or whatever steps you actually followed, that might enable someone to give more specific suggestions than “well, looks like you need to do some debugging to find out what is going wrong”.

Dear Guy,

Unfortunately you neglected to provide both the program and the description of the issue you are facing.

The code fragment you provided contains a very basic mistake: the action update_pkt_count() expects its second argument to have the type psa_ingress_output_metadata_t

action update_pkt_count (inout bit<8> counter, in psa_ingress_output_metadata_t ostd )
{	
	counter = counter + (bit<8>)ostd.class_of_service;
}

However, it is invoked with the second parameter having the type ClassOfService_t:

update_pkt_count(tmp, class);

While many targets should allow you to increment a register by a certain value, I have trouble ascribing any logic in adding together the values of ClassOfService…

I suggest you think carefully about what you doing and re-post.

Happy hacking,
Vladimir

The main goal is to sum the value of all QoS in order to be able to measure the
“weight” of the buffer in sum situation of burst of packet on the same time. Then
I can decide to drop/save the packets from the buffer.

Hi
I really don’t know what is wrong in my implementation:

#include <core.p4>
#include <psa.p4>

const bit<16> ETHERTYPE_TPID = 0x8100;
const bit<16> ETHERTYPE_IPV4 = 0x0800;

/* Define all the headers the program will recognize
 * The actual sets of headers processed by each gress can differ
 */

header ethernet_h {
	bit<48>   dst_addr;
	bit<48>   src_addr;
	bit<16>   ether_type;
}

header vlan_tag_h {
	bit<16> pcp_cfi_vid;
	bit<16>  ether_type;
}

header ipv4_h {
	bit<8>       version_ihl;
	bit<8>       diffserv;
	bit<16>      total_len;
	bit<16>      identification;
	bit<16>      flags_frag_offset;
	bit<8>       ttl;
	bit<8>       protocol;
	bit<16>      hdr_checksum;
	bit<32>      src_addr;
	bit<32>      dst_addr;
}

const int IPV4_HOST_SIZE = 65536;

typedef bit<48> ethernet_addr_t;

struct my_ingress_headers_t {
	ethernet_h   ethernet;
	vlan_tag_h   vlan_tag;
	ipv4_h       ipv4;
}

struct my_ingress_metadata_t {
}

struct empty_metadata_t {
}

parser Ingress_Parser(
	packet_in pkt,
	out my_ingress_headers_t hdr,
	inout my_ingress_metadata_t meta,
	in psa_ingress_parser_input_metadata_t ig_intr_md,
	in empty_metadata_t resub_meta,
	in empty_metadata_t recirc_meta)
{
	 state start {
		transition parse_ethernet;
	}

	state parse_ethernet {
		pkt.extract(hdr.ethernet);
		transition select(hdr.ethernet.ether_type) {
			ETHERTYPE_TPID:  parse_vlan_tag;
			ETHERTYPE_IPV4:  parse_ipv4;
			default: accept;
		}
	}

	state parse_vlan_tag {
		pkt.extract(hdr.vlan_tag);
		transition select(hdr.vlan_tag.ether_type) {
			ETHERTYPE_IPV4:  parse_ipv4;
			default: accept;
		}
	}

	state parse_ipv4 {
		pkt.extract(hdr.ipv4);
		transition accept;
	}

}

action update_pkt_count (inout bit<8> counter, in ClassOfService_t class )
{	
	counter = counter + (bit<8>)class;
}

control ingress(
	inout my_ingress_headers_t hdr,
	inout my_ingress_metadata_t meta,
	in psa_ingress_input_metadata_t ig_intr_md,
	inout psa_ingress_output_metadata_t ostd
)
{
	Register<bit<8>, bit<8>>(5) reg_counter;

	/*
	 * If got match -> egress
	 * to port 1 else drop
	 */
	action send(PortId_t port, ClassOfService_t class) {
		bit<8> tmp;

		ostd.egress_port = (PortId_t) port;
		ostd.drop = false;
		ostd.class_of_service = (ClassOfService_t) class;
		
		tmp = reg_counter.read(0);
		update_pkt_count(tmp, ostd.class_of_service);
		reg_counter.write(0, tmp);
	}

	action drop() {
		ostd.drop = true;
	}
	
	action set_port_and_src_mac( PortId_t port,
								 ethernet_addr_t src_mac,
								 ethernet_addr_t dst_mac) {
	send_to_port(ostd, port);
		hdr.ethernet.src_addr = src_mac;
		hdr.ethernet.dst_addr = dst_mac;
	}

	table ipv4_host {
		key = { hdr.ipv4.dst_addr : exact; }
		actions = {
			send;drop;
			@defaultonly NoAction;
		}

		const default_action = NoAction();

		size = IPV4_HOST_SIZE;
	}

	apply {
				ipv4_host.apply();
	}
}

control Ingress_Deparser(packet_out pkt,
	out empty_metadata_t clone_i2e_meta,
	out empty_metadata_t resubmit_meta,
	out empty_metadata_t normal_meta,
	inout my_ingress_headers_t hdr,
	in    my_ingress_metadata_t meta,
	in psa_ingress_output_metadata_t istd)
{
	apply {
		pkt.emit(hdr);
	}
}

struct my_egress_headers_t {
}

struct my_egress_metadata_t {
}

parser Egress_Parser(
	packet_in pkt,
	out my_egress_headers_t hdr,
	inout my_ingress_metadata_t meta,
	in psa_egress_parser_input_metadata_t istd,
	in empty_metadata_t normal_meta,
	in empty_metadata_t clone_i2e_meta,
	in empty_metadata_t clone_e2e_meta)
{
	state start {
		transition accept;
	}
}

control egress(
	inout my_egress_headers_t hdr,
	inout my_ingress_metadata_t meta,
	in psa_egress_input_metadata_t istd,
	inout psa_egress_output_metadata_t ostd)
{
	apply {
	}
}

control Egress_Deparser(packet_out pkt,
	out empty_metadata_t clone_e2e_meta,
	out empty_metadata_t recirculate_meta,
	inout my_egress_headers_t hdr,
	in my_ingress_metadata_t meta,
	in psa_egress_output_metadata_t istd,
	in psa_egress_deparser_input_metadata_t edstd)
{
	apply {
		pkt.emit(hdr);
	}
}

#if __p4c__
bit<32> test_version = __p4c_version__;
#endif

IngressPipeline(Ingress_Parser(), ingress(), Ingress_Deparser()) pipe;

EgressPipeline(Egress_Parser(), egress(), Egress_Deparser()) ep;

PSA_Switch(pipe, PacketReplicationEngine(), ep, BufferingQueueingEngine()) main;

when I send traffic I see that there is matches in my table:

pipeline> pipeline PIPELINE0 stats
Davidi's: status counter: 4
Input ports:
        Port 0: packets 224060118 bytes 13443607080 empty 13799034802
        Port 1: packets 254070246 bytes 15244214760 empty 13769024679

Output ports:
        Port 0: packets 0 bytes 0 clone 0 clonerr 0
        Port 1: packets 357764924 bytes 21465895440 clone 0 clonerr 0
        DROP: packets 120365439 bytes 5536810194 clone 0 clonerr 0

Davidi's-Tables:
        Table ipv4_host:
                Hit (packets): 357764928
                Miss (packets): 120365440
                Action NoAction (packets): 120365440
                Action send (packets): 357764928
                Action drop_1 (packets): 0

Learner tables:
pipeline> pipeline PIPELINE0 regrd reg_counter 0
Command failed.

but as you can see I can read the reg value from dpdk application CLI.

I configure the table like:

match 0x0A000000 action send port 0x1 class 17
match 0x0B652B58 action send port 0x0 class 11

I would expect to get 17+… for those packets that got match

Thanks in advance!

Guy

Do you have a recommendation for another architecture that is complete and supported by DPDK?

PSA and PNA are the only two architectures implemented by the DPDK back end that I know of. Both of those should implement the same Register extern, so if there is something wrong with it for one of them, it is probably also similar for the other architecture, too.

I can try using the Register extern myself on DPDK with the PSA architecture to see if I get similar results as you.

One possibility is that the Register extern “mostly works”, i.e. the data plane methods work, but that it is not yet implemented correctly to write and read the Register from a controller via the P4Runtime API. See this issue, for example: Support to read & write Register by PI · Issue #376 · p4lang/PI · GitHub

The ideal solution is to implement this so that it works, of course, but a workaround is to use PacketIn and PacketOut and perhaps a little extra P4 code to enable writing and reading P4 registers via those packets injected from the controller. An example of this for the v1model architecture on BMv2 using the P4Runtime API PacketIn and PacketOut can be found here, but something nearly the same should hopefully work with DPDK PSA architecture, too (I have not tried yet): p4-guide/ptf-tests/registeraccess at master · jafingerhut/p4-guide · GitHub