190e02896SMartin KaFai Lau /* Copyright (c) 2016 Facebook
290e02896SMartin KaFai Lau  *
390e02896SMartin KaFai Lau  * This program is free software; you can redistribute it and/or
490e02896SMartin KaFai Lau  * modify it under the terms of version 2 of the GNU General Public
590e02896SMartin KaFai Lau  * License as published by the Free Software Foundation.
690e02896SMartin KaFai Lau  */
7cdb749ceSJesper Dangaard Brouer #define KBUILD_MODNAME "foo"
890e02896SMartin KaFai Lau #include <uapi/linux/bpf.h>
990e02896SMartin KaFai Lau #include <uapi/linux/if_ether.h>
1090e02896SMartin KaFai Lau #include <uapi/linux/if_packet.h>
1190e02896SMartin KaFai Lau #include <uapi/linux/ip.h>
1290e02896SMartin KaFai Lau #include <uapi/linux/ipv6.h>
1390e02896SMartin KaFai Lau #include <uapi/linux/in.h>
1490e02896SMartin KaFai Lau #include <uapi/linux/tcp.h>
1590e02896SMartin KaFai Lau #include <uapi/linux/filter.h>
1690e02896SMartin KaFai Lau #include <uapi/linux/pkt_cls.h>
1790e02896SMartin KaFai Lau #include <net/ipv6.h>
187cf245a3SToke Høiland-Jørgensen #include <bpf/bpf_helpers.h>
1990e02896SMartin KaFai Lau 
2090e02896SMartin KaFai Lau #define _htonl __builtin_bswap32
2190e02896SMartin KaFai Lau 
2290e02896SMartin KaFai Lau #define PIN_GLOBAL_NS		2
2390e02896SMartin KaFai Lau struct bpf_elf_map {
2490e02896SMartin KaFai Lau 	__u32 type;
2590e02896SMartin KaFai Lau 	__u32 size_key;
2690e02896SMartin KaFai Lau 	__u32 size_value;
2790e02896SMartin KaFai Lau 	__u32 max_elem;
2890e02896SMartin KaFai Lau 	__u32 flags;
2990e02896SMartin KaFai Lau 	__u32 id;
3090e02896SMartin KaFai Lau 	__u32 pinning;
3190e02896SMartin KaFai Lau };
3290e02896SMartin KaFai Lau 
3390e02896SMartin KaFai Lau /* copy of 'struct ethhdr' without __packed */
3490e02896SMartin KaFai Lau struct eth_hdr {
3590e02896SMartin KaFai Lau 	unsigned char   h_dest[ETH_ALEN];
3690e02896SMartin KaFai Lau 	unsigned char   h_source[ETH_ALEN];
3790e02896SMartin KaFai Lau 	unsigned short  h_proto;
3890e02896SMartin KaFai Lau };
3990e02896SMartin KaFai Lau 
4090e02896SMartin KaFai Lau struct bpf_elf_map SEC("maps") tun_iface = {
4190e02896SMartin KaFai Lau 	.type = BPF_MAP_TYPE_ARRAY,
4290e02896SMartin KaFai Lau 	.size_key = sizeof(int),
4390e02896SMartin KaFai Lau 	.size_value = sizeof(int),
4490e02896SMartin KaFai Lau 	.pinning = PIN_GLOBAL_NS,
4590e02896SMartin KaFai Lau 	.max_elem = 1,
4690e02896SMartin KaFai Lau };
4790e02896SMartin KaFai Lau 
is_vip_addr(__be16 eth_proto,__be32 daddr)4890e02896SMartin KaFai Lau static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr)
4990e02896SMartin KaFai Lau {
5090e02896SMartin KaFai Lau 	if (eth_proto == htons(ETH_P_IP))
5190e02896SMartin KaFai Lau 		return (_htonl(0xffffff00) & daddr) == _htonl(0x0a0a0100);
5290e02896SMartin KaFai Lau 	else if (eth_proto == htons(ETH_P_IPV6))
5390e02896SMartin KaFai Lau 		return (daddr == _htonl(0x2401face));
5490e02896SMartin KaFai Lau 
5590e02896SMartin KaFai Lau 	return false;
5690e02896SMartin KaFai Lau }
5790e02896SMartin KaFai Lau 
5890e02896SMartin KaFai Lau SEC("l2_to_iptun_ingress_forward")
_l2_to_iptun_ingress_forward(struct __sk_buff * skb)5990e02896SMartin KaFai Lau int _l2_to_iptun_ingress_forward(struct __sk_buff *skb)
6090e02896SMartin KaFai Lau {
6190e02896SMartin KaFai Lau 	struct bpf_tunnel_key tkey = {};
6290e02896SMartin KaFai Lau 	void *data = (void *)(long)skb->data;
6390e02896SMartin KaFai Lau 	struct eth_hdr *eth = data;
6490e02896SMartin KaFai Lau 	void *data_end = (void *)(long)skb->data_end;
6590e02896SMartin KaFai Lau 	int key = 0, *ifindex;
6690e02896SMartin KaFai Lau 
6790e02896SMartin KaFai Lau 	int ret;
6890e02896SMartin KaFai Lau 
6990e02896SMartin KaFai Lau 	if (data + sizeof(*eth) > data_end)
7090e02896SMartin KaFai Lau 		return TC_ACT_OK;
7190e02896SMartin KaFai Lau 
7290e02896SMartin KaFai Lau 	ifindex = bpf_map_lookup_elem(&tun_iface, &key);
7390e02896SMartin KaFai Lau 	if (!ifindex)
7490e02896SMartin KaFai Lau 		return TC_ACT_OK;
7590e02896SMartin KaFai Lau 
7690e02896SMartin KaFai Lau 	if (eth->h_proto == htons(ETH_P_IP)) {
7790e02896SMartin KaFai Lau 		char fmt4[] = "ingress forward to ifindex:%d daddr4:%x\n";
7890e02896SMartin KaFai Lau 		struct iphdr *iph = data + sizeof(*eth);
7990e02896SMartin KaFai Lau 
8090e02896SMartin KaFai Lau 		if (data + sizeof(*eth) + sizeof(*iph) > data_end)
8190e02896SMartin KaFai Lau 			return TC_ACT_OK;
8290e02896SMartin KaFai Lau 
8390e02896SMartin KaFai Lau 		if (iph->protocol != IPPROTO_IPIP)
8490e02896SMartin KaFai Lau 			return TC_ACT_OK;
8590e02896SMartin KaFai Lau 
8690e02896SMartin KaFai Lau 		bpf_trace_printk(fmt4, sizeof(fmt4), *ifindex,
8790e02896SMartin KaFai Lau 				 _htonl(iph->daddr));
8890e02896SMartin KaFai Lau 		return bpf_redirect(*ifindex, BPF_F_INGRESS);
8990e02896SMartin KaFai Lau 	} else if (eth->h_proto == htons(ETH_P_IPV6)) {
9090e02896SMartin KaFai Lau 		char fmt6[] = "ingress forward to ifindex:%d daddr6:%x::%x\n";
9190e02896SMartin KaFai Lau 		struct ipv6hdr *ip6h = data + sizeof(*eth);
9290e02896SMartin KaFai Lau 
9390e02896SMartin KaFai Lau 		if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
9490e02896SMartin KaFai Lau 			return TC_ACT_OK;
9590e02896SMartin KaFai Lau 
9690e02896SMartin KaFai Lau 		if (ip6h->nexthdr != IPPROTO_IPIP &&
9790e02896SMartin KaFai Lau 		    ip6h->nexthdr != IPPROTO_IPV6)
9890e02896SMartin KaFai Lau 			return TC_ACT_OK;
9990e02896SMartin KaFai Lau 
10090e02896SMartin KaFai Lau 		bpf_trace_printk(fmt6, sizeof(fmt6), *ifindex,
10190e02896SMartin KaFai Lau 				 _htonl(ip6h->daddr.s6_addr32[0]),
10290e02896SMartin KaFai Lau 				 _htonl(ip6h->daddr.s6_addr32[3]));
10390e02896SMartin KaFai Lau 		return bpf_redirect(*ifindex, BPF_F_INGRESS);
10490e02896SMartin KaFai Lau 	}
10590e02896SMartin KaFai Lau 
10690e02896SMartin KaFai Lau 	return TC_ACT_OK;
10790e02896SMartin KaFai Lau }
10890e02896SMartin KaFai Lau 
10990e02896SMartin KaFai Lau SEC("l2_to_iptun_ingress_redirect")
_l2_to_iptun_ingress_redirect(struct __sk_buff * skb)11090e02896SMartin KaFai Lau int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb)
11190e02896SMartin KaFai Lau {
11290e02896SMartin KaFai Lau 	struct bpf_tunnel_key tkey = {};
11390e02896SMartin KaFai Lau 	void *data = (void *)(long)skb->data;
11490e02896SMartin KaFai Lau 	struct eth_hdr *eth = data;
11590e02896SMartin KaFai Lau 	void *data_end = (void *)(long)skb->data_end;
11690e02896SMartin KaFai Lau 	int key = 0, *ifindex;
11790e02896SMartin KaFai Lau 
11890e02896SMartin KaFai Lau 	int ret;
11990e02896SMartin KaFai Lau 
12090e02896SMartin KaFai Lau 	if (data + sizeof(*eth) > data_end)
12190e02896SMartin KaFai Lau 		return TC_ACT_OK;
12290e02896SMartin KaFai Lau 
12390e02896SMartin KaFai Lau 	ifindex = bpf_map_lookup_elem(&tun_iface, &key);
12490e02896SMartin KaFai Lau 	if (!ifindex)
12590e02896SMartin KaFai Lau 		return TC_ACT_OK;
12690e02896SMartin KaFai Lau 
12790e02896SMartin KaFai Lau 	if (eth->h_proto == htons(ETH_P_IP)) {
12890e02896SMartin KaFai Lau 		char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
12990e02896SMartin KaFai Lau 		struct iphdr *iph = data + sizeof(*eth);
13090e02896SMartin KaFai Lau 		__be32 daddr = iph->daddr;
13190e02896SMartin KaFai Lau 
13290e02896SMartin KaFai Lau 		if (data + sizeof(*eth) + sizeof(*iph) > data_end)
13390e02896SMartin KaFai Lau 			return TC_ACT_OK;
13490e02896SMartin KaFai Lau 
13590e02896SMartin KaFai Lau 		if (!is_vip_addr(eth->h_proto, daddr))
13690e02896SMartin KaFai Lau 			return TC_ACT_OK;
13790e02896SMartin KaFai Lau 
13890e02896SMartin KaFai Lau 		bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(daddr), *ifindex);
13990e02896SMartin KaFai Lau 	} else {
14090e02896SMartin KaFai Lau 		return TC_ACT_OK;
14190e02896SMartin KaFai Lau 	}
14290e02896SMartin KaFai Lau 
14390e02896SMartin KaFai Lau 	tkey.tunnel_id = 10000;
14490e02896SMartin KaFai Lau 	tkey.tunnel_ttl = 64;
14590e02896SMartin KaFai Lau 	tkey.remote_ipv4 = 0x0a020166; /* 10.2.1.102 */
14690e02896SMartin KaFai Lau 	bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), 0);
14790e02896SMartin KaFai Lau 	return bpf_redirect(*ifindex, 0);
14890e02896SMartin KaFai Lau }
14990e02896SMartin KaFai Lau 
15090e02896SMartin KaFai Lau SEC("l2_to_ip6tun_ingress_redirect")
_l2_to_ip6tun_ingress_redirect(struct __sk_buff * skb)15190e02896SMartin KaFai Lau int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb)
15290e02896SMartin KaFai Lau {
15390e02896SMartin KaFai Lau 	struct bpf_tunnel_key tkey = {};
15490e02896SMartin KaFai Lau 	void *data = (void *)(long)skb->data;
15590e02896SMartin KaFai Lau 	struct eth_hdr *eth = data;
15690e02896SMartin KaFai Lau 	void *data_end = (void *)(long)skb->data_end;
15790e02896SMartin KaFai Lau 	int key = 0, *ifindex;
15890e02896SMartin KaFai Lau 
15990e02896SMartin KaFai Lau 	if (data + sizeof(*eth) > data_end)
16090e02896SMartin KaFai Lau 		return TC_ACT_OK;
16190e02896SMartin KaFai Lau 
16290e02896SMartin KaFai Lau 	ifindex = bpf_map_lookup_elem(&tun_iface, &key);
16390e02896SMartin KaFai Lau 	if (!ifindex)
16490e02896SMartin KaFai Lau 		return TC_ACT_OK;
16590e02896SMartin KaFai Lau 
16690e02896SMartin KaFai Lau 	if (eth->h_proto == htons(ETH_P_IP)) {
16790e02896SMartin KaFai Lau 		char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
16890e02896SMartin KaFai Lau 		struct iphdr *iph = data + sizeof(*eth);
16990e02896SMartin KaFai Lau 
17090e02896SMartin KaFai Lau 		if (data + sizeof(*eth) + sizeof(*iph) > data_end)
17190e02896SMartin KaFai Lau 			return TC_ACT_OK;
17290e02896SMartin KaFai Lau 
17390e02896SMartin KaFai Lau 		if (!is_vip_addr(eth->h_proto, iph->daddr))
17490e02896SMartin KaFai Lau 			return TC_ACT_OK;
17590e02896SMartin KaFai Lau 
17690e02896SMartin KaFai Lau 		bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(iph->daddr),
17790e02896SMartin KaFai Lau 				 *ifindex);
17890e02896SMartin KaFai Lau 	} else if (eth->h_proto == htons(ETH_P_IPV6)) {
17990e02896SMartin KaFai Lau 		char fmt6[] = "e/ingress redirect daddr6:%x to ifindex:%d\n";
18090e02896SMartin KaFai Lau 		struct ipv6hdr *ip6h = data + sizeof(*eth);
18190e02896SMartin KaFai Lau 
18290e02896SMartin KaFai Lau 		if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
18390e02896SMartin KaFai Lau 			return TC_ACT_OK;
18490e02896SMartin KaFai Lau 
18590e02896SMartin KaFai Lau 		if (!is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
18690e02896SMartin KaFai Lau 			return TC_ACT_OK;
18790e02896SMartin KaFai Lau 
18890e02896SMartin KaFai Lau 		bpf_trace_printk(fmt6, sizeof(fmt6),
18990e02896SMartin KaFai Lau 				 _htonl(ip6h->daddr.s6_addr32[0]), *ifindex);
19090e02896SMartin KaFai Lau 	} else {
19190e02896SMartin KaFai Lau 		return TC_ACT_OK;
19290e02896SMartin KaFai Lau 	}
19390e02896SMartin KaFai Lau 
19490e02896SMartin KaFai Lau 	tkey.tunnel_id = 10000;
19590e02896SMartin KaFai Lau 	tkey.tunnel_ttl = 64;
19690e02896SMartin KaFai Lau 	/* 2401:db02:0:0:0:0:0:66 */
19790e02896SMartin KaFai Lau 	tkey.remote_ipv6[0] = _htonl(0x2401db02);
19890e02896SMartin KaFai Lau 	tkey.remote_ipv6[1] = 0;
19990e02896SMartin KaFai Lau 	tkey.remote_ipv6[2] = 0;
20090e02896SMartin KaFai Lau 	tkey.remote_ipv6[3] = _htonl(0x00000066);
20190e02896SMartin KaFai Lau 	bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), BPF_F_TUNINFO_IPV6);
20290e02896SMartin KaFai Lau 	return bpf_redirect(*ifindex, 0);
20390e02896SMartin KaFai Lau }
20490e02896SMartin KaFai Lau 
20590e02896SMartin KaFai Lau SEC("drop_non_tun_vip")
_drop_non_tun_vip(struct __sk_buff * skb)20690e02896SMartin KaFai Lau int _drop_non_tun_vip(struct __sk_buff *skb)
20790e02896SMartin KaFai Lau {
20890e02896SMartin KaFai Lau 	struct bpf_tunnel_key tkey = {};
20990e02896SMartin KaFai Lau 	void *data = (void *)(long)skb->data;
21090e02896SMartin KaFai Lau 	struct eth_hdr *eth = data;
21190e02896SMartin KaFai Lau 	void *data_end = (void *)(long)skb->data_end;
21290e02896SMartin KaFai Lau 
21390e02896SMartin KaFai Lau 	if (data + sizeof(*eth) > data_end)
21490e02896SMartin KaFai Lau 		return TC_ACT_OK;
21590e02896SMartin KaFai Lau 
21690e02896SMartin KaFai Lau 	if (eth->h_proto == htons(ETH_P_IP)) {
21790e02896SMartin KaFai Lau 		struct iphdr *iph = data + sizeof(*eth);
21890e02896SMartin KaFai Lau 
21990e02896SMartin KaFai Lau 		if (data + sizeof(*eth) + sizeof(*iph) > data_end)
22090e02896SMartin KaFai Lau 			return TC_ACT_OK;
22190e02896SMartin KaFai Lau 
22290e02896SMartin KaFai Lau 		if (is_vip_addr(eth->h_proto, iph->daddr))
22390e02896SMartin KaFai Lau 			return TC_ACT_SHOT;
22490e02896SMartin KaFai Lau 	} else if (eth->h_proto == htons(ETH_P_IPV6)) {
22590e02896SMartin KaFai Lau 		struct ipv6hdr *ip6h = data + sizeof(*eth);
22690e02896SMartin KaFai Lau 
22790e02896SMartin KaFai Lau 		if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
22890e02896SMartin KaFai Lau 			return TC_ACT_OK;
22990e02896SMartin KaFai Lau 
23090e02896SMartin KaFai Lau 		if (is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
23190e02896SMartin KaFai Lau 			return TC_ACT_SHOT;
23290e02896SMartin KaFai Lau 	}
23390e02896SMartin KaFai Lau 
23490e02896SMartin KaFai Lau 	return TC_ACT_OK;
23590e02896SMartin KaFai Lau }
23690e02896SMartin KaFai Lau 
23790e02896SMartin KaFai Lau char _license[] SEC("license") = "GPL";
238