Merge tag 'acpi-5.15-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-2.6-microblaze.git] / samples / bpf / tc_l2_redirect_kern.c
1 /* Copyright (c) 2016 Facebook
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of version 2 of the GNU General Public
5  * License as published by the Free Software Foundation.
6  */
7 #define KBUILD_MODNAME "foo"
8 #include <uapi/linux/bpf.h>
9 #include <uapi/linux/if_ether.h>
10 #include <uapi/linux/if_packet.h>
11 #include <uapi/linux/ip.h>
12 #include <uapi/linux/ipv6.h>
13 #include <uapi/linux/in.h>
14 #include <uapi/linux/tcp.h>
15 #include <uapi/linux/filter.h>
16 #include <uapi/linux/pkt_cls.h>
17 #include <net/ipv6.h>
18 #include <bpf/bpf_helpers.h>
19
20 #define _htonl __builtin_bswap32
21
22 #define PIN_GLOBAL_NS           2
23 struct bpf_elf_map {
24         __u32 type;
25         __u32 size_key;
26         __u32 size_value;
27         __u32 max_elem;
28         __u32 flags;
29         __u32 id;
30         __u32 pinning;
31 };
32
33 /* copy of 'struct ethhdr' without __packed */
34 struct eth_hdr {
35         unsigned char   h_dest[ETH_ALEN];
36         unsigned char   h_source[ETH_ALEN];
37         unsigned short  h_proto;
38 };
39
40 struct bpf_elf_map SEC("maps") tun_iface = {
41         .type = BPF_MAP_TYPE_ARRAY,
42         .size_key = sizeof(int),
43         .size_value = sizeof(int),
44         .pinning = PIN_GLOBAL_NS,
45         .max_elem = 1,
46 };
47
48 static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr)
49 {
50         if (eth_proto == htons(ETH_P_IP))
51                 return (_htonl(0xffffff00) & daddr) == _htonl(0x0a0a0100);
52         else if (eth_proto == htons(ETH_P_IPV6))
53                 return (daddr == _htonl(0x2401face));
54
55         return false;
56 }
57
58 SEC("l2_to_iptun_ingress_forward")
59 int _l2_to_iptun_ingress_forward(struct __sk_buff *skb)
60 {
61         struct bpf_tunnel_key tkey = {};
62         void *data = (void *)(long)skb->data;
63         struct eth_hdr *eth = data;
64         void *data_end = (void *)(long)skb->data_end;
65         int key = 0, *ifindex;
66
67         int ret;
68
69         if (data + sizeof(*eth) > data_end)
70                 return TC_ACT_OK;
71
72         ifindex = bpf_map_lookup_elem(&tun_iface, &key);
73         if (!ifindex)
74                 return TC_ACT_OK;
75
76         if (eth->h_proto == htons(ETH_P_IP)) {
77                 char fmt4[] = "ingress forward to ifindex:%d daddr4:%x\n";
78                 struct iphdr *iph = data + sizeof(*eth);
79
80                 if (data + sizeof(*eth) + sizeof(*iph) > data_end)
81                         return TC_ACT_OK;
82
83                 if (iph->protocol != IPPROTO_IPIP)
84                         return TC_ACT_OK;
85
86                 bpf_trace_printk(fmt4, sizeof(fmt4), *ifindex,
87                                  _htonl(iph->daddr));
88                 return bpf_redirect(*ifindex, BPF_F_INGRESS);
89         } else if (eth->h_proto == htons(ETH_P_IPV6)) {
90                 char fmt6[] = "ingress forward to ifindex:%d daddr6:%x::%x\n";
91                 struct ipv6hdr *ip6h = data + sizeof(*eth);
92
93                 if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
94                         return TC_ACT_OK;
95
96                 if (ip6h->nexthdr != IPPROTO_IPIP &&
97                     ip6h->nexthdr != IPPROTO_IPV6)
98                         return TC_ACT_OK;
99
100                 bpf_trace_printk(fmt6, sizeof(fmt6), *ifindex,
101                                  _htonl(ip6h->daddr.s6_addr32[0]),
102                                  _htonl(ip6h->daddr.s6_addr32[3]));
103                 return bpf_redirect(*ifindex, BPF_F_INGRESS);
104         }
105
106         return TC_ACT_OK;
107 }
108
109 SEC("l2_to_iptun_ingress_redirect")
110 int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb)
111 {
112         struct bpf_tunnel_key tkey = {};
113         void *data = (void *)(long)skb->data;
114         struct eth_hdr *eth = data;
115         void *data_end = (void *)(long)skb->data_end;
116         int key = 0, *ifindex;
117
118         int ret;
119
120         if (data + sizeof(*eth) > data_end)
121                 return TC_ACT_OK;
122
123         ifindex = bpf_map_lookup_elem(&tun_iface, &key);
124         if (!ifindex)
125                 return TC_ACT_OK;
126
127         if (eth->h_proto == htons(ETH_P_IP)) {
128                 char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
129                 struct iphdr *iph = data + sizeof(*eth);
130                 __be32 daddr = iph->daddr;
131
132                 if (data + sizeof(*eth) + sizeof(*iph) > data_end)
133                         return TC_ACT_OK;
134
135                 if (!is_vip_addr(eth->h_proto, daddr))
136                         return TC_ACT_OK;
137
138                 bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(daddr), *ifindex);
139         } else {
140                 return TC_ACT_OK;
141         }
142
143         tkey.tunnel_id = 10000;
144         tkey.tunnel_ttl = 64;
145         tkey.remote_ipv4 = 0x0a020166; /* 10.2.1.102 */
146         bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), 0);
147         return bpf_redirect(*ifindex, 0);
148 }
149
150 SEC("l2_to_ip6tun_ingress_redirect")
151 int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb)
152 {
153         struct bpf_tunnel_key tkey = {};
154         void *data = (void *)(long)skb->data;
155         struct eth_hdr *eth = data;
156         void *data_end = (void *)(long)skb->data_end;
157         int key = 0, *ifindex;
158
159         if (data + sizeof(*eth) > data_end)
160                 return TC_ACT_OK;
161
162         ifindex = bpf_map_lookup_elem(&tun_iface, &key);
163         if (!ifindex)
164                 return TC_ACT_OK;
165
166         if (eth->h_proto == htons(ETH_P_IP)) {
167                 char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
168                 struct iphdr *iph = data + sizeof(*eth);
169
170                 if (data + sizeof(*eth) + sizeof(*iph) > data_end)
171                         return TC_ACT_OK;
172
173                 if (!is_vip_addr(eth->h_proto, iph->daddr))
174                         return TC_ACT_OK;
175
176                 bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(iph->daddr),
177                                  *ifindex);
178         } else if (eth->h_proto == htons(ETH_P_IPV6)) {
179                 char fmt6[] = "e/ingress redirect daddr6:%x to ifindex:%d\n";
180                 struct ipv6hdr *ip6h = data + sizeof(*eth);
181
182                 if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
183                         return TC_ACT_OK;
184
185                 if (!is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
186                         return TC_ACT_OK;
187
188                 bpf_trace_printk(fmt6, sizeof(fmt6),
189                                  _htonl(ip6h->daddr.s6_addr32[0]), *ifindex);
190         } else {
191                 return TC_ACT_OK;
192         }
193
194         tkey.tunnel_id = 10000;
195         tkey.tunnel_ttl = 64;
196         /* 2401:db02:0:0:0:0:0:66 */
197         tkey.remote_ipv6[0] = _htonl(0x2401db02);
198         tkey.remote_ipv6[1] = 0;
199         tkey.remote_ipv6[2] = 0;
200         tkey.remote_ipv6[3] = _htonl(0x00000066);
201         bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), BPF_F_TUNINFO_IPV6);
202         return bpf_redirect(*ifindex, 0);
203 }
204
205 SEC("drop_non_tun_vip")
206 int _drop_non_tun_vip(struct __sk_buff *skb)
207 {
208         struct bpf_tunnel_key tkey = {};
209         void *data = (void *)(long)skb->data;
210         struct eth_hdr *eth = data;
211         void *data_end = (void *)(long)skb->data_end;
212
213         if (data + sizeof(*eth) > data_end)
214                 return TC_ACT_OK;
215
216         if (eth->h_proto == htons(ETH_P_IP)) {
217                 struct iphdr *iph = data + sizeof(*eth);
218
219                 if (data + sizeof(*eth) + sizeof(*iph) > data_end)
220                         return TC_ACT_OK;
221
222                 if (is_vip_addr(eth->h_proto, iph->daddr))
223                         return TC_ACT_SHOT;
224         } else if (eth->h_proto == htons(ETH_P_IPV6)) {
225                 struct ipv6hdr *ip6h = data + sizeof(*eth);
226
227                 if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
228                         return TC_ACT_OK;
229
230                 if (is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
231                         return TC_ACT_SHOT;
232         }
233
234         return TC_ACT_OK;
235 }
236
237 char _license[] SEC("license") = "GPL";