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