Linux 4.18開始支持bpfilter,用于代替netfilter,其工作原理見下圖:

bpfilter
可以看到bpfilter需要一個UMH(User Module Helper)實現(xiàn)eBPF的規(guī)則轉(zhuǎn)換,這個UMH是需要運行在用戶空間的。在內(nèi)核源碼下的net/bpfilter可以看到以下文件:
.
├── bpfilter_kern.c
├── bpfilter_umh_blob.S
├── Kconfig
├── main.c
├── Makefile
└── msgfmt.h
其中,main.c就是要在用戶空間運行的bpfilter_umh的源代碼,main.c將編譯成net/bpfilter/bpfilter_umh,然后在bpfilter_umh_blob.S里面用incbin將編譯好的bpfilter_umh包進去:
/* net/bpfilter/bpfilter_umh_blob.S */
/* SPDX-License-Identifier: GPL-2.0 */
.section .init.rodata, "a"
.global bpfilter_umh_start
bpfilter_umh_start:
.incbin "net/bpfilter/bpfilter_umh"
.global bpfilter_umh_end
bpfilter_umh_end:
bpfilter在加載的時候?qū)pfilter_umh fork到用戶空間里運行:
/* net/bpfilter/bpfilter_kern.c */
static int __init load_umh(void)
{
int err;
/* fork usermode process */
err = fork_usermode_blob(&bpfilter_umh_start,
&bpfilter_umh_end - &bpfilter_umh_start,
&info);
if (err)
return err;
pr_info("Loaded bpfilter_umh pid %d\n", info.pid);
/* health check that usermode process started correctly */
if (__bpfilter_process_sockopt(NULL, 0, 0, 0, 0) != 0) {
stop_umh();
return -EFAULT;
}
if (IS_ENABLED(CONFIG_INET))
bpfilter_process_sockopt = &__bpfilter_process_sockopt;
return 0;
}
# net/bpfilter/Kconfig
menuconfig BPFILTER
bool "BPF based packet filtering framework (BPFILTER)"
depends on NET && BPF && INET
help
This builds experimental bpfilter framework that is aiming to
provide netfilter compatible functionality via BPF
if BPFILTER
config BPFILTER_UMH
tristate "bpfilter kernel module with user mode helper"
depends on $(success,$(srctree)/scripts/cc-can-link.sh $(CC))
default m
help
This builds bpfilter kernel module with embedded user mode helper
endif
要特別注意的是,在Kconfig中,如果CONFIG_BPFILTER_UMH為m,那么bpfilter_umh將不會使用靜態(tài)鏈接的方式編譯,這樣一來,如果目標系統(tǒng)使用的libc與編譯內(nèi)核的工具鏈使用的libc差距過大的話,會導致bpfilter_umh無法工作,也就意味著bpfilter模塊無法裝載。
例如,使用glibc的工具鏈編譯的啟用bpfilter支持的內(nèi)核,放在musl環(huán)境的OpenWrt中,由于C庫不同致使bpfilter_umh無法運行,bpfilter模塊也就不能加載,最終導致iptables報錯:
root@OpenWrt:~# iptables -L
iptables v1.6.2: can't initialize iptables table `filter': No child process
為了解決這個問題,需要將CONFIG_BPFILTER_UMH設定為y,這樣會給bpfilter_umh添加-static的鏈接參數(shù)(靜態(tài)鏈接),就不會產(chǎn)生libc的依賴問題了。