[ovs-dev] [PATCH 3/3] ofproto-dpif: New unixctl command ofproto/trace-packet-out.

Gurucharan Shetty shettyg at nicira.com
Tue Nov 5 23:27:16 UTC 2013


On Wed, Oct 30, 2013 at 2:13 PM, Ben Pfaff <blp at nicira.com> wrote:
> Feature #20543.
> Requested-by: Ronghua Zhang <rzhang at vmware.com>
> Signed-off-by: Ben Pfaff <blp at nicira.com>
> ---
>  ofproto/ofproto-dpif.c      |  123 ++++++++++++++++++++++++++++++++++++++-----
>  ofproto/ofproto-unixctl.man |   57 +++++++++++++++-----
>  tests/ofproto-dpif.at       |   19 +++++++
>  3 files changed, 172 insertions(+), 27 deletions(-)
>
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index d735507..c79570e 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -515,7 +515,9 @@ ofproto_dpif_cast(const struct ofproto *ofproto)
>  static struct ofport_dpif *get_ofp_port(const struct ofproto_dpif *ofproto,
>                                          ofp_port_t ofp_port);
>  static void ofproto_trace(struct ofproto_dpif *, const struct flow *,
> -                          const struct ofpbuf *packet, struct ds *);
> +                          const struct ofpbuf *packet,
> +                          const struct ofpact[], size_t ofpacts_len,
> +                          struct ds *);
I think the above change in ofproto_trace definition should be in patch 1.

>
>  /* Upcalls. */
>  static void handle_upcalls(struct dpif_backer *);
> @@ -5278,31 +5280,118 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
>  }
>
>  static void
> +ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
> +                              const char *argv[], void *aux OVS_UNUSED)
> +{
> +    enum ofputil_protocol usable_protocols;
> +    struct ofproto_dpif *ofproto;
> +    bool enforce_consistency;
> +    struct ofpbuf ofpacts;
> +    struct ofpbuf *packet;
> +    struct ds result;
> +    struct flow flow;
> +    uint16_t in_port;
> +
> +    /* Three kinds of error return values! */
> +    enum ofperr retval;
> +    const char *error;
> +    char *rw_error;
> +
> +    packet = NULL;
> +    ds_init(&result);
> +    ofpbuf_init(&ofpacts, 0);
> +
> +    /* Parse actions. */
> +    rw_error = parse_ofpacts(argv[--argc], &ofpacts, &usable_protocols);
> +    if (rw_error) {
> +        unixctl_command_reply_error(conn, rw_error);
> +        free(rw_error);
> +        goto exit;
> +    }
> +
> +    /* OpenFlow 1.1 and later suggest that the switch enforces certain forms of
> +     * consistency between the flow and the actions, so enforce these by
> +     * default if the actions can only work in OF1.1 or later. */
> +    enforce_consistency = !(usable_protocols & OFPUTIL_P_OF10_ANY);
> +    if (!strcmp(argv[1], "-consistent")) {
> +        enforce_consistency = true;
> +        argv++;
> +        argc--;
> +    }
> +
> +    error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet);
> +    if (error) {
> +        unixctl_command_reply_error(conn, error);
> +        goto exit;
> +    }
> +
> +    /* Do the same checks as handle_packet_out() in ofproto.c.
> +     *
> +     * We pass a 'table_id' of 0 to ofproto_check_ofpacts(), which isn't
> +     * strictly correct because these actions aren't in any table, but it's OK
> +     * because it 'table_id' is used only to check goto_table instructions, but
> +     * packet-outs take a list of actions and therefore it can't include
> +     * instructions.
> +     *
> +     * We skip the "meter" check here because meter is an instruction, not an
> +     * action, and thus cannot appear in ofpacts. */
> +    in_port = ofp_to_u16(flow.in_port.ofp_port);
> +    if (in_port >= ofproto->up.max_ports && in_port < ofp_to_u16(OFPP_MAX)) {
> +        unixctl_command_reply_error(conn, "invalid in_port");
> +        goto exit;
> +    }
> +    retval = ofpacts_check(ofpacts.data, ofpacts.size, &flow,
> +                           u16_to_ofp(ofproto->up.max_ports), 0,
> +                           enforce_consistency);
This patch needs a rebase as ofpacts_check interface has changed by a
later commit.

Otherrwise, This looks good to me.


