upcall: Refactor ukey creation and dump handling
authorJoe Stringer <joestringer@nicira.com>
Tue, 11 Feb 2014 21:55:34 +0000 (13:55 -0800)
committerBen Pfaff <blp@nicira.com>
Wed, 26 Feb 2014 00:11:22 +0000 (16:11 -0800)
This splits out functions for re-use by later patches, and compacts the
udump revalidation code.

Co-authored-by: Ethan Jackson <ethan@nicira.com>
Signed-off-by: Joe Stringer <joestringer@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Conflicts:
ofproto/ofproto-dpif-upcall.c

ofproto/ofproto-dpif-upcall.c

index 7ff55a0..fa718a2 100644 (file)
@@ -1262,6 +1262,22 @@ ukey_lookup(struct revalidator *revalidator, struct udpif_flow_dump *udump)
     return NULL;
 }
 
+static struct udpif_key *
+ukey_create(const struct nlattr *key, size_t key_len, long long int used)
+{
+    struct udpif_key *ukey = xmalloc(sizeof *ukey);
+
+    ukey->key = (struct nlattr *) &ukey->key_buf;
+    memcpy(&ukey->key_buf, key, key_len);
+    ukey->key_len = key_len;
+
+    ukey->mark = false;
+    ukey->created = used ? used : time_msec();
+    memset(&ukey->stats, 0, sizeof ukey->stats);
+
+    return ukey;
+}
+
 static void
 ukey_delete(struct revalidator *revalidator, struct udpif_key *ukey)
 {
@@ -1370,22 +1386,101 @@ exit:
     return ok;
 }
 
+struct dump_op {
+    struct udpif_key *ukey;
+    struct udpif_flow_dump *udump;
+    struct dpif_flow_stats stats; /* Stats for 'op'. */
+    struct dpif_op op;            /* Flow del operation. */
+};
+
 static void
-revalidate_udumps(struct revalidator *revalidator, struct list *udumps)
+dump_op_init(struct dump_op *op, const struct nlattr *key, size_t key_len,
+             struct udpif_key *ukey, struct udpif_flow_dump *udump)
+{
+    op->ukey = ukey;
+    op->udump = udump;
+    op->op.type = DPIF_OP_FLOW_DEL;
+    op->op.u.flow_del.key = key;
+    op->op.u.flow_del.key_len = key_len;
+    op->op.u.flow_del.stats = &op->stats;
+}
+
+static void
+push_dump_ops(struct revalidator *revalidator,
+              struct dump_op *ops, size_t n_ops)
 {
     struct udpif *udpif = revalidator->udpif;
+    struct dpif_op *opsp[REVALIDATE_MAX_BATCH];
+    size_t i;
 
-    struct dump_op {
-        struct udpif_key *ukey;
-        struct udpif_flow_dump *udump;
-        struct dpif_flow_stats stats; /* Stats for 'op'. */
-        struct dpif_op op;            /* Flow del operation. */
-    };
+    ovs_assert(n_ops <= REVALIDATE_MAX_BATCH);
+    for (i = 0; i < n_ops; i++) {
+        opsp[i] = &ops[i].op;
+    }
+    dpif_operate(udpif->dpif, opsp, n_ops);
+
+    for (i = 0; i < n_ops; i++) {
+        struct dump_op *op = &ops[i];
+        struct dpif_flow_stats *push, *stats, push_buf;
+
+        stats = op->op.u.flow_del.stats;
+        if (op->ukey) {
+            push = &push_buf;
+            push->used = MAX(stats->used, op->ukey->stats.used);
+            push->tcp_flags = stats->tcp_flags | op->ukey->stats.tcp_flags;
+            push->n_packets = stats->n_packets - op->ukey->stats.n_packets;
+            push->n_bytes = stats->n_bytes - op->ukey->stats.n_bytes;
+        } else {
+            push = stats;
+        }
+
+        if (push->n_packets || netflow_exists()) {
+            struct ofproto_dpif *ofproto;
+            struct netflow *netflow;
+            struct flow flow;
+
+            if (!xlate_receive(udpif->backer, NULL, op->op.u.flow_del.key,
+                               op->op.u.flow_del.key_len, &flow, NULL,
+                               &ofproto, NULL, NULL, &netflow, NULL)) {
+                struct xlate_in xin;
+
+                xlate_in_init(&xin, ofproto, &flow, NULL, push->tcp_flags,
+                              NULL);
+                xin.resubmit_stats = push->n_packets ? push : NULL;
+                xin.may_learn = push->n_packets > 0;
+                xin.skip_wildcards = true;
+                xlate_actions_for_side_effects(&xin);
+
+                if (netflow) {
+                    netflow_expire(netflow, &flow);
+                    netflow_flow_clear(netflow, &flow);
+                    netflow_unref(netflow);
+                }
+            }
+        }
+    }
+
+    for (i = 0; i < n_ops; i++) {
+        struct udpif_key *ukey = ops[i].ukey;
+
+        /* Look up the ukey to prevent double-free in case 'ops' contains a
+         * given ukey more than once (which can happen if the datapath dumps a
+         * given flow more than once). */
+        ukey = ukey_lookup(revalidator, ops[i].udump);
+        if (ukey) {
+            ukey_delete(revalidator, ukey);
+        }
+    }
+}
+
+static void
+revalidate_udumps(struct revalidator *revalidator, struct list *udumps)
+{
+    struct udpif *udpif = revalidator->udpif;
 
     struct dump_op ops[REVALIDATE_MAX_BATCH];
-    struct dpif_op *opsp[REVALIDATE_MAX_BATCH];
     struct udpif_flow_dump *udump, *next_udump;
-    size_t n_ops, i, n_flows;
+    size_t n_ops, n_flows;
     unsigned int flow_limit;
     long long int max_idle;
     bool must_del;
@@ -1416,30 +1511,13 @@ revalidate_udumps(struct revalidator *revalidator, struct list *udumps)
 
         if (must_del || (used && used < now - max_idle)) {
             struct dump_op *dop = &ops[n_ops++];
-            struct dpif_op *op = &dop->op;
-
-            dop->ukey = ukey;
-            dop->udump = udump;
-            op->type = DPIF_OP_FLOW_DEL;
-            op->u.flow_del.key = udump->key;
-            op->u.flow_del.key_len = udump->key_len;
-            op->u.flow_del.stats = &ops[n_ops].stats;
 
+            dump_op_init(dop, udump->key, udump->key_len, ukey, udump);
             continue;
         }
 
         if (!ukey) {
-            ukey = xmalloc(sizeof *ukey);
-
-            ukey->key = (struct nlattr *) &ukey->key_buf;
-            memcpy(ukey->key, udump->key, udump->key_len);
-            ukey->key_len = udump->key_len;
-
-            ukey->created = used ? used : now;
-            memset(&ukey->stats, 0, sizeof ukey->stats);
-
-            ukey->mark = false;
-
+            ukey = ukey_create(udump->key, udump->key_len, used);
             hmap_insert(&revalidator->ukeys, &ukey->hmap_node,
                         udump->key_hash);
         }
@@ -1454,57 +1532,7 @@ revalidate_udumps(struct revalidator *revalidator, struct list *udumps)
         free(udump);
     }
 
