datapath: Convert kernel priority actions into match/set.
[sliver-openvswitch.git] / lib / dpif.c
index b7e2b38..cc6e805 100644 (file)
@@ -36,7 +36,7 @@
 #include "packets.h"
 #include "poll-loop.h"
 #include "shash.h"
-#include "svec.h"
+#include "sset.h"
 #include "timeval.h"
 #include "util.h"
 #include "valgrind.h"
@@ -101,38 +101,6 @@ dp_initialize(void)
     }
 }
 
-/* Performs periodic work needed by all the various kinds of dpifs.
- *
- * If your program opens any dpifs, it must call both this function and
- * netdev_run() within its main poll loop. */
-void
-dp_run(void)
-{
-    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();
-        }
-    }
-}
-
-/* Arranges for poll_block() to wake up when dp_run() needs to be called.
- *
- * If your program opens any dpifs, it must call both this function and
- * netdev_wait() within its main poll loop. */
-void
-dp_wait(void)
-{
-    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();
-        }
-    }
-}
-
 /* Registers a new datapath provider.  After successful registration, new
  * datapaths of that type can be opened using dpif_open(). */
 int
@@ -184,36 +152,36 @@ dp_unregister_provider(const char *type)
 }
 
 /* Clears 'types' and enumerates the types of all currently registered datapath
- * providers into it.  The caller must first initialize the svec. */
+ * providers into it.  The caller must first initialize the sset. */
 void
-dp_enumerate_types(struct svec *types)
+dp_enumerate_types(struct sset *types)
 {
     struct shash_node *node;
 
     dp_initialize();
-    svec_clear(types);
+    sset_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);
+        sset_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
+ * the given 'type'.  The caller must first initialize the sset.  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_names(const char *type, struct svec *names)
+dp_enumerate_names(const char *type, struct sset *names)
 {
     const struct registered_dpif_class *registered_class;
     const struct dpif_class *dpif_class;
     int error;
 
     dp_initialize();
-    svec_clear(names);
+    sset_clear(names);
 
     registered_class = shash_find_data(&dpif_classes, type);
     if (!registered_class) {
@@ -232,8 +200,10 @@ dp_enumerate_names(const char *type, struct svec *names)
     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. */
+/* Parses 'datapath_name_', which is of the form [type@]name into its
+ * component pieces.  'name' and 'type' must be freed by the caller.
+ *
+ * The returned 'type' is normalized, as if by dpif_normalize_type(). */
 void
 dp_parse_name(const char *datapath_name_, char **name, char **type)
 {
@@ -244,10 +214,10 @@ dp_parse_name(const char *datapath_name_, char **name, char **type)
     if (separator) {
         *separator = '\0';
         *type = datapath_name;
-        *name = xstrdup(separator + 1);
+        *name = xstrdup(dpif_normalize_type(separator + 1));
     } else {
         *name = datapath_name;
-        *type = NULL;
+        *type = xstrdup(dpif_normalize_type(NULL));
     }
 }
 
@@ -260,9 +230,7 @@ do_open(const char *name, const char *type, bool create, struct dpif **dpifp)
 
     dp_initialize();
 
-    if (!type || *type == '\0') {
-        type = "system";
-    }
+    type = dpif_normalize_type(type);
 
     registered_class = shash_find_data(&dpif_classes, type);
     if (!registered_class) {
@@ -347,6 +315,25 @@ dpif_close(struct dpif *dpif)
     }
 }
 
+/* Performs periodic work needed by 'dpif'. */
+void
+dpif_run(struct dpif *dpif)
+{
+    if (dpif->dpif_class->run) {
+        dpif->dpif_class->run(dpif);
+    }
+}
+
+/* Arranges for poll_block() to wake up when dp_run() needs to be called for
+ * 'dpif'. */
+void
+dpif_wait(struct dpif *dpif)
+{
+    if (dpif->dpif_class->wait) {
+        dpif->dpif_class->wait(dpif);
+    }
+}
+
 /* Returns the name of datapath 'dpif' prefixed with the type
  * (for use in log messages). */
 const char *
@@ -363,33 +350,16 @@ 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
- * Linux datapath, for example, supports opening a datapath both by number,
- * e.g. "dp0", and by the name of the datapath's local port.  For some
- * datapaths, this might be an infinite set (e.g. in a file name, slashes may
- * be duplicated any number of times), in which case only the names most likely
- * to be used will be enumerated.
+/* Returns the fully spelled out name for the given datapath 'type'.
  *
- * The caller must already have initialized 'all_names'.  Any existing names in
- * 'all_names' will not be disturbed. */
-int
-dpif_get_all_names(const struct dpif *dpif, struct svec *all_names)
+ * Normalized type string can be compared with strcmp().  Unnormalized type
+ * string might be the same even if they have different spellings. */
+const char *
+dpif_normalize_type(const char *type)
 {
-    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",
-                         dpif_name(dpif), strerror(error));
-        }
-        return error;
-    } else {
-        svec_add(all_names, dpif_base_name(dpif));
-        return 0;
-    }
+    return type && type[0] ? type : "system";
 }
 
