]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - samples/bpf/xdp_redirect_map_multi_user.c
Merge branch 'stable/for-linus-5.15' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / samples / bpf / xdp_redirect_map_multi_user.c
CommitLineData
e48cfe4b
HL
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/bpf.h>
3#include <linux/if_link.h>
4#include <assert.h>
5#include <errno.h>
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <net/if.h>
11#include <unistd.h>
12#include <libgen.h>
13#include <sys/resource.h>
14#include <sys/ioctl.h>
15#include <sys/types.h>
16#include <sys/socket.h>
17#include <netinet/in.h>
18
19#include "bpf_util.h"
20#include <bpf/bpf.h>
21#include <bpf/libbpf.h>
22
23#define MAX_IFACE_NUM 32
24
25static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
26static int ifaces[MAX_IFACE_NUM] = {};
27static int rxcnt_map_fd;
28
29static void int_exit(int sig)
30{
31 __u32 prog_id = 0;
32 int i;
33
34 for (i = 0; ifaces[i] > 0; i++) {
35 if (bpf_get_link_xdp_id(ifaces[i], &prog_id, xdp_flags)) {
36 printf("bpf_get_link_xdp_id failed\n");
37 exit(1);
38 }
39 if (prog_id)
40 bpf_set_link_xdp_fd(ifaces[i], -1, xdp_flags);
41 }
42
43 exit(0);
44}
45
46static void poll_stats(int interval)
47{
48 unsigned int nr_cpus = bpf_num_possible_cpus();
49 __u64 values[nr_cpus], prev[nr_cpus];
50
51 memset(prev, 0, sizeof(prev));
52
53 while (1) {
54 __u64 sum = 0;
55 __u32 key = 0;
56 int i;
57
58 sleep(interval);
59 assert(bpf_map_lookup_elem(rxcnt_map_fd, &key, values) == 0);
60 for (i = 0; i < nr_cpus; i++)
61 sum += (values[i] - prev[i]);
62 if (sum)
63 printf("Forwarding %10llu pkt/s\n", sum / interval);
64 memcpy(prev, values, sizeof(values));
65 }
66}
67
68static int get_mac_addr(unsigned int ifindex, void *mac_addr)
69{
70 char ifname[IF_NAMESIZE];
71 struct ifreq ifr;
72 int fd, ret = -1;
73
74 fd = socket(AF_INET, SOCK_DGRAM, 0);
75 if (fd < 0)
76 return ret;
77
78 if (!if_indextoname(ifindex, ifname))
79 goto err_out;
80
81 strcpy(ifr.ifr_name, ifname);
82
83 if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
84 goto err_out;
85
86 memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, 6 * sizeof(char));
87 ret = 0;
88
89err_out:
90 close(fd);
91 return ret;
92}
93
94static int update_mac_map(struct bpf_object *obj)
95{
96 int i, ret = -1, mac_map_fd;
97 unsigned char mac_addr[6];
98 unsigned int ifindex;
99
100 mac_map_fd = bpf_object__find_map_fd_by_name(obj, "mac_map");
101 if (mac_map_fd < 0) {
102 printf("find mac map fd failed\n");
103 return ret;
104 }
105
106 for (i = 0; ifaces[i] > 0; i++) {
107 ifindex = ifaces[i];
108
109 ret = get_mac_addr(ifindex, mac_addr);
110 if (ret < 0) {
111 printf("get interface %d mac failed\n", ifindex);
112 return ret;
113 }
114
115 ret = bpf_map_update_elem(mac_map_fd, &ifindex, mac_addr, 0);
116 if (ret) {
117 perror("bpf_update_elem mac_map_fd");
118 return ret;
119 }
120 }
121
122 return 0;
123}
124
125static void usage(const char *prog)
126{
127 fprintf(stderr,
128 "usage: %s [OPTS] <IFNAME|IFINDEX> <IFNAME|IFINDEX> ...\n"
129 "OPTS:\n"
130 " -S use skb-mode\n"
131 " -N enforce native mode\n"
132 " -F force loading prog\n"
133 " -X load xdp program on egress\n",
134 prog);
135}
136
137int main(int argc, char **argv)
138{
139 int i, ret, opt, forward_map_fd, max_ifindex = 0;
140 struct bpf_program *ingress_prog, *egress_prog;
141 int ingress_prog_fd, egress_prog_fd = 0;
142 struct bpf_devmap_val devmap_val;
143 bool attach_egress_prog = false;
144 char ifname[IF_NAMESIZE];
145 struct bpf_map *mac_map;
146 struct bpf_object *obj;
147 unsigned int ifindex;
148 char filename[256];
149
150 while ((opt = getopt(argc, argv, "SNFX")) != -1) {
151 switch (opt) {
152 case 'S':
153 xdp_flags |= XDP_FLAGS_SKB_MODE;
154 break;
155 case 'N':
156 /* default, set below */
157 break;
158 case 'F':
159 xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
160 break;
161 case 'X':
162 attach_egress_prog = true;
163 break;
164 default:
165 usage(basename(argv[0]));
166 return 1;
167 }
168 }
169
170 if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) {
171 xdp_flags |= XDP_FLAGS_DRV_MODE;
172 } else if (attach_egress_prog) {
173 printf("Load xdp program on egress with SKB mode not supported yet\n");
174 return 1;
175 }
176
177 if (optind == argc) {
178 printf("usage: %s <IFNAME|IFINDEX> <IFNAME|IFINDEX> ...\n", argv[0]);
179 return 1;
180 }
181
182 printf("Get interfaces");
183 for (i = 0; i < MAX_IFACE_NUM && argv[optind + i]; i++) {
184 ifaces[i] = if_nametoindex(argv[optind + i]);
185 if (!ifaces[i])
186 ifaces[i] = strtoul(argv[optind + i], NULL, 0);
187 if (!if_indextoname(ifaces[i], ifname)) {
188 perror("Invalid interface name or i");
189 return 1;
190 }
191
192 /* Find the largest index number */
193 if (ifaces[i] > max_ifindex)
194 max_ifindex = ifaces[i];
195
196 printf(" %d", ifaces[i]);
197 }
198 printf("\n");
199
200 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
201
202 obj = bpf_object__open(filename);
203 if (libbpf_get_error(obj)) {
204 printf("ERROR: opening BPF object file failed\n");
205 obj = NULL;
206 goto err_out;
207 }
208
209 /* Reset the map size to max ifindex + 1 */
210 if (attach_egress_prog) {
211 mac_map = bpf_object__find_map_by_name(obj, "mac_map");
212 ret = bpf_map__resize(mac_map, max_ifindex + 1);
213 if (ret < 0) {
214 printf("ERROR: reset mac map size failed\n");
215 goto err_out;
216 }
217 }
218
219 /* load BPF program */
220 if (bpf_object__load(obj)) {
221 printf("ERROR: loading BPF object file failed\n");
222 goto err_out;
223 }
224
225 if (xdp_flags & XDP_FLAGS_SKB_MODE) {
226 ingress_prog = bpf_object__find_program_by_name(obj, "xdp_redirect_map_general");
227 forward_map_fd = bpf_object__find_map_fd_by_name(obj, "forward_map_general");
228 } else {
229 ingress_prog = bpf_object__find_program_by_name(obj, "xdp_redirect_map_native");
230 forward_map_fd = bpf_object__find_map_fd_by_name(obj, "forward_map_native");
231 }
232 if (!ingress_prog || forward_map_fd < 0) {
233 printf("finding ingress_prog/forward_map in obj file failed\n");
234 goto err_out;
235 }
236
237 ingress_prog_fd = bpf_program__fd(ingress_prog);
238 if (ingress_prog_fd < 0) {
239 printf("find ingress_prog fd failed\n");
240 goto err_out;
241 }
242
243 rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
244 if (rxcnt_map_fd < 0) {
245 printf("bpf_object__find_map_fd_by_name failed\n");
246 goto err_out;
247 }
248
249 if (attach_egress_prog) {
250 /* Update mac_map with all egress interfaces' mac addr */
251 if (update_mac_map(obj) < 0) {
252 printf("Error: update mac map failed");
253 goto err_out;
254 }
255
256 /* Find egress prog fd */
257 egress_prog = bpf_object__find_program_by_name(obj, "xdp_devmap_prog");
258 if (!egress_prog) {
259 printf("finding egress_prog in obj file failed\n");
260 goto err_out;
261 }
262 egress_prog_fd = bpf_program__fd(egress_prog);
263 if (egress_prog_fd < 0) {
264 printf("find egress_prog fd failed\n");
265 goto err_out;
266 }
267 }
268
269 /* Remove attached program when program is interrupted or killed */
270 signal(SIGINT, int_exit);
271 signal(SIGTERM, int_exit);
272
273 /* Init forward multicast groups */
274 for (i = 0; ifaces[i] > 0; i++) {
275 ifindex = ifaces[i];
276
277 /* bind prog_fd to each interface */
278 ret = bpf_set_link_xdp_fd(ifindex, ingress_prog_fd, xdp_flags);
279 if (ret) {
280 printf("Set xdp fd failed on %d\n", ifindex);
281 goto err_out;
282 }
283
284 /* Add all the interfaces to forward group and attach
285 * egress devmap programe if exist
286 */
287 devmap_val.ifindex = ifindex;
288 devmap_val.bpf_prog.fd = egress_prog_fd;
289 ret = bpf_map_update_elem(forward_map_fd, &ifindex, &devmap_val, 0);
290 if (ret) {
291 perror("bpf_map_update_elem forward_map");
292 goto err_out;
293 }
294 }
295
296 poll_stats(2);
297
298 return 0;
299
300err_out:
301 return 1;
302}