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 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 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