ofproto-dpif: Always un-wildcard 'dl_type'.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index a51b60d..c6a7abc 100644 (file)
@@ -69,6 +69,7 @@ COVERAGE_DEFINE(facet_changed_rule);
 COVERAGE_DEFINE(facet_revalidate);
 COVERAGE_DEFINE(facet_unexpected);
 COVERAGE_DEFINE(facet_suppress);
+COVERAGE_DEFINE(subfacet_install_fail);
 
 struct flow_miss;
 struct facet;
@@ -258,6 +259,16 @@ static void push_all_stats(void);
 
 static bool facet_is_controller_flow(struct facet *);
 
+/* Node in 'ofport_dpif''s 'priorities' map.  Used to maintain a map from
+ * 'priority' (the datapath's term for QoS queue) to the dscp bits which all
+ * traffic egressing the 'ofport' with that priority should be marked with. */
+struct priority_to_dscp {
+    struct hmap_node hmap_node; /* Node in 'ofport_dpif''s 'priorities' map. */
+    uint32_t priority;          /* Priority of this queue (see struct flow). */
+
+    uint8_t dscp;               /* DSCP bits to mark outgoing traffic with. */
+};
+
 /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
  *
  * This is deprecated.  It is only for compatibility with broken device drivers
@@ -267,17 +278,17 @@ static bool facet_is_controller_flow(struct facet *);
 struct vlan_splinter {
     struct hmap_node realdev_vid_node;
     struct hmap_node vlandev_node;
-    uint16_t realdev_ofp_port;
-    uint16_t vlandev_ofp_port;
+    ofp_port_t realdev_ofp_port;
+    ofp_port_t vlandev_ofp_port;
     int vid;
 };
 
 static bool vsp_adjust_flow(const struct ofproto_dpif *, struct flow *);
 static void vsp_remove(struct ofport_dpif *);
-static void vsp_add(struct ofport_dpif *, uint16_t realdev_ofp_port, int vid);
+static void vsp_add(struct ofport_dpif *, ofp_port_t realdev_ofp_port, int vid);
 
-static uint16_t odp_port_to_ofp_port(const struct ofproto_dpif *,
-                                     uint32_t odp_port);
+static ofp_port_t odp_port_to_ofp_port(const struct ofproto_dpif *,
+                                       odp_port_t odp_port);
 
 static struct ofport_dpif *
 ofport_dpif_cast(const struct ofport *ofport)
@@ -291,6 +302,7 @@ static void port_wait(struct ofport_dpif *);
 static int set_bfd(struct ofport *, const struct smap *);
 static int set_cfm(struct ofport *, const struct cfm_settings *);
 static void ofport_clear_priorities(struct ofport_dpif *);
