diff -crB --new-file neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py
*** neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py	2019-07-17 11:57:05.891052340 -0700
***************
*** 69,74 ****
--- 69,86 ----
  )
  
  ## Tunnel bridge (tun_br)
+ INT_BR_ALL_TABLES = (
+     LOCAL_SWITCHING,
+     DVR_TO_SRC_MAC,
+     DVR_TO_SRC_MAC_VLAN,
+     CANARY_TABLE,
+     ARP_SPOOF_TABLE,
+     MAC_SPOOF_TABLE,
+     BASE_EGRESS_TABLE,
+     RULES_EGRESS_TABLE,
+     ACCEPT_OR_INGRESS_TABLE,
+     BASE_INGRESS_TABLE,
+     RULES_INGRESS_TABLE)
  
  # Various tables for tunneling flows
  DVR_PROCESS = 1
***************
*** 84,89 ****
--- 96,113 ----
  FLOOD_TO_TUN = 22
  
  ## Physical Bridges (phys_brs)
+ TUN_BR_ALL_TABLES = (
+     LOCAL_SWITCHING,
+     DVR_PROCESS,
+     PATCH_LV_TO_TUN,
+     GRE_TUN_TO_LV,
+     VXLAN_TUN_TO_LV,
+     GENEVE_TUN_TO_LV,
+     DVR_NOT_LEARN,
+     LEARN_FROM_TUN,
+     UCAST_TO_TUN,
+     ARP_RESPONDER,
+     FLOOD_TO_TUN)
  
  # Various tables for DVR use of physical bridge flows
  DVR_PROCESS_VLAN = 1
***************
*** 90,96 ****
--- 114,126 ----
  LOCAL_VLAN_TRANSLATION = 2
  DVR_NOT_LEARN_VLAN = 3
  
+ 
  ### end of OpenFlow table IDs
+ PHY_BR_ALL_TABLES = (
+     LOCAL_SWITCHING,
+     DVR_PROCESS_VLAN,
+     LOCAL_VLAN_TRANSLATION,
+     DVR_NOT_LEARN_VLAN)
  
  # type for ARP reply in ARP header
  ARP_REPLY = '0x2'
diff -crB --new-file neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py
*** neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py	2019-07-17 11:57:05.891052340 -0700
***************
*** 39,44 ****
--- 39,46 ----
  class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
      """openvswitch agent br-int specific logic."""
  
+     of_tables = constants.INT_BR_ALL_TABLES
+ 
      def setup_default_table(self):
          self.setup_canary_table()
          self.install_normal()
diff -crB --new-file neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_phys.py neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_phys.py
*** neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_phys.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_phys.py	2019-07-17 11:57:05.891052340 -0700
***************
*** 28,33 ****
--- 28,34 ----
      # Used by OVSDVRProcessMixin
      dvr_process_table_id = constants.DVR_PROCESS_VLAN
      dvr_process_next_table_id = constants.LOCAL_VLAN_TRANSLATION
+     of_tables = constants.PHY_BR_ALL_TABLES
  
      def setup_default_table(self):
          self.install_normal()
diff -crB --new-file neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py
*** neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py	2019-07-17 11:57:05.891052340 -0700
***************
*** 46,51 ****
--- 46,52 ----
      # Used by OVSDVRProcessMixin
      dvr_process_table_id = constants.DVR_PROCESS
      dvr_process_next_table_id = constants.PATCH_LV_TO_TUN
+     of_tables = constants.TUN_BR_ALL_TABLES
  
      def setup_default_table(self, patch_int_ofport, arp_responder_enabled):
          (dp, ofp, ofpp) = self._get_dp()
diff -crB --new-file neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py
*** neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py	2019-07-17 11:57:05.895052368 -0700
***************
*** 23,29 ****
  import ryu.app.ofctl.api as ofctl_api
  import ryu.exception as ryu_exc
  
! from neutron._i18n import _, _LW
  
  LOG = logging.getLogger(__name__)
  
--- 23,29 ----
  import ryu.app.ofctl.api as ofctl_api
  import ryu.exception as ryu_exc
  
! from neutron._i18n import _, _LW, _LI
  
  LOG = logging.getLogger(__name__)
  
***************
*** 134,144 ****
              flows += rep.body
          return flows
  
!     def cleanup_flows(self):
!         cookies = set([f.cookie for f in self.dump_flows()]) - \
!                   self.reserved_cookies
!         LOG.debug("Reserved cookies for %s: %s", self.br_name,
!                   self.reserved_cookies)
          for c in cookies:
              LOG.warning(_LW("Deleting flow with cookie 0x%(cookie)x"),
                          {'cookie': c})
--- 134,142 ----
              flows += rep.body
          return flows
  
!     def _dump_and_clean(self, table_id=None):
!         cookies = set([f.cookie for f in self.dump_flows(table_id)]) - \
!                       self.reserved_cookies
          for c in cookies:
              LOG.warning(_LW("Deleting flow with cookie 0x%(cookie)x"),
                          {'cookie': c})
***************
*** 147,152 ****
--- 145,158 ----
      def install_goto_next(self, table_id):
          self.install_goto(table_id=table_id, dest_table_id=table_id + 1)
  
+     def cleanup_flows(self):
+         LOG.info(_LI("Reserved cookies for %(br_name)s: %(cookie)s"),
+                  {'br_name': self.br_name,
+                   'cookie': self.reserved_cookies})
+ 
+         for table_id in self.of_tables:
+             self._dump_and_clean(table_id)
+ 
      def install_output(self, port, table_id=0, priority=0,
                         match=None, **match_kwargs):
          (_dp, ofp, ofpp) = self._get_dp()
