1 // Copyright (c) PLUMgrid, Inc.
2 // Licensed under the Apache License, Version 2.0 (the "License")
3
4 #include <bcc/proto.h>
5
6 struct ifindex_leaf_t {
7 int out_ifindex;
8 int vlan_tci; // populated by phys2virt and used by virt2phys
9 int vlan_proto; // populated by phys2virt and used by virt2phys
10 u64 tx_pkts;
11 u64 tx_bytes;
12 };
13
14 // redirect based on mac -> out_ifindex (auto-learning)
15 BPF_HASH(egress, int, struct ifindex_leaf_t, 4096);
16
17 // redirect based on mac -> out_ifindex (config-driven)
18 BPF_HASH(ingress, u64, struct ifindex_leaf_t, 4096);
19
handle_phys2virt(struct __sk_buff * skb)20 int handle_phys2virt(struct __sk_buff *skb) {
21 // only handle vlan packets
22 if (!skb->vlan_present)
23 return 1;
24 u8 *cursor = 0;
25 ethernet: {
26 struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
27 u64 src_mac = ethernet->src;
28 struct ifindex_leaf_t *leaf = ingress.lookup(&src_mac);
29 if (leaf) {
30 lock_xadd(&leaf->tx_pkts, 1);
31 lock_xadd(&leaf->tx_bytes, skb->len);
32 // auto-program reverse direction table
33 int out_ifindex = leaf->out_ifindex;
34 struct ifindex_leaf_t zleaf = {0};
35 struct ifindex_leaf_t *out_leaf = egress.lookup_or_init(&out_ifindex, &zleaf);
36 // to capture potential configuration changes
37 out_leaf->out_ifindex = skb->ifindex;
38 out_leaf->vlan_tci = skb->vlan_tci;
39 out_leaf->vlan_proto = skb->vlan_proto;
40 // pop the vlan header and send to the destination
41 bpf_skb_vlan_pop(skb);
42 bpf_clone_redirect(skb, leaf->out_ifindex, 0);
43 }
44 }
45 return 1;
46 }
47
handle_virt2phys(struct __sk_buff * skb)48 int handle_virt2phys(struct __sk_buff *skb) {
49 u8 *cursor = 0;
50 ethernet: {
51 struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
52 int src_ifindex = skb->ifindex;
53 struct ifindex_leaf_t *leaf = egress.lookup(&src_ifindex);
54 if (leaf) {
55 lock_xadd(&leaf->tx_pkts, 1);
56 lock_xadd(&leaf->tx_bytes, skb->len);
57 bpf_skb_vlan_push(skb, leaf->vlan_proto, leaf->vlan_tci);
58 bpf_clone_redirect(skb, leaf->out_ifindex, 0);
59 }
60 }
61 return 1;
62 }
63