diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py b/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py index 11d5d6cba27..7ebe6566012 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py @@ -77,6 +77,23 @@ ACCEPTED_INGRESS_TRAFFIC_TABLE = 92 DROPPED_TRAFFIC_TABLE = 93 ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE = 94 +INT_BR_ALL_TABLES = ( + LOCAL_SWITCHING, + DVR_TO_SRC_MAC, + DVR_TO_SRC_MAC_VLAN, + CANARY_TABLE, + ARP_SPOOF_TABLE, + MAC_SPOOF_TABLE, + TRANSIENT_TABLE, + BASE_EGRESS_TABLE, + RULES_EGRESS_TABLE, + ACCEPT_OR_INGRESS_TABLE, + BASE_INGRESS_TABLE, + RULES_INGRESS_TABLE, + ACCEPTED_EGRESS_TRAFFIC_TABLE, + ACCEPTED_INGRESS_TRAFFIC_TABLE, + DROPPED_TRAFFIC_TABLE) + # --- Tunnel bridge (tun_br) # Various tables for tunneling flows @@ -92,6 +109,19 @@ UCAST_TO_TUN = 20 ARP_RESPONDER = 21 FLOOD_TO_TUN = 22 +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) + # --- Physical Bridges (phys_brs) # Various tables for DVR use of physical bridge flows @@ -99,6 +129,12 @@ DVR_PROCESS_VLAN = 1 LOCAL_VLAN_TRANSLATION = 2 DVR_NOT_LEARN_VLAN = 3 +PHY_BR_ALL_TABLES = ( + LOCAL_SWITCHING, + DVR_PROCESS_VLAN, + LOCAL_VLAN_TRANSLATION, + DVR_NOT_LEARN_VLAN) + # --- end of OpenFlow table IDs # type for ARP reply in ARP header diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py index 019685d3885..54af6d7a850 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py @@ -38,6 +38,8 @@ LOG = logging.getLogger(__name__) 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_goto(dest_table_id=constants.TRANSIENT_TABLE) diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_phys.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_phys.py index cfbed539732..ec8259ee35a 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_phys.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_phys.py @@ -28,6 +28,7 @@ class OVSPhysicalBridge(ovs_bridge.OVSAgentBridge, # 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 --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py index 853eb6caf3f..f361d082dc2 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py @@ -46,6 +46,7 @@ class OVSTunnelBridge(ovs_bridge.OVSAgentBridge, # 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 --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py index 491efff4a1b..e816d99e3d2 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py @@ -166,16 +166,21 @@ class OpenFlowSwitchMixin(object): 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) + 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("Deleting flow with cookie 0x%(cookie)x", {'cookie': c}) self.uninstall_flows(cookie=c, cookie_mask=ovs_lib.UINT64_BITMASK) + def cleanup_flows(self): + LOG.info("Reserved cookies for %s: %s", self.br_name, + self.reserved_cookies) + + for table_id in self.of_tables: + self._dump_and_clean(table_id) + def install_goto_next(self, table_id, active_bundle=None): self.install_goto(table_id=table_id, dest_table_id=table_id + 1, active_bundle=active_bundle) diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py index eea4651c010..8e35d845c9d 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -1971,13 +1971,15 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin, return port_stats def cleanup_stale_flows(self): - bridges = [self.int_br] - bridges.extend(self.phys_brs.values()) + LOG.info("Cleaning stale %s flows", self.int_br.br_name) + self.int_br.cleanup_flows() + for pby_br in self.phys_brs.values(): + LOG.info("Cleaning stale %s flows", pby_br.br_name) + pby_br.cleanup_flows() + if self.enable_tunneling: - bridges.append(self.tun_br) - for bridge in bridges: - LOG.info("Cleaning stale %s flows", bridge.br_name) - bridge.cleanup_flows() + LOG.info("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 --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py index 0ca8722fe4f..7c7e6eeb8b9 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py @@ -2395,21 +2395,28 @@ class TestOvsNeutronAgentOSKen(TestOvsNeutronAgent, mock.patch.object(self.agent.int_br, 'uninstall_flows') as uninstall_flows: self.agent.int_br.set_agent_uuid_stamp(1234) - dump_flows.return_value = [ + fake_flows = [ # mock os_ken.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)] uninstall_flows.assert_has_calls(expected, any_order=True) - self.assertEqual(len(expected), len(uninstall_flows.mock_calls)) + self.assertEqual(len(constants.INT_BR_ALL_TABLES) * len(expected), + len(uninstall_flows.mock_calls)) class AncillaryBridgesTest(object): diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py index 0d81fb2170b..e6645398961 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py @@ -579,10 +579,10 @@ class TunnelTest(object): 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(), + ] + self.mock_tun_bridge_expected += [ mock.call.cleanup_flows() ] # No cleanup is expected on ancillary bridge