All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch net-next] tc: add BPF based action
@ 2015-01-07 16:43 Jiri Pirko
  2015-01-07 16:47 ` [patch iproute2 1/2] tc: push bpf common code into separate file Jiri Pirko
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Jiri Pirko @ 2015-01-07 16:43 UTC (permalink / raw)
  To: netdev; +Cc: davem, jhs, stephen

This action provides a possibility to exec custom BPF code.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
 include/net/tc_act/tc_bpf.h        |  25 +++++
 include/uapi/linux/tc_act/Kbuild   |   1 +
 include/uapi/linux/tc_act/tc_bpf.h |  31 ++++++
 net/sched/Kconfig                  |  11 +++
 net/sched/Makefile                 |   1 +
 net/sched/act_bpf.c                | 196 +++++++++++++++++++++++++++++++++++++
 6 files changed, 265 insertions(+)
 create mode 100644 include/net/tc_act/tc_bpf.h
 create mode 100644 include/uapi/linux/tc_act/tc_bpf.h
 create mode 100644 net/sched/act_bpf.c

diff --git a/include/net/tc_act/tc_bpf.h b/include/net/tc_act/tc_bpf.h
new file mode 100644
index 0000000..95e11da
--- /dev/null
+++ b/include/net/tc_act/tc_bpf.h
@@ -0,0 +1,25 @@
+/*
+ * 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 __NET_TC_BPF_H
+#define __NET_TC_BPF_H
+
+#include <linux/filter.h>
+#include <net/act_api.h>
+
+struct tcf_bpf {
+	struct tcf_common	common;
+	struct bpf_prog		*filter;
+	struct sock_filter	*bpf_ops;
+	u16			bpf_len;
+};
+#define to_bpf(a) \
+	container_of(a->priv, struct tcf_bpf, common)
+
+#endif /* __NET_TC_BPF_H */
diff --git a/include/uapi/linux/tc_act/Kbuild b/include/uapi/linux/tc_act/Kbuild
index b057da2..19d5219 100644
--- a/include/uapi/linux/tc_act/Kbuild
+++ b/include/uapi/linux/tc_act/Kbuild
@@ -8,3 +8,4 @@ header-y += tc_nat.h
 header-y += tc_pedit.h
 header-y += tc_skbedit.h
 header-y += tc_vlan.h
+header-y += tc_bpf.h
diff --git a/include/uapi/linux/tc_act/tc_bpf.h b/include/uapi/linux/tc_act/tc_bpf.h
new file mode 100644
index 0000000..5288bd77
--- /dev/null
+++ b/include/uapi/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/net/sched/Kconfig b/net/sched/Kconfig
index c54c9d9..cc311e9 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -698,6 +698,17 @@ config NET_ACT_VLAN
 	  To compile this code as a module, choose M here: the
 	  module will be called act_vlan.
 
+config NET_ACT_BPF
+        tristate "BPF based action"
+        depends on NET_CLS_ACT
+        ---help---
+	  Say Y here to execute BFP code on packets.
+
+	  If unsure, say N.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called act_bpf.
+
 config NET_CLS_IND
 	bool "Incoming device classification"
 	depends on NET_CLS_U32 || NET_CLS_FW
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 679f24a..7ca2b4e 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
 obj-$(CONFIG_NET_ACT_SKBEDIT)	+= act_skbedit.o
 obj-$(CONFIG_NET_ACT_CSUM)	+= act_csum.o
 obj-$(CONFIG_NET_ACT_VLAN)	+= act_vlan.o
+obj-$(CONFIG_NET_ACT_BPF)	+= act_bpf.o
 obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
 obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
 obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
new file mode 100644
index 0000000..43f5f9d
--- /dev/null
+++ b/net/sched/act_bpf.c
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/filter.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+
+#include <linux/tc_act/tc_bpf.h>
+#include <net/tc_act/tc_bpf.h>
+
+#define BPF_TAB_MASK     15
+
+static int tcf_bpf(struct sk_buff *skb, const struct tc_action *a,
+		   struct tcf_result *res)
+{
+	struct tcf_bpf *b = a->priv;
+	int action;
+	int filter_res;
+
+	spin_lock(&b->tcf_lock);
+	b->tcf_tm.lastuse = jiffies;
+	bstats_update(&b->tcf_bstats, skb);
+	action = b->tcf_action;
+
+	filter_res = BPF_PROG_RUN(b->filter, skb);
+	if (filter_res == -1)
+		goto drop;
+
+	goto unlock;
+
+drop:
+	action = TC_ACT_SHOT;
+	b->tcf_qstats.drops++;
+unlock:
+	spin_unlock(&b->tcf_lock);
+	return action;
+}
+
+static const struct nla_policy act_bpf_policy[TCA_ACT_BPF_MAX + 1] = {
+	[TCA_ACT_BPF_PARMS]	= { .len = sizeof(struct tc_act_bpf) },
+	[TCA_ACT_BPF_OPS_LEN]	= { .type = NLA_U16 },
+	[TCA_ACT_BPF_OPS]	= { .type = NLA_BINARY,
+				    .len = sizeof(struct sock_filter) * BPF_MAXINSNS },
+};
+
+static int tcf_bpf_init(struct net *net, struct nlattr *nla,
+			struct nlattr *est, struct tc_action *a,
+			int ovr, int bind)
+{
+	struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
+	struct tc_act_bpf *parm;
+	struct tcf_bpf *b;
+	u16 bpf_size, bpf_len;
+	struct sock_filter *bpf_ops;
+	struct sock_fprog_kern tmp;
+	struct bpf_prog *fp;
+	int ret;
+
+	if (!nla)
+		return -EINVAL;
+
+	ret = nla_parse_nested(tb, TCA_ACT_BPF_MAX, nla, act_bpf_policy);
+	if (ret < 0)
+		return ret;
+
+	if (!tb[TCA_ACT_BPF_PARMS] ||
+	    !tb[TCA_ACT_BPF_OPS_LEN] || !tb[TCA_ACT_BPF_OPS])
+		return -EINVAL;
+	parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
+
+	bpf_len = nla_get_u16(tb[TCA_ACT_BPF_OPS_LEN]);
+	if (bpf_len > BPF_MAXINSNS || bpf_len == 0)
+		return -EINVAL;
+
+	bpf_size = bpf_len * sizeof(*bpf_ops);
+	bpf_ops = kzalloc(bpf_size, GFP_KERNEL);
+	if (!bpf_ops)
+		return -ENOMEM;
+
+	memcpy(bpf_ops, nla_data(tb[TCA_ACT_BPF_OPS]), bpf_size);
+
+	tmp.len = bpf_len;
+	tmp.filter = bpf_ops;
+
+	ret = bpf_prog_create(&fp, &tmp);
+	if (ret)
+		goto free_bpf_ops;
+
+	if (!tcf_hash_check(parm->index, a, bind)) {
+		ret = tcf_hash_create(parm->index, est, a, sizeof(*b), bind);
+		if (ret)
+			goto free_bpf_ops;
+
+		ret = ACT_P_CREATED;
+	} else {
+		if (bind)
+			goto free_bpf_ops;
+		tcf_hash_release(a, bind);
+		if (!ovr) {
+			ret = -EEXIST;
+			goto free_bpf_ops;
+		}
+	}
+
+	b = to_bpf(a);
+	spin_lock_bh(&b->tcf_lock);
+	b->tcf_action = parm->action;
+	b->bpf_len = bpf_len;
+	b->bpf_ops = bpf_ops;
+	b->filter = fp;
+	spin_unlock_bh(&b->tcf_lock);
+
+	if (ret == ACT_P_CREATED)
+		tcf_hash_insert(a);
+	return ret;
+
+free_bpf_ops:
+	kfree(bpf_ops);
+	return ret;
+}
+
+static int tcf_bpf_dump(struct sk_buff *skb, struct tc_action *a,
+			int bind, int ref)
+{
+	unsigned char *tp = skb_tail_pointer(skb);
+	struct tcf_bpf *b = a->priv;
+	struct tc_act_bpf opt = {
+		.index    = b->tcf_index,
+		.refcnt   = b->tcf_refcnt - ref,
+		.bindcnt  = b->tcf_bindcnt - bind,
+		.action   = b->tcf_action,
+	};
+	struct tcf_t t;
+	struct nlattr *nla;
+
+	if (nla_put(skb, TCA_ACT_BPF_PARMS, sizeof(opt), &opt))
+		goto nla_put_failure;
+
+	if (nla_put_u16(skb, TCA_ACT_BPF_OPS_LEN, b->bpf_len))
+		goto nla_put_failure;
+
+	nla = nla_reserve(skb, TCA_ACT_BPF_OPS, b->bpf_len *
+			  sizeof(struct sock_filter));
+	if (!nla)
+		goto nla_put_failure;
+
+	memcpy(nla_data(nla), b->bpf_ops, nla_len(nla));
+
+	t.install = jiffies_to_clock_t(jiffies - b->tcf_tm.install);
+	t.lastuse = jiffies_to_clock_t(jiffies - b->tcf_tm.lastuse);
+	t.expires = jiffies_to_clock_t(b->tcf_tm.expires);
+	if (nla_put(skb, TCA_ACT_BPF_TM, sizeof(t), &t))
+		goto nla_put_failure;
+	return skb->len;
+
+nla_put_failure:
+	nlmsg_trim(skb, tp);
+	return -1;
+}
+
+static struct tc_action_ops act_bpf_ops = {
+	.kind		=	"bpf",
+	.type		=	TCA_ACT_BPF,
+	.owner		=	THIS_MODULE,
+	.act		=	tcf_bpf,
+	.dump		=	tcf_bpf_dump,
+	.init		=	tcf_bpf_init,
+};
+
+static int __init bpf_init_module(void)
+{
+	return tcf_register_action(&act_bpf_ops, BPF_TAB_MASK);
+}
+
+static void __exit bpf_cleanup_module(void)
+{
+	tcf_unregister_action(&act_bpf_ops);
+}
+
+module_init(bpf_init_module);
+module_exit(bpf_cleanup_module);
+
+MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
+MODULE_DESCRIPTION("TC BPF based action");
+MODULE_LICENSE("GPL v2");
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [patch iproute2 1/2] tc: push bpf common code into separate file
  2015-01-07 16:43 [patch net-next] tc: add BPF based action Jiri Pirko
@ 2015-01-07 16:47 ` Jiri Pirko
  2015-01-07 16:47   ` [patch iproute2 2/2] tc: add support for BPF based actions Jiri Pirko
  2015-01-07 18:33 ` [patch net-next] tc: add BPF based action Daniel Borkmann
  2015-01-08 14:55 ` Hannes Frederic Sowa
  2 siblings, 1 reply; 13+ messages in thread
From: Jiri Pirko @ 2015-01-07 16:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jhs, stephen

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
 tc/Makefile |   2 +-
 tc/f_bpf.c  | 136 +++++--------------------------------------------------
 tc/tc_bpf.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tc/tc_bpf.h |  28 ++++++++++++
 4 files changed, 186 insertions(+), 126 deletions(-)
 create mode 100644 tc/tc_bpf.c
 create mode 100644 tc/tc_bpf.h

diff --git a/tc/Makefile b/tc/Makefile
index 830c97d..45304a1 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -1,5 +1,5 @@
 TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o \
-       tc_monitor.o m_police.o m_estimator.o m_action.o \
+       tc_monitor.o tc_bpf.o m_police.o m_estimator.o m_action.o \
        m_ematch.o emp_ematch.yacc.o emp_ematch.lex.o
 
 include ../Config
diff --git a/tc/f_bpf.c b/tc/f_bpf.c
index 48635a7..e2af94e 100644
--- a/tc/f_bpf.c
+++ b/tc/f_bpf.c
@@ -26,6 +26,7 @@
 
 #include "utils.h"
 #include "tc_util.h"
+#include "tc_bpf.h"
 
 static void explain(void)
 {
@@ -44,130 +45,6 @@ static void explain(void)
 	fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
-static int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
-			    char **bpf_string, bool *need_release,
-			    const char separator)
-{
-	char sp;
-
-	if (from_file) {
-		size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,");
-		char *tmp_string;
-		FILE *fp;
-
-		tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len;
-		tmp_string = malloc(tmp_len);
-		if (tmp_string == NULL)
-			return -ENOMEM;
-
-		memset(tmp_string, 0, tmp_len);
-
-		fp = fopen(arg, "r");
-		if (fp == NULL) {
-			perror("Cannot fopen");
-			free(tmp_string);
-			return -ENOENT;
-		}
-
-		if (!fgets(tmp_string, tmp_len, fp)) {
-			free(tmp_string);
-			fclose(fp);
-			return -EIO;
-		}
-
-		fclose(fp);
-
-		*need_release = true;
-		*bpf_string = tmp_string;
-	} else {
-		*need_release = false;
-		*bpf_string = arg;
-	}
-
-	if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 ||
-	    sp != separator) {
-		if (*need_release)
-			free(*bpf_string);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int bpf_parse_ops(int argc, char **argv, struct nlmsghdr *n,
-			 bool from_file)
-{
-	char *bpf_string, *token, separator = ',';
-	struct sock_filter bpf_ops[BPF_MAXINSNS];
-	int ret = 0, i = 0;
-	bool need_release;
-	__u16 bpf_len = 0;
-
-	if (argc < 1)
-		return -EINVAL;
-	if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string,
-			     &need_release, separator))
-		return -EINVAL;
-	if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	token = bpf_string;
-	while ((token = strchr(token, separator)) && (++token)[0]) {
-		if (i >= bpf_len) {
-			fprintf(stderr, "Real program length exceeds encoded "
-				"length parameter!\n");
-			ret = -EINVAL;
-			goto out;
-		}
-
-		if (sscanf(token, "%hu %hhu %hhu %u,",
-			   &bpf_ops[i].code, &bpf_ops[i].jt,
-			   &bpf_ops[i].jf, &bpf_ops[i].k) != 4) {
-			fprintf(stderr, "Error at instruction %d!\n", i);
-			ret = -EINVAL;
-			goto out;
-		}
-
-		i++;
-	}
-
-	if (i != bpf_len) {
-		fprintf(stderr, "Parsed program length is less than encoded"
-			"length parameter!\n");
-		ret = -EINVAL;
-		goto out;
-	}
-
-	addattr_l(n, MAX_MSG, TCA_BPF_OPS_LEN, &bpf_len, sizeof(bpf_len));
-	addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops,
-		  bpf_len * sizeof(struct sock_filter));
-out:
-	if (need_release)
-		free(bpf_string);
-
-	return ret;
-}
-
-static void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len)
-{
-	struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops);
-	int i;
-
-	if (len == 0)
-		return;
-
-	fprintf(f, "bytecode \'%u,", len);
-
-	for (i = 0; i < len - 1; i++)
-		fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt,
-			ops[i].jf, ops[i].k);
-
-	fprintf(f, "%hu %hhu %hhu %u\'\n", ops[i].code, ops[i].jt,
-		ops[i].jf, ops[i].k);
-}
-
 static int bpf_parse_opt(struct filter_util *qu, char *handle,
 			 int argc, char **argv, struct nlmsghdr *n)
 {
@@ -195,6 +72,10 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle,
 	while (argc > 0) {
 		if (matches(*argv, "run") == 0) {
 			bool from_file;
+			struct sock_filter bpf_ops[BPF_MAXINSNS];
+			__u16 bpf_len;
+			int ret;
+
 			NEXT_ARG();
 			if (strcmp(*argv, "bytecode-file") == 0) {
 				from_file = true;
@@ -206,10 +87,15 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle,
 				return -1;
 			}
 			NEXT_ARG();
-			if (bpf_parse_ops(argc, argv, n, from_file)) {
+			ret = bpf_parse_ops(argc, argv, bpf_ops, from_file);
+			if (ret < 0) {
 				fprintf(stderr, "Illegal \"bytecode\"\n");
 				return -1;
 			}
+			bpf_len = ret;
+			addattr16(n, MAX_MSG, TCA_BPF_OPS_LEN, bpf_len);
+			addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops,
+				  bpf_len * sizeof(struct sock_filter));
 		} else if (matches(*argv, "classid") == 0 ||
 			   strcmp(*argv, "flowid") == 0) {
 			unsigned handle;
diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c
new file mode 100644
index 0000000..c6901d6
--- /dev/null
+++ b/tc/tc_bpf.c
@@ -0,0 +1,146 @@
+/*
+ * tc_bpf.c	BPF common code
+ *
+ *		This program is free software; you can distribute 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:	Daniel Borkmann <dborkman@redhat.com>
+ *		Jiri Pirko <jiri@resnulli.us>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include "utils.h"
+#include "tc_util.h"
+#include "tc_bpf.h"
+
+int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
+		     char **bpf_string, bool *need_release,
+		     const char separator)
+{
+	char sp;
+
+	if (from_file) {
+		size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,");
+		char *tmp_string;
+		FILE *fp;
+
+		tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len;
+		tmp_string = malloc(tmp_len);
+		if (tmp_string == NULL)
+			return -ENOMEM;
+
+		memset(tmp_string, 0, tmp_len);
+
+		fp = fopen(arg, "r");
+		if (fp == NULL) {
+			perror("Cannot fopen");
+			free(tmp_string);
+			return -ENOENT;
+		}
+
+		if (!fgets(tmp_string, tmp_len, fp)) {
+			free(tmp_string);
+			fclose(fp);
+			return -EIO;
+		}
+
+		fclose(fp);
+
+		*need_release = true;
+		*bpf_string = tmp_string;
+	} else {
+		*need_release = false;
+		*bpf_string = arg;
+	}
+
+	if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 ||
+	    sp != separator) {
+		if (*need_release)
+			free(*bpf_string);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops,
+		  bool from_file)
+{
+	char *bpf_string, *token, separator = ',';
+	int ret = 0, i = 0;
+	bool need_release;
+	__u16 bpf_len = 0;
+
+	if (argc < 1)
+		return -EINVAL;
+	if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string,
+			     &need_release, separator))
+		return -EINVAL;
+	if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	token = bpf_string;
+	while ((token = strchr(token, separator)) && (++token)[0]) {
+		if (i >= bpf_len) {
+			fprintf(stderr, "Real program length exceeds encoded "
+				"length parameter!\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (sscanf(token, "%hu %hhu %hhu %u,",
+			   &bpf_ops[i].code, &bpf_ops[i].jt,
+			   &bpf_ops[i].jf, &bpf_ops[i].k) != 4) {
+			fprintf(stderr, "Error at instruction %d!\n", i);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		i++;
+	}
+
+	if (i != bpf_len) {
+		fprintf(stderr, "Parsed program length is less than encoded"
+			"length parameter!\n");
+		ret = -EINVAL;
+		goto out;
+	}
+	ret = bpf_len;
+
+out:
+	if (need_release)
+		free(bpf_string);
+
+	return ret;
+}
+
+void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len)
+{
+	struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops);
+	int i;
+
+	if (len == 0)
+		return;
+
+	fprintf(f, "bytecode \'%u,", len);
+
+	for (i = 0; i < len - 1; i++)
+		fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt,
+			ops[i].jf, ops[i].k);
+
+	fprintf(f, "%hu %hhu %hhu %u\'\n", ops[i].code, ops[i].jt,
+		ops[i].jf, ops[i].k);
+}
diff --git a/tc/tc_bpf.h b/tc/tc_bpf.h
new file mode 100644
index 0000000..08cca92
--- /dev/null
+++ b/tc/tc_bpf.h
@@ -0,0 +1,28 @@
+/*
+ * tc_bpf.h	BPF common code
+ *
+ *		This program is free software; you can distribute 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:	Daniel Borkmann <dborkman@redhat.com>
+ *		Jiri Pirko <jiri@resnulli.us>
+ */
+
+#ifndef _TC_BPF_H_
+#define _TC_BPF_H_ 1
+
+#include <stdio.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
+		     char **bpf_string, bool *need_release,
+		     const char separator);
+int bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops,
+		  bool from_file);
+void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len);
+
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [patch iproute2 2/2] tc: add support for BPF based actions
  2015-01-07 16:47 ` [patch iproute2 1/2] tc: push bpf common code into separate file Jiri Pirko
