1 // Copyright (c) PLUMgrid, Inc.
2 // Licensed under the Apache License, Version 2.0 (the "License")
3 #include <bcc/proto.h>
4
5 BPF_HASH(vni2if, u32, int, 1024);
6
7 struct vni_key {
8 u64 mac;
9 int ifindex;
10 int pad;
11 };
12 struct host {
13 u32 tunnel_id;
14 u32 remote_ipv4;
15 u64 rx_pkts;
16 u64 tx_pkts;
17 };
18 BPF_HASH(mac2host, struct vni_key, struct host);
19
20 struct config {
21 int tunnel_ifindex;
22 };
23 BPF_HASH(conf, int, struct config, 1);
24
25 // Handle packets from the encap device, demux into the dest tenant
handle_ingress(struct __sk_buff * skb)26 int handle_ingress(struct __sk_buff *skb) {
27 u8 *cursor = 0;
28
29 struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
30
31 struct bpf_tunnel_key tkey = {};
32 bpf_skb_get_tunnel_key(skb, &tkey,
33 offsetof(struct bpf_tunnel_key, remote_ipv6[1]), 0);
34
35 int *ifindex = vni2if.lookup(&tkey.tunnel_id);
36 if (ifindex) {
37 //bpf_trace_printk("ingress tunnel_id=%d ifindex=%d\n", tkey.tunnel_id, *ifindex);
38 struct vni_key vk = {ethernet->src, *ifindex, 0};
39 struct host *src_host = mac2host.lookup_or_init(&vk,
40 &(struct host){tkey.tunnel_id, tkey.remote_ipv4, 0, 0});
41 lock_xadd(&src_host->rx_pkts, 1);
42 bpf_clone_redirect(skb, *ifindex, 1/*ingress*/);
43 } else {
44 bpf_trace_printk("ingress invalid tunnel_id=%d\n", tkey.tunnel_id);
45 }
46
47 return 1;
48 }
49
50 // Handle packets from the tenant, mux into the encap device
handle_egress(struct __sk_buff * skb)51 int handle_egress(struct __sk_buff *skb) {
52 u8 *cursor = 0;
53
54 int one = 1;
55 struct config *cfg = conf.lookup(&one);
56 if (!cfg) return 1;
57
58 struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
59
60 struct vni_key vk = {ethernet->dst, skb->ifindex, 0};
61 struct host *dst_host = mac2host.lookup(&vk);
62 struct bpf_tunnel_key tkey = {};
63 if (dst_host) {
64 u32 zero = 0;
65 tkey.tunnel_id = dst_host->tunnel_id;
66 tkey.remote_ipv4 = dst_host->remote_ipv4;
67 bpf_skb_set_tunnel_key(skb, &tkey,
68 offsetof(struct bpf_tunnel_key, remote_ipv6[1]), 0);
69 lock_xadd(&dst_host->tx_pkts, 1);
70 } else {
71 struct bpf_tunnel_key tkey = {};
72 vk.mac = 0xFFFFFFFFFFFFull;
73 dst_host = mac2host.lookup(&vk);
74 if (!dst_host)
75 return 1;
76 tkey.tunnel_id = dst_host->tunnel_id;
77 tkey.remote_ipv4 = dst_host->remote_ipv4;
78 bpf_skb_set_tunnel_key(skb, &tkey,
79 offsetof(struct bpf_tunnel_key, remote_ipv6[1]), 0);
80 }
81 bpf_clone_redirect(skb, cfg->tunnel_ifindex, 0/*egress*/);
82 return 1;
83 }
84