diff -crB --new-file neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py
*** neutron-9.4.2.dev21-original/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py	2019-07-17 11:54:54.118130494 -0700
--- neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py	2019-07-17 11:59:29.636040672 -0700
***************
*** 1846,1858 ****
          return port_stats
  
      def cleanup_stale_flows(self):
!         bridges = [self.int_br]
!         bridges.extend(self.phys_brs.values())
          if self.enable_tunneling:
!             bridges.append(self.tun_br)
!         for bridge in bridges:
!             LOG.info(_LI("Cleaning stale %s flows"), bridge.br_name)
!             bridge.cleanup_flows()
  
      def process_port_info(self, start, polling_manager, sync, ovs_restarted,
                         ports, ancillary_ports, updated_ports_copy,
--- 1846,1860 ----
          return port_stats
  
      def cleanup_stale_flows(self):
!         LOG.info(_LI("Cleaning stale %s flows"), self.int_br.br_name)
!         self.int_br.cleanup_flows()
!         for pby_br in self.phys_brs.values():
!             LOG.info(_LI("Cleaning stale %s flows"), pby_br.br_name)
!             pby_br.cleanup_flows()
! 
          if self.enable_tunneling:
!             LOG.info(_LI("Cleaning stale %s flows"), self.tun_br.br_name)
!             self.tun_br.cleanup_flows()
  
      def process_port_info(self, start, polling_manager, sync, ovs_restarted,
                         ports, ancillary_ports, updated_ports_copy,
diff -crB --new-file neutron-9.4.2.dev21-original/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py neutron-9.4.2.dev21/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py
*** neutron-9.4.2.dev21-original/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py	2019-07-17 11:54:54.122130524 -0700
--- neutron-9.4.2.dev21/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py	2019-07-17 11:57:05.895052368 -0700
***************
*** 2123,2143 ****
                  mock.patch.object(self.agent.int_br,
                                    'delete_flows') as del_flow:
              self.agent.int_br.set_agent_uuid_stamp(1234)
!             dump_flows.return_value = [
                  # mock ryu.ofproto.ofproto_v1_3_parser.OFPFlowStats
                  mock.Mock(cookie=1234, table_id=0),
                  mock.Mock(cookie=17185, table_id=2),
                  mock.Mock(cookie=9029, table_id=2),
                  mock.Mock(cookie=1234, table_id=3),
              ]
              self.agent.iter_num = 3
              self.agent.cleanup_stale_flows()
              expected = [mock.call(cookie=17185,
                                    cookie_mask=uint64_max),
                          mock.call(cookie=9029,
                                    cookie_mask=uint64_max)]
              del_flow.assert_has_calls(expected, any_order=True)
!             self.assertEqual(len(expected), len(del_flow.mock_calls))
  
  
  class AncillaryBridgesTest(object):
--- 2123,2150 ----
                  mock.patch.object(self.agent.int_br,
                                    'delete_flows') as del_flow:
              self.agent.int_br.set_agent_uuid_stamp(1234)
!             fake_flows = [
                  # mock ryu.ofproto.ofproto_v1_3_parser.OFPFlowStats
                  mock.Mock(cookie=1234, table_id=0),
                  mock.Mock(cookie=17185, table_id=2),
                  mock.Mock(cookie=9029, table_id=2),
                  mock.Mock(cookie=1234, table_id=3),
              ]
+             dump_flows.return_value = fake_flows
              self.agent.iter_num = 3
              self.agent.cleanup_stale_flows()
+ 
+             dump_flows_expected = [
+                 mock.call(tid) for tid in constants.INT_BR_ALL_TABLES]
+             dump_flows.assert_has_calls(dump_flows_expected)
+ 
              expected = [mock.call(cookie=17185,
                                    cookie_mask=uint64_max),
                          mock.call(cookie=9029,
                                    cookie_mask=uint64_max)]
              del_flow.assert_has_calls(expected, any_order=True)
!             self.assertEqual(len(constants.INT_BR_ALL_TABLES) * len(expected),
!                              len(uninstall_flows.mock_calls))
  
  
  class AncillaryBridgesTest(object):
diff -crB --new-file neutron-9.4.2.dev21-original/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py neutron-9.4.2.dev21/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py
*** neutron-9.4.2.dev21-original/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py	2019-07-17 11:52:30.165056054 -0700
--- neutron-9.4.2.dev21/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py	2019-07-17 11:57:05.899052396 -0700
***************
*** 565,576 ****
              mock.call.cleanup_flows(),
              mock.call.check_canary_table()
          ]
-         self.mock_tun_bridge_expected += [
-             mock.call.cleanup_flows()
-         ]
          self.mock_map_tun_bridge_expected += [
              mock.call.cleanup_flows()
          ]
          # No cleanup is expected on ancillary bridge
  
          self.ovs_bridges[self.INT_BRIDGE].check_canary_table.return_value = \
--- 565,576 ----
              mock.call.cleanup_flows(),
              mock.call.check_canary_table()
          ]
          self.mock_map_tun_bridge_expected += [
              mock.call.cleanup_flows()
          ]
+         self.mock_tun_bridge_expected += [
+             mock.call.cleanup_flows()
+         }
          # No cleanup is expected on ancillary bridge
  
          self.ovs_bridges[self.INT_BRIDGE].check_canary_table.return_value = \