@ 2015-01-07 16:47   ` Jiri Pirko
  2015-01-07 18:50     ` Cong Wang
  2015-01-14  1:19     ` Stephen Hemminger
  0 siblings, 2 replies; 13+ messages in thread
From: Jiri Pirko @ 2015-01-07 16:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jhs, stephen

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

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,
+};
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [patch net-next] tc: add BPF based action
  2015-01-07 16:43 [patch net-next] tc: add BPF based action Jiri Pirko
  2015-01-07 16:47 ` [patch iproute2 1/2] tc: push bpf common code into separate file Jiri Pirko
@ 2015-01-07 18:33 ` Daniel Borkmann
  2015-01-07 18:46   ` Cong Wang
  2015-01-08  7:26   ` Jiri Pirko
  2015-01-08 14:55 ` Hannes Frederic Sowa
  2 siblings, 2 replies; 13+ messages in thread
From: Daniel Borkmann @ 2015-01-07 18:33 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, davem, jhs, stephen, ast

On 01/07/2015 05:43 PM, Jiri Pirko wrote:
> This action provides a possibility to exec custom BPF code.

Can you elaborate a bit more on the particular use-case, and
what scenarios are unsolveable with the BPF filter we already
have in tc? Just wondering, since you're using BPF for the
purpose of classifying (but just from the context of actions)
what about a possibility of a generic container for reusing
(any) classifier from the framework, so we would not need to
duplicate code?

