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 <pshe...@nicira.com>
---
 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
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to