[ovs-dev] [PATCH] dpif-provider: Get rid of redundant operations.

Ben Pfaff blp at nicira.com
Tue Jul 15 23:09:45 UTC 2014


The dpif provider 'operate' call duplicates all of the features available
from the 'flow_put', 'flow_del', and 'execute' calls, yielding redundant
code in providers that support both mechanisms.  This change drops the
latter calls in favor of making every dpif provider support 'operate'.
The result is code that is overall less duplicative.

It might make sense to do the same with flow_get but so far 'operate'
doesn't support flow_get.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 lib/dpif-linux.c    |   64 -------------
 lib/dpif-netdev.c   |   29 +++++-
 lib/dpif-provider.h |   45 +--------
 lib/dpif.c          |  265 ++++++++++++++++++---------------------------------
 lib/dpif.h          |   58 +++++++++--
 5 files changed, 169 insertions(+), 292 deletions(-)

diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 4475731..7bf69cb 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -1104,25 +1104,6 @@ dpif_linux_init_flow_put(struct dpif_linux *dpif, const struct dpif_flow_put *pu
     request->nlmsg_flags = put->flags & DPIF_FP_MODIFY ? 0 : NLM_F_CREATE;
 }
 
-static int
-dpif_linux_flow_put(struct dpif *dpif_, const struct dpif_flow_put *put)
-{
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
-    struct dpif_linux_flow request, reply;
-    struct ofpbuf *buf;
-    int error;
-
-    dpif_linux_init_flow_put(dpif, put, &request);
-    error = dpif_linux_flow_transact(&request,
-                                     put->stats ? &reply : NULL,
-                                     put->stats ? &buf : NULL);
-    if (!error && put->stats) {
-        dpif_linux_flow_get_stats(&reply, put->stats);
-        ofpbuf_delete(buf);
-    }
-    return error;
-}
-
 static void
 dpif_linux_init_flow_del(struct dpif_linux *dpif, const struct dpif_flow_del *del,
                          struct dpif_linux_flow *request)
@@ -1134,25 +1115,6 @@ dpif_linux_init_flow_del(struct dpif_linux *dpif, const struct dpif_flow_del *de
     request->key_len = del->key_len;
 }
 
-static int
-dpif_linux_flow_del(struct dpif *dpif_, const struct dpif_flow_del *del)
-{
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
-    struct dpif_linux_flow request, reply;
-    struct ofpbuf *buf;
-    int error;
-
-    dpif_linux_init_flow_del(dpif, del, &request);
-    error = dpif_linux_flow_transact(&request,
-                                     del->stats ? &reply : NULL,
-                                     del->stats ? &buf : NULL);
-    if (!error && del->stats) {
-        dpif_linux_flow_get_stats(&reply, del->stats);
-        ofpbuf_delete(buf);
-    }
-    return error;
-}
-
 struct dpif_linux_flow_dump {
     struct dpif_flow_dump up;
     struct nl_dump nl_dump;
@@ -1345,29 +1307,6 @@ dpif_linux_encode_execute(int dp_ifindex, const struct dpif_execute *d_exec,
                       d_exec->actions, d_exec->actions_len);
 }
 
-static int
-dpif_linux_execute__(int dp_ifindex, const struct dpif_execute *execute)
-{
-    uint64_t request_stub[1024 / 8];
-    struct ofpbuf request;
-    int error;
-
-    ofpbuf_use_stub(&request, request_stub, sizeof request_stub);
-    dpif_linux_encode_execute(dp_ifindex, execute, &request);
-    error = nl_transact(NETLINK_GENERIC, &request, NULL);
-    ofpbuf_uninit(&request);
-
-    return error;
-}
-
-static int
-dpif_linux_execute(struct dpif *dpif_, struct dpif_execute *execute)
-{
-    const struct dpif_linux *dpif = dpif_linux_cast(dpif_);
-
-    return dpif_linux_execute__(dpif->dp_ifindex, execute);
-}
-
 #define MAX_OPS 50
 
 static void
