Merge "ML2: update port's status to DOWN if its binding info has changed"
This commit is contained in:
commit
fea9e09816
|
@ -38,7 +38,6 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
|||
def initialize(self):
|
||||
LOG.debug("Experimental L2 population driver")
|
||||
self.rpc_ctx = n_context.get_admin_context_without_session()
|
||||
self.migrated_ports = {}
|
||||
|
||||
def _get_port_fdb_entries(self, port):
|
||||
return [l2pop_rpc.PortInfo(mac_address=port['mac_address'],
|
||||
|
@ -48,8 +47,8 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
|||
def delete_port_postcommit(self, context):
|
||||
port = context.current
|
||||
agent_host = context.host
|
||||
|
||||
fdb_entries = self._get_agent_fdb(context, port, agent_host)
|
||||
fdb_entries = self._get_agent_fdb(context.bottom_bound_segment,
|
||||
port, agent_host)
|
||||
self.L2populationAgentNotify.remove_fdb_entries(self.rpc_ctx,
|
||||
fdb_entries)
|
||||
|
||||
|
@ -122,50 +121,41 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
|||
if context.status == const.PORT_STATUS_DOWN:
|
||||
agent_host = context.host
|
||||
fdb_entries = self._get_agent_fdb(
|
||||
context, port, agent_host)
|
||||
context.bottom_bound_segment, port, agent_host)
|
||||
self.L2populationAgentNotify.remove_fdb_entries(
|
||||
self.rpc_ctx, fdb_entries)
|
||||
elif (context.host != context.original_host
|
||||
and context.status == const.PORT_STATUS_ACTIVE
|
||||
and not self.migrated_ports.get(orig['id'])):
|
||||
# The port has been migrated. We have to store the original
|
||||
# binding to send appropriate fdb once the port will be set
|
||||
# on the destination host
|
||||
self.migrated_ports[orig['id']] = (
|
||||
(orig, context.original_host))
|
||||
and context.original_status == const.PORT_STATUS_ACTIVE
|
||||
and context.status == const.PORT_STATUS_DOWN):
|
||||
# The port has been migrated. Send notification about port
|
||||
# removal from old host.
|
||||
fdb_entries = self._get_agent_fdb(
|
||||
context.original_bottom_bound_segment,
|
||||
orig, context.original_host)
|
||||
self.L2populationAgentNotify.remove_fdb_entries(
|
||||
self.rpc_ctx, fdb_entries)
|
||||
elif context.status != context.original_status:
|
||||
if context.status == const.PORT_STATUS_ACTIVE:
|
||||
self._update_port_up(context)
|
||||
elif context.status == const.PORT_STATUS_DOWN:
|
||||
fdb_entries = self._get_agent_fdb(
|
||||
context, port, context.host)
|
||||
self.L2populationAgentNotify.remove_fdb_entries(
|
||||
self.rpc_ctx, fdb_entries)
|
||||
elif context.status == const.PORT_STATUS_BUILD:
|
||||
orig = self.migrated_ports.pop(port['id'], None)
|
||||
if orig:
|
||||
original_port = orig[0]
|
||||
original_host = orig[1]
|
||||
# this port has been migrated: remove its entries from fdb
|
||||
fdb_entries = self._get_agent_fdb(
|
||||
context, original_port, original_host)
|
||||
context.bottom_bound_segment, port, context.host)
|
||||
self.L2populationAgentNotify.remove_fdb_entries(
|
||||
self.rpc_ctx, fdb_entries)
|
||||
|
||||
def _get_and_validate_segment(self, context, port_id, agent):
|
||||
segment = context.bottom_bound_segment
|
||||
def _validate_segment(self, segment, port_id, agent):
|
||||
if not segment:
|
||||
LOG.debug("Port %(port)s updated by agent %(agent)s isn't bound "
|
||||
"to any segment", {'port': port_id, 'agent': agent})
|
||||
return
|
||||
return False
|
||||
|
||||
network_types = l2pop_db.get_agent_l2pop_network_types(agent)
|
||||
if network_types is None:
|
||||
network_types = l2pop_db.get_agent_tunnel_types(agent)
|
||||
if segment['network_type'] not in network_types:
|
||||
return
|
||||
return False
|
||||
|
||||
return segment
|
||||
return True
|
||||
|
||||
def _create_agent_fdb(self, session, agent, segment, network_id):
|
||||
agent_fdb_entries = {network_id:
|
||||
|
@ -220,8 +210,8 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
|||
session, agent_host, network_id)
|
||||
|
||||
agent_ip = l2pop_db.get_agent_ip(agent)
|
||||
segment = self._get_and_validate_segment(context, port['id'], agent)
|
||||
if not segment:
|
||||
segment = context.bottom_bound_segment
|
||||
if not self._validate_segment(segment, port['id'], agent):
|
||||
return
|
||||
other_fdb_entries = self._get_fdb_entries_template(
|
||||
segment, agent_ip, network_id)
|
||||
|
@ -250,7 +240,7 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
|||
self.L2populationAgentNotify.add_fdb_entries(self.rpc_ctx,
|
||||
other_fdb_entries)
|
||||
|
||||
def _get_agent_fdb(self, context, port, agent_host):
|
||||
def _get_agent_fdb(self, segment, port, agent_host):
|
||||
if not agent_host:
|
||||
return
|
||||
|
||||
|
@ -261,8 +251,7 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
|||
session, agent_host, network_id)
|
||||
|
||||
agent = l2pop_db.get_agent_by_host(db_api.get_session(), agent_host)
|
||||
segment = self._get_and_validate_segment(context, port['id'], agent)
|
||||
if not segment:
|
||||
if not self._validate_segment(segment, port['id'], agent):
|
||||
return
|
||||
|
||||
agent_ip = l2pop_db.get_agent_ip(agent)
|
||||
|
|
|
@ -284,6 +284,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
binding.vif_details = ''
|
||||
db.clear_binding_levels(session, port_id, original_host)
|
||||
mech_context._clear_binding_levels()
|
||||
port['status'] = const.PORT_STATUS_DOWN
|
||||
super(Ml2Plugin, self).update_port(
|
||||
mech_context._plugin_context, port_id,
|
||||
{attributes.PORT: {'status': const.PORT_STATUS_DOWN}})
|
||||
|
||||
if port['device_owner'] == const.DEVICE_OWNER_DVR_INTERFACE:
|
||||
binding.vif_type = portbindings.VIF_TYPE_UNBOUND
|
||||
|
|
|
@ -778,6 +778,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase):
|
|||
device_owner=DEVICE_OWNER_COMPUTE,
|
||||
arg_list=(portbindings.HOST_ID,),
|
||||
**host_arg) as port1:
|
||||
tunnel_ip = '20.0.0.1'
|
||||
p1 = port1['port']
|
||||
device1 = 'tap' + p1['id']
|
||||
self.callbacks.update_device_up(
|
||||
|
@ -785,19 +786,18 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase):
|
|||
agent_id=HOST,
|
||||
device=device1)
|
||||
if twice:
|
||||
tunnel_ip = '20.0.0.4'
|
||||
self._update_and_check_portbinding(p1['id'], HOST_4)
|
||||
self._update_and_check_portbinding(p1['id'], HOST_2)
|
||||
self.callbacks.update_device_up(self.adminContext,
|
||||
agent_id=HOST_4,
|
||||
device=device1)
|
||||
|
||||
self.mock_fanout.reset_mock()
|
||||
# NOTE(yamamoto): see bug #1441488
|
||||
self.adminContext.session.expire_all()
|
||||
self.callbacks.get_device_details(
|
||||
self.adminContext,
|
||||
device=device1,
|
||||
agent_id=HOST_2)
|
||||
self._update_and_check_portbinding(p1['id'], HOST_2)
|
||||
p1_ips = [p['ip_address'] for p in p1['fixed_ips']]
|
||||
expected = {p1['network_id']:
|
||||
{'ports':
|
||||
{'20.0.0.1': [constants.FLOODING_ENTRY,
|
||||
{tunnel_ip: [constants.FLOODING_ENTRY,
|
||||
l2pop_rpc.PortInfo(
|
||||
p1['mac_address'],
|
||||
p1_ips[0])]},
|
||||
|
|
|
@ -518,6 +518,16 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
|
|||
plugin.update_port(ctx, port['port']['id'], port)
|
||||
self.assertTrue(sg_member_update.called)
|
||||
|
||||
def test_update_port_host_id_changed(self):
|
||||
ctx = context.get_admin_context()
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
host_id = {portbindings.HOST_ID: 'host1'}
|
||||
with self.port(**host_id) as port:
|
||||
plugin.update_port_status(ctx, port['port']['id'], 'UP')
|
||||
port['port']['binding:host_id'] = 'host2'
|
||||
result = plugin.update_port(ctx, port['port']['id'], port)
|
||||
self.assertEqual(constants.PORT_STATUS_DOWN, result['status'])
|
||||
|
||||
def test_update_port_status_with_network(self):
|
||||
ctx = context.get_admin_context()
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
|
@ -1793,7 +1803,9 @@ class TestMl2PluginCreateUpdateDeletePort(base.BaseTestCase):
|
|||
def test_create_port_rpc_outside_transaction(self):
|
||||
with mock.patch.object(ml2_plugin.Ml2Plugin, '__init__') as init,\
|
||||
mock.patch.object(base_plugin.NeutronDbPluginV2,
|
||||
'create_port') as db_create_port:
|
||||
'create_port') as db_create_port, \
|
||||
mock.patch.object(base_plugin.NeutronDbPluginV2,
|
||||
'update_port'):
|
||||
init.return_value = None
|
||||
|
||||
new_port = mock.MagicMock()
|
||||
|
|
Loading…
Reference in New Issue