On the other hand, I would understand if it's at some point in
time eBPF which would f.e. mangle the packet, but the API you
propose is clearly classic BPF. ;)

Thanks,
Daniel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch net-next] tc: add BPF based action
  2015-01-07 18:33 ` [patch net-next] tc: add BPF based action Daniel Borkmann
@ 2015-01-07 18:46   ` Cong Wang
  2015-01-08  7:26   ` Jiri Pirko
  1 sibling, 0 replies; 13+ messages in thread
From: Cong Wang @ 2015-01-07 18:46 UTC (permalink / raw)
  To: Daniel Borkmann
  Cc: Jiri Pirko, netdev, David Miller, Jamal Hadi Salim,
	Stephen Hemminger, Alexei Starovoitov

On Wed, Jan 7, 2015 at 10:33 AM, Daniel Borkmann <dborkman@redhat.com> wrote:
> On 01/07/2015 05:43 PM, Jiri Pirko wrote:
>>
>> This action provides a possibility to exec custom BPF code.
>
>
> Can you elaborate a bit more on the particular use-case, and
> what scenarios are unsolveable with the BPF filter we already
> have in tc? Just wondering, since you're using BPF for the
> purpose of classifying (but just from the context of actions)
> what about a possibility of a generic container for reusing
> (any) classifier from the framework, so we would not need to
> duplicate code?
>

+1

Also as its name tells, BPF is a filter, why it could be used
as an action here? (I don't follow eBPF though.)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch iproute2 2/2] tc: add support for BPF based actions
  2015-01-07 16:47   ` [patch iproute2 2/2] tc: add support for BPF based actions Jiri Pirko
