p4-lang

Invalid key type for BPF_MAP_TYPE_ARRAY. P4 programm based on ebpf_model.p4 template


I am writing a P4 programm, and will later load it into the kernel for cilium development. For the test I have no one byte counter. P4 to count the byte that comes to the computer.

Based on this repository:

https://github.com/p4lang/p4c/blob/main/backends/ebpf/README.md

  1. I will first write my own p4 code and use p4c-ebpf to transform it to ebpf C file
  2. use clang to compile it to .o file which can be used for further kernel loading.
  3. I will use tc or bpftool to load it to kernel(under Cilium related TC folder) hier is my p4 code, epbf_model.p4 can be seen under this link:https://github.com/p4lang/p4c/tree/main/backends/ebpf/p4include
#include "ebpf_model.p4"

// Define headers
header ethernet_t {
    bit<48> dstAddr;
    bit<48> srcAddr;
    bit<16> etherType;
}

header ipv4_t {
    bit<4> version;
    bit<4> ihl;
    bit<8> diffserv;
    bit<16> totalLen;
    bit<16> identification;
    bit<3> flags;
    bit<13> fragOffset;
    bit<8> ttl;
    bit<8> protocol;
    bit<16> hdrChecksum;
    bit<32> srcAddr;
    bit<32> dstAddr;
}

struct headers {
    ethernet_t ethernet;
    ipv4_t ipv4;
}

// Define the parser
parser MyParser(packet_in pkt, out headers hdr) {
    state start {
        pkt.extract(hdr.ethernet);
        transition select(hdr.ethernet.etherType) {
            0x0800: parse_ipv4;
            default: accept;
        }
    }

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

// Define the filter control block
control MyFilter(inout headers hdr, out bool accept) {
    // Define the counter array as per the model
    CounterArray(32w1, false) byte_counter;
    //bit<32> byteCount;

    apply {
        //byteCount = 0;
        if (hdr.ipv4.isValid()) {
            // Cast totalLen to bit<32> and add to counter
            byte_counter.add(32w0, (bit<32>)hdr.ipv4.totalLen);
            // Update byteCount
            //byteCount = byteCount + (bit<32>)hdr.ipv4.totalLen;
        }
        // Set accept to true
        accept = true;
    }
}

// Define the package
//package ebpfFilter(MyParser(), MyFilter()) main;
// Corrected package declaration
ebpfFilter(
    MyParser(),
    MyFilter()
) main;

the error alwayls shows like this, I don't know how to fix the format

$ make -f ../p4c/backends/ebpf/runtime/kernel.mk BPFOBJ=out.o P4FILE=bytecounter.p4
pass verify_cmds: true
pass verify_cmds: true
pass verify_target_bpf: true
p4c-ebpf
Version 1.2.4.14 (SHA: 95e590edc BUILD: RELEASE)
p4c-ebpf -I/home/daqing/p4c/p4c/backends/ebpf/runtime/../p4include --target kernel -o out.c bytecounter.p4 --Werror ;
[--Werror=invalid] error: Invalid key type (MyFilter_byte_counter_key) for table kind BPF_MAP_TYPE_ARRAY, replacing with u32
make: *** [../p4c/backends/ebpf/runtime/kernel.mk:65: out.c] Error 1

How do I find the solution to the problem?


Solution

  • This error is a false error, a false positive: it doesn't mean that there is anything wrong with the P4 code.

    If you look into the .c file generated from the P4 source code, you will find that MyFilter_byte_counter_key is defined as typedef u32 MyFilter_byte_counter_key;. The error claims that MyFilter_byte_counter_key is invalid and the compiler will use u32 instead, while they are actually the same type! This is why I believe this error is a false positive.

    You can mitigate this error by modifying the arguments you use for compiling. The backends/ebpf/runtime/kernel.mk Makefile sets the P4ARGS variable to --Werror by default, which causes p4c-ebpf to treat all warnings as errors. You can override this behavior for example by setting P4ARGS to --Wwarn, resulting in warnings being treated as warnings.

    With the fix mentioned above, the error you are currently getting will become just a warning and your code will compile successfully. You can safely ignore this warning, your code will be fully functional despite it.