Reputation: 23
I compiled the bpf code below(netfilter_ip4_blacklist.bpf.c) successfully, but when i load the netfilter_ip4_blacklist.bpf.o with bpftool prog load netfilter_ip4_blacklist.bpf.o /sys/fs/bpf/netfilter_ip4_blacklist
, it throws libbpf: failed to find BTF for extern 'bpf_dynptr_from_skb': -2
// SPDX-License-Identifier: GPL-2.0
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#define NF_DROP 0
#define NF_ACCEPT 1
extern int bpf_dynptr_from_skb(struct sk_buff *skb,
__u64 flags, struct bpf_dynptr *ptr__uninit) __ksym;
extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr,
uint32_t offset, void *buffer, uint32_t buffer__sz) __ksym;
struct ipv4_lpm_key {
__u32 prefixlen;
__u32 data;
};
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__type(key, struct ipv4_lpm_key);
__type(value, __u32);
__uint(map_flags, BPF_F_NO_PREALLOC);
__uint(max_entries, 200);
} ipv4_lpm_map SEC(".maps");
SEC("netfilter")
int netfilter_ip4block(struct bpf_nf_ctx *ctx)
{
struct sk_buff *skb = ctx->skb;
struct bpf_dynptr ptr;
struct iphdr *p, iph = {};
struct ipv4_lpm_key key;
__u32 *pvalue;
if (skb->len <= 20 || bpf_dynptr_from_skb(skb, 0, &ptr))
return NF_ACCEPT;
p = bpf_dynptr_slice(&ptr, 0, &iph, sizeof(iph));
if (!p)
return NF_ACCEPT;
/* ip4 only */
if (p->version != 4)
return NF_ACCEPT;
/* search p->daddr in trie */
key.prefixlen = 32;
key.data = p->daddr;
pvalue = bpf_map_lookup_elem(&ipv4_lpm_map, &key);
if (pvalue) {
/* cat /sys/kernel/debug/tracing/trace_pipe */
bpf_printk("rule matched with %d...\n", *pvalue);
return NF_DROP;
}
return NF_ACCEPT;
}
char _license[] SEC("license") = "GPL";
Actually this bpf code comes from a patch from linux up stream, here is the link: samples-bpf-Add-sample-usage-for-BPF_PROG_TYPE_NETFILTER.patch
Here are the informations of the tool chain and kernel:
all above compiled and installed from source, here are the compiling options:
# for clang/llvm
cmake -S llvm -B build -G 'Unix Makefiles' -DLLVM_ENABLE_PROJECTS="clang;lld;lldb" -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DLLVM_USE_LINKER=lld -DLLVM_BINUTILS_INCDIR=/usr/include -DLLVM_BUILD_LLVM_DYLIB=true -DLLVM_LINK_LLVM_DYLIB=true -DCLANG_LINK_CLANG_DYLIB=true -DLLVM_PARALLEL_LINK_JOBS=8 -DLLVM_TARGETS_TO_BUILD="X86;BPF"
# for kernel
CONFIG_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
CONFIG_BPF_LSM=y
CONFIG_NETFILTER_BPF_LINK=y
CONFIG_BPFILTER=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_BPF_EVENTS=y
# some else not concerning
# for libbpf
nothing
# for bpftool
nothing
what i did:
clang -target bpf -g -c nf-monitor.bpf.c -o netfilter_ip4_blacklist.bpf.o
bpftool prog load netfilter_ip4_blacklist.bpf.o /sys/fs/bpf/netfilter_ip4_blacklist
what i tried:
bpf_dynptr_from_skb
should be in the .BTF section of .o but actually not, may it be something wrong with clang/llvm while linking?(i don't think so)So can anyone tell me where the problem is?Thanks a log!
Upvotes: 1
Views: 232
Reputation: 7978
You are right in all of your observations, the BTF info for the kfuncs doesn't make it into the .BTF
section. This is because you are calling clang without optimizations -O2
.
Changing the clang invocation to: clang -target bpf -g -O2 -c nf-monitor.bpf.c -o netfilter_ip4_blacklist.bpf.o
resolves the issue.
The unfortunate reason for this is the way eBPF is integrated into clang. Simply put a number of critical features are implemented in optimization passes only enabled in -O2
mode. So specifying it is required to get load-able eBPF object files.
Upvotes: 2