-
 /* Destroys the datapath that 'dpif' is connected to, first removing all of its
  * ports.  After calling this function, it does not make sense to pass 'dpif'
  * to any functions other than dpif_name() or dpif_close(). */
@@ -408,7 +378,7 @@ dpif_delete(struct dpif *dpif)
 /* Retrieves statistics for 'dpif' into 'stats'.  Returns 0 if successful,
  * otherwise a positive errno value. */
 int
-dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats)
+dpif_get_dp_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
 {
     int error = dpif->dpif_class->get_stats(dpif, stats);
     if (error) {
@@ -418,33 +388,6 @@ dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats)
     return error;
 }
 
-/* Retrieves the current IP fragment handling policy for 'dpif' into
- * '*drop_frags': true indicates that fragments are dropped, false indicates
- * that fragments are treated in the same way as other IP packets (except that
- * the L4 header cannot be read).  Returns 0 if successful, otherwise a
- * positive errno value. */
-int
-dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags)
-{
-    int error = dpif->dpif_class->get_drop_frags(dpif, drop_frags);
-    if (error) {
-        *drop_frags = false;
-    }
-    log_operation(dpif, "get_drop_frags", error);
-    return error;
-}
-
-/* Changes 'dpif''s treatment of IP fragments to 'drop_frags', whose meaning is
- * the same as for the get_drop_frags member function.  Returns 0 if
- * successful, otherwise a positive errno value. */
-int
-dpif_set_drop_frags(struct dpif *dpif, bool drop_frags)
-{
-    int error = dpif->dpif_class->set_drop_frags(dpif, drop_frags);
-    log_operation(dpif, "set_drop_frags", error);
-    return error;
-}
-
 /* Attempts to add 'netdev' as a port on 'dpif'.  If successful, returns 0 and
  * sets '*port_nop' to the new port's port number (if 'port_nop' is non-null).
  * On failure, returns a positive errno value and sets '*port_nop' to
@@ -552,11 +495,14 @@ dpif_port_query_by_name(const struct dpif *dpif, const char *devname,
     } else {
         memset(port, 0, sizeof *port);
 
-        /* Log level is DBG here because all the current callers are interested
-         * in whether 'dpif' actually has a port 'devname', so that it's not an
-         * issue worth logging if it doesn't. */
-        VLOG_DBG_RL(&error_rl, "%s: failed to query port %s: %s",
-                    dpif_name(dpif), devname, strerror(error));
+        /* For ENOENT or ENODEV we use DBG level because the caller is probably
+         * interested in whether 'dpif' actually has a port 'devname', so that
+         * it's not an issue worth logging if it doesn't.  Other errors are
+         * uncommon and more likely to indicate a real problem. */
+        VLOG_RL(&error_rl,
+                error == ENOENT || error == ENODEV ? VLL_DBG : VLL_WARN,
+                "%s: failed to query port %s: %s",
+                dpif_name(dpif), devname, strerror(error));
     }
     return error;
 }
@@ -569,6 +515,23 @@ dpif_get_max_ports(const struct dpif *dpif)
     return dpif->dpif_class->get_max_ports(dpif);
 }
 
