aboutsummaryrefslogtreecommitdiffstats
path: root/tc/m_bpf.c
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2015-04-01 17:57:44 +0200
committerStephen Hemminger <shemming@brocade.com>2015-04-10 13:31:19 -0700
commit6256f8c9e45f01187b297a576e148534a393c990 (patch)
tree503648c148d7778a9eb2a6afa86431cf8054d06d /tc/m_bpf.c
parentf0eb8da59a01557bd782a28c30fd1b458147403a (diff)
downloadplatform_external_iproute2-6256f8c9e45f01187b297a576e148534a393c990.tar.gz
platform_external_iproute2-6256f8c9e45f01187b297a576e148534a393c990.tar.bz2
platform_external_iproute2-6256f8c9e45f01187b297a576e148534a393c990.zip
tc, bpf: finalize eBPF support for cls and act front-end
This work finalizes both eBPF front-ends for the classifier and action part in tc, it allows for custom ELF section selection, a simplified tc command frontend (while keeping compat), reusing of common maps between classifier and actions residing in the same object file, and exporting of all map fds to an eBPF agent for handing off further control in user space. It also adds an extensive example of how eBPF can be used, and a minimal self-contained example agent that dumps map data. The example is well documented and hopefully provides a good starting point into programming cls_bpf and act_bpf. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Cc: Alexei Starovoitov <ast@plumgrid.com> Cc: Jiri Pirko <jiri@resnulli.us> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Acked-by: Alexei Starovoitov <ast@plumgrid.com> Acked-by: Thomas Graf <tgraf@suug.ch> Acked-by: Jiri Pirko <jiri@resnulli.us> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Diffstat (limited to 'tc/m_bpf.c')
-rw-r--r--tc/m_bpf.c128
1 files changed, 109 insertions, 19 deletions
diff --git a/tc/m_bpf.c b/tc/m_bpf.c
index bc6cc47a..c8175791 100644
--- a/tc/m_bpf.c
+++ b/tc/m_bpf.c
@@ -7,6 +7,7 @@
* 2 of the License, or (at your option) any later version.
*
* Authors: Jiri Pirko <jiri@resnulli.us>
+ * Daniel Borkmann <daniel@iogearbox.net>
*/
#include <stdio.h>
@@ -14,6 +15,8 @@
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
+#include <libgen.h>
+#include <linux/bpf.h>
#include <linux/tc_act/tc_bpf.h>
#include "utils.h"
@@ -21,16 +24,30 @@
#include "tc_util.h"
#include "tc_bpf.h"
+static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_ACT;
+
static void explain(void)
{
fprintf(stderr, "Usage: ... bpf ...\n");
fprintf(stderr, "\n");
- fprintf(stderr, " [inline]: run bytecode BPF_BYTECODE\n");
- fprintf(stderr, " [from file]: run bytecode-file FILE\n");
+ fprintf(stderr, "BPF use case:\n");
+ fprintf(stderr, " bytecode BPF_BYTECODE\n");
+ fprintf(stderr, " bytecode-file FILE\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "eBPF use case:\n");
+ fprintf(stderr, " object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
- fprintf(stderr, " c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
- fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string\n");
+ fprintf(stderr, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string,\n");
+ fprintf(stderr, "an ELF file containing eBPF map definitions and bytecode.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where ACT_NAME refers to the section name containing the\n");
+ fprintf(stderr, "action (default \'%s\').\n", bpf_default_section(bpf_type));
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where UDS_FILE points to a unix domain socket file in order\n");
+ fprintf(stderr, "to hand off control of all created eBPF maps to an agent.\n");
}
static void usage(void)
@@ -42,12 +59,17 @@ static void usage(void)
static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n)
{
- int argc = *argc_p;
- char **argv = *argv_p;
+ char **argv = *argv_p, bpf_name[256];
struct rtattr *tail;
struct tc_act_bpf parm = { 0 };
struct sock_filter bpf_ops[BPF_MAXINSNS];
+ bool ebpf = false, seen_run = false;
+ const char *bpf_uds_name = NULL;
+ const char *bpf_sec_name = NULL;
+ char *bpf_obj = NULL;
+ int argc = *argc_p, ret = 0;
__u16 bpf_len = 0;
+ __u32 bpf_fd = 0;
if (matches(*argv, "bpf") != 0)
return -1;
@@ -60,25 +82,70 @@ static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p,
int ret;
NEXT_ARG();
- if (strcmp(*argv, "bytecode-file") == 0) {
+opt_bpf:
+ bpf_sec_name = bpf_default_section(bpf_type);
+ seen_run = true;
+
+ if (strcmp(*argv, "bytecode-file") == 0 ||
+ strcmp(*argv, "bcf") == 0) {
from_file = true;
- } else if (strcmp(*argv, "bytecode") == 0) {
+ } else if (strcmp(*argv, "bytecode") == 0 ||
+ strcmp(*argv, "bc") == 0) {
from_file = false;
+ } else if (strcmp(*argv, "object-file") == 0 ||
+ strcmp(*argv, "obj") == 0) {
+ ebpf = true;
} else {
fprintf(stderr, "unexpected \"%s\"\n", *argv);
explain();
return -1;
}
+
NEXT_ARG();
- ret = bpf_parse_ops(argc, argv, bpf_ops, from_file);
+ if (ebpf) {
+ bpf_obj = *argv;
+ NEXT_ARG();
+
+ if (strcmp(*argv, "section") == 0 ||
+ strcmp(*argv, "sec") == 0) {
+ NEXT_ARG();
+ bpf_sec_name = *argv;
+ NEXT_ARG();
+ }
+ if (strcmp(*argv, "export") == 0 ||
+ strcmp(*argv, "exp") == 0) {
+ NEXT_ARG();
+ bpf_uds_name = *argv;
+ NEXT_ARG();
+ }
+
+ PREV_ARG();
+ }
+
+ ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name) :
+ bpf_parse_ops(argc, argv, bpf_ops, from_file);
if (ret < 0) {
- fprintf(stderr, "Illegal \"bytecode\"\n");
+ fprintf(stderr, "%s\n", ebpf ?
+ "Could not load object" :
+ "Illegal \"bytecode\"");
return -1;
}
- bpf_len = ret;
+
+ if (ebpf) {
+ bpf_obj = basename(bpf_obj);
+
+ snprintf(bpf_name, sizeof(bpf_name), "%s:[%s]",
+ bpf_obj, bpf_sec_name);
+
+ bpf_fd = ret;
+ } else {
+ bpf_len = ret;
+ }
} else if (matches(*argv, "help") == 0) {
usage();
} else {
+ if (!seen_run)
+ goto opt_bpf;
break;
}
argc--;
@@ -123,29 +190,42 @@ static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p,
}
}
- if (!bpf_len) {
+ if ((!bpf_len && !ebpf) || (!bpf_fd && ebpf)) {
fprintf(stderr, "bpf: Bytecode needs to be passed\n");
explain();
return -1;
}
tail = NLMSG_TAIL(n);
+
addattr_l(n, MAX_MSG, tca_id, NULL, 0);
addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm));
- addattr16(n, MAX_MSG, TCA_ACT_BPF_OPS_LEN, bpf_len);
- addattr_l(n, MAX_MSG, TCA_ACT_BPF_OPS, &bpf_ops,
- bpf_len * sizeof(struct sock_filter));
+
+ if (ebpf) {
+ addattr32(n, MAX_MSG, TCA_ACT_BPF_FD, bpf_fd);
+ addattrstrz(n, MAX_MSG, TCA_ACT_BPF_NAME, bpf_name);
+ } else {
+ addattr16(n, MAX_MSG, TCA_ACT_BPF_OPS_LEN, bpf_len);
+ addattr_l(n, MAX_MSG, TCA_ACT_BPF_OPS, &bpf_ops,
+ bpf_len * sizeof(struct sock_filter));
+ }
+
tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
*argc_p = argc;
*argv_p = argv;
- return 0;
+
+ if (bpf_uds_name)
+ ret = bpf_handoff_map_fds(bpf_uds_name, bpf_obj);
+
+ return ret;
}
static int print_bpf(struct action_util *au, FILE *f, struct rtattr *arg)
{
struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
struct tc_act_bpf *parm;
+ SPRINT_BUF(action_buf);
if (arg == NULL)
return -1;
@@ -156,15 +236,25 @@ static int print_bpf(struct action_util *au, FILE *f, struct rtattr *arg)
fprintf(f, "[NULL bpf parameters]");
return -1;
}
+
parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
- fprintf(f, " bpf ");
+ fprintf(f, "bpf ");
+
+ if (tb[TCA_ACT_BPF_NAME])
+ fprintf(f, "%s ", rta_getattr_str(tb[TCA_ACT_BPF_NAME]));
+ else if (tb[TCA_ACT_BPF_FD])
+ fprintf(f, "pfd %u ", rta_getattr_u32(tb[TCA_ACT_BPF_FD]));
- if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN])
+ if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) {
bpf_print_ops(f, tb[TCA_ACT_BPF_OPS],
rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));
+ fprintf(f, " ");
+ }
- fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt,
+ fprintf(f, "default-action %s\n", action_n2a(parm->action, action_buf,
+ sizeof(action_buf)));
+ fprintf(f, "\tindex %d ref %d bind %d", parm->index, parm->refcnt,
parm->bindcnt);
if (show_stats) {