• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) PLUMgrid, Inc.
2 // Licensed under the Apache License, Version 2.0 (the "License")
3 
4 #include <bcc/proto.h>
5 
6 // hash
7 struct FwdKey {
8   u32 dip:32;
9 };
10 struct FwdLeaf {
11   u32 fwd_idx:32;
12 };
13 BPF_HASH(fwd_map, struct FwdKey, struct FwdLeaf, 1);
14 
15 // array
16 struct ConfigKey {
17   u32 index;
18 };
19 struct ConfigLeaf {
20   u32 bpfdev_ip;
21   u32 slave_ip;
22 };
23 BPF_TABLE("array", struct ConfigKey, struct ConfigLeaf, config_map, 1);
24 
25 // hash
26 struct MacaddrKey {
27   u32 ip;
28 };
29 struct MacaddrLeaf {
30   u64 mac;
31 };
32 BPF_HASH(macaddr_map, struct MacaddrKey, struct MacaddrLeaf, 11);
33 
34 // hash
35 struct SlaveKey {
36   u32 slave_ip;
37 };
38 struct SlaveLeaf {
39   u32 slave_ifindex;
40 };
41 BPF_HASH(slave_map, struct SlaveKey, struct SlaveLeaf, 10);
42 
handle_packet(struct __sk_buff * skb)43 int handle_packet(struct __sk_buff *skb) {
44   int ret = 0;
45   u8 *cursor = 0;
46 
47   if (skb->pkt_type == 0) {
48     // tx
49     // make sure configured
50     u32 slave_ip;
51 
52     struct ConfigKey cfg_key = {.index = 0};
53     struct ConfigLeaf *cfg_leaf = config_map.lookup(&cfg_key);
54     if (cfg_leaf) {
55       slave_ip = cfg_leaf->slave_ip;
56     } else {
57       return 0xffffffff;
58     }
59 
60     // make sure slave configured
61     // tx, default to the single slave
62     struct SlaveKey slave_key = {.slave_ip = slave_ip};
63     struct SlaveLeaf *slave_leaf = slave_map.lookup(&slave_key);
64     if (slave_leaf) {
65       ret = slave_leaf->slave_ifindex;
66     } else {
67       return 0xffffffff;
68     }
69   } else {
70     // rx, default to stack
71     ret = 0;
72   }
73 
74   struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
75   switch (ethernet->type) {
76     case ETH_P_IP: goto ip;
77     case ETH_P_ARP: goto arp;
78     case ETH_P_8021Q: goto dot1q;
79     default: goto EOP;
80   }
81 
82   dot1q: {
83     struct dot1q_t *dot1q = cursor_advance(cursor, sizeof(*dot1q));
84     switch (dot1q->type) {
85       case ETH_P_IP: goto ip;
86       case ETH_P_ARP: goto arp;
87       default: goto EOP;
88     }
89   }
90 
91   arp: {
92     struct arp_t *arp = cursor_advance(cursor, sizeof(*arp));
93     if (skb->pkt_type) {
94       if (arp->oper == 1) {
95         struct MacaddrKey mac_key = {.ip=arp->spa};
96         struct MacaddrLeaf mac_leaf = {.mac=arp->sha};
97         macaddr_map.update(&mac_key, &mac_leaf);
98       }
99     }
100     goto EOP;
101   }
102 
103   struct ip_t *ip;
104   ip: {
105     ip = cursor_advance(cursor, sizeof(*ip));
106     switch (ip->nextp) {
107       case 6: goto tcp;
108       case 17: goto udp;
109       default: goto EOP;
110     }
111   }
112   tcp: {
113     struct tcp_t *tcp = cursor_advance(cursor, sizeof(*tcp));
114     goto EOP;
115   }
116   udp: {
117     struct udp_t *udp = cursor_advance(cursor, sizeof(*udp));
118     if (udp->dport != 5000) {
119        goto EOP;
120     }
121     if (skb->pkt_type) {
122       // lookup and then forward
123       struct FwdKey fwd_key = {.dip=ip->dst};
124       struct FwdLeaf *fwd_val = fwd_map.lookup(&fwd_key);
125       if (fwd_val) {
126          return fwd_val->fwd_idx;
127       }
128     } else {
129       // rewrite the packet and send to a pre-configured index if needed
130       u32 new_ip;
131       u32 old_ip;
132       u64 src_mac;
133       u64 dst_mac;
134 
135       struct ConfigKey cfg_key = {.index = 0};
136       struct ConfigLeaf *cfg_leaf = config_map.lookup(&cfg_key);
137       if (cfg_leaf) {
138         struct MacaddrKey mac_key = {.ip = cfg_leaf->bpfdev_ip};
139         struct MacaddrLeaf *mac_leaf;
140 
141         mac_key.ip = cfg_leaf->bpfdev_ip;
142         mac_leaf = macaddr_map.lookup(&mac_key);
143         if (mac_leaf) {
144           src_mac = mac_leaf->mac;
145         } else {
146           goto EOP;
147         }
148 
149         mac_key.ip = cfg_leaf->slave_ip;
150         mac_leaf = macaddr_map.lookup(&mac_key);
151         if (mac_leaf) {
152           dst_mac = mac_leaf->mac;
153         } else {
154           goto EOP;
155         }
156 
157         // rewrite ethernet header
158         ethernet->dst = dst_mac;
159         ethernet->src = src_mac;
160 
161         // ip & udp checksum
162         incr_cksum_l4(&udp->crc, ip->src, cfg_leaf->bpfdev_ip, 1);
163         incr_cksum_l4(&udp->crc, ip->dst, cfg_leaf->slave_ip, 1);
164 
165         // rewrite ip src/dst fields
166         ip->src = cfg_leaf->bpfdev_ip;
167         ip->dst = cfg_leaf->slave_ip;
168       }
169     }
170     goto EOP;
171   }
172 
173 EOP:
174   return ret;
175 }
176