Home | History | Annotate | Download | only in vlan_learning
      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