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