You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

P4转eBPF时BPF_MAP_TYPE_ARRAY密钥类型无效问题求助

问题:P4-eBPF编译计数器数组时的BPF_MAP_TYPE_ARRAY键类型错误

背景

  • 基于p4c的eBPF后端开发P4程序,目标是统计进入主机的IPv4数据包总字节数,最终将程序加载到Cilium相关TC链中
  • 开发流程:
    1. 编写自定义P4代码,通过p4c-ebpf转换为eBPF C文件
    2. 使用clang编译生成可内核加载的.o文件
    3. 通过tc或bpftool加载到Cilium对应的TC目录

现有P4代码

#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
ebpfFilter(
    MyParser(),
    MyFilter()
) main;

编译错误信息

$ 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

问题原因

eBPF的BPF_MAP_TYPE_ARRAY类型要求键必须是u32(32位无符号整数),但当前代码中CounterArray(32w1, false)的定义方式,让p4c-ebpf生成了自定义的键类型MyFilter_byte_counter_key,违反了该约束。加上编译时启用了--Werror,将警告升级为错误,导致编译失败。

解决方案

修改CounterArray的定义,明确指定键类型为bit<32>(对应eBPF的u32),值类型使用适合统计字节数的bit<64>(避免溢出)。具体修改如下:

修改后的Control块代码

// Define the filter control block
control MyFilter(inout headers hdr, out bool accept) {
    // 明确指定键类型为bit<32>,值类型为bit<64>的计数器数组
    CounterArray(bit<32>, bit<64>) byte_counter;

    apply {
        if (hdr.ipv4.isValid()) {
            // 将totalLen转为bit<64>后累加,避免统计溢出
            byte_counter.add(32w0, (bit<64>)hdr.ipv4.totalLen);
        }
        accept = true;
    }
}

验证编译

修改完成后重新执行make命令:

make -f ../p4c/backends/ebpf/runtime/kernel.mk BPFOBJ=out.o P4FILE=bytecounter.p4

此时p4c-ebpf会生成符合BPF_MAP_TYPE_ARRAY要求的键类型,编译可正常通过。

内容的提问来源于stack exchange,提问作者Xuan Tuoba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 00:27:05