2020-10-06 15:53:55 +02:00
|
|
|
#include <linux/bpf.h>
|
|
|
|
#include <linux/in6.h>
|
|
|
|
#include <bpf/bpf_helpers.h>
|
|
|
|
#include <xdp/parsing_helpers.h>
|
|
|
|
#include "encap.h"
|
|
|
|
|
2020-10-07 13:35:38 +02:00
|
|
|
#ifdef IPV6
|
|
|
|
#define OFFSET sizeof(struct ipv6hdr)
|
|
|
|
#define ENCAP_TYPE BPF_F_ADJ_ROOM_ENCAP_L3_IPV6
|
|
|
|
#else
|
|
|
|
#define OFFSET sizeof(struct iphdr)
|
|
|
|
#define ENCAP_TYPE BPF_F_ADJ_ROOM_ENCAP_L3_IPV4
|
|
|
|
#endif
|
|
|
|
|
2022-04-27 13:04:49 +02:00
|
|
|
#ifndef AF_INET
|
2020-10-08 16:02:16 +02:00
|
|
|
#define AF_INET 2
|
2022-04-27 13:04:49 +02:00
|
|
|
#endif
|
2020-10-08 16:02:16 +02:00
|
|
|
|
2020-10-06 15:53:55 +02:00
|
|
|
SEC("classifier") int tc_encap(struct __sk_buff *skb)
|
|
|
|
{
|
2020-10-08 16:02:16 +02:00
|
|
|
struct bpf_fib_lookup fib_params = {};
|
2020-10-06 15:53:55 +02:00
|
|
|
volatile void *data, *data_end;
|
2020-10-07 13:35:38 +02:00
|
|
|
size_t offset = OFFSET;
|
2020-10-06 15:53:55 +02:00
|
|
|
int ret = BPF_DROP;
|
2020-10-08 16:02:16 +02:00
|
|
|
struct ethhdr *eth;
|
|
|
|
struct iphdr *iph;
|
2020-10-06 15:53:55 +02:00
|
|
|
|
2020-10-07 13:35:38 +02:00
|
|
|
if (bpf_skb_adjust_room(skb, offset, BPF_ADJ_ROOM_MAC, ENCAP_TYPE))
|
2020-10-06 15:53:55 +02:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
data = (void *)(long)skb->data;
|
|
|
|
data_end = (void *)(long)skb->data_end;
|
2020-11-25 11:31:06 +01:00
|
|
|
eth = (void *)data;
|
2020-10-06 15:53:55 +02:00
|
|
|
|
2020-10-07 13:35:38 +02:00
|
|
|
#ifdef IPV6
|
|
|
|
encap_ipv6(data, data_end);
|
|
|
|
#else
|
2020-10-06 15:53:55 +02:00
|
|
|
encap_ipv4(data, data_end);
|
2020-10-06 16:06:45 +02:00
|
|
|
|
2020-10-08 16:02:16 +02:00
|
|
|
iph = (void *)(eth +1);
|
|
|
|
if (iph +1 > data_end)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
fib_params.family = AF_INET;
|
|
|
|
fib_params.tos = iph->tos;
|
|
|
|
fib_params.l4_protocol = iph->protocol;
|
|
|
|
fib_params.sport = 0;
|
|
|
|
fib_params.dport = 0;
|
|
|
|
fib_params.tot_len = bpf_ntohs(iph->tot_len);
|
|
|
|
fib_params.ipv4_src = iph->saddr;
|
|
|
|
fib_params.ipv4_dst = iph->daddr;
|
|
|
|
fib_params.ifindex = skb->ingress_ifindex;
|
|
|
|
|
|
|
|
ret = bpf_fib_lookup(skb, &fib_params, sizeof(fib_params), 0);
|
|
|
|
if (ret == BPF_FIB_LKUP_RET_SUCCESS) {
|
|
|
|
__builtin_memcpy(eth->h_dest, fib_params.dmac, ETH_ALEN);
|
|
|
|
__builtin_memcpy(eth->h_source, fib_params.smac, ETH_ALEN);
|
|
|
|
|
|
|
|
return bpf_redirect(fib_params.ifindex, 0);
|
|
|
|
} else if (ret == BPF_FIB_LKUP_RET_NO_NEIGH) {
|
2020-10-21 16:53:33 +02:00
|
|
|
struct bpf_redir_neigh nh_params = {};
|
|
|
|
|
|
|
|
nh_params.nh_family = fib_params.family;
|
|
|
|
__builtin_memcpy(&nh_params.ipv6_nh, &fib_params.ipv6_dst,
|
|
|
|
sizeof(nh_params.ipv6_nh));
|
|
|
|
return bpf_redirect_neigh(fib_params.ifindex, &nh_params,
|
|
|
|
sizeof(nh_params), 0);
|
2020-10-08 16:02:16 +02:00
|
|
|
}
|
|
|
|
|
2020-10-07 13:35:38 +02:00
|
|
|
#endif
|
2020-10-06 17:14:07 +02:00
|
|
|
|
2020-10-06 15:53:55 +02:00
|
|
|
ret = BPF_OK;
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char _license[] SEC("license") = "GPL";
|