P4转eBPF时BPF_MAP_TYPE_ARRAY密钥类型无效问题求助
问题:P4-eBPF编译计数器数组时的BPF_MAP_TYPE_ARRAY键类型错误
背景
- 基于p4c的eBPF后端开发P4程序,目标是统计进入主机的IPv4数据包总字节数,最终将程序加载到Cilium相关TC链中
- 开发流程:
- 编写自定义P4代码,通过
p4c-ebpf转换为eBPF C文件 - 使用clang编译生成可内核加载的.o文件
- 通过tc或bpftool加载到Cilium对应的TC目录
- 编写自定义P4代码,通过
现有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
相关产品推荐
相关产品推荐

