1 // SPDX-License-Identifier: GPL-2.0
2 #define KBUILD_MODNAME "foo"
3 #include <string.h>
4 #include <linux/in.h>
5 #include <linux/if_ether.h>
6 #include <linux/if_packet.h>
7 #include <linux/ip.h>
8 #include <linux/ipv6.h>
9
10 #include <linux/bpf.h>
11 #include <bpf/bpf_helpers.h>
12 #include <bpf/bpf_endian.h>
13
14 /* One map use devmap, another one use devmap_hash for testing */
15 struct {
16 __uint(type, BPF_MAP_TYPE_DEVMAP);
17 __uint(key_size, sizeof(int));
18 __uint(value_size, sizeof(int));
19 __uint(max_entries, 1024);
20 } map_all SEC(".maps");
21
22 struct {
23 __uint(type, BPF_MAP_TYPE_DEVMAP_HASH);
24 __uint(key_size, sizeof(int));
25 __uint(value_size, sizeof(struct bpf_devmap_val));
26 __uint(max_entries, 128);
27 } map_egress SEC(".maps");
28
29 /* map to store egress interfaces mac addresses */
30 struct {
31 __uint(type, BPF_MAP_TYPE_HASH);
32 __type(key, __u32);
33 __type(value, __be64);
34 __uint(max_entries, 128);
35 } mac_map SEC(".maps");
36
37 /* map to store redirect flags for each protocol*/
38 struct {
39 __uint(type, BPF_MAP_TYPE_HASH);
40 __type(key, __u16);
41 __type(value, __u64);
42 __uint(max_entries, 16);
43 } redirect_flags SEC(".maps");
44
45 SEC("xdp")
xdp_redirect_map_multi_prog(struct xdp_md * ctx)46 int xdp_redirect_map_multi_prog(struct xdp_md *ctx)
47 {
48 void *data_end = (void *)(long)ctx->data_end;
49 void *data = (void *)(long)ctx->data;
50 int if_index = ctx->ingress_ifindex;
51 struct ethhdr *eth = data;
52 __u64 *flags_from_map;
53 __u16 h_proto;
54 __u64 nh_off;
55 __u64 flags;
56
57 nh_off = sizeof(*eth);
58 if (data + nh_off > data_end)
59 return XDP_DROP;
60
61 h_proto = bpf_htons(eth->h_proto);
62
63 flags_from_map = bpf_map_lookup_elem(&redirect_flags, &h_proto);
64
65 /* Default flags for IPv4 : (BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS) */
66 if (h_proto == ETH_P_IP) {
67 flags = flags_from_map ? *flags_from_map : BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS;
68 return bpf_redirect_map(&map_all, 0, flags);
69 }
70 /* Default flags for IPv6 : 0 */
71 if (h_proto == ETH_P_IPV6) {
72 flags = flags_from_map ? *flags_from_map : 0;
73 return bpf_redirect_map(&map_all, if_index, flags);
74 }
75 /* Default flags for others BPF_F_BROADCAST : 0 */
76 else {
77 flags = flags_from_map ? *flags_from_map : BPF_F_BROADCAST;
78 return bpf_redirect_map(&map_all, 0, flags);
79 }
80 }
81
82 /* The following 2 progs are for 2nd devmap prog testing */
83 SEC("xdp")
xdp_redirect_map_all_prog(struct xdp_md * ctx)84 int xdp_redirect_map_all_prog(struct xdp_md *ctx)
85 {
86 return bpf_redirect_map(&map_egress, 0,
87 BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS);
88 }
89
90 SEC("xdp/devmap")
xdp_devmap_prog(struct xdp_md * ctx)91 int xdp_devmap_prog(struct xdp_md *ctx)
92 {
93 void *data_end = (void *)(long)ctx->data_end;
94 void *data = (void *)(long)ctx->data;
95 __u32 key = ctx->egress_ifindex;
96 struct ethhdr *eth = data;
97 __u64 nh_off;
98 __be64 *mac;
99
100 nh_off = sizeof(*eth);
101 if (data + nh_off > data_end)
102 return XDP_DROP;
103
104 mac = bpf_map_lookup_elem(&mac_map, &key);
105 if (mac)
106 __builtin_memcpy(eth->h_source, mac, ETH_ALEN);
107
108 return XDP_PASS;
109 }
110
111 char _license[] SEC("license") = "GPL";
112