+ return error;
+}
+
+static void
+ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
+ void *aux OVS_UNUSED)
+{
+ struct ofproto_dpif *ofproto;
+ struct ofpbuf *packet;
+ const char *error;
+ struct flow flow;
+
+ error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet);
+ if (!error) {
+ struct ds result;
+
+ ds_init(&result);
+ ofproto_trace(ofproto, &flow, packet, NULL, 0, &result);
+ unixctl_command_reply(conn, ds_cstr(&result));
+ ds_destroy(&result);
+ ofpbuf_delete(packet);
+ } else {
+ unixctl_command_reply_error(conn, error);
+ }
+}
+
+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. With -consistent, we
+ * enforce consistency even for a flow supported in OpenFlow 1.0. */
+ if (!strcmp(argv[1], "-consistent")) {
+ enforce_consistency = true;
+ argv++;
+ argc--;
+ } else {
+ enforce_consistency = false;
+ }
+
+ 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;
+ }
+ if (enforce_consistency) {
+ retval = ofpacts_check_consistency(ofpacts.data, ofpacts.size, &flow,
+ u16_to_ofp(ofproto->up.max_ports),
+ 0, 0, usable_protocols);
+ } else {
+ retval = ofpacts_check(ofpacts.data, ofpacts.size, &flow,
+ u16_to_ofp(ofproto->up.max_ports), 0, 0,
+ &usable_protocols);
+ }
+
+ 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);