+/* Returns the Netlink PID value to supply in OVS_ACTION_ATTR_USERSPACE actions
+ * as the OVS_USERSPACE_ATTR_PID attribute's value, for use in flows whose
+ * packets arrived on port 'port_no'.
+ *
+ * The return value is only meaningful when DPIF_UC_ACTION has been enabled in
+ * the 'dpif''s listen mask.  It is allowed to change when DPIF_UC_ACTION is
+ * disabled and then re-enabled, so a client that does that must be prepared to
+ * update all of the flows that it installed that contain
+ * OVS_ACTION_ATTR_USERSPACE actions. */
+uint32_t
+dpif_port_get_pid(const struct dpif *dpif, uint16_t port_no)
+{
+    return (dpif->dpif_class->port_get_pid
+            ? (dpif->dpif_class->port_get_pid)(dpif, port_no)
+            : 0);
+}
+
 /* Looks up port number 'port_no' in 'dpif'.  On success, returns 0 and copies
  * the port's name into the 'name_size' bytes in 'name', ensuring that the
  * result is null-terminated.  On failure, returns a positive errno value and
@@ -688,6 +651,26 @@ dpif_port_poll_wait(const struct dpif *dpif)
     dpif->dpif_class->port_poll_wait(dpif);
 }
 
+/* Extracts the flow stats for a packet.  The 'flow' and 'packet'
+ * arguments must have been initialized through a call to flow_extract().
+ */
+void
+dpif_flow_stats_extract(const struct flow *flow, struct ofpbuf *packet,
+                        struct dpif_flow_stats *stats)
+{
+    memset(stats, 0, sizeof(*stats));
+
+    if ((flow->dl_type == htons(ETH_TYPE_IP)) && packet->l4) {
+        if ((flow->nw_proto == IPPROTO_TCP) && packet->l7) {
+            struct tcp_header *tcp = packet->l4;
+            stats->tcp_flags = TCP_FLAGS(tcp->tcp_ctl);
+        }
+    }
+
+    stats->n_bytes = packet->size;
+    stats->n_packets = 1;
+}
+
 /* Appends a human-readable representation of 'stats' to 's'. */
 void
 dpif_flow_stats_format(const struct dpif_flow_stats *stats, struct ds *s)
@@ -717,7 +700,7 @@ dpif_flow_flush(struct dpif *dpif)
 }
 
 /* Queries 'dpif' for a flow entry.  The flow is specified by the Netlink
- * attributes with types ODP_KEY_ATTR_* in the 'key_len' bytes starting at
+ * attributes with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at
  * 'key'.
  *
  * Returns 0 if successful.  If no flow matches, returns ENOENT.  On other
@@ -731,7 +714,7 @@ dpif_flow_flush(struct dpif *dpif)
  * If 'stats' is nonnull, then on success it will be updated with the flow's
  * statistics. */
 int
