ofproto-dpif: Use proper special value for the reserved PID.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index fe0aae3..bc54122 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.
@@ -76,6 +76,7 @@ BUILD_ASSERT_DECL(N_TABLES >= 2 && N_TABLES <= 255);
 
 struct ofport_dpif;
 struct ofproto_dpif;
+struct flow_miss;
 
 struct rule_dpif {
     struct rule up;
@@ -366,13 +367,18 @@ struct subfacet {
      * splinters can cause it to differ.  This value should be removed when
      * the VLAN splinters feature is no longer needed.  */
     ovs_be16 initial_tci;       /* Initial VLAN TCI value. */
+
+    /* Datapath port the packet arrived on.  This is needed to remove
+     * flows for ports that are no longer part of the bridge.  Since the
+     * flow definition only has the OpenFlow port number and the port is
+     * no longer part of the bridge, we can't determine the datapath port
+     * number needed to delete the flow from the datapath. */
+    uint32_t odp_in_port;
 };
 
 #define SUBFACET_DESTROY_MAX_BATCH 50
 
-static struct subfacet *subfacet_create(struct facet *, enum odp_key_fitness,
-                                        const struct nlattr *key,
-                                        size_t key_len, ovs_be16 initial_tci,
+static struct subfacet *subfacet_create(struct facet *, struct flow_miss *miss,
                                         long long int now);
 static struct subfacet *subfacet_find(struct ofproto_dpif *,
                                       const struct nlattr *key, size_t key_len,
@@ -788,6 +794,20 @@ port_open_type(const char *datapath_type, const char *port_type)
 
 /* Type functions. */
 
+static struct ofproto_dpif *
+lookup_ofproto_dpif_by_port_name(const char *name)
+{
+    struct ofproto_dpif *ofproto;
+
+    HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+        if (sset_contains(&ofproto->ports, name)) {
+            return ofproto;
+        }
+    }
+
+    return NULL;
+}
+
 static int
 type_run(const char *type)
 {
@@ -811,21 +831,15 @@ type_run(const char *type)
 
     /* Check for port changes in the dpif. */
     while ((error = dpif_port_poll(backer->dpif, &devname)) == 0) {
-        struct ofproto_dpif *ofproto = NULL;
+        struct ofproto_dpif *ofproto;
         struct dpif_port port;
 
         /* Don't report on the datapath's device. */
         if (!strcmp(devname, dpif_base_name(backer->dpif))) {
-            continue;
-        }
-
-        HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node,
-                       &all_ofproto_dpifs) {
-            if (sset_contains(&ofproto->ports, devname)) {
-                break;
-            }
+            goto next;
         }
 
+        ofproto = lookup_ofproto_dpif_by_port_name(devname);
         if (dpif_port_query_by_name(backer->dpif, devname, &port)) {
             /* The port was removed.  If we know the datapath,
              * report it through poll_set().  If we don't, it may be
@@ -836,13 +850,14 @@ type_run(const char *type)
                 sset_add(&ofproto->port_poll_set, devname);
                 ofproto->port_poll_errno = 0;
             }
-            dpif_port_destroy(&port);
         } else if (!ofproto) {
             /* The port was added, but we don't know with which
              * ofproto we should associate it.  Delete it. */
             dpif_port_del(backer->dpif, port.port_no);
         }
+        dpif_port_destroy(&port);
 
+    next:
         free(devname);
     }
 
@@ -1109,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. */
@@ -1119,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);
         }
     }
