blob: 0ddc88ad6ca1b62beae9a6bb6fb5d24514256d38 [file] [log] [blame]
// 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_TABLE("hash", struct FwdKey, struct FwdLeaf, fwd_map, 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_TABLE("hash", struct MacaddrKey, struct MacaddrLeaf, macaddr_map, 11);
// hash
struct SlaveKey {
u32 slave_ip;
};
struct SlaveLeaf {
u32 slave_ifindex;
};
BPF_TABLE("hash", struct SlaveKey, struct SlaveLeaf, slave_map, 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;
}