diff mbox

[iproute2,2/2] tc: add support for BPF based actions

Message ID 1420649244-9574-2-git-send-email-jiri@resnulli.us
State Rejected, archived
Delegated to: stephen hemminger
Headers show

Commit Message

Jiri Pirko Jan. 7, 2015, 4:47 p.m. UTC
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
 include/linux/tc_act/tc_bpf.h |  31 +++++++
 tc/Makefile                   |   1 +
 tc/m_bpf.c                    | 183 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
 create mode 100644 include/linux/tc_act/tc_bpf.h
 create mode 100644 tc/m_bpf.c

Comments

Cong Wang Jan. 7, 2015, 6:50 p.m. UTC | #1
On Wed, Jan 7, 2015 at 8:47 AM, Jiri Pirko <jiri@resnulli.us> wrote:
> +       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, "\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, "\nACTION_SPEC := ... look at individual actions\n");
> +       fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");

Can we just use BPF transparently for gact? It is never user-friendly to
use this kind of bytecode even though I know there is a tool to "compile"
BPF.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiri Pirko Jan. 7, 2015, 7:52 p.m. UTC | #2
Wed, Jan 07, 2015 at 07:50:47PM CET, cwang@twopensource.com wrote:
>On Wed, Jan 7, 2015 at 8:47 AM, Jiri Pirko <jiri@resnulli.us> wrote:
>> +       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, "\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, "\nACTION_SPEC := ... look at individual actions\n");
>> +       fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
>
>Can we just use BPF transparently for gact?

Why to squash it there? I think it is much clearer to do this
separatelly.

>It is never user-friendly to
>use this kind of bytecode even though I know there is a tool to "compile"
>BPF.

Please see cls_bpf. It's already in-tree for some time. act_bpf just
completes this.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Cong Wang Jan. 7, 2015, 7:58 p.m. UTC | #3
On Wed, Jan 7, 2015 at 11:52 AM, Jiri Pirko <jiri@resnulli.us> wrote:
> Wed, Jan 07, 2015 at 07:50:47PM CET, cwang@twopensource.com wrote:
>>On Wed, Jan 7, 2015 at 8:47 AM, Jiri Pirko <jiri@resnulli.us> wrote:
>>> +       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, "\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, "\nACTION_SPEC := ... look at individual actions\n");
>>> +       fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
>>
>>Can we just use BPF transparently for gact?
>
> Why to squash it there? I think it is much clearer to do this
> separatelly.
>

Because they are both intended to drop/pass/pipe packets,
we don't have to make a separated one just because one is
using BPF one isn't.

>>It is never user-friendly to
>>use this kind of bytecode even though I know there is a tool to "compile"
>>BPF.
>
> Please see cls_bpf. It's already in-tree for some time. act_bpf just
> completes this.

Yeah, that is what I hate too.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Hemminger Jan. 14, 2015, 1:19 a.m. UTC | #4
On Wed,  7 Jan 2015 17:47:24 +0100
Jiri Pirko <jiri@resnulli.us> wrote:

> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
> ---
>  include/linux/tc_act/tc_bpf.h |  31 +++++++

The overall concept is fine, but the mechanics of file management
gets in the way.

All header files in the linux directory of iproute2 must come from sanitized
version of kernel headers that are in uapi/linux in the kernel source.

I take headers from 'make install_headers' and copy them over to keep
in sync. The headers for master branch are kept in sync with upstream
kernel (from Linus tree), and for net-next branch I derive them from Davem's
net-next tree.

If you want to use tc_bpf.h it has to be in upstream kernel first.

Sorry
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiri Pirko Jan. 14, 2015, 9:19 a.m. UTC | #5
Wed, Jan 14, 2015 at 02:19:17AM CET, stephen@networkplumber.org wrote:
>On Wed,  7 Jan 2015 17:47:24 +0100
>Jiri Pirko <jiri@resnulli.us> wrote:
>
>> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
>> ---
>>  include/linux/tc_act/tc_bpf.h |  31 +++++++
>
>The overall concept is fine, but the mechanics of file management
>gets in the way.
>
>All header files in the linux directory of iproute2 must come from sanitized
>version of kernel headers that are in uapi/linux in the kernel source.
>
>I take headers from 'make install_headers' and copy them over to keep
>in sync. The headers for master branch are kept in sync with upstream
>kernel (from Linus tree), and for net-next branch I derive them from Davem's
>net-next tree.
>
>If you want to use tc_bpf.h it has to be in upstream kernel first.

