ofproto: Add 'name' field to struct ofproto and use hmap instead of shash.
[openvswitch] / ofproto / ofproto.c
index 6745a49b602abe77a1fa1725fabacca7985f93c0..01b44e7f30c7028a17c9b897b1093ed2dbfe954c 100644 (file)
@@ -54,6 +54,7 @@
 #include "pinsched.h"
 #include "pktbuf.h"
 #include "poll-loop.h"
+#include "private.h"
 #include "rconn.h"
 #include "shash.h"
 #include "sset.h"
@@ -101,7 +102,7 @@ struct rule;
 struct ofport {
     struct hmap_node hmap_node; /* In struct ofproto's "ports" hmap. */
     struct netdev *netdev;
-    struct ofp_phy_port opp;    /* In host byte order. */
+    struct ofp_phy_port opp;
     uint16_t odp_port;
     struct cfm *cfm;            /* Connectivity Fault Management, if any. */
 };
@@ -276,6 +277,9 @@ static void send_packet_in(struct ofproto *, struct dpif_upcall *,
                            const struct flow *, bool clone);
 
 struct ofproto {
+    char *name;                 /* Datapath name. */
+    struct hmap_node hmap_node; /* In global 'all_ofprotos' hmap. */
+
     /* Settings. */
     uint64_t datapath_id;       /* Datapath ID. */
     uint64_t fallback_dpid;     /* Datapath ID if no better choice found. */
@@ -317,7 +321,7 @@ struct ofproto {
 };
 
 /* Map from dpif name to struct ofproto, for use by unixctl commands. */
-static struct shash all_ofprotos = SHASH_INITIALIZER(&all_ofprotos);
+static struct hmap all_ofprotos = HMAP_INITIALIZER(&all_ofprotos);
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
@@ -358,7 +362,7 @@ ofproto_create(const char *datapath, const char *datapath_type,
     ofproto_unixctl_init();
 
     /* Connect to datapath and start listening for messages. */
-    error = dpif_open(datapath, datapath_type, &dpif);
+    error = dpif_create_and_open(datapath, datapath_type, &dpif);
     if (error) {
         VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error));
         return error;
@@ -386,6 +390,8 @@ ofproto_create(const char *datapath, const char *datapath_type,
 
     /* Initialize settings. */
     p = xzalloc(sizeof *p);
+    p->name = xstrdup(dpif_name(dpif));
+    hmap_insert(&all_ofprotos, &p->hmap_node, hash_string(p->name, 0));
     p->fallback_dpid = pick_fallback_dpid();
     p->datapath_id = p->fallback_dpid;
     p->mfr_desc = xstrdup(DEFAULT_MFR_DESC);
@@ -429,8 +435,6 @@ ofproto_create(const char *datapath, const char *datapath_type,
     p->datapath_id = pick_datapath_id(p);
     VLOG_INFO("using datapath ID %016"PRIx64, p->datapath_id);
 
-    shash_add_once(&all_ofprotos, dpif_name(p->dpif), p);
-
     /* Initialize OpenFlow connections. */
     p->connmgr = connmgr_create(p, datapath, local_name);
 
@@ -592,7 +596,7 @@ ofproto_set_sflow(struct ofproto *ofproto,
 
 /* Clears the CFM configuration from 'port_no' on 'ofproto'. */
 void
-ofproto_iface_clear_cfm(struct ofproto *ofproto, uint32_t port_no)
+ofproto_port_clear_cfm(struct ofproto *ofproto, uint32_t port_no)
 {
     struct ofport *ofport = get_port(ofproto, port_no);
     if (ofport && ofport->cfm){
@@ -608,16 +612,16 @@ ofproto_iface_clear_cfm(struct ofproto *ofproto, uint32_t port_no)
  *
  * This function has no effect if 'ofproto' does not have a port 'port_no'. */
 void
-ofproto_iface_set_cfm(struct ofproto *ofproto, uint32_t port_no,
-                      const struct cfm *cfm,
-                      const uint16_t *remote_mps, size_t n_remote_mps)
+ofproto_port_set_cfm(struct ofproto *ofproto, uint32_t port_no,
+                     const struct cfm *cfm,
+                     const uint16_t *remote_mps, size_t n_remote_mps)
 {
     struct ofport *ofport;
 
     ofport = get_port(ofproto, port_no);
     if (!ofport) {
         VLOG_WARN("%s: cannot configure CFM on nonexistent port %"PRIu32,
-                  dpif_name(ofproto->dpif), port_no);
+                  ofproto->name, port_no);
         return;
     }
 
@@ -633,7 +637,7 @@ ofproto_iface_set_cfm(struct ofproto *ofproto, uint32_t port_no,
 
     if (!cfm_configure(ofport->cfm)) {
         VLOG_WARN("%s: CFM configuration on port %"PRIu32" (%s) failed",
-                  dpif_name(ofproto->dpif), port_no,
+                  ofproto->name, port_no,
                   netdev_get_name(ofport->netdev));
         cfm_destroy(ofport->cfm);
         ofport->cfm = NULL;
@@ -645,7 +649,7 @@ ofproto_iface_set_cfm(struct ofproto *ofproto, uint32_t port_no,
  * 'port_no' or if that port does not have CFM configured.  The caller must not
  * modify or destroy the returned object. */
 const struct cfm *
-ofproto_iface_get_cfm(struct ofproto *ofproto, uint32_t port_no)
+ofproto_port_get_cfm(struct ofproto *ofproto, uint32_t port_no)
 {
     struct ofport *ofport = get_port(ofproto, port_no);
     return ofport ? ofport->cfm : NULL;
@@ -675,8 +679,8 @@ ofproto_get_snoops(const struct ofproto *ofproto, struct sset *snoops)
     connmgr_get_snoops(ofproto->connmgr, snoops);
 }
 
-void
-ofproto_destroy(struct ofproto *p)
+static void
+ofproto_destroy__(struct ofproto *p, bool delete)
 {
     struct ofport *ofport, *next_ofport;
 
@@ -684,14 +688,22 @@ ofproto_destroy(struct ofproto *p)
         return;
     }
 
-    shash_find_and_delete(&all_ofprotos, dpif_name(p->dpif));
+    hmap_remove(&all_ofprotos, &p->hmap_node);
 
     ofproto_flush_flows__(p);
     connmgr_destroy(p->connmgr);
     classifier_destroy(&p->cls);
     hmap_destroy(&p->facets);
 
+    if (delete) {
+        int error = dpif_delete(p->dpif);
+        if (error && error != ENOENT) {
+            VLOG_ERR("bridge %s: failed to destroy (%s)",
+                     p->name, strerror(error));
+        }
+    }
     dpif_close(p->dpif);
+
     netdev_monitor_destroy(p->netdev_monitor);
     HMAP_FOR_EACH_SAFE (ofport, next_ofport, hmap_node, &p->ports) {
         hmap_remove(&p->ports, &ofport->hmap_node);
@@ -712,9 +724,22 @@ ofproto_destroy(struct ofproto *p)
 
     hmap_destroy(&p->ports);
 
+    free(p->name);
     free(p);
 }
 
+void
+ofproto_destroy(struct ofproto *p)
+{
+    ofproto_destroy__(p, false);
+}
+
+void
+ofproto_destroy_and_delete(struct ofproto *p)
+{
+    ofproto_destroy__(p, true);
+}
+
 int
 ofproto_run(struct ofproto *p)
 {
@@ -759,7 +784,7 @@ ofproto_run1(struct ofproto *p)
                  * spin from here on out. */
                 static struct vlog_rate_limit rl2 = VLOG_RATE_LIMIT_INIT(1, 5);
                 VLOG_ERR_RL(&rl2, "%s: datapath was destroyed externally",
-                            dpif_name(p->dpif));
+                            p->name);
                 return ENODEV;
             }
             break;
@@ -893,7 +918,134 @@ ofproto_free_ofproto_controller_info(struct shash *info)
     shash_destroy(info);
 }
 
-/* Deletes port number 'odp_port' from the datapath for 'ofproto'.
+/* Makes a deep copy of 'old' into 'port'. */
+void
+ofproto_port_clone(struct ofproto_port *port, const struct ofproto_port *old)
+{
+    port->name = xstrdup(old->name);
+    port->type = xstrdup(old->type);
+    port->ofp_port = old->ofp_port;
+}
+
+/* Frees memory allocated to members of 'ofproto_port'.
+ *
+ * Do not call this function on an ofproto_port obtained from
+ * ofproto_port_dump_next(): that function retains ownership of the data in the
+ * ofproto_port. */
+void
+ofproto_port_destroy(struct ofproto_port *ofproto_port)
+{
+    free(ofproto_port->name);
+    free(ofproto_port->type);
+}
+
+/* Converts a dpif_port into an ofproto_port.
+ *
+ * This only makes a shallow copy, so make sure that the dpif_port doesn't get
+ * freed while the ofproto_port is still in use.  You can choose to free the
+ * ofproto_port instead of the dpif_port. */
+static void
+ofproto_port_from_dpif_port(struct ofproto_port *ofproto_port,
+                            struct dpif_port *dpif_port)
+{
+    ofproto_port->name = dpif_port->name;
+    ofproto_port->type = dpif_port->type;
+    ofproto_port->ofp_port = odp_port_to_ofp_port(dpif_port->port_no);
+}
+
+/* Initializes 'dump' to begin dumping the ports in an ofproto.
+ *
+ * This function provides no status indication.  An error status for the entire
+ * dump operation is provided when it is completed by calling
+ * ofproto_port_dump_done().
+ */
+void
+ofproto_port_dump_start(struct ofproto_port_dump *dump,
+                        const struct ofproto *ofproto)
+{
+    struct dpif_port_dump *dpif_dump;
+
+    dump->state = dpif_dump = xmalloc(sizeof *dpif_dump);
+    dpif_port_dump_start(dpif_dump, ofproto->dpif);
+}
+
+/* Attempts to retrieve another port from 'dump', which must have been created
+ * with ofproto_port_dump_start().  On success, stores a new ofproto_port into
+ * 'port' and returns true.  On failure, returns false.
+ *
+ * Failure might indicate an actual error or merely that the last port has been
+ * dumped.  An error status for the entire dump operation is provided when it
+ * is completed by calling ofproto_port_dump_done().
+ *
+ * The ofproto owns the data stored in 'port'.  It will remain valid until at
+ * least the next time 'dump' is passed to ofproto_port_dump_next() or
+ * ofproto_port_dump_done(). */
+bool
+ofproto_port_dump_next(struct ofproto_port_dump *dump,
+                       struct ofproto_port *port)
+{
+    struct dpif_port_dump *dpif_dump = dump->state;
+    struct dpif_port dpif_port;
+    bool ok;
+
+    ok = dpif_port_dump_next(dpif_dump, &dpif_port);
+    if (ok) {
+        ofproto_port_from_dpif_port(port, &dpif_port);
+    }
+    return ok;
+}
+
+/* Completes port table dump operation 'dump', which must have been created
+ * with ofproto_port_dump_start().  Returns 0 if the dump operation was
+ * error-free, otherwise a positive errno value describing the problem. */
+int
+ofproto_port_dump_done(struct ofproto_port_dump *dump)
+{
+    struct dpif_port_dump *dpif_dump = dump->state;
+    int error = dpif_port_dump_done(dpif_dump);
+    free(dpif_dump);
+    return error;
+}
+
+/* Attempts to add 'netdev' as a port on 'ofproto'.  If successful, returns 0
+ * and sets '*ofp_portp' to the new port's port OpenFlow number (if 'ofp_portp'
+ * is non-null).  On failure, returns a positive errno value and sets
+ * '*ofp_portp' to OFPP_NONE (if 'ofp_portp' is non-null). */
+int
+ofproto_port_add(struct ofproto *ofproto, struct netdev *netdev,
+                 uint16_t *ofp_portp)
+{
+    uint16_t odp_port;
+    int error;
+
+    error = dpif_port_add(ofproto->dpif, netdev, &odp_port);
+    if (ofp_portp) {
+        *ofp_portp = error ? OFPP_NONE : odp_port_to_ofp_port(odp_port);
+    }
+    return error;
+}
+
+/* Looks up a port named 'devname' in 'ofproto'.  On success, returns 0 and
+ * initializes '*port' appropriately; on failure, returns a positive errno
+ * value.
+ *
+ * The caller owns the data in 'port' and must free it with
+ * ofproto_port_destroy() when it is no longer needed. */
+int
+ofproto_port_query_by_name(const struct ofproto *ofproto, const char *devname,
+                           struct ofproto_port *port)
+{
+    struct dpif_port dpif_port;
+    int error;
+
+    error = dpif_port_query_by_name(ofproto->dpif, devname, &dpif_port);
+    if (!error) {
+        ofproto_port_from_dpif_port(port, &dpif_port);
+    }
+    return error;
+}
+
+/* Deletes port number 'ofp_port' from the datapath for 'ofproto'.
  *
  * This is almost the same as calling dpif_port_del() directly on the
  * datapath, but it also makes 'ofproto' close its open netdev for the port
@@ -904,8 +1056,9 @@ ofproto_free_ofproto_controller_info(struct shash *info)
  *
  * Returns 0 if successful, otherwise a positive errno. */
 int
-ofproto_port_del(struct ofproto *ofproto, uint16_t odp_port)
+ofproto_port_del(struct ofproto *ofproto, uint16_t ofp_port)
 {
+    uint32_t odp_port = ofp_port_to_odp_port(ofp_port);
     struct ofport *ofport = get_port(ofproto, odp_port);
     const char *name = ofport ? netdev_get_name(ofport->netdev) : "<unknown>";
     int error;
@@ -913,7 +1066,7 @@ ofproto_port_del(struct ofproto *ofproto, uint16_t odp_port)
     error = dpif_port_del(ofproto->dpif, odp_port);
     if (error) {
         VLOG_ERR("%s: failed to remove port %"PRIu16" (%s) interface (%s)",
-                 dpif_name(ofproto->dpif), odp_port, name, strerror(error));
+                 ofproto->name, odp_port, name, strerror(error));
     } else if (ofport) {
         /* 'name' is the netdev's name and update_port() is going to close the
          * netdev.  Just in case update_port() refers to 'name' after it
@@ -932,7 +1085,7 @@ bool
 ofproto_port_is_floodable(struct ofproto *ofproto, uint16_t odp_port)
 {
     struct ofport *ofport = get_port(ofproto, odp_port);
-    return ofport && !(ofport->opp.config & OFPPC_NO_FLOOD);
+    return ofport && !(ofport->opp.config & htonl(OFPPC_NO_FLOOD));
 }
 
 /* Sends 'packet' out of port 'port_no' within 'p'.  If 'vlan_tci' is zero the
@@ -940,7 +1093,7 @@ ofproto_port_is_floodable(struct ofproto *ofproto, uint16_t odp_port)
  * will be sent with the VLAN TCI specified by 'vlan_tci & ~VLAN_CFI'.
  *
  * Returns 0 if successful, otherwise a positive errno value. */
-int
+static int
 ofproto_send_packet(struct ofproto *ofproto,
                     uint32_t port_no, uint16_t vlan_tci,
                     const struct ofpbuf *packet)
@@ -960,7 +1113,7 @@ ofproto_send_packet(struct ofproto *ofproto,
 
     if (error) {
         VLOG_WARN_RL(&rl, "%s: failed to send packet on port %"PRIu32" (%s)",
-                     dpif_name(ofproto->dpif), port_no, strerror(error));
+                     ofproto->name, port_no, strerror(error));
     }
     return error;
 }
@@ -1056,10 +1209,11 @@ reinit_ports(struct ofproto *p)
 }
 
 /* Opens and returns a netdev for 'dpif_port', or a null pointer if the netdev
- * cannot be opened.  On success, also fills in 'opp', in *HOST* byte order. */
+ * cannot be opened.  On success, also fills in 'opp'. */
 static struct netdev *
 ofport_open(const struct dpif_port *dpif_port, struct ofp_phy_port *opp)
 {
+    uint32_t curr, advertised, supported, peer;
     struct netdev_options netdev_options;
     enum netdev_flags flags;
     struct netdev *netdev;
@@ -1080,14 +1234,18 @@ ofport_open(const struct dpif_port *dpif_port, struct ofp_phy_port *opp)
     }
 
     netdev_get_flags(netdev, &flags);
+    netdev_get_features(netdev, &curr, &advertised, &supported, &peer);
 
-    opp->port_no = odp_port_to_ofp_port(dpif_port->port_no);
+    opp->port_no = htons(odp_port_to_ofp_port(dpif_port->port_no));
     netdev_get_etheraddr(netdev, opp->hw_addr);
     ovs_strzcpy(opp->name, dpif_port->name, sizeof opp->name);
-    opp->config = flags & NETDEV_UP ? 0 : OFPPC_PORT_DOWN;
-    opp->state = netdev_get_carrier(netdev) ? 0 : OFPPS_LINK_DOWN;
-    netdev_get_features(netdev, &opp->curr, &opp->advertised,
-                        &opp->supported, &opp->peer);
+    opp->config = flags & NETDEV_UP ? 0 : htonl(OFPPC_PORT_DOWN);
+    opp->state = netdev_get_carrier(netdev) ? 0 : htonl(OFPPS_LINK_DOWN);
+    opp->curr = htonl(curr);
+    opp->advertised = htonl(advertised);
+    opp->supported = htonl(supported);
+    opp->peer = htonl(peer);
+
     return netdev;
 }
 
@@ -1116,7 +1274,7 @@ ofport_equal(const struct ofp_phy_port *a, const struct ofp_phy_port *b)
     BUILD_ASSERT_DECL(sizeof *a == 48); /* Detect ofp_phy_port changes. */
     return (!memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr)
             && a->state == b->state
-            && !((a->config ^ b->config) & OFPPC_PORT_DOWN)
+            && !((a->config ^ b->config) & htonl(OFPPC_PORT_DOWN))
             && a->curr == b->curr
             && a->advertised == b->advertised
             && a->supported == b->supported
@@ -1139,7 +1297,7 @@ ofport_install(struct ofproto *p,
     ofport = xmalloc(sizeof *ofport);
     ofport->netdev = netdev;
     ofport->opp = *opp;
-    ofport->odp_port = ofp_port_to_odp_port(opp->port_no);
+    ofport->odp_port = ofp_port_to_odp_port(ntohs(opp->port_no));
     ofport->cfm = NULL;
 
     /* Add port to 'p'. */
@@ -1189,8 +1347,8 @@ ofport_modified(struct ofproto *ofproto, struct ofport *port,
                 struct netdev *netdev, struct ofp_phy_port *opp)
 {
     memcpy(port->opp.hw_addr, opp->hw_addr, ETH_ADDR_LEN);
-    port->opp.config = ((port->opp.config & ~OFPPC_PORT_DOWN)
-                        | (opp->config & OFPPC_PORT_DOWN));
+    port->opp.config = ((port->opp.config & ~htonl(OFPPC_PORT_DOWN))
+                        | (opp->config & htonl(OFPPC_PORT_DOWN)));
     port->opp.state = opp->state;
     port->opp.curr = opp->curr;
     port->opp.advertised = opp->advertised;
@@ -1922,7 +2080,7 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
                          (1u << OFPAT_ENQUEUE));
 
     HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
-        hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp));
+        ofpbuf_put(buf, &port->opp, sizeof port->opp);
     }
 
     ofconn_send_reply(ofconn, buf);
@@ -1987,7 +2145,7 @@ add_output_action(struct action_xlate_ctx *ctx, uint16_t port)
     const struct ofport *ofport = get_port(ctx->ofproto, port);
 
     if (ofport) {
-        if (ofport->opp.config & OFPPC_NO_FWD) {
+        if (ofport->opp.config & htonl(OFPPC_NO_FWD)) {
             /* Forwarding disabled on port. */
             return;
         }
@@ -2042,7 +2200,7 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
 }
 
 static void
-flood_packets(struct ofproto *ofproto, uint16_t odp_in_port, uint32_t mask,
+flood_packets(struct ofproto *ofproto, uint16_t odp_in_port, ovs_be32 mask,
               uint16_t *nf_output_iface, struct ofpbuf *odp_actions)
 {
     struct ofport *ofport;
@@ -2082,11 +2240,11 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
         }
         break;
     case OFPP_FLOOD:
-        flood_packets(ctx->ofproto, ctx->flow.in_port, OFPPC_NO_FLOOD,
+        flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(OFPPC_NO_FLOOD),
                       &ctx->nf_output_iface, ctx->odp_actions);
         break;
     case OFPP_ALL:
-        flood_packets(ctx->ofproto, ctx->flow.in_port, 0,
+        flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(0),
                       &ctx->nf_output_iface, ctx->odp_actions);
         break;
     case OFPP_CONTROLLER:
@@ -2339,9 +2497,10 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
     const struct ofport *port;
 
     port = get_port(ctx->ofproto, ctx->flow.in_port);
-    if (port && port->opp.config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
+    if (port && port->opp.config & htonl(OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
         port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp)
-                            ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) {
+                            ? htonl(OFPPC_NO_RECV_STP)
+                            : htonl(OFPPC_NO_RECV))) {
         /* Drop this flow. */
         return;
     }
@@ -2583,11 +2742,11 @@ exit:
 
 static void
 update_port_config(struct ofproto *p, struct ofport *port,
-                   uint32_t config, uint32_t mask)
+                   ovs_be32 config, ovs_be32 mask)
 {
     mask &= config ^ port->opp.config;
-    if (mask & OFPPC_PORT_DOWN) {
-        if (config & OFPPC_PORT_DOWN) {
+    if (mask & htonl(OFPPC_PORT_DOWN)) {
+        if (config & htonl(OFPPC_PORT_DOWN)) {
             netdev_turn_flags_off(port->netdev, NETDEV_UP, true);
         } else {
             netdev_turn_flags_on(port->netdev, NETDEV_UP, true);
@@ -2595,14 +2754,14 @@ update_port_config(struct ofproto *p, struct ofport *port,
     }
 #define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP |    \
                          OFPPC_NO_FWD | OFPPC_NO_FLOOD)
-    if (mask & REVALIDATE_BITS) {
+    if (mask & htonl(REVALIDATE_BITS)) {
         COVERAGE_INC(ofproto_costly_flags);
-        port->opp.config ^= mask & REVALIDATE_BITS;
+        port->opp.config ^= mask & htonl(REVALIDATE_BITS);
         p->need_revalidate = true;
     }
 #undef REVALIDATE_BITS
-    if (mask & OFPPC_NO_PACKET_IN) {
-        port->opp.config ^= OFPPC_NO_PACKET_IN;
+    if (mask & htonl(OFPPC_NO_PACKET_IN)) {
+        port->opp.config ^= htonl(OFPPC_NO_PACKET_IN);
     }
 }
 
@@ -2625,7 +2784,7 @@ handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh)
     } else if (memcmp(port->opp.hw_addr, opm->hw_addr, OFP_ETH_ALEN)) {
         return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_HW_ADDR);
     } else {
-        update_port_config(p, port, ntohl(opm->config), ntohl(opm->mask));
+        update_port_config(p, port, opm->config, opm->mask);
         if (opm->advertise) {
             netdev_set_advertisements(port->netdev, ntohl(opm->advertise));
         }
@@ -2764,7 +2923,7 @@ append_port_stat(struct ofport *port, struct ofconn *ofconn,
     netdev_get_stats(port->netdev, &stats);
 
     ops = append_ofp_stats_reply(sizeof *ops, ofconn, msgp);
-    ops->port_no = htons(port->opp.port_no);
+    ops->port_no = port->opp.port_no;
     memset(ops->pad, 0, sizeof ops->pad);
     put_32aligned_be64(&ops->rx_packets, htonll(stats.rx_packets));
     put_32aligned_be64(&ops->tx_packets, htonll(stats.tx_packets));
@@ -3016,6 +3175,15 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results)
     }
 }
 
+/* Obtains the NetFlow engine type and engine ID for 'ofproto' into
+ * '*engine_type' and '*engine_id', respectively. */
+void
+ofproto_get_netflow_ids(const struct ofproto *ofproto,
+                        uint8_t *engine_type, uint8_t *engine_id)
+{
+    dpif_get_netflow_ids(ofproto->dpif, engine_type, engine_id);
+}
+
 static void
 query_aggregate_stats(struct ofproto *ofproto, struct cls_rule *target,
                       ovs_be16 out_port, uint8_t table_id,
@@ -3120,7 +3288,7 @@ put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
     struct ofp_queue_stats *reply;
 
     reply = append_ofp_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg);
-    reply->port_no = htons(cbdata->ofport->opp.port_no);
+    reply->port_no = cbdata->ofport->opp.port_no;
     memset(reply->pad, 0, sizeof reply->pad);
     reply->queue_id = htonl(queue_id);
     put_32aligned_be64(&reply->tx_bytes, htonll(stats->tx_bytes));
@@ -3788,7 +3956,7 @@ handle_miss_upcall(struct ofproto *p, struct dpif_upcall *upcall)
             /* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */
             struct ofport *port = get_port(p, flow.in_port);
             if (port) {
-                if (port->opp.config & OFPPC_NO_PACKET_IN) {
+                if (port->opp.config & htonl(OFPPC_NO_PACKET_IN)) {
                     COVERAGE_INC(ofproto_no_packet_in);
                     /* XXX install 'drop' flow entry */
                     ofpbuf_delete(upcall->packet);
@@ -4053,8 +4221,7 @@ ofproto_dp_max_idle(const struct ofproto *ofproto)
                 ds_put_format(&s, " %d:%d", i * BUCKET_WIDTH, buckets[i]);
             }
         }
-        VLOG_INFO("%s: %s (msec:count)",
-                  dpif_name(ofproto->dpif), ds_cstr(&s));
+        VLOG_INFO("%s: %s (msec:count)", ofproto->name, ds_cstr(&s));
         ds_destroy(&s);
     }
 
@@ -4228,16 +4395,30 @@ pick_fallback_dpid(void)
     return eth_addr_to_uint64(ea);
 }
 \f
+static struct ofproto *
+ofproto_lookup(const char *name)
+{
+    struct ofproto *ofproto;
+
+    HMAP_FOR_EACH_WITH_HASH (ofproto, hmap_node, hash_string(name, 0),
+                             &all_ofprotos) {
+        if (!strcmp(ofproto->name, name)) {
+            return ofproto;
+        }
+    }
+    return NULL;
+}
+
 static void
 ofproto_unixctl_list(struct unixctl_conn *conn, const char *arg OVS_UNUSED,
                      void *aux OVS_UNUSED)
 {
-    const struct shash_node *node;
+    struct ofproto *ofproto;
     struct ds results;
 
     ds_init(&results);
-    SHASH_FOR_EACH (node, &all_ofprotos) {
-        ds_put_format(&results, "%s\n", node->name);
+    HMAP_FOR_EACH (ofproto, hmap_node, &all_ofprotos) {
+        ds_put_format(&results, "%s\n", ofproto->name);
     }
     unixctl_command_reply(conn, 200, ds_cstr(&results));
     ds_destroy(&results);
@@ -4324,7 +4505,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_,
         goto exit;
     }
 
-    ofproto = shash_find_data(&all_ofprotos, dpname);
+    ofproto = ofproto_lookup(dpname);
     if (!ofproto) {
         unixctl_command_reply(conn, 501, "Unknown ofproto (use ofproto/list "
                               "for help)");
@@ -4431,7 +4612,7 @@ default_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet,
     /* Determine output port. */
     dst_mac = mac_learning_lookup(ofproto->ml, flow->dl_dst, 0, tags);
     if (!dst_mac) {
-        flood_packets(ofproto, flow->in_port, OFPPC_NO_FLOOD,
+        flood_packets(ofproto, flow->in_port, htonl(OFPPC_NO_FLOOD),
                       nf_output_iface, odp_actions);
     } else {
         int out_port = dst_mac->port.i;