diff mbox series

[ovs-dev] ofproto-dpif-trace: Make -generate send packets to controller again.

Message ID 20180824192539.5286-1-blp@ovn.org
State Accepted
Headers show
Series [ovs-dev] ofproto-dpif-trace: Make -generate send packets to controller again. | expand

Commit Message

Ben Pfaff Aug. 24, 2018, 7:25 p.m. UTC
Prior to the OVS 2.9 development cycle, any flow that sent a packet to a
controller required that the flow be slow-pathed.  In some cases this led
to poor performance, so OVS 2.9 made controller actions fast-pathable.  As
a side effect of the change, "ovs-appctl ofproto/trace -generate" no longer
sent packets to the controller.  This usually didn't matter but it broke
the Faucet tutorial, which relied on this behavior.  This commit
reintroduces the original behavior and thus should fix the tutorial.

CC: Justin Pettit <jpettit@ovn.org>
Fixes: d39ec23de384 ("ofproto-dpif: Don't slow-path controller actions.")
Reported-by: macman31 <https://github.com/macman31>
Reported-at: https://github.com/openvswitch/ovs-issues/issues/145
Reported-by: Brad Cowie <brad@cowie.nz>
Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2018-August/047234.html
Signed-off-by: Ben Pfaff <blp@ovn.org>
---
 ofproto/ofproto-dpif-trace.c | 91 +++++++++++++++++++++++++++++++++++++-------
 ofproto/ofproto-unixctl.man  |  6 +--
 2 files changed, 80 insertions(+), 17 deletions(-)

Comments

Justin Pettit Aug. 24, 2018, 8:30 p.m. UTC | #1
> On Aug 24, 2018, at 12:25 PM, Ben Pfaff <blp@ovn.org> wrote:
> 
> +/* Copies ODP actions from 'in' (with length 'size') to 'out', dropping
> + * OVS_ACTION_ATTR_OUTPUT along the way. */
> +static void
> +prune_output_actions(const struct ofpbuf *in, struct ofpbuf *out)

Do you think it's worth clarifying that it's 'in->size'?  Otherwise it sounds like a separate argument.

> +/* Executes all of the datapath actions, except for any OVS_ACTION_ATTR_OUTPUT
> + * actions, in 'actions' on 'packet', which has the given 'flow', on 'dpif'.
> + * The actions have slow path reason 'slow' (if any).  Appends any error
> + * message to 'output'.
> + *
> + * This is mainly useful to execute actions to send a packet to an OpenFlow
> + * controller. */

Does this now generate NetFlow and sFlow events?  If so, do you think it's worth mentioning here and in the commit message?

Thanks for fixing this!

Acked-by: Justin Pettit <jpettit@ovn.org>

--Justin
Ben Pfaff Aug. 27, 2018, 4:40 p.m. UTC | #2
On Fri, Aug 24, 2018 at 01:30:24PM -0700, Justin Pettit wrote:
> 
> > On Aug 24, 2018, at 12:25 PM, Ben Pfaff <blp@ovn.org> wrote:
> > 
> > +/* Copies ODP actions from 'in' (with length 'size') to 'out', dropping
> > + * OVS_ACTION_ATTR_OUTPUT along the way. */
> > +static void
> > +prune_output_actions(const struct ofpbuf *in, struct ofpbuf *out)
> 
> Do you think it's worth clarifying that it's 'in->size'?  Otherwise it
> sounds like a separate argument.

Oh, whoops, this was a separate argument in a previous version.

I dropped the parenthetical.

> > +/* Executes all of the datapath actions, except for any OVS_ACTION_ATTR_OUTPUT
> > + * actions, in 'actions' on 'packet', which has the given 'flow', on 'dpif'.
> > + * The actions have slow path reason 'slow' (if any).  Appends any error
> > + * message to 'output'.
> > + *
> > + * This is mainly useful to execute actions to send a packet to an OpenFlow
> > + * controller. */
> 
> Does this now generate NetFlow and sFlow events?  If so, do you think it's worth mentioning here and in the commit message?

It does generate them.  I'll update things.

I decided to make it drop recirc actions too, which can also have side
effects.

> Thanks for fixing this!
> 
> Acked-by: Justin Pettit <jpettit@ovn.org>

Thanks, applied to master.
diff mbox series

Patch

diff --git a/ofproto/ofproto-dpif-trace.c b/ofproto/ofproto-dpif-trace.c
index e8fe0c6c17e9..2110fc713f0d 100644
--- a/ofproto/ofproto-dpif-trace.c
+++ b/ofproto/ofproto-dpif-trace.c
@@ -573,6 +573,74 @@  exit:
     free_ct_states(&next_ct_states);
 }
 
