This is incremental patch to sFlow patch posted. Fixed according to
comments from Jesse.
- Fixed use-after-free bug in sample()
- Fixed comments
- Controller generated packets at undefined in_port are not
sampled
Signed-off-by: Pravin Shelar <[email protected]>
---
datapath/actions.c | 29 +++++++--------
datapath/datapath.c | 2 +-
datapath/datapath.h | 4 +-
include/openvswitch/datapath-protocol.h | 14 +++++---
lib/odp-util.c | 17 ++++-----
ofproto/ofproto-dpif-sflow.c | 8 +----
ofproto/ofproto-dpif.c | 57 ++++++++++++++++---------------
7 files changed, 64 insertions(+), 67 deletions(-)
diff --git a/datapath/actions.c b/datapath/actions.c
index 6fb6ea6..cba12e6 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -28,7 +28,7 @@
#include "vlan.h"
#include "vport.h"
-static int __do_execute_actions(struct datapath *dp, struct sk_buff *skb,
+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)
@@ -265,7 +265,8 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *a;
int rem;
- nla_for_each_nested(a, attr, 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))
@@ -273,16 +274,17 @@ static int sample(struct datapath *dp, struct sk_buff
*skb,
break;
case OVS_SAMPLE_ATTR_ACTIONS:
- acts_list = nla_data(a);
+ acts_list = a;
break;
}
}
- return __do_execute_actions(dp, skb, acts_list, nla_len(acts_list), 1);
+ 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,
+static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *attr, int len, bool keep_skb)
{
/* Every output action needs a separate clone of 'skb', but the common
@@ -371,21 +373,17 @@ static int __do_execute_actions(struct datapath *dp,
struct sk_buff *skb,
}
}
- if (prev_port != -1)
+ if (prev_port != -1) {
+ if (keep_skb)
+ skb = skb_clone(skb, GFP_ATOMIC);
+
do_output(dp, skb, prev_port);
- else if (!keep_skb)
+ } else if (!keep_skb)
consume_skb(skb);
return 0;
}
-
-static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
- struct sw_flow_actions *acts)
-{
- return __do_execute_actions(dp, skb, acts->actions, acts->actions_len,
0);
-}
-
/* Execute a list of actions against 'skb'. */
int execute_actions(struct datapath *dp, struct sk_buff *skb)
{
@@ -404,7 +402,8 @@ int execute_actions(struct datapath *dp, struct sk_buff
*skb)
}
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))
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 189ca39..63a3932 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -544,7 +544,7 @@ static int validate_actions(const struct nlattr *attr, int
depth)
const struct nlattr *a;
int rem, err;
- if (depth >= MAX_ACTIONS_DEPTH)
+ if (depth >= SAMPLE_ACTION_DEPTH)
return -EOVERFLOW;
nla_for_each_nested(a, attr, rem) {
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 361fe6b..ea200a3 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -34,7 +34,7 @@ struct vport;
#define DP_MAX_PORTS 1024
-#define MAX_ACTIONS_DEPTH 3
+#define SAMPLE_ACTION_DEPTH 3
/**
* struct dp_stats_percpu - per-cpu packet processing statistics for a given
@@ -123,7 +123,7 @@ struct ovs_skb_cb {
* struct dp_upcall - metadata to include with a packet to send to userspace
* @cmd: One of %OVS_PACKET_CMD_*.
* @key: Becomes %OVS_PACKET_ATTR_KEY. Must be nonnull.
- * @userdata: Is passed to user-space as %OVS_PACKET_ATTR_USERDATA if cmd is
+ * @userdata: Is passed to user-space as %OVS_PACKET_ATTR_USERDATA if @cmd is
* %OVS_PACKET_CMD_ACTION.
*/
struct dp_upcall_info {
diff --git a/include/openvswitch/datapath-protocol.h
b/include/openvswitch/datapath-protocol.h
index 3f83b23..b29ff0e 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -168,6 +168,8 @@ enum ovs_packet_cmd {
* extracted from the packet as nested %OVS_KEY_ATTR_* attributes. This allows
* userspace to adapt its flow setup strategy by comparing its notion of the
* flow key against the kernel's.
+ * @OVS_PACKET_ATTR_ACTIONS: Contains actions for the packet. Used
+ * for %OVS_PACKET_CMD_EXECUTE. It has nested %OVS_ACTION_ATTR_* attributes.
* @OVS_PACKET_ATTR_UPCALL_PID: Optionally present for OVS_PACKET_CMD_EXECUTE.
* The Netlink socket in userspace that OVS_PACKET_CMD_USERSPACE and
* OVS_PACKET_CMD_SAMPLE upcalls will be directed to for actions triggered by
@@ -175,8 +177,7 @@ enum ovs_packet_cmd {
* @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION
* notification if the %OVS_ACTION_ATTR_USERSPACE, action's argument was
* nonzero.
- * @OVS_PACKET_ATTR_ACTIONS: Contains a copy of the actions for the packet.
Used
- * for %OVS_PACKET_CMD_EXECUTE. It has nested %OVS_ACTION_ATTR_* attributes.
+ *
* These attributes follow the &struct ovs_header within the Generic Netlink
* payload for %OVS_PACKET_* commands.
*/
@@ -184,9 +185,9 @@ enum ovs_packet_attr {
OVS_PACKET_ATTR_UNSPEC,
OVS_PACKET_ATTR_PACKET, /* Packet data. */
OVS_PACKET_ATTR_KEY, /* Nested OVS_KEY_ATTR_* attributes. */
+ OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
OVS_PACKET_ATTR_UPCALL_PID, /* Netlink PID to receive upcalls. */
OVS_PACKET_ATTR_USERDATA, /* u64 OVS_ACTION_ATTR_USERSPACE arg. */
- OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
__OVS_PACKET_ATTR_MAX
};
@@ -416,7 +417,10 @@ enum ovs_flow_attr {
/**
* enum ovs_sample_attr - Attributes for OVS_ACTION_ATTR_SAMPLE
- * @OVS_SAMPLE_ATTR_PROBABILITY: Prabability for sample event.
+ * @OVS_SAMPLE_ATTR_PROBABILITY: 32-bit fraction of packets to sample with
+ * @OVS_ACTION_ATTR_SAMPLE. A value of 0 samples no packets, a value of
+ * %UINT32_MAX samples all packets and intermediate values sample intermediate
+ * fractions of packets.
* @OVS_SAMPLE_ATTR_ACTIONS: Set of actions to execute in sampling event.
* Actions are passed as nested attributes.
*/
@@ -447,7 +451,7 @@ enum ovs_action_type {
OVS_ACTION_ATTR_SET_PRIORITY, /* Set skb->priority. */
OVS_ACTION_ATTR_POP_PRIORITY, /* Restore original skb->priority. */
OVS_ACTION_ATTR_SAMPLE, /* Execute list of actions at given
- prabability. */
+ probability. */
__OVS_ACTION_ATTR_MAX
};
diff --git a/lib/odp-util.c b/lib/odp-util.c
index c8ee983..d97d30c 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -32,7 +32,6 @@
#include "packets.h"
#include "timeval.h"
#include "util.h"
-#include "ofproto/ofproto.h"
/* The interface between userspace and kernel uses an "OVS_*" prefix.
* Since this is fairly non-specific for the OVS userspace components,
@@ -94,11 +93,11 @@ format_generic_odp_action(struct ds *ds, const struct
nlattr *a)
static void
format_odp_sample_action(struct ds *ds, const struct nlattr *attr)
{
- static const struct nl_policy ovs_sample_act[] = {
- [OVS_SAMPLE_ATTR_PROBABILITY] = { .type = NL_A_U32, .optional = false
},
- [OVS_SAMPLE_ATTR_ACTIONS] = { .type = NL_A_UNSPEC, .optional = false },
+ static const struct nl_policy ovs_sample_policy[] = {
+ [OVS_SAMPLE_ATTR_PROBABILITY] = { .type = NL_A_U32 },
+ [OVS_SAMPLE_ATTR_ACTIONS] = { .type = NL_A_NESTED }
};
- struct nlattr *a[ARRAY_SIZE(ovs_sample_act)];
+ struct nlattr *a[ARRAY_SIZE(ovs_sample_policy)];
struct ofpbuf buf;
double percentage;
const struct nlattr *nla_acts;
@@ -107,8 +106,8 @@ format_odp_sample_action(struct ds *ds, const struct nlattr
*attr)
ds_put_cstr(ds, "sample");
ofpbuf_use_const(&buf, nl_attr_get(attr), nl_attr_get_size(attr));
- if (!nl_policy_parse(&buf, 0, ovs_sample_act, a,
- ARRAY_SIZE(ovs_sample_act))) {
+ if (!nl_policy_parse(&buf, 0, ovs_sample_policy, a,
+ ARRAY_SIZE(ovs_sample_policy))) {
ds_put_cstr(ds, "(error)");
return;
}
@@ -150,7 +149,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
memcpy(&cookie, &data, sizeof(cookie));
if (cookie.type == USER_ACTION_COOKIE_CONTROLLER) {
- ds_put_format(ds, "userspace(controller,data=%"PRIu32")",
+ ds_put_format(ds, "userspace(controller,length=%"PRIu32")",
cookie.data);
} else if (cookie.type == USER_ACTION_COOKIE_SFLOW) {
ds_put_format(ds, "userspace(sFlow,n_output=%"PRIu8","
@@ -158,7 +157,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
cookie.n_output, vlan_tci_to_vid(cookie.vlan_tci),
vlan_tci_to_pcp(cookie.vlan_tci), cookie.data);
} else {
- ds_put_format(ds, "userspace(Unknown,data=0x%"PRIx64")",
+ ds_put_format(ds, "userspace(unknown,data=0x%"PRIx64")",
nl_attr_get_u64(a));
}
break;
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index b96d7d2..cc9a5bd 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -503,8 +503,6 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf
*packet,
in_dsp = dpif_sflow_find_port(ds, ofp_port_to_odp_port(flow->in_port));
if (!in_dsp) {
- VLOG_WARN_RL(&rl, "No sFlow port for input port (%"PRIu32")",
- flow->in_port);
return;
}
fs.input = SFL_DS_INDEX(in_dsp->dsi);
@@ -514,7 +512,7 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf
*packet,
VLOG_WARN_RL(&rl, "netdev get-stats error %s", strerror(error));
return;
}
- fs.sample_pool = stats.rx_packets + stats.tx_packets;
+ fs.sample_pool = stats.rx_packets;
/* We are going to give it to the sampler that represents this input port.
* By implementing "ingress-only" sampling like this we ensure that we
@@ -545,10 +543,6 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf
*packet,
switchElem.tag = SFLFLOW_EX_SWITCH;
switchElem.flowType.sw.src_vlan = vlan_tci_to_vid(flow->vlan_tci);
switchElem.flowType.sw.src_priority = vlan_tci_to_pcp(flow->vlan_tci);
- /* Initialize the output VLAN and priority to be the same as the input,
- but these fields can be overriden below if affected by an action. */
- switchElem.flowType.sw.dst_vlan = switchElem.flowType.sw.src_vlan;
- switchElem.flowType.sw.dst_priority = switchElem.flowType.sw.src_priority;
/* Retrieve data from user_action_cookie. */
switchElem.flowType.sw.dst_vlan = vlan_tci_to_vid(cookie->vlan_tci);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 39d9f2f..ba4a29e 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -404,9 +404,9 @@ static int expire(struct ofproto_dpif *);
/* Utilities. */
static int send_packet(struct ofproto_dpif *, uint32_t odp_port,
const struct ofpbuf *packet);
-static size_t compose_sflow_action(struct ofpbuf *odp_actions,
- uint32_t probability,
- uint32_t odp_port);
+static size_t
+compose_sflow_action(struct ofproto_dpif *, struct ofpbuf *odp_actions,
+ const struct flow *, uint32_t odp_port);
/* Global variables. */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
@@ -2939,15 +2939,7 @@ send_packet(struct ofproto_dpif *ofproto, uint32_t
odp_port,
odp_flow_key_from_flow(&key, &flow);
ofpbuf_init(&odp_actions, 32);
- if (ofproto->sflow) {
- uint32_t port_ifindex;
- uint32_t probability;
-
- probability = dpif_sflow_get_probability(ofproto->sflow);
- port_ifindex = dpif_sflow_odp_port_to_ifindex(ofproto->sflow,
odp_port);
-
- compose_sflow_action(&odp_actions, probability, port_ifindex);
- }
+ compose_sflow_action(ofproto, &odp_actions, &flow, odp_port);
nl_msg_put_u32(&odp_actions, OVS_ACTION_ATTR_OUTPUT, odp_port);
error = dpif_execute(ofproto->dpif,
@@ -2971,17 +2963,33 @@ static void xlate_normal(struct action_xlate_ctx *);
/* Compose SAMPLE action for sFlow. */
static size_t
-compose_sflow_action(struct ofpbuf *odp_actions,
- uint32_t probability,
- uint32_t port_ifindex)
+compose_sflow_action(struct ofproto_dpif *ofproto,
+ struct ofpbuf *odp_actions,
+ const struct flow *flow,
+ uint32_t odp_port)
{
+ uint32_t port_ifindex;
+ uint32_t probability;
struct user_action_cookie *cookie;
size_t sample_offset, actions_offset;
- int user_cookie_offset;
+ int user_cookie_offset, n_output;
+
+ if (!ofproto->sflow || flow->in_port == OFPP_NONE) {
+ return 0;
+ }
+
+ if (odp_port == OVSP_NONE) {
+ port_ifindex = 0;
+ n_output = 0;
+ } else {
+ port_ifindex = dpif_sflow_odp_port_to_ifindex(ofproto->sflow,
odp_port);
+ n_output = 1;
+ }
sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE);
/* Number of packets out of UINT_MAX to sample. */
+ probability = dpif_sflow_get_probability(ofproto->sflow);
nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability);
actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS);
@@ -2990,7 +2998,7 @@ compose_sflow_action(struct ofpbuf *odp_actions,
sizeof(*cookie));
cookie->type = USER_ACTION_COOKIE_SFLOW;
cookie->data = port_ifindex;
- cookie->n_output = 1;
+ cookie->n_output = n_output;
cookie->vlan_tci = 0;
user_cookie_offset = (char *) cookie - (char *) odp_actions->data;
@@ -3005,16 +3013,9 @@ compose_sflow_action(struct ofpbuf *odp_actions,
static void
add_sflow_action(struct action_xlate_ctx *ctx)
{
- uint32_t probability;
-
- if (!ctx->ofproto->sflow) {
- return;
- }
-
- probability = dpif_sflow_get_probability(ctx->ofproto->sflow);
- ctx->user_cookie_offset = compose_sflow_action(ctx->odp_actions,
- probability, 0);
-
+ ctx->user_cookie_offset = compose_sflow_action(ctx->ofproto,
+ ctx->odp_actions,
+ &ctx->flow, OVSP_NONE);
ctx->sflow_odp_port = 0;
ctx->sflow_n_outputs = 0;
}
@@ -3028,7 +3029,7 @@ fix_sflow_action(struct action_xlate_ctx *ctx)
const struct flow *base = &ctx->base_flow;
struct user_action_cookie *cookie;
- if (!ctx->ofproto->sflow) {
+ if (!ctx->user_cookie_offset) {
return;
}
--
1.7.1
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev