lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1423090122-19807-3-git-send-email-azhou@nicira.com>
Date:	Wed,  4 Feb 2015 14:48:42 -0800
From:	Andy Zhou <azhou@...ira.com>
To:	dev@...nvswitch.com
Cc:	netdev@...r.kernel.org, Andy Zhou <azhou@...ira.com>
Subject: [RFC: add openvswitch actions using BPF 2/2] openvswitch: implements the BPF_PROG action in datapath

BPF_PROG action allows an action to be implemented in eBPF language and
downloaded by the userspace at runtime.

Signed-off-by: Andy Zhou <azhou@...ira.com>
---
 net/openvswitch/actions.c      | 30 ++++++++++++++
 net/openvswitch/datapath.c     |  6 ++-
 net/openvswitch/flow_netlink.c | 92 +++++++++++++++++++++++++++++++++++++++++-
 net/openvswitch/flow_netlink.h |  8 ++++
 4 files changed, 132 insertions(+), 4 deletions(-)

diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index b4cffe6..29e9171 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -38,8 +38,12 @@
 
 #include "datapath.h"
 #include "flow.h"
+#include "flow_netlink.h"
 #include "vport.h"
 
+typedef int (*ovs_bpf_func_t)(const struct ovs_bpf_action_ctxt *,
+			      const struct bpf_insn *);
+
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
 			      struct sw_flow_key *key,
 			      const struct nlattr *attr, int len);
@@ -747,6 +751,28 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
 	return 0;
 }
 
+static int execute_bpf(struct sk_buff *skb, struct sw_flow_key *key,
+		       const struct nlattr *a)
+{
+	struct ovs_action_bpf_runtime *rt;
+	struct bpf_prog *prog;
+	struct ovs_bpf_action_ctxt ctxt;
+	ovs_bpf_func_t ovs_bpf_func;
+	int err;
+
+	rt = nla_data(a);
+	prog = rt->prog;
+
+	/* Build the BPF program runtime context. */
+	ctxt.skb = (void *)skb;
+	ctxt.arg0 = rt->arg0;
+	ctxt.arg1 = rt->arg1;
+
+	ovs_bpf_func = (ovs_bpf_func_t)(prog->bpf_func);
+	err = ovs_bpf_func(&ctxt, prog->insnsi);
+	return err;
+}
+
 /* Execute a list of actions against 'skb'. */
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
 			      struct sw_flow_key *key,
@@ -814,6 +840,10 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
 			}
 			break;
 
+		case OVS_ACTION_ATTR_BPF_PROG:
+			err = execute_bpf(skb, key, a);
+			break;
+
 		case OVS_ACTION_ATTR_SET:
 			err = execute_set_action(skb, key, nla_data(a));
 			break;
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index ae5e77c..810a0bf 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -699,6 +699,8 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts,
 		len += nla_total_size(ovs_key_attr_size());
 
 	/* OVS_FLOW_ATTR_ACTIONS */
+	/* XXX this logic needs to be fixed to accommodate BPF_PROG action
+	 * will expand the run time action size.   */
 	if (should_fill_actions(ufid_flags))
 		len += nla_total_size(acts->actions_len);
 
@@ -1017,7 +1019,7 @@ err_unlock_ovs:
 	ovs_unlock();
 	kfree_skb(reply);
 err_kfree_acts:
-	kfree(acts);
+	free_flow_actions(acts);
 err_kfree_flow:
 	ovs_flow_free(new_flow, false);
 error:
@@ -1152,7 +1154,7 @@ err_unlock_ovs:
 	ovs_unlock();
 	kfree_skb(reply);
 err_kfree_acts:
-	kfree(acts);
+	free_flow_actions(acts);
 error:
 	return error;
 }
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 8b9a612..466e85f 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -42,6 +42,7 @@
 #include <linux/icmp.h>
 #include <linux/icmpv6.h>
 #include <linux/rculist.h>
+#include <linux/bpf.h>
 #include <net/geneve.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -1546,11 +1547,38 @@ static struct sw_flow_actions *nla_alloc_flow_actions(int size, bool log)
 	return sfa;
 }
 
