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