Hello,
I am using the bmv2 software switch. I am trying to access the queue length for a specific port number in the ingress so I can reroute traffic in case that port is congested. I realized I can only access the enq_qdepth value in egress. Therefore, I have defined a global register to share this value between the egress and ingress control blocks where egress writes the enq_qdepth for each port in the corresponding index of the global register and the ingress reads from the register.
Does this approach make sense? Can I read a value related to standard metadata and write it to a global register and then try to read that value from another control block?
Here is the problem:
According to the log file of the switch, the value written to the register is nonzero because a queue is built up (I have also verified this using the simple_switch_CLI program):
[16:28:54.649] [bmv2] [T] [thread 12964] [602.0] [cxt 0] Wrote register 'approx_queue_depth_pkts' at index 1 with value 16
.
.
.
[16:28:54.649] [bmv2] [T] [thread 12964] [603.0] [cxt 0] Wrote register 'approx_queue_depth_pkts' at index 1 with value 15
However, the value read from the register in the ingress is always 0:
[16:28:50.748] [bmv2] [T] [thread 12961] [602.0] [cxt 0] Read register 'approx_queue_depth_pkts' at index 1 read value 0
.
.
.
[16:28:50.760] [bmv2] [T] [thread 12961] [603.0] [cxt 0] Read register 'approx_queue_depth_pkts' at index 1 read value 0
I donât know why this is happening. I have also taken a look at https://github.com/jafingerhut/p4-guide/blob/master/demo6/demo-global-register.p4_16.p4 for reference. When I simulate this code, it works. But the difference with what I am trying to do is that the value written to the register is not derived from standard metadata in this case.
Here is a snippet of my code that I think is most relevant.
Ingress
apply {
phy_forward.apply();
log_msg("Stat in ingress: egress_spec={}, enq_qdepth={}, deq_qdepth={}",
{stdmeta.egress_spec, stdmeta.enq_qdepth, stdmeta.deq_qdepth});
approx_queue_depth_pkts.read(tmp_count, (bit<32>) 1);
log_msg("Register read in ingress: {}",
{tmp_count});
if(tmp_count > 7) {
stdmeta.egress_spec = (bit<9>) 3;
}
}
egress
log_msg("Stat in egress: enq_qdepth={}, deq_qdepth={}",
{stdmeta.enq_qdepth, stdmeta.deq_qdepth});
bit<32> value = (bit<32>)stdmeta.deq_qdepth;
approx_queue_depth_pkts.write((bit<32>) 1, value);
Here is my complete code:
#include <core.p4>
#include <v1model.p4>
typedef bit<9> egressSpec_t;
header ethernet_t {
bit<48> dstAddr;
bit<48> srcAddr;
bit<16> etherType;
}
struct metadata_t {
}
struct headers_t {
ethernet_t ethernet;
}
typedef bit<32> PktCount_t;
register<PktCount_t>(3) approx_queue_depth_pkts;
parser parserImpl(packet_in packet,
out headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t stdmeta)
{
state start {
packet.extract(hdr.ethernet);
transition accept;
}
}
control ingressImpl(inout headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t stdmeta)
{
PktCount_t tmp_count;
action drop() {
mark_to_drop(stdmeta);
}
action forward(egressSpec_t port) {
stdmeta.egress_spec = port;
}
table phy_forward {
key = {
stdmeta.ingress_port: exact;
}
actions = {
forward;
drop;
}
size = 1024;
default_action = drop();
}
apply {
phy_forward.apply();
log_msg("Stat in ingress: egress_spec={}, enq_qdepth={}, deq_qdepth={}",
{stdmeta.egress_spec, stdmeta.enq_qdepth, stdmeta.deq_qdepth});
approx_queue_depth_pkts.read(tmp_count, (bit<32>) 1);
log_msg("Register read in ingress: {}",
{tmp_count});
if(tmp_count > 7) {
stdmeta.egress_spec = (bit<9>) 3;
}
}
}
control egressImpl(inout headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t stdmeta)
{
apply {
log_msg("Stat in egress: enq_qdepth={}, deq_qdepth={}",
{stdmeta.enq_qdepth, stdmeta.deq_qdepth});
bit<32> value = (bit<32>)stdmeta.deq_qdepth;
approx_queue_depth_pkts.write((bit<32>) 1, value);
}
}
control deparserImpl(packet_out packet,
in headers_t hdr)
{
apply {
packet.emit(hdr.ethernet);
}
}
control verifyChecksum(inout headers_t hdr, inout metadata_t meta) {
apply { }
}
control updateChecksum(inout headers_t hdr, inout metadata_t meta) {
apply { }
}
V1Switch(parserImpl(),
verifyChecksum(),
ingressImpl(),
egressImpl(),
updateChecksum(),
deparserImpl()) main;