Blame tc/m_bpf.c

Packit d3f73b
/*
Packit d3f73b
 * m_bpf.c	BPF based action module
Packit d3f73b
 *
Packit d3f73b
 *              This program is free software; you can redistribute it and/or
Packit d3f73b
 *              modify it under the terms of the GNU General Public License
Packit d3f73b
 *              as published by the Free Software Foundation; either version
Packit d3f73b
 *              2 of the License, or (at your option) any later version.
Packit d3f73b
 *
Packit d3f73b
 * Authors:     Jiri Pirko <jiri@resnulli.us>
Packit d3f73b
 *              Daniel Borkmann <daniel@iogearbox.net>
Packit d3f73b
 */
Packit d3f73b
Packit d3f73b
#include <stdio.h>
Packit d3f73b
#include <stdlib.h>
Packit d3f73b
Packit d3f73b
#include <linux/bpf.h>
Packit d3f73b
#include <linux/tc_act/tc_bpf.h>
Packit d3f73b
Packit d3f73b
#include "utils.h"
Packit d3f73b
Packit d3f73b
#include "tc_util.h"
Packit d3f73b
#include "bpf_util.h"
Packit d3f73b
Packit d3f73b
static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_ACT;
Packit d3f73b
Packit d3f73b
static void explain(void)
Packit d3f73b
{
Packit d3f73b
	fprintf(stderr,
Packit d3f73b
		"Usage: ... bpf ... [ index INDEX ]\n"
Packit d3f73b
		"\n"
Packit d3f73b
		"BPF use case:\n"
Packit d3f73b
		" bytecode BPF_BYTECODE\n"
Packit d3f73b
		" bytecode-file FILE\n"
Packit d3f73b
		"\n"
Packit d3f73b
		"eBPF use case:\n"
Packit d3f73b
		" object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]"
Packit d3f73b
		" [ verbose ]\n"
Packit d3f73b
		" object-pinned FILE\n"
Packit d3f73b
		"\n"
Packit d3f73b
		"Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n"
Packit d3f73b
		"c,t,f,k and s are decimals; s denotes number of 4-tuples\n"
Packit d3f73b
		"\n"
Packit d3f73b
		"Where FILE points to a file containing the BPF_BYTECODE string,\n"
Packit d3f73b
		"an ELF file containing eBPF map definitions and bytecode, or a\n"
Packit d3f73b
		"pinned eBPF program.\n"
Packit d3f73b
		"\n"
Packit d3f73b
		"Where ACT_NAME refers to the section name containing the\n"
Packit d3f73b
		"action (default \'%s\').\n"
Packit d3f73b
		"\n"
Packit d3f73b
		"Where UDS_FILE points to a unix domain socket file in order\n"
Packit d3f73b
		"to hand off control of all created eBPF maps to an agent.\n"
Packit d3f73b
		"\n"
Packit d3f73b
		"Where optionally INDEX points to an existing action, or\n"
Packit d3f73b
		"explicitly specifies an action index upon creation.\n",
Packit d3f73b
		bpf_prog_to_default_section(bpf_type));
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
static void bpf_cbpf_cb(void *nl, const struct sock_filter *ops, int ops_len)
Packit d3f73b
{
Packit d3f73b
	addattr16(nl, MAX_MSG, TCA_ACT_BPF_OPS_LEN, ops_len);
Packit d3f73b
	addattr_l(nl, MAX_MSG, TCA_ACT_BPF_OPS, ops,
Packit d3f73b
		  ops_len * sizeof(struct sock_filter));
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
static void bpf_ebpf_cb(void *nl, int fd, const char *annotation)
Packit d3f73b
{
Packit d3f73b
	addattr32(nl, MAX_MSG, TCA_ACT_BPF_FD, fd);
Packit d3f73b
	addattrstrz(nl, MAX_MSG, TCA_ACT_BPF_NAME, annotation);
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
static const struct bpf_cfg_ops bpf_cb_ops = {
Packit d3f73b
	.cbpf_cb = bpf_cbpf_cb,
Packit d3f73b
	.ebpf_cb = bpf_ebpf_cb,
Packit d3f73b
};
Packit d3f73b
Packit d3f73b
static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv,
Packit d3f73b
			 int tca_id, struct nlmsghdr *n)
Packit d3f73b
{
Packit d3f73b
	const char *bpf_obj = NULL, *bpf_uds_name = NULL;
Packit d3f73b
	struct tc_act_bpf parm = {};
Packit d3f73b
	struct bpf_cfg_in cfg = {};
Packit d3f73b
	bool seen_run = false;
Packit d3f73b
	struct rtattr *tail;
Packit d3f73b
	int argc, ret = 0;
Packit d3f73b
	char **argv;
Packit d3f73b
Packit d3f73b
	argv = *ptr_argv;
Packit d3f73b
	argc = *ptr_argc;
Packit d3f73b
Packit d3f73b
	if (matches(*argv, "bpf") != 0)
Packit d3f73b
		return -1;
Packit d3f73b
Packit d3f73b
	NEXT_ARG();
Packit d3f73b
Packit d3f73b
	tail = addattr_nest(n, MAX_MSG, tca_id);
Packit d3f73b
Packit d3f73b
	while (argc > 0) {
Packit d3f73b
		if (matches(*argv, "run") == 0) {
Packit d3f73b
			NEXT_ARG();
Packit d3f73b
Packit d3f73b
			if (seen_run)
Packit d3f73b
				duparg("run", *argv);
Packit d3f73b
opt_bpf:
Packit d3f73b
			seen_run = true;
Packit d3f73b
			cfg.type = bpf_type;
Packit d3f73b
			cfg.argc = argc;
Packit d3f73b
			cfg.argv = argv;
Packit d3f73b
Packit d3f73b
			if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, n))
Packit d3f73b
				return -1;
Packit d3f73b
Packit d3f73b
			argc = cfg.argc;
Packit d3f73b
			argv = cfg.argv;
Packit d3f73b
Packit d3f73b
			bpf_obj = cfg.object;
Packit d3f73b
			bpf_uds_name = cfg.uds;
Packit d3f73b
		} else if (matches(*argv, "help") == 0) {
Packit d3f73b
			explain();
Packit d3f73b
			return -1;
Packit d3f73b
		} else if (matches(*argv, "index") == 0) {
Packit d3f73b
			break;
Packit d3f73b
		} else {
Packit d3f73b
			if (!seen_run)
Packit d3f73b
				goto opt_bpf;
Packit d3f73b
			break;
Packit d3f73b
		}
Packit d3f73b
Packit d3f73b
		NEXT_ARG_FWD();
Packit d3f73b
	}
Packit d3f73b
Packit d3f73b
	parse_action_control_dflt(&argc, &argv, &parm.action,
Packit d3f73b
				  false, TC_ACT_PIPE);
Packit d3f73b
Packit d3f73b
	if (argc) {
Packit d3f73b
		if (matches(*argv, "index") == 0) {
Packit d3f73b
			NEXT_ARG();
Packit d3f73b
			if (get_u32(&parm.index, *argv, 10)) {
Packit d3f73b
				fprintf(stderr, "bpf: Illegal \"index\"\n");
Packit d3f73b
				return -1;
Packit d3f73b
			}
Packit d3f73b
Packit d3f73b
			NEXT_ARG_FWD();
Packit d3f73b
		}
Packit d3f73b
	}
Packit d3f73b
Packit d3f73b
	addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm));
