xref: /OK3568_Linux_fs/kernel/samples/bpf/test_lwt_bpf.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
4*4882a593Smuzhiyun  * modify it under the terms of version 2 of the GNU General Public
5*4882a593Smuzhiyun  * License as published by the Free Software Foundation.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but
8*4882a593Smuzhiyun  * WITHOUT ANY WARRANTY; without even the implied warranty of
9*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10*4882a593Smuzhiyun  * General Public License for more details.
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <stdint.h>
14*4882a593Smuzhiyun #include <stddef.h>
15*4882a593Smuzhiyun #include <linux/bpf.h>
16*4882a593Smuzhiyun #include <linux/ip.h>
17*4882a593Smuzhiyun #include <linux/in.h>
18*4882a593Smuzhiyun #include <linux/in6.h>
19*4882a593Smuzhiyun #include <linux/tcp.h>
20*4882a593Smuzhiyun #include <linux/udp.h>
21*4882a593Smuzhiyun #include <linux/icmpv6.h>
22*4882a593Smuzhiyun #include <linux/if_ether.h>
23*4882a593Smuzhiyun #include <bpf/bpf_helpers.h>
24*4882a593Smuzhiyun #include <string.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun # define printk(fmt, ...)						\
27*4882a593Smuzhiyun 		({							\
28*4882a593Smuzhiyun 			char ____fmt[] = fmt;				\
29*4882a593Smuzhiyun 			bpf_trace_printk(____fmt, sizeof(____fmt),	\
30*4882a593Smuzhiyun 				     ##__VA_ARGS__);			\
31*4882a593Smuzhiyun 		})
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define CB_MAGIC 1234
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* Test: Pass all packets through */
36*4882a593Smuzhiyun SEC("nop")
do_nop(struct __sk_buff * skb)37*4882a593Smuzhiyun int do_nop(struct __sk_buff *skb)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	return BPF_OK;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /* Test: Verify context information can be accessed */
43*4882a593Smuzhiyun SEC("test_ctx")
do_test_ctx(struct __sk_buff * skb)44*4882a593Smuzhiyun int do_test_ctx(struct __sk_buff *skb)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	skb->cb[0] = CB_MAGIC;
47*4882a593Smuzhiyun 	printk("len %d hash %d protocol %d\n", skb->len, skb->hash,
48*4882a593Smuzhiyun 	       skb->protocol);
49*4882a593Smuzhiyun 	printk("cb %d ingress_ifindex %d ifindex %d\n", skb->cb[0],
50*4882a593Smuzhiyun 	       skb->ingress_ifindex, skb->ifindex);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	return BPF_OK;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /* Test: Ensure skb->cb[] buffer is cleared */
56*4882a593Smuzhiyun SEC("test_cb")
do_test_cb(struct __sk_buff * skb)57*4882a593Smuzhiyun int do_test_cb(struct __sk_buff *skb)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	printk("cb0: %x cb1: %x cb2: %x\n", skb->cb[0], skb->cb[1],
60*4882a593Smuzhiyun 	       skb->cb[2]);
61*4882a593Smuzhiyun 	printk("cb3: %x cb4: %x\n", skb->cb[3], skb->cb[4]);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	return BPF_OK;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /* Test: Verify skb data can be read */
67*4882a593Smuzhiyun SEC("test_data")
do_test_data(struct __sk_buff * skb)68*4882a593Smuzhiyun int do_test_data(struct __sk_buff *skb)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	void *data = (void *)(long)skb->data;
71*4882a593Smuzhiyun 	void *data_end = (void *)(long)skb->data_end;
72*4882a593Smuzhiyun 	struct iphdr *iph = data;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	if (data + sizeof(*iph) > data_end) {
75*4882a593Smuzhiyun 		printk("packet truncated\n");
76*4882a593Smuzhiyun 		return BPF_DROP;
77*4882a593Smuzhiyun 	}
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	printk("src: %x dst: %x\n", iph->saddr, iph->daddr);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	return BPF_OK;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #define IP_CSUM_OFF offsetof(struct iphdr, check)
85*4882a593Smuzhiyun #define IP_DST_OFF offsetof(struct iphdr, daddr)
86*4882a593Smuzhiyun #define IP_SRC_OFF offsetof(struct iphdr, saddr)
87*4882a593Smuzhiyun #define IP_PROTO_OFF offsetof(struct iphdr, protocol)
88*4882a593Smuzhiyun #define TCP_CSUM_OFF offsetof(struct tcphdr, check)
89*4882a593Smuzhiyun #define UDP_CSUM_OFF offsetof(struct udphdr, check)
90*4882a593Smuzhiyun #define IS_PSEUDO 0x10
91*4882a593Smuzhiyun 
rewrite(struct __sk_buff * skb,uint32_t old_ip,uint32_t new_ip,int rw_daddr)92*4882a593Smuzhiyun static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
93*4882a593Smuzhiyun 			  uint32_t new_ip, int rw_daddr)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	int ret, off = 0, flags = IS_PSEUDO;
96*4882a593Smuzhiyun 	uint8_t proto;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1);
99*4882a593Smuzhiyun 	if (ret < 0) {
100*4882a593Smuzhiyun 		printk("bpf_l4_csum_replace failed: %d\n", ret);
101*4882a593Smuzhiyun 		return BPF_DROP;
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	switch (proto) {
105*4882a593Smuzhiyun 	case IPPROTO_TCP:
106*4882a593Smuzhiyun 		off = TCP_CSUM_OFF;
107*4882a593Smuzhiyun 		break;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	case IPPROTO_UDP:
110*4882a593Smuzhiyun 		off = UDP_CSUM_OFF;
111*4882a593Smuzhiyun 		flags |= BPF_F_MARK_MANGLED_0;
112*4882a593Smuzhiyun 		break;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	case IPPROTO_ICMPV6:
115*4882a593Smuzhiyun 		off = offsetof(struct icmp6hdr, icmp6_cksum);
116*4882a593Smuzhiyun 		break;
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	if (off) {
120*4882a593Smuzhiyun 		ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
121*4882a593Smuzhiyun 					  flags | sizeof(new_ip));
122*4882a593Smuzhiyun 		if (ret < 0) {
123*4882a593Smuzhiyun 			printk("bpf_l4_csum_replace failed: %d\n");
124*4882a593Smuzhiyun 			return BPF_DROP;
125*4882a593Smuzhiyun 		}
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip));
129*4882a593Smuzhiyun 	if (ret < 0) {
130*4882a593Smuzhiyun 		printk("bpf_l3_csum_replace failed: %d\n", ret);
131*4882a593Smuzhiyun 		return BPF_DROP;
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	if (rw_daddr)
135*4882a593Smuzhiyun 		ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0);
136*4882a593Smuzhiyun 	else
137*4882a593Smuzhiyun 		ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (ret < 0) {
140*4882a593Smuzhiyun 		printk("bpf_skb_store_bytes() failed: %d\n", ret);
141*4882a593Smuzhiyun 		return BPF_DROP;
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	return BPF_OK;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun /* Test: Verify skb data can be modified */
148*4882a593Smuzhiyun SEC("test_rewrite")
do_test_rewrite(struct __sk_buff * skb)149*4882a593Smuzhiyun int do_test_rewrite(struct __sk_buff *skb)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	uint32_t old_ip, new_ip = 0x3fea8c0;
152*4882a593Smuzhiyun 	int ret;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4);
155*4882a593Smuzhiyun 	if (ret < 0) {
156*4882a593Smuzhiyun 		printk("bpf_skb_load_bytes failed: %d\n", ret);
157*4882a593Smuzhiyun 		return BPF_DROP;
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	if (old_ip == 0x2fea8c0) {
161*4882a593Smuzhiyun 		printk("out: rewriting from %x to %x\n", old_ip, new_ip);
162*4882a593Smuzhiyun 		return rewrite(skb, old_ip, new_ip, 1);
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	return BPF_OK;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
__do_push_ll_and_redirect(struct __sk_buff * skb)168*4882a593Smuzhiyun static inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	uint64_t smac = SRC_MAC, dmac = DST_MAC;
171*4882a593Smuzhiyun 	int ret, ifindex = DST_IFINDEX;
172*4882a593Smuzhiyun 	struct ethhdr ehdr;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	ret = bpf_skb_change_head(skb, 14, 0);
175*4882a593Smuzhiyun 	if (ret < 0) {
176*4882a593Smuzhiyun 		printk("skb_change_head() failed: %d\n", ret);
177*4882a593Smuzhiyun 	}
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	ehdr.h_proto = __constant_htons(ETH_P_IP);
180*4882a593Smuzhiyun 	memcpy(&ehdr.h_source, &smac, 6);
181*4882a593Smuzhiyun 	memcpy(&ehdr.h_dest, &dmac, 6);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0);
184*4882a593Smuzhiyun 	if (ret < 0) {
185*4882a593Smuzhiyun 		printk("skb_store_bytes() failed: %d\n", ret);
186*4882a593Smuzhiyun 		return BPF_DROP;
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return bpf_redirect(ifindex, 0);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun SEC("push_ll_and_redirect_silent")
do_push_ll_and_redirect_silent(struct __sk_buff * skb)193*4882a593Smuzhiyun int do_push_ll_and_redirect_silent(struct __sk_buff *skb)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	return __do_push_ll_and_redirect(skb);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun SEC("push_ll_and_redirect")
do_push_ll_and_redirect(struct __sk_buff * skb)199*4882a593Smuzhiyun int do_push_ll_and_redirect(struct __sk_buff *skb)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	int ret, ifindex = DST_IFINDEX;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	ret = __do_push_ll_and_redirect(skb);
204*4882a593Smuzhiyun 	if (ret >= 0)
205*4882a593Smuzhiyun 		printk("redirected to %d\n", ifindex);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	return ret;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
__fill_garbage(struct __sk_buff * skb)210*4882a593Smuzhiyun static inline void __fill_garbage(struct __sk_buff *skb)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	uint64_t f = 0xFFFFFFFFFFFFFFFF;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 0, &f, sizeof(f), 0);
215*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 8, &f, sizeof(f), 0);
216*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 16, &f, sizeof(f), 0);
217*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 24, &f, sizeof(f), 0);
218*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 32, &f, sizeof(f), 0);
219*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 40, &f, sizeof(f), 0);
220*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 48, &f, sizeof(f), 0);
221*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 56, &f, sizeof(f), 0);
222*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 64, &f, sizeof(f), 0);
223*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 72, &f, sizeof(f), 0);
224*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 80, &f, sizeof(f), 0);
225*4882a593Smuzhiyun 	bpf_skb_store_bytes(skb, 88, &f, sizeof(f), 0);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun SEC("fill_garbage")
do_fill_garbage(struct __sk_buff * skb)229*4882a593Smuzhiyun int do_fill_garbage(struct __sk_buff *skb)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	__fill_garbage(skb);
232*4882a593Smuzhiyun 	printk("Set initial 96 bytes of header to FF\n");
233*4882a593Smuzhiyun 	return BPF_OK;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun SEC("fill_garbage_and_redirect")
do_fill_garbage_and_redirect(struct __sk_buff * skb)237*4882a593Smuzhiyun int do_fill_garbage_and_redirect(struct __sk_buff *skb)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	int ifindex = DST_IFINDEX;
240*4882a593Smuzhiyun 	__fill_garbage(skb);
241*4882a593Smuzhiyun 	printk("redirected to %d\n", ifindex);
242*4882a593Smuzhiyun 	return bpf_redirect(ifindex, 0);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun /* Drop all packets */
246*4882a593Smuzhiyun SEC("drop_all")
do_drop_all(struct __sk_buff * skb)247*4882a593Smuzhiyun int do_drop_all(struct __sk_buff *skb)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	printk("dropping with: %d\n", BPF_DROP);
250*4882a593Smuzhiyun 	return BPF_DROP;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun char _license[] SEC("license") = "GPL";
254