@ 2015-01-07 18:50     ` Cong Wang
  2015-01-07 19:52       ` Jiri Pirko
  2015-01-14  1:19     ` Stephen Hemminger
  1 sibling, 1 reply; 13+ messages in thread
From: Cong Wang @ 2015-01-07 18:50 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, David Miller, Jamal Hadi Salim, Stephen Hemminger

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.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch iproute2 2/2] tc: add support for BPF based actions
  2015-01-07 18:50     ` Cong Wang
@ 2015-01-07 19:52       ` Jiri Pirko
  2015-01-07 19:58         ` Cong Wang
  0 siblings, 1 reply; 13+ messages in thread
From: Jiri Pirko @ 2015-01-07 19:52 UTC (permalink / raw)
  To: Cong Wang; +Cc: netdev, David Miller, Jamal Hadi Salim, Stephen Hemminger

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.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch iproute2 2/2] tc: add support for BPF based actions
  2015-01-07 19:52       ` Jiri Pirko
@ 2015-01-07 19:58         ` Cong Wang
  0 siblings, 0 replies; 13+ messages in thread
From: Cong Wang @ 2015-01-07 19:58 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, David Miller, Jamal Hadi Salim, Stephen Hemminger

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.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch net-next] tc: add BPF based action
  2015-01-07 18:33 ` [patch net-next] tc: add BPF based action Daniel Borkmann
  2015-01-07 18:46   ` Cong Wang
