xref: /linux/tools/testing/selftests/bpf/progs/test_tc_tunnel.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 /* In-place tunneling */
4 
5 #include <vmlinux.h>
6 
7 #include <bpf/bpf_helpers.h>
8 #include <bpf/bpf_endian.h>
9 #include <bpf/bpf_core_read.h>
10 #include "bpf_tracing_net.h"
11 #include "bpf_compiler.h"
12 
13 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
14 
15 static const int cfg_port = 8000;
16 
17 static const int cfg_udp_src = 20000;
18 
19 #define ETH_P_MPLS_UC	0x8847
20 #define ETH_P_TEB	0x6558
21 
22 #define MPLS_LS_S_MASK	0x00000100
23 #define BPF_F_ADJ_ROOM_ENCAP_L2(len)			\
24 	(((__u64)len & BPF_ADJ_ROOM_ENCAP_L2_MASK)	\
25 	 << BPF_ADJ_ROOM_ENCAP_L2_SHIFT)
26 
27 struct vxlanhdr___local {
28 	__be32 vx_flags;
29 	__be32 vx_vni;
30 };
31 
32 #define	L2_PAD_SZ	(sizeof(struct vxlanhdr___local) + ETH_HLEN)
33 
34 #define	UDP_PORT		5555
35 #define	MPLS_OVER_UDP_PORT	6635
36 #define	ETH_OVER_UDP_PORT	7777
37 #define	VXLAN_UDP_PORT		8472
38 
39 #define	EXTPROTO_VXLAN	0x1
40 
41 #define SKB_GSO_UDP_TUNNEL_MASK	(SKB_GSO_UDP_TUNNEL |			\
42 				 SKB_GSO_UDP_TUNNEL_CSUM)
43 
44 #define SKB_GSO_TUNNEL_MASK	(SKB_GSO_UDP_TUNNEL_MASK |		\
45 				 SKB_GSO_GRE |				\
46 				 SKB_GSO_GRE_CSUM |			\
47 				 SKB_GSO_IPXIP4 |			\
48 				 SKB_GSO_IPXIP6 |			\
49 				 SKB_GSO_ESP)
50 
51 #define BPF_F_ADJ_ROOM_DECAP_L4_MASK	(BPF_F_ADJ_ROOM_DECAP_L4_UDP |	\
52 					 BPF_F_ADJ_ROOM_DECAP_L4_GRE)
53 
54 #define BPF_F_ADJ_ROOM_DECAP_IPXIP_MASK	(BPF_F_ADJ_ROOM_DECAP_IPXIP4 |	\
55 					 BPF_F_ADJ_ROOM_DECAP_IPXIP6)
56 
57 #define	VXLAN_FLAGS     bpf_htonl(1<<27)
58 #define	VNI_ID		1
59 #define	VXLAN_VNI	bpf_htonl(VNI_ID << 8)
60 
61 #ifndef NEXTHDR_DEST
62 #define NEXTHDR_DEST	60
63 #endif
64 
65 /* MPLS label 1000 with S bit (last label) set and ttl of 255. */
66 static const __u32 mpls_label = __bpf_constant_htonl(1000 << 12 |
67 						     MPLS_LS_S_MASK | 0xff);
68 struct gre_hdr {
69 	__be16 flags;
70 	__be16 protocol;
71 } __attribute__((packed));
72 
73 union l4hdr {
74 	struct udphdr udp;
75 	struct gre_hdr gre;
76 };
77 
78 struct v4hdr {
79 	struct iphdr ip;
80 	union l4hdr l4hdr;
81 	__u8 pad[L2_PAD_SZ];		/* space for L2 header / vxlan header ... */
82 } __attribute__((packed));
83 
84 struct v6hdr {
85 	struct ipv6hdr ip;
86 	union l4hdr l4hdr;
87 	__u8 pad[L2_PAD_SZ];		/* space for L2 header / vxlan header ... */
88 } __attribute__((packed));
89 
set_ipv4_csum(struct iphdr * iph)90 static __always_inline void set_ipv4_csum(struct iphdr *iph)
91 {
92 	__u16 *iph16 = (__u16 *)iph;
93 	__u32 csum;
94 	int i;
95 
96 	iph->check = 0;
97 
98 	__pragma_loop_unroll_full
99 	for (i = 0, csum = 0; i < sizeof(*iph) >> 1; i++)
100 		csum += *iph16++;
101 
102 	iph->check = ~((csum & 0xffff) + (csum >> 16));
103 }
104 
__encap_ipv4(struct __sk_buff * skb,__u8 encap_proto,__u16 l2_proto,__u16 ext_proto)105 static __always_inline int __encap_ipv4(struct __sk_buff *skb, __u8 encap_proto,
106 					__u16 l2_proto, __u16 ext_proto)
107 {
108 	struct iphdr iph_inner = {0};
109 	__u16 udp_dst = UDP_PORT;
110 	struct v4hdr h_outer;
111 	struct tcphdr tcph;
112 	int olen, l2_len;
113 	__u8 *l2_hdr = NULL;
114 	int tcp_off;
115 	__u64 flags;
116 
117 	/* Most tests encapsulate a packet into a tunnel with the same
118 	 * network protocol, and derive the outer header fields from
119 	 * the inner header.
120 	 *
121 	 * The 6in4 case tests different inner and outer protocols. As
122 	 * the inner is ipv6, but the outer expects an ipv4 header as
123 	 * input, manually build a struct iphdr based on the ipv6hdr.
124 	 */
125 	if (encap_proto == IPPROTO_IPV6) {
126 		const __u32 saddr = (192 << 24) | (168 << 16) | (1 << 8) | 1;
127 		const __u32 daddr = (192 << 24) | (168 << 16) | (1 << 8) | 2;
128 		struct ipv6hdr iph6_inner;
129 
130 		/* Read the IPv6 header */
131 		if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph6_inner,
132 				       sizeof(iph6_inner)) < 0)
133 			return TC_ACT_OK;
134 
135 		/* Derive the IPv4 header fields from the IPv6 header */
136 		iph_inner.version = 4;
137 		iph_inner.ihl = 5;
138 		iph_inner.tot_len = bpf_htons(sizeof(iph6_inner) +
139 				    bpf_ntohs(iph6_inner.payload_len));
140 		iph_inner.ttl = iph6_inner.hop_limit - 1;
141 		iph_inner.protocol = iph6_inner.nexthdr;
142 		iph_inner.saddr = __bpf_constant_htonl(saddr);
143 		iph_inner.daddr = __bpf_constant_htonl(daddr);
144 
145 		tcp_off = sizeof(iph6_inner);
146 	} else {
147 		if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner,
148 				       sizeof(iph_inner)) < 0)
149 			return TC_ACT_OK;
150 
151 		tcp_off = sizeof(iph_inner);
152 	}
153 
154 	/* filter only packets we want */
155 	if (iph_inner.ihl != 5 || iph_inner.protocol != IPPROTO_TCP)
156 		return TC_ACT_OK;
157 
158 	if (bpf_skb_load_bytes(skb, ETH_HLEN + tcp_off,
159 			       &tcph, sizeof(tcph)) < 0)
160 		return TC_ACT_OK;
161 
162 	if (tcph.dest != __bpf_constant_htons(cfg_port))
163 		return TC_ACT_OK;
164 
165 	olen = sizeof(h_outer.ip);
166 	l2_len = 0;
167 
168 	flags = BPF_F_ADJ_ROOM_FIXED_GSO | BPF_F_ADJ_ROOM_ENCAP_L3_IPV4;
169 
170 	switch (l2_proto) {
171 	case ETH_P_MPLS_UC:
172 		l2_len = sizeof(mpls_label);
173 		udp_dst = MPLS_OVER_UDP_PORT;
174 		break;
175 	case ETH_P_TEB:
176 		l2_len = ETH_HLEN;
177 		if (ext_proto & EXTPROTO_VXLAN) {
178 			udp_dst = VXLAN_UDP_PORT;
179 			l2_len += sizeof(struct vxlanhdr___local);
180 		} else
181 			udp_dst = ETH_OVER_UDP_PORT;
182 		break;
183 	}
184 	flags |= BPF_F_ADJ_ROOM_ENCAP_L2(l2_len);
185 
186 	switch (encap_proto) {
187 	case IPPROTO_GRE:
188 		flags |= BPF_F_ADJ_ROOM_ENCAP_L4_GRE;
189 		olen += sizeof(h_outer.l4hdr.gre);
190 		h_outer.l4hdr.gre.protocol = bpf_htons(l2_proto);
191 		h_outer.l4hdr.gre.flags = 0;
192 		break;
193 	case IPPROTO_UDP:
194 		flags |= BPF_F_ADJ_ROOM_ENCAP_L4_UDP;
195 		olen += sizeof(h_outer.l4hdr.udp);
196 		h_outer.l4hdr.udp.source = __bpf_constant_htons(cfg_udp_src);
197 		h_outer.l4hdr.udp.dest = bpf_htons(udp_dst);
198 		h_outer.l4hdr.udp.check = 0;
199 		h_outer.l4hdr.udp.len = bpf_htons(bpf_ntohs(iph_inner.tot_len) +
200 						  sizeof(h_outer.l4hdr.udp) +
201 						  l2_len);
202 		break;
203 	case IPPROTO_IPIP:
204 	case IPPROTO_IPV6:
205 		break;
206 	default:
207 		return TC_ACT_OK;
208 	}
209 
210 	/* add L2 encap (if specified) */
211 	l2_hdr = (__u8 *)&h_outer + olen;
212 	switch (l2_proto) {
213 	case ETH_P_MPLS_UC:
214 		*(__u32 *)l2_hdr = mpls_label;
215 		break;
216 	case ETH_P_TEB:
217 		flags |= BPF_F_ADJ_ROOM_ENCAP_L2_ETH;
218 
219 		if (ext_proto & EXTPROTO_VXLAN) {
220 			struct vxlanhdr___local *vxlan_hdr = (struct vxlanhdr___local *)l2_hdr;
221 
222 			vxlan_hdr->vx_flags = VXLAN_FLAGS;
223 			vxlan_hdr->vx_vni = VXLAN_VNI;
224 
225 			l2_hdr += sizeof(struct vxlanhdr___local);
226 		}
227 
228 		if (bpf_skb_load_bytes(skb, 0, l2_hdr, ETH_HLEN))
229 			return TC_ACT_SHOT;
230 
231 		break;
232 	}
233 	olen += l2_len;
234 
235 	/* add room between mac and network header */
236 	if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_MAC, flags))
237 		return TC_ACT_SHOT;
238 
239 	/* prepare new outer network header */
240 	h_outer.ip = iph_inner;
241 	h_outer.ip.tot_len = bpf_htons(olen +
242 				       bpf_ntohs(h_outer.ip.tot_len));
243 	h_outer.ip.protocol = encap_proto;
244 
245 	set_ipv4_csum((void *)&h_outer.ip);
246 
247 	/* store new outer network header */
248 	if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen,
249 				BPF_F_INVALIDATE_HASH) < 0)
250 		return TC_ACT_SHOT;
251 
252 	/* if changing outer proto type, update eth->h_proto */
253 	if (encap_proto == IPPROTO_IPV6) {
254 		struct ethhdr eth;
255 
256 		if (bpf_skb_load_bytes(skb, 0, &eth, sizeof(eth)) < 0)
257 			return TC_ACT_SHOT;
258 		eth.h_proto = bpf_htons(ETH_P_IP);
259 		if (bpf_skb_store_bytes(skb, 0, &eth, sizeof(eth), 0) < 0)
260 			return TC_ACT_SHOT;
261 	}
262 
263 	return TC_ACT_OK;
264 }
265 
encap_ipv4(struct __sk_buff * skb,__u8 encap_proto,__u16 l2_proto)266 static __always_inline int encap_ipv4(struct __sk_buff *skb, __u8 encap_proto,
267 				      __u16 l2_proto)
268 {
269 	return __encap_ipv4(skb, encap_proto, l2_proto, 0);
270 }
271 
__encap_ipv6(struct __sk_buff * skb,__u8 encap_proto,__u16 l2_proto,__u16 ext_proto)272 static __always_inline int __encap_ipv6(struct __sk_buff *skb, __u8 encap_proto,
273 					__u16 l2_proto, __u16 ext_proto)
274 {
275 	__u16 udp_dst = UDP_PORT;
276 	struct ipv6hdr iph_inner;
277 	struct v6hdr h_outer;
278 	struct tcphdr tcph;
279 	int olen, l2_len;
280 	__u8 *l2_hdr = NULL;
281 	__u16 tot_len;
282 	__u64 flags;
283 
284 	if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner,
285 			       sizeof(iph_inner)) < 0)
286 		return TC_ACT_OK;
287 
288 	/* filter only packets we want */
289 	if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(iph_inner),
290 			       &tcph, sizeof(tcph)) < 0)
291 		return TC_ACT_OK;
292 
293 	if (tcph.dest != __bpf_constant_htons(cfg_port))
294 		return TC_ACT_OK;
295 
296 	olen = sizeof(h_outer.ip);
297 	l2_len = 0;
298 
299 	flags = BPF_F_ADJ_ROOM_FIXED_GSO | BPF_F_ADJ_ROOM_ENCAP_L3_IPV6;
300 
301 	switch (l2_proto) {
302 	case ETH_P_MPLS_UC:
303 		l2_len = sizeof(mpls_label);
304 		udp_dst = MPLS_OVER_UDP_PORT;
305 		break;
306 	case ETH_P_TEB:
307 		l2_len = ETH_HLEN;
308 		if (ext_proto & EXTPROTO_VXLAN) {
309 			udp_dst = VXLAN_UDP_PORT;
310 			l2_len += sizeof(struct vxlanhdr___local);
311 		} else
312 			udp_dst = ETH_OVER_UDP_PORT;
313 		break;
314 	}
315 	flags |= BPF_F_ADJ_ROOM_ENCAP_L2(l2_len);
316 
317 	switch (encap_proto) {
318 	case IPPROTO_GRE:
319 		flags |= BPF_F_ADJ_ROOM_ENCAP_L4_GRE;
320 		olen += sizeof(h_outer.l4hdr.gre);
321 		h_outer.l4hdr.gre.protocol = bpf_htons(l2_proto);
322 		h_outer.l4hdr.gre.flags = 0;
323 		break;
324 	case IPPROTO_UDP:
325 		flags |= BPF_F_ADJ_ROOM_ENCAP_L4_UDP;
326 		olen += sizeof(h_outer.l4hdr.udp);
327 		h_outer.l4hdr.udp.source = __bpf_constant_htons(cfg_udp_src);
328 		h_outer.l4hdr.udp.dest = bpf_htons(udp_dst);
329 		tot_len = bpf_ntohs(iph_inner.payload_len) + sizeof(iph_inner) +
330 			  sizeof(h_outer.l4hdr.udp) + l2_len;
331 		h_outer.l4hdr.udp.check = 0;
332 		h_outer.l4hdr.udp.len = bpf_htons(tot_len);
333 		break;
334 	case IPPROTO_IPV6:
335 		break;
336 	default:
337 		return TC_ACT_OK;
338 	}
339 
340 	/* add L2 encap (if specified) */
341 	l2_hdr = (__u8 *)&h_outer + olen;
342 	switch (l2_proto) {
343 	case ETH_P_MPLS_UC:
344 		*(__u32 *)l2_hdr = mpls_label;
345 		break;
346 	case ETH_P_TEB:
347 		flags |= BPF_F_ADJ_ROOM_ENCAP_L2_ETH;
348 
349 		if (ext_proto & EXTPROTO_VXLAN) {
350 			struct vxlanhdr___local *vxlan_hdr = (struct vxlanhdr___local *)l2_hdr;
351 
352 			vxlan_hdr->vx_flags = VXLAN_FLAGS;
353 			vxlan_hdr->vx_vni = VXLAN_VNI;
354 
355 			l2_hdr += sizeof(struct vxlanhdr___local);
356 		}
357 
358 		if (bpf_skb_load_bytes(skb, 0, l2_hdr, ETH_HLEN))
359 			return TC_ACT_SHOT;
360 		break;
361 	}
362 	olen += l2_len;
363 
364 	/* add room between mac and network header */
365 	if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_MAC, flags))
366 		return TC_ACT_SHOT;
367 
368 	/* prepare new outer network header */
369 	h_outer.ip = iph_inner;
370 	h_outer.ip.payload_len = bpf_htons(olen +
371 					   bpf_ntohs(h_outer.ip.payload_len));
372 
373 	h_outer.ip.nexthdr = encap_proto;
374 
375 	/* store new outer network header */
376 	if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen,
377 				BPF_F_INVALIDATE_HASH) < 0)
378 		return TC_ACT_SHOT;
379 
380 	return TC_ACT_OK;
381 }
382 
encap_ipv6_ipip6(struct __sk_buff * skb)383 static int encap_ipv6_ipip6(struct __sk_buff *skb)
384 {
385 	struct v6hdr h_outer = {0};
386 	struct iphdr iph_inner;
387 	struct tcphdr tcph;
388 	struct ethhdr eth;
389 	__u64 flags;
390 	int olen;
391 
392 	if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner,
393 			       sizeof(iph_inner)) < 0)
394 		return TC_ACT_OK;
395 
396 	/* filter only packets we want */
397 	if (bpf_skb_load_bytes(skb, ETH_HLEN + (iph_inner.ihl << 2),
398 			       &tcph, sizeof(tcph)) < 0)
399 		return TC_ACT_OK;
400 
401 	if (tcph.dest != __bpf_constant_htons(cfg_port))
402 		return TC_ACT_OK;
403 
404 	olen = sizeof(h_outer.ip);
405 
406 	flags = BPF_F_ADJ_ROOM_FIXED_GSO | BPF_F_ADJ_ROOM_ENCAP_L3_IPV6;
407 
408 	/* add room between mac and network header */
409 	if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_MAC, flags))
410 		return TC_ACT_SHOT;
411 
412 	/* prepare new outer network header */
413 	h_outer.ip.version = 6;
414 	h_outer.ip.hop_limit = iph_inner.ttl;
415 	h_outer.ip.saddr.in6_u.u6_addr8[1] = 0xfd;
416 	h_outer.ip.saddr.in6_u.u6_addr8[15] = 1;
417 	h_outer.ip.daddr.in6_u.u6_addr8[1] = 0xfd;
418 	h_outer.ip.daddr.in6_u.u6_addr8[15] = 2;
419 	h_outer.ip.payload_len = iph_inner.tot_len;
420 	h_outer.ip.nexthdr = IPPROTO_IPIP;
421 
422 	/* store new outer network header */
423 	if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen,
424 				BPF_F_INVALIDATE_HASH) < 0)
425 		return TC_ACT_SHOT;
426 
427 	/* update eth->h_proto */
428 	if (bpf_skb_load_bytes(skb, 0, &eth, sizeof(eth)) < 0)
429 		return TC_ACT_SHOT;
430 	eth.h_proto = bpf_htons(ETH_P_IPV6);
431 	if (bpf_skb_store_bytes(skb, 0, &eth, sizeof(eth), 0) < 0)
432 		return TC_ACT_SHOT;
433 
434 	return TC_ACT_OK;
435 }
436 
encap_ipv6(struct __sk_buff * skb,__u8 encap_proto,__u16 l2_proto)437 static __always_inline int encap_ipv6(struct __sk_buff *skb, __u8 encap_proto,
438 				      __u16 l2_proto)
439 {
440 	return __encap_ipv6(skb, encap_proto, l2_proto, 0);
441 }
442 
443 SEC("tc")
__encap_ipip_none(struct __sk_buff * skb)444 int __encap_ipip_none(struct __sk_buff *skb)
445 {
446 	if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
447 		return encap_ipv4(skb, IPPROTO_IPIP, ETH_P_IP);
448 	else
449 		return TC_ACT_OK;
450 }
451 
452 SEC("tc")
__encap_gre_none(struct __sk_buff * skb)453 int __encap_gre_none(struct __sk_buff *skb)
454 {
455 	if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
456 		return encap_ipv4(skb, IPPROTO_GRE, ETH_P_IP);
457 	else
458 		return TC_ACT_OK;
459 }
460 
461 SEC("tc")
__encap_gre_mpls(struct __sk_buff * skb)462 int __encap_gre_mpls(struct __sk_buff *skb)
463 {
464 	if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
465 		return encap_ipv4(skb, IPPROTO_GRE, ETH_P_MPLS_UC);
466 	else
467 		return TC_ACT_OK;
468 }
469 
470 SEC("tc")
__encap_gre_eth(struct __sk_buff * skb)471 int __encap_gre_eth(struct __sk_buff *skb)
472 {
473 	if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
474 		return encap_ipv4(skb, IPPROTO_GRE, ETH_P_TEB);
475 	else
476 		return TC_ACT_OK;
477 }
478 
479 SEC("tc")
__encap_udp_none(struct __sk_buff * skb)480 int __encap_udp_none(struct __sk_buff *skb)
481 {
482 	if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
483 		return encap_ipv4(skb, IPPROTO_UDP, ETH_P_IP);
484 	else
485 		return TC_ACT_OK;
486 }
487 
488 SEC("tc")
__encap_udp_mpls(struct __sk_buff * skb)489 int __encap_udp_mpls(struct __sk_buff *skb)
490 {
491 	if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
492 		return encap_ipv4(skb, IPPROTO_UDP, ETH_P_MPLS_UC);
493 	else
494 		return TC_ACT_OK;
495 }
496 
497 SEC("tc")
__encap_udp_eth(struct __sk_buff * skb)498 int __encap_udp_eth(struct __sk_buff *skb)
499 {
500 	if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
501 		return encap_ipv4(skb, IPPROTO_UDP, ETH_P_TEB);
502 	else
503 		return TC_ACT_OK;
504 }
505 
506 SEC("tc")
__encap_vxlan_eth(struct __sk_buff * skb)507 int __encap_vxlan_eth(struct __sk_buff *skb)
508 {
509 	if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
510 		return __encap_ipv4(skb, IPPROTO_UDP,
511 				    ETH_P_TEB,
512 				    EXTPROTO_VXLAN);
513 	else
514 		return TC_ACT_OK;
515 }
516 
517 SEC("tc")
__encap_sit_none(struct __sk_buff * skb)518 int __encap_sit_none(struct __sk_buff *skb)
519 {
520 	if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
521 		return encap_ipv4(skb, IPPROTO_IPV6, ETH_P_IP);
522 	else
523 		return TC_ACT_OK;
524 }
525 
526 SEC("tc")
__encap_ip6tnl_none(struct __sk_buff * skb)527 int __encap_ip6tnl_none(struct __sk_buff *skb)
528 {
529 	if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
530 		return encap_ipv6(skb, IPPROTO_IPV6, ETH_P_IPV6);
531 	else
532 		return TC_ACT_OK;
533 }
534 
535 SEC("tc")
__encap_ipip6_none(struct __sk_buff * skb)536 int __encap_ipip6_none(struct __sk_buff *skb)
537 {
538 	if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
539 		return encap_ipv6_ipip6(skb);
540 	else
541 		return TC_ACT_OK;
542 }
543 
544 SEC("tc")
__encap_ip6gre_none(struct __sk_buff * skb)545 int __encap_ip6gre_none(struct __sk_buff *skb)
546 {
547 	if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
548 		return encap_ipv6(skb, IPPROTO_GRE, ETH_P_IPV6);
549 	else
550 		return TC_ACT_OK;
551 }
552 
553 SEC("tc")
__encap_ip6gre_mpls(struct __sk_buff * skb)554 int __encap_ip6gre_mpls(struct __sk_buff *skb)
555 {
556 	if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
557 		return encap_ipv6(skb, IPPROTO_GRE, ETH_P_MPLS_UC);
558 	else
559 		return TC_ACT_OK;
560 }
561 
562 SEC("tc")
__encap_ip6gre_eth(struct __sk_buff * skb)563 int __encap_ip6gre_eth(struct __sk_buff *skb)
564 {
565 	if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
566 		return encap_ipv6(skb, IPPROTO_GRE, ETH_P_TEB);
567 	else
568 		return TC_ACT_OK;
569 }
570 
571 SEC("tc")
__encap_ip6udp_none(struct __sk_buff * skb)572 int __encap_ip6udp_none(struct __sk_buff *skb)
573 {
574 	if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
575 		return encap_ipv6(skb, IPPROTO_UDP, ETH_P_IPV6);
576 	else
577 		return TC_ACT_OK;
578 }
579 
580 SEC("tc")
__encap_ip6udp_mpls(struct __sk_buff * skb)581 int __encap_ip6udp_mpls(struct __sk_buff *skb)
582 {
583 	if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
584 		return encap_ipv6(skb, IPPROTO_UDP, ETH_P_MPLS_UC);
585 	else
586 		return TC_ACT_OK;
587 }
588 
589 SEC("tc")
__encap_ip6udp_eth(struct __sk_buff * skb)590 int __encap_ip6udp_eth(struct __sk_buff *skb)
591 {
592 	if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
593 		return encap_ipv6(skb, IPPROTO_UDP, ETH_P_TEB);
594 	else
595 		return TC_ACT_OK;
596 }
597 
598 SEC("tc")
__encap_ip6vxlan_eth(struct __sk_buff * skb)599 int __encap_ip6vxlan_eth(struct __sk_buff *skb)
600 {
601 	if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
602 		return __encap_ipv6(skb, IPPROTO_UDP,
603 				    ETH_P_TEB,
604 				    EXTPROTO_VXLAN);
605 	else
606 		return TC_ACT_OK;
607 }
608 
decap_internal(struct __sk_buff * skb,int off,int len,char proto,__u64 ipxip_flag)609 static int decap_internal(struct __sk_buff *skb, int off, int len, char proto,
610 			  __u64 ipxip_flag)
611 {
612 	__u64 flags = BPF_F_ADJ_ROOM_FIXED_GSO;
613 	struct sk_buff *kskb;
614 	struct skb_shared_info *shinfo;
615 	struct ipv6_opt_hdr ip6_opt_hdr;
616 	struct gre_hdr greh;
617 	struct udphdr udph;
618 	int olen = len;
619 
620 	switch (proto) {
621 	case IPPROTO_IPIP:
622 		flags |= BPF_F_ADJ_ROOM_DECAP_L3_IPV4 |
623 			 ipxip_flag;
624 		break;
625 	case IPPROTO_IPV6:
626 		flags |= BPF_F_ADJ_ROOM_DECAP_L3_IPV6 |
627 			 ipxip_flag;
628 		break;
629 	case NEXTHDR_DEST:
630 		if (bpf_skb_load_bytes(skb, off + len, &ip6_opt_hdr,
631 				       sizeof(ip6_opt_hdr)) < 0)
632 			return TC_ACT_OK;
633 		switch (ip6_opt_hdr.nexthdr) {
634 		case IPPROTO_IPIP:
635 			flags |= BPF_F_ADJ_ROOM_DECAP_L3_IPV4 |
636 				 ipxip_flag;
637 			break;
638 		case IPPROTO_IPV6:
639 			flags |= BPF_F_ADJ_ROOM_DECAP_L3_IPV6 |
640 				 ipxip_flag;
641 			break;
642 		default:
643 			return TC_ACT_OK;
644 		}
645 		break;
646 	case IPPROTO_GRE:
647 		olen += sizeof(struct gre_hdr);
648 		if (!bpf_core_enum_value_exists(enum bpf_adj_room_flags,
649 						BPF_F_ADJ_ROOM_DECAP_L4_GRE))
650 			return TC_ACT_SHOT;
651 		flags |= BPF_F_ADJ_ROOM_DECAP_L4_GRE;
652 
653 		if (bpf_skb_load_bytes(skb, off + len, &greh, sizeof(greh)) < 0)
654 			return TC_ACT_OK;
655 		switch (bpf_ntohs(greh.protocol)) {
656 		case ETH_P_MPLS_UC:
657 			olen += sizeof(mpls_label);
658 			break;
659 		case ETH_P_TEB:
660 			olen += ETH_HLEN;
661 			break;
662 		}
663 		break;
664 	case IPPROTO_UDP:
665 		olen += sizeof(struct udphdr);
666 		if (!bpf_core_enum_value_exists(enum bpf_adj_room_flags,
667 						BPF_F_ADJ_ROOM_DECAP_L4_UDP))
668 			return TC_ACT_SHOT;
669 		flags |= BPF_F_ADJ_ROOM_DECAP_L4_UDP;
670 		if (bpf_skb_load_bytes(skb, off + len, &udph, sizeof(udph)) < 0)
671 			return TC_ACT_OK;
672 		switch (bpf_ntohs(udph.dest)) {
673 		case MPLS_OVER_UDP_PORT:
674 			olen += sizeof(mpls_label);
675 			break;
676 		case ETH_OVER_UDP_PORT:
677 			olen += ETH_HLEN;
678 			break;
679 		case VXLAN_UDP_PORT:
680 			olen += ETH_HLEN + sizeof(struct vxlanhdr___local);
681 			break;
682 		}
683 		break;
684 	default:
685 		return TC_ACT_OK;
686 	}
687 
688 	if (bpf_skb_adjust_room(skb, -olen, BPF_ADJ_ROOM_MAC, flags))
689 		return TC_ACT_SHOT;
690 
691 	kskb = bpf_cast_to_kern_ctx(skb);
692 	shinfo = bpf_core_cast(kskb->head + kskb->end, struct skb_shared_info);
693 	if (shinfo->gso_size) {
694 		if ((flags & BPF_F_ADJ_ROOM_DECAP_L4_UDP) &&
695 		    (shinfo->gso_type & SKB_GSO_UDP_TUNNEL_MASK))
696 			return TC_ACT_SHOT;
697 
698 		if ((flags & BPF_F_ADJ_ROOM_DECAP_L4_GRE) &&
699 		    (shinfo->gso_type & (SKB_GSO_GRE | SKB_GSO_GRE_CSUM)))
700 			return TC_ACT_SHOT;
701 
702 		if ((flags & BPF_F_ADJ_ROOM_DECAP_IPXIP4) &&
703 		    (shinfo->gso_type & SKB_GSO_IPXIP4))
704 			return TC_ACT_SHOT;
705 
706 		if ((flags & BPF_F_ADJ_ROOM_DECAP_IPXIP6) &&
707 		    (shinfo->gso_type & SKB_GSO_IPXIP6))
708 			return TC_ACT_SHOT;
709 
710 		if (flags & (BPF_F_ADJ_ROOM_DECAP_L4_MASK |
711 			     BPF_F_ADJ_ROOM_DECAP_IPXIP_MASK)) {
712 			if ((shinfo->gso_type & SKB_GSO_TUNNEL_MASK) &&
713 			    !kskb->encapsulation)
714 				return TC_ACT_SHOT;
715 			if (!(shinfo->gso_type & SKB_GSO_TUNNEL_MASK) &&
716 			    kskb->encapsulation)
717 				return TC_ACT_SHOT;
718 		}
719 	} else if ((flags & (BPF_F_ADJ_ROOM_DECAP_L4_MASK |
720 			     BPF_F_ADJ_ROOM_DECAP_IPXIP_MASK)) &&
721 		   kskb->encapsulation) {
722 		return TC_ACT_SHOT;
723 	}
724 
725 	return TC_ACT_OK;
726 }
727 
decap_ipv4(struct __sk_buff * skb)728 static int decap_ipv4(struct __sk_buff *skb)
729 {
730 	struct iphdr iph_outer;
731 
732 	if (!bpf_core_enum_value_exists(enum bpf_adj_room_flags,
733 					BPF_F_ADJ_ROOM_DECAP_IPXIP4))
734 		return TC_ACT_SHOT;
735 
736 	if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_outer,
737 			       sizeof(iph_outer)) < 0)
738 		return TC_ACT_OK;
739 
740 	if (iph_outer.ihl != 5)
741 		return TC_ACT_OK;
742 
743 	return decap_internal(skb, ETH_HLEN, sizeof(iph_outer),
744 			      iph_outer.protocol,
745 			      BPF_F_ADJ_ROOM_DECAP_IPXIP4);
746 }
747 
decap_ipv6(struct __sk_buff * skb)748 static int decap_ipv6(struct __sk_buff *skb)
749 {
750 	struct ipv6hdr iph_outer;
751 
752 	if (!bpf_core_enum_value_exists(enum bpf_adj_room_flags,
753 					BPF_F_ADJ_ROOM_DECAP_IPXIP6))
754 		return TC_ACT_SHOT;
755 
756 	if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_outer,
757 			       sizeof(iph_outer)) < 0)
758 		return TC_ACT_OK;
759 
760 	return decap_internal(skb, ETH_HLEN, sizeof(iph_outer),
761 			      iph_outer.nexthdr,
762 			      BPF_F_ADJ_ROOM_DECAP_IPXIP6);
763 }
764 
765 SEC("tc")
decap_f(struct __sk_buff * skb)766 int decap_f(struct __sk_buff *skb)
767 {
768 	switch (skb->protocol) {
769 	case __bpf_constant_htons(ETH_P_IP):
770 		return decap_ipv4(skb);
771 	case __bpf_constant_htons(ETH_P_IPV6):
772 		return decap_ipv6(skb);
773 	default:
774 		/* does not match, ignore */
775 		return TC_ACT_OK;
776 	}
777 }
778 
779 char __license[] SEC("license") = "GPL";
780