[<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