Merge tag 'xfs-5.20-merge-8' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-2.6-microblaze.git] / samples / bpf / xdp_redirect_map_multi_user.c
1 // SPDX-License-Identifier: GPL-2.0
2 static const char *__doc__ =
3 "XDP multi redirect tool, using BPF_MAP_TYPE_DEVMAP and BPF_F_BROADCAST flag for bpf_redirect_map\n"
4 "Usage: xdp_redirect_map_multi <IFINDEX|IFNAME> <IFINDEX|IFNAME> ... <IFINDEX|IFNAME>\n";
5
6 #include <linux/bpf.h>
7 #include <linux/if_link.h>
8 #include <assert.h>
9 #include <getopt.h>
10 #include <errno.h>
11 #include <signal.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <net/if.h>
16 #include <unistd.h>
17 #include <libgen.h>
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <linux/if_ether.h>
23 #include <bpf/bpf.h>
24 #include <bpf/libbpf.h>
25 #include "bpf_util.h"
26 #include "xdp_sample_user.h"
27 #include "xdp_redirect_map_multi.skel.h"
28
29 #define MAX_IFACE_NUM 32
30 static int ifaces[MAX_IFACE_NUM] = {};
31
32 static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT |
33                   SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT |
34                   SAMPLE_DEVMAP_XMIT_CNT_MULTI | SAMPLE_SKIP_HEADING;
35
36 DEFINE_SAMPLE_INIT(xdp_redirect_map_multi);
37
38 static const struct option long_options[] = {
39         { "help", no_argument, NULL, 'h' },
40         { "skb-mode", no_argument, NULL, 'S' },
41         { "force", no_argument, NULL, 'F' },
42         { "load-egress", no_argument, NULL, 'X' },
43         { "stats", no_argument, NULL, 's' },
44         { "interval", required_argument, NULL, 'i' },
45         { "verbose", no_argument, NULL, 'v' },
46         {}
47 };
48
49 static int update_mac_map(struct bpf_map *map)
50 {
51         int mac_map_fd = bpf_map__fd(map);
52         unsigned char mac_addr[6];
53         unsigned int ifindex;
54         int i, ret = -1;
55
56         for (i = 0; ifaces[i] > 0; i++) {
57                 ifindex = ifaces[i];
58
59                 ret = get_mac_addr(ifindex, mac_addr);
60                 if (ret < 0) {
61                         fprintf(stderr, "get interface %d mac failed\n",
62                                 ifindex);
63                         return ret;
64                 }
65
66                 ret = bpf_map_update_elem(mac_map_fd, &ifindex, mac_addr, 0);
67                 if (ret < 0) {
68                         fprintf(stderr, "Failed to update mac address for ifindex %d\n",
69                                 ifindex);
70                         return ret;
71                 }
72         }
73
74         return 0;
75 }
76
77 int main(int argc, char **argv)
78 {
79         struct bpf_devmap_val devmap_val = {};
80         struct xdp_redirect_map_multi *skel;
81         struct bpf_program *ingress_prog;
82         bool xdp_devmap_attached = false;
83         struct bpf_map *forward_map;
84         int ret = EXIT_FAIL_OPTION;
85         unsigned long interval = 2;
86         char ifname[IF_NAMESIZE];
87         unsigned int ifindex;
88         bool generic = false;
89         bool force = false;
90         bool tried = false;
91         bool error = true;
92         int i, opt;
93
94         while ((opt = getopt_long(argc, argv, "hSFXi:vs",
95                                   long_options, NULL)) != -1) {
96                 switch (opt) {
97                 case 'S':
98                         generic = true;
99                         /* devmap_xmit tracepoint not available */
100                         mask &= ~(SAMPLE_DEVMAP_XMIT_CNT |
101                                   SAMPLE_DEVMAP_XMIT_CNT_MULTI);
102                         break;
103                 case 'F':
104                         force = true;
105                         break;
106                 case 'X':
107                         xdp_devmap_attached = true;
108                         break;
109                 case 'i':
110                         interval = strtoul(optarg, NULL, 0);
111                         break;
112                 case 'v':
113                         sample_switch_mode();
114                         break;
115                 case 's':
116                         mask |= SAMPLE_REDIRECT_MAP_CNT;
117                         break;
118                 case 'h':
119                         error = false;
120                 default:
121                         sample_usage(argv, long_options, __doc__, mask, error);
122                         return ret;
123                 }
124         }
125
126         if (argc <= optind + 1) {
127                 sample_usage(argv, long_options, __doc__, mask, error);
128                 return ret;
129         }
130
131         skel = xdp_redirect_map_multi__open();
132         if (!skel) {
133                 fprintf(stderr, "Failed to xdp_redirect_map_multi__open: %s\n",
134                         strerror(errno));
135                 ret = EXIT_FAIL_BPF;
136                 goto end;
137         }
138
139         ret = sample_init_pre_load(skel);
140         if (ret < 0) {
141                 fprintf(stderr, "Failed to sample_init_pre_load: %s\n", strerror(-ret));
142                 ret = EXIT_FAIL_BPF;
143                 goto end_destroy;
144         }
145
146         ret = EXIT_FAIL_OPTION;
147         for (i = 0; i < MAX_IFACE_NUM && argv[optind + i]; i++) {
148                 ifaces[i] = if_nametoindex(argv[optind + i]);
149                 if (!ifaces[i])
150                         ifaces[i] = strtoul(argv[optind + i], NULL, 0);
151                 if (!if_indextoname(ifaces[i], ifname)) {
152                         fprintf(stderr, "Bad interface index or name\n");
153                         sample_usage(argv, long_options, __doc__, mask, true);
154                         goto end_destroy;
155                 }
156
157                 skel->rodata->from_match[i] = ifaces[i];
158                 skel->rodata->to_match[i] = ifaces[i];
159         }
160
161         ret = xdp_redirect_map_multi__load(skel);
162         if (ret < 0) {
163                 fprintf(stderr, "Failed to xdp_redirect_map_multi__load: %s\n",
164                         strerror(errno));
165                 ret = EXIT_FAIL_BPF;
166                 goto end_destroy;
167         }
168
169         if (xdp_devmap_attached) {
170                 /* Update mac_map with all egress interfaces' mac addr */
171                 if (update_mac_map(skel->maps.mac_map) < 0) {
172                         fprintf(stderr, "Updating mac address failed\n");
173                         ret = EXIT_FAIL;
174                         goto end_destroy;
175                 }
176         }
177
178         ret = sample_init(skel, mask);
179         if (ret < 0) {
180                 fprintf(stderr, "Failed to initialize sample: %s\n", strerror(-ret));
181                 ret = EXIT_FAIL;
182                 goto end_destroy;
183         }
184
185         ingress_prog = skel->progs.xdp_redirect_map_native;
186         forward_map = skel->maps.forward_map_native;
187
188         for (i = 0; ifaces[i] > 0; i++) {
189                 ifindex = ifaces[i];
190
191                 ret = EXIT_FAIL_XDP;
192 restart:
193                 /* bind prog_fd to each interface */
194                 if (sample_install_xdp(ingress_prog, ifindex, generic, force) < 0) {
195                         if (generic && !tried) {
196                                 fprintf(stderr,
197                                         "Trying fallback to sizeof(int) as value_size for devmap in generic mode\n");
198                                 ingress_prog = skel->progs.xdp_redirect_map_general;
199                                 forward_map = skel->maps.forward_map_general;
200                                 tried = true;
201                                 goto restart;
202                         }
203                         goto end_destroy;
204                 }
205
206                 /* Add all the interfaces to forward group and attach
207                  * egress devmap program if exist
208                  */
209                 devmap_val.ifindex = ifindex;
210                 if (xdp_devmap_attached)
211                         devmap_val.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_devmap_prog);
212                 ret = bpf_map_update_elem(bpf_map__fd(forward_map), &ifindex, &devmap_val, 0);
213                 if (ret < 0) {
214                         fprintf(stderr, "Failed to update devmap value: %s\n",
215                                 strerror(errno));
216                         ret = EXIT_FAIL_BPF;
217                         goto end_destroy;
218                 }
219         }
220
221         ret = sample_run(interval, NULL, NULL);
222         if (ret < 0) {
223                 fprintf(stderr, "Failed during sample run: %s\n", strerror(-ret));
224                 ret = EXIT_FAIL;
225                 goto end_destroy;
226         }
227         ret = EXIT_OK;
228 end_destroy:
229         xdp_redirect_map_multi__destroy(skel);
230 end:
231         sample_exit(ret);
232 }