+static void ofport_update_peer(struct ofport_dpif *);
 static void run_fast_rl(void);
 
 struct dpif_completion {
@@ -298,6 +310,21 @@ struct dpif_completion {
     struct ofoperation *op;
 };
 
+/* Reasons that we might need to revalidate every facet, and corresponding
+ * coverage counters.
+ *
+ * A value of 0 means that there is no need to revalidate.
+ *
+ * It would be nice to have some cleaner way to integrate with coverage
+ * counters, but with only a few reasons I guess this is good enough for
+ * now. */
+enum revalidate_reason {
+    REV_RECONFIGURE = 1,       /* Switch configuration changed. */
+    REV_STP,                   /* Spanning tree protocol port status change. */
+    REV_PORT_TOGGLED,          /* Port enabled or disabled by CFM, LACP, ...*/
+    REV_FLOW_TABLE,            /* Flow table changed. */
+    REV_INCONSISTENCY          /* Facet self-check failed. */
+};
 COVERAGE_DEFINE(rev_reconfigure);
 COVERAGE_DEFINE(rev_stp);
 COVERAGE_DEFINE(rev_port_toggled);
@@ -313,12 +340,64 @@ struct drop_key {
     size_t key_len;
 };
 
+struct avg_subfacet_rates {
+    double add_rate;   /* Moving average of new flows created per minute. */
+    double del_rate;   /* Moving average of flows deleted per minute. */
+};
+
+/* All datapaths of a given type share a single dpif backer instance. */
+struct dpif_backer {
+    char *type;
+    int refcount;
+    struct dpif *dpif;
+    struct timer next_expiration;
+    struct hmap odp_to_ofport_map; /* ODP port to ofport mapping. */
+
+    struct simap tnl_backers;      /* Set of dpif ports backing tunnels. */
+
+    /* Facet revalidation flags applying to facets which use this backer. */
+    enum revalidate_reason need_revalidate; /* Revalidate every facet. */
+    struct tag_set revalidate_set; /* Revalidate only matching facets. */
+
+    struct hmap drop_keys; /* Set of dropped odp keys. */
+    bool recv_set_enable; /* Enables or disables receiving packets. */
+
+    struct hmap subfacets;
+    struct governor *governor;
+
+    /* Subfacet statistics.
+     *
+     * These keep track of the total number of subfacets added and deleted and
+     * flow life span.  They are useful for computing the flow rates stats
+     * exposed via "ovs-appctl dpif/show".  The goal is to learn about
+     * traffic patterns in ways that we can use later to improve Open vSwitch
+     * performance in new situations.  */
+    long long int created;           /* Time when it is created. */
+    unsigned max_n_subfacet;         /* Maximum number of flows */
+    unsigned avg_n_subfacet;         /* Average number of flows. */
+    long long int avg_subfacet_life; /* Average life span of subfacets. */
+
+    /* The average number of subfacets... */
+    struct avg_subfacet_rates hourly;   /* ...over the last hour. */
+    struct avg_subfacet_rates daily;    /* ...over the last day. */
+    struct avg_subfacet_rates lifetime; /* ...over the switch lifetime. */
+    long long int last_minute;          /* Last time 'hourly' was updated. */
+
+    /* Number of subfacets added or deleted since 'last_minute'. */
+    unsigned subfacet_add_count;
+    unsigned subfacet_del_count;
+
+    /* Number of subfacets added or deleted from 'created' to 'last_minute.' */
+    unsigned long long int total_subfacet_add_count;
+    unsigned long long int total_subfacet_del_count;
+};
+
 /* All existing ofproto_backer instances, indexed by ofproto->up.type. */
 static struct shash all_dpif_backers = SHASH_INITIALIZER(&all_dpif_backers);
 
 static void drop_key_clear(struct dpif_backer *);
 static struct ofport_dpif *
-odp_port_to_ofport(const struct dpif_backer *, uint32_t odp_port);
+odp_port_to_ofport(const struct dpif_backer *, odp_port_t odp_port);
 static void update_moving_averages(struct dpif_backer *backer);
 
 /* Defer flow mod completion until "ovs-appctl ofproto/unclog"?  (Useful only
@@ -506,17 +585,18 @@ type_run(const char *type)
                 } else {
                     node = simap_find(&backer->tnl_backers, dp_port);
                     if (!node) {
-                        uint32_t odp_port = UINT32_MAX;
+                        odp_port_t odp_port = ODPP_NONE;
 
                         if (!dpif_port_add(backer->dpif, iter->up.netdev,
                                            &odp_port)) {
-                            simap_put(&backer->tnl_backers, dp_port, odp_port);
+                            simap_put(&backer->tnl_backers, dp_port,
+                                      odp_to_u32(odp_port));
                             node = simap_find(&backer->tnl_backers, dp_port);
                         }
                     }
                 }
 
-                iter->odp_port = node ? node->data : OVSP_NONE;
+                iter->odp_port = node ? u32_to_odp(node->data) : ODPP_NONE;
                 if (tnl_port_reconfigure(&iter->up, iter->odp_port,
                                          &iter->tnl_port)) {
                     backer->need_revalidate = REV_RECONFIGURE;
@@ -525,7 +605,7 @@ type_run(const char *type)
         }
 
         SIMAP_FOR_EACH (node, &tmp_backers) {
-            dpif_port_del(backer->dpif, node->data);
+            dpif_port_del(backer->dpif, u32_to_odp(node->data));
         }
         simap_destroy(&tmp_backers);
 
@@ -799,7 +879,7 @@ close_dpif_backer(struct dpif_backer *backer)
 /* Datapath port slated for removal from datapath. */
 struct odp_garbage {
     struct list list_node;
-    uint32_t odp_port;
+    odp_port_t odp_port;
 };
 
 static int
@@ -925,7 +1005,7 @@ construct(struct ofproto *ofproto_)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     struct shash_node *node, *next;
-    int max_ports;
+    odp_port_t max_ports;
     int error;
     int i;
 
@@ -935,7 +1015,8 @@ construct(struct ofproto *ofproto_)
     }
 
     max_ports = dpif_get_max_ports(ofproto->backer->dpif);
-    ofproto_init_max_ports(ofproto_, MIN(max_ports, OFPP_MAX));
+    ofproto_init_max_ports(ofproto_, u16_to_ofp(MIN(odp_to_u32(max_ports),
+                                                    ofp_to_u16(OFPP_MAX))));
 
     ofproto->netflow = NULL;
     ofproto->sflow = NULL;
@@ -1096,6 +1177,7 @@ destruct(struct ofproto *ofproto_)
     struct oftable *table;
     int i;
 
+    ofproto->backer->need_revalidate = REV_RECONFIGURE;
     hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node);
     complete_operations(ofproto);
 
@@ -1378,6 +1460,7 @@ port_construct(struct ofport *port_)
     port->stp_port = NULL;
     port->stp_state = STP_DISABLED;
     port->tnl_port = NULL;
+    port->peer = NULL;
     hmap_init(&port->priorities);
     port->realdev_ofp_port = 0;
     port->vlandev_vid = 0;
@@ -1389,7 +1472,8 @@ port_construct(struct ofport *port_)
         * because the patch port represents an interface that sFlow considers
         * to be "internal" to the switch as a whole, and therefore not an
         * candidate for counter polling. */
-        port->odp_port = OVSP_NONE;
+        port->odp_port = ODPP_NONE;
+        ofport_update_peer(port);
         return 0;
     }
 
@@ -1416,7 +1500,7 @@ port_construct(struct ofport *port_)
         }
 
         hmap_insert(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node,
-                    hash_int(port->odp_port, 0));
+                    hash_odp_port(port->odp_port));
     }
     dpif_port_destroy(&dpif_port);
 
@@ -1436,6 +1520,8 @@ port_destruct(struct ofport *port_)
     char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
     const char *dp_port_name;
 
