This patch adds support for batching flow_get operations to the dpif. As
part of this, it also now allows fetching the mask (this was previously
not possible using a 'get' operation).

Signed-off-by: Joe Stringer <joestrin...@nicira.com>
---
 lib/dpif-linux.c    |   70 +++++++++++++++++++++++++++++++-------------
 lib/dpif-netdev.c   |   41 ++++++++++++++++----------
 lib/dpif-provider.h |   19 ++++++------
 lib/dpif.c          |   80 +++++++++++++++++++++++++++++++++------------------
 lib/dpif.h          |   17 +++++++++--
 5 files changed, 154 insertions(+), 73 deletions(-)

diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 0eac3e7..2cf6de1 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -126,6 +126,8 @@ static int dpif_linux_flow_transact(struct dpif_linux_flow 
*request,
                                     struct ofpbuf **bufp);
 static void dpif_linux_flow_get_stats(const struct dpif_linux_flow *,
                                       struct dpif_flow_stats *);
+static void dpif_linux_flow_to_dpif_flow(struct dpif_flow *,
+                                         const struct dpif_linux_flow *);
 
 /* One of the dpif channels between the kernel and userspace. */
 struct dpif_channel {
@@ -1029,6 +1031,18 @@ dpif_linux_port_poll_wait(const struct dpif *dpif_)
     }
 }
 
