ofproto-dpif-xlate: Cache xlate_actions() effects.
[sliver-openvswitch.git] / ofproto / ofproto-dpif-upcall.c
index 938cfde..9bf1336 100644 (file)
@@ -168,6 +168,9 @@ struct udpif_key {
     bool mark;                     /* Used by mark and sweep GC algorithm. */
 
     struct odputil_keybuf key_buf; /* Memory for 'key'. */
+    struct xlate_cache *xcache;    /* Cache for xlate entries that
+                                    * are affected by this ukey.
+                                    * Used for stats and learning.*/
 };
 
 /* 'udpif_flow_dump's hold the state associated with one iteration in a flow
@@ -1314,6 +1317,7 @@ ukey_create(const struct nlattr *key, size_t key_len, long long int used)
     ukey->mark = false;
     ukey->created = used ? used : time_msec();
     memset(&ukey->stats, 0, sizeof ukey->stats);
+    ukey->xcache = NULL;
 
     return ukey;
 }
@@ -1322,6 +1326,7 @@ static void
 ukey_delete(struct revalidator *revalidator, struct udpif_key *ukey)
 {
     hmap_remove(&revalidator->ukeys, &ukey->hmap_node);
+    xlate_cache_delete(ukey->xcache);
     free(ukey);
 }
 
@@ -1341,12 +1346,13 @@ revalidate_ukey(struct udpif *udpif, struct udpif_flow_dump *udump,
     struct xlate_in xin;
     int error;
     size_t i;
-    bool ok;
+    bool may_learn, ok;
 
     ok = false;
     xoutp = NULL;
     actions = NULL;
     netflow = NULL;
+    may_learn = push.n_packets > 0;
 
     /* If we don't need to revalidate, we can simply push the stats contained
      * in the udump, otherwise we'll have to get the actions so we can check
@@ -1373,15 +1379,29 @@ revalidate_ukey(struct udpif *udpif, struct udpif_flow_dump *udump,
         goto exit;
     }
 
+    if (ukey->xcache && !udump->need_revalidate) {
+        xlate_push_stats(ukey->xcache, may_learn, &push);
+        ok = true;
+        goto exit;
+    }
+
     error = xlate_receive(udpif->backer, NULL, ukey->key, ukey->key_len, &flow,
                           &ofproto, NULL, NULL, &netflow, &odp_in_port);
     if (error) {
         goto exit;
     }
 
+    if (udump->need_revalidate) {
+        xlate_cache_clear(ukey->xcache);
+    }
+    if (!ukey->xcache) {
+        ukey->xcache = xlate_cache_new();
+    }
+
     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.xcache = ukey->xcache;
+    xin.may_learn = may_learn;
     xin.skip_wildcards = !udump->need_revalidate;
     xlate_actions(&xin, &xout);
     xoutp = &xout;
@@ -1487,6 +1507,13 @@ push_dump_ops(struct revalidator *revalidator,
             struct ofproto_dpif *ofproto;
             struct netflow *netflow;
             struct flow flow;
+            bool may_learn;
+
+            may_learn = push->n_packets > 0;
+            if (op->ukey && op->ukey->xcache) {
+                xlate_push_stats(op->ukey->xcache, may_learn, push);
+                continue;
+            }
 
             if (!xlate_receive(udpif->backer, NULL, op->op.u.flow_del.key,
                                op->op.u.flow_del.key_len, &flow, &ofproto,
@@ -1496,7 +1523,7 @@ push_dump_ops(struct revalidator *revalidator,
                 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.may_learn = may_learn;
                 xin.skip_wildcards = true;
                 xlate_actions_for_side_effects(&xin);