From: Ethan Jackson Date: Wed, 27 Feb 2013 03:12:22 +0000 (-0800) Subject: ofproto-dpif: Handle tunnel config changes in facet_revalidate(). X-Git-Tag: sliver-openvswitch-1.10.90-1~10^2~124 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=f231418e8b95f3a0baf930dee587a2bb271ae196;p=sliver-openvswitch.git ofproto-dpif: Handle tunnel config changes in facet_revalidate(). 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 --- diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 9405f1dcb..703553014 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -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.