+static void
+dpif_linux_init_flow_get(const struct dpif_linux *dpif,
+                         const struct nlattr *key, size_t key_len,
+                         struct dpif_linux_flow *request)
+{
+    dpif_linux_flow_init(request);
+    request->cmd = OVS_FLOW_CMD_GET;
+    request->dp_ifindex = dpif->dp_ifindex;
+    request->key = key;
+    request->key_len = key_len;
+}
+
 static int
 dpif_linux_flow_get__(const struct dpif_linux *dpif,
                       const struct nlattr *key, size_t key_len,
@@ -1036,36 +1050,22 @@ dpif_linux_flow_get__(const struct dpif_linux *dpif,
 {
     struct dpif_linux_flow request;
 
-    dpif_linux_flow_init(&request);
-    request.cmd = OVS_FLOW_CMD_GET;
-    request.dp_ifindex = dpif->dp_ifindex;
-    request.key = key;
-    request.key_len = key_len;
+    dpif_linux_init_flow_get(dpif, key, key_len, &request);
     return dpif_linux_flow_transact(&request, reply, bufp);
 }
 
 static int
-dpif_linux_flow_get(const struct dpif *dpif_,
-                    const struct nlattr *key, size_t key_len,
-                    struct ofpbuf **actionsp, struct dpif_flow_stats *stats)
+dpif_linux_flow_get(const struct dpif *dpif_, const struct dpif_flow_get *get)
 {
     const struct dpif_linux *dpif = dpif_linux_cast(dpif_);
     struct dpif_linux_flow reply;
     struct ofpbuf *buf;
     int error;
 
-    error = dpif_linux_flow_get__(dpif, key, key_len, &reply, &buf);
+    error = dpif_linux_flow_get__(dpif, get->key, get->key_len, &reply, &buf);
     if (!error) {
-        if (stats) {
-            dpif_linux_flow_get_stats(&reply, stats);
-        }
-        if (actionsp) {
-            ofpbuf_set_data(buf, CONST_CAST(struct nlattr *, reply.actions));
-            ofpbuf_set_size(buf, reply.actions_len);
-            *actionsp = buf;
-        } else {
-            ofpbuf_delete(buf);
-        }
+        *get->buffer = *buf;
+        dpif_linux_flow_to_dpif_flow(get->flow, &reply);
     }
     return error;
 }
@@ -1235,7 +1235,7 @@ dpif_linux_flow_dump_thread_destroy(struct 
dpif_flow_dump_thread *thread_)
 
 static void
 dpif_linux_flow_to_dpif_flow(struct dpif_flow *dpif_flow,
-                             struct dpif_linux_flow *linux_flow)
+                             const struct dpif_linux_flow *linux_flow)
 {
     dpif_flow->key = linux_flow->key;
     dpif_flow->key_len = linux_flow->key_len;
@@ -1385,6 +1385,7 @@ dpif_linux_operate__(struct dpif_linux *dpif,
         struct dpif_flow_put *put;
         struct dpif_flow_del *del;
         struct dpif_execute *execute;
+        struct dpif_flow_get *get;
         struct dpif_linux_flow flow;
 
         ofpbuf_use_stub(&aux->request,
@@ -1421,6 +1422,14 @@ dpif_linux_operate__(struct dpif_linux *dpif,
                                       &aux->request);
             break;
 
+        case DPIF_OP_FLOW_GET:
+            get = &op->u.flow_get;
+            dpif_linux_init_flow_get(dpif, get->key, get->key_len, &flow);
+            flow.nlmsg_flags |= NLM_F_ECHO;
+            aux->txn.reply = &aux->reply;
+            dpif_linux_flow_to_ofpbuf(&flow, &aux->request);
+            break;
+
         default:
             OVS_NOT_REACHED();
         }
@@ -1437,6 +1446,7 @@ dpif_linux_operate__(struct dpif_linux *dpif,
         struct dpif_op *op = ops[i];
         struct dpif_flow_put *put;
         struct dpif_flow_del *del;
+        struct dpif_flow_get *get;
 
         op->error = txn->error;
 
@@ -1482,6 +1492,26 @@ dpif_linux_operate__(struct dpif_linux *dpif,
         case DPIF_OP_EXECUTE:
             break;
 
+        case DPIF_OP_FLOW_GET:
+            get = &op->u.flow_get;
+            if (!op->error) {
+                struct dpif_linux_flow reply;
+
+                op->error = dpif_linux_flow_from_ofpbuf(&reply,
+                                                        txn->reply);
+                if (!op->error) {
+                    /* Steal the reply */
+                    *get->buffer = *txn->reply;
+                    txn->reply = NULL;
+                    dpif_linux_flow_to_dpif_flow(get->flow, &reply);
+                }
+            }
+
+            if (op->error) {
+                memset(get->flow, 0, sizeof *get->flow);
+            }
+            break;
+
         default:
             OVS_NOT_REACHED();
         }
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 58c629b..c3fde36 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1101,7 +1101,7 @@ dp_netdev_find_flow(const struct dp_netdev *dp, const 
struct flow *flow)
 }
 
 static void
-get_dpif_flow_stats(struct dp_netdev_flow *netdev_flow,
+get_dpif_flow_stats(const struct dp_netdev_flow *netdev_flow,
                     struct dpif_flow_stats *stats)
 {
     struct dp_netdev_flow_stats *bucket;
@@ -1118,6 +1118,28 @@ get_dpif_flow_stats(struct dp_netdev_flow *netdev_flow,
     }
 }
 
+static void
+dp_netdev_flow_to_dpif_flow(const struct dp_netdev_flow *netdev_flow,
+                            struct ofpbuf *buf, struct dpif_flow *flow)
+{
+    struct flow_wildcards wc;
+    struct dp_netdev_actions *actions;
+
+    minimask_expand(&netdev_flow->cr.match.mask, &wc);
+    ofpbuf_init(buf, sizeof(struct odputil_keybuf));
+    odp_flow_key_from_mask(buf, &wc.masks, &netdev_flow->flow,
+                           odp_to_u32(wc.masks.in_port.odp_port),
+                           SIZE_MAX, true);
+    flow->mask = ofpbuf_data(buf);
+    flow->mask_len = ofpbuf_size(buf);
+
+    actions = dp_netdev_flow_get_actions(netdev_flow);
+    flow->actions = ofpbuf_put(buf, actions->actions, actions->size);
+    flow->actions_len = actions->size;
+
+    get_dpif_flow_stats(netdev_flow, &flow->stats);
+}
+
 static int
 dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len,
                               const struct nlattr *mask_key,
@@ -1211,16 +1233,14 @@ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, 
uint32_t key_len,
 }
 
 static int
-dpif_netdev_flow_get(const struct dpif *dpif,
-                     const struct nlattr *nl_key, size_t nl_key_len,
-                     struct ofpbuf **actionsp, struct dpif_flow_stats *stats)
+dpif_netdev_flow_get(const struct dpif *dpif, const struct dpif_flow_get *get)
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
     struct dp_netdev_flow *netdev_flow;
     struct flow key;
     int error;
 
-    error = dpif_netdev_flow_from_nlattrs(nl_key, nl_key_len, &key);
+    error = dpif_netdev_flow_from_nlattrs(get->key, get->key_len, &key);
     if (error) {
         return error;
     }
@@ -1230,16 +1250,7 @@ dpif_netdev_flow_get(const struct dpif *dpif,
     fat_rwlock_unlock(&dp->cls.rwlock);
 
     if (netdev_flow) {
-        if (stats) {
-            get_dpif_flow_stats(netdev_flow, stats);
-        }
-
-        if (actionsp) {
-            struct dp_netdev_actions *actions;
-
-            actions = dp_netdev_flow_get_actions(netdev_flow);
-            *actionsp = ofpbuf_clone_data(actions->actions, actions->size);
-        }
+        dp_netdev_flow_to_dpif_flow(netdev_flow, get->buffer, get->flow);
      } else {
         error = ENOENT;
     }
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index b762ac0..13e426c 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -246,16 +246,19 @@ struct dpif_class {
      * Returns 0 if successful.  If no flow matches, returns ENOENT.  On other
      * failure, returns a positive errno value.
      *
-     * If 'actionsp' is nonnull, then on success '*actionsp' must be set to an
-     * ofpbuf owned by the caller that contains the Netlink attributes for the
-     * flow's actions.  The caller must free the ofpbuf (with ofpbuf_delete())
-     * when it is no longer needed.
+     * If 'get->mask' is nonnull, then on success '*get->mask' must be set to
+     * an ofpbuf owned by the caller that contains the Netlink attributes for
+     * the flow's actions.  The caller must free the ofpbuf (with
+     * ofpbuf_delete()) when it is no longer needed.
      *
-     * If 'stats' is nonnull, then on success it must be updated with the
+     * If 'get->actions' is nonnull, then on success '*get->actions' must be
+     * set to an ofpbuf owned by the caller that contains the Netlink
+     * attributes for the flow's actions.  The caller must free the ofpbuf
+     * (with ofpbuf_delete()) when it is no longer needed.
+     *
+     * If 'get->stats' is nonnull, then on success it must be updated with the
      * flow's statistics. */
-    int (*flow_get)(const struct dpif *dpif,
-                    const struct nlattr *key, size_t key_len,
-                    struct ofpbuf **actionsp, struct dpif_flow_stats *stats);
+    int (*flow_get)(const struct dpif *dpif, const struct dpif_flow_get *get);
 
     /* 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
diff --git a/lib/dpif.c b/lib/dpif.c
index 2b6f36d..e7744f4 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -97,6 +97,8 @@ static void log_flow_del_message(struct dpif *, const struct 
dpif_flow_del *,
                                  int error);
 static void log_execute_message(struct dpif *, const struct dpif_execute *,
                                 bool subexecute, int error);
+static void log_flow_get_message(const struct dpif *,
+                                 const struct dpif_flow_get *, int error);
 
 static void
 dp_initialize(void)
@@ -827,6 +829,22 @@ dpif_flow_flush(struct dpif *dpif)
     return error;
 }
 
+static int
+dpif_flow_get__(const struct dpif *dpif, const struct dpif_flow_get *get)
+{
+    int error;
+
+    COVERAGE_INC(dpif_flow_get);
+
+    error = dpif->dpif_class->flow_get(dpif, get);
+    if (error) {
+        memset(get->flow, 0, sizeof *get->flow);
+    }
+    log_flow_get_message(dpif, get, error);
+
+    return error;
+}
+
 /* Queries 'dpif' for a flow entry.  The flow is specified by the Netlink
  * attributes with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at
  * 'key'.
@@ -834,6 +852,11 @@ dpif_flow_flush(struct dpif *dpif)
  * Returns 0 if successful.  If no flow matches, returns ENOENT.  On other
  * failure, returns a positive errno value.
  *
+ * If 'maskp' is nonnull, then on success '*maskp' will be set to an ofpbuf
+ * owned by the caller that contains the Netlink attributes for the flow's
+ * mask.  The caller must free the ofpbuf (with ofpbuf_delete()) when it is no
+ * longer needed.
+ *
  * If 'actionsp' is nonnull, then on success '*actionsp' will be set to an
  * ofpbuf owned by the caller that contains the Netlink attributes for the
  * flow's actions.  The caller must free the ofpbuf (with ofpbuf_delete()) when
@@ -844,36 +867,17 @@ dpif_flow_flush(struct dpif *dpif)
 int
 dpif_flow_get(const struct dpif *dpif,
               const struct nlattr *key, size_t key_len,
-              struct ofpbuf **actionsp, struct dpif_flow_stats *stats)
+              struct ofpbuf *buffer, struct dpif_flow *flow)
 {
-    int error;
-
-    COVERAGE_INC(dpif_flow_get);
-
-    error = dpif->dpif_class->flow_get(dpif, key, key_len, actionsp, stats);
-    if (error) {
-        if (actionsp) {
-            *actionsp = NULL;
-        }
-        if (stats) {
-            memset(stats, 0, sizeof *stats);
-        }
-    }
-    if (should_log_flow_message(error)) {
-        const struct nlattr *actions;
-        size_t actions_len;
+    struct dpif_flow_get get;
 
-        if (!error && actionsp) {
-            actions = ofpbuf_data(*actionsp);
-            actions_len = ofpbuf_size(*actionsp);
-        } else {
-            actions = NULL;
-            actions_len = 0;
-        }
-        log_flow_message(dpif, error, "flow_get", key, key_len,
-                         NULL, 0, stats, actions, actions_len);
-    }
-    return error;
+    get.key = key;
+    get.key_len = key_len;
+    get.buffer = buffer;
+    get.flow = flow;
+    get.flow->key = key;
+    get.flow->key_len = key_len;
+    return dpif_flow_get__(dpif, &get);
 }
 
 static int
@@ -1237,6 +1241,9 @@ dpif_operate(struct dpif *dpif, struct dpif_op **ops, 
size_t n_ops)
                         log_execute_message(dpif, &op->u.execute, false,
                                             op->error);
                         break;
+                    case DPIF_OP_FLOW_GET:
+                        log_flow_get_message(dpif, &op->u.flow_get, op->error);
+                        break;
                     }
                 }
 
@@ -1270,6 +1277,10 @@ dpif_operate(struct dpif *dpif, struct dpif_op **ops, 
size_t n_ops)
                 op->error = dpif_execute(dpif, &op->u.execute);
                 break;
 
+            case DPIF_OP_FLOW_GET:
+                op->error = dpif_flow_get__(dpif, &op->u.flow_get);
+                break;
+
             default:
                 OVS_NOT_REACHED();
             }
@@ -1596,3 +1607,16 @@ log_execute_message(struct dpif *dpif, const struct 
dpif_execute *execute,
         free(packet);
     }
 }
+
+static void
+log_flow_get_message(const struct dpif *dpif, const struct dpif_flow_get *get,
+                     int error)
+{
+    if (should_log_flow_message(error)) {
+        log_flow_message(dpif, error, "flow_get",
+                         get->key, get->key_len,
+                         get->flow->mask, get->flow->mask_len,
+                         &get->flow->stats,
+                         get->flow->actions, get->flow->actions_len);
+    }
+}
diff --git a/lib/dpif.h b/lib/dpif.h
index f080cde..57ad5a2 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -405,6 +405,7 @@ struct flow;
 struct nlattr;
 struct sset;
 struct dpif_class;
+struct dpif_flow;
 
 int dp_register_provider(const struct dpif_class *);
 int dp_unregister_provider(const char *type);
@@ -523,8 +524,8 @@ int dpif_flow_del(struct dpif *,
                   const struct nlattr *key, size_t key_len,
                   struct dpif_flow_stats *);
 int dpif_flow_get(const struct dpif *,
-                  const struct nlattr *key, size_t key_len,
-                  struct ofpbuf **actionsp, struct dpif_flow_stats *);
+                  const struct nlattr *key, size_t key_len, struct ofpbuf *,
+                  struct dpif_flow *);
 
 /* Flow dumping interface
  * ======================
@@ -584,6 +585,7 @@ enum dpif_op_type {
     DPIF_OP_FLOW_PUT = 1,
     DPIF_OP_FLOW_DEL,
     DPIF_OP_EXECUTE,
+    DPIF_OP_FLOW_GET,
 };
 
 struct dpif_flow_put {
@@ -626,6 +628,16 @@ struct dpif_execute {
     bool needs_help;
 };
 
+struct dpif_flow_get {
+    /* Input. */
+    const struct nlattr *key;       /* Flow to get. */
+    size_t key_len;                 /* Length of 'key' in bytes. */
+    struct ofpbuf *buffer;          /* Storage for output parameters. */
+
+    /* Output. */
+    struct dpif_flow *flow;         /* Resulting flow from datapath. */
+};
+
 int dpif_execute(struct dpif *, struct dpif_execute *);
 
 struct dpif_op {
@@ -635,6 +647,7 @@ struct dpif_op {
         struct dpif_flow_put flow_put;
         struct dpif_flow_del flow_del;
         struct dpif_execute execute;
+        struct dpif_flow_get flow_get;
     } u;
 };
 
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to