@@ -1538,19 +1554,17 @@ port_destruct(struct ofport *port_)
 {
     struct ofport_dpif *port = ofport_dpif_cast(port_);
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
-    struct dpif_port dpif_port;
+    const char *devname = netdev_get_name(port->up.netdev);
 
-    if (!dpif_port_query_by_number(ofproto->backer->dpif,
-                                   port->odp_port, &dpif_port)) {
+    if (dpif_port_exists(ofproto->backer->dpif, devname)) {
         /* The underlying device is still there, so delete it.  This
          * happens when the ofproto is being destroyed, since the caller
          * assumes that removal of attached ports will happen as part of
          * destruction. */
         dpif_port_del(ofproto->backer->dpif, port->odp_port);
-        dpif_port_destroy(&dpif_port);
     }
 
-    sset_find_and_delete(&ofproto->ports, netdev_get_name(port->up.netdev));
+    sset_find_and_delete(&ofproto->ports, devname);
     hmap_remove(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node);
     ofproto->need_revalidate = REV_RECONFIGURE;
     bundle_remove(port_);
@@ -2758,10 +2772,12 @@ forward_bpdu_changed(struct ofproto *ofproto_)
 }
 
 static void
-set_mac_idle_time(struct ofproto *ofproto_, unsigned int idle_time)
+set_mac_table_config(struct ofproto *ofproto_, unsigned int idle_time,
+                     size_t max_entries)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     mac_learning_set_idle_time(ofproto->ml, idle_time);
+    mac_learning_set_max_entries(ofproto->ml, max_entries);
 }
 \f
 /* Ports. */
@@ -2776,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
@@ -2913,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
@@ -3064,6 +3081,7 @@ struct flow_miss {
     ovs_be16 initial_tci;
     struct list packets;
     enum dpif_upcall_type upcall_type;
+    uint32_t odp_in_port;
 };
 
 struct flow_miss_op {
@@ -3283,9 +3301,7 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
     struct subfacet *subfacet;
     struct ofpbuf *packet;
 
-    subfacet = subfacet_create(facet,
-                               miss->key_fitness, miss->key, miss->key_len,
-                               miss->initial_tci, now);
+    subfacet = subfacet_create(facet, miss, now);
 
     LIST_FOR_EACH (packet, list_node, &miss->packets) {
         struct flow_miss_op *op = &ops[*n_ops];
@@ -3378,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;
     }
-    *initial_tci = flow->vlan_tci;
 
-    if (vsp_adjust_flow(ofproto, flow)) {
+    if (initial_tci) {
+        *initial_tci = flow->vlan_tci;
+    }
+
+    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
@@ -3427,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
@@ -3459,34 +3516,27 @@ 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);
-        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_extract(upcall->packet, flow.skb_priority, flow.skb_mark,
                      &flow.tunnel, flow.in_port, &miss->flow);
 
         /* Add other packets to a to-do list. */
@@ -3498,6 +3548,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
             miss->key = upcall->key;
             miss->key_len = upcall->key_len;
             miss->upcall_type = upcall->type;
+            miss->odp_in_port = odp_in_port;
             list_init(&miss->packets);
 
             n_misses++;
@@ -3585,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;
     }
 
@@ -3823,11 +3857,8 @@ update_stats(struct dpif_backer *backer)
         if (!port) {
             /* This flow is for a 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,
-                        "stats update for flow with unassociated port %"PRIu32,
-                        flow.in_port);
+             * traffic is being received.  Ignore this flow, since it
+             * will get timed out. */
             continue;
         }
 
@@ -4652,21 +4683,26 @@ subfacet_find(struct ofproto_dpif *ofproto,
 }
 
 /* Searches 'facet' (within 'ofproto') for a subfacet with the specified
- * 'key_fitness', 'key', and 'key_len'.  Returns the existing subfacet if
- * there is one, otherwise creates and returns a new subfacet.
+ * 'key_fitness', 'key', and 'key_len' members in 'miss'.  Returns the
+ * existing subfacet if there is one, otherwise creates and returns a
+ * new subfacet.
  *
  * If the returned subfacet is new, then subfacet->actions will be NULL, in
  * which case the caller must populate the actions with
  * subfacet_make_actions(). */
 static struct subfacet *
-subfacet_create(struct facet *facet, enum odp_key_fitness key_fitness,
-                const struct nlattr *key, size_t key_len,
-                ovs_be16 initial_tci, long long int now)
+subfacet_create(struct facet *facet, struct flow_miss *miss,
+                long long int now)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
-    uint32_t key_hash = odp_flow_key_hash(key, key_len);
+    enum odp_key_fitness key_fitness = miss->key_fitness;
+    const struct nlattr *key = miss->key;
+    size_t key_len = miss->key_len;
+    uint32_t key_hash;
     struct subfacet *subfacet;
 
