-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add sample usage for BPF_PROG_TYPE_NETFILTER
Signed-off-by: David Wang <[email protected]>
- Loading branch information
1 parent
bc9df64
commit 28c42fe
Showing
3 changed files
with
206 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Introduction | ||
|
||
BPF_PROG_TYPE_NETFILTER was introduced in 6.4, now with a new kernel, a bpf program could attach to netfilter hooks and handles package in a similiar way as iptables/nftables. By now, 6.5.0, there is no bpf kfunc implemented yet for DNAT/SNAT, and the only thing a bpf program can do is to decide whether to DROP the package or not. | ||
|
||
* netfilter_ip4_blocklist.c/netfilter_ip4_blocklist.bpf.c | ||
|
||
This sample code implements a simple ipv4 blacklist. | ||
The bpf program drops package if destination ip address hits a match in the map of type BPF_MAP_TYPE_LPM_TRIE, | ||
The userspace code would load the bpf program, attach it to netfilter's FORWARD/OUTPUT hook, and then write ip patterns into the bpf map. | ||
|
||
|
||
# Build | ||
|
||
The sample code use several types newly introduced in kernel, and also use the "vmlinux.h" generated by libbpf. | ||
The easiest way to compile is to take advantage of the structure in samples/bpf from kernel tree: just copy *.c files to samples/bpf, and make following changes to the Makefile | ||
|
||
``` | ||
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile | ||
index 4ccf4236031c..24941d8f1775 100644 | ||
--- a/samples/bpf/Makefile | ||
+++ b/samples/bpf/Makefile | ||
@@ -46,6 +46,7 @@ tprogs-y += xdp_fwd | ||
tprogs-y += task_fd_query | ||
tprogs-y += ibumad | ||
tprogs-y += hbm | ||
+tprogs-y += netfilter_ip4_blocklist | ||
# Libbpf dependencies | ||
LIBBPF_SRC = $(TOOLS_PATH)/lib/bpf | ||
@@ -96,6 +97,7 @@ xdp_fwd-objs := xdp_fwd_user.o | ||
task_fd_query-objs := task_fd_query_user.o $(TRACE_HELPERS) | ||
ibumad-objs := ibumad_user.o | ||
hbm-objs := hbm.o $(CGROUP_HELPERS) | ||
+netfilter_ip4_blocklist-objs := netfilter_ip4_blocklist.o | ||
xdp_router_ipv4-objs := xdp_router_ipv4_user.o $(XDP_SAMPLE) | ||
@@ -149,6 +151,7 @@ always-y += task_fd_query_kern.o | ||
always-y += ibumad_kern.o | ||
always-y += hbm_out_kern.o | ||
always-y += hbm_edt_kern.o | ||
+always-y += netfilter_ip4_blocklist.bpf.o | ||
ifeq ($(ARCH), arm) | ||
# Strip all except -D__LINUX_ARM_ARCH__ option needed to handle linux | ||
``` | ||
|
||
And then run `make` in samples/bpf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
#include "vmlinux.h" | ||
#include <bpf/bpf_helpers.h> | ||
|
||
|
||
#define NF_DROP 0 | ||
#define NF_ACCEPT 1 | ||
|
||
int bpf_dynptr_from_skb(struct sk_buff *skb, | ||
__u64 flags, struct bpf_dynptr *ptr__uninit) __ksym; | ||
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"; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <asm/unistd.h> | ||
#include <bpf/libbpf.h> | ||
#include <bpf/bpf.h> | ||
#include <linux/netfilter.h> | ||
|
||
|
||
static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size) | ||
{ | ||
return syscall(__NR_bpf, cmd, attr, size); | ||
} | ||
struct ipv4_lpm_key { | ||
__u32 prefixlen; | ||
__u32 data; | ||
}; | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
int prog_fd, map_fd; | ||
int err; | ||
struct bpf_object *obj; | ||
struct bpf_program *prog; | ||
union bpf_attr attr = { }; | ||
|
||
obj = bpf_object__open_file("./netfilter_ip4_blocklist.bpf.o", NULL); | ||
if (libbpf_get_error(obj)) { | ||
printf("fail to open bpf file\n"); | ||
return 1; | ||
} | ||
prog = bpf_object__find_program_by_name(obj, "netfilter_ip4block"); | ||
if (!prog) { | ||
printf("fail to find bpf program\n"); | ||
return 1; | ||
} | ||
bpf_program__set_type(prog, BPF_PROG_TYPE_NETFILTER); | ||
if (bpf_object__load(obj)) { | ||
printf("loading BPF object file failed\n"); | ||
return 1; | ||
} | ||
map_fd = bpf_object__find_map_fd_by_name(obj, "ipv4_lpm_map"); | ||
if (map_fd < 0) { | ||
printf("Fail to locate trie ipv4_lpm_map\n"); | ||
return 1; | ||
} | ||
/* attach to netfilter forward handler */ | ||
prog_fd = bpf_program__fd(prog); | ||
attr.link_create.prog_fd = prog_fd; | ||
attr.link_create.attach_type = BPF_NETFILTER; | ||
attr.link_create.netfilter.pf = NFPROTO_IPV4; | ||
attr.link_create.netfilter.hooknum = NF_INET_FORWARD; | ||
attr.link_create.netfilter.priority = -128; | ||
err = sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr)); | ||
if (err < 0) { | ||
perror("Fail to link bpf program to netfilter forward hook\n"); | ||
return 1; | ||
} | ||
/* attach to netfilter output handler */ | ||
attr.link_create.netfilter.hooknum = NF_INET_LOCAL_OUT; | ||
err = sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr)); | ||
if (err < 0) { | ||
perror("Fail to link bpf program to netfilter output hook\n"); | ||
return 1; | ||
} | ||
printf("bpf program/map loaded....\n"); | ||
/* add rules */ | ||
{ | ||
struct ipv4_lpm_key key; | ||
__u32 value = 0; | ||
__u8 *p = (__u8 *) &key.data; | ||
/* block 192.168.11.107/32 */ | ||
key.prefixlen = 27; | ||
/* same as key.data = 0x6B0BA8C0; on a little-endian machine */ | ||
p[0] = 192; | ||
p[1] = 168; | ||
p[2] = 11; | ||
p[3] = 107; | ||
bpf_map_update_elem(map_fd, &key, &value, BPF_ANY); | ||
/* block 192.168.11.107/24 */ | ||
key.prefixlen = 24; | ||
value++; | ||
bpf_map_update_elem(map_fd, &key, &value, BPF_ANY); | ||
/* block 192.168.11.107/27 */ | ||
key.prefixlen = 32; | ||
value++; | ||
bpf_map_update_elem(map_fd, &key, &value, BPF_ANY); | ||
/* remove rule */ | ||
/* bpf_map_delete_elem(map_fd, &key); */ | ||
printf("rules inserted, ready to work\n"); | ||
} | ||
while (1) | ||
sleep(600); | ||
return 0; | ||
} |