+/* Following a change to OpenFlow table 'table_id' in 'ofproto', update the
+ * taggability of that table.
+ *
+ * This function must be called after *each* change to a flow table. If you
+ * skip calling it on some changes then the pointer comparisons at the end can
+ * be invalid if you get unlucky. For example, if a flow removal causes a
+ * cls_table to be destroyed and then a flow insertion causes a cls_table with
+ * different wildcards to be created with the same address, then this function
+ * will incorrectly skip revalidation. */
+static void
+table_update_taggable(struct ofproto_dpif *ofproto, uint8_t table_id)
+{
+ struct table_dpif *table = &ofproto->tables[table_id];
+ const struct classifier *cls = &ofproto->up.tables[table_id];
+ struct cls_table *catchall, *other;
+ struct cls_table *t;
+
+ catchall = other = NULL;
+
+ switch (hmap_count(&cls->tables)) {
+ case 0:
+ /* We could tag this OpenFlow table but it would make the logic a
+ * little harder and it's a corner case that doesn't seem worth it
+ * yet. */
+ break;
+
+ case 1:
+ case 2:
+ HMAP_FOR_EACH (t, hmap_node, &cls->tables) {
+ if (cls_table_is_catchall(t)) {
+ catchall = t;
+ } else if (!other) {
+ other = t;
+ } else {
+ /* Indicate that we can't tag this by setting both tables to
+ * NULL. (We know that 'catchall' is already NULL.) */
+ other = NULL;
+ }
+ }
+ break;
+
+ default:
+ /* Can't tag this table. */
+ break;
+ }
+
+ if (table->catchall_table != catchall || table->other_table != other) {
+ table->catchall_table = catchall;
+ table->other_table = other;
+ ofproto->need_revalidate = true;
+ }
+}
+
+/* Given 'rule' that has changed in some way (either it is a rule being
+ * inserted, a rule being deleted, or a rule whose actions are being
+ * modified), marks facets for revalidation to ensure that packets will be
+ * forwarded correctly according to the new state of the flow table.
+ *
+ * This function must be called after *each* change to a flow table. See
+ * the comment on table_update_taggable() for more information. */
+static void
+rule_invalidate(const struct rule_dpif *rule)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+
+ table_update_taggable(ofproto, rule->up.table_id);
+
+ if (!ofproto->need_revalidate) {
+ struct table_dpif *table = &ofproto->tables[rule->up.table_id];
+
+ if (table->other_table && rule->tag) {
+ tag_set_add(&ofproto->revalidate_set, rule->tag);
+ } else {
+ ofproto->need_revalidate = true;
+ }
+ }