ofproto-dpif: Disable miss handling in rule_get_stats().
authorEthan Jackson <ethan@nicira.com>
Sat, 6 Apr 2013 22:22:14 +0000 (15:22 -0700)
committerEthan Jackson <ethan@nicira.com>
Sun, 7 Apr 2013 01:26:19 +0000 (18:26 -0700)
rule_get_stats() is often called when iterating over every rule in
the flow table.  To ensure up-to-date statistics, rule_get_stats()
calls push_all_stats() which can cause flow misses to be handled.
When using the learn action, this can cause rules to be added (and
potentially removed) from the OpenFlow table.  This could corrupt
the caller's data structures, leading to a segmentation fault.
This patch fixes the issue by disabling flow miss handling from
within rule_get_stats().

Bug #15999.
Signed-off-by: Ethan Jackson <ethan@nicira.com>
ofproto/ofproto-dpif.c

index d535aad..239f8d3 100644 (file)
@@ -5109,7 +5109,7 @@ facet_push_stats(struct facet *facet)
 }
 
 static void
-push_all_stats(void)
+push_all_stats__(bool run_fast)
 {
     static long long int rl = LLONG_MIN;
     struct ofproto_dpif *ofproto;
@@ -5123,13 +5123,21 @@ push_all_stats(void)
 
         HMAP_FOR_EACH (facet, hmap_node, &ofproto->facets) {
             facet_push_stats(facet);
-            run_fast_rl();
+            if (run_fast) {
+                run_fast_rl();
+            }
         }
     }
 
     rl = time_msec() + 100;
 }
 
+static void
+push_all_stats(void)
+{
+    push_all_stats__(true);
+}
+
 static void
 rule_credit_stats(struct rule_dpif *rule, const struct dpif_flow_stats *stats)
 {
@@ -5613,7 +5621,11 @@ rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes)
     struct rule_dpif *rule = rule_dpif_cast(rule_);
     struct facet *facet;
 
-    push_all_stats();
+    /* push_all_stats() can handle flow misses which, when using the learn
+     * action, can cause rules to be added and deleted.  This can corrupt our
+     * caller's datastructures which assume that rule_get_stats() doesn't have
+     * an impact on the flow table. To be safe, we disable miss handling. */
+    push_all_stats__(false);
 
     /* Start from historical data for 'rule' itself that are no longer tracked
      * in facets.  This counts, for example, facets that have expired. */