1bd4aed0eSJiong Wang // SPDX-License-Identifier: GPL-2.0
2bd4aed0eSJiong Wang /* Copyright (c) 2016 VMware
3bd4aed0eSJiong Wang  * Copyright (c) 2016 Facebook
4bd4aed0eSJiong Wang  *
5bd4aed0eSJiong Wang  * This program is free software; you can redistribute it and/or
6bd4aed0eSJiong Wang  * modify it under the terms of version 2 of the GNU General Public
7bd4aed0eSJiong Wang  * License as published by the Free Software Foundation.
8bd4aed0eSJiong Wang  */
9bd4aed0eSJiong Wang #include <stddef.h>
10bd4aed0eSJiong Wang #include <string.h>
11bd4aed0eSJiong Wang #include <arpa/inet.h>
12bd4aed0eSJiong Wang #include <linux/bpf.h>
13bd4aed0eSJiong Wang #include <linux/if_ether.h>
14bd4aed0eSJiong Wang #include <linux/if_packet.h>
158cc61b7aSShmulik Ladkani #include <linux/if_tunnel.h>
16bd4aed0eSJiong Wang #include <linux/ip.h>
17bd4aed0eSJiong Wang #include <linux/ipv6.h>
181115169fSPaul Chaignon #include <linux/icmp.h>
19bd4aed0eSJiong Wang #include <linux/types.h>
20bd4aed0eSJiong Wang #include <linux/socket.h>
21bd4aed0eSJiong Wang #include <linux/pkt_cls.h>
22bd4aed0eSJiong Wang #include <linux/erspan.h>
231115169fSPaul Chaignon #include <linux/udp.h>
243e689141SToke Høiland-Jørgensen #include <bpf/bpf_helpers.h>
253e689141SToke Høiland-Jørgensen #include <bpf/bpf_endian.h>
26bd4aed0eSJiong Wang 
2771b2ec21SKaixi Fan #define log_err(__ret) bpf_printk("ERROR line:%d ret:%d\n", __LINE__, __ret)
28bd4aed0eSJiong Wang 
291115169fSPaul Chaignon #define VXLAN_UDP_PORT 4789
301115169fSPaul Chaignon 
311115169fSPaul Chaignon /* Only IPv4 address assigned to veth1.
321115169fSPaul Chaignon  * 172.16.1.200
331115169fSPaul Chaignon  */
341115169fSPaul Chaignon #define ASSIGNED_ADDR_VETH1 0xac1001c8
351115169fSPaul Chaignon 
36bd4aed0eSJiong Wang struct geneve_opt {
37bd4aed0eSJiong Wang 	__be16	opt_class;
38bd4aed0eSJiong Wang 	__u8	type;
39bd4aed0eSJiong Wang 	__u8	length:5;
40bd4aed0eSJiong Wang 	__u8	r3:1;
41bd4aed0eSJiong Wang 	__u8	r2:1;
42bd4aed0eSJiong Wang 	__u8	r1:1;
43bd4aed0eSJiong Wang 	__u8	opt_data[8]; /* hard-coded to 8 byte */
44bd4aed0eSJiong Wang };
45bd4aed0eSJiong Wang 
461115169fSPaul Chaignon struct vxlanhdr {
471115169fSPaul Chaignon 	__be32 vx_flags;
481115169fSPaul Chaignon 	__be32 vx_vni;
491115169fSPaul Chaignon } __attribute__((packed));
501115169fSPaul Chaignon 
51bd4aed0eSJiong Wang struct vxlan_metadata {
52bd4aed0eSJiong Wang 	__u32     gbp;
53bd4aed0eSJiong Wang };
54bd4aed0eSJiong Wang 
55d9688f89SChristian Ehrig struct bpf_fou_encap {
56d9688f89SChristian Ehrig 	__be16 sport;
57d9688f89SChristian Ehrig 	__be16 dport;
58d9688f89SChristian Ehrig };
59d9688f89SChristian Ehrig 
60d9688f89SChristian Ehrig enum bpf_fou_encap_type {
61d9688f89SChristian Ehrig 	FOU_BPF_ENCAP_FOU,
62d9688f89SChristian Ehrig 	FOU_BPF_ENCAP_GUE,
63d9688f89SChristian Ehrig };
64d9688f89SChristian Ehrig 
65d9688f89SChristian Ehrig int bpf_skb_set_fou_encap(struct __sk_buff *skb_ctx,
66d9688f89SChristian Ehrig 			  struct bpf_fou_encap *encap, int type) __ksym;
67d9688f89SChristian Ehrig int bpf_skb_get_fou_encap(struct __sk_buff *skb_ctx,
68d9688f89SChristian Ehrig 			  struct bpf_fou_encap *encap) __ksym;
69d9688f89SChristian Ehrig 
701ee7efd4SKaixi Fan struct {
711ee7efd4SKaixi Fan 	__uint(type, BPF_MAP_TYPE_ARRAY);
721ee7efd4SKaixi Fan 	__uint(max_entries, 1);
731ee7efd4SKaixi Fan 	__type(key, __u32);
741ee7efd4SKaixi Fan 	__type(value, __u32);
751ee7efd4SKaixi Fan } local_ip_map SEC(".maps");
761ee7efd4SKaixi Fan 
771ee7efd4SKaixi Fan SEC("tc")
gre_set_tunnel(struct __sk_buff * skb)781ee7efd4SKaixi Fan int gre_set_tunnel(struct __sk_buff *skb)
79bd4aed0eSJiong Wang {
80bd4aed0eSJiong Wang 	int ret;
81bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
82bd4aed0eSJiong Wang 
83bd4aed0eSJiong Wang 	__builtin_memset(&key, 0x0, sizeof(key));
84bd4aed0eSJiong Wang 	key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
85bd4aed0eSJiong Wang 	key.tunnel_id = 2;
86bd4aed0eSJiong Wang 	key.tunnel_tos = 0;
87bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
88bd4aed0eSJiong Wang 
89bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
90bd4aed0eSJiong Wang 				     BPF_F_ZERO_CSUM_TX | BPF_F_SEQ_NUMBER);
91bd4aed0eSJiong Wang 	if (ret < 0) {
9271b2ec21SKaixi Fan 		log_err(ret);
93bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
94bd4aed0eSJiong Wang 	}
95bd4aed0eSJiong Wang 
96bd4aed0eSJiong Wang 	return TC_ACT_OK;
97bd4aed0eSJiong Wang }
98bd4aed0eSJiong Wang 
991ee7efd4SKaixi Fan SEC("tc")
gre_set_tunnel_no_key(struct __sk_buff * skb)100ac6e45e0SChristian Ehrig int gre_set_tunnel_no_key(struct __sk_buff *skb)
101ac6e45e0SChristian Ehrig {
102ac6e45e0SChristian Ehrig 	int ret;
103ac6e45e0SChristian Ehrig 	struct bpf_tunnel_key key;
104ac6e45e0SChristian Ehrig 
105ac6e45e0SChristian Ehrig 	__builtin_memset(&key, 0x0, sizeof(key));
106ac6e45e0SChristian Ehrig 	key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
107ac6e45e0SChristian Ehrig 	key.tunnel_ttl = 64;
108ac6e45e0SChristian Ehrig 
109ac6e45e0SChristian Ehrig 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
110ac6e45e0SChristian Ehrig 				     BPF_F_ZERO_CSUM_TX | BPF_F_SEQ_NUMBER |
111ac6e45e0SChristian Ehrig 				     BPF_F_NO_TUNNEL_KEY);
112ac6e45e0SChristian Ehrig 	if (ret < 0) {
113ac6e45e0SChristian Ehrig 		log_err(ret);
114ac6e45e0SChristian Ehrig 		return TC_ACT_SHOT;
115ac6e45e0SChristian Ehrig 	}
116ac6e45e0SChristian Ehrig 
117ac6e45e0SChristian Ehrig 	return TC_ACT_OK;
118ac6e45e0SChristian Ehrig }
119ac6e45e0SChristian Ehrig 
120ac6e45e0SChristian Ehrig SEC("tc")
gre_get_tunnel(struct __sk_buff * skb)1211ee7efd4SKaixi Fan int gre_get_tunnel(struct __sk_buff *skb)
122bd4aed0eSJiong Wang {
123bd4aed0eSJiong Wang 	int ret;
124bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
125bd4aed0eSJiong Wang 
126bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
127bd4aed0eSJiong Wang 	if (ret < 0) {
12871b2ec21SKaixi Fan 		log_err(ret);
129bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
130bd4aed0eSJiong Wang 	}
131bd4aed0eSJiong Wang 
13271b2ec21SKaixi Fan 	bpf_printk("key %d remote ip 0x%x\n", key.tunnel_id, key.remote_ipv4);
133bd4aed0eSJiong Wang 	return TC_ACT_OK;
134bd4aed0eSJiong Wang }
135bd4aed0eSJiong Wang 
1361ee7efd4SKaixi Fan SEC("tc")
ip6gretap_set_tunnel(struct __sk_buff * skb)1371ee7efd4SKaixi Fan int ip6gretap_set_tunnel(struct __sk_buff *skb)
138bd4aed0eSJiong Wang {
139bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
140bd4aed0eSJiong Wang 	int ret;
141bd4aed0eSJiong Wang 
142bd4aed0eSJiong Wang 	__builtin_memset(&key, 0x0, sizeof(key));
143bd4aed0eSJiong Wang 	key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
144bd4aed0eSJiong Wang 	key.tunnel_id = 2;
145bd4aed0eSJiong Wang 	key.tunnel_tos = 0;
146bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
147bd4aed0eSJiong Wang 	key.tunnel_label = 0xabcde;
148bd4aed0eSJiong Wang 
149bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
150bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6 | BPF_F_ZERO_CSUM_TX |
151bd4aed0eSJiong Wang 				     BPF_F_SEQ_NUMBER);
152bd4aed0eSJiong Wang 	if (ret < 0) {
15371b2ec21SKaixi Fan 		log_err(ret);
154bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
155bd4aed0eSJiong Wang 	}
156bd4aed0eSJiong Wang 
157bd4aed0eSJiong Wang 	return TC_ACT_OK;
158bd4aed0eSJiong Wang }
159bd4aed0eSJiong Wang 
1601ee7efd4SKaixi Fan SEC("tc")
ip6gretap_get_tunnel(struct __sk_buff * skb)1611ee7efd4SKaixi Fan int ip6gretap_get_tunnel(struct __sk_buff *skb)
162bd4aed0eSJiong Wang {
163bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
164bd4aed0eSJiong Wang 	int ret;
165bd4aed0eSJiong Wang 
166bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
167bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
168bd4aed0eSJiong Wang 	if (ret < 0) {
16971b2ec21SKaixi Fan 		log_err(ret);
170bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
171bd4aed0eSJiong Wang 	}
172bd4aed0eSJiong Wang 
17371b2ec21SKaixi Fan 	bpf_printk("key %d remote ip6 ::%x label %x\n",
174bd4aed0eSJiong Wang 		   key.tunnel_id, key.remote_ipv6[3], key.tunnel_label);
175bd4aed0eSJiong Wang 
176bd4aed0eSJiong Wang 	return TC_ACT_OK;
177bd4aed0eSJiong Wang }
178bd4aed0eSJiong Wang 
1791ee7efd4SKaixi Fan SEC("tc")
erspan_set_tunnel(struct __sk_buff * skb)1801ee7efd4SKaixi Fan int erspan_set_tunnel(struct __sk_buff *skb)
181bd4aed0eSJiong Wang {
182bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
183bd4aed0eSJiong Wang 	struct erspan_metadata md;
184bd4aed0eSJiong Wang 	int ret;
185bd4aed0eSJiong Wang 
186bd4aed0eSJiong Wang 	__builtin_memset(&key, 0x0, sizeof(key));
187bd4aed0eSJiong Wang 	key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
188bd4aed0eSJiong Wang 	key.tunnel_id = 2;
189bd4aed0eSJiong Wang 	key.tunnel_tos = 0;
190bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
191bd4aed0eSJiong Wang 
192bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
193bd4aed0eSJiong Wang 				     BPF_F_ZERO_CSUM_TX);
194bd4aed0eSJiong Wang 	if (ret < 0) {
19571b2ec21SKaixi Fan 		log_err(ret);
196bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
197bd4aed0eSJiong Wang 	}
198bd4aed0eSJiong Wang 
199bd4aed0eSJiong Wang 	__builtin_memset(&md, 0, sizeof(md));
200bd4aed0eSJiong Wang #ifdef ERSPAN_V1
201bd4aed0eSJiong Wang 	md.version = 1;
202bd4aed0eSJiong Wang 	md.u.index = bpf_htonl(123);
203bd4aed0eSJiong Wang #else
204bd4aed0eSJiong Wang 	__u8 direction = 1;
205bd4aed0eSJiong Wang 	__u8 hwid = 7;
206bd4aed0eSJiong Wang 
207bd4aed0eSJiong Wang 	md.version = 2;
208bd4aed0eSJiong Wang 	md.u.md2.dir = direction;
209bd4aed0eSJiong Wang 	md.u.md2.hwid = hwid & 0xf;
210bd4aed0eSJiong Wang 	md.u.md2.hwid_upper = (hwid >> 4) & 0x3;
211bd4aed0eSJiong Wang #endif
212bd4aed0eSJiong Wang 
213bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
214bd4aed0eSJiong Wang 	if (ret < 0) {
21571b2ec21SKaixi Fan 		log_err(ret);
216bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
217bd4aed0eSJiong Wang 	}
218bd4aed0eSJiong Wang 
219bd4aed0eSJiong Wang 	return TC_ACT_OK;
220bd4aed0eSJiong Wang }
221bd4aed0eSJiong Wang 
2221ee7efd4SKaixi Fan SEC("tc")
erspan_get_tunnel(struct __sk_buff * skb)2231ee7efd4SKaixi Fan int erspan_get_tunnel(struct __sk_buff *skb)
224bd4aed0eSJiong Wang {
225bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
226bd4aed0eSJiong Wang 	struct erspan_metadata md;
227bd4aed0eSJiong Wang 	int ret;
228bd4aed0eSJiong Wang 
229bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
230bd4aed0eSJiong Wang 	if (ret < 0) {
23171b2ec21SKaixi Fan 		log_err(ret);
232bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
233bd4aed0eSJiong Wang 	}
234bd4aed0eSJiong Wang 
235bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md));
236bd4aed0eSJiong Wang 	if (ret < 0) {
23771b2ec21SKaixi Fan 		log_err(ret);
238bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
239bd4aed0eSJiong Wang 	}
240bd4aed0eSJiong Wang 
24171b2ec21SKaixi Fan 	bpf_printk("key %d remote ip 0x%x erspan version %d\n",
242bd4aed0eSJiong Wang 		   key.tunnel_id, key.remote_ipv4, md.version);
243bd4aed0eSJiong Wang 
244bd4aed0eSJiong Wang #ifdef ERSPAN_V1
245bd4aed0eSJiong Wang 	index = bpf_ntohl(md.u.index);
24671b2ec21SKaixi Fan 	bpf_printk("\tindex %x\n", index);
247bd4aed0eSJiong Wang #else
24871b2ec21SKaixi Fan 	bpf_printk("\tdirection %d hwid %x timestamp %u\n",
249bd4aed0eSJiong Wang 		   md.u.md2.dir,
250bd4aed0eSJiong Wang 		   (md.u.md2.hwid_upper << 4) + md.u.md2.hwid,
251bd4aed0eSJiong Wang 		   bpf_ntohl(md.u.md2.timestamp));
252bd4aed0eSJiong Wang #endif
253bd4aed0eSJiong Wang 
254bd4aed0eSJiong Wang 	return TC_ACT_OK;
255bd4aed0eSJiong Wang }
256bd4aed0eSJiong Wang 
2571ee7efd4SKaixi Fan SEC("tc")
ip4ip6erspan_set_tunnel(struct __sk_buff * skb)2581ee7efd4SKaixi Fan int ip4ip6erspan_set_tunnel(struct __sk_buff *skb)
259bd4aed0eSJiong Wang {
260bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
261bd4aed0eSJiong Wang 	struct erspan_metadata md;
262bd4aed0eSJiong Wang 	int ret;
263bd4aed0eSJiong Wang 
264bd4aed0eSJiong Wang 	__builtin_memset(&key, 0x0, sizeof(key));
265bd4aed0eSJiong Wang 	key.remote_ipv6[3] = bpf_htonl(0x11);
266bd4aed0eSJiong Wang 	key.tunnel_id = 2;
267bd4aed0eSJiong Wang 	key.tunnel_tos = 0;
268bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
269bd4aed0eSJiong Wang 
270bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
271bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
272bd4aed0eSJiong Wang 	if (ret < 0) {
27371b2ec21SKaixi Fan 		log_err(ret);
274bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
275bd4aed0eSJiong Wang 	}
276bd4aed0eSJiong Wang 
277bd4aed0eSJiong Wang 	__builtin_memset(&md, 0, sizeof(md));
278bd4aed0eSJiong Wang 
279bd4aed0eSJiong Wang #ifdef ERSPAN_V1
280bd4aed0eSJiong Wang 	md.u.index = bpf_htonl(123);
281bd4aed0eSJiong Wang 	md.version = 1;
282bd4aed0eSJiong Wang #else
283bd4aed0eSJiong Wang 	__u8 direction = 0;
284bd4aed0eSJiong Wang 	__u8 hwid = 17;
285bd4aed0eSJiong Wang 
286bd4aed0eSJiong Wang 	md.version = 2;
287bd4aed0eSJiong Wang 	md.u.md2.dir = direction;
288bd4aed0eSJiong Wang 	md.u.md2.hwid = hwid & 0xf;
289bd4aed0eSJiong Wang 	md.u.md2.hwid_upper = (hwid >> 4) & 0x3;
290bd4aed0eSJiong Wang #endif
291bd4aed0eSJiong Wang 
292bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
293bd4aed0eSJiong Wang 	if (ret < 0) {
29471b2ec21SKaixi Fan 		log_err(ret);
295bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
296bd4aed0eSJiong Wang 	}
297bd4aed0eSJiong Wang 
298bd4aed0eSJiong Wang 	return TC_ACT_OK;
299bd4aed0eSJiong Wang }
300bd4aed0eSJiong Wang 
3011ee7efd4SKaixi Fan SEC("tc")
ip4ip6erspan_get_tunnel(struct __sk_buff * skb)3021ee7efd4SKaixi Fan int ip4ip6erspan_get_tunnel(struct __sk_buff *skb)
303bd4aed0eSJiong Wang {
304bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
305bd4aed0eSJiong Wang 	struct erspan_metadata md;
306bd4aed0eSJiong Wang 	int ret;
307bd4aed0eSJiong Wang 
308bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
309bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
310bd4aed0eSJiong Wang 	if (ret < 0) {
31171b2ec21SKaixi Fan 		log_err(ret);
312bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
313bd4aed0eSJiong Wang 	}
314bd4aed0eSJiong Wang 
315bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md));
316bd4aed0eSJiong Wang 	if (ret < 0) {
31771b2ec21SKaixi Fan 		log_err(ret);
318bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
319bd4aed0eSJiong Wang 	}
320bd4aed0eSJiong Wang 
32171b2ec21SKaixi Fan 	bpf_printk("ip6erspan get key %d remote ip6 ::%x erspan version %d\n",
322bd4aed0eSJiong Wang 		   key.tunnel_id, key.remote_ipv4, md.version);
323bd4aed0eSJiong Wang 
324bd4aed0eSJiong Wang #ifdef ERSPAN_V1
325bd4aed0eSJiong Wang 	index = bpf_ntohl(md.u.index);
32671b2ec21SKaixi Fan 	bpf_printk("\tindex %x\n", index);
327bd4aed0eSJiong Wang #else
32871b2ec21SKaixi Fan 	bpf_printk("\tdirection %d hwid %x timestamp %u\n",
329bd4aed0eSJiong Wang 		   md.u.md2.dir,
330bd4aed0eSJiong Wang 		   (md.u.md2.hwid_upper << 4) + md.u.md2.hwid,
331bd4aed0eSJiong Wang 		   bpf_ntohl(md.u.md2.timestamp));
332bd4aed0eSJiong Wang #endif
333bd4aed0eSJiong Wang 
334bd4aed0eSJiong Wang 	return TC_ACT_OK;
335bd4aed0eSJiong Wang }
336bd4aed0eSJiong Wang 
3371ee7efd4SKaixi Fan SEC("tc")
vxlan_set_tunnel_dst(struct __sk_buff * skb)3381ee7efd4SKaixi Fan int vxlan_set_tunnel_dst(struct __sk_buff *skb)
339bd4aed0eSJiong Wang {
340bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
341bd4aed0eSJiong Wang 	struct vxlan_metadata md;
3421ee7efd4SKaixi Fan 	__u32 index = 0;
3431ee7efd4SKaixi Fan 	__u32 *local_ip = NULL;
344ec97a76fSDave Marchevsky 	int ret = 0;
3451ee7efd4SKaixi Fan 
3461ee7efd4SKaixi Fan 	local_ip = bpf_map_lookup_elem(&local_ip_map, &index);
3471ee7efd4SKaixi Fan 	if (!local_ip) {
3481ee7efd4SKaixi Fan 		log_err(ret);
3491ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
3501ee7efd4SKaixi Fan 	}
351bd4aed0eSJiong Wang 
352bd4aed0eSJiong Wang 	__builtin_memset(&key, 0x0, sizeof(key));
3531ee7efd4SKaixi Fan 	key.local_ipv4 = 0xac100164; /* 172.16.1.100 */
3541ee7efd4SKaixi Fan 	key.remote_ipv4 = *local_ip;
3551ee7efd4SKaixi Fan 	key.tunnel_id = 2;
3561ee7efd4SKaixi Fan 	key.tunnel_tos = 0;
3571ee7efd4SKaixi Fan 	key.tunnel_ttl = 64;
3581ee7efd4SKaixi Fan 
3591ee7efd4SKaixi Fan 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
3601ee7efd4SKaixi Fan 				     BPF_F_ZERO_CSUM_TX);
3611ee7efd4SKaixi Fan 	if (ret < 0) {
3621ee7efd4SKaixi Fan 		log_err(ret);
3631ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
3641ee7efd4SKaixi Fan 	}
3651ee7efd4SKaixi Fan 
3661ee7efd4SKaixi Fan 	md.gbp = 0x800FF; /* Set VXLAN Group Policy extension */
3671ee7efd4SKaixi Fan 	ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
3681ee7efd4SKaixi Fan 	if (ret < 0) {
3691ee7efd4SKaixi Fan 		log_err(ret);
3701ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
3711ee7efd4SKaixi Fan 	}
3721ee7efd4SKaixi Fan 
3731ee7efd4SKaixi Fan 	return TC_ACT_OK;
3741ee7efd4SKaixi Fan }
3751ee7efd4SKaixi Fan 
3761ee7efd4SKaixi Fan SEC("tc")
vxlan_set_tunnel_src(struct __sk_buff * skb)3771ee7efd4SKaixi Fan int vxlan_set_tunnel_src(struct __sk_buff *skb)
3781ee7efd4SKaixi Fan {
3791ee7efd4SKaixi Fan 	struct bpf_tunnel_key key;
3801ee7efd4SKaixi Fan 	struct vxlan_metadata md;
3811ee7efd4SKaixi Fan 	__u32 index = 0;
3821ee7efd4SKaixi Fan 	__u32 *local_ip = NULL;
383ec97a76fSDave Marchevsky 	int ret = 0;
3841ee7efd4SKaixi Fan 
3851ee7efd4SKaixi Fan 	local_ip = bpf_map_lookup_elem(&local_ip_map, &index);
3861ee7efd4SKaixi Fan 	if (!local_ip) {
38771b2ec21SKaixi Fan 		log_err(ret);
3881ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
3891ee7efd4SKaixi Fan 	}
3901ee7efd4SKaixi Fan 
3911ee7efd4SKaixi Fan 	__builtin_memset(&key, 0x0, sizeof(key));
3921ee7efd4SKaixi Fan 	key.local_ipv4 = *local_ip;
393bd4aed0eSJiong Wang 	key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
394bd4aed0eSJiong Wang 	key.tunnel_id = 2;
395bd4aed0eSJiong Wang 	key.tunnel_tos = 0;
396bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
397bd4aed0eSJiong Wang 
398bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
399bd4aed0eSJiong Wang 				     BPF_F_ZERO_CSUM_TX);
400bd4aed0eSJiong Wang 	if (ret < 0) {
40171b2ec21SKaixi Fan 		log_err(ret);
402bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
403bd4aed0eSJiong Wang 	}
404bd4aed0eSJiong Wang 
405bd4aed0eSJiong Wang 	md.gbp = 0x800FF; /* Set VXLAN Group Policy extension */
406bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
407bd4aed0eSJiong Wang 	if (ret < 0) {
40871b2ec21SKaixi Fan 		log_err(ret);
409bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
410bd4aed0eSJiong Wang 	}
411bd4aed0eSJiong Wang 
412bd4aed0eSJiong Wang 	return TC_ACT_OK;
413bd4aed0eSJiong Wang }
414bd4aed0eSJiong Wang 
4151ee7efd4SKaixi Fan SEC("tc")
vxlan_get_tunnel_src(struct __sk_buff * skb)4161ee7efd4SKaixi Fan int vxlan_get_tunnel_src(struct __sk_buff *skb)
417bd4aed0eSJiong Wang {
418bd4aed0eSJiong Wang 	int ret;
419bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
420bd4aed0eSJiong Wang 	struct vxlan_metadata md;
421bd4aed0eSJiong Wang 
4228cc61b7aSShmulik Ladkani 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
4238cc61b7aSShmulik Ladkani 				     BPF_F_TUNINFO_FLAGS);
424bd4aed0eSJiong Wang 	if (ret < 0) {
42571b2ec21SKaixi Fan 		log_err(ret);
426bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
427bd4aed0eSJiong Wang 	}
428bd4aed0eSJiong Wang 
429bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md));
430bd4aed0eSJiong Wang 	if (ret < 0) {
43171b2ec21SKaixi Fan 		log_err(ret);
432bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
433bd4aed0eSJiong Wang 	}
434bd4aed0eSJiong Wang 
4358cc61b7aSShmulik Ladkani 	if (key.local_ipv4 != ASSIGNED_ADDR_VETH1 || md.gbp != 0x800FF ||
4368cc61b7aSShmulik Ladkani 	    !(key.tunnel_flags & TUNNEL_KEY) ||
4378cc61b7aSShmulik Ladkani 	    (key.tunnel_flags & TUNNEL_CSUM)) {
4388cc61b7aSShmulik Ladkani 		bpf_printk("vxlan key %d local ip 0x%x remote ip 0x%x gbp 0x%x flags 0x%x\n",
4391ee7efd4SKaixi Fan 			   key.tunnel_id, key.local_ipv4,
4408cc61b7aSShmulik Ladkani 			   key.remote_ipv4, md.gbp,
4418cc61b7aSShmulik Ladkani 			   bpf_ntohs(key.tunnel_flags));
4421ee7efd4SKaixi Fan 		log_err(ret);
4431ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
4441ee7efd4SKaixi Fan 	}
445bd4aed0eSJiong Wang 
446bd4aed0eSJiong Wang 	return TC_ACT_OK;
447bd4aed0eSJiong Wang }
448bd4aed0eSJiong Wang 
4491ee7efd4SKaixi Fan SEC("tc")
veth_set_outer_dst(struct __sk_buff * skb)4501115169fSPaul Chaignon int veth_set_outer_dst(struct __sk_buff *skb)
4511115169fSPaul Chaignon {
4521115169fSPaul Chaignon 	struct ethhdr *eth = (struct ethhdr *)(long)skb->data;
4531115169fSPaul Chaignon 	__u32 assigned_ip = bpf_htonl(ASSIGNED_ADDR_VETH1);
4541115169fSPaul Chaignon 	void *data_end = (void *)(long)skb->data_end;
4551115169fSPaul Chaignon 	struct udphdr *udph;
4561115169fSPaul Chaignon 	struct iphdr *iph;
4571115169fSPaul Chaignon 	int ret = 0;
4581115169fSPaul Chaignon 	__s64 csum;
4591115169fSPaul Chaignon 
4601115169fSPaul Chaignon 	if ((void *)eth + sizeof(*eth) > data_end) {
4611115169fSPaul Chaignon 		log_err(ret);
4621115169fSPaul Chaignon 		return TC_ACT_SHOT;
4631115169fSPaul Chaignon 	}
4641115169fSPaul Chaignon 
4651115169fSPaul Chaignon 	if (eth->h_proto != bpf_htons(ETH_P_IP))
4661115169fSPaul Chaignon 		return TC_ACT_OK;
4671115169fSPaul Chaignon 
4681115169fSPaul Chaignon 	iph = (struct iphdr *)(eth + 1);
4691115169fSPaul Chaignon 	if ((void *)iph + sizeof(*iph) > data_end) {
4701115169fSPaul Chaignon 		log_err(ret);
4711115169fSPaul Chaignon 		return TC_ACT_SHOT;
4721115169fSPaul Chaignon 	}
4731115169fSPaul Chaignon 	if (iph->protocol != IPPROTO_UDP)
4741115169fSPaul Chaignon 		return TC_ACT_OK;
4751115169fSPaul Chaignon 
4761115169fSPaul Chaignon 	udph = (struct udphdr *)(iph + 1);
4771115169fSPaul Chaignon 	if ((void *)udph + sizeof(*udph) > data_end) {
4781115169fSPaul Chaignon 		log_err(ret);
4791115169fSPaul Chaignon 		return TC_ACT_SHOT;
4801115169fSPaul Chaignon 	}
4811115169fSPaul Chaignon 	if (udph->dest != bpf_htons(VXLAN_UDP_PORT))
4821115169fSPaul Chaignon 		return TC_ACT_OK;
4831115169fSPaul Chaignon 
4841115169fSPaul Chaignon 	if (iph->daddr != assigned_ip) {
4851115169fSPaul Chaignon 		csum = bpf_csum_diff(&iph->daddr, sizeof(__u32), &assigned_ip,
4861115169fSPaul Chaignon 				     sizeof(__u32), 0);
4871115169fSPaul Chaignon 		if (bpf_skb_store_bytes(skb, ETH_HLEN + offsetof(struct iphdr, daddr),
4881115169fSPaul Chaignon 					&assigned_ip, sizeof(__u32), 0) < 0) {
4891115169fSPaul Chaignon 			log_err(ret);
4901115169fSPaul Chaignon 			return TC_ACT_SHOT;
4911115169fSPaul Chaignon 		}
4921115169fSPaul Chaignon 		if (bpf_l3_csum_replace(skb, ETH_HLEN + offsetof(struct iphdr, check),
4931115169fSPaul Chaignon 					0, csum, 0) < 0) {
4941115169fSPaul Chaignon 			log_err(ret);
4951115169fSPaul Chaignon 			return TC_ACT_SHOT;
4961115169fSPaul Chaignon 		}
4971115169fSPaul Chaignon 		bpf_skb_change_type(skb, PACKET_HOST);
4981115169fSPaul Chaignon 	}
4991115169fSPaul Chaignon 	return TC_ACT_OK;
5001115169fSPaul Chaignon }
5011115169fSPaul Chaignon 
5021115169fSPaul Chaignon SEC("tc")
ip6vxlan_set_tunnel_dst(struct __sk_buff * skb)5031ee7efd4SKaixi Fan int ip6vxlan_set_tunnel_dst(struct __sk_buff *skb)
504bd4aed0eSJiong Wang {
505bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
5061ee7efd4SKaixi Fan 	__u32 index = 0;
5071ee7efd4SKaixi Fan 	__u32 *local_ip;
508ec97a76fSDave Marchevsky 	int ret = 0;
5091ee7efd4SKaixi Fan 
5101ee7efd4SKaixi Fan 	local_ip = bpf_map_lookup_elem(&local_ip_map, &index);
5111ee7efd4SKaixi Fan 	if (!local_ip) {
5121ee7efd4SKaixi Fan 		log_err(ret);
5131ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
5141ee7efd4SKaixi Fan 	}
515bd4aed0eSJiong Wang 
516bd4aed0eSJiong Wang 	__builtin_memset(&key, 0x0, sizeof(key));
5171ee7efd4SKaixi Fan 	key.local_ipv6[3] = bpf_htonl(0x11); /* ::11 */
5181ee7efd4SKaixi Fan 	key.remote_ipv6[3] = bpf_htonl(*local_ip);
5191ee7efd4SKaixi Fan 	key.tunnel_id = 22;
5201ee7efd4SKaixi Fan 	key.tunnel_tos = 0;
5211ee7efd4SKaixi Fan 	key.tunnel_ttl = 64;
5221ee7efd4SKaixi Fan 
5231ee7efd4SKaixi Fan 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
5241ee7efd4SKaixi Fan 				     BPF_F_TUNINFO_IPV6);
5251ee7efd4SKaixi Fan 	if (ret < 0) {
5261ee7efd4SKaixi Fan 		log_err(ret);
5271ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
5281ee7efd4SKaixi Fan 	}
5291ee7efd4SKaixi Fan 
5301ee7efd4SKaixi Fan 	return TC_ACT_OK;
5311ee7efd4SKaixi Fan }
5321ee7efd4SKaixi Fan 
5331ee7efd4SKaixi Fan SEC("tc")
ip6vxlan_set_tunnel_src(struct __sk_buff * skb)5341ee7efd4SKaixi Fan int ip6vxlan_set_tunnel_src(struct __sk_buff *skb)
5351ee7efd4SKaixi Fan {
5361ee7efd4SKaixi Fan 	struct bpf_tunnel_key key;
5371ee7efd4SKaixi Fan 	__u32 index = 0;
5381ee7efd4SKaixi Fan 	__u32 *local_ip;
539ec97a76fSDave Marchevsky 	int ret = 0;
5401ee7efd4SKaixi Fan 
5411ee7efd4SKaixi Fan 	local_ip = bpf_map_lookup_elem(&local_ip_map, &index);
5421ee7efd4SKaixi Fan 	if (!local_ip) {
54371b2ec21SKaixi Fan 		log_err(ret);
5441ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
5451ee7efd4SKaixi Fan 	}
5461ee7efd4SKaixi Fan 
5471ee7efd4SKaixi Fan 	__builtin_memset(&key, 0x0, sizeof(key));
5481ee7efd4SKaixi Fan 	key.local_ipv6[3] = bpf_htonl(*local_ip);
549bd4aed0eSJiong Wang 	key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
550bd4aed0eSJiong Wang 	key.tunnel_id = 22;
551bd4aed0eSJiong Wang 	key.tunnel_tos = 0;
552bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
553bd4aed0eSJiong Wang 
554bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
555bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
556bd4aed0eSJiong Wang 	if (ret < 0) {
55771b2ec21SKaixi Fan 		log_err(ret);
558bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
559bd4aed0eSJiong Wang 	}
560bd4aed0eSJiong Wang 
561bd4aed0eSJiong Wang 	return TC_ACT_OK;
562bd4aed0eSJiong Wang }
563bd4aed0eSJiong Wang 
5641ee7efd4SKaixi Fan SEC("tc")
ip6vxlan_get_tunnel_src(struct __sk_buff * skb)5651ee7efd4SKaixi Fan int ip6vxlan_get_tunnel_src(struct __sk_buff *skb)
566bd4aed0eSJiong Wang {
567bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
5681ee7efd4SKaixi Fan 	__u32 index = 0;
5691ee7efd4SKaixi Fan 	__u32 *local_ip;
570ec97a76fSDave Marchevsky 	int ret = 0;
5711ee7efd4SKaixi Fan 
5721ee7efd4SKaixi Fan 	local_ip = bpf_map_lookup_elem(&local_ip_map, &index);
5731ee7efd4SKaixi Fan 	if (!local_ip) {
57471b2ec21SKaixi Fan 		log_err(ret);
5751ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
5761ee7efd4SKaixi Fan 	}
577bd4aed0eSJiong Wang 
578bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
5798cc61b7aSShmulik Ladkani 				     BPF_F_TUNINFO_IPV6 | BPF_F_TUNINFO_FLAGS);
580bd4aed0eSJiong Wang 	if (ret < 0) {
58171b2ec21SKaixi Fan 		log_err(ret);
582bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
583bd4aed0eSJiong Wang 	}
584bd4aed0eSJiong Wang 
5858cc61b7aSShmulik Ladkani 	if (bpf_ntohl(key.local_ipv6[3]) != *local_ip ||
5868cc61b7aSShmulik Ladkani 	    !(key.tunnel_flags & TUNNEL_KEY) ||
5878cc61b7aSShmulik Ladkani 	    !(key.tunnel_flags & TUNNEL_CSUM)) {
5888cc61b7aSShmulik Ladkani 		bpf_printk("ip6vxlan key %d local ip6 ::%x remote ip6 ::%x label 0x%x flags 0x%x\n",
58971b2ec21SKaixi Fan 			   key.tunnel_id, bpf_ntohl(key.local_ipv6[3]),
5908cc61b7aSShmulik Ladkani 			   bpf_ntohl(key.remote_ipv6[3]), key.tunnel_label,
5918cc61b7aSShmulik Ladkani 			   bpf_ntohs(key.tunnel_flags));
59271b2ec21SKaixi Fan 		bpf_printk("local_ip 0x%x\n", *local_ip);
59371b2ec21SKaixi Fan 		log_err(ret);
5941ee7efd4SKaixi Fan 		return TC_ACT_SHOT;
5951ee7efd4SKaixi Fan 	}
596bd4aed0eSJiong Wang 
597bd4aed0eSJiong Wang 	return TC_ACT_OK;
598bd4aed0eSJiong Wang }
599bd4aed0eSJiong Wang 
600*1b2631ddSCupertino Miranda struct local_geneve_opt {
601*1b2631ddSCupertino Miranda 	struct geneve_opt gopt;
602*1b2631ddSCupertino Miranda 	int data;
603*1b2631ddSCupertino Miranda };
604*1b2631ddSCupertino Miranda 
6051ee7efd4SKaixi Fan SEC("tc")
geneve_set_tunnel(struct __sk_buff * skb)6061ee7efd4SKaixi Fan int geneve_set_tunnel(struct __sk_buff *skb)
607bd4aed0eSJiong Wang {
608069904ceSzuoqilin 	int ret;
609bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
610*1b2631ddSCupertino Miranda 	struct local_geneve_opt local_gopt;
611*1b2631ddSCupertino Miranda 	struct geneve_opt *gopt = (struct geneve_opt *) &local_gopt;
612bd4aed0eSJiong Wang 
613bd4aed0eSJiong Wang 	__builtin_memset(&key, 0x0, sizeof(key));
614bd4aed0eSJiong Wang 	key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
615bd4aed0eSJiong Wang 	key.tunnel_id = 2;
616bd4aed0eSJiong Wang 	key.tunnel_tos = 0;
617bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
618bd4aed0eSJiong Wang 
619*1b2631ddSCupertino Miranda 	__builtin_memset(gopt, 0x0, sizeof(local_gopt));
620*1b2631ddSCupertino Miranda 	gopt->opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */
621*1b2631ddSCupertino Miranda 	gopt->type = 0x08;
622*1b2631ddSCupertino Miranda 	gopt->r1 = 0;
623*1b2631ddSCupertino Miranda 	gopt->r2 = 0;
624*1b2631ddSCupertino Miranda 	gopt->r3 = 0;
625*1b2631ddSCupertino Miranda 	gopt->length = 2; /* 4-byte multiple */
626*1b2631ddSCupertino Miranda 	*(int *) &gopt->opt_data = bpf_htonl(0xdeadbeef);
627bd4aed0eSJiong Wang 
628bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
629bd4aed0eSJiong Wang 				     BPF_F_ZERO_CSUM_TX);
630bd4aed0eSJiong Wang 	if (ret < 0) {
63171b2ec21SKaixi Fan 		log_err(ret);
632bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
633bd4aed0eSJiong Wang 	}
634bd4aed0eSJiong Wang 
635*1b2631ddSCupertino Miranda 	ret = bpf_skb_set_tunnel_opt(skb, gopt, sizeof(local_gopt));
636bd4aed0eSJiong Wang 	if (ret < 0) {
63771b2ec21SKaixi Fan 		log_err(ret);
638bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
639bd4aed0eSJiong Wang 	}
640bd4aed0eSJiong Wang 
641bd4aed0eSJiong Wang 	return TC_ACT_OK;
642bd4aed0eSJiong Wang }
643bd4aed0eSJiong Wang 
6441ee7efd4SKaixi Fan SEC("tc")
geneve_get_tunnel(struct __sk_buff * skb)6451ee7efd4SKaixi Fan int geneve_get_tunnel(struct __sk_buff *skb)
646bd4aed0eSJiong Wang {
647bd4aed0eSJiong Wang 	int ret;
648bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
649bd4aed0eSJiong Wang 	struct geneve_opt gopt;
650bd4aed0eSJiong Wang 
651bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
652bd4aed0eSJiong Wang 	if (ret < 0) {
65371b2ec21SKaixi Fan 		log_err(ret);
654bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
655bd4aed0eSJiong Wang 	}
656bd4aed0eSJiong Wang 
657bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt));
658557c223bSHangbin Liu 	if (ret < 0)
659557c223bSHangbin Liu 		gopt.opt_class = 0;
660bd4aed0eSJiong Wang 
66171b2ec21SKaixi Fan 	bpf_printk("key %d remote ip 0x%x geneve class 0x%x\n",
662bd4aed0eSJiong Wang 		   key.tunnel_id, key.remote_ipv4, gopt.opt_class);
663bd4aed0eSJiong Wang 	return TC_ACT_OK;
664bd4aed0eSJiong Wang }
665bd4aed0eSJiong Wang 
6661ee7efd4SKaixi Fan SEC("tc")
ip6geneve_set_tunnel(struct __sk_buff * skb)6671ee7efd4SKaixi Fan int ip6geneve_set_tunnel(struct __sk_buff *skb)
668bd4aed0eSJiong Wang {
669bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
670*1b2631ddSCupertino Miranda 	struct local_geneve_opt local_gopt;
671*1b2631ddSCupertino Miranda 	struct geneve_opt *gopt = (struct geneve_opt *) &local_gopt;
672bd4aed0eSJiong Wang 	int ret;
673bd4aed0eSJiong Wang 
674bd4aed0eSJiong Wang 	__builtin_memset(&key, 0x0, sizeof(key));
675bd4aed0eSJiong Wang 	key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
676bd4aed0eSJiong Wang 	key.tunnel_id = 22;
677bd4aed0eSJiong Wang 	key.tunnel_tos = 0;
678bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
679bd4aed0eSJiong Wang 
680bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
681bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
682bd4aed0eSJiong Wang 	if (ret < 0) {
68371b2ec21SKaixi Fan 		log_err(ret);
684bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
685bd4aed0eSJiong Wang 	}
686bd4aed0eSJiong Wang 
687*1b2631ddSCupertino Miranda 	__builtin_memset(gopt, 0x0, sizeof(local_gopt));
688*1b2631ddSCupertino Miranda 	gopt->opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */
689*1b2631ddSCupertino Miranda 	gopt->type = 0x08;
690*1b2631ddSCupertino Miranda 	gopt->r1 = 0;
691*1b2631ddSCupertino Miranda 	gopt->r2 = 0;
692*1b2631ddSCupertino Miranda 	gopt->r3 = 0;
693*1b2631ddSCupertino Miranda 	gopt->length = 2; /* 4-byte multiple */
694*1b2631ddSCupertino Miranda 	*(int *) &gopt->opt_data = bpf_htonl(0xfeedbeef);
695bd4aed0eSJiong Wang 
696*1b2631ddSCupertino Miranda 	ret = bpf_skb_set_tunnel_opt(skb, gopt, sizeof(gopt));
697bd4aed0eSJiong Wang 	if (ret < 0) {
69871b2ec21SKaixi Fan 		log_err(ret);
699bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
700bd4aed0eSJiong Wang 	}
701bd4aed0eSJiong Wang 
702bd4aed0eSJiong Wang 	return TC_ACT_OK;
703bd4aed0eSJiong Wang }
704bd4aed0eSJiong Wang 
7051ee7efd4SKaixi Fan SEC("tc")
ip6geneve_get_tunnel(struct __sk_buff * skb)7061ee7efd4SKaixi Fan int ip6geneve_get_tunnel(struct __sk_buff *skb)
707bd4aed0eSJiong Wang {
708bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
709bd4aed0eSJiong Wang 	struct geneve_opt gopt;
710bd4aed0eSJiong Wang 	int ret;
711bd4aed0eSJiong Wang 
712bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
713bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
714bd4aed0eSJiong Wang 	if (ret < 0) {
71571b2ec21SKaixi Fan 		log_err(ret);
716bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
717bd4aed0eSJiong Wang 	}
718bd4aed0eSJiong Wang 
719bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt));
72031254dc9SHangbin Liu 	if (ret < 0)
72131254dc9SHangbin Liu 		gopt.opt_class = 0;
722bd4aed0eSJiong Wang 
72371b2ec21SKaixi Fan 	bpf_printk("key %d remote ip 0x%x geneve class 0x%x\n",
724bd4aed0eSJiong Wang 		   key.tunnel_id, key.remote_ipv4, gopt.opt_class);
725bd4aed0eSJiong Wang 
726bd4aed0eSJiong Wang 	return TC_ACT_OK;
727bd4aed0eSJiong Wang }
728bd4aed0eSJiong Wang 
7291ee7efd4SKaixi Fan SEC("tc")
ipip_set_tunnel(struct __sk_buff * skb)7301ee7efd4SKaixi Fan int ipip_set_tunnel(struct __sk_buff *skb)
731bd4aed0eSJiong Wang {
732bd4aed0eSJiong Wang 	struct bpf_tunnel_key key = {};
733bd4aed0eSJiong Wang 	void *data = (void *)(long)skb->data;
734bd4aed0eSJiong Wang 	struct iphdr *iph = data;
735bd4aed0eSJiong Wang 	void *data_end = (void *)(long)skb->data_end;
736bd4aed0eSJiong Wang 	int ret;
737bd4aed0eSJiong Wang 
738bd4aed0eSJiong Wang 	/* single length check */
73958cfa49cSHangbin Liu 	if (data + sizeof(*iph) > data_end) {
74071b2ec21SKaixi Fan 		log_err(1);
741bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
742bd4aed0eSJiong Wang 	}
743bd4aed0eSJiong Wang 
744bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
745bd4aed0eSJiong Wang 	if (iph->protocol == IPPROTO_ICMP) {
746bd4aed0eSJiong Wang 		key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
747bd4aed0eSJiong Wang 	}
748bd4aed0eSJiong Wang 
749bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0);
750bd4aed0eSJiong Wang 	if (ret < 0) {
75171b2ec21SKaixi Fan 		log_err(ret);
752bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
753bd4aed0eSJiong Wang 	}
754bd4aed0eSJiong Wang 
755bd4aed0eSJiong Wang 	return TC_ACT_OK;
756bd4aed0eSJiong Wang }
757bd4aed0eSJiong Wang 
7581ee7efd4SKaixi Fan SEC("tc")
ipip_get_tunnel(struct __sk_buff * skb)7591ee7efd4SKaixi Fan int ipip_get_tunnel(struct __sk_buff *skb)
760bd4aed0eSJiong Wang {
761bd4aed0eSJiong Wang 	int ret;
762bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
763bd4aed0eSJiong Wang 
764bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
765bd4aed0eSJiong Wang 	if (ret < 0) {
76671b2ec21SKaixi Fan 		log_err(ret);
767bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
768bd4aed0eSJiong Wang 	}
769bd4aed0eSJiong Wang 
77071b2ec21SKaixi Fan 	bpf_printk("remote ip 0x%x\n", key.remote_ipv4);
771bd4aed0eSJiong Wang 	return TC_ACT_OK;
772bd4aed0eSJiong Wang }
773bd4aed0eSJiong Wang 
7741ee7efd4SKaixi Fan SEC("tc")
ipip_gue_set_tunnel(struct __sk_buff * skb)775d9688f89SChristian Ehrig int ipip_gue_set_tunnel(struct __sk_buff *skb)
776d9688f89SChristian Ehrig {
777d9688f89SChristian Ehrig 	struct bpf_tunnel_key key = {};
778d9688f89SChristian Ehrig 	struct bpf_fou_encap encap = {};
779d9688f89SChristian Ehrig 	void *data = (void *)(long)skb->data;
780d9688f89SChristian Ehrig 	struct iphdr *iph = data;
781d9688f89SChristian Ehrig 	void *data_end = (void *)(long)skb->data_end;
782d9688f89SChristian Ehrig 	int ret;
783d9688f89SChristian Ehrig 
784d9688f89SChristian Ehrig 	if (data + sizeof(*iph) > data_end) {
785d9688f89SChristian Ehrig 		log_err(1);
786d9688f89SChristian Ehrig 		return TC_ACT_SHOT;
787d9688f89SChristian Ehrig 	}
788d9688f89SChristian Ehrig 
789d9688f89SChristian Ehrig 	key.tunnel_ttl = 64;
790d9688f89SChristian Ehrig 	if (iph->protocol == IPPROTO_ICMP)
791d9688f89SChristian Ehrig 		key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
792d9688f89SChristian Ehrig 
793d9688f89SChristian Ehrig 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0);
794d9688f89SChristian Ehrig 	if (ret < 0) {
795d9688f89SChristian Ehrig 		log_err(ret);
796d9688f89SChristian Ehrig 		return TC_ACT_SHOT;
797d9688f89SChristian Ehrig 	}
798d9688f89SChristian Ehrig 
799d9688f89SChristian Ehrig 	encap.sport = 0;
800d9688f89SChristian Ehrig 	encap.dport = bpf_htons(5555);
801d9688f89SChristian Ehrig 
802d9688f89SChristian Ehrig 	ret = bpf_skb_set_fou_encap(skb, &encap, FOU_BPF_ENCAP_GUE);
803d9688f89SChristian Ehrig 	if (ret < 0) {
804d9688f89SChristian Ehrig 		log_err(ret);
805d9688f89SChristian Ehrig 		return TC_ACT_SHOT;
806d9688f89SChristian Ehrig 	}
807d9688f89SChristian Ehrig 
808d9688f89SChristian Ehrig 	return TC_ACT_OK;
809d9688f89SChristian Ehrig }
810d9688f89SChristian Ehrig 
811d9688f89SChristian Ehrig SEC("tc")
ipip_fou_set_tunnel(struct __sk_buff * skb)812d9688f89SChristian Ehrig int ipip_fou_set_tunnel(struct __sk_buff *skb)
813d9688f89SChristian Ehrig {
814d9688f89SChristian Ehrig 	struct bpf_tunnel_key key = {};
815d9688f89SChristian Ehrig 	struct bpf_fou_encap encap = {};
816d9688f89SChristian Ehrig 	void *data = (void *)(long)skb->data;
817d9688f89SChristian Ehrig 	struct iphdr *iph = data;
818d9688f89SChristian Ehrig 	void *data_end = (void *)(long)skb->data_end;
819d9688f89SChristian Ehrig 	int ret;
820d9688f89SChristian Ehrig 
821d9688f89SChristian Ehrig 	if (data + sizeof(*iph) > data_end) {
822d9688f89SChristian Ehrig 		log_err(1);
823d9688f89SChristian Ehrig 		return TC_ACT_SHOT;
824d9688f89SChristian Ehrig 	}
825d9688f89SChristian Ehrig 
826d9688f89SChristian Ehrig 	key.tunnel_ttl = 64;
827d9688f89SChristian Ehrig 	if (iph->protocol == IPPROTO_ICMP)
828d9688f89SChristian Ehrig 		key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
829d9688f89SChristian Ehrig 
830d9688f89SChristian Ehrig 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0);
831d9688f89SChristian Ehrig 	if (ret < 0) {
832d9688f89SChristian Ehrig 		log_err(ret);
833d9688f89SChristian Ehrig 		return TC_ACT_SHOT;
834d9688f89SChristian Ehrig 	}
835d9688f89SChristian Ehrig 
836d9688f89SChristian Ehrig 	encap.sport = 0;
837d9688f89SChristian Ehrig 	encap.dport = bpf_htons(5555);
838d9688f89SChristian Ehrig 
839d9688f89SChristian Ehrig 	ret = bpf_skb_set_fou_encap(skb, &encap, FOU_BPF_ENCAP_FOU);
840d9688f89SChristian Ehrig 	if (ret < 0) {
841d9688f89SChristian Ehrig 		log_err(ret);
842d9688f89SChristian Ehrig 		return TC_ACT_SHOT;
843d9688f89SChristian Ehrig 	}
844d9688f89SChristian Ehrig 
845d9688f89SChristian Ehrig 	return TC_ACT_OK;
846d9688f89SChristian Ehrig }
847d9688f89SChristian Ehrig 
848d9688f89SChristian Ehrig SEC("tc")
ipip_encap_get_tunnel(struct __sk_buff * skb)849d9688f89SChristian Ehrig int ipip_encap_get_tunnel(struct __sk_buff *skb)
850d9688f89SChristian Ehrig {
851d9688f89SChristian Ehrig 	int ret;
852d9688f89SChristian Ehrig 	struct bpf_tunnel_key key = {};
853d9688f89SChristian Ehrig 	struct bpf_fou_encap encap = {};
854d9688f89SChristian Ehrig 
855d9688f89SChristian Ehrig 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
856d9688f89SChristian Ehrig 	if (ret < 0) {
857d9688f89SChristian Ehrig 		log_err(ret);
858d9688f89SChristian Ehrig 		return TC_ACT_SHOT;
859d9688f89SChristian Ehrig 	}
860d9688f89SChristian Ehrig 
861d9688f89SChristian Ehrig 	ret = bpf_skb_get_fou_encap(skb, &encap);
862d9688f89SChristian Ehrig 	if (ret < 0) {
863d9688f89SChristian Ehrig 		log_err(ret);
864d9688f89SChristian Ehrig 		return TC_ACT_SHOT;
865d9688f89SChristian Ehrig 	}
866d9688f89SChristian Ehrig 
867d9688f89SChristian Ehrig 	if (bpf_ntohs(encap.dport) != 5555)
868d9688f89SChristian Ehrig 		return TC_ACT_SHOT;
869d9688f89SChristian Ehrig 
870d9688f89SChristian Ehrig 	bpf_printk("%d remote ip 0x%x, sport %d, dport %d\n", ret,
871d9688f89SChristian Ehrig 		   key.remote_ipv4, bpf_ntohs(encap.sport),
872d9688f89SChristian Ehrig 		   bpf_ntohs(encap.dport));
873d9688f89SChristian Ehrig 	return TC_ACT_OK;
874d9688f89SChristian Ehrig }
875d9688f89SChristian Ehrig 
876d9688f89SChristian Ehrig SEC("tc")
ipip6_set_tunnel(struct __sk_buff * skb)8771ee7efd4SKaixi Fan int ipip6_set_tunnel(struct __sk_buff *skb)
878bd4aed0eSJiong Wang {
879bd4aed0eSJiong Wang 	struct bpf_tunnel_key key = {};
880bd4aed0eSJiong Wang 	void *data = (void *)(long)skb->data;
881bd4aed0eSJiong Wang 	struct iphdr *iph = data;
882bd4aed0eSJiong Wang 	void *data_end = (void *)(long)skb->data_end;
883bd4aed0eSJiong Wang 	int ret;
884bd4aed0eSJiong Wang 
885bd4aed0eSJiong Wang 	/* single length check */
88658cfa49cSHangbin Liu 	if (data + sizeof(*iph) > data_end) {
88771b2ec21SKaixi Fan 		log_err(1);
888bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
889bd4aed0eSJiong Wang 	}
890bd4aed0eSJiong Wang 
891bd4aed0eSJiong Wang 	__builtin_memset(&key, 0x0, sizeof(key));
892bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
89358cfa49cSHangbin Liu 	if (iph->protocol == IPPROTO_ICMP) {
89458cfa49cSHangbin Liu 		key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
89558cfa49cSHangbin Liu 	}
896bd4aed0eSJiong Wang 
897bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
898bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
899bd4aed0eSJiong Wang 	if (ret < 0) {
90071b2ec21SKaixi Fan 		log_err(ret);
901bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
902bd4aed0eSJiong Wang 	}
903bd4aed0eSJiong Wang 
904bd4aed0eSJiong Wang 	return TC_ACT_OK;
905bd4aed0eSJiong Wang }
906bd4aed0eSJiong Wang 
9071ee7efd4SKaixi Fan SEC("tc")
ipip6_get_tunnel(struct __sk_buff * skb)9081ee7efd4SKaixi Fan int ipip6_get_tunnel(struct __sk_buff *skb)
909bd4aed0eSJiong Wang {
910bd4aed0eSJiong Wang 	int ret;
911bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
912bd4aed0eSJiong Wang 
913bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
914bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
915bd4aed0eSJiong Wang 	if (ret < 0) {
91671b2ec21SKaixi Fan 		log_err(ret);
917bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
918bd4aed0eSJiong Wang 	}
919bd4aed0eSJiong Wang 
92071b2ec21SKaixi Fan 	bpf_printk("remote ip6 %x::%x\n", bpf_htonl(key.remote_ipv6[0]),
921bd4aed0eSJiong Wang 		   bpf_htonl(key.remote_ipv6[3]));
922bd4aed0eSJiong Wang 	return TC_ACT_OK;
923bd4aed0eSJiong Wang }
924bd4aed0eSJiong Wang 
9251ee7efd4SKaixi Fan SEC("tc")
ip6ip6_set_tunnel(struct __sk_buff * skb)9261ee7efd4SKaixi Fan int ip6ip6_set_tunnel(struct __sk_buff *skb)
927bd4aed0eSJiong Wang {
928bd4aed0eSJiong Wang 	struct bpf_tunnel_key key = {};
929bd4aed0eSJiong Wang 	void *data = (void *)(long)skb->data;
930bd4aed0eSJiong Wang 	struct ipv6hdr *iph = data;
931bd4aed0eSJiong Wang 	void *data_end = (void *)(long)skb->data_end;
932bd4aed0eSJiong Wang 	int ret;
933bd4aed0eSJiong Wang 
934bd4aed0eSJiong Wang 	/* single length check */
93558cfa49cSHangbin Liu 	if (data + sizeof(*iph) > data_end) {
93671b2ec21SKaixi Fan 		log_err(1);
937bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
938bd4aed0eSJiong Wang 	}
939bd4aed0eSJiong Wang 
940bd4aed0eSJiong Wang 	key.tunnel_ttl = 64;
941bd4aed0eSJiong Wang 	if (iph->nexthdr == 58 /* NEXTHDR_ICMP */) {
94258cfa49cSHangbin Liu 		key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
943bd4aed0eSJiong Wang 	}
944bd4aed0eSJiong Wang 
945bd4aed0eSJiong Wang 	ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
946bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
947bd4aed0eSJiong Wang 	if (ret < 0) {
94871b2ec21SKaixi Fan 		log_err(ret);
949bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
950bd4aed0eSJiong Wang 	}
951bd4aed0eSJiong Wang 
952bd4aed0eSJiong Wang 	return TC_ACT_OK;
953bd4aed0eSJiong Wang }
954bd4aed0eSJiong Wang 
9551ee7efd4SKaixi Fan SEC("tc")
ip6ip6_get_tunnel(struct __sk_buff * skb)9561ee7efd4SKaixi Fan int ip6ip6_get_tunnel(struct __sk_buff *skb)
957bd4aed0eSJiong Wang {
958bd4aed0eSJiong Wang 	int ret;
959bd4aed0eSJiong Wang 	struct bpf_tunnel_key key;
960bd4aed0eSJiong Wang 
961bd4aed0eSJiong Wang 	ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
962bd4aed0eSJiong Wang 				     BPF_F_TUNINFO_IPV6);
963bd4aed0eSJiong Wang 	if (ret < 0) {
96471b2ec21SKaixi Fan 		log_err(ret);
965bd4aed0eSJiong Wang 		return TC_ACT_SHOT;
966bd4aed0eSJiong Wang 	}
967bd4aed0eSJiong Wang 
96871b2ec21SKaixi Fan 	bpf_printk("remote ip6 %x::%x\n", bpf_htonl(key.remote_ipv6[0]),
969bd4aed0eSJiong Wang 		   bpf_htonl(key.remote_ipv6[3]));
970bd4aed0eSJiong Wang 	return TC_ACT_OK;
971bd4aed0eSJiong Wang }
972bd4aed0eSJiong Wang 
9731ee7efd4SKaixi Fan SEC("tc")
xfrm_get_state(struct __sk_buff * skb)9741ee7efd4SKaixi Fan int xfrm_get_state(struct __sk_buff *skb)
975bd4aed0eSJiong Wang {
976bd4aed0eSJiong Wang 	struct bpf_xfrm_state x;
977bd4aed0eSJiong Wang 	int ret;
978bd4aed0eSJiong Wang 
979bd4aed0eSJiong Wang 	ret = bpf_skb_get_xfrm_state(skb, 0, &x, sizeof(x), 0);
980bd4aed0eSJiong Wang 	if (ret < 0)
981bd4aed0eSJiong Wang 		return TC_ACT_OK;
982bd4aed0eSJiong Wang 
98371b2ec21SKaixi Fan 	bpf_printk("reqid %d spi 0x%x remote ip 0x%x\n",
98471b2ec21SKaixi Fan 		   x.reqid, bpf_ntohl(x.spi),
985bd4aed0eSJiong Wang 		   bpf_ntohl(x.remote_ipv4));
986bd4aed0eSJiong Wang 	return TC_ACT_OK;
987bd4aed0eSJiong Wang }
988bd4aed0eSJiong Wang 
989bd4aed0eSJiong Wang char _license[] SEC("license") = "GPL";
990