+    ofproto->backer->need_revalidate = REV_RECONFIGURE;
+
     dp_port_name = netdev_vport_get_dpif_port(port->up.netdev, namebuf,
                                               sizeof namebuf);
     if (dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
@@ -1446,17 +1532,20 @@ port_destruct(struct ofport *port_)
         if (!port->tnl_port) {
             dpif_port_del(ofproto->backer->dpif, port->odp_port);
         }
-        ofproto->backer->need_revalidate = REV_RECONFIGURE;
     }
 
-    if (port->odp_port != OVSP_NONE && !port->tnl_port) {
+    if (port->peer) {
+        port->peer->peer = NULL;
+        port->peer = NULL;
+    }
+
+    if (port->odp_port != ODPP_NONE && !port->tnl_port) {
         hmap_remove(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node);
     }
 
     tnl_port_del(port->tnl_port);
     sset_find_and_delete(&ofproto->ports, devname);
     sset_find_and_delete(&ofproto->ghost_ports, devname);
-    ofproto->backer->need_revalidate = REV_RECONFIGURE;
     bundle_remove(port_);
     set_cfm(port_, NULL);
     set_bfd(port_, NULL);
@@ -1480,6 +1569,14 @@ port_modified(struct ofport *port_)
     if (port->cfm) {
         cfm_set_netdev(port->cfm, port->up.netdev);
     }
+
+    if (port->tnl_port && tnl_port_reconfigure(&port->up, port->odp_port,
+                                               &port->tnl_port)) {
+        ofproto_dpif_cast(port->up.ofproto)->backer->need_revalidate =
+            REV_RECONFIGURE;
+    }
+
+    ofport_update_peer(port);
 }
 
 static void
@@ -1850,14 +1947,16 @@ stp_wait(struct ofproto_dpif *ofproto)
     }
 }
 
-/* Returns true if STP should process 'flow'. */
-static bool
-stp_should_process_flow(const struct flow *flow)
+/* Returns true if STP should process 'flow'.  Sets fields in 'wc' that
+ * were used to make the determination.*/
+bool
+stp_should_process_flow(const struct flow *flow, struct flow_wildcards *wc)
 {
+    memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
     return eth_addr_equals(flow->dl_dst, eth_addr_stp);
 }
 
-static void
+void
 stp_process_packet(const struct ofport_dpif *ofport,
                    const struct ofpbuf *packet)
 {
@@ -1881,7 +1980,14 @@ stp_process_packet(const struct ofport_dpif *ofport,
     }
 }
 \f
-struct priority_to_dscp *
+int
+ofproto_dpif_queue_to_priority(const struct ofproto_dpif *ofproto,
+                               uint32_t queue_id, uint32_t *priority)
+{
+    return dpif_queue_to_priority(ofproto->backer->dpif, queue_id, priority);
+}
+
+static struct priority_to_dscp *
 get_priority(const struct ofport_dpif *ofport, uint32_t priority)
 {
     struct priority_to_dscp *pdscp;
@@ -1896,6 +2002,15 @@ get_priority(const struct ofport_dpif *ofport, uint32_t priority)
     return NULL;
 }
 
+bool
+ofproto_dpif_dscp_from_priority(const struct ofport_dpif *ofport,
+                                uint32_t priority, uint8_t *dscp)
+{
+    struct priority_to_dscp *pdscp = get_priority(ofport, priority);
+    *dscp = pdscp ? pdscp->dscp : 0;
+    return pdscp != NULL;
+}
+
 static void
 ofport_clear_priorities(struct ofport_dpif *ofport)
 {
@@ -2067,7 +2182,7 @@ bundle_del_port(struct ofport_dpif *port)
 }
 
 static bool
