Home | History | Annotate | Download | only in python
      1 // Copyright (c) PLUMgrid, Inc.
      2 // Licensed under the Apache License, Version 2.0 (the "License")
      3 #include <bcc/proto.h>
      4 
      5 #define _memcpy __builtin_memcpy
      6 
      7 // meta data passed between bpf programs
      8 typedef struct bpf_metadata {
      9     u32 prog_id;
     10     u32 rx_port_id;
     11 } bpf_metadata_t;
     12 
     13 typedef struct bpf_dest {
     14     u32 prog_id;
     15     u32 port_id;
     16 } bpf_dest_t;
     17 
     18 // use u64 to represent eth_addr.
     19 // maintain the structure though to indicate the semantics
     20 typedef struct eth_addr {
     21     u64 addr;
     22 } eth_addr_t;
     23 
     24 // Program table definitions for tail calls
     25 BPF_PROG_ARRAY(jump, 16);
     26 
     27 // physical endpoint manager (pem) tables which connects to boeht bridge 1 and bridge 2
     28 // <port_id, bpf_dest>
     29 BPF_ARRAY(pem_dest, bpf_dest_t, 256);
     30 // <port_id, ifindex>
     31 BPF_ARRAY(pem_port, u32, 256);
     32 // <ifindex, port_id>
     33 BPF_HASH(pem_ifindex, u32, u32, 256);
     34 // <0, tx2vm_pkts>
     35 BPF_ARRAY(pem_stats, u32, 1);
     36 
     37 // bridge 1 (br1) tables
     38 // <port_id, bpf_dest>
     39 BPF_ARRAY(br1_dest, bpf_dest_t, 256);
     40 // <eth_addr, port_id>
     41 BPF_HASH(br1_mac, eth_addr_t, u32, 256);
     42 // <0, rtr_ifindex>
     43 BPF_ARRAY(br1_rtr, u32, 1);
     44 // <mac, ifindex>
     45 BPF_HASH(br1_mac_ifindex, eth_addr_t, u32, 1);
     46 
     47 // bridge 2 (br2) tables
     48 // <port_id, bpf_dest>
     49 BPF_ARRAY(br2_dest, bpf_dest_t, 256);
     50 // <eth_addr, port_id>
     51 BPF_HASH(br2_mac, eth_addr_t, u32, 256);
     52 // <0, rtr_ifindex>
     53 BPF_ARRAY(br2_rtr, u32, 1);
     54 // <mac, ifindex>
     55 BPF_HASH(br2_mac_ifindex, eth_addr_t, u32, 1);
     56 
     57 int pem(struct __sk_buff *skb) {
     58     bpf_metadata_t meta = {};
     59     u32 ifindex;
     60     u32 *tx_port_id_p;
     61     u32 tx_port_id;
     62     u32 rx_port;
     63     u32 *ifindex_p;
     64     bpf_dest_t *dest_p;
     65 
     66     // pem does not look at packet data
     67     if (skb->tc_index == 0) {
     68         skb->tc_index = 1;
     69         skb->cb[0] = skb->cb[1] = 0;
     70         meta.prog_id = meta.rx_port_id = 0;
     71     } else {
     72         meta.prog_id = skb->cb[0];
     73         asm volatile("" ::: "memory");
     74         meta.rx_port_id = skb->cb[1];
     75     }
     76     if (!meta.prog_id) {
     77         /* from external */
     78         ifindex = skb->ingress_ifindex;
     79         tx_port_id_p = pem_ifindex.lookup(&ifindex);
     80         if (tx_port_id_p) {
     81             tx_port_id = *tx_port_id_p;
     82             dest_p = pem_dest.lookup(&tx_port_id);
     83             if (dest_p) {
     84                 skb->cb[0] = dest_p->prog_id;
     85                 skb->cb[1] = dest_p->port_id;
     86                 jump.call(skb, dest_p->prog_id);
     87             }
     88         }
     89     } else {
     90         /* from internal */
     91         rx_port = meta.rx_port_id;
     92         ifindex_p = pem_port.lookup(&rx_port);
     93         if (ifindex_p) {
     94 #if 1
     95             /* accumulate stats, may hurt performance slightly */
     96             u32 index = 0;
     97             u32 *value = pem_stats.lookup(&index);
     98             if (value)
     99                 lock_xadd(value, 1);
    100 #endif
    101             bpf_clone_redirect(skb, *ifindex_p, 0);
    102         }
    103     }
    104 
    105     return 1;
    106 }
    107 
    108 static int br_common(struct __sk_buff *skb, int which_br) {
    109     u8 *cursor = 0;
    110     u16 proto;
    111     u16 arpop;
    112     eth_addr_t dmac;
    113     u8 *mac_p;
    114     u32 dip;
    115     u32 *tx_port_id_p;
    116     u32 tx_port_id;
    117     bpf_dest_t *dest_p;
    118     u32 index, *rtrif_p;
    119 
    120     struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
    121     /* handle ethernet packet header */
    122     {
    123         dmac.addr = ethernet->dst;
    124         /* skb->tc_index may be preserved across router namespace if router simply rewrite packet
    125          * and send it back.
    126          */
    127         if (skb->tc_index == 1) {
    128             /* packet from pem, send to the router, set tc_index to 2 */
    129             skb->tc_index = 2;
    130             if (dmac.addr == 0xffffffffffffULL) {
    131                  index = 0;
    132                  if (which_br == 1)
    133                      rtrif_p = br1_rtr.lookup(&index);
    134                  else
    135                      rtrif_p = br2_rtr.lookup(&index);
    136                  if (rtrif_p)
    137                      bpf_clone_redirect(skb, *rtrif_p, 0);
    138              } else {
    139                  /* the dmac address should match the router's */
    140                  if (which_br == 1)
    141                      rtrif_p = br1_mac_ifindex.lookup(&dmac);
    142                  else
    143                      rtrif_p = br2_mac_ifindex.lookup(&dmac);
    144                  if (rtrif_p)
    145                      bpf_clone_redirect(skb, *rtrif_p, 0);
    146              }
    147              return 1;
    148         }
    149 
    150         /* set the tc_index to 1 so pem knows it is from internal */
    151         skb->tc_index = 1;
    152         switch (ethernet->type) {
    153             case ETH_P_IP: goto ip;
    154             case ETH_P_ARP: goto arp;
    155             case ETH_P_8021Q: goto dot1q;
    156             default: goto EOP;
    157         }
    158     }
    159 
    160     dot1q: {
    161         struct dot1q_t *dot1q = cursor_advance(cursor, sizeof(*dot1q));
    162         switch(dot1q->type) {
    163             case ETH_P_IP: goto ip;
    164             case ETH_P_ARP: goto arp;
    165             default: goto EOP;
    166         }
    167     }
    168 
    169     arp: {
    170         struct arp_t *arp = cursor_advance(cursor, sizeof(*arp));
    171         /* mac learning */
    172         arpop = arp->oper;
    173         if (arpop == 2) {
    174             index = 0;
    175             if (which_br == 1)
    176                 rtrif_p = br1_rtr.lookup(&index);
    177             else
    178                 rtrif_p = br2_rtr.lookup(&index);
    179             if (rtrif_p) {
    180                 __u32 ifindex = *rtrif_p;
    181                 eth_addr_t smac;
    182 
    183                 smac.addr = ethernet->src;
    184                 if (which_br == 1)
    185                     br1_mac_ifindex.update(&smac, &ifindex);
    186                 else
    187                     br2_mac_ifindex.update(&smac, &ifindex);
    188             }
    189         }
    190         goto xmit;
    191     }
    192 
    193     ip: {
    194         struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
    195         goto xmit;
    196     }
    197 
    198 xmit:
    199     if (which_br == 1)
    200         tx_port_id_p = br1_mac.lookup(&dmac);
    201     else
    202         tx_port_id_p = br2_mac.lookup(&dmac);
    203     if (tx_port_id_p) {
    204         tx_port_id = *tx_port_id_p;
    205         if (which_br == 1)
    206             dest_p = br1_dest.lookup(&tx_port_id);
    207         else
    208             dest_p = br2_dest.lookup(&tx_port_id);
    209         if (dest_p) {
    210             skb->cb[0] = dest_p->prog_id;
    211             skb->cb[1] = dest_p->port_id;
    212             jump.call(skb, dest_p->prog_id);
    213         }
    214     }
    215 
    216 EOP:
    217     return 1;
    218 }
    219 
    220 int br1(struct __sk_buff *skb) {
    221     return br_common(skb, 1);
    222 }
    223 
    224 int br2(struct __sk_buff *skb) {
    225     return br_common(skb, 2);
    226 }
    227