1 /* Copyright (C) 2017 Cavium, Inc.
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of version 2 of the GNU General Public License
5 * as published by the Free Software Foundation.
7 #define KBUILD_MODNAME "foo"
8 #include <uapi/linux/bpf.h>
10 #include <linux/if_ether.h>
11 #include <linux/if_packet.h>
12 #include <linux/if_vlan.h>
14 #include <linux/ipv6.h>
15 #include "bpf_helpers.h"
16 #include <linux/slab.h>
17 #include <net/ip_fib.h>
44 /* Map for trie implementation*/
45 struct bpf_map_def
SEC("maps") lpm_map
= {
46 .type
= BPF_MAP_TYPE_LPM_TRIE
,
48 .value_size
= sizeof(struct trie_value
),
50 .map_flags
= BPF_F_NO_PREALLOC
,
54 struct bpf_map_def
SEC("maps") rxcnt
= {
55 .type
= BPF_MAP_TYPE_PERCPU_ARRAY
,
56 .key_size
= sizeof(u32
),
57 .value_size
= sizeof(u64
),
61 /* Map for ARP table*/
62 struct bpf_map_def
SEC("maps") arp_table
= {
63 .type
= BPF_MAP_TYPE_HASH
,
64 .key_size
= sizeof(__be32
),
65 .value_size
= sizeof(__be64
),
69 /* Map to keep the exact match entries in the route table*/
70 struct bpf_map_def
SEC("maps") exact_match
= {
71 .type
= BPF_MAP_TYPE_HASH
,
72 .key_size
= sizeof(__be32
),
73 .value_size
= sizeof(struct direct_map
),
77 struct bpf_map_def
SEC("maps") tx_port
= {
78 .type
= BPF_MAP_TYPE_DEVMAP
,
79 .key_size
= sizeof(int),
80 .value_size
= sizeof(int),
84 /* Function to set source and destination mac of the packet */
85 static inline void set_src_dst_mac(void *data
, void *src
, void *dst
)
87 unsigned short *source
= src
;
88 unsigned short *dest
= dst
;
89 unsigned short *p
= data
;
91 __builtin_memcpy(p
, dest
, 6);
92 __builtin_memcpy(p
+ 3, source
, 6);
95 /* Parse IPV4 packet to get SRC, DST IP and protocol */
96 static inline int parse_ipv4(void *data
, u64 nh_off
, void *data_end
,
97 __be32
*src
, __be32
*dest
)
99 struct iphdr
*iph
= data
+ nh_off
;
101 if (iph
+ 1 > data_end
)
105 return iph
->protocol
;
108 SEC("xdp_router_ipv4")
109 int xdp_router_ipv4_prog(struct xdp_md
*ctx
)
111 void *data_end
= (void *)(long)ctx
->data_end
;
112 __be64
*dest_mac
= NULL
, *src_mac
= NULL
;
113 void *data
= (void *)(long)ctx
->data
;
114 struct trie_value
*prefix_value
;
115 int rc
= XDP_DROP
, forward_to
;
116 struct ethhdr
*eth
= data
;
123 nh_off
= sizeof(*eth
);
124 if (data
+ nh_off
> data_end
)
127 h_proto
= eth
->h_proto
;
129 if (h_proto
== htons(ETH_P_8021Q
) || h_proto
== htons(ETH_P_8021AD
)) {
130 struct vlan_hdr
*vhdr
;
132 vhdr
= data
+ nh_off
;
133 nh_off
+= sizeof(struct vlan_hdr
);
134 if (data
+ nh_off
> data_end
)
136 h_proto
= vhdr
->h_vlan_encapsulated_proto
;
138 if (h_proto
== htons(ETH_P_ARP
)) {
140 } else if (h_proto
== htons(ETH_P_IP
)) {
141 struct direct_map
*direct_entry
;
142 __be32 src_ip
= 0, dest_ip
= 0;
144 ipproto
= parse_ipv4(data
, nh_off
, data_end
, &src_ip
, &dest_ip
);
145 direct_entry
= bpf_map_lookup_elem(&exact_match
, &dest_ip
);
146 /* Check for exact match, this would give a faster lookup*/
147 if (direct_entry
&& direct_entry
->mac
&& direct_entry
->arp
.mac
) {
148 src_mac
= &direct_entry
->mac
;
149 dest_mac
= &direct_entry
->arp
.mac
;
150 forward_to
= direct_entry
->ifindex
;
152 /* Look up in the trie for lpm*/
154 key4
.b8
[4] = dest_ip
& 0xff;
155 key4
.b8
[5] = (dest_ip
>> 8) & 0xff;
156 key4
.b8
[6] = (dest_ip
>> 16) & 0xff;
157 key4
.b8
[7] = (dest_ip
>> 24) & 0xff;
158 prefix_value
= bpf_map_lookup_elem(&lpm_map
, &key4
);
161 src_mac
= &prefix_value
->value
;
164 dest_mac
= bpf_map_lookup_elem(&arp_table
, &dest_ip
);
166 if (!prefix_value
->gw
)
168 dest_ip
= prefix_value
->gw
;
169 dest_mac
= bpf_map_lookup_elem(&arp_table
, &dest_ip
);
171 forward_to
= prefix_value
->ifindex
;
176 if (src_mac
&& dest_mac
) {
177 set_src_dst_mac(data
, src_mac
, dest_mac
);
178 value
= bpf_map_lookup_elem(&rxcnt
, &ipproto
);
181 return bpf_redirect_map(&tx_port
, forward_to
, 0);
186 char _license
[] SEC("license") = "GPL";