+    key_hash = odp_flow_key_hash(key, key_len);
+
     if (list_is_empty(&facet->subfacets)) {
         subfacet = &facet->one_subfacet;
     } else {
@@ -4705,7 +4741,8 @@ subfacet_create(struct facet *facet, enum odp_key_fitness key_fitness,
                       ? SLOW_MATCH
                       : 0);
     subfacet->path = SF_NOT_INSTALLED;
-    subfacet->initial_tci = initial_tci;
+    subfacet->initial_tci = miss->initial_tci;
+    subfacet->odp_in_port = miss->odp_in_port;
 
     return subfacet;
 }
@@ -4780,13 +4817,10 @@ subfacet_get_key(struct subfacet *subfacet, struct odputil_keybuf *keybuf,
 {
 
     if (!subfacet->key) {
-        struct ofproto_dpif *ofproto;
         struct flow *flow = &subfacet->facet->flow;
 
         ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
-        ofproto = ofproto_dpif_cast(subfacet->facet->rule->up.ofproto);
-        odp_flow_key_from_flow(key, flow,
-                               ofp_port_to_odp_port(ofproto, flow->in_port));
+        odp_flow_key_from_flow(key, flow, subfacet->odp_in_port);
     } else {
         ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
     }
@@ -5176,7 +5210,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
     struct flow flow;
     int error;
 
-    flow_extract(packet, 0, NULL, 0, &flow);
+    flow_extract(packet, 0, 0, NULL, OFPP_LOCAL, &flow);
     odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
                                       flow.vlan_tci);
     if (odp_port != ofport->odp_port) {
@@ -5237,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);
@@ -5366,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,
@@ -5450,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,
@@ -5916,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;
 
@@ -6022,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.
@@ -6036,7 +6066,7 @@ 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);
@@ -6066,8 +6096,8 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
 {
     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->rule = rule;
     ctx->packet = packet;
@@ -6150,6 +6180,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);
@@ -6170,7 +6201,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;
@@ -7168,7 +7201,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. */
@@ -7179,13 +7211,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;
             }
@@ -7200,7 +7232,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. */
@@ -7208,15 +7239,17 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
             packet = ofpbuf_new(0);
             flow_compose(packet, &flow);
         }
-    } else if (argc == 6) {
-        /* ofproto/trace dpname priority tun_id in_port packet */
+    } else if (argc == 7) {
+        /* ofproto/trace dpname priority tun_id in_port mark packet */
         const char *priority_s = argv[2];
         const char *tun_id_s = argv[3];
         const char *in_port_s = argv[4];
-        const char *packet_s = argv[5];
+        const char *mark_s = argv[5];
+        const char *packet_s = argv[6];
         uint32_t in_port = atoi(in_port_s);
         ovs_be64 tun_id = htonll(strtoull(tun_id_s, NULL, 0));
         uint32_t priority = atoi(priority_s);
+        uint32_t mark = atoi(mark_s);
         const char *msg;
 
         msg = eth_from_hex(packet_s, &packet);
@@ -7230,7 +7263,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
         ds_put_cstr(&result, s);
         free(s);
 
-        flow_extract(packet, priority, NULL, in_port, &flow);
+        flow_extract(packet, priority, mark, NULL, in_port, &flow);
         flow.tunnel.tun_id = tun_id;
         initial_tci = flow.vlan_tci;
     } else {
@@ -7625,8 +7658,8 @@ ofproto_dpif_unixctl_init(void)
 
     unixctl_command_register(
         "ofproto/trace",
-        "bridge {tun_id in_port packet | odp_flow [-generate]}",
-        2, 5, ofproto_unixctl_trace, NULL);
+        "bridge {priority tun_id in_port mark packet | odp_flow [-generate]}",
+        2, 6, ofproto_unixctl_trace, NULL);
     unixctl_command_register("fdb/flush", "[bridge]", 0, 1,
                              ofproto_unixctl_fdb_flush, NULL);
     unixctl_command_register("fdb/show", "bridge", 1, 1,
@@ -7859,7 +7892,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;
@@ -7932,6 +7965,6 @@ const struct ofproto_class ofproto_dpif_class = {
     set_flood_vlans,
     is_mirror_output_bundle,
     forward_bpdu_changed,
-    set_mac_idle_time,
+    set_mac_table_config,
     set_realdev,
 };