Packit d3f73b
	addattr_nest_end(n, tail);
Packit d3f73b
Packit d3f73b
	if (bpf_uds_name)
Packit d3f73b
		ret = bpf_send_map_fds(bpf_uds_name, bpf_obj);
Packit d3f73b
Packit d3f73b
	*ptr_argc = argc;
Packit d3f73b
	*ptr_argv = argv;
Packit d3f73b
Packit d3f73b
	return ret;
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
Packit d3f73b
{
Packit d3f73b
	struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
Packit d3f73b
	struct tc_act_bpf *parm;
Packit d3f73b
	int d_ok = 0;
Packit d3f73b
Packit d3f73b
	if (arg == NULL)
Packit d3f73b
		return -1;
Packit d3f73b
Packit d3f73b
	parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);
Packit d3f73b
Packit d3f73b
	if (!tb[TCA_ACT_BPF_PARMS]) {
Packit d3f73b
		fprintf(stderr, "Missing bpf parameters\n");
Packit d3f73b
		return -1;
Packit d3f73b
	}
Packit d3f73b
Packit d3f73b
	parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
Packit d3f73b
	print_string(PRINT_ANY, "kind", "%s ", "bpf");
Packit d3f73b
Packit d3f73b
	if (tb[TCA_ACT_BPF_NAME])
Packit d3f73b
		print_string(PRINT_ANY, "bpf_name", "%s ",
Packit d3f73b
			     rta_getattr_str(tb[TCA_ACT_BPF_NAME]));
Packit d3f73b
	if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) {
Packit d3f73b
		bpf_print_ops(tb[TCA_ACT_BPF_OPS],
Packit d3f73b
			      rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));
Packit d3f73b
		print_string(PRINT_FP, NULL, "%s", " ");
Packit d3f73b
	}
Packit d3f73b
Packit d3f73b
	if (tb[TCA_ACT_BPF_ID])
Packit d3f73b
		d_ok = bpf_dump_prog_info(f,
Packit d3f73b
					  rta_getattr_u32(tb[TCA_ACT_BPF_ID]));
Packit d3f73b
	if (!d_ok && tb[TCA_ACT_BPF_TAG]) {
Packit d3f73b
		SPRINT_BUF(b);
Packit d3f73b
Packit d3f73b
		print_string(PRINT_ANY, "tag", "tag %s ",
Packit d3f73b
			     hexstring_n2a(RTA_DATA(tb[TCA_ACT_BPF_TAG]),
Packit d3f73b
			     RTA_PAYLOAD(tb[TCA_ACT_BPF_TAG]),
Packit d3f73b
			     b, sizeof(b)));
Packit d3f73b
	}
Packit d3f73b
Packit d3f73b
	print_action_control(f, "default-action ", parm->action, _SL_);
Packit d3f73b
	print_uint(PRINT_ANY, "index", "\t index %u", parm->index);
Packit d3f73b
	print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
Packit d3f73b
	print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
Packit d3f73b
Packit d3f73b
	if (show_stats) {
Packit d3f73b
		if (tb[TCA_ACT_BPF_TM]) {
Packit d3f73b
			struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]);
Packit d3f73b
Packit d3f73b
			print_tm(f, tm);
Packit d3f73b
		}
Packit d3f73b
	}
Packit d3f73b
Packit d3f73b
	fprintf(f, "\n ");
Packit d3f73b
	return 0;
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
struct action_util bpf_action_util = {
Packit d3f73b
	.id		= "bpf",
Packit d3f73b
	.parse_aopt	= bpf_parse_opt,
Packit d3f73b
	.print_aopt	= bpf_print_opt,
Packit d3f73b
};