+static void
+explain_slow_path(enum slow_path_reason slow, struct ds *output)
+{
+    ds_put_cstr(output, "\nThis flow is handled by the userspace "
+                "slow path because it:");
+    for (; slow; slow = zero_rightmost_1bit(slow)) {
+        enum slow_path_reason bit = rightmost_1bit(slow);
+        ds_put_format(output, "\n  - %s.",
+                      slow_path_reason_to_explanation(bit));
+    }
+}
+
+/* Copies ODP actions from 'in' (with length 'size') to 'out', dropping
+ * OVS_ACTION_ATTR_OUTPUT along the way. */
+static void
+prune_output_actions(const struct ofpbuf *in, struct ofpbuf *out)
+{
+    const struct nlattr *a;
+    unsigned int left;
+    NL_ATTR_FOR_EACH (a, left, in->data, in->size) {
+        if (a->nla_type == OVS_ACTION_ATTR_CLONE) {
+            struct ofpbuf in_nested;
+            nl_attr_get_nested(a, &in_nested);
+
+            size_t ofs = nl_msg_start_nested(out, OVS_ACTION_ATTR_CLONE);
+            prune_output_actions(&in_nested, out);
+            nl_msg_end_nested(out, ofs);
+        } else if (a->nla_type != OVS_ACTION_ATTR_OUTPUT) {
+            ofpbuf_put(out, a, NLA_ALIGN(a->nla_len));
+        }
+    }
+}
+
+/* Executes all of the datapath actions, except for any OVS_ACTION_ATTR_OUTPUT
+ * actions, in 'actions' on 'packet', which has the given 'flow', on 'dpif'.
+ * The actions have slow path reason 'slow' (if any).  Appends any error
+ * message to 'output'.
+ *
+ * This is mainly useful to execute actions to send a packet to an OpenFlow
+ * controller. */
+static void
+execute_actions_except_outputs(struct dpif *dpif,
+                               const struct dp_packet *packet,
+                               const struct flow *flow,
+                               const struct ofpbuf *actions,
+                               enum slow_path_reason slow,
+                               struct ds *output)
+{
+    struct ofpbuf pruned_actions;
+    ofpbuf_init(&pruned_actions, 0);
+    prune_output_actions(actions, &pruned_actions);
+
+    struct dpif_execute execute = {
+        .actions = pruned_actions.data,
+        .actions_len = pruned_actions.size,
+        .needs_help = (slow & SLOW_ACTION) != 0,
+        .flow = flow,
+        .packet = dp_packet_clone_with_headroom(packet, 2),
+    };
+    int error = dpif_execute(dpif, &execute);
+    if (error) {
+        ds_put_format(output, "\nAction execution failed (%s)\n.",
+                      ovs_strerror(error));
+    }
+    dp_packet_delete(execute.packet);
+    ofpbuf_uninit(&pruned_actions);
+}
+
 static void
 ofproto_trace__(struct ofproto_dpif *ofproto, const struct flow *flow,
                 const struct dp_packet *packet, struct ovs_list *recirc_queue,
@@ -627,23 +695,18 @@  ofproto_trace__(struct ofproto_dpif *ofproto, const struct flow *flow,
         ds_put_format(output,
                       "\nTranslation failed (%s), packet is dropped.\n",
                       xlate_strerror(error));
-    } else if (xout.slow) {
-        enum slow_path_reason slow;
-
-        ds_put_cstr(output, "\nThis flow is handled by the userspace "
-                    "slow path because it:");
-
-        slow = xout.slow;
-        while (slow) {
-            enum slow_path_reason bit = rightmost_1bit(slow);
-
-            ds_put_format(output, "\n  - %s.",
-                          slow_path_reason_to_explanation(bit));
-
-            slow &= ~bit;
+    } else {
+        if (xout.slow) {
+            explain_slow_path(xout.slow, output);
+        }
+        if (packet) {
+            execute_actions_except_outputs(ofproto->backer->dpif, packet,
+                                           &initial_flow, &odp_actions,
+                                           xout.slow, output);
         }
     }
 
+
     xlate_out_uninit(&xout);
     ofpbuf_uninit(&odp_actions);
     oftrace_node_list_destroy(&trace);
diff --git a/ofproto/ofproto-unixctl.man b/ofproto/ofproto-unixctl.man
index dede5f39da84..2db4fe6330f9 100644
--- a/ofproto/ofproto-unixctl.man
+++ b/ofproto/ofproto-unixctl.man
@@ -126,9 +126,9 @@  effects when a packet is specified.  If you want side effects to take
 place, then you must supply a packet.
 .
 .IP
-(Side effects when tracing do not have external consequences.  Even if a
-packet is specified, a trace will not output a packet or generate sFlow,
-NetFlow or controller events.)
+(Output actions are obviously side effects too, but
+the trace commands never execute them, even when one specifies a
+packet.)
 .
 .IP "Incomplete information."
 Most of the time, Open vSwitch can figure out everything about the