2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-29 15:28:56 +00:00

sFlow: Genericize/simplify kernel sFlow implementation

Following patch adds sampling action which takes probability and set
of actions as arguments. When probability is hit, actions are executed for
given packet.
USERSPACE action's userdata (u64) is used to store struct
user_action_cookie as cookie. CONTROLLER action is fixed accordingly.

Now we can remove sFlow code from kernel and implement sFlow generically
as SAMPLE action. sFlow is defined as SAMPLE Action with probability (sFlow
sampling rate) and USERSPACE action as argument. USERSPACE action's data
is used as cookie. sFlow uses this cookie to store output-port, number of
output ports and vlan-id. sample-pool is calculated by using vport
stats.

Signed-off-by: Pravin Shelar <pshelar@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Pravin Shelar
2011-09-28 10:43:07 -07:00
parent 89ac6b1f19
commit 6ff686f2bc
16 changed files with 437 additions and 325 deletions

View File

@@ -28,8 +28,8 @@
#include "vlan.h"
#include "vport.h"
static int do_execute_actions(struct datapath *, struct sk_buff *,
struct sw_flow_actions *acts);
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *attr, int len, bool keep_skb);
static int make_writable(struct sk_buff *skb, int write_len)
{
@@ -255,15 +255,37 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, u64 arg)
upcall.cmd = OVS_PACKET_CMD_ACTION;
upcall.key = &OVS_CB(skb)->flow->key;
upcall.userdata = arg;
upcall.sample_pool = 0;
upcall.actions = NULL;
upcall.actions_len = 0;
return dp_upcall(dp, skb, &upcall);
}
static int sample(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *attr)
{
const struct nlattr *acts_list = NULL;
const struct nlattr *a;
int rem;
for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
a = nla_next(a, &rem)) {
switch (nla_type(a)) {
case OVS_SAMPLE_ATTR_PROBABILITY:
if (net_random() >= nla_get_u32(a))
return 0;
break;
case OVS_SAMPLE_ATTR_ACTIONS:
acts_list = a;
break;
}
}
return do_execute_actions(dp, skb, nla_data(acts_list),
nla_len(acts_list), true);
}
/* Execute a list of actions against 'skb'. */
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_actions *acts)
const struct nlattr *attr, int len, bool keep_skb)
{
/* Every output action needs a separate clone of 'skb', but the common
* case is just a single output action, so that doing a clone and
@@ -274,7 +296,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *a;
int rem;
for (a = acts->actions, rem = acts->actions_len; rem > 0;
for (a = attr, rem = len; rem > 0;
a = nla_next(a, &rem)) {
int err = 0;
@@ -339,49 +361,29 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
case OVS_ACTION_ATTR_POP_PRIORITY:
skb->priority = priority;
break;
}
case OVS_ACTION_ATTR_SAMPLE:
err = sample(dp, skb, a);
break;
}
if (unlikely(err)) {
kfree_skb(skb);
return err;
}
}
if (prev_port != -1)
if (prev_port != -1) {
if (keep_skb)
skb = skb_clone(skb, GFP_ATOMIC);
do_output(dp, skb, prev_port);
else
} else if (!keep_skb)
consume_skb(skb);
return 0;
}
static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_actions *acts)
{
struct sk_buff *nskb;
struct vport *p = OVS_CB(skb)->vport;
struct dp_upcall_info upcall;
if (unlikely(!p))
return;
atomic_inc(&p->sflow_pool);
if (net_random() >= dp->sflow_probability)
return;
nskb = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!nskb))
return;
upcall.cmd = OVS_PACKET_CMD_SAMPLE;
upcall.key = &OVS_CB(skb)->flow->key;
upcall.userdata = 0;
upcall.sample_pool = atomic_read(&p->sflow_pool);
upcall.actions = acts->actions;
upcall.actions_len = acts->actions_len;
dp_upcall(dp, nskb, &upcall);
}
/* Execute a list of actions against 'skb'. */
int execute_actions(struct datapath *dp, struct sk_buff *skb)
{
@@ -399,11 +401,9 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb)
goto out_loop;
}
/* Really execute actions. */
if (dp->sflow_probability)
sflow_sample(dp, skb, acts);
OVS_CB(skb)->tun_id = 0;
error = do_execute_actions(dp, skb, acts);
error = do_execute_actions(dp, skb, acts->actions,
acts->actions_len, false);
/* Check whether sub-actions looped too much. */
if (unlikely(loop->looping))