]>
git.proxmox.com Git - mirror_ubuntu-artful-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 #include <uapi/linux/bpf.h>
8 #include <uapi/linux/if_ether.h>
9 #include <uapi/linux/if_packet.h>
10 #include <uapi/linux/ip.h>
11 #include <uapi/linux/ipv6.h>
12 #include <uapi/linux/in.h>
13 #include <uapi/linux/tcp.h>
14 #include <uapi/linux/filter.h>
15 #include <uapi/linux/pkt_cls.h>
17 #include "bpf_helpers.h"
19 #define _htonl __builtin_bswap32
21 #define PIN_GLOBAL_NS 2
32 /* copy of 'struct ethhdr' without __packed */
34 unsigned char h_dest
[ETH_ALEN
];
35 unsigned char h_source
[ETH_ALEN
];
36 unsigned short h_proto
;
39 struct bpf_elf_map
SEC("maps") tun_iface
= {
40 .type
= BPF_MAP_TYPE_ARRAY
,
41 .size_key
= sizeof(int),
42 .size_value
= sizeof(int),
43 .pinning
= PIN_GLOBAL_NS
,
47 static __always_inline
bool is_vip_addr(__be16 eth_proto
, __be32 daddr
)
49 if (eth_proto
== htons(ETH_P_IP
))
50 return (_htonl(0xffffff00) & daddr
) == _htonl(0x0a0a0100);
51 else if (eth_proto
== htons(ETH_P_IPV6
))
52 return (daddr
== _htonl(0x2401face));
57 SEC("l2_to_iptun_ingress_forward")
58 int _l2_to_iptun_ingress_forward(struct __sk_buff
*skb
)
60 struct bpf_tunnel_key tkey
= {};
61 void *data
= (void *)(long)skb
->data
;
62 struct eth_hdr
*eth
= data
;
63 void *data_end
= (void *)(long)skb
->data_end
;
64 int key
= 0, *ifindex
;
68 if (data
+ sizeof(*eth
) > data_end
)
71 ifindex
= bpf_map_lookup_elem(&tun_iface
, &key
);
75 if (eth
->h_proto
== htons(ETH_P_IP
)) {
76 char fmt4
[] = "ingress forward to ifindex:%d daddr4:%x\n";
77 struct iphdr
*iph
= data
+ sizeof(*eth
);
79 if (data
+ sizeof(*eth
) + sizeof(*iph
) > data_end
)
82 if (iph
->protocol
!= IPPROTO_IPIP
)
85 bpf_trace_printk(fmt4
, sizeof(fmt4
), *ifindex
,
87 return bpf_redirect(*ifindex
, BPF_F_INGRESS
);
88 } else if (eth
->h_proto
== htons(ETH_P_IPV6
)) {
89 char fmt6
[] = "ingress forward to ifindex:%d daddr6:%x::%x\n";
90 struct ipv6hdr
*ip6h
= data
+ sizeof(*eth
);
92 if (data
+ sizeof(*eth
) + sizeof(*ip6h
) > data_end
)
95 if (ip6h
->nexthdr
!= IPPROTO_IPIP
&&
96 ip6h
->nexthdr
!= IPPROTO_IPV6
)
99 bpf_trace_printk(fmt6
, sizeof(fmt6
), *ifindex
,
100 _htonl(ip6h
->daddr
.s6_addr32
[0]),
101 _htonl(ip6h
->daddr
.s6_addr32
[3]));
102 return bpf_redirect(*ifindex
, BPF_F_INGRESS
);
108 SEC("l2_to_iptun_ingress_redirect")
109 int _l2_to_iptun_ingress_redirect(struct __sk_buff
*skb
)
111 struct bpf_tunnel_key tkey
= {};
112 void *data
= (void *)(long)skb
->data
;
113 struct eth_hdr
*eth
= data
;
114 void *data_end
= (void *)(long)skb
->data_end
;
115 int key
= 0, *ifindex
;
119 if (data
+ sizeof(*eth
) > data_end
)
122 ifindex
= bpf_map_lookup_elem(&tun_iface
, &key
);
126 if (eth
->h_proto
== htons(ETH_P_IP
)) {
127 char fmt4
[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
128 struct iphdr
*iph
= data
+ sizeof(*eth
);
129 __be32 daddr
= iph
->daddr
;
131 if (data
+ sizeof(*eth
) + sizeof(*iph
) > data_end
)
134 if (!is_vip_addr(eth
->h_proto
, daddr
))
137 bpf_trace_printk(fmt4
, sizeof(fmt4
), _htonl(daddr
), *ifindex
);
142 tkey
.tunnel_id
= 10000;
143 tkey
.tunnel_ttl
= 64;
144 tkey
.remote_ipv4
= 0x0a020166; /* 10.2.1.102 */
145 bpf_skb_set_tunnel_key(skb
, &tkey
, sizeof(tkey
), 0);
146 return bpf_redirect(*ifindex
, 0);
149 SEC("l2_to_ip6tun_ingress_redirect")
150 int _l2_to_ip6tun_ingress_redirect(struct __sk_buff
*skb
)
152 struct bpf_tunnel_key tkey
= {};
153 void *data
= (void *)(long)skb
->data
;
154 struct eth_hdr
*eth
= data
;
155 void *data_end
= (void *)(long)skb
->data_end
;
156 int key
= 0, *ifindex
;
158 if (data
+ sizeof(*eth
) > data_end
)
161 ifindex
= bpf_map_lookup_elem(&tun_iface
, &key
);
165 if (eth
->h_proto
== htons(ETH_P_IP
)) {
166 char fmt4
[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
167 struct iphdr
*iph
= data
+ sizeof(*eth
);
169 if (data
+ sizeof(*eth
) + sizeof(*iph
) > data_end
)
172 if (!is_vip_addr(eth
->h_proto
, iph
->daddr
))
175 bpf_trace_printk(fmt4
, sizeof(fmt4
), _htonl(iph
->daddr
),
177 } else if (eth
->h_proto
== htons(ETH_P_IPV6
)) {
178 char fmt6
[] = "e/ingress redirect daddr6:%x to ifindex:%d\n";
179 struct ipv6hdr
*ip6h
= data
+ sizeof(*eth
);
181 if (data
+ sizeof(*eth
) + sizeof(*ip6h
) > data_end
)
184 if (!is_vip_addr(eth
->h_proto
, ip6h
->daddr
.s6_addr32
[0]))
187 bpf_trace_printk(fmt6
, sizeof(fmt6
),
188 _htonl(ip6h
->daddr
.s6_addr32
[0]), *ifindex
);
193 tkey
.tunnel_id
= 10000;
194 tkey
.tunnel_ttl
= 64;
195 /* 2401:db02:0:0:0:0:0:66 */
196 tkey
.remote_ipv6
[0] = _htonl(0x2401db02);
197 tkey
.remote_ipv6
[1] = 0;
198 tkey
.remote_ipv6
[2] = 0;
199 tkey
.remote_ipv6
[3] = _htonl(0x00000066);
200 bpf_skb_set_tunnel_key(skb
, &tkey
, sizeof(tkey
), BPF_F_TUNINFO_IPV6
);
201 return bpf_redirect(*ifindex
, 0);
204 SEC("drop_non_tun_vip")
205 int _drop_non_tun_vip(struct __sk_buff
*skb
)
207 struct bpf_tunnel_key tkey
= {};
208 void *data
= (void *)(long)skb
->data
;
209 struct eth_hdr
*eth
= data
;
210 void *data_end
= (void *)(long)skb
->data_end
;
212 if (data
+ sizeof(*eth
) > data_end
)
215 if (eth
->h_proto
== htons(ETH_P_IP
)) {
216 struct iphdr
*iph
= data
+ sizeof(*eth
);
218 if (data
+ sizeof(*eth
) + sizeof(*iph
) > data_end
)
221 if (is_vip_addr(eth
->h_proto
, iph
->daddr
))
223 } else if (eth
->h_proto
== htons(ETH_P_IPV6
)) {
224 struct ipv6hdr
*ip6h
= data
+ sizeof(*eth
);
226 if (data
+ sizeof(*eth
) + sizeof(*ip6h
) > data_end
)
229 if (is_vip_addr(eth
->h_proto
, ip6h
->daddr
.s6_addr32
[0]))
236 char _license
[] SEC("license") = "GPL";