in bpf/xdp_router_ipv4_kern.c [109:184]
int xdp_router_ipv4_prog(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
__be64 *dest_mac = NULL, *src_mac = NULL;
void *data = (void *)(long)ctx->data;
struct trie_value *prefix_value;
int rc = XDP_DROP, forward_to;
struct ethhdr *eth = data;
union key_4 key4;
long *value;
u16 h_proto;
u32 ipproto;
u64 nh_off;
nh_off = sizeof(*eth);
if (data + nh_off > data_end)
return rc;
h_proto = eth->h_proto;
if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
struct vlan_hdr *vhdr;
vhdr = data + nh_off;
nh_off += sizeof(struct vlan_hdr);
if (data + nh_off > data_end)
return rc;
h_proto = vhdr->h_vlan_encapsulated_proto;
}
if (h_proto == htons(ETH_P_ARP)) {
return XDP_PASS;
} else if (h_proto == htons(ETH_P_IP)) {
struct direct_map *direct_entry;
__be32 src_ip = 0, dest_ip = 0;
ipproto = parse_ipv4(data, nh_off, data_end, &src_ip, &dest_ip);
direct_entry = bpf_map_lookup_elem(&exact_match, &dest_ip);
/* Check for exact match, this would give a faster lookup*/
if (direct_entry && direct_entry->mac && direct_entry->arp.mac) {
src_mac = &direct_entry->mac;
dest_mac = &direct_entry->arp.mac;
forward_to = direct_entry->ifindex;
} else {
/* Look up in the trie for lpm*/
key4.b32[0] = 32;
key4.b8[4] = dest_ip & 0xff;
key4.b8[5] = (dest_ip >> 8) & 0xff;
key4.b8[6] = (dest_ip >> 16) & 0xff;
key4.b8[7] = (dest_ip >> 24) & 0xff;
prefix_value = bpf_map_lookup_elem(&lpm_map, &key4);
if (!prefix_value)
return XDP_DROP;
src_mac = &prefix_value->value;
if (!src_mac)
return XDP_DROP;
dest_mac = bpf_map_lookup_elem(&arp_table, &dest_ip);
if (!dest_mac) {
if (!prefix_value->gw)
return XDP_DROP;
dest_ip = prefix_value->gw;
dest_mac = bpf_map_lookup_elem(&arp_table, &dest_ip);
}
forward_to = prefix_value->ifindex;
}
} else {
ipproto = 0;
}
if (src_mac && dest_mac) {
set_src_dst_mac(data, src_mac, dest_mac);
value = bpf_map_lookup_elem(&rxcnt, &ipproto);
if (value)
*value += 1;
return bpf_redirect_map(&tx_port, forward_to, 0);
}
return rc;
}