Reputation: 65
I have an implementation in BPF for XDP, wherein I specify five maps to be created as follows:
struct bpf_map_def SEC("maps") servers = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(struct ip_key),
.value_size = sizeof(struct dest_info),
.max_entries = MAX_SERVERS,
};
struct bpf_map_def SEC("maps") server_ips = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(struct ip_key),
.value_size = sizeof(struct server_ip_key),
.max_entries = MAX_SERVERS,
};
struct bpf_map_def SEC("maps") client_addrs = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(struct port_key),
.value_size = sizeof(struct client_port_addr),
.max_entries = MAX_CLIENTS,
};
struct bpf_map_def SEC("maps") stoc_port_maps = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(struct port_key),
.value_size = sizeof(struct port_map),
.max_entries = MAX_FLOWS,
};
struct bpf_map_def SEC("maps") ctos_port_maps = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(struct port_key),
.value_size = sizeof(struct port_map),
.max_entries = MAX_FLOWS,
};
However, no matter what I do, the servers
map is not getting created. When I run bpftool map show
, I only get such output as the following:
root@balancer:/xdp# bpftool map list
68: hash name client_addrs flags 0x0
key 8B value 16B max_entries 4096 memlock 98304B
69: hash name ctos_port_maps flags 0x0
key 8B value 20B max_entries 4096 memlock 131072B
70: hash name server_ips flags 0x0
key 8B value 8B max_entries 512 memlock 8192B
73: hash name stoc_port_maps flags 0x0
key 8B value 20B max_entries 4096 memlock 131072B
74: array name xdp_lb_k.rodata flags 0x480
key 4B value 50B max_entries 1 memlock 4096B
frozen
root@balancer:/xdp#
It is notable that each of the key or value structs have been padded to the closest multiple of eight bytes, and there are no compile or verifier errors. I am also running the program on docker containers. So far, I have tried moving the servers
map definition around in my code, commenting out the other map definitions leaving only the servers
definition active, changing the name to other combinations, and a few other minor changes but nothing has worked so far.
Please let me know if you would need any other portion of my code or information for a better analysis of the situation.
Appendix 1: I am compiling the object file using this Makefile rule:
xdp_lb_kern.o: xdp_lb_kern.c
clang -S \
-target bpf \
-D __BPF_TRACING__ \
-I../../libbpf/src \
-I../../custom-headers \
-Wall \
-Wno-unused-value \
-Wno-pointer-sign \
-Wno-compare-distinct-pointer-types \
-O2 -emit-llvm -c -o ${@:.o=.ll} $<
llc -march=bpf -filetype=obj -o $@ ${@:.o=.ll}
Then, in the container's environment, I load the program using this rule:
load_balancer:
bpftool net detach xdpgeneric dev eth0
rm -f /sys/fs/bpf/xdp_lb
bpftool prog load xdp_lb_kern.o /sys/fs/bpf/xdp_lb
bpftool net attach xdpgeneric pinned /sys/fs/bpf/xdp_lb dev eth0
The compilation process generates a .o
and a .ll
output file. The beginning lines of the .ll
output file, where the map definitions are visible, are shown below:
; ModuleID = 'xdp_lb_kern.c'
source_filename = "xdp_lb_kern.c"
target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
target triple = "bpf"
%struct.bpf_map_def = type { i32, i32, i32, i32, i32 }
%struct.xdp_md = type { i32, i32, i32, i32, i32 }
%struct.ip_key = type { i32, i32 }
%struct.port_key = type { i16, [3 x i16] }
%struct.ethhdr = type { [6 x i8], [6 x i8], i16 }
%struct.iphdr = type { i8, i8, i16, i16, i16, i8, i8, i16, i32, i32 }
@servers = dso_local global %struct.bpf_map_def { i32 1, i32 8, i32 32, i32 512, i32 0 }, section "maps", align 4
@server_ips = dso_local global %struct.bpf_map_def { i32 1, i32 8, i32 8, i32 512, i32 0 }, section "maps", align 4
@client_addrs = dso_local global %struct.bpf_map_def { i32 1, i32 8, i32 16, i32 4096, i32 0 }, section "maps", align 4
@stoc_port_maps = dso_local global %struct.bpf_map_def { i32 1, i32 8, i32 20, i32 4096, i32 0 }, section "maps", align 4
@ctos_port_maps = dso_local global %struct.bpf_map_def { i32 1, i32 8, i32 20, i32 4096, i32 0 }, section "maps", align 4
@loadbal.____fmt = internal constant [24 x i8] c"balancer got something!\00", align 1
@_license = dso_local global [4 x i8] c"GPL\00", section "license", align 1
@process_packet.____fmt = internal constant [26 x i8] c"it's an ip packet from %x\00", align 1
@llvm.used = appending global [7 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @_license, i32 0, i32 0), i8* bitcast (%struct.bpf_map_def* @client_addrs to i8*), i8* bitcast (%struct.bpf_map_def* @ctos_port_maps to i8*), i8* bitcast (i32 (%struct.xdp_md*)* @loadbal to i8*), i8* bitcast (%struct.bpf_map_def* @server_ips to i8*), i8* bitcast (%struct.bpf_map_def* @servers to i8*), i8* bitcast (%struct.bpf_map_def* @stoc_port_maps to i8*)], section "llvm.metadata"
; Function Attrs: nounwind
define dso_local i32 @loadbal(%struct.xdp_md* nocapture readonly %0) #0 section "xdp" {
%2 = alloca %struct.ip_key, align 4
%3 = alloca %struct.port_key, align 2
%4 = alloca %struct.port_key, align 2
%5 = getelementptr inbounds %struct.xdp_md, %struct.xdp_md* %0, i64 0, i32 1
%6 = load i32, i32* %5, align 4, !tbaa !2
%7 = zext i32 %6 to i64
%8 = inttoptr i64 %7 to i8*
%9 = getelementptr inbounds %struct.xdp_md, %struct.xdp_md* %0, i64 0, i32 0
%10 = load i32, i32* %9, align 4, !tbaa !7
Upvotes: 0
Views: 1004
Reputation: 9114
As per the discussion in the comments, the map is not created because it is not actually used in your eBPF code (not provided in the question).
As you realised yourself, the branch in your code that was calling the map was in fact unreachable. Based on that, it's likely that clang compiled out this portion of code, and that the map is not used in the resulting eBPF bytecode. When preparing to load your program, bpftool (libbpf) looks at what maps are necessary, and only creates the ones that are needed for your program. It may skip maps that are defined in the ELF file if no program uses them.
One hint here is that, if the program was effectively using the map, it couldn't load successfully if the map was missing: given that your program loads, the map would necessarily be present if it was needed. Note that bpftool prog show
will show you the ids of the maps used by a program.
Upvotes: 2