+void free_flow_actions(struct sw_flow_actions *sf_acts)
+{
+	const struct nlattr *a;
+	int rem;
+	struct ovs_action_bpf_runtime *rt;
+
+	nla_for_each_attr(a, sf_acts->actions, sf_acts->actions_len, rem) {
+		int type = nla_type(a);
+
+		switch (type) {
+		case OVS_ACTION_ATTR_BPF_PROG:
+			rt = nla_data(a);
+			bpf_prog_put(rt->prog);
+			break;
+		}
+	}
+
+	kfree(sf_acts);
+}
+
+static void free_flow_actions_rcu(struct rcu_head *head)
+{
+	struct sw_flow_actions *acts = container_of(head, struct sw_flow_actions, rcu);
+
+	free_flow_actions(acts);
+}
+
 /* Schedules 'sf_acts' to be freed after the next RCU grace period.
  * The caller must hold rcu_read_lock for this to be sensible. */
 void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts)
 {
-	kfree_rcu(sf_acts, rcu);
+	call_rcu(&sf_acts->rcu, free_flow_actions_rcu);
 }
 
 static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa,
@@ -1695,6 +1723,37 @@ static int validate_and_copy_sample(const struct nlattr *attr,
 	return 0;
 }
 
+static int validate_and_copy_bpf(const struct nlattr *attr,
+				 struct sw_flow_actions **sfa,
+				 bool log)
+{
+	const struct ovs_action_bpf_prog *act_bpf = nla_data(attr);
+	struct ovs_action_bpf_runtime rt;
+	u32 fd;
+	int err;
+
+	fd = ntohl(act_bpf->prog_fd);
+	rt.prog = bpf_prog_get(fd);
+	if (!rt.prog)
+		return -EINVAL;
+
+	if (rt.prog->aux->prog_type != BPF_PROG_TYPE_OPENVSWITCH) {
+		bpf_prog_put(rt.prog);
+		return -EINVAL;
+	}
+
+	rt.fd = fd;
+	rt.arg0 = ntohl(act_bpf->arg0);
+	rt.arg1 = ntohl(act_bpf->arg1);
+
+	/* Validation done.  Rewrite the action with runtime datastructure. */
+	err = add_action(sfa, OVS_ACTION_ATTR_BPF_PROG, &rt, sizeof(rt), log);
+	if (err)
+		return err;
+
+	return 0;
+}
+
 static int validate_tp_port(const struct sw_flow_key *flow_key,
 			    __be16 eth_type)
 {
@@ -1966,7 +2025,9 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
 			[OVS_ACTION_ATTR_POP_VLAN] = 0,
 			[OVS_ACTION_ATTR_SET] = (u32)-1,
 			[OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
-			[OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash)
+			[OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash),
+			[OVS_ACTION_ATTR_BPF_PROG] =
+				sizeof(struct ovs_action_bpf_prog),
 		};
 		const struct ovs_action_push_vlan *vlan;
 		int type = nla_type(a);
@@ -2073,6 +2134,13 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
 			skip_copy = true;
 			break;
 
+		case OVS_ACTION_ATTR_BPF_PROG:
+			err = validate_and_copy_bpf(a, sfa, log);
+			if (err)
+				return err;
+			skip_copy = true;
+			break;
+
 		default:
 			OVS_NLERR(log, "Unknown Action type %d", type);
 			return -EINVAL;
@@ -2177,6 +2245,21 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
 	return 0;
 }
 
+static int bpf_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
+{
+	const struct ovs_action_bpf_runtime *rt = nla_data(a);
+	struct ovs_action_bpf_prog prog;
+
+	prog.prog_fd = htonl(rt->fd);
+	prog.arg0 = htonl(rt->arg0);
+	prog.arg1 = htonl(rt->arg1);
+
+	if (nla_put(skb, OVS_ACTION_ATTR_BPF_PROG, sizeof(prog), &prog));
+		return -EMSGSIZE;
+
+	return 0;
+}
+
 int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb)
 {
 	const struct nlattr *a;
@@ -2197,6 +2280,11 @@ int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb)
 			if (err)
 				return err;
 			break;
+
+		case OVS_ACTION_ATTR_BPF_PROG:
+			err = bpf_action_to_attr(a, skb);
+			break;
+
 		default:
 			if (nla_put(skb, type, nla_len(a), nla_data(a)))
 				return -EMSGSIZE;
diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h
index 5c3d75b..e986ddb 100644
--- a/net/openvswitch/flow_netlink.h
+++ b/net/openvswitch/flow_netlink.h
@@ -68,6 +68,14 @@ int ovs_nla_copy_actions(const struct nlattr *attr,
 int ovs_nla_put_actions(const struct nlattr *attr,
 			int len, struct sk_buff *skb);
 
+void free_flow_actions(struct sw_flow_actions *);
 void ovs_nla_free_flow_actions(struct sw_flow_actions *);
 
+struct ovs_action_bpf_runtime {
+	uint32_t fd;
+	uint32_t arg0;
+	uint32_t arg1;
+	struct bpf_prog *prog;
+};
+
 #endif /* flow_netlink.h */
-- 
1.9.1

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