-bundle_add_port(struct ofbundle *bundle, uint16_t ofp_port,
+bundle_add_port(struct ofbundle *bundle, ofp_port_t ofp_port,
                 struct lacp_slave_settings *lacp)
 {
     struct ofport_dpif *port;
@@ -2710,14 +2825,14 @@ set_mac_table_config(struct ofproto *ofproto_, unsigned int idle_time,
 /* Ports. */
 
 struct ofport_dpif *
-get_ofp_port(const struct ofproto_dpif *ofproto, uint16_t ofp_port)
+get_ofp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port)
 {
     struct ofport *ofport = ofproto_get_port(&ofproto->up, ofp_port);
     return ofport ? ofport_dpif_cast(ofport) : NULL;
 }
 
 struct ofport_dpif *
-get_odp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
+get_odp_port(const struct ofproto_dpif *ofproto, odp_port_t odp_port)
 {
     struct ofport_dpif *port = odp_port_to_ofport(ofproto->backer, odp_port);
     return port && &ofproto->up == port->up.ofproto ? port : NULL;
@@ -2733,32 +2848,54 @@ ofproto_port_from_dpif_port(struct ofproto_dpif *ofproto,
     ofproto_port->ofp_port = odp_port_to_ofp_port(ofproto, dpif_port->port_no);
 }
 
-struct ofport_dpif *
-ofport_get_peer(const struct ofport_dpif *ofport_dpif)
+static void
+ofport_update_peer(struct ofport_dpif *ofport)
 {
     const struct ofproto_dpif *ofproto;
-    const struct dpif_backer *backer;
-    const char *peer;
+    struct dpif_backer *backer;
+    const char *peer_name;
 
-    peer = netdev_vport_patch_peer(ofport_dpif->up.netdev);
-    if (!peer) {
-        return NULL;
+    if (!netdev_vport_is_patch(ofport->up.netdev)) {
+        return;
+    }
+
+    backer = ofproto_dpif_cast(ofport->up.ofproto)->backer;
+    backer->need_revalidate = REV_RECONFIGURE;
+
+    if (ofport->peer) {
+        ofport->peer->peer = NULL;
+        ofport->peer = NULL;
+    }
+
+    peer_name = netdev_vport_patch_peer(ofport->up.netdev);
+    if (!peer_name) {
+        return;
     }
 
-    backer = ofproto_dpif_cast(ofport_dpif->up.ofproto)->backer;
     HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
-        struct ofport *ofport;
+        struct ofport *peer_ofport;
+        struct ofport_dpif *peer;
+        const char *peer_peer;
 
         if (ofproto->backer != backer) {
             continue;
         }
 
-        ofport = shash_find_data(&ofproto->up.port_by_name, peer);
-        if (ofport) {
-            return ofport_dpif_cast(ofport);
+        peer_ofport = shash_find_data(&ofproto->up.port_by_name, peer_name);
+        if (!peer_ofport) {
+            continue;
+        }
+
+        peer = ofport_dpif_cast(peer_ofport);
+        peer_peer = netdev_vport_patch_peer(peer->up.netdev);
+        if (peer_peer && !strcmp(netdev_get_name(ofport->up.netdev),
+                                 peer_peer)) {
+            ofport->peer = peer;
+            ofport->peer->peer = ofport;
         }
+
+        return;
     }
-    return NULL;
 }
 
 static void
@@ -2794,12 +2931,6 @@ port_run(struct ofport_dpif *ofport)
 
     port_run_fast(ofport);
 
-    if (ofport->tnl_port
-        && tnl_port_reconfigure(&ofport->up, ofport->odp_port,
-                                &ofport->tnl_port)) {
-        ofproto_dpif_cast(ofport->up.ofproto)->backer->need_revalidate = true;
-    }
-
     if (ofport->cfm) {
         int cfm_opup = cfm_get_opup(ofport->cfm);
 
@@ -2898,7 +3029,7 @@ port_add(struct ofproto *ofproto_, struct netdev *netdev)
 
     dp_port_name = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
     if (!dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
-        uint32_t port_no = UINT32_MAX;
+        odp_port_t port_no = ODPP_NONE;
         int error;
 
         error = dpif_port_add(ofproto->backer->dpif, netdev, &port_no);
@@ -2906,7 +3037,8 @@ port_add(struct ofproto *ofproto_, struct netdev *netdev)
             return error;
         }
         if (netdev_get_tunnel_config(netdev)) {
-            simap_put(&ofproto->backer->tnl_backers, dp_port_name, port_no);
+            simap_put(&ofproto->backer->tnl_backers,
+                      dp_port_name, odp_to_u32(port_no));
         }
     }
 
@@ -2919,7 +3051,7 @@ port_add(struct ofproto *ofproto_, struct netdev *netdev)
 }
 
 static int
-port_del(struct ofproto *ofproto_, uint16_t ofp_port)
+port_del(struct ofproto *ofproto_, ofp_port_t ofp_port)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port);
@@ -3115,6 +3247,13 @@ struct flow_miss_op {
     uint64_t slow_stub[128 / 8]; /* Buffer for compose_slow_path() */
     struct xlate_out xout;
     bool xout_garbage;           /* 'xout' needs to be uninitialized? */
+
+    struct ofpbuf mask;          /* Flow mask for "put" ops. */
+    struct odputil_keybuf maskbuf;
+
+    /* If this is a "put" op, then a pointer to the subfacet that should
+     * be marked as uninstalled if the operation fails. */
+    struct subfacet *subfacet;
 };
 
 /* Sends an OFPT_PACKET_IN message for 'packet' of type OFPR_NO_MATCH to each
@@ -3141,38 +3280,6 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, const struct ofpbuf *packet,
     connmgr_send_packet_in(ofproto->up.connmgr, &pin);
 }
 
-enum slow_path_reason
-process_special(struct ofproto_dpif *ofproto, const struct flow *flow,
-                const struct ofport_dpif *ofport, const struct ofpbuf *packet)
-{
-    if (!ofport) {
-        return 0;
-    } else if (ofport->cfm && cfm_should_process_flow(ofport->cfm, flow)) {
-        if (packet) {
-            cfm_process_heartbeat(ofport->cfm, packet);
-        }
-        return SLOW_CFM;
-    } else if (ofport->bfd && bfd_should_process_flow(flow)) {
-        if (packet) {
-            bfd_process_packet(ofport->bfd, flow, packet);
-        }
-        return SLOW_BFD;
-    } else if (ofport->bundle && ofport->bundle->lacp
-               && flow->dl_type == htons(ETH_TYPE_LACP)) {
-        if (packet) {
-            lacp_process_packet(ofport->bundle->lacp, ofport, packet);
-        }
-        return SLOW_LACP;
-    } else if (ofproto->stp && stp_should_process_flow(flow)) {
-        if (packet) {
-            stp_process_packet(ofport, packet);
-        }
-        return SLOW_STP;
-    } else {
-        return 0;
-    }
-}
-
 static struct flow_miss *
 flow_miss_find(struct hmap *todo, const struct ofproto_dpif *ofproto,
                const struct flow *flow, uint32_t hash)
@@ -3197,8 +3304,8 @@ static void
 init_flow_miss_execute_op(struct flow_miss *miss, struct ofpbuf *packet,
                           struct flow_miss_op *op)
 {
-    if (miss->flow.in_port
-        != vsp_realdev_to_vlandev(miss->ofproto, miss->flow.in_port,
+    if (miss->flow.in_port.ofp_port
+        != vsp_realdev_to_vlandev(miss->ofproto, miss->flow.in_port.ofp_port,
                                   miss->flow.vlan_tci)) {
         /* This packet was received on a VLAN splinter port.  We
          * added a VLAN to the packet to make the packet resemble
@@ -3209,11 +3316,13 @@ init_flow_miss_execute_op(struct flow_miss *miss, struct ofpbuf *packet,
         eth_pop_vlan(packet);
     }
 
+    op->subfacet = NULL;
     op->xout_garbage = false;
     op->dpif_op.type = DPIF_OP_EXECUTE;
     op->dpif_op.u.execute.key = miss->key;
     op->dpif_op.u.execute.key_len = miss->key_len;
     op->dpif_op.u.execute.packet = packet;
+    ofpbuf_use_stack(&op->mask, &op->maskbuf, sizeof op->maskbuf);
 }
 
 /* Helper for handle_flow_miss_without_facet() and
@@ -3361,11 +3470,19 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
 
         subfacet->path = want_path;
 
+        ofpbuf_use_stack(&op->mask, &op->maskbuf, sizeof op->maskbuf);
+        odp_flow_key_from_mask(&op->mask, &facet->xout.wc.masks,
+                               &miss->flow, UINT32_MAX);
+
         op->xout_garbage = false;
         op->dpif_op.type = DPIF_OP_FLOW_PUT;
+        op->subfacet = subfacet;
         put->flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
         put->key = miss->key;
         put->key_len = miss->key_len;
+        put->mask = op->mask.data;
+        put->mask_len = op->mask.size;
+
         if (want_path == SF_FAST_PATH) {
             put->actions = facet->xout.odp_actions.data;
             put->actions_len = facet->xout.odp_actions.size;
@@ -3503,7 +3620,7 @@ 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)
+                struct ofproto_dpif **ofproto, odp_port_t *odp_in_port)
 {
     const struct ofport_dpif *port;
     enum odp_key_fitness fitness;
@@ -3516,13 +3633,13 @@ ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
     }
 
     if (odp_in_port) {
-        *odp_in_port = flow->in_port;
+        *odp_in_port = flow->in_port.odp_port;
     }
 
     port = (tnl_port_should_receive(flow)
             ? ofport_dpif_cast(tnl_port_receive(flow))
-            : odp_port_to_ofport(backer, flow->in_port));
-    flow->in_port = port ? port->up.ofp_port : OFPP_NONE;
+            : odp_port_to_ofport(backer, flow->in_port.odp_port));
+    flow->in_port.ofp_port = port ? port->up.ofp_port : OFPP_NONE;
     if (!port) {
         goto exit;
     }
@@ -3597,7 +3714,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
         struct flow_miss *miss = &misses[n_misses];
         struct flow_miss *existing_miss;
         struct ofproto_dpif *ofproto;
-        uint32_t odp_in_port;
+        odp_port_t odp_in_port;
         struct flow flow;
         uint32_t hash;
         int error;
@@ -3626,7 +3743,8 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
                 hmap_insert(&backer->drop_keys, &drop_key->hmap_node,
                             hash_bytes(drop_key->key, drop_key->key_len, 0));
                 dpif_flow_put(backer->dpif, DPIF_FP_CREATE | DPIF_FP_MODIFY,
-                              drop_key->key, drop_key->key_len, NULL, 0, NULL);
+                              drop_key->key, drop_key->key_len,
+                              NULL, 0, NULL, 0, NULL);
             }
             continue;
         }
@@ -3636,7 +3754,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
 
         ofproto->n_missed++;
         flow_extract(upcall->packet, flow.skb_priority, flow.skb_mark,
-                     &flow.tunnel, flow.in_port, &miss->flow);
+                     &flow.tunnel, &flow.in_port, &miss->flow);
 
         /* Add other packets to a to-do list. */
         hash = flow_hash(&miss->flow, 0);
@@ -3670,8 +3788,18 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
     }
     dpif_operate(backer->dpif, dpif_ops, n_ops);
 
-    /* Free memory. */
     for (i = 0; i < n_ops; i++) {
+        if (dpif_ops[i]->error != 0
+            && flow_miss_ops[i].dpif_op.type == DPIF_OP_FLOW_PUT
+            && flow_miss_ops[i].subfacet) {
+            struct subfacet *subfacet = flow_miss_ops[i].subfacet;
+
+            COVERAGE_INC(subfacet_install_fail);
+
+            subfacet->path = SF_NOT_INSTALLED;
+        }
+
+        /* Free memory. */
         if (flow_miss_ops[i].xout_garbage) {
             xlate_out_uninit(&flow_miss_ops[i].xout);
         }
@@ -3740,7 +3868,7 @@ handle_sflow_upcall(struct dpif_backer *backer,
     struct ofproto_dpif *ofproto;
     union user_action_cookie cookie;
     struct flow flow;
-    uint32_t odp_in_port;
+    odp_port_t odp_in_port;
 
     if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len,
                         &flow, NULL, &ofproto, &odp_in_port)
@@ -4018,11 +4146,12 @@ update_stats(struct dpif_backer *backer)
 {
     const struct dpif_flow_stats *stats;
     struct dpif_flow_dump dump;
-    const struct nlattr *key;
-    size_t key_len;
+    const struct nlattr *key, *mask;
+    size_t key_len, mask_len;
 
     dpif_flow_dump_start(&dump, backer->dpif);
-    while (dpif_flow_dump_next(&dump, &key, &key_len, NULL, NULL, &stats)) {
+    while (dpif_flow_dump_next(&dump, &key, &key_len,
+                               &mask, &mask_len, NULL, NULL, &stats)) {
         struct subfacet *subfacet;
         uint32_t key_hash;
 
@@ -4284,7 +4413,7 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow,
 
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
     odp_flow_key_from_flow(&key, flow,
-                           ofp_port_to_odp_port(ofproto, flow->in_port));
+                           ofp_port_to_odp_port(ofproto, flow->in_port.ofp_port));
 
     error = dpif_execute(ofproto->backer->dpif, key.data, key.size,
                          odp_actions, actions_len, packet);
@@ -4382,7 +4511,7 @@ facet_account(struct facet *facet)
 
         switch (nl_attr_type(a)) {
         case OVS_ACTION_ATTR_OUTPUT:
-            port = get_odp_port(ofproto, nl_attr_get_u32(a));
+            port = get_odp_port(ofproto, nl_attr_get_odp_port(a));
             if (port && port->bundle && port->bundle->bond) {
                 bond_account(port->bundle->bond, &facet->flow,
                              vlan_tci_to_vid(vlan_tci), n_bytes);
@@ -4705,7 +4834,7 @@ facet_push_stats(struct facet *facet, bool may_learn)
         facet->prev_byte_count = facet->byte_count;
         facet->prev_used = facet->used;
 
-        in_port = get_ofp_port(ofproto, facet->flow.in_port);
+        in_port = get_ofp_port(ofproto, facet->flow.in_port.ofp_port);
         if (in_port && in_port->tnl_port) {
             netdev_vport_inc_rx(in_port->up.netdev, &stats);
         }
@@ -4911,6 +5040,8 @@ subfacet_install(struct subfacet *subfacet, const struct ofpbuf *odp_actions,
     enum subfacet_path path = facet->xout.slow ? SF_SLOW_PATH : SF_FAST_PATH;
     const struct nlattr *actions = odp_actions->data;
     size_t actions_len = odp_actions->size;
+    struct odputil_keybuf maskbuf;
+    struct ofpbuf mask;
 
     uint64_t slow_path_stub[128 / 8];
     enum dpif_flow_put_flags flags;
@@ -4927,14 +5058,21 @@ subfacet_install(struct subfacet *subfacet, const struct ofpbuf *odp_actions,
                           &actions, &actions_len);
     }
 
+    ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf);
+    odp_flow_key_from_mask(&mask, &facet->xout.wc.masks,
+                           &facet->flow, UINT32_MAX);
+
     ret = dpif_flow_put(subfacet->backer->dpif, flags, subfacet->key,
-                        subfacet->key_len, actions, actions_len, stats);
+                        subfacet->key_len,  mask.data, mask.size,
+                        actions, actions_len, stats);
 
     if (stats) {
         subfacet_reset_dp_stats(subfacet, stats);
     }
 
-    if (!ret) {
+    if (ret) {
+        COVERAGE_INC(subfacet_install_fail);
+    } else {
         subfacet->path = path;
     }
     return ret;
@@ -5035,6 +5173,11 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
         return NULL;
     }
 
+    if (wc) {
+        memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+        wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+    }
+
     cls = &ofproto->up.tables[table_id].cls;
     frag = (flow->nw_frag & FLOW_NW_FRAG_ANY) != 0;
     if (frag && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
@@ -5059,9 +5202,10 @@ rule_dpif_miss_rule(struct ofproto_dpif *ofproto, const struct flow *flow)
 {
     struct ofport_dpif *port;
 
-    port = get_ofp_port(ofproto, flow->in_port);
+    port = get_ofp_port(ofproto, flow->in_port.ofp_port);
     if (!port) {
-        VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, flow->in_port);
+        VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16,
+                     flow->in_port.ofp_port);
         return ofproto->miss_rule;
     }
 
@@ -5233,13 +5377,15 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
     struct xlate_out xout;
     struct xlate_in xin;
     struct flow flow;
+    union flow_in_port in_port_;
     int error;
 
     ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
 
     /* Use OFPP_NONE as the in_port to avoid special packet processing. */
-    flow_extract(packet, 0, 0, NULL, OFPP_NONE, &flow);
+    in_port_.ofp_port = OFPP_NONE;
+    flow_extract(packet, 0, 0, NULL, &in_port_, &flow);
     odp_flow_key_from_flow(&key, &flow, ofp_port_to_odp_port(ofproto,
                                                              OFPP_LOCAL));
     dpif_flow_stats_extract(&flow, packet, time_msec(), &stats);
@@ -5296,7 +5442,8 @@ compose_slow_path(const struct ofproto_dpif *ofproto, const struct flow *flow,
 
     ofpbuf_use_stack(&buf, stub, stub_size);
     if (slow & (SLOW_CFM | SLOW_BFD | SLOW_LACP | SLOW_STP)) {
-        uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX);
+        uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif,
+                                         ODPP_NONE);
         odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path, &buf);
     } else {
         put_userspace_action(ofproto, &buf, flow, &cookie,
@@ -5316,7 +5463,8 @@ put_userspace_action(const struct ofproto_dpif *ofproto,
     uint32_t pid;
 
     pid = dpif_port_get_pid(ofproto->backer->dpif,
-                            ofp_port_to_odp_port(ofproto, flow->in_port));
+                            ofp_port_to_odp_port(ofproto,
+                                                 flow->in_port.ofp_port));
 
     return odp_put_userspace_action(pid, cookie, cookie_size, odp_actions);
 }
@@ -5492,7 +5640,8 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
 
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
     odp_flow_key_from_flow(&key, flow,
-                           ofp_port_to_odp_port(ofproto, flow->in_port));
+                           ofp_port_to_odp_port(ofproto,
+                                      flow->in_port.ofp_port));
 
     dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
 
@@ -5520,13 +5669,16 @@ set_netflow(struct ofproto *ofproto_,
     if (netflow_options) {
         if (!ofproto->netflow) {
             ofproto->netflow = netflow_create();
+            ofproto->backer->need_revalidate = REV_RECONFIGURE;
         }
         return netflow_set_options(ofproto->netflow, netflow_options);
-    } else {
+    } else if (ofproto->netflow) {
+        ofproto->backer->need_revalidate = REV_RECONFIGURE;
         netflow_destroy(ofproto->netflow);
         ofproto->netflow = NULL;
-        return 0;
     }
+
+    return 0;
 }
 
 static void
@@ -5629,9 +5781,12 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
     ds_put_cstr(&ds, " port  VLAN  MAC                Age\n");
     LIST_FOR_EACH (e, lru_node, &ofproto->ml->lrus) {
         struct ofbundle *bundle = e->port.p;
-        ds_put_format(&ds, "%5d  %4d  "ETH_ADDR_FMT"  %3d\n",
-                      ofbundle_get_a_port(bundle)->odp_port,
-                      e->vlan, ETH_ADDR_ARGS(e->mac),
+        char name[OFP_MAX_PORT_NAME_LEN];
+
+        ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port,
+                               name, sizeof name);
+        ds_put_format(&ds, "%5s  %4d  "ETH_ADDR_FMT"  %3d\n",
+                      name, e->vlan, ETH_ADDR_ARGS(e->mac),
                       mac_entry_age(ofproto->ml, e));
     }
     unixctl_command_reply(conn, ds_cstr(&ds));
@@ -5766,7 +5921,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
      * bridge is specified. If function odp_flow_key_from_string()
      * returns 0, the flow is a odp_flow. If function
      * parse_ofp_exact_flow() returns 0, the flow is a br_flow. */
-    if (!odp_flow_key_from_string(argv[argc - 1], NULL, &odp_key)) {
+    if (!odp_flow_from_string(argv[argc - 1], NULL, &odp_key, NULL)) {
         /* If the odp_flow is the second argument,
          * the datapath name is the first argument. */
         if (argc == 3) {
@@ -5824,6 +5979,9 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
         if (!packet->size) {
             flow_compose(packet, &flow);
         } else {
+            union flow_in_port in_port_;
+
+            in_port_ = flow.in_port;
             ds_put_cstr(&result, "Packet: ");
             s = ofp_packet_to_string(packet->data, packet->size);
             ds_put_cstr(&result, s);
@@ -5832,7 +5990,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
             /* Use the metadata from the flow and the packet argument
              * to reconstruct the flow. */
             flow_extract(packet, flow.skb_priority, flow.skb_mark, NULL,
-                         flow.in_port, &flow);
+                         &in_port_, &flow);
         }
     }
 
@@ -6097,13 +6255,13 @@ dpif_show_backer(const struct dpif_backer *backer, struct ds *ds)
             const struct shash_node *node = ports[j];
             struct ofport *ofport = node->data;
             struct smap config;
-            uint32_t odp_port;
+            odp_port_t odp_port;
 
             ds_put_format(ds, "\t\t%s %u/", netdev_get_name(ofport->netdev),
                           ofport->ofp_port);
 
             odp_port = ofp_port_to_odp_port(ofproto, ofport->ofp_port);
-            if (odp_port != OVSP_NONE) {
+            if (odp_port != ODPP_NONE) {
                 ds_put_format(ds, "%"PRIu32":", odp_port);
             } else {
                 ds_put_cstr(ds, "none:");
@@ -6330,7 +6488,7 @@ ofproto_dpif_unixctl_init(void)
  * widespread use, we will delete these interfaces. */
 
 static int
-set_realdev(struct ofport *ofport_, uint16_t realdev_ofp_port, int vid)
+set_realdev(struct ofport *ofport_, ofp_port_t realdev_ofp_port, int vid)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport_->ofproto);
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
@@ -6362,9 +6520,9 @@ set_realdev(struct ofport *ofport_, uint16_t realdev_ofp_port, int vid)
 }
 
 static uint32_t
-hash_realdev_vid(uint16_t realdev_ofp_port, int vid)
+hash_realdev_vid(ofp_port_t realdev_ofp_port, int vid)
 {
-    return hash_2words(realdev_ofp_port, vid);
+    return hash_2words(ofp_to_u16(realdev_ofp_port), vid);
 }
 
 /* Returns the OFP port number of the Linux VLAN device that corresponds to
@@ -6374,9 +6532,9 @@ hash_realdev_vid(uint16_t realdev_ofp_port, int vid)
  *
  * Unless VLAN splinters are enabled for port 'realdev_ofp_port', this
  * function just returns its 'realdev_ofp_port' argument. */
-uint16_t
+ofp_port_t
 vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto,
-                       uint16_t realdev_ofp_port, ovs_be16 vlan_tci)
+                       ofp_port_t realdev_ofp_port, ovs_be16 vlan_tci)
 {
     if (!hmap_is_empty(&ofproto->realdev_vid_map)) {
         int vid = vlan_tci_to_vid(vlan_tci);
@@ -6395,11 +6553,12 @@ vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto,
 }
 
 static struct vlan_splinter *
-vlandev_find(const struct ofproto_dpif *ofproto, uint16_t vlandev_ofp_port)
+vlandev_find(const struct ofproto_dpif *ofproto, ofp_port_t vlandev_ofp_port)
 {
     struct vlan_splinter *vsp;
 
-    HMAP_FOR_EACH_WITH_HASH (vsp, vlandev_node, hash_int(vlandev_ofp_port, 0),
+    HMAP_FOR_EACH_WITH_HASH (vsp, vlandev_node,
+                             hash_ofp_port(vlandev_ofp_port),
                              &ofproto->vlandev_map) {
         if (vsp->vlandev_ofp_port == vlandev_ofp_port) {
             return vsp;
@@ -6418,9 +6577,9 @@ vlandev_find(const struct ofproto_dpif *ofproto, uint16_t vlandev_ofp_port)
  * Returns 0 and does not modify '*vid' if 'vlandev_ofp_port' is not a Linux
  * VLAN device.  Unless VLAN splinters are enabled, this is what this function
  * always does.*/
-static uint16_t
+static ofp_port_t
 vsp_vlandev_to_realdev(const struct ofproto_dpif *ofproto,
-                       uint16_t vlandev_ofp_port, int *vid)
+                       ofp_port_t vlandev_ofp_port, int *vid)
 {
     if (!hmap_is_empty(&ofproto->vlandev_map)) {
         const struct vlan_splinter *vsp;
@@ -6445,17 +6604,17 @@ vsp_vlandev_to_realdev(const struct ofproto_dpif *ofproto,
 static bool
 vsp_adjust_flow(const struct ofproto_dpif *ofproto, struct flow *flow)
 {
-    uint16_t realdev;
+    ofp_port_t realdev;
     int vid;
 
-    realdev = vsp_vlandev_to_realdev(ofproto, flow->in_port, &vid);
+    realdev = vsp_vlandev_to_realdev(ofproto, flow->in_port.ofp_port, &vid);
     if (!realdev) {
         return false;
     }
 
     /* Cause the flow to be processed as if it came in on the real device with
      * the VLAN device's VLAN ID. */
-    flow->in_port = realdev;
+    flow->in_port.ofp_port = realdev;
     flow->vlan_tci = htons((vid & VLAN_VID_MASK) | VLAN_CFI);
     return true;
 }
@@ -6479,7 +6638,7 @@ vsp_remove(struct ofport_dpif *port)
 }
 
 static void
-vsp_add(struct ofport_dpif *port, uint16_t realdev_ofp_port, int vid)
+vsp_add(struct ofport_dpif *port, ofp_port_t realdev_ofp_port, int vid)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
 
@@ -6490,7 +6649,7 @@ vsp_add(struct ofport_dpif *port, uint16_t realdev_ofp_port, int vid)
 
         vsp = xmalloc(sizeof *vsp);
         hmap_insert(&ofproto->vlandev_map, &vsp->vlandev_node,
-                    hash_int(port->up.ofp_port, 0));
+                    hash_ofp_port(port->up.ofp_port));
         hmap_insert(&ofproto->realdev_vid_map, &vsp->realdev_vid_node,
                     hash_realdev_vid(realdev_ofp_port, vid));
         vsp->realdev_ofp_port = realdev_ofp_port;
@@ -6503,20 +6662,19 @@ vsp_add(struct ofport_dpif *port, uint16_t realdev_ofp_port, int vid)
     }
 }
 
-uint32_t
-ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, uint16_t ofp_port)
+odp_port_t
+ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port)
 {
     const struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port);
-    return ofport ? ofport->odp_port : OVSP_NONE;
+    return ofport ? ofport->odp_port : ODPP_NONE;
 }
 
 static struct ofport_dpif *
-odp_port_to_ofport(const struct dpif_backer *backer, uint32_t odp_port)
+odp_port_to_ofport(const struct dpif_backer *backer, odp_port_t odp_port)
 {
     struct ofport_dpif *port;
 
-    HMAP_FOR_EACH_IN_BUCKET (port, odp_port_node,
-                             hash_int(odp_port, 0),
+    HMAP_FOR_EACH_IN_BUCKET (port, odp_port_node, hash_odp_port(odp_port),
                              &backer->odp_to_ofport_map) {
         if (port->odp_port == odp_port) {
             return port;
@@ -6526,8 +6684,8 @@ odp_port_to_ofport(const struct dpif_backer *backer, uint32_t odp_port)
     return NULL;
 }
 
-static uint16_t
-odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
+static ofp_port_t
+odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, odp_port_t odp_port)
 {
     struct ofport_dpif *port;