I am a complete novice at anything ebpf but trying out some random ideas to get some knowledge.
I wanted to have an eBPF module that could filter some packets based on an allowed list of CIDR. A userspace application should be able to update the allowed list so that filtering can happen without reloading the eBPF probe.
I started with some very simple kernel code:
// IPv4 addr/mask to store in the trie
struct ip4_trie_key {
__u32 prefixlen;
struct in_addr addr;
};
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__uint(max_entries, 128);
__type(key, struct ip4_trie_key);
__type(value, char);
__uint(map_flags, BPF_F_NO_PREALLOC);
} allowlist SEC(".maps");
SEC("socket")
int test_ip_filter(struct __sk_buff *skb)
{
// get header
struct iphdr iph;
if (0 != bpf_skb_load_bytes(skb, 0, &iph, sizeof(iph))) {
return BPF_DROP;
}
// Form the key to lookup in the allowlist
struct ip4_trie_key key = {
.prefixlen = 32,
.addr = iph.saddr
};
if (bpf_map_lookup_elem(&allowlist, &key)) {
return BPF_OK;
}
return BPF_DROP;
I load the module with bpftool prog load bpf_filter.o /sys/fs/bpf/ipfilter
and can see with the same tool it looks ok:
[root@~]$ bpftool -f map show
...
134: socket_filter name test_ip_filter tag ac82ae2a45a2e98d gpl
loaded_at 2022-10-26T16:36:03+0100 uid 0
xlated 472B jited 276B memlock 4096B map_ids 38,40
pinned /sys/fs/bpf/ipfilter
btf_id 191
[root@~]$ bpftool -f map show
...
38: lpm_trie name allowlist flags 0x1
key 8B value 1B max_entries 128 memlock 4096B
btf_id 191
Now in my userspace application I want to connect to the map and update it. I thought I could maybe do something like this:
// note, error checking omitted.
// Get object fd
int obj_fd = bpf_obj_get("/sys/fs/bpf/ipfilter");
// Get the bpf object
struct bpf_object *obj; // <= HOW TO GET THIS
// Get the maps FD (use for updating etc).
int map_fd = bpf_object__find_map_fd_by_name(obj, "allowlist");
// get details about the map (key size etc).
struct bpf_map_info map_info = {};
__u32 info_len = sizeof(map_info);
bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len);
Assuming what I have is correct so far, how do I retrieve bpf_object
struct or am I way off in my undertanding?
Posting an answer myself as I seem to have found a way (although not sure it is the correct thing to do?).
I set the pinning mode of the struct in kernel space to be pinned by name e.g
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__uint(max_entries, 128);
__type(key, struct ip4_trie_key);
__type(value, char);
__uint(map_flags, BPF_F_NO_PREALLOC);
__uint(pinning, LIBBPF_PIN_BY_NAME); // <= THIS LINE FIXED IT
} allowlist SEC(".maps");
This gave the map it's own pinned file in /sys/fs/bpf/allowlist
which I could then just access with bpf_obj_get("/sys/fs/bpf/allowlist")
.