ofproto-dpif: Handle tunnel config changes in facet_revalidate().
authorEthan Jackson <ethan@nicira.com>
Wed, 27 Feb 2013 03:12:22 +0000 (19:12 -0800)
committerEthan Jackson <ethan@nicira.com>
Thu, 28 Feb 2013 00:48:59 +0000 (16:48 -0800)
For most of the history of Open vSwitch, one could assume that a
given datapath flow key would consistently translate into the same
userspace struct flow representation.  However, with the switch to
flow based tunneling, we now have a situation where a database
configuration change can cause a datapath flow key's in_port to
correspond to a completely different OpenFlow in_port possibly on a
completely different bridge.  This can cause all sorts of problems,
including traffic black holes due to confused facet revalidations.

To solve the problem, this patch verifies that each facet's
subfacets still result in the appropriate struct flow.  If a facet
fails this test, it is simply removed.

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

index 9405f1d..7035530 100644 (file)
@@ -912,13 +912,13 @@ type_run(const char *type)
         backer->need_revalidate = 0;
 
         HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
-            struct facet *facet;
+            struct facet *facet, *next;
 
             if (ofproto->backer != backer) {
                 continue;
             }
 
-            HMAP_FOR_EACH (facet, hmap_node, &ofproto->facets) {
+            HMAP_FOR_EACH_SAFE (facet, next, hmap_node, &ofproto->facets) {
                 if (need_revalidate
                     || tag_set_intersects(&revalidate_set, facet->tags)) {
                     facet_revalidate(facet);
@@ -4582,6 +4582,9 @@ facet_lookup_valid(struct ofproto_dpif *ofproto, const struct flow *flow,
             || tag_set_intersects(&ofproto->backer->revalidate_set,
                                   facet->tags))) {
         facet_revalidate(facet);
+
+        /* facet_revalidate() may have destroyed 'facet'. */
+        facet = facet_find(ofproto, flow, hash);
     }
 
     return facet;
@@ -4741,7 +4744,10 @@ facet_check_consistency(struct facet *facet)
  *     'facet' to the new rule and recompiles its actions.
  *
  *   - If the rule found is the same as 'facet''s current rule, leaves 'facet'
- *     where it is and recompiles its actions anyway. */
+ *     where it is and recompiles its actions anyway.
+ *
+ *   - If any of 'facet''s subfacets correspond to a new flow according to
+ *     ofproto_receive(), 'facet' is removed. */
 static void
 facet_revalidate(struct facet *facet)
 {
@@ -4762,6 +4768,25 @@ facet_revalidate(struct facet *facet)
 
     COVERAGE_INC(facet_revalidate);
 
+    /* Check that child subfacets still correspond to this facet.  Tunnel
+     * configuration changes could cause a subfacet's OpenFlow in_port to
+     * change. */
+    LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
+        struct ofproto_dpif *recv_ofproto;
+        struct flow recv_flow;
+        int error;
+
+        error = ofproto_receive(ofproto->backer, NULL, subfacet->key,
+                                subfacet->key_len, &recv_flow, NULL,
+                                &recv_ofproto, NULL, NULL);
+        if (error
+            || recv_ofproto != ofproto
+            || memcmp(&recv_flow, &facet->flow, sizeof recv_flow)) {
+            facet_remove(facet);
+            return;
+        }
+    }
+
     new_rule = rule_dpif_lookup(ofproto, &facet->flow);
 
     /* Calculate new datapath actions.