treewide: Remove trailing whitespace
[sliver-openvswitch.git] / lib / dpif.c
index 649c246..01e905d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "ofpbuf.h"
 #include "packets.h"
 #include "poll-loop.h"
+#include "shash.h"
 #include "svec.h"
 #include "util.h"
 #include "valgrind.h"
-
 #include "vlog.h"
-#define THIS_MODULE VLM_dpif
 
-static const struct dpif_class *dpif_classes[] = {
+VLOG_DEFINE_THIS_MODULE(dpif)
+
+static const struct dpif_class *base_dpif_classes[] = {
+#ifdef HAVE_NETLINK
     &dpif_linux_class,
+#endif
     &dpif_netdev_class,
 };
-enum { N_DPIF_CLASSES = ARRAY_SIZE(dpif_classes) };
+
+struct registered_dpif_class {
+    struct dpif_class dpif_class;
+    int refcount;
+};
+static struct shash dpif_classes = SHASH_INITIALIZER(&dpif_classes);
 
 /* Rate limit for individual messages going to or from the datapath, output at
  * DBG level.  This is very high because, if these are enabled, it is because
@@ -52,7 +60,7 @@ enum { N_DPIF_CLASSES = ARRAY_SIZE(dpif_classes) };
 static struct vlog_rate_limit dpmsg_rl = VLOG_RATE_LIMIT_INIT(600, 600);
 
 /* Not really much point in logging many dpif errors. */
-static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
+static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);
 
 static void log_operation(const struct dpif *, const char *operation,
                           int error);
