[DVR] Reconfigure re-created physical bridges for dvr routers

In case when physical bridge is removed and created again it
is initialized by neutron-ovs-agent.
But if agent has enabled distributed routing, dvr related
flows wasn't configured again and that lead to connectivity issues
in case of DVR routers.

This patch fixes it by adding configuration of dvr related flows
if distributed routing is enabled in agent's configuration.

It also adds reset list of phys_brs in dvr_agent. Without that there
were different objects used in ovs agent and dvr_agent classes thus
e.g. 2 various cookie ids were set on flows in physical bridge.
This was also the same issue in case when openvswitch was restarted and
all bridges were reconfigured.
Now in such case there is correctly new cookie_id configured for all
flows.

Conflicts:
    neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py

Change-Id: I710f00f0f542bcf7fa2fc60800797b90f9f77e14
Closes-Bug: #1864822
(cherry picked from commit 91f0bf3c85)
This commit is contained in:
Slawek Kaplonski 2020-04-21 10:30:52 +02:00
parent 774b3ff89e
commit 33217c9c43
3 changed files with 84 additions and 14 deletions

View File

@ -130,10 +130,9 @@ class OVSDVRNeutronAgent(object):
self.enable_tunneling = enable_tunneling
self.enable_distributed_routing = enable_distributed_routing
self.bridge_mappings = bridge_mappings
self.phys_brs = phys_brs
self.int_ofports = int_ofports
self.phys_ofports = phys_ofports
self.reset_ovs_parameters(integ_br, tun_br,
self.reset_ovs_parameters(integ_br, tun_br, phys_brs,
patch_int_ofport, patch_tun_ofport)
self.reset_dvr_parameters()
self.dvr_mac_address = None
@ -145,17 +144,19 @@ class OVSDVRNeutronAgent(object):
def set_firewall(self, firewall=None):
self.firewall = firewall
def setup_dvr_flows(self):
def setup_dvr_flows(self, bridge_mappings=None):
bridge_mappings = bridge_mappings or self.bridge_mappings
self.setup_dvr_flows_on_integ_br()
self.setup_dvr_flows_on_tun_br()
self.setup_dvr_flows_on_phys_br()
self.setup_dvr_flows_on_phys_br(bridge_mappings)
self.setup_dvr_mac_flows_on_all_brs()
def reset_ovs_parameters(self, integ_br, tun_br,
def reset_ovs_parameters(self, integ_br, tun_br, phys_brs,
patch_int_ofport, patch_tun_ofport):
'''Reset the openvswitch parameters'''
self.int_br = integ_br
self.tun_br = tun_br
self.phys_brs = phys_brs
self.patch_int_ofport = patch_int_ofport
self.patch_tun_ofport = patch_tun_ofport
@ -166,6 +167,15 @@ class OVSDVRNeutronAgent(object):
self.local_ports = {}
self.registered_dvr_macs = set()
def reset_dvr_flows(self, integ_br, tun_br, phys_brs,
patch_int_ofport, patch_tun_ofport,
bridge_mappings=None):
'''Reset the openvswitch and DVR parameters and DVR flows'''
self.reset_ovs_parameters(
integ_br, tun_br, phys_brs, patch_int_ofport, patch_tun_ofport)
self.reset_dvr_parameters()
self.setup_dvr_flows(bridge_mappings)
def get_dvr_mac_address(self):
try:
self.get_dvr_mac_address_with_retry()
@ -241,10 +251,10 @@ class OVSDVRNeutronAgent(object):
self.tun_br.install_goto(table_id=constants.DVR_PROCESS,
dest_table_id=constants.PATCH_LV_TO_TUN)
def setup_dvr_flows_on_phys_br(self):
def setup_dvr_flows_on_phys_br(self, bridge_mappings=None):
'''Setup up initial dvr flows into br-phys'''
for physical_network in self.bridge_mappings:
bridge_mappings = bridge_mappings or self.bridge_mappings
for physical_network in bridge_mappings:
self.phys_brs[physical_network].install_goto(
in_port=self.phys_ofports[physical_network],
priority=2,

View File

@ -1160,6 +1160,11 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
if bridge_mappings:
sync = True
self.setup_physical_bridges(bridge_mappings)
if self.enable_distributed_routing:
self.dvr_agent.reset_dvr_flows(
self.int_br, self.tun_br, self.phys_brs,
self.patch_int_ofport, self.patch_tun_ofport,
bridge_mappings)
return sync
def _check_bridge_datapath_id(self, bridge, datapath_ids_set):
@ -2202,12 +2207,9 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
# with l2pop fdb entries update
self._report_state()
if self.enable_distributed_routing:
self.dvr_agent.reset_ovs_parameters(self.int_br,
self.tun_br,
self.patch_int_ofport,
self.patch_tun_ofport)
self.dvr_agent.reset_dvr_parameters()
self.dvr_agent.setup_dvr_flows()
self.dvr_agent.reset_dvr_flows(
self.int_br, self.tun_br, self.phys_brs,
self.patch_int_ofport, self.patch_tun_ofport)
# notify that OVS has restarted
registry.notify(
callback_resources.AGENT,

View File

@ -3487,6 +3487,64 @@ class TestOvsDvrNeutronAgent(object):
self.agent.ancillary_brs = mock.Mock()
self._test_scan_ports_failure('scan_ancillary_ports')
def test_ext_br_recreated(self):
self._setup_for_dvr_test()
reset_methods = (
'reset_ovs_parameters', 'reset_dvr_parameters',
'setup_dvr_flows_on_integ_br', 'setup_dvr_flows_on_tun_br',
'setup_dvr_flows_on_phys_br', 'setup_dvr_mac_flows_on_all_brs')
for method in reset_methods:
mock.patch.object(self.agent.dvr_agent, method).start()
bridge_mappings = {'physnet0': 'br-ex0',
'physnet1': 'br-ex1'}
ex_br_mocks = [mock.Mock(br_name='br-ex0'),
mock.Mock(br_name='br-ex1')]
phys_bridges = {'physnet0': ex_br_mocks[0],
'physnet1': ex_br_mocks[1]},
bm_mock = mock.Mock()
bridges_added = ['br-ex0']
with mock.patch(
'neutron.agent.linux.ovsdb_monitor.get_bridges_monitor',
return_value=bm_mock),\
mock.patch.object(
self.agent,
'check_ovs_status',
return_value=constants.OVS_NORMAL),\
mock.patch.object(
self.agent,
'_agent_has_updates',
side_effect=TypeError('loop exit')),\
mock.patch.dict(
self.agent.bridge_mappings, bridge_mappings, clear=True),\
mock.patch.dict(
self.agent.phys_brs, phys_bridges, clear=True),\
mock.patch.object(
self.agent,
'setup_physical_bridges') as setup_physical_bridges:
bm_mock.bridges_added = bridges_added
try:
self.agent.rpc_loop(polling_manager=mock.Mock(),
bridges_monitor=bm_mock)
except TypeError:
pass
# Setup bridges should be called once even if it will raise Runtime
# Error because TypeError is raised in _agent_has_updates to stop
# agent after first loop iteration
setup_physical_bridges.assert_called_once_with({'physnet0': 'br-ex0'})
# Ensure dvr_agent methods were called correctly
self.agent.dvr_agent.reset_ovs_parameters.assert_called_once_with(
self.agent.int_br, self.agent.tun_br, self.agent.phys_brs,
self.agent.patch_int_ofport, self.agent.patch_tun_ofport)
self.agent.dvr_agent.reset_dvr_parameters.assert_called_once_with()
(self.agent.dvr_agent.setup_dvr_flows_on_phys_br.
assert_called_once_with({'physnet0': 'br-ex0'}))
(self.agent.dvr_agent.setup_dvr_flows_on_integ_br.
assert_called_once_with())
(self.agent.dvr_agent.setup_dvr_flows_on_tun_br.
assert_called_once_with())
(self.agent.dvr_agent.setup_dvr_mac_flows_on_all_brs.
assert_called_once_with())
class TestOvsDvrNeutronAgentOFCtl(TestOvsDvrNeutronAgent,
ovs_test_base.OVSOFCtlTestBase):