@ 2015-01-08  7:26   ` Jiri Pirko
  1 sibling, 0 replies; 13+ messages in thread
From: Jiri Pirko @ 2015-01-08  7:26 UTC (permalink / raw)
  To: Daniel Borkmann; +Cc: netdev, davem, jhs, stephen, ast

Wed, Jan 07, 2015 at 07:33:39PM CET, dborkman@redhat.com wrote:
>On 01/07/2015 05:43 PM, Jiri Pirko wrote:
>>This action provides a possibility to exec custom BPF code.
>
>Can you elaborate a bit more on the particular use-case, and
>what scenarios are unsolveable with the BPF filter we already
>have in tc? Just wondering, since you're using BPF for the
>purpose of classifying (but just from the context of actions)
>what about a possibility of a generic container for reusing
>(any) classifier from the framework, so we would not need to
>duplicate code?
>
>On the other hand, I would understand if it's at some point in
>time eBPF which would f.e. mangle the packet, but the API you
>propose is clearly classic BPF. ;)

Exactly. I would like to extend cls_bpf and act_bpf to handle eBPF right
after. That is the point.

>
>Thanks,
>Daniel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch net-next] tc: add BPF based action
  2015-01-07 16:43 [patch net-next] tc: add BPF based action Jiri Pirko
  2015-01-07 16:47 ` [patch iproute2 1/2] tc: push bpf common code into separate file Jiri Pirko
  2015-01-07 18:33 ` [patch net-next] tc: add BPF based action Daniel Borkmann
@ 2015-01-08 14:55 ` Hannes Frederic Sowa
  2015-01-08 15:01   ` Jiri Pirko
  2 siblings, 1 reply; 13+ messages in thread
From: Hannes Frederic Sowa @ 2015-01-08 14:55 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, davem, jhs, stephen

On Mi, 2015-01-07 at 17:43 +0100, Jiri Pirko wrote:
> +static int tcf_bpf(struct sk_buff *skb, const struct tc_action *a,
> +		   struct tcf_result *res)
> +{
> +	struct tcf_bpf *b = a->priv;
> +	int action;
> +	int filter_res;
> +
> +	spin_lock(&b->tcf_lock);
> +	b->tcf_tm.lastuse = jiffies;
> +	bstats_update(&b->tcf_bstats, skb);
> +	action = b->tcf_action;
> +
> +	filter_res = BPF_PROG_RUN(b->filter, skb);
> +	if (filter_res == -1)
> +		goto drop;
> +
> +	goto unlock;
> +
> +drop:
> +	action = TC_ACT_SHOT;
> +	b->tcf_qstats.drops++;
> +unlock:
> +	spin_unlock(&b->tcf_lock);
> +	return action;
> +}

In theory this could be like:

filter_res = BPF_PROG_RUN(b->filter, skb);

spin_lock(&b->tcf_lock);
<update stats...>

if (filter_res == -1)
  goto drop;

action = b->tcf_action;
...

to keep BPF_PROG_RUN out of the spin_lock?

Bye,
Hannes

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch net-next] tc: add BPF based action
  2015-01-08 14:55 ` Hannes Frederic Sowa
