Replace most uses of assert by ovs_assert.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index 6ce9a07..b37b482 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -565,7 +565,7 @@ static uint16_t odp_port_to_ofp_port(const struct ofproto_dpif *,
 static struct ofport_dpif *
 ofport_dpif_cast(const struct ofport *ofport)
 {
-    assert(ofport->ofproto->ofproto_class == &ofproto_dpif_class);
+    ovs_assert(ofport->ofproto->ofproto_class == &ofproto_dpif_class);
     return ofport ? CONTAINER_OF(ofport, struct ofport_dpif, up) : NULL;
 }
 
@@ -691,7 +691,7 @@ static void ofproto_dpif_unixctl_init(void);
 static struct ofproto_dpif *
 ofproto_dpif_cast(const struct ofproto *ofproto)
 {
-    assert(ofproto->ofproto_class == &ofproto_dpif_class);
+    ovs_assert(ofproto->ofproto_class == &ofproto_dpif_class);
     return CONTAINER_OF(ofproto, struct ofproto_dpif, up);
 }
 
@@ -950,7 +950,7 @@ close_dpif_backer(struct dpif_backer *backer)
 {
     struct shash_node *node;
 
-    assert(backer->refcount > 0);
+    ovs_assert(backer->refcount > 0);
 
     if (--backer->refcount) {
         return;
@@ -1124,7 +1124,7 @@ construct(struct ofproto *ofproto_)
     ofproto->port_poll_errno = 0;
 
     SHASH_FOR_EACH_SAFE (node, next, &init_ofp_ports) {
-        const struct iface_hint *iface_hint = node->data;
+        struct iface_hint *iface_hint = node->data;
 
         if (!strcmp(iface_hint->br_name, ofproto->up.name)) {
             /* Check if the datapath already has this port. */
@@ -1134,6 +1134,7 @@ construct(struct ofproto *ofproto_)
 
             free(iface_hint->br_name);
             free(iface_hint->br_type);
+            free(iface_hint);
             shash_delete(&init_ofp_ports, node);
         }
     }
@@ -1180,7 +1181,7 @@ add_internal_flow(struct ofproto_dpif *ofproto, int id,
     }
 
     *rulep = rule_dpif_lookup__(ofproto, &fm.match.flow, TBL_INTERNAL);
-    assert(*rulep != NULL);
+    ovs_assert(*rulep != NULL);
 
     return 0;
 }
@@ -2226,8 +2227,8 @@ bundle_set(struct ofproto *ofproto_, void *aux,
         return 0;
     }
 
-    assert(s->n_slaves == 1 || s->bond != NULL);
-    assert((s->lacp != NULL) == (s->lacp_slaves != NULL));
+    ovs_assert(s->n_slaves == 1 || s->bond != NULL);
+    ovs_assert((s->lacp != NULL) == (s->lacp_slaves != NULL));
 
     bundle = bundle_lookup(ofproto, aux);
     if (!bundle) {
@@ -2294,7 +2295,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
         found: ;
         }
     }
-    assert(list_size(&bundle->ports) <= s->n_slaves);
+    ovs_assert(list_size(&bundle->ports) <= s->n_slaves);
 
     if (list_is_empty(&bundle->ports)) {
         bundle_destroy(bundle);
@@ -2791,7 +2792,8 @@ get_ofp_port(const struct ofproto_dpif *ofproto, uint16_t ofp_port)
 static struct ofport_dpif *
 get_odp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
 {
-    return get_ofp_port(ofproto, odp_port_to_ofp_port(ofproto, odp_port));
+    struct ofport_dpif *port = odp_port_to_ofport(ofproto->backer, odp_port);
+    return port && &ofproto->up == port->up.ofproto ? port : NULL;
 }
 
 static void
@@ -2928,7 +2930,7 @@ port_get_stats(const struct ofport *ofport_, struct netdev_stats *stats)
 
     error = netdev_get_stats(ofport->up.netdev, stats);
 
-    if (!error && ofport->odp_port == OVSP_LOCAL) {
+    if (!error && ofport_->ofp_port == OFPP_LOCAL) {
         struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
 
         /* ofproto->stats.tx_packets represents packets that we created
@@ -3392,32 +3394,68 @@ handle_flow_miss(struct flow_miss *miss, struct flow_miss_op *ops,
     handle_flow_miss_with_facet(miss, facet, now, ops, n_ops);
 }
 
-/* This function does post-processing on data returned from
- * odp_flow_key_to_flow() to help make VLAN splinters transparent to the
- * rest of the upcall processing logic.  In particular, if the extracted
- * in_port is a VLAN splinter port, it replaces flow->in_port by the "real"
- * port, sets flow->vlan_tci correctly for the VLAN of the VLAN splinter
- * port, and pushes a VLAN header onto 'packet' (if it is nonnull). The
- * caller must have called odp_flow_key_to_flow() and supply 'fitness' and
- * 'flow' from its output.  The 'flow' argument must have had the "in_port"
- * member converted to the OpenFlow number.
+/* Given a datpath, packet, and flow metadata ('backer', 'packet', and 'key'
+ * respectively), populates 'flow' with the result of odp_flow_key_to_flow().
+ * Optionally, if nonnull, populates 'fitnessp' with the fitness of 'flow' as
+ * returned by odp_flow_key_to_flow().  Also, optionally populates 'ofproto'
+ * with the ofproto_dpif, and 'odp_in_port' with the datapath in_port, that
+ * 'packet' ingressed.
  *
- * Sets '*initial_tci' to the VLAN TCI with which the packet was really
- * received, that is, the actual VLAN TCI extracted by odp_flow_key_to_flow().
- * (This differs from the value returned in flow->vlan_tci only for packets
- * received on VLAN splinters.) */
-static enum odp_key_fitness
-ofproto_dpif_vsp_adjust(const struct ofproto_dpif *ofproto,
-                        enum odp_key_fitness fitness,
-                        struct flow *flow, ovs_be16 *initial_tci,
-                        struct ofpbuf *packet)
+ * If 'ofproto' is nonnull, requires 'flow''s in_port to exist.  Otherwise sets
+ * 'flow''s in_port to OFPP_NONE.
+ *
+ * This function does post-processing on data returned from
+ * odp_flow_key_to_flow() to help make VLAN splinters transparent to the rest
+ * of the upcall processing logic.  In particular, if the extracted in_port is
+ * a VLAN splinter port, it replaces flow->in_port by the "real" port, sets
+ * flow->vlan_tci correctly for the VLAN of the VLAN splinter port, and pushes
+ * a VLAN header onto 'packet' (if it is nonnull).
+ *
+ * Optionally, if nonnull, sets '*initial_tci' to the VLAN TCI with which the
+ * packet was really received, that is, the actual VLAN TCI extracted by
+ * odp_flow_key_to_flow().  (This differs from the value returned in
+ * flow->vlan_tci only for packets received on VLAN splinters.)
+ *
+ * Returns 0 if successful, ENODEV if the parsed flow has no associated ofport,
+ * or some other positive errno if there are other problems. */
+static int
+ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
+                const struct nlattr *key, size_t key_len,
+                struct flow *flow, enum odp_key_fitness *fitnessp,
+                struct ofproto_dpif **ofproto, uint32_t *odp_in_port,
+                ovs_be16 *initial_tci)
 {
+    const struct ofport_dpif *port;
+    enum odp_key_fitness fitness;
+    int error;
+
+    fitness = odp_flow_key_to_flow(key, key_len, flow);
     if (fitness == ODP_FIT_ERROR) {
-        return fitness;
+        error = EINVAL;
+        goto exit;
+    }
+
+    if (initial_tci) {
+        *initial_tci = flow->vlan_tci;
     }
-    *initial_tci = flow->vlan_tci;
 
-    if (vsp_adjust_flow(ofproto, flow)) {
+    if (odp_in_port) {
+        *odp_in_port = flow->in_port;
+    }
+
+    port = odp_port_to_ofport(backer, flow->in_port);
+    if (!port) {
+        flow->in_port = OFPP_NONE;
+        error = ofproto ? ENODEV : 0;
+        goto exit;
+    }
+
+    if (ofproto) {
+        *ofproto = ofproto_dpif_cast(port->up.ofproto);
+    }
+
+    flow->in_port = port->up.ofp_port;
+    if (vsp_adjust_flow(ofproto_dpif_cast(port->up.ofproto), flow)) {
         if (packet) {
             /* Make the packet resemble the flow, so that it gets sent to an
              * OpenFlow controller properly, so that it looks correct for
@@ -3441,8 +3479,13 @@ ofproto_dpif_vsp_adjust(const struct ofproto_dpif *ofproto,
             fitness = ODP_FIT_TOO_MUCH;
         }
     }
+    error = 0;
 
-    return fitness;
+exit:
+    if (fitnessp) {
+        *fitnessp = fitness;
+    }
+    return error;
 }
 
 static void
@@ -3473,33 +3516,24 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
     for (upcall = upcalls; upcall < &upcalls[n_upcalls]; upcall++) {
         struct flow_miss *miss = &misses[n_misses];
         struct flow_miss *existing_miss;
-        enum odp_key_fitness fitness;
         struct ofproto_dpif *ofproto;
-        struct ofport_dpif *port;
         uint32_t odp_in_port;
         struct flow flow;
         uint32_t hash;
+        int error;
 
-        fitness = odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
-        port = odp_port_to_ofport(backer, flow.in_port);
-        if (!port) {
+        error = ofproto_receive(backer, upcall->packet, upcall->key,
+                                upcall->key_len, &flow, &miss->key_fitness,
+                                &ofproto, &odp_in_port, &miss->initial_tci);
+        if (error == ENODEV) {
             /* Received packet on port for which we couldn't associate
              * an ofproto.  This can happen if a port is removed while
              * traffic is being received.  Print a rate-limited message
              * in case it happens frequently. */
             VLOG_INFO_RL(&rl, "received packet on unassociated port %"PRIu32,
                          flow.in_port);
-            continue;
         }
-        ofproto = ofproto_dpif_cast(port->up.ofproto);
-        odp_in_port = flow.in_port;
-        flow.in_port = port->up.ofp_port;
-
-        /* Obtain metadata and check userspace/kernel agreement on flow match,
-         * then set 'flow''s header pointers. */
-        miss->key_fitness = ofproto_dpif_vsp_adjust(ofproto, fitness,
-                                &flow, &miss->initial_tci, upcall->packet);
-        if (miss->key_fitness == ODP_FIT_ERROR) {
+        if (error) {
             continue;
         }
         flow_extract(upcall->packet, flow.skb_priority, flow.skb_mark,
@@ -3530,7 +3564,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
     HMAP_FOR_EACH (miss, hmap_node, &todo) {
         handle_flow_miss(miss, flow_miss_ops, &n_ops);
     }
-    assert(n_ops <= ARRAY_SIZE(flow_miss_ops));
+    ovs_assert(n_ops <= ARRAY_SIZE(flow_miss_ops));
 
     /* Execute batch. */
     for (i = 0; i < n_ops; i++) {
@@ -3602,29 +3636,12 @@ handle_sflow_upcall(struct dpif_backer *backer,
 {
     struct ofproto_dpif *ofproto;
     union user_action_cookie cookie;
-    enum odp_key_fitness fitness;
-    struct ofport_dpif *port;
-    ovs_be16 initial_tci;
     struct flow flow;
     uint32_t odp_in_port;
 
-    fitness = odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
-
-    port = odp_port_to_ofport(backer, flow.in_port);
-    if (!port) {
-        return;
-    }
-
-    ofproto = ofproto_dpif_cast(port->up.ofproto);
-    if (!ofproto->sflow) {
-        return;
-    }
-
-    odp_in_port = flow.in_port;
-    flow.in_port = port->up.ofp_port;
-    fitness = ofproto_dpif_vsp_adjust(ofproto, fitness, &flow,
-                                      &initial_tci, upcall->packet);
-    if (fitness == ODP_FIT_ERROR) {
+    if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len,
+                        &flow, NULL, &ofproto, &odp_in_port, NULL)
+        || !ofproto->sflow) {
         return;
     }
 
@@ -3643,7 +3660,7 @@ handle_upcalls(struct dpif_backer *backer, unsigned int max_batch)
     int n_misses;
     int i;
 
-    assert(max_batch <= FLOW_MISS_MAX_BATCH);
+    ovs_assert(max_batch <= FLOW_MISS_MAX_BATCH);
 
     n_misses = 0;
     for (n_processed = 0; n_processed < max_batch; n_processed++) {
@@ -4108,7 +4125,7 @@ facet_remove(struct facet *facet)
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
     struct subfacet *subfacet, *next_subfacet;
 
-    assert(!list_is_empty(&facet->subfacets));
+    ovs_assert(!list_is_empty(&facet->subfacets));
 
     /* First uninstall all of the subfacets to get final statistics. */
     LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
@@ -4238,8 +4255,8 @@ facet_flush_stats(struct facet *facet)
     struct subfacet *subfacet;
 
     LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
-        assert(!subfacet->dp_byte_count);
-        assert(!subfacet->dp_packet_count);
+        ovs_assert(!subfacet->dp_byte_count);
+        ovs_assert(!subfacet->dp_packet_count);
     }
 
     facet_push_stats(facet);
@@ -4596,9 +4613,9 @@ facet_push_stats(struct facet *facet)
 {
     struct dpif_flow_stats stats;
 
-    assert(facet->packet_count >= facet->prev_packet_count);
-    assert(facet->byte_count >= facet->prev_byte_count);
-    assert(facet->used >= facet->prev_used);
+    ovs_assert(facet->packet_count >= facet->prev_packet_count);
+    ovs_assert(facet->byte_count >= facet->prev_byte_count);
+    ovs_assert(facet->used >= facet->prev_used);
 
     stats.n_packets = facet->packet_count - facet->prev_packet_count;
     stats.n_bytes = facet->byte_count - facet->prev_byte_count;
@@ -4915,8 +4932,8 @@ subfacet_uninstall(struct subfacet *subfacet)
         }
         subfacet->path = SF_NOT_INSTALLED;
     } else {
-        assert(subfacet->dp_packet_count == 0);
-        assert(subfacet->dp_byte_count == 0);
+        ovs_assert(subfacet->dp_packet_count == 0);
+        ovs_assert(subfacet->dp_byte_count == 0);
     }
 }
 
@@ -5254,7 +5271,7 @@ compose_slow_path(const struct ofproto_dpif *ofproto, const struct flow *flow,
 
     ofpbuf_use_stack(&buf, stub, stub_size);
     if (slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)) {
-        uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT16_MAX);
+        uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX);
         odp_put_userspace_action(pid, &cookie, &buf);
     } else {
         put_userspace_action(ofproto, &buf, flow, &cookie);
@@ -5369,7 +5386,7 @@ fix_sflow_action(struct action_xlate_ctx *ctx)
 
     cookie = ofpbuf_at(ctx->odp_actions, ctx->user_cookie_offset,
                        sizeof(*cookie));
-    assert(cookie->type == USER_ACTION_COOKIE_SFLOW);
+    ovs_assert(cookie->type == USER_ACTION_COOKIE_SFLOW);
 
     compose_sflow_cookie(ctx->ofproto, base->vlan_tci,
                          ctx->sflow_odp_port, ctx->sflow_n_outputs, cookie);
@@ -5383,28 +5400,24 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
     uint32_t odp_port = ofp_port_to_odp_port(ctx->ofproto, ofp_port);
     ovs_be16 flow_vlan_tci = ctx->flow.vlan_tci;
     uint8_t flow_nw_tos = ctx->flow.nw_tos;
-    uint16_t out_port;
-
-    if (ofport) {
-        struct priority_to_dscp *pdscp;
+    struct priority_to_dscp *pdscp;
+    uint32_t out_port;
 
-        if (ofport->up.pp.config & OFPUTIL_PC_NO_FWD) {
-            xlate_report(ctx, "OFPPC_NO_FWD set, skipping output");
-            return;
-        } else if (check_stp && !stp_forward_in_state(ofport->stp_state)) {
-            xlate_report(ctx, "STP not in forwarding state, skipping output");
-            return;
-        }
+    if (!ofport) {
+        xlate_report(ctx, "Nonexistent output port");
+        return;
+    } else if (ofport->up.pp.config & OFPUTIL_PC_NO_FWD) {
+        xlate_report(ctx, "OFPPC_NO_FWD set, skipping output");
+        return;
+    } else if (check_stp && !stp_forward_in_state(ofport->stp_state)) {
+        xlate_report(ctx, "STP not in forwarding state, skipping output");
+        return;
+    }
 
-        pdscp = get_priority(ofport, ctx->flow.skb_priority);
-        if (pdscp) {
-            ctx->flow.nw_tos &= ~IP_DSCP_MASK;
-            ctx->flow.nw_tos |= pdscp->dscp;
-        }
-    } else {
-        /* We may not have an ofport record for this port, but it doesn't hurt
-         * to allow forwarding to it anyhow.  Maybe such a port will appear
-         * later and we're pre-populating the flow table.  */
+    pdscp = get_priority(ofport, ctx->flow.skb_priority);
+    if (pdscp) {
+        ctx->flow.nw_tos &= ~IP_DSCP_MASK;
+        ctx->flow.nw_tos |= pdscp->dscp;
     }
 
     out_port = vsp_realdev_to_vlandev(ctx->ofproto, odp_port,
@@ -5467,7 +5480,7 @@ xlate_table_action(struct action_xlate_ctx *ctx,
         }
 
         if (rule == NULL && may_packet_in) {
-            /* TODO:XXX
+            /* XXX
              * check if table configuration flags
              * OFPTC_TABLE_MISS_CONTROLLER, default.
              * OFPTC_TABLE_MISS_CONTINUE,
@@ -5567,8 +5580,8 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
         /* If the Ethernet type is less than ETH_TYPE_MIN, it's likely an 802.2
          * LLC frame.  Calculating the Ethernet type of these frames is more
          * trouble than seems appropriate for a simple assertion. */
-        assert(ntohs(eh->eth_type) < ETH_TYPE_MIN
-               || eh->eth_type == ctx->flow.dl_type);
+        ovs_assert(ntohs(eh->eth_type) < ETH_TYPE_MIN
+                   || eh->eth_type == ctx->flow.dl_type);
 
         memcpy(eh->eth_src, ctx->flow.dl_src, sizeof eh->eth_src);
         memcpy(eh->eth_dst, ctx->flow.dl_dst, sizeof eh->eth_dst);
@@ -5933,7 +5946,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_PUSH_VLAN:
-            /* TODO:XXX 802.1AD(QinQ) */
+            /* XXX 802.1AD(QinQ) */
             ctx->flow.vlan_tci = htons(VLAN_CFI);
             break;
 
@@ -6039,7 +6052,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_CLEAR_ACTIONS:
-            /* TODO:XXX
+            /* XXX
              * Nothing to do because writa-actions is not supported for now.
              * When writa-actions is supported, clear-actions also must
              * be supported at the same time.
@@ -6053,10 +6066,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_GOTO_TABLE: {
-            /* TODO:XXX remove recursion */
+            /* XXX remove recursion */
             /* It is assumed that goto-table is last action */
             struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a);
-            assert(ctx->table_id < ogt->table_id);
+            ovs_assert(ctx->table_id < ogt->table_id);
             xlate_table_action(ctx, ctx->flow.in_port, ogt->table_id, true);
             break;
         }
@@ -6081,11 +6094,35 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
                       ovs_be16 initial_tci, struct rule_dpif *rule,
                       uint8_t tcp_flags, const struct ofpbuf *packet)
 {
+    ovs_be64 initial_tun_id = flow->tunnel.tun_id;
+
+    /* Flow initialization rules:
+     * - 'base_flow' must match the kernel's view of the packet at the
+     *   time that action processing starts.  'flow' represents any
+     *   transformations we wish to make through actions.
+     * - By default 'base_flow' and 'flow' are the same since the input
+     *   packet matches the output before any actions are applied.
+     * - When using VLAN splinters, 'base_flow''s VLAN is set to the value
+     *   of the received packet as seen by the kernel.  If we later output
+     *   to another device without any modifications this will cause us to
+     *   insert a new tag since the original one was stripped off by the
+     *   VLAN device.
+     * - Tunnel 'flow' is largely cleared when transitioning between
+     *   the input and output stages since it does not make sense to output
+     *   a packet with the exact headers that it was received with (i.e.
+     *   the destination IP is us).  The one exception is the tun_id, which
+     *   is preserved to allow use in later resubmit lookups and loads into
+     *   registers.
+     * - Tunnel 'base_flow' is completely cleared since that is what the
+     *   kernel does.  If we wish to maintain the original values an action
+     *   needs to be generated. */
+
     ctx->ofproto = ofproto;
     ctx->flow = *flow;
+    memset(&ctx->flow.tunnel, 0, sizeof ctx->flow.tunnel);
     ctx->base_flow = ctx->flow;
-    memset(&ctx->base_flow.tunnel, 0, sizeof ctx->base_flow.tunnel);
     ctx->base_flow.vlan_tci = initial_tci;
+    ctx->flow.tunnel.tun_id = initial_tun_id;
     ctx->rule = rule;
     ctx->packet = packet;
     ctx->may_learn = packet != NULL;
@@ -6167,6 +6204,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
     } else {
         static struct vlog_rate_limit trace_rl = VLOG_RATE_LIMIT_INIT(1, 1);
         ovs_be16 initial_tci = ctx->base_flow.vlan_tci;
+        uint32_t local_odp_port;
 
         add_sflow_action(ctx);
         do_xlate_actions(ofpacts, ofpacts_len, ctx);
@@ -6187,7 +6225,9 @@ xlate_actions(struct action_xlate_ctx *ctx,
             }
         }
 
+        local_odp_port = ofp_port_to_odp_port(ctx->ofproto, OFPP_LOCAL);
         if (!connmgr_may_set_up_flow(ctx->ofproto->up.connmgr, &ctx->flow,
+                                     local_odp_port,
                                      ctx->odp_actions->data,
                                      ctx->odp_actions->size)) {
             ctx->slow |= SLOW_IN_BAND;
@@ -7185,7 +7225,6 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
          * you just say "syntax error" or do you present both error messages?
          * Both choices seem lousy. */
         if (strchr(flow_s, '(')) {
-            enum odp_key_fitness fitness;
             int error;
 
             /* Convert string to datapath key. */
@@ -7196,13 +7235,13 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
                 goto exit;
             }
 
-            fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
-            flow.in_port = odp_port_to_ofp_port(ofproto, flow.in_port);
-
-            /* Convert odp_key to flow. */
-            error = ofproto_dpif_vsp_adjust(ofproto, fitness, &flow,
-                                            &initial_tci, NULL);
-            if (error == ODP_FIT_ERROR) {
+            /* XXX: Since we allow the user to specify an ofproto, it's
+             * possible they will specify a different ofproto than the one the
+             * port actually belongs too.  Ideally we should simply remove the
+             * ability to specify the ofproto. */
+            if (ofproto_receive(ofproto->backer, NULL, odp_key.data,
+                                odp_key.size, &flow, NULL, NULL, NULL,
+                                &initial_tci)) {
                 unixctl_command_reply_error(conn, "Invalid flow");
                 goto exit;
             }
@@ -7217,7 +7256,6 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
             }
 
             initial_tci = flow.vlan_tci;
-            vsp_adjust_flow(ofproto, &flow);
         }
 
         /* Generate a packet, if requested. */
@@ -7878,7 +7916,7 @@ odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
     struct ofport_dpif *port;
 
     port = odp_port_to_ofport(ofproto->backer, odp_port);
-    if (port && ofproto == ofproto_dpif_cast(port->up.ofproto)) {
+    if (port && &ofproto->up == port->up.ofproto) {
         return port->up.ofp_port;
     } else {
         return OFPP_NONE;