Blame tc/f_bpf.c

Packit Service 3880ab
/*
Packit Service 3880ab
 * f_bpf.c	BPF-based Classifier
Packit Service 3880ab
 *
Packit Service 3880ab
 *		This program is free software; you can distribute it and/or
Packit Service 3880ab
 *		modify it under the terms of the GNU General Public License
Packit Service 3880ab
 *		as published by the Free Software Foundation; either version
Packit Service 3880ab
 *		2 of the License, or (at your option) any later version.
Packit Service 3880ab
 *
Packit Service 3880ab
 * Authors:	Daniel Borkmann <daniel@iogearbox.net>
Packit Service 3880ab
 */
Packit Service 3880ab
Packit Service 3880ab
#include <stdio.h>
Packit Service 3880ab
#include <stdlib.h>
Packit Service 3880ab
Packit Service 3880ab
#include <linux/bpf.h>
Packit Service 3880ab
Packit Service 3880ab
#include "utils.h"
Packit Service 3880ab
Packit Service 3880ab
#include "tc_util.h"
Packit Service 3880ab
#include "bpf_util.h"
Packit Service 3880ab
Packit Service 3880ab
static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_CLS;
Packit Service 3880ab
Packit Service 3880ab
static void explain(void)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(stderr,
Packit Service 3880ab
		"Usage: ... bpf ...\n"
Packit Service 3880ab
		"\n"
Packit Service 3880ab
		"BPF use case:\n"
Packit Service 3880ab
		" bytecode BPF_BYTECODE\n"
Packit Service 3880ab
		" bytecode-file FILE\n"
Packit Service 3880ab
		"\n"
Packit Service 3880ab
		"eBPF use case:\n"
Packit Service 3880ab
		" object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]"
Packit Service 3880ab
		" [ verbose ] [ direct-action ] [ skip_hw | skip_sw ]\n"
Packit Service 3880ab
		" object-pinned FILE [ direct-action ] [ skip_hw | skip_sw ]\n"
Packit Service 3880ab
		"\n"
Packit Service 3880ab
		"Common remaining options:\n"
Packit Service 3880ab
		" [ action ACTION_SPEC ]\n"
Packit Service 3880ab
		" [ classid CLASSID ]\n"
Packit Service 3880ab
		"\n"
Packit Service 3880ab
		"Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n"
Packit Service 3880ab
		"c,t,f,k and s are decimals; s denotes number of 4-tuples\n"
Packit Service 3880ab
		"\n"
Packit Service 3880ab
		"Where FILE points to a file containing the BPF_BYTECODE string,\n"
Packit Service 3880ab
		"an ELF file containing eBPF map definitions and bytecode, or a\n"
Packit Service 3880ab
		"pinned eBPF program.\n"
Packit Service 3880ab
		"\n"
Packit Service 3880ab
		"Where CLS_NAME refers to the section name containing the\n"
Packit Service 3880ab
		"classifier (default \'%s\').\n"
Packit Service 3880ab
		"\n"
Packit Service 3880ab
		"Where UDS_FILE points to a unix domain socket file in order\n"
Packit Service 3880ab
		"to hand off control of all created eBPF maps to an agent.\n"
Packit Service 3880ab
		"\n"
Packit Service 3880ab
		"ACTION_SPEC := ... look at individual actions\n"
Packit Service 3880ab
		"NOTE: CLASSID is parsed as hexadecimal input.\n",
Packit Service 3880ab
		bpf_prog_to_default_section(bpf_type));
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void bpf_cbpf_cb(void *nl, const struct sock_filter *ops, int ops_len)
Packit Service 3880ab
{
Packit Service 3880ab
	addattr16(nl, MAX_MSG, TCA_BPF_OPS_LEN, ops_len);
Packit Service 3880ab
	addattr_l(nl, MAX_MSG, TCA_BPF_OPS, ops,
Packit Service 3880ab
		  ops_len * sizeof(struct sock_filter));
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void bpf_ebpf_cb(void *nl, int fd, const char *annotation)
Packit Service 3880ab
{
Packit Service 3880ab
	addattr32(nl, MAX_MSG, TCA_BPF_FD, fd);
Packit Service 3880ab
	addattrstrz(nl, MAX_MSG, TCA_BPF_NAME, annotation);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static const struct bpf_cfg_ops bpf_cb_ops = {
Packit Service 3880ab
	.cbpf_cb = bpf_cbpf_cb,
Packit Service 3880ab
	.ebpf_cb = bpf_ebpf_cb,
Packit Service 3880ab
};
Packit Service 3880ab
Packit Service 3880ab
static int bpf_parse_opt(struct filter_util *qu, char *handle,
Packit Service 3880ab
			 int argc, char **argv, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	const char *bpf_obj = NULL, *bpf_uds_name = NULL;
Packit Service 3880ab
	struct tcmsg *t = NLMSG_DATA(n);
Packit Service 3880ab
	unsigned int bpf_gen_flags = 0;
Packit Service 3880ab
	unsigned int bpf_flags = 0;
Packit Service 3880ab
	struct bpf_cfg_in cfg = {};
Packit Service 3880ab
	bool seen_run = false;
Packit Service 3880ab
	bool skip_sw = false;
Packit Service 3880ab
	struct rtattr *tail;
Packit Service 3880ab
	int ret = 0;
Packit Service 3880ab
Packit Service 3880ab
	if (handle) {
Packit Service 3880ab
		if (get_u32(&t->tcm_handle, handle, 0)) {
Packit Service 3880ab
			fprintf(stderr, "Illegal \"handle\"\n");
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (argc == 0)
Packit Service 3880ab
		return 0;
Packit Service 3880ab
Packit Service 3880ab
	tail = (struct rtattr *)(((void *)n) + NLMSG_ALIGN(n->nlmsg_len));
Packit Service 3880ab
	addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
Packit Service 3880ab
Packit Service 3880ab
	while (argc > 0) {
Packit Service 3880ab
		if (matches(*argv, "run") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
			if (seen_run)
Packit Service 3880ab
				duparg("run", *argv);
Packit Service 3880ab
opt_bpf:
Packit Service 3880ab
			seen_run = true;
Packit Service 3880ab
			cfg.type = bpf_type;
Packit Service 3880ab
			cfg.argc = argc;
Packit Service 3880ab
			cfg.argv = argv;
Packit Service 3880ab
Packit Service 3880ab
			if (bpf_parse_common(&cfg, &bpf_cb_ops) < 0) {
Packit Service 3880ab
				fprintf(stderr,
Packit Service 3880ab
					"Unable to parse bpf command line\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			argc = cfg.argc;
Packit Service 3880ab
			argv = cfg.argv;
Packit Service 3880ab
Packit Service 3880ab
			bpf_obj = cfg.object;
Packit Service 3880ab
			bpf_uds_name = cfg.uds;
Packit Service 3880ab
		} else if (matches(*argv, "classid") == 0 ||
Packit Service 3880ab
			   matches(*argv, "flowid") == 0) {
Packit Service 3880ab
			unsigned int handle;
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_tc_classid(&handle, *argv)) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"classid\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			addattr32(n, MAX_MSG, TCA_BPF_CLASSID, handle);
Packit Service 3880ab
		} else if (matches(*argv, "direct-action") == 0 ||
Packit Service 3880ab
			   matches(*argv, "da") == 0) {
Packit Service 3880ab
			bpf_flags |= TCA_BPF_FLAG_ACT_DIRECT;
Packit Service 3880ab
		} else if (matches(*argv, "skip_hw") == 0) {
Packit Service 3880ab
			bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_HW;
Packit Service 3880ab
		} else if (matches(*argv, "skip_sw") == 0) {
Packit Service 3880ab
			bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_SW;
Packit Service 3880ab
			skip_sw = true;
Packit Service 3880ab
		} else if (matches(*argv, "action") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"action\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			continue;
Packit Service 3880ab
		} else if (matches(*argv, "police") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (parse_police(&argc, &argv, TCA_BPF_POLICE, n)) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"police\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			continue;
Packit Service 3880ab
		} else if (matches(*argv, "help") == 0) {
Packit Service 3880ab
			explain();
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		} else {
Packit Service 3880ab
			if (!seen_run)
Packit Service 3880ab
				goto opt_bpf;
Packit Service 3880ab
Packit Service 3880ab
			fprintf(stderr, "What is \"%s\"?\n", *argv);
Packit Service 3880ab
			explain();
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
Packit Service 3880ab
		NEXT_ARG_FWD();
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (skip_sw)
Packit Service 3880ab
		cfg.ifindex = t->tcm_ifindex;
Packit Service 3880ab
	if (bpf_load_common(&cfg, &bpf_cb_ops, n) < 0) {
Packit Service 3880ab
		fprintf(stderr, "Unable to load program\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (bpf_gen_flags)
Packit Service 3880ab
		addattr32(n, MAX_MSG, TCA_BPF_FLAGS_GEN, bpf_gen_flags);
Packit Service 3880ab
	if (bpf_flags)
Packit Service 3880ab
		addattr32(n, MAX_MSG, TCA_BPF_FLAGS, bpf_flags);
Packit Service 3880ab
Packit Service 3880ab
	tail->rta_len = (((void *)n) + n->nlmsg_len) - (void *)tail;
Packit Service 3880ab
Packit Service 3880ab
	if (bpf_uds_name)
Packit Service 3880ab
		ret = bpf_send_map_fds(bpf_uds_name, bpf_obj);
Packit Service 3880ab
Packit Service 3880ab
	return ret;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int bpf_print_opt(struct filter_util *qu, FILE *f,
Packit Service 3880ab
			 struct rtattr *opt, __u32 handle)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[TCA_BPF_MAX + 1];
Packit Service 3880ab
	int dump_ok = 0;
Packit Service 3880ab
Packit Service 3880ab
	if (opt == NULL)
Packit Service 3880ab
		return 0;
Packit Service 3880ab
Packit Service 3880ab
	parse_rtattr_nested(tb, TCA_BPF_MAX, opt);
Packit Service 3880ab
Packit Service 3880ab
	if (handle)
Packit Service 3880ab
		print_0xhex(PRINT_ANY, "handle", "handle %#llx ", handle);
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_BPF_CLASSID]) {
Packit Service 3880ab
		SPRINT_BUF(b1);
Packit Service 3880ab
		print_string(PRINT_ANY, "flowid", "flowid %s ",
Packit Service 3880ab
			sprint_tc_classid(rta_getattr_u32(tb[TCA_BPF_CLASSID]), b1));
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_BPF_NAME])
Packit Service 3880ab
		print_string(PRINT_ANY, "bpf_name", "%s ",
Packit Service 3880ab
			     rta_getattr_str(tb[TCA_BPF_NAME]));
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_BPF_FLAGS]) {
Packit Service 3880ab
		unsigned int flags = rta_getattr_u32(tb[TCA_BPF_FLAGS]);
Packit Service 3880ab
Packit Service 3880ab
		if (flags & TCA_BPF_FLAG_ACT_DIRECT)
Packit Service 3880ab
			print_bool(PRINT_ANY,
Packit Service 3880ab
				   "direct-action", "direct-action ", true);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_BPF_FLAGS_GEN]) {
Packit Service 3880ab
		unsigned int flags =
Packit Service 3880ab
			rta_getattr_u32(tb[TCA_BPF_FLAGS_GEN]);
Packit Service 3880ab
Packit Service 3880ab
		if (flags & TCA_CLS_FLAGS_SKIP_HW)
Packit Service 3880ab
			print_bool(PRINT_ANY, "skip_hw", "skip_hw ", true);
Packit Service 3880ab
		if (flags & TCA_CLS_FLAGS_SKIP_SW)
Packit Service 3880ab
			print_bool(PRINT_ANY, "skip_sw", "skip_sw ", true);
Packit Service 3880ab
		if (flags & TCA_CLS_FLAGS_IN_HW)
Packit Service 3880ab
			print_bool(PRINT_ANY, "in_hw", "in_hw ", true);
Packit Service 3880ab
		else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
Packit Service 3880ab
			print_bool(PRINT_ANY,
Packit Service 3880ab
				   "not_in_hw", "not_in_hw ", true);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN])
Packit Service 3880ab
		bpf_print_ops(tb[TCA_BPF_OPS],
Packit Service 3880ab
			      rta_getattr_u16(tb[TCA_BPF_OPS_LEN]));
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_BPF_ID])
Packit Service 3880ab
		dump_ok = bpf_dump_prog_info(f, rta_getattr_u32(tb[TCA_BPF_ID]));
Packit Service 3880ab
	if (!dump_ok && tb[TCA_BPF_TAG]) {
Packit Service 3880ab
		SPRINT_BUF(b);
Packit Service 3880ab
Packit Service 3880ab
		print_string(PRINT_ANY, "tag", "tag %s ",
Packit Service 3880ab
			     hexstring_n2a(RTA_DATA(tb[TCA_BPF_TAG]),
Packit Service 3880ab
			     RTA_PAYLOAD(tb[TCA_BPF_TAG]), b, sizeof(b)));
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_BPF_POLICE]) {
Packit Service 3880ab
		print_nl();
Packit Service 3880ab
		tc_print_police(f, tb[TCA_BPF_POLICE]);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_BPF_ACT])
Packit Service 3880ab
		tc_print_action(f, tb[TCA_BPF_ACT], 0);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
struct filter_util bpf_filter_util = {
Packit Service 3880ab
	.id		= "bpf",
Packit Service 3880ab
	.parse_fopt	= bpf_parse_opt,
Packit Service 3880ab
	.print_fopt	= bpf_print_opt,
Packit Service 3880ab
};