1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/if_link.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>
21 #include <bpf/libbpf.h>
23 #define MAX_IFACE_NUM 32
25 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
26 static int ifaces[MAX_IFACE_NUM] = {};
27 static int rxcnt_map_fd;
29 static void int_exit(int sig)
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");
40 bpf_set_link_xdp_fd(ifaces[i], -1, xdp_flags);
46 static void poll_stats(int interval)
48 unsigned int nr_cpus = bpf_num_possible_cpus();
49 __u64 values[nr_cpus], prev[nr_cpus];
51 memset(prev, 0, sizeof(prev));
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]);
63 printf("Forwarding %10llu pkt/s\n", sum / interval);
64 memcpy(prev, values, sizeof(values));
68 static int get_mac_addr(unsigned int ifindex, void *mac_addr)
70 char ifname[IF_NAMESIZE];
74 fd = socket(AF_INET, SOCK_DGRAM, 0);
78 if (!if_indextoname(ifindex, ifname))
81 strcpy(ifr.ifr_name, ifname);
83 if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
86 memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, 6 * sizeof(char));
94 static int update_mac_map(struct bpf_object *obj)
96 int i, ret = -1, mac_map_fd;
97 unsigned char mac_addr[6];
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");
106 for (i = 0; ifaces[i] > 0; i++) {
109 ret = get_mac_addr(ifindex, mac_addr);
111 printf("get interface %d mac failed\n", ifindex);
115 ret = bpf_map_update_elem(mac_map_fd, &ifindex, mac_addr, 0);
117 perror("bpf_update_elem mac_map_fd");
125 static void usage(const char *prog)
128 "usage: %s [OPTS] <IFNAME|IFINDEX> <IFNAME|IFINDEX> ...\n"
131 " -N enforce native mode\n"
132 " -F force loading prog\n"
133 " -X load xdp program on egress\n",
137 int main(int argc, char **argv)
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;
150 while ((opt = getopt(argc, argv, "SNFX")) != -1) {
153 xdp_flags |= XDP_FLAGS_SKB_MODE;
156 /* default, set below */
159 xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
162 attach_egress_prog = true;
165 usage(basename(argv[0]));
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");
177 if (optind == argc) {
178 printf("usage: %s <IFNAME|IFINDEX> <IFNAME|IFINDEX> ...\n", argv[0]);
182 printf("Get interfaces");
183 for (i = 0; i < MAX_IFACE_NUM && argv[optind + i]; i++) {
184 ifaces[i] = if_nametoindex(argv[optind + i]);
186 ifaces[i] = strtoul(argv[optind + i], NULL, 0);
187 if (!if_indextoname(ifaces[i], ifname)) {
188 perror("Invalid interface name or i");
192 /* Find the largest index number */
193 if (ifaces[i] > max_ifindex)
194 max_ifindex = ifaces[i];
196 printf(" %d", ifaces[i]);
200 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
202 obj = bpf_object__open(filename);
203 if (libbpf_get_error(obj)) {
204 printf("ERROR: opening BPF object file failed\n");
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);
214 printf("ERROR: reset mac map size failed\n");
219 /* load BPF program */
220 if (bpf_object__load(obj)) {
221 printf("ERROR: loading BPF object file failed\n");
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");
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");
232 if (!ingress_prog || forward_map_fd < 0) {
233 printf("finding ingress_prog/forward_map in obj file failed\n");
237 ingress_prog_fd = bpf_program__fd(ingress_prog);
238 if (ingress_prog_fd < 0) {
239 printf("find ingress_prog fd failed\n");
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");
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");
256 /* Find egress prog fd */
257 egress_prog = bpf_object__find_program_by_name(obj, "xdp_devmap_prog");
259 printf("finding egress_prog in obj file failed\n");
262 egress_prog_fd = bpf_program__fd(egress_prog);
263 if (egress_prog_fd < 0) {
264 printf("find egress_prog fd failed\n");
269 /* Remove attached program when program is interrupted or killed */
270 signal(SIGINT, int_exit);
271 signal(SIGTERM, int_exit);
273 /* Init forward multicast groups */
274 for (i = 0; ifaces[i] > 0; i++) {
277 /* bind prog_fd to each interface */
278 ret = bpf_set_link_xdp_fd(ifindex, ingress_prog_fd, xdp_flags);
280 printf("Set xdp fd failed on %d\n", ifindex);
284 /* Add all the interfaces to forward group and attach
285 * egress devmap programe if exist
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);
291 perror("bpf_map_update_elem forward_map");