18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2017-18 David Ahern <dsahern@gmail.com>
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
58c2ecf20Sopenharmony_ci * modify it under the terms of version 2 of the GNU General Public
68c2ecf20Sopenharmony_ci * License as published by the Free Software Foundation.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
98c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
108c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
118c2ecf20Sopenharmony_ci * General Public License for more details.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/bpf.h>
158c2ecf20Sopenharmony_ci#include <linux/if_link.h>
168c2ecf20Sopenharmony_ci#include <linux/limits.h>
178c2ecf20Sopenharmony_ci#include <net/if.h>
188c2ecf20Sopenharmony_ci#include <errno.h>
198c2ecf20Sopenharmony_ci#include <stdio.h>
208c2ecf20Sopenharmony_ci#include <stdlib.h>
218c2ecf20Sopenharmony_ci#include <stdbool.h>
228c2ecf20Sopenharmony_ci#include <string.h>
238c2ecf20Sopenharmony_ci#include <unistd.h>
248c2ecf20Sopenharmony_ci#include <fcntl.h>
258c2ecf20Sopenharmony_ci#include <libgen.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
288c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic int do_attach(int idx, int prog_fd, int map_fd, const char *name)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	int err;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	err = bpf_set_link_xdp_fd(idx, prog_fd, xdp_flags);
378c2ecf20Sopenharmony_ci	if (err < 0) {
388c2ecf20Sopenharmony_ci		printf("ERROR: failed to attach program to %s\n", name);
398c2ecf20Sopenharmony_ci		return err;
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	/* Adding ifindex as a possible egress TX port */
438c2ecf20Sopenharmony_ci	err = bpf_map_update_elem(map_fd, &idx, &idx, 0);
448c2ecf20Sopenharmony_ci	if (err)
458c2ecf20Sopenharmony_ci		printf("ERROR: failed using device %s as TX-port\n", name);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	return err;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int do_detach(int idx, const char *name)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	int err;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	err = bpf_set_link_xdp_fd(idx, -1, xdp_flags);
558c2ecf20Sopenharmony_ci	if (err < 0)
568c2ecf20Sopenharmony_ci		printf("ERROR: failed to detach program from %s\n", name);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* TODO: Remember to cleanup map, when adding use of shared map
598c2ecf20Sopenharmony_ci	 *  bpf_map_delete_elem((map_fd, &idx);
608c2ecf20Sopenharmony_ci	 */
618c2ecf20Sopenharmony_ci	return err;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void usage(const char *prog)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	fprintf(stderr,
678c2ecf20Sopenharmony_ci		"usage: %s [OPTS] interface-list\n"
688c2ecf20Sopenharmony_ci		"\nOPTS:\n"
698c2ecf20Sopenharmony_ci		"    -d    detach program\n"
708c2ecf20Sopenharmony_ci		"    -D    direct table lookups (skip fib rules)\n",
718c2ecf20Sopenharmony_ci		prog);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ciint main(int argc, char **argv)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct bpf_prog_load_attr prog_load_attr = {
778c2ecf20Sopenharmony_ci		.prog_type	= BPF_PROG_TYPE_XDP,
788c2ecf20Sopenharmony_ci	};
798c2ecf20Sopenharmony_ci	const char *prog_name = "xdp_fwd";
808c2ecf20Sopenharmony_ci	struct bpf_program *prog;
818c2ecf20Sopenharmony_ci	int prog_fd, map_fd = -1;
828c2ecf20Sopenharmony_ci	char filename[PATH_MAX];
838c2ecf20Sopenharmony_ci	struct bpf_object *obj;
848c2ecf20Sopenharmony_ci	int opt, i, idx, err;
858c2ecf20Sopenharmony_ci	int attach = 1;
868c2ecf20Sopenharmony_ci	int ret = 0;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	while ((opt = getopt(argc, argv, ":dDSF")) != -1) {
898c2ecf20Sopenharmony_ci		switch (opt) {
908c2ecf20Sopenharmony_ci		case 'd':
918c2ecf20Sopenharmony_ci			attach = 0;
928c2ecf20Sopenharmony_ci			break;
938c2ecf20Sopenharmony_ci		case 'S':
948c2ecf20Sopenharmony_ci			xdp_flags |= XDP_FLAGS_SKB_MODE;
958c2ecf20Sopenharmony_ci			break;
968c2ecf20Sopenharmony_ci		case 'F':
978c2ecf20Sopenharmony_ci			xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
988c2ecf20Sopenharmony_ci			break;
998c2ecf20Sopenharmony_ci		case 'D':
1008c2ecf20Sopenharmony_ci			prog_name = "xdp_fwd_direct";
1018c2ecf20Sopenharmony_ci			break;
1028c2ecf20Sopenharmony_ci		default:
1038c2ecf20Sopenharmony_ci			usage(basename(argv[0]));
1048c2ecf20Sopenharmony_ci			return 1;
1058c2ecf20Sopenharmony_ci		}
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (!(xdp_flags & XDP_FLAGS_SKB_MODE))
1098c2ecf20Sopenharmony_ci		xdp_flags |= XDP_FLAGS_DRV_MODE;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (optind == argc) {
1128c2ecf20Sopenharmony_ci		usage(basename(argv[0]));
1138c2ecf20Sopenharmony_ci		return 1;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (attach) {
1178c2ecf20Sopenharmony_ci		snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
1188c2ecf20Sopenharmony_ci		prog_load_attr.file = filename;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci		if (access(filename, O_RDONLY) < 0) {
1218c2ecf20Sopenharmony_ci			printf("error accessing file %s: %s\n",
1228c2ecf20Sopenharmony_ci				filename, strerror(errno));
1238c2ecf20Sopenharmony_ci			return 1;
1248c2ecf20Sopenharmony_ci		}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci		err = bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd);
1278c2ecf20Sopenharmony_ci		if (err) {
1288c2ecf20Sopenharmony_ci			printf("Does kernel support devmap lookup?\n");
1298c2ecf20Sopenharmony_ci			/* If not, the error message will be:
1308c2ecf20Sopenharmony_ci			 *  "cannot pass map_type 14 into func bpf_map_lookup_elem#1"
1318c2ecf20Sopenharmony_ci			 */
1328c2ecf20Sopenharmony_ci			return 1;
1338c2ecf20Sopenharmony_ci		}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci		prog = bpf_object__find_program_by_title(obj, prog_name);
1368c2ecf20Sopenharmony_ci		prog_fd = bpf_program__fd(prog);
1378c2ecf20Sopenharmony_ci		if (prog_fd < 0) {
1388c2ecf20Sopenharmony_ci			printf("program not found: %s\n", strerror(prog_fd));
1398c2ecf20Sopenharmony_ci			return 1;
1408c2ecf20Sopenharmony_ci		}
1418c2ecf20Sopenharmony_ci		map_fd = bpf_map__fd(bpf_object__find_map_by_name(obj,
1428c2ecf20Sopenharmony_ci							"xdp_tx_ports"));
1438c2ecf20Sopenharmony_ci		if (map_fd < 0) {
1448c2ecf20Sopenharmony_ci			printf("map not found: %s\n", strerror(map_fd));
1458c2ecf20Sopenharmony_ci			return 1;
1468c2ecf20Sopenharmony_ci		}
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	for (i = optind; i < argc; ++i) {
1508c2ecf20Sopenharmony_ci		idx = if_nametoindex(argv[i]);
1518c2ecf20Sopenharmony_ci		if (!idx)
1528c2ecf20Sopenharmony_ci			idx = strtoul(argv[i], NULL, 0);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		if (!idx) {
1558c2ecf20Sopenharmony_ci			fprintf(stderr, "Invalid arg\n");
1568c2ecf20Sopenharmony_ci			return 1;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci		if (!attach) {
1598c2ecf20Sopenharmony_ci			err = do_detach(idx, argv[i]);
1608c2ecf20Sopenharmony_ci			if (err)
1618c2ecf20Sopenharmony_ci				ret = err;
1628c2ecf20Sopenharmony_ci		} else {
1638c2ecf20Sopenharmony_ci			err = do_attach(idx, prog_fd, map_fd, argv[i]);
1648c2ecf20Sopenharmony_ci			if (err)
1658c2ecf20Sopenharmony_ci				ret = err;
1668c2ecf20Sopenharmony_ci		}
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	return ret;
1708c2ecf20Sopenharmony_ci}
171