]>
git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - samples/bpf/tc_l2_redirect_kern.c
1 /* Copyright (c) 2016 Facebook
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.
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>
18 #include "bpf_helpers.h"
20 #define _htonl __builtin_bswap32
22 #define PIN_GLOBAL_NS 2
33 /* copy of 'struct ethhdr' without __packed */
35 unsigned char h_dest
[ETH_ALEN
];
36 unsigned char h_source
[ETH_ALEN
];
37 unsigned short h_proto
;
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
,
48 static __always_inline
bool is_vip_addr(__be16 eth_proto
, __be32 daddr
)
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));
58 SEC("l2_to_iptun_ingress_forward")
59 int _l2_to_iptun_ingress_forward(struct __sk_buff
*skb
)
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
;
69 if (data
+ sizeof(*eth
) > data_end
)
72 ifindex
= bpf_map_lookup_elem(&tun_iface
, &key
);
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
);
80 if (data
+ sizeof(*eth
) + sizeof(*iph
) > data_end
)
83 if (iph
->protocol
!= IPPROTO_IPIP
)
86 bpf_trace_printk(fmt4
, sizeof(fmt4
), *ifindex
,
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
);
93 if (data
+ sizeof(*eth
) + sizeof(*ip6h
) > data_end
)
96 if (ip6h
->nexthdr
!= IPPROTO_IPIP
&&
97 ip6h
->nexthdr
!= IPPROTO_IPV6
)
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
);
109 SEC("l2_to_iptun_ingress_redirect")
110 int _l2_to_iptun_ingress_redirect(struct __sk_buff
*skb
)
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
;
120 if (data
+ sizeof(*eth
) > data_end
)
123 ifindex
= bpf_map_lookup_elem(&tun_iface
, &key
);
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
;
132 if (data
+ sizeof(*eth
) + sizeof(*iph
) > data_end
)
135 if (!is_vip_addr(eth
->h_proto
, daddr
))
138 bpf_trace_printk(fmt4
, sizeof(fmt4
), _htonl(daddr
), *ifindex
);
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);
150 SEC("l2_to_ip6tun_ingress_redirect")
151 int _l2_to_ip6tun_ingress_redirect(struct __sk_buff
*skb
)
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
;
159 if (data
+ sizeof(*eth
) > data_end
)
162 ifindex
= bpf_map_lookup_elem(&tun_iface
, &key
);
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
);
170 if (data
+ sizeof(*eth
) + sizeof(*iph
) > data_end
)
173 if (!is_vip_addr(eth
->h_proto
, iph
->daddr
))
176 bpf_trace_printk(fmt4
, sizeof(fmt4
), _htonl(iph
->daddr
),
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
);
182 if (data
+ sizeof(*eth
) + sizeof(*ip6h
) > data_end
)
185 if (!is_vip_addr(eth
->h_proto
, ip6h
->daddr
.s6_addr32
[0]))
188 bpf_trace_printk(fmt6
, sizeof(fmt6
),
189 _htonl(ip6h
->daddr
.s6_addr32
[0]), *ifindex
);
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);
205 SEC("drop_non_tun_vip")
206 int _drop_non_tun_vip(struct __sk_buff
*skb
)
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
;
213 if (data
+ sizeof(*eth
) > data_end
)
216 if (eth
->h_proto
== htons(ETH_P_IP
)) {
217 struct iphdr
*iph
= data
+ sizeof(*eth
);
219 if (data
+ sizeof(*eth
) + sizeof(*iph
) > data_end
)
222 if (is_vip_addr(eth
->h_proto
, iph
->daddr
))
224 } else if (eth
->h_proto
== htons(ETH_P_IPV6
)) {
225 struct ipv6hdr
*ip6h
= data
+ sizeof(*eth
);
227 if (data
+ sizeof(*eth
) + sizeof(*ip6h
) > data_end
)
230 if (is_vip_addr(eth
->h_proto
, ip6h
->daddr
.s6_addr32
[0]))
237 char _license
[] SEC("license") = "GPL";