Blame tc/m_bpf.c

Packit Service 3880ab
/*
Packit Service 3880ab
 * m_bpf.c	BPF based action module
Packit Service 3880ab
 *
Packit Service 3880ab
 *              This program is free software; you can redistribute 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:     Jiri Pirko <jiri@resnulli.us>
Packit Service 3880ab
 *              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
#include <linux/tc_act/tc_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_ACT;
Packit Service 3880ab
Packit Service 3880ab
static void explain(void)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(stderr,
Packit Service 3880ab
		"Usage: ... bpf ... [ index INDEX ]\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 ACT_NAME ] [ export UDS_FILE ]"
Packit Service 3880ab
		" [ verbose ]\n"
Packit Service 3880ab
		" object-pinned FILE\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 ACT_NAME refers to the section name containing the\n"
Packit Service 3880ab
		"action (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
		"Where optionally INDEX points to an existing action, or\n"
Packit Service 3880ab
		"explicitly specifies an action index upon creation.\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_ACT_BPF_OPS_LEN, ops_len);
Packit Service 3880ab
	addattr_l(nl, MAX_MSG, TCA_ACT_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_ACT_BPF_FD, fd);
Packit Service 3880ab
	addattrstrz(nl, MAX_MSG, TCA_ACT_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 action_util *a, int *ptr_argc, char ***ptr_argv,
Packit Service 3880ab
			 int tca_id, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	const char *bpf_obj = NULL, *bpf_uds_name = NULL;
Packit Service 3880ab
	struct tc_act_bpf parm = {};
Packit Service 3880ab
	struct bpf_cfg_in cfg = {};
Packit Service 3880ab
	bool seen_run = false;
Packit Service 3880ab
	struct rtattr *tail;
Packit Service 3880ab
	int argc, ret = 0;
Packit Service 3880ab
	char **argv;
Packit Service 3880ab
Packit Service 3880ab
	argv = *ptr_argv;
Packit Service 3880ab
	argc = *ptr_argc;
Packit Service 3880ab
Packit Service 3880ab
	if (matches(*argv, "bpf") != 0)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
	tail = addattr_nest(n, MAX_MSG, tca_id);
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_and_load_common(&cfg, &bpf_cb_ops, n))
Packit Service 3880ab
				return -1;
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, "help") == 0) {
Packit Service 3880ab
			explain();
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		} else if (matches(*argv, "index") == 0) {
Packit Service 3880ab
			break;
Packit Service 3880ab
		} else {
Packit Service 3880ab
			if (!seen_run)
Packit Service 3880ab
				goto opt_bpf;
Packit Service 3880ab
			break;
Packit Service 3880ab
		}
Packit Service 3880ab
Packit Service 3880ab
		NEXT_ARG_FWD();
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	parse_action_control_dflt(&argc, &argv, &parm.action,
Packit Service 3880ab
				  false, TC_ACT_PIPE);
Packit Service 3880ab
Packit Service 3880ab
	if (argc) {
Packit Service 3880ab
		if (matches(*argv, "index") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_u32(&parm.index, *argv, 10)) {
Packit Service 3880ab
				fprintf(stderr, "bpf: Illegal \"index\"\n");
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
Packit Service 3880ab
	addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm));
Packit Service 3880ab
	addattr_nest_end(n, 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
	*ptr_argc = argc;
Packit Service 3880ab
	*ptr_argv = argv;
Packit Service 3880ab
Packit Service 3880ab
	return ret;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
Packit Service 3880ab
	struct tc_act_bpf *parm;
Packit Service 3880ab
	int d_ok = 0;
Packit Service 3880ab
Packit Service 3880ab
	if (arg == NULL)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);
Packit Service 3880ab
Packit Service 3880ab
	if (!tb[TCA_ACT_BPF_PARMS]) {
Packit Service 3880ab
		fprintf(stderr, "Missing bpf parameters\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
Packit Service 3880ab
	print_string(PRINT_ANY, "kind", "%s ", "bpf");
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_ACT_BPF_NAME])
Packit Service 3880ab
		print_string(PRINT_ANY, "bpf_name", "%s ",
Packit Service 3880ab
			     rta_getattr_str(tb[TCA_ACT_BPF_NAME]));
Packit Service 3880ab
	if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) {
Packit Service 3880ab
		bpf_print_ops(tb[TCA_ACT_BPF_OPS],
Packit Service 3880ab
			      rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));
Packit Service 3880ab
		print_string(PRINT_FP, NULL, "%s", " ");
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_ACT_BPF_ID])
Packit Service 3880ab
		d_ok = bpf_dump_prog_info(f,
Packit Service 3880ab
					  rta_getattr_u32(tb[TCA_ACT_BPF_ID]));
Packit Service 3880ab
	if (!d_ok && tb[TCA_ACT_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_ACT_BPF_TAG]),
Packit Service 3880ab
			     RTA_PAYLOAD(tb[TCA_ACT_BPF_TAG]),
Packit Service 3880ab
			     b, sizeof(b)));
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	print_action_control(f, "default-action ", parm->action, _SL_);
Packit Service 3880ab
	print_uint(PRINT_ANY, "index", "\t index %u", parm->index);
Packit Service 3880ab
	print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
Packit Service 3880ab
	print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
Packit Service 3880ab
Packit Service 3880ab
	if (show_stats) {
Packit Service 3880ab
		if (tb[TCA_ACT_BPF_TM]) {
Packit Service 3880ab
			struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]);
Packit Service 3880ab
Packit Service 3880ab
			print_tm(f, tm);
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	fprintf(f, "\n ");
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
struct action_util bpf_action_util = {
Packit Service 3880ab
	.id		= "bpf",
Packit Service 3880ab
	.parse_aopt	= bpf_parse_opt,
Packit Service 3880ab
	.print_aopt	= bpf_print_opt,
Packit Service 3880ab
};