Back to home page

OSCL-LXR

 
 

    


0001 /* Copyright (C) 2017 Cavium, Inc.
0002  *
0003  * This program is free software; you can redistribute it and/or modify it
0004  * under the terms of version 2 of the GNU General Public License
0005  * as published by the Free Software Foundation.
0006  */
0007 
0008 #include "vmlinux.h"
0009 #include "xdp_sample.bpf.h"
0010 #include "xdp_sample_shared.h"
0011 
0012 #define ETH_ALEN    6
0013 #define ETH_P_8021Q 0x8100
0014 #define ETH_P_8021AD    0x88A8
0015 
0016 struct trie_value {
0017     __u8 prefix[4];
0018     __be64 value;
0019     int ifindex;
0020     int metric;
0021     __be32 gw;
0022 };
0023 
0024 /* Key for lpm_trie */
0025 union key_4 {
0026     u32 b32[2];
0027     u8 b8[8];
0028 };
0029 
0030 struct arp_entry {
0031     __be64 mac;
0032     __be32 dst;
0033 };
0034 
0035 struct direct_map {
0036     struct arp_entry arp;
0037     int ifindex;
0038     __be64 mac;
0039 };
0040 
0041 /* Map for trie implementation */
0042 struct {
0043     __uint(type, BPF_MAP_TYPE_LPM_TRIE);
0044     __uint(key_size, 8);
0045     __uint(value_size, sizeof(struct trie_value));
0046     __uint(max_entries, 50);
0047     __uint(map_flags, BPF_F_NO_PREALLOC);
0048 } lpm_map SEC(".maps");
0049 
0050 /* Map for ARP table */
0051 struct {
0052     __uint(type, BPF_MAP_TYPE_HASH);
0053     __type(key, __be32);
0054     __type(value, __be64);
0055     __uint(max_entries, 50);
0056 } arp_table SEC(".maps");
0057 
0058 /* Map to keep the exact match entries in the route table */
0059 struct {
0060     __uint(type, BPF_MAP_TYPE_HASH);
0061     __type(key, __be32);
0062     __type(value, struct direct_map);
0063     __uint(max_entries, 50);
0064 } exact_match SEC(".maps");
0065 
0066 struct {
0067     __uint(type, BPF_MAP_TYPE_DEVMAP);
0068     __uint(key_size, sizeof(int));
0069     __uint(value_size, sizeof(int));
0070     __uint(max_entries, 100);
0071 } tx_port SEC(".maps");
0072 
0073 SEC("xdp")
0074 int xdp_router_ipv4_prog(struct xdp_md *ctx)
0075 {
0076     void *data_end = (void *)(long)ctx->data_end;
0077     void *data = (void *)(long)ctx->data;
0078     struct ethhdr *eth = data;
0079     u64 nh_off = sizeof(*eth);
0080     struct datarec *rec;
0081     __be16 h_proto;
0082     u32 key = 0;
0083 
0084     rec = bpf_map_lookup_elem(&rx_cnt, &key);
0085     if (rec)
0086         NO_TEAR_INC(rec->processed);
0087 
0088     if (data + nh_off > data_end)
0089         goto drop;
0090 
0091     h_proto = eth->h_proto;
0092     if (h_proto == bpf_htons(ETH_P_8021Q) ||
0093         h_proto == bpf_htons(ETH_P_8021AD)) {
0094         struct vlan_hdr *vhdr;
0095 
0096         vhdr = data + nh_off;
0097         nh_off += sizeof(struct vlan_hdr);
0098         if (data + nh_off > data_end)
0099             goto drop;
0100 
0101         h_proto = vhdr->h_vlan_encapsulated_proto;
0102     }
0103 
0104     switch (bpf_ntohs(h_proto)) {
0105     case ETH_P_ARP:
0106         if (rec)
0107             NO_TEAR_INC(rec->xdp_pass);
0108         return XDP_PASS;
0109     case ETH_P_IP: {
0110         struct iphdr *iph = data + nh_off;
0111         struct direct_map *direct_entry;
0112         __be64 *dest_mac, *src_mac;
0113         int forward_to;
0114 
0115         if (iph + 1 > data_end)
0116             goto drop;
0117 
0118         direct_entry = bpf_map_lookup_elem(&exact_match, &iph->daddr);
0119 
0120         /* Check for exact match, this would give a faster lookup */
0121         if (direct_entry && direct_entry->mac &&
0122             direct_entry->arp.mac) {
0123             src_mac = &direct_entry->mac;
0124             dest_mac = &direct_entry->arp.mac;
0125             forward_to = direct_entry->ifindex;
0126         } else {
0127             struct trie_value *prefix_value;
0128             union key_4 key4;
0129 
0130             /* Look up in the trie for lpm */
0131             key4.b32[0] = 32;
0132             key4.b8[4] = iph->daddr & 0xff;
0133             key4.b8[5] = (iph->daddr >> 8) & 0xff;
0134             key4.b8[6] = (iph->daddr >> 16) & 0xff;
0135             key4.b8[7] = (iph->daddr >> 24) & 0xff;
0136 
0137             prefix_value = bpf_map_lookup_elem(&lpm_map, &key4);
0138             if (!prefix_value)
0139                 goto drop;
0140 
0141             forward_to = prefix_value->ifindex;
0142             src_mac = &prefix_value->value;
0143             if (!src_mac)
0144                 goto drop;
0145 
0146             dest_mac = bpf_map_lookup_elem(&arp_table, &iph->daddr);
0147             if (!dest_mac) {
0148                 if (!prefix_value->gw)
0149                     goto drop;
0150 
0151                 dest_mac = bpf_map_lookup_elem(&arp_table,
0152                                    &prefix_value->gw);
0153                 if (!dest_mac) {
0154                     /* Forward the packet to the kernel in
0155                      * order to trigger ARP discovery for
0156                      * the default gw.
0157                      */
0158                     if (rec)
0159                         NO_TEAR_INC(rec->xdp_pass);
0160                     return XDP_PASS;
0161                 }
0162             }
0163         }
0164 
0165         if (src_mac && dest_mac) {
0166             int ret;
0167 
0168             __builtin_memcpy(eth->h_dest, dest_mac, ETH_ALEN);
0169             __builtin_memcpy(eth->h_source, src_mac, ETH_ALEN);
0170 
0171             ret = bpf_redirect_map(&tx_port, forward_to, 0);
0172             if (ret == XDP_REDIRECT) {
0173                 if (rec)
0174                     NO_TEAR_INC(rec->xdp_redirect);
0175                 return ret;
0176             }
0177         }
0178     }
0179     default:
0180         break;
0181     }
0182 drop:
0183     if (rec)
0184         NO_TEAR_INC(rec->xdp_drop);
0185 
0186     return XDP_DROP;
0187 }
0188 
0189 char _license[] SEC("license") = "GPL";