@@ -1918,15 +1857,12 @@ const struct dpif_class dpif_linux_class = {
     dpif_linux_port_poll,
     dpif_linux_port_poll_wait,
     dpif_linux_flow_get,
-    dpif_linux_flow_put,
-    dpif_linux_flow_del,
     dpif_linux_flow_flush,
     dpif_linux_flow_dump_create,
     dpif_linux_flow_dump_destroy,
     dpif_linux_flow_dump_thread_create,
     dpif_linux_flow_dump_thread_destroy,
     dpif_linux_flow_dump_next,
-    dpif_linux_execute,
     dpif_linux_operate,
     dpif_linux_recv_set,
     dpif_linux_handlers_set,
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 21a4f56..8645c3a 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1562,6 +1562,30 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
 }
 
 static void
+dpif_netdev_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops)
+{
+    size_t i;
+
+    for (i = 0; i < n_ops; i++) {
+        struct dpif_op *op = ops[i];
+
+        switch (op->type) {
+        case DPIF_OP_FLOW_PUT:
+            op->error = dpif_netdev_flow_put(dpif, &op->u.flow_put);
+            break;
+
+        case DPIF_OP_FLOW_DEL:
+            op->error = dpif_netdev_flow_del(dpif, &op->u.flow_del);
+            break;
+
+        case DPIF_OP_EXECUTE:
+            op->error = dpif_netdev_execute(dpif, &op->u.execute);
+            break;
+        }
+    }
+}
+
+static void
 dp_netdev_destroy_all_queues(struct dp_netdev *dp)
     OVS_REQ_WRLOCK(dp->queue_rwlock)
 {
@@ -2382,16 +2406,13 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_port_poll,
     dpif_netdev_port_poll_wait,
     dpif_netdev_flow_get,
-    dpif_netdev_flow_put,
-    dpif_netdev_flow_del,
     dpif_netdev_flow_flush,
     dpif_netdev_flow_dump_create,
     dpif_netdev_flow_dump_destroy,
     dpif_netdev_flow_dump_thread_create,
     dpif_netdev_flow_dump_thread_destroy,
     dpif_netdev_flow_dump_next,
-    dpif_netdev_execute,
-    NULL,                       /* operate */
+    dpif_netdev_operate,
     dpif_netdev_recv_set,
     dpif_netdev_handlers_set,
     dpif_netdev_queue_to_priority,
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 2a765de..403c6fe 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -268,39 +268,6 @@ struct dpif_class {
                     struct nlattr **actionsp, size_t *acts_len,
                     struct dpif_flow_stats *stats);
 
-    /* Adds or modifies a flow in 'dpif'.  The flow is specified by the Netlink
-     * attributes with types OVS_KEY_ATTR_* in the 'put->key_len' bytes
-     * starting at 'put->key'.  The associated actions are specified by the
-     * Netlink attributes with types OVS_ACTION_ATTR_* in the
-     * 'put->actions_len' bytes starting at 'put->actions'.
-     *
-     * - If the flow's key does not exist in 'dpif', then the flow will be
-     *   added if 'put->flags' includes DPIF_FP_CREATE.  Otherwise the
-     *   operation will fail with ENOENT.
-     *
-     *   If the operation succeeds, then 'put->stats', if nonnull, must be
-     *   zeroed.
-     *
-     * - If the flow's key does exist in 'dpif', then the flow's actions will
-     *   be updated if 'put->flags' includes DPIF_FP_MODIFY.  Otherwise the
-     *   operation will fail with EEXIST.  If the flow's actions are updated,
-     *   then its statistics will be zeroed if 'put->flags' includes
-     *   DPIF_FP_ZERO_STATS, and left as-is otherwise.
-     *
-     *   If the operation succeeds, then 'put->stats', if nonnull, must be set
-     *   to the flow's statistics before the update.
-     */
-    int (*flow_put)(struct dpif *dpif, const struct dpif_flow_put *put);
-
-    /* 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 OVS_KEY_ATTR_* in the 'del->key_len' bytes
-     * starting at 'del->key'.
-     *
-     * If the operation succeeds, then 'del->stats', if nonnull, must be set to
-     * the flow's statistics before its deletion. */
-    int (*flow_del)(struct dpif *dpif, const struct dpif_flow_del *del);
-
     /* Deletes all flows from 'dpif' and clears all of its queues of received
      * packets. */
     int (*flow_flush)(struct dpif *dpif);
@@ -329,18 +296,10 @@ struct dpif_class {
     int (*flow_dump_next)(struct dpif_flow_dump_thread *thread,
                           struct dpif_flow *flows, int max_flows);
 
-    /* Performs the 'execute->actions_len' bytes of actions in
-     * 'execute->actions' on the Ethernet frame in 'execute->packet'
-     * and on the packet metadata in 'execute->md'.
-     * May modify both packet and metadata. */
-    int (*execute)(struct dpif *dpif, struct dpif_execute *execute);
-
     /* 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 is optional.  It is only worthwhile to implement it if
-     * 'dpif' can perform operations in batch faster than individually. */
+     * "output" members documented in comments and the 'error' member of each
+     * dpif_op. */
     void (*operate)(struct dpif *dpif, struct dpif_op **ops, size_t n_ops);
 
     /* Enables or disables receiving packets with dpif_recv() for 'dpif'.
diff --git a/lib/dpif.c b/lib/dpif.c
index 5b9da4d..4f2491b 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -878,49 +878,7 @@ dpif_flow_get(const struct dpif *dpif,
     return error;
 }
 
-static int
-dpif_flow_put__(struct dpif *dpif, const struct dpif_flow_put *put)
-{
-    int error;
-
-    COVERAGE_INC(dpif_flow_put);
-    ovs_assert(!(put->flags & ~(DPIF_FP_CREATE | DPIF_FP_MODIFY
-                                | DPIF_FP_ZERO_STATS)));
-
-    error = dpif->dpif_class->flow_put(dpif, put);
-    if (error && put->stats) {
-        memset(put->stats, 0, sizeof *put->stats);
-    }
-    log_flow_put_message(dpif, put, error);
-    return error;
-}
-
-/* Adds or modifies a flow in 'dpif'.  The flow is specified by the Netlink
- * attribute OVS_FLOW_ATTR_KEY with types OVS_KEY_ATTR_* in the 'key_len' bytes
- * starting at 'key', and OVS_FLOW_ATTR_MASK with types of OVS_KEY_ATTR_* in
- * the 'mask_len' bytes starting at 'mask'. The associated actions are
- * specified by the Netlink attributes with 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
- *   ENOENT.
- *
- *   The datapath may reject attempts to insert overlapping flows with EINVAL
- *   or EEXIST, but clients should not rely on this: avoiding overlapping flows
- *   is primarily the client's responsibility.
- *
- *   If the operation succeeds, then 'stats', if nonnull, will be zeroed.
- *
- * - If the flow's key does exist in 'dpif', then the flow's actions will be
- *   updated if 'flags' includes DPIF_FP_MODIFY.  Otherwise the operation will
- *   fail with EEXIST.  If the flow's actions are updated, then its statistics
- *   will be zeroed if 'flags' includes DPIF_FP_ZERO_STATS, and left as-is
- *   otherwise.
- *
- *   If the operation succeeds, then 'stats', if nonnull, will be set to the
- *   flow's statistics before the update.
- */
+/* A dpif_operate() wrapper for performing a single DPIF_OP_FLOW_PUT. */
 int
 dpif_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
               const struct nlattr *key, size_t key_len,
@@ -928,51 +886,43 @@ dpif_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
               const struct nlattr *actions, size_t actions_len,
               struct dpif_flow_stats *stats)
 {
-    struct dpif_flow_put put;
+    struct dpif_op *opp;
+    struct dpif_op op;
 
-    put.flags = flags;
-    put.key = key;
-    put.key_len = key_len;
-    put.mask = mask;
-    put.mask_len = mask_len;
-    put.actions = actions;
-    put.actions_len = actions_len;
-    put.stats = stats;
-    return dpif_flow_put__(dpif, &put);
-}
-
-static int
-dpif_flow_del__(struct dpif *dpif, struct dpif_flow_del *del)
-{
-    int error;
+    op.type = DPIF_OP_FLOW_PUT;
+    op.u.flow_put.flags = flags;
+    op.u.flow_put.key = key;
+    op.u.flow_put.key_len = key_len;
+    op.u.flow_put.mask = mask;
+    op.u.flow_put.mask_len = mask_len;
+    op.u.flow_put.actions = actions;
+    op.u.flow_put.actions_len = actions_len;
+    op.u.flow_put.stats = stats;
 
-    COVERAGE_INC(dpif_flow_del);
+    opp = &op;
+    dpif_operate(dpif, &opp, 1);
 
-    error = dpif->dpif_class->flow_del(dpif, del);
-    if (error && del->stats) {
-        memset(del->stats, 0, sizeof *del->stats);
-    }
-    log_flow_del_message(dpif, del, error);
-    return error;
+    return op.error;
 }
 
-/* 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 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. */
+/* A dpif_operate() wrapper for performing a single DPIF_OP_FLOW_DEL. */
 int
 dpif_flow_del(struct dpif *dpif,
               const struct nlattr *key, size_t key_len,
               struct dpif_flow_stats *stats)
 {
-    struct dpif_flow_del del;
+    struct dpif_op *opp;
+    struct dpif_op op;
 
-    del.key = key;
-    del.key_len = key_len;
-    del.stats = stats;
-    return dpif_flow_del__(dpif, &del);
+    op.type = DPIF_OP_FLOW_DEL;
+    op.u.flow_del.key = key;
+    op.u.flow_del.key_len = key_len;
+    op.u.flow_del.stats = stats;
+
+    opp = &op;
+    dpif_operate(dpif, &opp, 1);
+
+    return op.error;
 }
 
 /* Creates and returns a new 'struct dpif_flow_dump' for iterating through the
@@ -1099,8 +1049,7 @@ dpif_execute_helper_cb(void *aux_, struct dpif_packet **packets, int cnt,
         execute.packet = packet;
         execute.md = *md;
         execute.needs_help = false;
-        aux->error = aux->dpif->dpif_class->execute(aux->dpif, &execute);
-
+        aux->error = dpif_execute(aux->dpif, &execute);
         log_execute_message(aux->dpif, &execute, true, aux->error);
 
         if (md->tunnel.ip_dst) {
@@ -1156,125 +1105,99 @@ dpif_execute_needs_help(const struct dpif_execute *execute)
     return execute->needs_help || nl_attr_oversized(execute->actions_len);
 }
 
-/* Causes 'dpif' to perform the 'execute->actions_len' bytes of actions in
- * 'execute->actions' on the Ethernet frame in 'execute->packet' and on packet
- * metadata in 'execute->md'.  The implementation is allowed to modify both the
- * '*execute->packet' and 'execute->md'.
- *
- * Some dpif providers do not implement every action.  The Linux kernel
- * datapath, in particular, does not implement ARP field modification.  If
- * 'needs_help' is true, the dpif layer executes in userspace all of the
- * actions that it can, and for OVS_ACTION_ATTR_OUTPUT and
- * OVS_ACTION_ATTR_USERSPACE actions it passes the packet through to the dpif
- * implementation.
- *
- * This works even if 'execute->actions_len' is too long for a Netlink
- * attribute.
- *
- * Returns 0 if successful, otherwise a positive errno value. */
+/* A dpif_operate() wrapper for performing a single DPIF_OP_EXECUTE. */
 int
 dpif_execute(struct dpif *dpif, struct dpif_execute *execute)
 {
-    int error;
+    if (execute->actions_len) {
+        struct dpif_op *opp;
+        struct dpif_op op;
 
-    COVERAGE_INC(dpif_execute);
-    if (execute->actions_len > 0) {
-        error = (dpif_execute_needs_help(execute)
-                 ? dpif_execute_with_help(dpif, execute)
-                 : dpif->dpif_class->execute(dpif, execute));
-    } else {
-        error = 0;
-    }
+        op.type = DPIF_OP_EXECUTE;
+        op.u.execute = *execute;
 
-    log_execute_message(dpif, execute, false, error);
+        opp = &op;
+        dpif_operate(dpif, &opp, 1);
 
-    return error;
+        return op.error;
+    } else {
+        return 0;
+    }
 }
 
 /* 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. */
+ * which they are specified.  Places each operation's results in the "output"
+ * members documented in comments, and 0 in the 'error' member on success or a
+ * positive errno on failure. */
 void
 dpif_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops)
 {
-    if (dpif->dpif_class->operate) {
-        while (n_ops > 0) {
-            size_t chunk;
+    while (n_ops > 0) {
+        size_t chunk;
 
-            /* Count 'chunk', the number of ops that can be executed without
-             * needing any help.  Ops that need help should be rare, so we
-             * expect this to ordinarily be 'n_ops', that is, all the ops. */
-            for (chunk = 0; chunk < n_ops; chunk++) {
-                struct dpif_op *op = ops[chunk];
+        /* Count 'chunk', the number of ops that can be executed without
+         * needing any help.  Ops that need help should be rare, so we
+         * expect this to ordinarily be 'n_ops', that is, all the ops. */
+        for (chunk = 0; chunk < n_ops; chunk++) {
+            struct dpif_op *op = ops[chunk];
 
-                if (op->type == DPIF_OP_EXECUTE
-                    && dpif_execute_needs_help(&op->u.execute)) {
-                    break;
-                }
+            if (op->type == DPIF_OP_EXECUTE
+                && dpif_execute_needs_help(&op->u.execute)) {
+                break;
             }
+        }
 
-            if (chunk) {
-                /* Execute a chunk full of ops that the dpif provider can
-                 * handle itself, without help. */
-                size_t i;
-
-                dpif->dpif_class->operate(dpif, ops, chunk);
+        if (chunk) {
+            /* Execute a chunk full of ops that the dpif provider can
+             * handle itself, without help. */
+            size_t i;
 
-                for (i = 0; i < chunk; i++) {
-                    struct dpif_op *op = ops[i];
+            dpif->dpif_class->operate(dpif, ops, chunk);
 
-                    switch (op->type) {
-                    case DPIF_OP_FLOW_PUT:
-                        log_flow_put_message(dpif, &op->u.flow_put, op->error);
-                        break;
+            for (i = 0; i < chunk; i++) {
+                struct dpif_op *op = ops[i];
+                int error = op->error;
 
-                    case DPIF_OP_FLOW_DEL:
-                        log_flow_del_message(dpif, &op->u.flow_del, op->error);
-                        break;
+                switch (op->type) {
+                case DPIF_OP_FLOW_PUT: {
+                    struct dpif_flow_put *put = &op->u.flow_put;
 
-                    case DPIF_OP_EXECUTE:
-                        log_execute_message(dpif, &op->u.execute, false,
-                                            op->error);
-                        break;
+                    COVERAGE_INC(dpif_flow_put);
+                    log_flow_put_message(dpif, put, error);
+                    if (error && put->stats) {
+                        memset(put->stats, 0, sizeof *put->stats);
                     }
+                    break;
                 }
 
-                ops += chunk;
-                n_ops -= chunk;
-            } else {
-                /* Help the dpif provider to execute one op. */
-                struct dpif_op *op = ops[0];
+                case DPIF_OP_FLOW_DEL: {
+                    struct dpif_flow_del *del = &op->u.flow_del;
 
-                op->error = dpif_execute(dpif, &op->u.execute);
-                ops++;
-                n_ops--;
-            }
-        }
-    } else {
-        size_t i;
-
-        for (i = 0; i < n_ops; i++) {
-            struct dpif_op *op = ops[i];
-
-            switch (op->type) {
-            case DPIF_OP_FLOW_PUT:
-                op->error = dpif_flow_put__(dpif, &op->u.flow_put);
-                break;
+                    COVERAGE_INC(dpif_flow_del);
+                    log_flow_del_message(dpif, del, error);
+                    if (error && del->stats) {
+                        memset(del->stats, 0, sizeof *del->stats);
+                    }
+                    break;
+                }
 
-            case DPIF_OP_FLOW_DEL:
-                op->error = dpif_flow_del__(dpif, &op->u.flow_del);
-                break;
+                case DPIF_OP_EXECUTE:
+                    COVERAGE_INC(dpif_execute);
+                    log_execute_message(dpif, &op->u.execute, false, error);
+                    break;
+                }
+            }
 
-            case DPIF_OP_EXECUTE:
-                op->error = dpif_execute(dpif, &op->u.execute);
-                break;
+            ops += chunk;
+            n_ops -= chunk;
+        } else {
+            /* Help the dpif provider to execute one op. */
+            struct dpif_op *op = ops[0];
 
-            default:
-                OVS_NOT_REACHED();
-            }
+            COVERAGE_INC(dpif_execute);
+            op->error = dpif_execute_with_help(dpif, &op->u.execute);
+            ops++;
+            n_ops--;
         }
     }
 }
diff --git a/lib/dpif.h b/lib/dpif.h
index 94bcacc..a27bc01 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -587,6 +587,28 @@ enum dpif_op_type {
     DPIF_OP_EXECUTE,
 };
 
+/* Add or modify a flow.
+ *
+ * The flow is specified by the Netlink 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 OVS_ACTION_ATTR_* in the 'actions_len'
+ * bytes starting at 'actions'.
+ *
+ *   - If the flow's key does not exist in the dpif, then the flow will be
+ *     added if 'flags' includes DPIF_FP_CREATE.  Otherwise the operation will
+ *     fail with ENOENT.
+ *
+ *     If the operation succeeds, then 'stats', if nonnull, will be zeroed.
+ *
+ *   - If the flow's key does exist in the dpif, then the flow's actions will
+ *     be updated if 'flags' includes DPIF_FP_MODIFY.  Otherwise the operation
+ *     will fail with EEXIST.  If the flow's actions are updated, then its
+ *     statistics will be zeroed if 'flags' includes DPIF_FP_ZERO_STATS, and
+ *     left as-is otherwise.
+ *
+ *     If the operation succeeds, then 'stats', if nonnull, will be set to the
+ *     flow's statistics before the update.
+ */
 struct dpif_flow_put {
     /* Input. */
     enum dpif_flow_put_flags flags; /* DPIF_FP_*. */
@@ -601,6 +623,14 @@ struct dpif_flow_put {
     struct dpif_flow_stats *stats;  /* Optional flow statistics. */
 };
 
+/* Delete a flow.
+ *
+ * The flow is specified by the Netlink attributes with types OVS_KEY_ATTR_* in
+ * the 'key_len' bytes starting at 'key'.  Succeeds with status 0 if the flow
+ * is deleted, or fails with ENOENT if the dpif does not contain such a flow.
+ *
+ * If the operation succeeds, then 'stats', if nonnull, will be set to the
+ * flow's statistics before its deletion. */
 struct dpif_flow_del {
     /* Input. */
     const struct nlattr *key;       /* Flow to delete. */
@@ -610,21 +640,29 @@ struct dpif_flow_del {
     struct dpif_flow_stats *stats;  /* Optional flow statistics. */
 };
 
+/* Executes actions on a specified packet.
+ *
+ * Performs the 'actions_len' bytes of actions in 'actions' on the Ethernet
+ * frame in 'packet' and on the packet metadata in 'md'.  May modify both
+ * 'packet' and 'md'.
+ *
+ * Some dpif providers do not implement every action.  The Linux kernel
+ * datapath, in particular, does not implement ARP field modification.  If
+ * 'needs_help' is true, the dpif layer executes in userspace all of the
+ * actions that it can, and for OVS_ACTION_ATTR_OUTPUT and
+ * OVS_ACTION_ATTR_USERSPACE actions it passes the packet through to the dpif
+ * implementation.
+ *
+ * This works even if 'actions_len' is too long for a Netlink attribute. */
 struct dpif_execute {
-    /* Raw support for execute passed along to the provider. */
+    /* Input. */
     const struct nlattr *actions;   /* Actions to execute on packet. */
     size_t actions_len;             /* Length of 'actions' in bytes. */
+    bool needs_help;
+
+    /* Input, but possibly modified as a side effect of execution. */
     struct ofpbuf *packet;          /* Packet to execute. */
     struct pkt_metadata md;         /* Packet metadata. */
-
-    /* Some dpif providers do not implement every action.  The Linux kernel
-     * datapath, in particular, does not implement ARP field modification.
-     *
-     * If this member is set to true, the dpif layer executes in userspace all
-     * of the actions that it can, and for OVS_ACTION_ATTR_OUTPUT and
-     * OVS_ACTION_ATTR_USERSPACE actions it passes the packet through to the
-     * dpif implementation. */
-    bool needs_help;
 };
 
 int dpif_execute(struct dpif *, struct dpif_execute *);
-- 
1.7.10.4




More information about the dev mailing list