[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