-    for (i = 0; i < n_ops; i++) {
-        opsp[i] = &ops[i].op;
-    }
-    dpif_operate(udpif->dpif, opsp, n_ops);
-
-    for (i = 0; i < n_ops; i++) {
-        struct dpif_flow_stats push, *stats, *ukey_stats;
-
-        ukey_stats = &ops[i].ukey->stats;
-        stats = ops[i].op.u.flow_del.stats;
-        push.used = MAX(stats->used, ukey_stats->used);
-        push.tcp_flags = stats->tcp_flags | ukey_stats->tcp_flags;
-        push.n_packets = stats->n_packets - ukey_stats->n_packets;
-        push.n_bytes = stats->n_bytes - ukey_stats->n_bytes;
-
-        if (push.n_packets || netflow_exists()) {
-            struct ofproto_dpif *ofproto;
-            struct netflow *netflow;
-            struct flow flow;
-
-            if (!xlate_receive(udpif->backer, NULL, ops[i].op.u.flow_del.key,
-                               ops[i].op.u.flow_del.key_len, &flow, NULL,
-                               &ofproto, NULL, NULL, &netflow, NULL)) {
-                struct xlate_in xin;
-
-                xlate_in_init(&xin, ofproto, &flow, NULL, push.tcp_flags,
-                              NULL);
-                xin.resubmit_stats = push.n_packets ? &push : NULL;
-                xin.may_learn = push.n_packets > 0;
-                xin.skip_wildcards = true;
-                xlate_actions_for_side_effects(&xin);
-
-                if (netflow) {
-                    netflow_expire(netflow, &flow);
-                    netflow_flow_clear(netflow, &flow);
-                    netflow_unref(netflow);
-                }
-            }
-        }
-    }
-
-    for (i = 0; i < n_ops; i++) {
-        struct udpif_key *ukey = ops[i].ukey;
-
-        /* Look up the ukey to prevent double-free if the datapath dumps the
-         * same flow twice. */
-        ukey = ukey_lookup(revalidator, ops[i].udump);
-        if (ukey) {
-            ukey_delete(revalidator, ukey);
-        }
-    }
+    push_dump_ops(revalidator, ops, n_ops);
 
     LIST_FOR_EACH_SAFE (udump, next_udump, list_node, udumps) {
         list_remove(&udump->list_node);