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