Skip to content

Commit 28c42fe

Browse files
committed
Add sample usage for BPF_PROG_TYPE_NETFILTER
Signed-off-by: David Wang <[email protected]>
1 parent bc9df64 commit 28c42fe

File tree

3 files changed

+206
-0
lines changed

3 files changed

+206
-0
lines changed

netfilter-bpf/README.md

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Introduction
2+
3+
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.
4+
5+
* netfilter_ip4_blocklist.c/netfilter_ip4_blocklist.bpf.c
6+
7+
This sample code implements a simple ipv4 blacklist.
8+
The bpf program drops package if destination ip address hits a match in the map of type BPF_MAP_TYPE_LPM_TRIE,
9+
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.
10+
11+
12+
# Build
13+
14+
The sample code use several types newly introduced in kernel, and also use the "vmlinux.h" generated by libbpf.
15+
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
16+
17+
```
18+
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
19+
index 4ccf4236031c..24941d8f1775 100644
20+
--- a/samples/bpf/Makefile
21+
+++ b/samples/bpf/Makefile
22+
@@ -46,6 +46,7 @@ tprogs-y += xdp_fwd
23+
tprogs-y += task_fd_query
24+
tprogs-y += ibumad
25+
tprogs-y += hbm
26+
+tprogs-y += netfilter_ip4_blocklist
27+
28+
# Libbpf dependencies
29+
LIBBPF_SRC = $(TOOLS_PATH)/lib/bpf
30+
@@ -96,6 +97,7 @@ xdp_fwd-objs := xdp_fwd_user.o
31+
task_fd_query-objs := task_fd_query_user.o $(TRACE_HELPERS)
32+
ibumad-objs := ibumad_user.o
33+
hbm-objs := hbm.o $(CGROUP_HELPERS)
34+
+netfilter_ip4_blocklist-objs := netfilter_ip4_blocklist.o
35+
36+
xdp_router_ipv4-objs := xdp_router_ipv4_user.o $(XDP_SAMPLE)
37+
38+
@@ -149,6 +151,7 @@ always-y += task_fd_query_kern.o
39+
always-y += ibumad_kern.o
40+
always-y += hbm_out_kern.o
41+
always-y += hbm_edt_kern.o
42+
+always-y += netfilter_ip4_blocklist.bpf.o
43+
44+
ifeq ($(ARCH), arm)
45+
# Strip all except -D__LINUX_ARM_ARCH__ option needed to handle linux
46+
```
47+
48+
And then run `make` in samples/bpf
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include "vmlinux.h"
4+
#include <bpf/bpf_helpers.h>
5+
6+
7+
#define NF_DROP 0
8+
#define NF_ACCEPT 1
9+
10+
int bpf_dynptr_from_skb(struct sk_buff *skb,
11+
__u64 flags, struct bpf_dynptr *ptr__uninit) __ksym;
12+
void *bpf_dynptr_slice(const struct bpf_dynptr *ptr,
13+
uint32_t offset, void *buffer, uint32_t buffer__sz) __ksym;
14+
15+
16+
struct ipv4_lpm_key {
17+
__u32 prefixlen;
18+
__u32 data;
19+
};
20+
21+
struct {
22+
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
23+
__type(key, struct ipv4_lpm_key);
24+
__type(value, __u32);
25+
__uint(map_flags, BPF_F_NO_PREALLOC);
26+
__uint(max_entries, 200);
27+
} ipv4_lpm_map SEC(".maps");
28+
29+
30+
SEC("netfilter")
31+
int netfilter_ip4block(struct bpf_nf_ctx *ctx)
32+
{
33+
struct sk_buff *skb = ctx->skb;
34+
struct bpf_dynptr ptr;
35+
struct iphdr *p, iph = {};
36+
struct ipv4_lpm_key key;
37+
__u32 *pvalue;
38+
39+
if (skb->len <= 20 || bpf_dynptr_from_skb(skb, 0, &ptr))
40+
return NF_ACCEPT;
41+
p = bpf_dynptr_slice(&ptr, 0, &iph, sizeof(iph));
42+
if (!p)
43+
return NF_ACCEPT;
44+
45+
/* ip4 only */
46+
if (p->version != 4)
47+
return NF_ACCEPT;
48+
49+
/* search p->daddr in trie */
50+
key.prefixlen = 32;
51+
key.data = p->daddr;
52+
pvalue = bpf_map_lookup_elem(&ipv4_lpm_map, &key);
53+
if (pvalue) {
54+
/* cat /sys/kernel/debug/tracing/trace_pipe */
55+
bpf_printk("rule matched with %d...\n", *pvalue);
56+
return NF_DROP;
57+
}
58+
return NF_ACCEPT;
59+
}
60+
61+
char _license[] SEC("license") = "GPL";
62+
+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <stdio.h>
4+
#include <unistd.h>
5+
#include <asm/unistd.h>
6+
#include <bpf/libbpf.h>
7+
#include <bpf/bpf.h>
8+
#include <linux/netfilter.h>
9+
10+
11+
static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size)
12+
{
13+
return syscall(__NR_bpf, cmd, attr, size);
14+
}
15+
struct ipv4_lpm_key {
16+
__u32 prefixlen;
17+
__u32 data;
18+
};
19+
20+
int main(int argc, char **argv)
21+
{
22+
int prog_fd, map_fd;
23+
int err;
24+
struct bpf_object *obj;
25+
struct bpf_program *prog;
26+
union bpf_attr attr = { };
27+
28+
obj = bpf_object__open_file("./netfilter_ip4_blocklist.bpf.o", NULL);
29+
if (libbpf_get_error(obj)) {
30+
printf("fail to open bpf file\n");
31+
return 1;
32+
}
33+
prog = bpf_object__find_program_by_name(obj, "netfilter_ip4block");
34+
if (!prog) {
35+
printf("fail to find bpf program\n");
36+
return 1;
37+
}
38+
bpf_program__set_type(prog, BPF_PROG_TYPE_NETFILTER);
39+
if (bpf_object__load(obj)) {
40+
printf("loading BPF object file failed\n");
41+
return 1;
42+
}
43+
map_fd = bpf_object__find_map_fd_by_name(obj, "ipv4_lpm_map");
44+
if (map_fd < 0) {
45+
printf("Fail to locate trie ipv4_lpm_map\n");
46+
return 1;
47+
}
48+
/* attach to netfilter forward handler */
49+
prog_fd = bpf_program__fd(prog);
50+
attr.link_create.prog_fd = prog_fd;
51+
attr.link_create.attach_type = BPF_NETFILTER;
52+
attr.link_create.netfilter.pf = NFPROTO_IPV4;
53+
attr.link_create.netfilter.hooknum = NF_INET_FORWARD;
54+
attr.link_create.netfilter.priority = -128;
55+
err = sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr));
56+
if (err < 0) {
57+
perror("Fail to link bpf program to netfilter forward hook\n");
58+
return 1;
59+
}
60+
/* attach to netfilter output handler */
61+
attr.link_create.netfilter.hooknum = NF_INET_LOCAL_OUT;
62+
err = sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr));
63+
if (err < 0) {
64+
perror("Fail to link bpf program to netfilter output hook\n");
65+
return 1;
66+
}
67+
printf("bpf program/map loaded....\n");
68+
/* add rules */
69+
{
70+
struct ipv4_lpm_key key;
71+
__u32 value = 0;
72+
__u8 *p = (__u8 *) &key.data;
73+
/* block 192.168.11.107/32 */
74+
key.prefixlen = 27;
75+
/* same as key.data = 0x6B0BA8C0; on a little-endian machine */
76+
p[0] = 192;
77+
p[1] = 168;
78+
p[2] = 11;
79+
p[3] = 107;
80+
bpf_map_update_elem(map_fd, &key, &value, BPF_ANY);
81+
/* block 192.168.11.107/24 */
82+
key.prefixlen = 24;
83+
value++;
84+
bpf_map_update_elem(map_fd, &key, &value, BPF_ANY);
85+
/* block 192.168.11.107/27 */
86+
key.prefixlen = 32;
87+
value++;
88+
bpf_map_update_elem(map_fd, &key, &value, BPF_ANY);
89+
/* remove rule */
90+
/* bpf_map_delete_elem(map_fd, &key); */
91+
printf("rules inserted, ready to work\n");
92+
}
93+
while (1)
94+
sleep(600);
95+
return 0;
96+
}

0 commit comments

Comments
 (0)