Sure. I will reposet these patches once act_bpf code is applied to
net-next kernel tree. Thanks!

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/tc_act/tc_bpf.h b/include/linux/tc_act/tc_bpf.h
new file mode 100644
index 0000000..5288bd7
--- /dev/null
+++ b/include/linux/tc_act/tc_bpf.h
@@ -0,0 +1,31 @@ 
+/*
+ * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_TC_BPF_H
+#define __LINUX_TC_BPF_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_BPF 13
+
+struct tc_act_bpf {
+	tc_gen;
+};
+
+enum {
+	TCA_ACT_BPF_UNSPEC,
+	TCA_ACT_BPF_TM,
+	TCA_ACT_BPF_PARMS,
+	TCA_ACT_BPF_OPS_LEN,
+	TCA_ACT_BPF_OPS,
+	__TCA_ACT_BPF_MAX,
+};
+#define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1)
+
+#endif
diff --git a/tc/Makefile b/tc/Makefile
index 45304a1..27506a6 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -41,6 +41,7 @@  TCMODULES += m_skbedit.o
 TCMODULES += m_csum.o
 TCMODULES += m_simple.o
 TCMODULES += m_vlan.o
+TCMODULES += m_bpf.o
 TCMODULES += p_ip.o
 TCMODULES += p_icmp.o
 TCMODULES += p_tcp.o
diff --git a/tc/m_bpf.c b/tc/m_bpf.c
new file mode 100644
index 0000000..611135e
--- /dev/null
+++ b/tc/m_bpf.c
@@ -0,0 +1,183 @@ 
+/*
+ * m_bpf.c	BFP based action module
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Authors:     Jiri Pirko <jiri@resnulli.us>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <linux/tc_act/tc_bpf.h>
+
+#include "utils.h"
+#include "rt_names.h"
+#include "tc_util.h"
+#include "tc_bpf.h"
+
+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, "\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, "\nACTION_SPEC := ... look at individual actions\n");
+	fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
+}
+
+static void usage(void)
+{
+	explain();
+	exit(-1);
+}
+
+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;
+	struct rtattr *tail;
+	struct tc_act_bpf parm = { 0 };
+	struct sock_filter bpf_ops[BPF_MAXINSNS];
+	__u16 bpf_len = 0;
+
+	if (matches(*argv, "bpf") != 0)
+		return -1;
+
+	NEXT_ARG();
+
+	while (argc > 0) {
+		if (matches(*argv, "run") == 0) {
+			bool from_file;
+			int ret;
+
+			NEXT_ARG();
+			if (strcmp(*argv, "bytecode-file") == 0) {
+				from_file = true;
+			} else if (strcmp(*argv, "bytecode") == 0) {
+				from_file = false;
+			} else {
+				fprintf(stderr, "unexpected \"%s\"\n", *argv);
+				explain();
+				return -1;
+			}
+			NEXT_ARG();
+			ret = bpf_parse_ops(argc, argv, bpf_ops, from_file);
+			if (ret < 0) {
+				fprintf(stderr, "Illegal \"bytecode\"\n");
+				return -1;
+			}
+			bpf_len = ret;
+		} else if (matches(*argv, "help") == 0) {
+			usage();
+		} else {
+			break;
+		}
+		argc--;
+		argv++;
+	}
+
+	parm.action = TC_ACT_PIPE;
+	if (argc) {
+		if (matches(*argv, "reclassify") == 0) {
+			parm.action = TC_ACT_RECLASSIFY;
+			NEXT_ARG();
+		} else if (matches(*argv, "pipe") == 0) {
+			parm.action = TC_ACT_PIPE;
+			NEXT_ARG();
+		} else if (matches(*argv, "drop") == 0 ||
+			   matches(*argv, "shot") == 0) {
+			parm.action = TC_ACT_SHOT;
+			NEXT_ARG();
+		} else if (matches(*argv, "continue") == 0) {
+			parm.action = TC_ACT_UNSPEC;
+			NEXT_ARG();
+		} else if (matches(*argv, "pass") == 0) {
+			parm.action = TC_ACT_OK;
+			NEXT_ARG();
+		}
+	}
+
+	if (argc) {
+		if (matches(*argv, "index") == 0) {
+			NEXT_ARG();
+			if (get_u32(&parm.index, *argv, 10)) {
+				fprintf(stderr, "bpf: Illegal \"index\"\n");
+				return -1;
+			}
+			argc--;
+			argv++;
+		}
+	}
+
+	if (!bpf_len) {
+		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));
+	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+
+	*argc_p = argc;
+	*argv_p = argv;
+	return 0;
+}
+
+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;
+
+	if (arg == NULL)
+		return -1;
+
+	parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);
+
+	if (!tb[TCA_ACT_BPF_PARMS]) {
+		fprintf(f, "[NULL bpf parameters]");
+		return -1;
+	}
+	parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
+
+	fprintf(f, " bpf ");
+
+	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, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt,
+		parm->bindcnt);
+
+	if (show_stats) {
+		if (tb[TCA_ACT_BPF_TM]) {
+			struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]);
+			print_tm(f, tm);
+		}
+	}
+
+	fprintf(f, "\n ");
+
+	return 0;
+}
+
+struct action_util bpf_action_util = {
+	.id = "bpf",
+	.parse_aopt = parse_bpf,
+	.print_aopt = print_bpf,
+};