> +    if (retval) {
> +        ds_clear(&result);
> +        ds_put_format(&result, "Bad actions: %s", ofperr_to_string(retval));
> +        unixctl_command_reply_error(conn, ds_cstr(&result));
> +        goto exit;
> +    }
> +
> +    ofproto_trace(ofproto, &flow, packet, ofpacts.data, ofpacts.size, &result);
> +    unixctl_command_reply(conn, ds_cstr(&result));
> +
> +exit:
> +    ds_destroy(&result);
> +    ofpbuf_delete(packet);
> +    ofpbuf_uninit(&ofpacts);
> +}
> +
> +static void
>  ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
> -              const struct ofpbuf *packet, struct ds *ds)
> +              const struct ofpbuf *packet,
> +              const struct ofpact ofpacts[], size_t ofpacts_len,
> +              struct ds *ds)
It will be nice if this function has a comment at the top.
>  {
>      struct rule_dpif *rule;
>      struct flow_wildcards wc;
>
> +    ds_put_format(ds, "Bridge: %s\n", ofproto->up.name);
>      ds_put_cstr(ds, "Flow: ");
>      flow_format(ds, flow);
>      ds_put_char(ds, '\n');
>
>      flow_wildcards_init_catchall(&wc);
> -    rule_dpif_lookup(ofproto, flow, &wc, &rule);
> +    if (ofpacts) {
> +        rule = NULL;
> +    } else {
> +        rule_dpif_lookup(ofproto, flow, &wc, &rule);
>
> -    trace_format_rule(ds, 0, rule);
> -    if (rule == ofproto->miss_rule) {
> -        ds_put_cstr(ds, "\nNo match, flow generates \"packet in\"s.\n");
> -    } else if (rule == ofproto->no_packet_in_rule) {
> -        ds_put_cstr(ds, "\nNo match, packets dropped because "
> -                    "OFPPC_NO_PACKET_IN is set on in_port.\n");
> -    } else if (rule == ofproto->drop_frags_rule) {
> -        ds_put_cstr(ds, "\nPackets dropped because they are IP fragments "
> -                    "and the fragment handling mode is \"drop\".\n");
> +        trace_format_rule(ds, 0, rule);
> +        if (rule == ofproto->miss_rule) {
> +            ds_put_cstr(ds, "\nNo match, flow generates \"packet in\"s.\n");
> +        } else if (rule == ofproto->no_packet_in_rule) {
> +            ds_put_cstr(ds, "\nNo match, packets dropped because "
> +                        "OFPPC_NO_PACKET_IN is set on in_port.\n");
> +        } else if (rule == ofproto->drop_frags_rule) {
> +            ds_put_cstr(ds, "\nPackets dropped because they are IP fragments "
> +                        "and the fragment handling mode is \"drop\".\n");
> +        }
>      }
>
> -    if (rule) {
> +    if (rule || ofpacts) {
>          uint64_t odp_actions_stub[1024 / 8];
>          struct ofpbuf odp_actions;
>          struct trace_ctx trace;
> @@ -5315,6 +5404,10 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
>          ofpbuf_use_stub(&odp_actions,
>                          odp_actions_stub, sizeof odp_actions_stub);
>          xlate_in_init(&trace.xin, ofproto, flow, rule, tcp_flags, packet);
> +        if (ofpacts) {
> +            trace.xin.ofpacts = ofpacts;
> +            trace.xin.ofpacts_len = ofpacts_len;
> +        }
>          trace.xin.resubmit_hook = trace_resubmit;
>          trace.xin.report_hook = trace_report;
>
> @@ -5750,6 +5843,10 @@ ofproto_dpif_unixctl_init(void)
>          "ofproto/trace",
>          "{[dp_name] odp_flow | bridge br_flow} [-generate|packet]",
>          1, 3, ofproto_unixctl_trace, NULL);
> +    unixctl_command_register(
> +        "ofproto/trace-packet-out",
> +        "[-consistent] {[dp_name] odp_flow | bridge br_flow} [-generate|packet] actions",
> +        2, 6, ofproto_unixctl_trace_actions, NULL);
>      unixctl_command_register("fdb/flush", "[bridge]", 0, 1,
>                               ofproto_unixctl_fdb_flush, NULL);
>      unixctl_command_register("fdb/show", "bridge", 1, 1,
> diff --git a/ofproto/ofproto-unixctl.man b/ofproto/ofproto-unixctl.man
> index dd8e8d8..89013d9 100644
> --- a/ofproto/ofproto-unixctl.man
> +++ b/ofproto/ofproto-unixctl.man
> @@ -6,15 +6,30 @@ These commands manage the core OpenFlow switch implementation (called
>  Lists the names of the running ofproto instances.  These are the names
>  that may be used on \fBofproto/trace\fR.
>  .
> -.IP "\fBofproto/trace\fR [\fIdpname\fR] \fIodp_flow\fR [\fB\-generate \fR| \
> -\fIpacket\fR]"
> -.IQ "\fBofproto/trace\fR \fIbridge\fR \fIbr_flow\fR \
> -[\fB\-generate \fR| \fIpacket\fR]"
> +.IP "\fBofproto/trace\fR [\fIdpname\fR] \fIodp_flow\fR [\fB\-generate \fR| \fIpacket\fR]"
> +.IQ "\fBofproto/trace\fR \fIbridge\fR \fIbr_flow\fR [\fB\-generate \fR| \fIpacket\fR]"
> +.IQ "\fBofproto/trace\-packet\-out\fR [\fB\-consistent\fR] [\fIdpname\fR] \fIodp_flow\fR [\fB\-generate \fR| \fIpacket\fR] \fIactions\fR"
> +.IQ "\fBofproto/trace\-packet\-out\fR [\fB\-consistent\fR] \fIbridge\fR \fIbr_flow\fR [\fB\-generate \fR| \fIpacket\fR] \fIactions\fR"
>  Traces the path of an imaginary packet through \fIswitch\fR and
> -reports the path that it took.  The packet's headers (e.g. source and
> -destination) and metadata (e.g. input port), together called its
> -``flow,'' are usually all that matter for this purpose.  You can
> -specify the flow in the following ways:
> +reports the path that it took.  The initial treatment of the packet
> +varies based on the command:
> +.
> +.RS
> +.IP \(bu
> +\fBofproto/trace\fR looks the packet up in the OpenFlow flow table, as
> +if the packet had arrived on an OpenFlow port.
> +.
> +.IP \(bu
> +\fBofproto/trace\-packet\-out\fR applies the specified OpenFlow
> +\fIactions\fR, as if the packet, flow, and actions had been specified
> +in an OpenFlow ``packet-out'' request.
> +.RE
> +.
> +.IP
> +The packet's headers (e.g. source and destination) and metadata
> +(e.g. input port), together called its ``flow,'' are usually all that
> +matter for the purpose of tracing a packet.  You can specify the flow
> +in the following ways:
>  .
>  .RS
>  .IP "\fIdpname\fR \fIodp_flow\fR"
> @@ -41,13 +56,13 @@ instead of just a flow:
>  .IP "Side effects."
>  Some actions have side effects.  For example, the \fBnormal\fR action
>  can update the MAC learning table, and the \fBlearn\fR action can
> -change OpenFlow tables.  \fBofproto/trace\fR only performs side
> +change OpenFlow tables.  The trace commands only perform side
>  effects when a packet is specified.  If you want side effects to take
>  place, then you must supply a packet.
>  .
>  .IP
>  (Output actions are obviously side effects too, but
> -\fBofproto/trace\fR never executes them, even when one specifies a
> +the trace commands never execute them, even when one specifies a
>  packet.)
>  .
>  .IP "Incomplete information."
> @@ -55,12 +70,12 @@ Most of the time, Open vSwitch can figure out everything about the
>  path of a packet using just the flow, but in some special
>  circumstances it needs to look at parts of the packet that are not
>  included in the flow.  When this is the case, and you do not supply a
> -packet, then \fBofproto/trace\fR will tell you it needs a packet.
> +packet, then a trace command will tell you it needs a packet.
>  .RE
>  .
>  .IP
> -If you wish to include a packet as part of the \fBofproto/trace\fR
> -operation, there are two ways to do it:
> +If you wish to include a packet as part of a trace operation, there
> +are two ways to do it:
>  .
>  .RS
>  .IP \fB\-generate\fR
> @@ -93,11 +108,25 @@ The tunnel ID on which the packet arrived.
>  .IP \fIin_port\fR
>  The port on which the packet arrived.
>  .RE
> +.RE
>  .
> +.IP
>  The in_port value is kernel datapath port number for the first format
>  and OpenFlow port number for the second format. The numbering of these
>  two types of port usually differs and there is no relationship.
> -.RE
> +.
> +.IP
> +\fBofproto\-trace\-packet\-out\fR accepts an additional
> +\fB\-consistent\fR option.  With this option specified, the command
> +rejects \fIactions\fR that are inconsistent with the specified packet.
> +(An example of an inconsistency is attempting to strip the VLAN tag
> +from a packet that does not have a VLAN tag.)  Open vSwitch ignores
> +most forms of inconsistency in OpenFlow 1.0 and rejects
> +inconsistencies in later versions of OpenFlow.  The option is
> +necessary because the command does not ordinarily imply a particular
> +OpenFlow version.  One exception is that, when \fIactions\fR includes
> +an action that only OpenFlow 1.1 and later supports (such as
> +\fBpush_vlan\fR), \fB\-consistent\fR is automatically enabled.
>  .IP "\fBofproto/self\-check\fR [\fIswitch\fR]"
>  Runs an internal consistency check on \fIswitch\fR, if specified,
>  otherwise on all ofproto instances, and responds with a brief summary
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index 4ae1054..a81b757 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -1504,6 +1504,25 @@ ovs-appctl: ovs-vswitchd: server returned an error
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
>
> +AT_SETUP([ofproto-dpif - ofproto/trace-packet-out])
> +OVS_VSWITCHD_START
> +ADD_OF_PORTS([br0], 1, 2, 3)
> +
> +AT_DATA([flows.txt], [dnl
> +in_port=1 actions=output:2
> +in_port=2 actions=output:1
> +])
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +AT_CHECK([ovs-appctl ofproto/trace-packet-out br0 in_port=1 'mod_vlan_vid:123,resubmit(,0)'], [0], [stdout])
> +AT_CHECK([tail -1 stdout], [0], [dnl
> +Datapath actions: push_vlan(vid=123,pcp=0),2
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +
>  m4_define([OFPROTO_TRACE],
>    [flow="$2"
>     AT_CHECK([ovs-appctl ofproto/trace $1 "$flow" $3], [0], [stdout])
> --
> 1.7.10.4
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev



More information about the dev mailing list