This is a super lightweight eBPF loader that separates filter-writing and filter-using. It uses neither libbpf nor bcc, thus using no heavy object files.
The main feature of this loader is that it treats writing filters and inserting filters as independent processes, allowing them to be completed on different machines (e.g. local and server), which is not supported by libbpf or bcc.
This loader extracts bytecode instruction streams from eBPF filters written in C that can be directly inserted into the kernel using the bpf
syscall.
The current example is an ICMP filter, logging information of ICMP packets to trace pipe. Use sudo cat /sys/kernel/debug/tracing/trace_pipe
to see printk
logging.
- Linux Kernel Headers with BPF support
- libelf
sh build.sh <ebpf source code path> <ebpf main section name>
Example Output:
sh build.sh example_filters/ebpf_filter.c section_name
object file name: example_filters/ebpf_filter
section name: section_name
instruction stream:
{
{0xb7, 0x0, 0x0, 0x2},
{0x1261, 0x50, 0x0, 0x0},
{0x1161, 0x4c, 0x0, 0x0},
{0x107, 0x0, 0x0, 0xe},
{0x212d, 0xe, 0x0, 0x0},
{0x1b7, 0x0, 0x0, 0xa},
{0x1a6b, 0xf0, 0xff, 0x0},
{0x118, 0x0, 0x0, 0x75206e61},
{0x0, 0x0, 0x0, 0x75253a70},
{0x1a7b, 0xe8, 0xff, 0x0},
{0x118, 0x0, 0x0, 0x74736554},
{0x0, 0x0, 0x0, 0x656c6320},
{0x1a7b, 0xe0, 0xff, 0x0},
{0xa1bf, 0x0, 0x0, 0x0},
{0x107, 0x0, 0x0, 0xffffffe0},
{0x2b7, 0x0, 0x0, 0x12},
{0x3b7, 0x0, 0x0, 0x8},
{0x85, 0x0, 0x0, 0x6},
{0xb7, 0x0, 0x0, 0x0},
{0x95, 0x0, 0x0, 0x0},
};
number of instructions: 20
Then use Syscall bpf to load output bytecode filter to kernel, copy the output instruction stream and filter length to struct bpfinstr filter[]
.
struct bpfinstr
{
uint16_t code;
uint8_t jt;
uint8_t jf;
uint32_t k;
};
int main()
{
char license[ELF_MAX_LICENSE_LEN] = "GPL";
int filter_len = 20;
struct bpfinstr filter[] = {
{0xb7, 0x0, 0x0, 0x2},
{0x1261, 0x50, 0x0, 0x0},
{0x1161, 0x4c, 0x0, 0x0},
{0x107, 0x0, 0x0, 0xe},
{0x212d, 0xe, 0x0, 0x0},
{0x1b7, 0x0, 0x0, 0xa},
{0x1a6b, 0xf0, 0xff, 0x0},
{0x118, 0x0, 0x0, 0x75206e61},
{0x0, 0x0, 0x0, 0x75253a70},
{0x1a7b, 0xe8, 0xff, 0x0},
{0x118, 0x0, 0x0, 0x74736554},
{0x0, 0x0, 0x0, 0x656c6320},
{0x1a7b, 0xe0, 0xff, 0x0},
{0xa1bf, 0x0, 0x0, 0x0},
{0x107, 0x0, 0x0, 0xffffffe0},
{0x2b7, 0x0, 0x0, 0x12},
{0x3b7, 0x0, 0x0, 0x8},
{0x85, 0x0, 0x0, 0x6},
{0xb7, 0x0, 0x0, 0x0},
{0x95, 0x0, 0x0, 0x0},
};
union bpf_attr attr = {
.prog_type = 3,
.insns = (uintptr_t)filter,
.insn_cnt = filter_len,
.license = (uintptr_t)license
};
int fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
if (fd > 0) {
printf("eBPF filter loaded, fd=%d", %d);
return 0;
}
return fd;
}
No BPF map support!