Skip to content

Commit 40bbc1d

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

File tree

6 files changed

+369
-62
lines changed

6 files changed

+369
-62
lines changed

headers/vmlinux/vmlinux_net.h

Lines changed: 176 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ typedef unsigned int sk_buff_data_t;
1616
typedef unsigned char *sk_buff_data_t;
1717
#endif
1818
*/
19+
struct llist_node {
20+
struct llist_node *next;
21+
};
1922

2023
struct sk_buff {
2124
union {
@@ -29,6 +32,7 @@ struct sk_buff {
2932
};
3033
struct rb_node rbnode;
3134
struct list_head list;
35+
struct llist_node ll_node;
3236
};
3337
union {
3438
struct sock *sk;
@@ -45,6 +49,7 @@ struct sk_buff {
4549
void (*destructor)(struct sk_buff *);
4650
};
4751
struct list_head tcp_tsorted_anchor;
52+
long unsigned int _sk_redir;
4853
};
4954
long unsigned int _nfct;
5055
unsigned int len;
@@ -59,73 +64,152 @@ struct sk_buff {
5964
__u8 peeked: 1;
6065
__u8 head_frag: 1;
6166
__u8 pfmemalloc: 1;
67+
__u8 pp_recycle: 1;
6268
__u8 active_extensions;
63-
__u32 headers_start[0];
64-
__u8 __pkt_type_offset[0];
65-
__u8 pkt_type: 3;
66-
__u8 ignore_df: 1;
67-
__u8 nf_trace: 1;
68-
__u8 ip_summed: 2;
69-
__u8 ooo_okay: 1;
70-
__u8 l4_hash: 1;
71-
__u8 sw_hash: 1;
72-
__u8 wifi_acked_valid: 1;
73-
__u8 wifi_acked: 1;
74-
__u8 no_fcs: 1;
75-
__u8 encapsulation: 1;
76-
__u8 encap_hdr_csum: 1;
77-
__u8 csum_valid: 1;
78-
__u8 __pkt_vlan_present_offset[0];
79-
__u8 vlan_present: 1;
80-
__u8 csum_complete_sw: 1;
81-
__u8 csum_level: 2;
82-
__u8 csum_not_inet: 1;
83-
__u8 dst_pending_confirm: 1;
84-
__u8 ndisc_nodetype: 2;
85-
__u8 ipvs_property: 1;
86-
__u8 inner_protocol_type: 1;
87-
__u8 remcsum_offload: 1;
88-
__u8 offload_fwd_mark: 1;
89-
__u8 offload_l3_fwd_mark: 1;
90-
__u8 tc_skip_classify: 1;
91-
__u8 tc_at_ingress: 1;
92-
__u8 redirected: 1;
93-
__u8 from_ingress: 1;
94-
__u8 decrypted: 1;
95-
__u16 tc_index;
9669
union {
97-
__wsum csum;
9870
struct {
99-
__u16 csum_start;
100-
__u16 csum_offset;
71+
__u8 __pkt_type_offset[0];
72+
__u8 pkt_type: 3;
73+
__u8 ignore_df: 1;
74+
__u8 dst_pending_confirm: 1;
75+
__u8 ip_summed: 2;
76+
__u8 ooo_okay: 1;
77+
__u8 __mono_tc_offset[0];
78+
__u8 mono_delivery_time: 1;
79+
__u8 tc_at_ingress: 1;
80+
__u8 tc_skip_classify: 1;
81+
__u8 remcsum_offload: 1;
82+
__u8 csum_complete_sw: 1;
83+
__u8 csum_level: 2;
84+
__u8 inner_protocol_type: 1;
85+
__u8 l4_hash: 1;
86+
__u8 sw_hash: 1;
87+
__u8 wifi_acked_valid: 1;
88+
__u8 wifi_acked: 1;
89+
__u8 no_fcs: 1;
90+
__u8 encapsulation: 1;
91+
__u8 encap_hdr_csum: 1;
92+
__u8 csum_valid: 1;
93+
__u8 ndisc_nodetype: 2;
94+
__u8 ipvs_property: 1;
95+
__u8 nf_trace: 1;
96+
__u8 redirected: 1;
97+
__u8 from_ingress: 1;
98+
__u8 nf_skip_egress: 1;
99+
__u8 slow_gro: 1;
100+
__u8 csum_not_inet: 1;
101+
__u16 tc_index;
102+
u16 alloc_cpu;
103+
union {
104+
__wsum csum;
105+
struct {
106+
__u16 csum_start;
107+
__u16 csum_offset;
108+
};
109+
};
110+
__u32 priority;
111+
int skb_iif;
112+
__u32 hash;
113+
union {
114+
u32 vlan_all;
115+
struct {
116+
__be16 vlan_proto;
117+
__u16 vlan_tci;
118+
};
119+
};
120+
union {
121+
unsigned int napi_id;
122+
unsigned int sender_cpu;
123+
};
124+
__u32 secmark;
125+
union {
126+
__u32 mark;
127+
__u32 reserved_tailroom;
128+
};
129+
union {
130+
__be16 inner_protocol;
131+
__u8 inner_ipproto;
132+
};
133+
__u16 inner_transport_header;
134+
__u16 inner_network_header;
135+
__u16 inner_mac_header;
136+
__be16 protocol;
137+
__u16 transport_header;
138+
__u16 network_header;
139+
__u16 mac_header;
101140
};
141+
struct {
142+
__u8 __pkt_type_offset[0];
143+
__u8 pkt_type: 3;
144+
__u8 ignore_df: 1;
145+
__u8 dst_pending_confirm: 1;
146+
__u8 ip_summed: 2;
147+
__u8 ooo_okay: 1;
148+
__u8 __mono_tc_offset[0];
149+
__u8 mono_delivery_time: 1;
150+
__u8 tc_at_ingress: 1;
151+
__u8 tc_skip_classify: 1;
152+
__u8 remcsum_offload: 1;
153+
__u8 csum_complete_sw: 1;
154+
__u8 csum_level: 2;
155+
__u8 inner_protocol_type: 1;
156+
__u8 l4_hash: 1;
157+
__u8 sw_hash: 1;
158+
__u8 wifi_acked_valid: 1;
159+
__u8 wifi_acked: 1;
160+
__u8 no_fcs: 1;
161+
__u8 encapsulation: 1;
162+
__u8 encap_hdr_csum: 1;
163+
__u8 csum_valid: 1;
164+
__u8 ndisc_nodetype: 2;
165+
__u8 ipvs_property: 1;
166+
__u8 nf_trace: 1;
167+
__u8 redirected: 1;
168+
__u8 from_ingress: 1;
169+
__u8 nf_skip_egress: 1;
170+
__u8 slow_gro: 1;
171+
__u8 csum_not_inet: 1;
172+
__u16 tc_index;
173+
u16 alloc_cpu;
174+
union {
175+
__wsum csum;
176+
struct {
177+
__u16 csum_start;
178+
__u16 csum_offset;
179+
};
180+
};
181+
__u32 priority;
182+
int skb_iif;
183+
__u32 hash;
184+
union {
185+
u32 vlan_all;
186+
struct {
187+
__be16 vlan_proto;
188+
__u16 vlan_tci;
189+
};
190+
};
191+
union {
192+
unsigned int napi_id;
193+
unsigned int sender_cpu;
194+
};
195+
__u32 secmark;
196+
union {
197+
__u32 mark;
198+
__u32 reserved_tailroom;
199+
};
200+
union {
201+
__be16 inner_protocol;
202+
__u8 inner_ipproto;
203+
};
204+
__u16 inner_transport_header;
205+
__u16 inner_network_header;
206+
__u16 inner_mac_header;
207+
__be16 protocol;
208+
__u16 transport_header;
209+
__u16 network_header;
210+
__u16 mac_header;
211+
} headers;
102212
};
103-
__u32 priority;
104-
int skb_iif;
105-
__u32 hash;
106-
__be16 vlan_proto;
107-
__u16 vlan_tci;
108-
union {
109-
unsigned int napi_id;
110-
unsigned int sender_cpu;
111-
};
112-
__u32 secmark;
113-
union {
114-
__u32 mark;
115-
__u32 reserved_tailroom;
116-
};
117-
union {
118-
__be16 inner_protocol;
119-
__u8 inner_ipproto;
120-
};
121-
__u16 inner_transport_header;
122-
__u16 inner_network_header;
123-
__u16 inner_mac_header;
124-
__be16 protocol;
125-
__u16 transport_header;
126-
__u16 network_header;
127-
__u16 mac_header;
128-
__u32 headers_end[0];
129213
sk_buff_data_t tail;
130214
sk_buff_data_t end;
131215
unsigned char *head;
@@ -135,4 +219,34 @@ struct sk_buff {
135219
struct skb_ext *extensions;
136220
};
137221

222+
223+
224+
struct iphdr {
225+
__u8 ihl: 4;
226+
__u8 version: 4;
227+
__u8 tos;
228+
__be16 tot_len;
229+
__be16 id;
230+
__be16 frag_off;
231+
__u8 ttl;
232+
__u8 protocol;
233+
__sum16 check;
234+
union {
235+
struct {
236+
__be32 saddr;
237+
__be32 daddr;
238+
};
239+
struct {
240+
__be32 saddr;
241+
__be32 daddr;
242+
} addrs;
243+
};
244+
};
245+
246+
struct bpf_nf_ctx {
247+
const struct nf_hook_state *state;
248+
struct sk_buff *skb;
249+
};
250+
251+
138252
#endif /* __VMLINUX_NET_H__ */

headers/vmlinux/vmlinux_types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ typedef __u64 u64;
1111

1212
typedef s64 ktime_t;
1313

14+
typedef u32 uint32_t;
15+
16+
1417
#endif /* __VMLINUX_TYPES_H__ */

netfilter-bpf/Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
2+
3+
USER_TARGETS := netfilter_ip4_blocklist
4+
BPF_TARGETS := netfilter_ip4_blocklist.bpf
5+
6+
7+
LIB_DIR = ../lib
8+
9+
include $(LIB_DIR)/common.mk

netfilter-bpf/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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 blocklist.
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+
# TODO
13+
14+
This sample hard-codes ip address to be blocked, just for demonstration.
15+
It would be better to break the userspace program into two parts:
16+
* init program
17+
Loads bpf program and pin bpf program and map into somewhere under /sys/fs/bpf
18+
* interactive program
19+
add/delete/query ip blocklist via bpf map under /sys/fs/bpf
20+
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include "vmlinux_local.h"
4+
#include "linux/bpf.h"
5+
#include <bpf/bpf_helpers.h>
6+
7+
8+
#define NF_DROP 0
9+
#define NF_ACCEPT 1
10+
11+
int bpf_dynptr_from_skb(struct sk_buff *skb,
12+
__u64 flags, struct bpf_dynptr *ptr__uninit) __ksym;
13+
void *bpf_dynptr_slice(const struct bpf_dynptr *ptr,
14+
uint32_t offset, void *buffer, uint32_t buffer__sz) __ksym;
15+
16+
17+
struct ipv4_lpm_key {
18+
__u32 prefixlen;
19+
__u32 data;
20+
};
21+
22+
struct {
23+
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
24+
__type(key, struct ipv4_lpm_key);
25+
__type(value, __u32);
26+
__uint(map_flags, BPF_F_NO_PREALLOC);
27+
__uint(max_entries, 200);
28+
} ipv4_lpm_map SEC(".maps");
29+
30+
31+
SEC("netfilter")
32+
int netfilter_ip4block(struct bpf_nf_ctx *ctx)
33+
{
34+
struct sk_buff *skb = ctx->skb;
35+
struct bpf_dynptr ptr;
36+
struct iphdr *p, iph = {};
37+
struct ipv4_lpm_key key;
38+
__u32 *pvalue;
39+
40+
if (skb->len <= 20 || bpf_dynptr_from_skb(skb, 0, &ptr))
41+
return NF_ACCEPT;
42+
p = bpf_dynptr_slice(&ptr, 0, &iph, sizeof(iph));
43+
if (!p)
44+
return NF_ACCEPT;
45+
46+
/* ip4 only */
47+
if (p->version != 4)
48+
return NF_ACCEPT;
49+
50+
/* search p->daddr in trie */
51+
key.prefixlen = 32;
52+
key.data = p->daddr;
53+
pvalue = bpf_map_lookup_elem(&ipv4_lpm_map, &key);
54+
if (pvalue) {
55+
/* cat /sys/kernel/debug/tracing/trace_pipe */
56+
bpf_printk("rule matched with %d...\n", *pvalue);
57+
return NF_DROP;
58+
}
59+
return NF_ACCEPT;
60+
}
61+
62+
char _license[] SEC("license") = "GPL";
63+

0 commit comments

Comments
 (0)