Divide-and-conquer local bridge flows beasts
The dump-flows action will get a very large sets of flow information
if there are enormous ports or openflow security group rules. For now
we can meet some known exception during such action, for instance,
memory issue, timeout issue.
So after this patch, the cleanup action of the bridge stale flows
will be done one table by one table. But note, this only supports
for 'native' OpenFlow interface driver.
Related-Bug: #1813703
Related-Bug: #1813712
Related-Bug: #1813709
Related-Bug: #1813708
Change-Id: Ie06d1bebe83ffeaf7130dcbb8ca21e5e59a220fb
(cherry picked from commit f898ffd71f
)
This commit is contained in:
parent
2d07a2c24f
commit
fb84771d13
|
@ -71,6 +71,20 @@ OVS_FIREWALL_TABLES = (
|
|||
RULES_INGRESS_TABLE,
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
# --- Tunnel bridge (tun_br)
|
||||
|
||||
# Various tables for tunneling flows
|
||||
|
@ -86,6 +100,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
|
||||
|
@ -93,6 +120,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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -150,11 +150,9 @@ 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})
|
||||
|
@ -163,6 +161,13 @@ class OpenFlowSwitchMixin(object):
|
|||
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("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_output(self, port, table_id=0, priority=0,
|
||||
match=None, **match_kwargs):
|
||||
(_dp, ofp, ofpp) = self._get_dp()
|
||||
|
|
|
@ -1858,13 +1858,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,
|
||||
|
|
|
@ -2248,21 +2248,28 @@ class TestOvsNeutronAgentRyu(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 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)]
|
||||
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):
|
||||
|
|
|
@ -571,10 +571,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
|
||||
|
|
Loading…
Reference in New Issue