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