xref: /linux/tools/testing/selftests/drivers/net/hw/nk_forward.bpf.c (revision 91a4855d6c03e770e42f17c798a36a3c46e63de2)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bpf.h>
3 #include <linux/pkt_cls.h>
4 #include <linux/if_ether.h>
5 #include <linux/ipv6.h>
6 #include <linux/in6.h>
7 #include <bpf/bpf_endian.h>
8 #include <bpf/bpf_helpers.h>
9 
10 #define TC_ACT_OK 0
11 #define ETH_P_IPV6 0x86DD
12 
13 #define ctx_ptr(field)		((void *)(long)(field))
14 
15 #define v6_p64_equal(a, b)	(a.s6_addr32[0] == b.s6_addr32[0] && \
16 				 a.s6_addr32[1] == b.s6_addr32[1])
17 
18 volatile __u32 netkit_ifindex;
19 volatile __u8 ipv6_prefix[16];
20 
21 SEC("tc/ingress")
22 int tc_redirect_peer(struct __sk_buff *skb)
23 {
24 	void *data_end = ctx_ptr(skb->data_end);
25 	void *data = ctx_ptr(skb->data);
26 	struct in6_addr *peer_addr;
27 	struct ipv6hdr *ip6h;
28 	struct ethhdr *eth;
29 
30 	peer_addr = (struct in6_addr *)ipv6_prefix;
31 
32 	if (skb->protocol != bpf_htons(ETH_P_IPV6))
33 		return TC_ACT_OK;
34 
35 	eth = data;
36 	if ((void *)(eth + 1) > data_end)
37 		return TC_ACT_OK;
38 
39 	ip6h = data + sizeof(struct ethhdr);
40 	if ((void *)(ip6h + 1) > data_end)
41 		return TC_ACT_OK;
42 
43 	if (!v6_p64_equal(ip6h->daddr, (*peer_addr)))
44 		return TC_ACT_OK;
45 
46 	return bpf_redirect_peer(netkit_ifindex, 0);
47 }
48 
49 char __license[] SEC("license") = "GPL";
50