[ovs-dev] [optimize 03/26] ofproto-dpif: Batch flow uninstallations due to expiration.

Ben Pfaff blp at nicira.com
Tue Apr 17 00:18:43 UTC 2012


From: Ben Pfaff <blp at hardrock.nicira.com>

Signed-off-by: Ben Pfaff <blp at hardrock.nicira.com>
---
 lib/dpif-linux.c       |  103 +++++++++++++++++++++++++++++++++---------------
 lib/dpif-netdev.c      |   10 ++---
 lib/dpif-provider.h    |   19 ++++-----
 lib/dpif.c             |   53 +++++++++++++++++++------
 lib/dpif.h             |   13 ++++++-
 ofproto/ofproto-dpif.c |   50 +++++++++++++++++++++++-
 6 files changed, 186 insertions(+), 62 deletions(-)

diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 7013bc5..d47ddf1 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -645,26 +645,32 @@ dpif_linux_flow_put(struct dpif *dpif_, const struct dpif_flow_put *put)
     return error;
 }
 
-static int
-dpif_linux_flow_del(struct dpif *dpif_,
-                    const struct nlattr *key, size_t key_len,
-                    struct dpif_flow_stats *stats)
+static void
+dpif_linux_init_flow_del(struct dpif *dpif_, const struct dpif_flow_del *del,
+                         struct dpif_linux_flow *request)
 {
     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+
+    dpif_linux_flow_init(request);
+    request->cmd = OVS_FLOW_CMD_DEL;
+    request->dp_ifindex = dpif->dp_ifindex;
+    request->key = del->key;
+    request->key_len = del->key_len;
+}
+
+static int
+dpif_linux_flow_del(struct dpif *dpif_, const struct dpif_flow_del *del)
+{
     struct dpif_linux_flow request, reply;
     struct ofpbuf *buf;
     int error;
 
-    dpif_linux_flow_init(&request);
-    request.cmd = OVS_FLOW_CMD_DEL;
-    request.dp_ifindex = dpif->dp_ifindex;
-    request.key = key;
-    request.key_len = key_len;
+    dpif_linux_init_flow_del(dpif_, del, &request);
     error = dpif_linux_flow_transact(&request,
-                                     stats ? &reply : NULL,
-                                     stats ? &buf : NULL);
-    if (!error && stats) {
-        dpif_linux_flow_get_stats(&reply, stats);
+                                     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;
@@ -818,23 +824,39 @@ dpif_linux_operate(struct dpif *dpif_, struct dpif_op **ops, size_t n_ops)
     for (i = 0; i < n_ops; i++) {
         struct nl_transaction *txn = &txns[i];
         struct dpif_op *op = ops[i];
-
-        if (op->type == DPIF_OP_FLOW_PUT) {
-            struct dpif_flow_put *put = &op->u.flow_put;
-            struct dpif_linux_flow request;
-
+        struct dpif_flow_put *put;
+        struct dpif_flow_del *del;
+        struct dpif_execute *execute;
+        struct dpif_linux_flow request;
+
+        switch (op->type) {
+        case DPIF_OP_FLOW_PUT:
+            put = &op->u.flow_put;
             dpif_linux_init_flow_put(dpif_, put, &request);
             if (put->stats) {
                 request.nlmsg_flags |= NLM_F_ECHO;
             }
             txn->request = ofpbuf_new(1024);
             dpif_linux_flow_to_ofpbuf(&request, txn->request);
-        } else if (op->type == DPIF_OP_EXECUTE) {
-            struct dpif_execute *execute = &op->u.execute;
+            break;
+
+        case DPIF_OP_FLOW_DEL:
+            del = &op->u.flow_del;
+            dpif_linux_init_flow_del(dpif_, del, &request);
+            if (del->stats) {
+                request.nlmsg_flags |= NLM_F_ECHO;
+            }
+            txn->request = ofpbuf_new(1024);
+            dpif_linux_flow_to_ofpbuf(&request, txn->request);
+            break;
 
+        case DPIF_OP_EXECUTE:
+            execute = &op->u.execute;
             txn->request = dpif_linux_encode_execute(dpif->dp_ifindex,
                                                      execute);
-        } else {
+            break;
+
+        default:
             NOT_REACHED();
         }
     }
@@ -851,23 +873,40 @@ dpif_linux_operate(struct dpif *dpif_, struct dpif_op **ops, size_t n_ops)
     for (i = 0; i < n_ops; i++) {
         struct nl_transaction *txn = &txns[i];
         struct dpif_op *op = ops[i];
+        struct dpif_flow_put *put;
+        struct dpif_flow_del *del;
 
-        if (op->type == DPIF_OP_FLOW_PUT) {
-            struct dpif_flow_put *put = &op->u.flow_put;
-            int error = txn->error;
+        op->error = txn->error;
 
-            if (!error && put->stats) {
+        switch (op->type) {
+        case DPIF_OP_FLOW_PUT:
+            put = &op->u.flow_put;
+            if (!op->error && put->stats) {
                 struct dpif_linux_flow reply;
 
-                error = dpif_linux_flow_from_ofpbuf(&reply, txn->reply);
-                if (!error) {
+                op->error = dpif_linux_flow_from_ofpbuf(&reply, txn->reply);
+                if (!op->error) {
                     dpif_linux_flow_get_stats(&reply, put->stats);
                 }
             }
-            op->error = error;
-        } else if (op->type == DPIF_OP_EXECUTE) {
-            op->error = txn->error;
-        } else {
+            break;
+
+        case DPIF_OP_FLOW_DEL:
+            del = &op->u.flow_del;
+            if (!op->error && del->stats) {
+                struct dpif_linux_flow reply;
+
+                op->error = dpif_linux_flow_from_ofpbuf(&reply, txn->reply);
+                if (!op->error) {
+                    dpif_linux_flow_get_stats(&reply, del->stats);
+                }
+            }
+            break;
+
+        case DPIF_OP_EXECUTE:
+            break;
+
+        default:
             NOT_REACHED();
         }
 
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 1686087..a907722 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -777,24 +777,22 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
 }
 
 static int
-dpif_netdev_flow_del(struct dpif *dpif,
-                     const struct nlattr *nl_key, size_t nl_key_len,
-                     struct dpif_flow_stats *stats)
+dpif_netdev_flow_del(struct dpif *dpif, const struct dpif_flow_del *del)
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
     struct dp_netdev_flow *flow;
     struct flow key;
     int error;
 
-    error = dpif_netdev_flow_from_nlattrs(nl_key, nl_key_len, &key);
+    error = dpif_netdev_flow_from_nlattrs(del->key, del->key_len, &key);
     if (error) {
         return error;
     }
 
     flow = dp_netdev_lookup_flow(dp, &key);
     if (flow) {
-        if (stats) {
-            get_dpif_flow_stats(flow, stats);
+        if (del->stats) {
+            get_dpif_flow_stats(flow, del->stats);
         }
         dp_netdev_free_flow(dp, flow);
         return 0;
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 5ef4c99..d694975 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -46,8 +46,9 @@ void dpif_init(struct dpif *, const struct dpif_class *, const char *name,
                uint8_t netflow_engine_type, uint8_t netflow_engine_id);
 void dpif_uninit(struct dpif *dpif, bool close);
 
-static inline void dpif_assert_class(const struct dpif *dpif,
-                                     const struct dpif_class *dpif_class)
+static inline void dpif_assert_class(
+    const struct dpif *dpif OVS_UNUSED,
+    const struct dpif_class *dpif_class OVS_UNUSED)
 {
     assert(dpif->dpif_class == dpif_class);
 }
@@ -235,14 +236,12 @@ struct dpif_class {
 
     /* 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'.
+     * attributes with types OVS_KEY_ATTR_* in the 'del->key_len' bytes
+     * starting at 'del->key'.
      *
-     * If the operation succeeds, then 'stats', if nonnull, must be set to the
-     * flow's statistics before its deletion. */
-    int (*flow_del)(struct dpif *dpif,
-                    const struct nlattr *key, size_t key_len,
-                    struct dpif_flow_stats *stats);
+     * 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. */
diff --git a/lib/dpif.c b/lib/dpif.c
index 73696e4..0199b49 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -89,6 +89,8 @@ static void log_operation(const struct dpif *, const char *operation,
 static bool should_log_flow_message(int error);
 static void log_flow_put_message(struct dpif *, const struct dpif_flow_put *,
                                  int error);
+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 *,
                                 int error);
 
@@ -815,6 +817,21 @@ dpif_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
     return dpif_flow_put__(dpif, &put);
 }
 
+static int
+dpif_flow_del__(struct dpif *dpif, struct dpif_flow_del *del)
+{
+    int error;
+
+    COVERAGE_INC(dpif_flow_del);
+
+    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;
+}
+
 /* 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'.
@@ -826,21 +843,15 @@ dpif_flow_del(struct dpif *dpif,
               const struct nlattr *key, size_t key_len,
               struct dpif_flow_stats *stats)
 {
-    int error;
+    struct dpif_flow_del del;
 
-    COVERAGE_INC(dpif_flow_del);
-
-    error = dpif->dpif_class->flow_del(dpif, key, key_len, stats);
-    if (error && stats) {
-        memset(stats, 0, sizeof *stats);
-    }
-    if (should_log_flow_message(error)) {
-        log_flow_message(dpif, error, "flow_del", key, key_len,
-                         !error ? stats : NULL, NULL, 0);
-    }
-    return error;
+    del.key = key;
+    del.key_len = key_len;
+    del.stats = stats;
+    return dpif_flow_del__(dpif, &del);
 }
 
+
 /* Initializes 'dump' to begin dumping the flows in a dpif.
  *
  * This function provides no status indication.  An error status for the entire
@@ -994,6 +1005,10 @@ dpif_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops)
                 log_flow_put_message(dpif, &op->u.flow_put, op->error);
                 break;
 
+            case DPIF_OP_FLOW_DEL:
+                log_flow_del_message(dpif, &op->u.flow_del, op->error);
+                break;
+
             case DPIF_OP_EXECUTE:
                 log_execute_message(dpif, &op->u.execute, op->error);
                 break;
@@ -1010,6 +1025,10 @@ dpif_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops)
             op->error = dpif_flow_put__(dpif, &op->u.flow_put);
             break;
 
+        case DPIF_OP_FLOW_DEL:
+            op->error = dpif_flow_del__(dpif, &op->u.flow_del);
+            break;
+
         case DPIF_OP_EXECUTE:
             op->error = dpif_execute__(dpif, &op->u.execute);
             break;
@@ -1246,6 +1265,16 @@ log_flow_put_message(struct dpif *dpif, const struct dpif_flow_put *put,
 }
 
 static void
+log_flow_del_message(struct dpif *dpif, const struct dpif_flow_del *del,
+                     int error)
+{
+    if (should_log_flow_message(error)) {
+        log_flow_message(dpif, error, "flow_del", del->key, del->key_len,
+                         !error ? del->stats : NULL, NULL, 0);
+    }
+}
+
+static void
 log_execute_message(struct dpif *dpif, const struct dpif_execute *execute,
                     int error)
 {
diff --git a/lib/dpif.h b/lib/dpif.h
index 1a6ca05..768934b 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -177,7 +177,8 @@ int dpif_execute(struct dpif *,
 
 enum dpif_op_type {
     DPIF_OP_FLOW_PUT = 1,
-    DPIF_OP_EXECUTE
+    DPIF_OP_FLOW_DEL,
+    DPIF_OP_EXECUTE,
 };
 
 struct dpif_flow_put {
@@ -192,6 +193,15 @@ struct dpif_flow_put {
     struct dpif_flow_stats *stats;  /* Optional flow statistics. */
 };
 
+struct dpif_flow_del {
+    /* Input. */
+    const struct nlattr *key;       /* Flow to delete. */
+    size_t key_len;                 /* Length of 'key' in bytes. */
+
+    /* Output. */
+    struct dpif_flow_stats *stats;  /* Optional flow statistics. */
+};
+
 struct dpif_execute {
     const struct nlattr *key;       /* Partial flow key (only for metadata). */
     size_t key_len;                 /* Length of 'key' in bytes. */
@@ -205,6 +215,7 @@ struct dpif_op {
     int error;
     union {
         struct dpif_flow_put flow_put;
+        struct dpif_flow_del flow_del;
         struct dpif_execute execute;
     } u;
 };
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 265d6e9..594a705 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -2815,6 +2815,9 @@ handle_miss_upcalls(struct ofproto_dpif *ofproto, struct dpif_upcall *upcalls,
                 op->subfacet->installed = true;
             }
             break;
+
+        case DPIF_OP_FLOW_DEL:
+            NOT_REACHED();
         }
     }
     HMAP_FOR_EACH_SAFE (miss, next_miss, hmap_node, &todo) {
@@ -3104,18 +3107,63 @@ subfacet_max_idle(const struct ofproto_dpif *ofproto)
     return bucket * BUCKET_WIDTH;
 }
 
+enum { EXPIRE_MAX_BATCH = 50 };
+
+static void
+expire_batch(struct ofproto_dpif *ofproto, struct subfacet **subfacets, int n)
+{
+    struct odputil_keybuf keybufs[EXPIRE_MAX_BATCH];
+    struct dpif_op ops[EXPIRE_MAX_BATCH];
+    struct dpif_op *opsp[EXPIRE_MAX_BATCH];
+    struct ofpbuf keys[EXPIRE_MAX_BATCH];
+    struct dpif_flow_stats stats[EXPIRE_MAX_BATCH];
+    int i;
+
+    for (i = 0; i < n; i++) {
+        ops[i].type = DPIF_OP_FLOW_DEL;
+        subfacet_get_key(subfacets[i], &keybufs[i], &keys[i]);
+        ops[i].u.flow_del.key = keys[i].data;
+        ops[i].u.flow_del.key_len = keys[i].size;
+        ops[i].u.flow_del.stats = &stats[i];
+        opsp[i] = &ops[i];
+    }
+
+    dpif_operate(ofproto->dpif, opsp, n);
+    for (i = 0; i < n; i++) {
+        subfacet_reset_dp_stats(subfacets[i], &stats[i]);
+        subfacets[i]->installed = false;
+        subfacet_destroy(subfacets[i]);
+    }
+}
+
 static void
 expire_subfacets(struct ofproto_dpif *ofproto, int dp_max_idle)
 {
     long long int cutoff = time_msec() - dp_max_idle;
+
     struct subfacet *subfacet, *next_subfacet;
+    struct subfacet *batch[50];
+    int n_batch;
 
+    n_batch = 0;
     HMAP_FOR_EACH_SAFE (subfacet, next_subfacet, hmap_node,
                         &ofproto->subfacets) {
         if (subfacet->used < cutoff) {
-            subfacet_destroy(subfacet);
+            if (subfacet->installed) {
+                batch[n_batch++] = subfacet;
+                if (n_batch >= EXPIRE_MAX_BATCH) {
+                    expire_batch(ofproto, batch, n_batch);
+                    n_batch = 0;
+                }
+            } else {
+                subfacet_destroy(subfacet);
+            }
         }
     }
+
+    if (n_batch > 0) {
+        expire_batch(ofproto, batch, n_batch);
+    }
 }
 
 /* If 'rule' is an OpenFlow rule, that has expired according to OpenFlow rules,
-- 
1.7.9




More information about the dev mailing list