@ 2015-01-08 15:01   ` Jiri Pirko
  0 siblings, 0 replies; 13+ messages in thread
From: Jiri Pirko @ 2015-01-08 15:01 UTC (permalink / raw)
  To: Hannes Frederic Sowa; +Cc: netdev, davem, jhs, stephen

Thu, Jan 08, 2015 at 03:55:37PM CET, hannes@redhat.com wrote:
>On Mi, 2015-01-07 at 17:43 +0100, Jiri Pirko wrote:
>> +static int tcf_bpf(struct sk_buff *skb, const struct tc_action *a,
>> +		   struct tcf_result *res)
>> +{
>> +	struct tcf_bpf *b = a->priv;
>> +	int action;
>> +	int filter_res;
>> +
>> +	spin_lock(&b->tcf_lock);
>> +	b->tcf_tm.lastuse = jiffies;
>> +	bstats_update(&b->tcf_bstats, skb);
>> +	action = b->tcf_action;
>> +
>> +	filter_res = BPF_PROG_RUN(b->filter, skb);
>> +	if (filter_res == -1)
>> +		goto drop;
>> +
>> +	goto unlock;
>> +
>> +drop:
>> +	action = TC_ACT_SHOT;
>> +	b->tcf_qstats.drops++;
>> +unlock:
>> +	spin_unlock(&b->tcf_lock);
>> +	return action;
>> +}
>
>In theory this could be like:
>
>filter_res = BPF_PROG_RUN(b->filter, skb);
>
>spin_lock(&b->tcf_lock);
><update stats...>
>
>if (filter_res == -1)
>  goto drop;
>
>action = b->tcf_action;
>...
>
>to keep BPF_PROG_RUN out of the spin_lock?

Okay. That makes sense. Will include this change into v2.

Thanks.

>
>Bye,
>Hannes
>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch iproute2 2/2] tc: add support for BPF based actions
  2015-01-07 16:47   ` [patch iproute2 2/2] tc: add support for BPF based actions Jiri Pirko
  2015-01-07 18:50     ` Cong Wang
@ 2015-01-14  1:19     ` Stephen Hemminger
  2015-01-14  9:19       ` Jiri Pirko
  1 sibling, 1 reply; 13+ messages in thread
From: Stephen Hemminger @ 2015-01-14  1:19 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, davem, jhs

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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch iproute2 2/2] tc: add support for BPF based actions
  2015-01-14  1:19     ` Stephen Hemminger
@ 2015-01-14  9:19       ` Jiri Pirko
  0 siblings, 0 replies; 13+ messages in thread
From: Jiri Pirko @ 2015-01-14  9:19 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, davem, jhs

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!

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2015-01-14  9:19 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-07 16:43 [patch net-next] tc: add BPF based action Jiri Pirko
2015-01-07 16:47 ` [patch iproute2 1/2] tc: push bpf common code into separate file Jiri Pirko
2015-01-07 16:47   ` [patch iproute2 2/2] tc: add support for BPF based actions Jiri Pirko
2015-01-07 18:50     ` Cong Wang
2015-01-07 19:52       ` Jiri Pirko
2015-01-07 19:58         ` Cong Wang
2015-01-14  1:19     ` Stephen Hemminger
2015-01-14  9:19       ` Jiri Pirko
2015-01-07 18:33 ` [patch net-next] tc: add BPF based action Daniel Borkmann
2015-01-07 18:46   ` Cong Wang
2015-01-08  7:26   ` Jiri Pirko
2015-01-08 14:55 ` Hannes Frederic Sowa
2015-01-08 15:01   ` Jiri Pirko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.