-dpif_flow_get(const struct dpif *dpif, int flags,
+dpif_flow_get(const struct dpif *dpif,
               const struct nlattr *key, size_t key_len,
               struct ofpbuf **actionsp, struct dpif_flow_stats *stats)
 {
@@ -739,8 +722,7 @@ dpif_flow_get(const struct dpif *dpif, int flags,
 
     COVERAGE_INC(dpif_flow_get);
 
-    error = dpif->dpif_class->flow_get(dpif, flags, key, key_len, actionsp,
-                                       stats);
+    error = dpif->dpif_class->flow_get(dpif, key, key_len, actionsp, stats);
     if (error) {
         if (actionsp) {
             *actionsp = NULL;
@@ -767,9 +749,9 @@ dpif_flow_get(const struct dpif *dpif, int flags,
 }
 
 /* Adds or modifies a flow in 'dpif'.  The flow is specified by the Netlink
- * attributes with types ODP_KEY_ATTR_* in the 'key_len' bytes starting at
+ * attributes with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at
  * 'key'.  The associated actions are specified by the Netlink attributes with
- * types ODPAT_* in the 'actions_len' bytes starting at 'actions'.
+ * types OVS_ACTION_ATTR_* in the 'actions_len' bytes starting at 'actions'.
  *
  * - If the flow's key does not exist in 'dpif', then the flow will be added if
  *   'flags' includes DPIF_FP_CREATE.  Otherwise the operation will fail with
@@ -825,7 +807,7 @@ dpif_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
 
 /* Deletes a flow from 'dpif' and returns 0, or returns ENOENT if 'dpif' does
  * not contain such a flow.  The flow is specified by the Netlink attributes
- * with types ODP_KEY_ATTR_* in the 'key_len' bytes starting at 'key'.
+ * with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at 'key'.
  *
  * If the operation succeeds, then 'stats', if nonnull, will be set to the
  * flow's statistics before its deletion. */
@@ -871,11 +853,11 @@ dpif_flow_dump_start(struct dpif_flow_dump *dump, const struct dpif *dpif)
  * completed by calling dpif_flow_dump_done().
  *
  * On success, if 'key' and 'key_len' are nonnull then '*key' and '*key_len'
- * will be set to Netlink attributes with types ODP_KEY_ATTR_* representing the
+ * will be set to Netlink attributes with types OVS_KEY_ATTR_* representing the
  * dumped flow's key.  If 'actions' and 'actions_len' are nonnull then they are
- * set to Netlink attributes with types ODPAT_* representing the dumped flow's
- * actions.  If 'stats' is nonnull then it will be set to the dumped flow's
- * statistics.
+ * set to Netlink attributes with types OVS_ACTION_ATTR_* representing the
+ * dumped flow's actions.  If 'stats' is nonnull then it will be set to the
+ * dumped flow's statistics.
  *
  * All of the returned data is owned by 'dpif', not by the caller, and the
  * caller must not modify or free it.  'dpif' guarantees that it remains
@@ -941,11 +923,15 @@ dpif_flow_dump_done(struct dpif_flow_dump *dump)
 }
 
 /* Causes 'dpif' to perform the 'actions_len' bytes of actions in 'actions' on
- * the Ethernet frame specified in 'packet'.
+ * the Ethernet frame specified in 'packet' taken from the flow specified in
+ * the 'key_len' bytes of 'key'.  ('key' is mostly redundant with 'packet', but
+ * it contains some metadata that cannot be recovered from 'packet', such as
+ * tun_id and in_port.)
  *
  * Returns 0 if successful, otherwise a positive errno value. */
 int
 dpif_execute(struct dpif *dpif,
+             const struct nlattr *key, size_t key_len,
              const struct nlattr *actions, size_t actions_len,
              const struct ofpbuf *buf)
 {
@@ -953,7 +939,8 @@ dpif_execute(struct dpif *dpif,
 
     COVERAGE_INC(dpif_execute);
     if (actions_len > 0) {
-        error = dpif->dpif_class->execute(dpif, actions, actions_len, buf);
+        error = dpif->dpif_class->execute(dpif, key, key_len,
+                                          actions, actions_len, buf);
     } else {
         error = 0;
     }
@@ -974,68 +961,108 @@ dpif_execute(struct dpif *dpif,
     return error;
 }
 
-/* Retrieves 'dpif''s "listen mask" into '*listen_mask'.  Each ODPL_* bit set
- * in '*listen_mask' indicates that dpif_recv() will receive messages of that
- * type.  Returns 0 if successful, otherwise a positive errno value. */
-int
-dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
+/* Executes each of the 'n_ops' operations in 'ops' on 'dpif', in the order in
+ * which they are specified, placing each operation's results in the "output"
+ * members documented in comments.
+ *
+ * This function exists because some datapaths can perform batched operations
+ * faster than individual operations. */
+void
+dpif_operate(struct dpif *dpif, union dpif_op **ops, size_t n_ops)
 {
-    int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask);
-    if (error) {
-        *listen_mask = 0;
+    size_t i;
+
+    if (dpif->dpif_class->operate) {
+        dpif->dpif_class->operate(dpif, ops, n_ops);
+        return;
+    }
+
+    for (i = 0; i < n_ops; i++) {
+        union dpif_op *op = ops[i];
+        struct dpif_flow_put *put;
+        struct dpif_execute *execute;
+
+        switch (op->type) {
+        case DPIF_OP_FLOW_PUT:
+            put = &op->flow_put;
+            put->error = dpif_flow_put(dpif, put->flags,
+                                       put->key, put->key_len,
+                                       put->actions, put->actions_len,
+                                       put->stats);
+            break;
+
+        case DPIF_OP_EXECUTE:
+            execute = &op->execute;
+            execute->error = dpif_execute(dpif, execute->key, execute->key_len,
+                                          execute->actions,
+                                          execute->actions_len,
+                                          execute->packet);
+            break;
+
+        default:
+            NOT_REACHED();
+        }
     }
-    log_operation(dpif, "recv_get_mask", error);
-    return error;
 }
 
-/* Sets 'dpif''s "listen mask" to 'listen_mask'.  Each ODPL_* bit set in
- * '*listen_mask' requests that dpif_recv() receive messages of that type.
- * Returns 0 if successful, otherwise a positive errno value. */
-int
-dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
+
+/* Returns a string that represents 'type', for use in log messages. */
+const char *
+dpif_upcall_type_to_string(enum dpif_upcall_type type)
 {
-    int error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
-    log_operation(dpif, "recv_set_mask", error);
-    return error;
+    switch (type) {
+    case DPIF_UC_MISS: return "miss";
+    case DPIF_UC_ACTION: return "action";
+    case DPIF_N_UC_TYPES: default: return "<unknown>";
+    }
 }
 
-/* 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. */
+static bool OVS_UNUSED
+is_valid_listen_mask(int listen_mask)
+{
+    return !(listen_mask & ~((1u << DPIF_UC_MISS) |
+                             (1u << DPIF_UC_ACTION)));
+}
+
+/* Retrieves 'dpif''s "listen mask" into '*listen_mask'.  A 1-bit of value 2**X
+ * set in '*listen_mask' indicates that dpif_recv() will receive messages of
+ * the type (from "enum dpif_upcall_type") with value X.  Returns 0 if
+ * successful, otherwise a positive errno value. */
 int
-dpif_get_sflow_probability(const struct dpif *dpif, uint32_t *probability)
+dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
 {
-    int error = (dpif->dpif_class->get_sflow_probability
-                 ? dpif->dpif_class->get_sflow_probability(dpif, probability)
-                 : EOPNOTSUPP);
+    int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask);
     if (error) {
-        *probability = 0;
+        *listen_mask = 0;
     }
-    log_operation(dpif, "get_sflow_probability", error);
+    assert(is_valid_listen_mask(*listen_mask));
+    log_operation(dpif, "recv_get_mask", 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.
+/* Sets 'dpif''s "listen mask" to 'listen_mask'.  A 1-bit of value 2**X set in
+ * '*listen_mask' requests that dpif_recv() will receive messages of the type
+ * (from "enum dpif_upcall_type") with value X.  Returns 0 if successful,
+ * otherwise a positive errno value.
  *
- * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
- * indicates that 'dpif' does not support sFlow sampling. */
+ * Turning DPIF_UC_ACTION off and then back on may change the Netlink PID
+ * assignments returned by dpif_port_get_pid().  If the client does this, it
+ * must update all of the flows that have OVS_ACTION_ATTR_USERSPACE actions
+ * using the new PID assignment. */
 int
-dpif_set_sflow_probability(struct dpif *dpif, uint32_t probability)
+dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
 {
-    int error = (dpif->dpif_class->set_sflow_probability
-                 ? dpif->dpif_class->set_sflow_probability(dpif, probability)
-                 : EOPNOTSUPP);
-    log_operation(dpif, "set_sflow_probability", error);
+    int error;
+
+    assert(is_valid_listen_mask(listen_mask));
+
+    error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
+    log_operation(dpif, "recv_set_mask", error);
     return error;
 }
 
 /* Polls for an upcall from 'dpif'.  If successful, stores the upcall into
- * '*upcall'.  Only upcalls of the types selected with the set_listen_mask
+ * '*upcall'.  Only upcalls of the types selected with dpif_recv_set_mask()
  * member function will ordinarily be received (but if a message type is
  * enabled and then later disabled, some stragglers might pop up).
  *
@@ -1052,20 +1079,22 @@ dpif_recv(struct dpif *dpif, struct dpif_upcall *upcall)
 {
     int error = dpif->dpif_class->recv(dpif, upcall);
     if (!error && !VLOG_DROP_DBG(&dpmsg_rl)) {
-        struct flow flow;
-        char *s;
-
-        s = ofp_packet_to_string(upcall->packet->data,
-                                 upcall->packet->size, upcall->packet->size);
-        odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
-
-        VLOG_DBG("%s: %s upcall on port %"PRIu16": %s", dpif_name(dpif),
-                 (upcall->type == _ODPL_MISS_NR ? "miss"
-                  : upcall->type == _ODPL_ACTION_NR ? "action"
-                  : upcall->type == _ODPL_SFLOW_NR ? "sFlow"
-                  : "<unknown>"),
-                 flow.in_port, s);
-        free(s);
+        struct ds flow;
+        char *packet;
+
+        packet = ofp_packet_to_string(upcall->packet->data,
+                                      upcall->packet->size,
+                                      upcall->packet->size);
+
+        ds_init(&flow);
+        odp_flow_key_format(upcall->key, upcall->key_len, &flow);
+
+        VLOG_DBG("%s: %s upcall:\n%s\n%s",
+                 dpif_name(dpif), dpif_upcall_type_to_string(upcall->type),
+                 ds_cstr(&flow), packet);
+
+        ds_destroy(&flow);
+        free(packet);
     }
     return error;
 }
@@ -1100,9 +1129,9 @@ dpif_get_netflow_ids(const struct dpif *dpif,
 }
 
 /* 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'. */
+ * value used for setting packet priority.
+ * 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)