@@ -63,6 +71,21 @@ static void log_flow_put(struct dpif *, int error,
 static bool should_log_flow_message(int error);
 static void check_rw_odp_flow(struct odp_flow *);
 
+static void
+dp_initialize(void)
+{
+    static int status = -1;
+
+    if (status < 0) {
+        int i;
+
+        status = 0;
+        for (i = 0; i < ARRAY_SIZE(base_dpif_classes); i++) {
+            dp_register_provider(base_dpif_classes[i]);
+        }
+    }
+}
+
 /* Performs periodic work needed by all the various kinds of dpifs.
  *
  * If your program opens any dpifs, it must call both this function and
@@ -70,11 +93,11 @@ static void check_rw_odp_flow(struct odp_flow *);
 void
 dp_run(void)
 {
-    int i;
-    for (i = 0; i < N_DPIF_CLASSES; i++) {
-        const struct dpif_class *class = dpif_classes[i];
-        if (class->run) {
-            class->run();
+    struct shash_node *node;
+    SHASH_FOR_EACH(node, &dpif_classes) {
+        const struct registered_dpif_class *registered_class = node->data;
+        if (registered_class->dpif_class.run) {
+            registered_class->dpif_class.run();
         }
     }
 }
@@ -86,94 +109,208 @@ dp_run(void)
 void
 dp_wait(void)
 {
-    int i;
-    for (i = 0; i < N_DPIF_CLASSES; i++) {
-        const struct dpif_class *class = dpif_classes[i];
-        if (class->wait) {
-            class->wait();
+    struct shash_node *node;
+    SHASH_FOR_EACH(node, &dpif_classes) {
+        const struct registered_dpif_class *registered_class = node->data;
+        if (registered_class->dpif_class.wait) {
+            registered_class->dpif_class.wait();
         }
     }
 }
 
-/* Clears 'all_dps' and enumerates the names of all known created datapaths, 
- * where possible, into it.  The caller must first initialize 'all_dps'.
- * Returns 0 if successful, otherwise a positive errno value.
+/* Registers a new datapath provider.  After successful registration, new
+ * datapaths of that type can be opened using dpif_open(). */
+int
+dp_register_provider(const struct dpif_class *new_class)
+{
+    struct registered_dpif_class *registered_class;
+
+    if (shash_find(&dpif_classes, new_class->type)) {
+        VLOG_WARN("attempted to register duplicate datapath provider: %s",
+                  new_class->type);
+        return EEXIST;
+    }
+
+    registered_class = xmalloc(sizeof *registered_class);
+    memcpy(&registered_class->dpif_class, new_class,
+           sizeof registered_class->dpif_class);
+    registered_class->refcount = 0;
+
+    shash_add(&dpif_classes, new_class->type, registered_class);
+
+    return 0;
+}
+
+/* Unregisters a datapath provider.  'type' must have been previously
+ * registered and not currently be in use by any dpifs.  After unregistration
+ * new datapaths of that type cannot be opened using dpif_open(). */
+int
+dp_unregister_provider(const char *type)
+{
+    struct shash_node *node;
+    struct registered_dpif_class *registered_class;
+
+    node = shash_find(&dpif_classes, type);
+    if (!node) {
+        VLOG_WARN("attempted to unregister a datapath provider that is not "
+                  "registered: %s", type);
+        return EAFNOSUPPORT;
+    }
+
+    registered_class = node->data;
+    if (registered_class->refcount) {
+        VLOG_WARN("attempted to unregister in use datapath provider: %s", type);
+        return EBUSY;
+    }
+
+    shash_delete(&dpif_classes, node);
+    free(registered_class);
+
+    return 0;
+}
+
+/* Clears 'types' and enumerates the types of all currently registered datapath
+ * providers into it.  The caller must first initialize the svec. */
+void
+dp_enumerate_types(struct svec *types)
+{
+    struct shash_node *node;
+
+    dp_initialize();
+    svec_clear(types);
+
+    SHASH_FOR_EACH(node, &dpif_classes) {
+        const struct registered_dpif_class *registered_class = node->data;
+        svec_add(types, registered_class->dpif_class.type);
+    }
+}
+
+/* Clears 'names' and enumerates the names of all known created datapaths with
+ * the given 'type'.  The caller must first initialize the svec. Returns 0 if
+ * successful, otherwise a positive errno value.
  *
  * Some kinds of datapaths might not be practically enumerable.  This is not
  * considered an error. */
 int
-dp_enumerate(struct svec *all_dps)
+dp_enumerate_names(const char *type, struct svec *names)
 {
+    const struct registered_dpif_class *registered_class;
+    const struct dpif_class *dpif_class;
     int error;
-    int i;
-
-    svec_clear(all_dps);
-    error = 0;
-    for (i = 0; i < N_DPIF_CLASSES; i++) {
-        const struct dpif_class *class = dpif_classes[i];
-        int retval = class->enumerate ? class->enumerate(all_dps) : 0;
-        if (retval) {
-            VLOG_WARN("failed to enumerate %s datapaths: %s",
-                      class->name, strerror(retval));
-            if (!error) {
-                error = retval;
-            }
-        }
+
+    dp_initialize();
+    svec_clear(names);
+
+    registered_class = shash_find_data(&dpif_classes, type);
+    if (!registered_class) {
+        VLOG_WARN("could not enumerate unknown type: %s", type);
+        return EAFNOSUPPORT;
     }
+
+    dpif_class = &registered_class->dpif_class;
+    error = dpif_class->enumerate ? dpif_class->enumerate(names) : 0;
+
+    if (error) {
+        VLOG_WARN("failed to enumerate %s datapaths: %s", dpif_class->type,
+                   strerror(error));
+    }
+
     return error;
 }
 
+/* Parses 'datapath name', which is of the form type@name into its
+ * component pieces.  'name' and 'type' must be freed by the caller. */
+void
+dp_parse_name(const char *datapath_name_, char **name, char **type)
+{
+    char *datapath_name = xstrdup(datapath_name_);
+    char *separator;
+
+    separator = strchr(datapath_name, '@');
+    if (separator) {
+        *separator = '\0';
+        *type = datapath_name;
+        *name = xstrdup(separator + 1);
+    } else {
+        *name = datapath_name;
+        *type = NULL;
+    }
+}
+
 static int
-do_open(const char *name_, bool create, struct dpif **dpifp)
+do_open(const char *name, const char *type, bool create, struct dpif **dpifp)
 {
-    char *name = xstrdup(name_);
-    char *prefix, *suffix, *colon;
     struct dpif *dpif = NULL;
     int error;
-    int i;
+    struct registered_dpif_class *registered_class;
 
-    colon = strchr(name, ':');
-    if (colon) {
-        *colon = '\0';
-        prefix = name;
-        suffix = colon + 1;
-    } else {
-        prefix = "";
-        suffix = name;
+    dp_initialize();
+
+    if (!type || *type == '\0') {
+        type = "system";
     }
 
-    for (i = 0; i < N_DPIF_CLASSES; i++) {
-        const struct dpif_class *class = dpif_classes[i];
-        if (!strcmp(prefix, class->prefix)) {
-            error = class->open(name_, suffix, create, &dpif);
-            goto exit;
-        }
+    registered_class = shash_find_data(&dpif_classes, type);
+    if (!registered_class) {
+        VLOG_WARN("could not create datapath %s of unknown type %s", name,
+                  type);
+        error = EAFNOSUPPORT;
+        goto exit;
+    }
+
+    error = registered_class->dpif_class.open(name, type, create, &dpif);
+    if (!error) {
+        registered_class->refcount++;
     }
-    error = EAFNOSUPPORT;
 
 exit:
     *dpifp = error ? NULL : dpif;
     return error;
 }
 
-/* Tries to open an existing datapath named 'name'.  Will fail if no datapath
- * named 'name' exists.  Returns 0 if successful, otherwise a positive errno
- * value.  On success stores a pointer to the datapath in '*dpifp', otherwise a
- * null pointer. */
+/* Tries to open an existing datapath named 'name' and type 'type'.  Will fail
+ * if no datapath with 'name' and 'type' exists.  'type' may be either NULL or
+ * the empty string to specify the default system type.  Returns 0 if
+ * successful, otherwise a positive errno value.  On success stores a pointer
+ * to the datapath in '*dpifp', otherwise a null pointer. */
+int
+dpif_open(const char *name, const char *type, struct dpif **dpifp)
+{
+    return do_open(name, type, false, dpifp);
+}
+
+/* Tries to create and open a new datapath with the given 'name' and 'type'.
+ * 'type' may be either NULL or the empty string to specify the default system
+ * type.  Will fail if a datapath with 'name' and 'type' already exists.
+ * Returns 0 if successful, otherwise a positive errno value.  On success
+ * stores a pointer to the datapath in '*dpifp', otherwise a null pointer. */
 int
-dpif_open(const char *name, struct dpif **dpifp)
+dpif_create(const char *name, const char *type, struct dpif **dpifp)
 {
-    return do_open(name, false, dpifp);
+    return do_open(name, type, true, dpifp);
 }
 
-/* Tries to create and open a new datapath with the given 'name'.  Will fail if
- * a datapath named 'name' already exists.  Returns 0 if successful, otherwise
- * a positive errno value.  On success stores a pointer to the datapath in
- * '*dpifp', otherwise a null pointer.*/
+/* Tries to open a datapath with the given 'name' and 'type', creating it if it
+ * does not exist.  'type' may be either NULL or the empty string to specify
+ * the default system type.  Returns 0 if successful, otherwise a positive
+ * errno value. On success stores a pointer to the datapath in '*dpifp',
+ * otherwise a null pointer. */
 int
-dpif_create(const char *name, struct dpif **dpifp)
+dpif_create_and_open(const char *name, const char *type, struct dpif **dpifp)
 {
-    return do_open(name, true, dpifp);
+    int error;
+
+    error = dpif_create(name, type, dpifp);
+    if (error == EEXIST || error == EBUSY) {
+        error = dpif_open(name, type, dpifp);
+        if (error) {
+            VLOG_WARN("datapath %s already exists but cannot be opened: %s",
+                      name, strerror(error));
+        }
+    } else if (error) {
+        VLOG_WARN("failed to create datapath %s: %s", name, strerror(error));
+    }
+    return error;
 }
 
 /* Closes and frees the connection to 'dpif'.  Does not destroy the datapath
@@ -182,17 +319,32 @@ void
 dpif_close(struct dpif *dpif)
 {
     if (dpif) {
-        char *name = dpif->name;
-        dpif->class->close(dpif);
-        free(name);
+        struct registered_dpif_class *registered_class;
+
+        registered_class = shash_find_data(&dpif_classes,
+                dpif->dpif_class->type);
+        assert(registered_class);
+        assert(registered_class->refcount);
+
+        registered_class->refcount--;
+        dpif_uninit(dpif, true);
     }
 }
 
-/* Returns the name of datapath 'dpif' (for use in log messages). */
+/* Returns the name of datapath 'dpif' prefixed with the type
+ * (for use in log messages). */
 const char *
 dpif_name(const struct dpif *dpif)
 {
-    return dpif->name;
+    return dpif->full_name;
+}
+
+/* Returns the name of datapath 'dpif' without the type
+ * (for use in device names). */
+const char *
+dpif_base_name(const struct dpif *dpif)
+{
+    return dpif->base_name;
 }
 
 /* Enumerates all names that may be used to open 'dpif' into 'all_names'.  The
@@ -207,8 +359,8 @@ dpif_name(const struct dpif *dpif)
 int
 dpif_get_all_names(const struct dpif *dpif, struct svec *all_names)
 {
-    if (dpif->class->get_all_names) {
-        int error = dpif->class->get_all_names(dpif, all_names);
+    if (dpif->dpif_class->get_all_names) {
+        int error = dpif->dpif_class->get_all_names(dpif, all_names);
         if (error) {
             VLOG_WARN_RL(&error_rl,
                          "failed to retrieve names for datpath %s: %s",
@@ -216,7 +368,7 @@ dpif_get_all_names(const struct dpif *dpif, struct svec *all_names)
         }
         return error;
     } else {
-        svec_add(all_names, dpif_name(dpif));
+        svec_add(all_names, dpif_base_name(dpif));
         return 0;
     }
 }
@@ -231,7 +383,7 @@ dpif_delete(struct dpif *dpif)
 
     COVERAGE_INC(dpif_destroy);
 
-    error = dpif->class->delete(dpif);
+    error = dpif->dpif_class->destroy(dpif);
     log_operation(dpif, "delete", error);
     return error;
 }
@@ -241,7 +393,7 @@ dpif_delete(struct dpif *dpif)
 int
 dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats)
 {
-    int error = dpif->class->get_stats(dpif, stats);
+    int error = dpif->dpif_class->get_stats(dpif, stats);
     if (error) {
         memset(stats, 0, sizeof *stats);
     }
@@ -257,7 +409,7 @@ dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats)
 int
 dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags)
 {
-    int error = dpif->class->get_drop_frags(dpif, drop_frags);
+    int error = dpif->dpif_class->get_drop_frags(dpif, drop_frags);
     if (error) {
         *drop_frags = false;
     }
@@ -271,7 +423,7 @@ dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags)
 int
 dpif_set_drop_frags(struct dpif *dpif, bool drop_frags)
 {
-    int error = dpif->class->set_drop_frags(dpif, drop_frags);
+    int error = dpif->dpif_class->set_drop_frags(dpif, drop_frags);
     log_operation(dpif, "set_drop_frags", error);
     return error;
 }
@@ -290,7 +442,7 @@ dpif_port_add(struct dpif *dpif, const char *devname, uint16_t flags,
 
     COVERAGE_INC(dpif_port_add);
 
-    error = dpif->class->port_add(dpif, devname, flags, &port_no);
+    error = dpif->dpif_class->port_add(dpif, devname, flags, &port_no);
     if (!error) {
         VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16,
                     dpif_name(dpif), devname, port_no);
@@ -314,7 +466,7 @@ dpif_port_del(struct dpif *dpif, uint16_t port_no)
 
     COVERAGE_INC(dpif_port_del);
 
-    error = dpif->class->port_del(dpif, port_no);
+    error = dpif->dpif_class->port_del(dpif, port_no);
     log_operation(dpif, "port_del", error);
     return error;
 }
@@ -326,7 +478,7 @@ int
 dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
                           struct odp_port *port)
 {
-    int error = dpif->class->port_query_by_number(dpif, port_no, port);
+    int error = dpif->dpif_class->port_query_by_number(dpif, port_no, port);
     if (!error) {
         VLOG_DBG_RL(&dpmsg_rl, "%s: port %"PRIu16" is device %s",
                     dpif_name(dpif), port_no, port->devname);
@@ -345,7 +497,7 @@ int
 dpif_port_query_by_name(const struct dpif *dpif, const char *devname,
                         struct odp_port *port)
 {
-    int error = dpif->class->port_query_by_name(dpif, devname, port);
+    int error = dpif->dpif_class->port_query_by_name(dpif, devname, port);
     if (!error) {
         VLOG_DBG_RL(&dpmsg_rl, "%s: device %s is on port %"PRIu16,
                     dpif_name(dpif), devname, port->port);
@@ -410,7 +562,7 @@ dpif_port_list(const struct dpif *dpif,
         }
 
         ports = xcalloc(stats.n_ports, sizeof *ports);
-        retval = dpif->class->port_list(dpif, ports, stats.n_ports);
+        retval = dpif->dpif_class->port_list(dpif, ports, stats.n_ports);
         if (retval < 0) {
             /* Hard error. */
             error = -retval;
@@ -458,7 +610,7 @@ exit:
 int
 dpif_port_poll(const struct dpif *dpif, char **devnamep)
 {
-    int error = dpif->class->port_poll(dpif, devnamep);
+    int error = dpif->dpif_class->port_poll(dpif, devnamep);
     if (error) {
         *devnamep = NULL;
     }
@@ -470,7 +622,7 @@ dpif_port_poll(const struct dpif *dpif, char **devnamep)
 void
 dpif_port_poll_wait(const struct dpif *dpif)
 {
-    dpif->class->port_poll_wait(dpif);
+    dpif->dpif_class->port_poll_wait(dpif);
 }
 
 /* Retrieves a list of the port numbers in port group 'group' in 'dpif'.
@@ -491,8 +643,8 @@ dpif_port_group_get(const struct dpif *dpif, uint16_t group,
     *ports = NULL;
     *n_ports = 0;
     for (;;) {
-        int retval = dpif->class->port_group_get(dpif, group,
-                                                 *ports, *n_ports);
+        int retval = dpif->dpif_class->port_group_get(dpif, group,
+                                                      *ports, *n_ports);
         if (retval < 0) {
             /* Hard error. */
             error = -retval;
@@ -530,7 +682,7 @@ dpif_port_group_set(struct dpif *dpif, uint16_t group,
 
     COVERAGE_INC(dpif_port_group_set);
 
-    error = dpif->class->port_group_set(dpif, group, ports, n_ports);
+    error = dpif->dpif_class->port_group_set(dpif, group, ports, n_ports);
     log_operation(dpif, "port_group_set", error);
     return error;
 }
@@ -544,7 +696,7 @@ dpif_flow_flush(struct dpif *dpif)
 
     COVERAGE_INC(dpif_flow_flush);
 
-    error = dpif->class->flow_flush(dpif);
+    error = dpif->dpif_class->flow_flush(dpif);
     log_operation(dpif, "flow_flush", error);
     return error;
 }
@@ -570,10 +722,15 @@ dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow)
     COVERAGE_INC(dpif_flow_get);
 
     check_rw_odp_flow(flow);
-    error = dpif->class->flow_get(dpif, flow, 1);
+    error = dpif->dpif_class->flow_get(dpif, flow, 1);
     if (!error) {
         error = flow->stats.error;
     }
+    if (error) {
+        /* Make the results predictable on error. */
+        memset(&flow->stats, 0, sizeof flow->stats);
+        flow->n_actions = 0;
+    }
     if (should_log_flow_message(error)) {
         log_flow_operation(dpif, "flow_get", error, flow);
     }
@@ -620,7 +777,7 @@ dpif_flow_get_multiple(const struct dpif *dpif,
         check_rw_odp_flow(&flows[i]);
     }
 
-    error = dpif->class->flow_get(dpif, flows, n);
+    error = dpif->dpif_class->flow_get(dpif, flows, n);
     log_operation(dpif, "flow_get_multiple", error);
     return error;
 }
@@ -648,7 +805,7 @@ dpif_flow_put(struct dpif *dpif, struct odp_flow_put *put)
 
     COVERAGE_INC(dpif_flow_put);
 
-    error = dpif->class->flow_put(dpif, put);
+    error = dpif->dpif_class->flow_put(dpif, put);
     if (should_log_flow_message(error)) {
         log_flow_put(dpif, error, put);
     }
@@ -670,7 +827,7 @@ dpif_flow_del(struct dpif *dpif, struct odp_flow *flow)
     check_rw_odp_flow(flow);
     memset(&flow->stats, 0, sizeof flow->stats);
 
-    error = dpif->class->flow_del(dpif, flow);
+    error = dpif->dpif_class->flow_del(dpif, flow);
     if (should_log_flow_message(error)) {
         log_flow_operation(dpif, "delete flow", error, flow);
     }
@@ -699,7 +856,7 @@ dpif_flow_list(const struct dpif *dpif, struct odp_flow flows[], size_t n,
             flows[i].n_actions = 0;
         }
     }
-    retval = dpif->class->flow_list(dpif, flows, n);
+    retval = dpif->dpif_class->flow_list(dpif, flows, n);
     if (retval < 0) {
         *n_out = 0;
         VLOG_WARN_RL(&error_rl, "%s: flow list failed (%s)",
@@ -776,7 +933,8 @@ dpif_execute(struct dpif *dpif, uint16_t in_port,
 
     COVERAGE_INC(dpif_execute);
     if (n_actions > 0) {
-        error = dpif->class->execute(dpif, in_port, actions, n_actions, buf);
+        error = dpif->dpif_class->execute(dpif, in_port, actions,
+                                          n_actions, buf);
     } else {
         error = 0;
     }
@@ -803,7 +961,7 @@ dpif_execute(struct dpif *dpif, uint16_t in_port,
 int
 dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
 {
-    int error = dpif->class->recv_get_mask(dpif, listen_mask);
+    int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask);
     if (error) {
         *listen_mask = 0;
     }
@@ -817,14 +975,50 @@ dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
 int
 dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
 {
-    int error = dpif->class->recv_set_mask(dpif, listen_mask);
+    int error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
     log_operation(dpif, "recv_set_mask", error);
     return error;
 }
 
+/* Retrieve the sFlow sampling probability.  '*probability' is expressed as the
+ * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is
+ * the probability of sampling a given packet.
+ *
+ * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
+ * indicates that 'dpif' does not support sFlow sampling. */
+int
+dpif_get_sflow_probability(const struct dpif *dpif, uint32_t *probability)
+{
+    int error = (dpif->dpif_class->get_sflow_probability
+                 ? dpif->dpif_class->get_sflow_probability(dpif, probability)
+                 : EOPNOTSUPP);
+    if (error) {
+        *probability = 0;
+    }
+    log_operation(dpif, "get_sflow_probability", error);
+    return error;
+}
+
+/* Set the sFlow sampling probability.  'probability' is expressed as the
+ * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is
+ * the probability of sampling a given packet.
+ *
+ * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
+ * indicates that 'dpif' does not support sFlow sampling. */
+int
+dpif_set_sflow_probability(struct dpif *dpif, uint32_t probability)
+{
+    int error = (dpif->dpif_class->set_sflow_probability
+                 ? dpif->dpif_class->set_sflow_probability(dpif, probability)
+                 : EOPNOTSUPP);
+    log_operation(dpif, "set_sflow_probability", error);
+    return error;
+}
+
 /* Attempts to receive a message from 'dpif'.  If successful, stores the
  * message into '*packetp'.  The message, if one is received, will begin with
- * 'struct odp_msg' as a header.  Only messages of the types selected with
+ * 'struct odp_msg' as a header, and will have at least DPIF_RECV_MSG_PADDING
+ * bytes of headroom.  Only messages of the types selected with
  * dpif_set_listen_mask() will ordinarily be received (but if a message type is
  * enabled and then later disabled, some stragglers might pop up).
  *
@@ -833,10 +1027,12 @@ dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
 int
 dpif_recv(struct dpif *dpif, struct ofpbuf **packetp)
 {
-    int error = dpif->class->recv(dpif, packetp);
+    int error = dpif->dpif_class->recv(dpif, packetp);
     if (!error) {
+        struct ofpbuf *buf = *packetp;
+
+        assert(ofpbuf_headroom(buf) >= DPIF_RECV_MSG_PADDING);
         if (VLOG_IS_DBG_ENABLED()) {
-            struct ofpbuf *buf = *packetp;
             struct odp_msg *msg = buf->data;
             void *payload = msg + 1;
             size_t payload_len = buf->size - sizeof *msg;
@@ -845,6 +1041,7 @@ dpif_recv(struct dpif *dpif, struct ofpbuf **packetp)
                         "%zu on port %"PRIu16": %s", dpif_name(dpif),
                         (msg->type == _ODPL_MISS_NR ? "miss"
                          : msg->type == _ODPL_ACTION_NR ? "action"
+                         : msg->type == _ODPL_SFLOW_NR ? "sFlow"
                          : "<unknown>"),
                         payload_len, msg->port, s);
             free(s);
@@ -871,7 +1068,7 @@ dpif_recv_purge(struct dpif *dpif)
         return error;
     }
 
-    for (i = 0; i < stats.max_miss_queue + stats.max_action_queue; i++) {
+    for (i = 0; i < stats.max_miss_queue + stats.max_action_queue + stats.max_sflow_queue; i++) {
         struct ofpbuf *buf;
         error = dpif_recv(dpif, &buf);
         if (error) {
@@ -887,7 +1084,7 @@ dpif_recv_purge(struct dpif *dpif)
 void
 dpif_recv_wait(struct dpif *dpif)
 {
-    dpif->class->recv_wait(dpif);
+    dpif->dpif_class->recv_wait(dpif);
 }
 
 /* Obtains the NetFlow engine type and engine ID for 'dpif' into '*engine_type'
@@ -899,16 +1096,57 @@ dpif_get_netflow_ids(const struct dpif *dpif,
     *engine_type = dpif->netflow_engine_type;
     *engine_id = dpif->netflow_engine_id;
 }
+
+/* Translates OpenFlow queue ID 'queue_id' (in host byte order) into a priority
+ * value for use in the ODPAT_SET_PRIORITY action.  On success, returns 0 and
+ * stores the priority into '*priority'.  On failure, returns a positive errno
+ * value and stores 0 into '*priority'. */
+int
+dpif_queue_to_priority(const struct dpif *dpif, uint32_t queue_id,
+                       uint32_t *priority)
+{
+    int error = (dpif->dpif_class->queue_to_priority
+                 ? dpif->dpif_class->queue_to_priority(dpif, queue_id,
+                                                       priority)
+                 : EOPNOTSUPP);
+    if (error) {
+        *priority = 0;
+    }
+    log_operation(dpif, "queue_to_priority", error);
+    return error;
+}
 \f
 void
-dpif_init(struct dpif *dpif, const struct dpif_class *class, const char *name,
+dpif_init(struct dpif *dpif, const struct dpif_class *dpif_class,
+          const char *name,
           uint8_t netflow_engine_type, uint8_t netflow_engine_id)
 {
-    dpif->class = class;
-    dpif->name = xstrdup(name);
+    dpif->dpif_class = dpif_class;
+    dpif->base_name = xstrdup(name);
+    dpif->full_name = xasprintf("%s@%s", dpif_class->type, name);
     dpif->netflow_engine_type = netflow_engine_type;
     dpif->netflow_engine_id = netflow_engine_id;
 }
+
+/* Undoes the results of initialization.
+ *
+ * Normally this function only needs to be called from dpif_close().
+ * However, it may be called by providers due to an error on opening
+ * that occurs after initialization.  It this case dpif_close() would
+ * never be called. */
+void
+dpif_uninit(struct dpif *dpif, bool close)
+{
+    char *base_name = dpif->base_name;
+    char *full_name = dpif->full_name;
+
+    if (close) {
+        dpif->dpif_class->close(dpif);
+    }
+
+    free(base_name);
+    free(full_name);
+}
 \f
 static void
 log_operation(const struct dpif *dpif, const char *operation, int error)