Browse Source

Notify L2pop driver from update_device_(up|down)

This patch calls update_port_up and update_port_down inside
of the l2pop driver directly from update_device_up and
update_device_down in the ML2 RPC layer. This allows the L2pop
driver to setup forwarding entries completely independent of
the port status update events.

This will allow L2pop to function without requiring the ports to
transition from ACTIVE->BUILD->ACTIVE every time the agent requests
device details.

This will unblock the push notifications work and will additionally
enable us to remove the update to BUILD status as part of a performance
improvement backport for bug #1665215.

Partial-Bug: #1665215
Partially-Implements: blueprint push-notifications
Change-Id: Icd4cd4e3f735e88299e86468380c5f786e7628fe
(cherry picked from commit 9f55d77016)
changes/44/643144/4
Kevin Benton 5 years ago committed by Swaminathan Vasudevan
parent
commit
7b960e57ce
  1. 52
      neutron/plugins/ml2/rpc.py
  2. 6
      neutron/tests/unit/plugins/ml2/test_rpc.py

52
neutron/plugins/ml2/rpc.py

@ -230,8 +230,8 @@ class RpcCallbacks(type_tunnel.TunnelRpcCallbackMixin):
"executed concurrently. Ignoring StaleDataError.")
return {'device': device,
'exists': port_exists}
self.notify_ha_port_status(port_id, rpc_context,
n_const.PORT_STATUS_DOWN, host)
self.notify_l2pop_port_wiring(port_id, rpc_context,
n_const.PORT_STATUS_DOWN, host)
return {'device': device,
'exists': port_exists}
@ -266,8 +266,8 @@ class RpcCallbacks(type_tunnel.TunnelRpcCallbackMixin):
return
else:
self.update_port_status_to_active(port, rpc_context, port_id, host)
self.notify_ha_port_status(port_id, rpc_context,
n_const.PORT_STATUS_ACTIVE, host, port=port)
self.notify_l2pop_port_wiring(port_id, rpc_context,
n_const.PORT_STATUS_ACTIVE, host)
def update_port_status_to_active(self, port, rpc_context, port_id, host):
plugin = directory.get_plugin()
@ -290,29 +290,39 @@ class RpcCallbacks(type_tunnel.TunnelRpcCallbackMixin):
rpc_context, port['id'], resources.PORT,
provisioning_blocks.L2_AGENT_ENTITY)
def notify_ha_port_status(self, port_id, rpc_context,
status, host, port=None):
def notify_l2pop_port_wiring(self, port_id, rpc_context,
status, host):
"""Notify the L2pop driver that a port has been wired/unwired.
The L2pop driver uses this notification to broadcast forwarding
entries to other agents on the same network as the port for port_id.
"""
plugin = directory.get_plugin()
l2pop_driver = plugin.mechanism_manager.mech_drivers.get(
'l2population')
if not l2pop_driver:
return
if not port:
port = ml2_db.get_port(rpc_context, port_id)
if not port:
port_context = plugin.get_bound_port_context(
rpc_context, port_id)
if not port_context:
# port deleted
return
port = port_context.current
if (status == n_const.PORT_STATUS_ACTIVE and
port[portbindings.HOST_ID] != host and
not l3_hamode_db.is_ha_router_port(rpc_context,
port['device_owner'],
port['device_id'])):
# don't setup ACTIVE forwarding entries unless bound to this
# host or if it's an HA port (which is special-cased in the
# mech driver)
return
is_ha_port = l3_hamode_db.is_ha_router_port(rpc_context,
port['device_owner'],
port['device_id'])
if is_ha_port:
port_context = plugin.get_bound_port_context(
rpc_context, port_id)
port_context.current['status'] = status
port_context.current[portbindings.HOST_ID] = host
if status == n_const.PORT_STATUS_ACTIVE:
l2pop_driver.obj.update_port_up(port_context)
else:
l2pop_driver.obj.update_port_down(port_context)
port_context.current['status'] = status
port_context.current[portbindings.HOST_ID] = host
if status == n_const.PORT_STATUS_ACTIVE:
l2pop_driver.obj.update_port_up(port_context)
else:
l2pop_driver.obj.update_port_down(port_context)
def update_device_list(self, rpc_context, **kwargs):
devices_up = []

6
neutron/tests/unit/plugins/ml2/test_rpc.py

@ -60,7 +60,7 @@ class RpcCallbacksTestCase(base.BaseTestCase):
}
with mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin'
'._device_to_port_id'),\
mock.patch.object(self.callbacks, 'notify_ha_port_status'):
mock.patch.object(self.callbacks, 'notify_l2pop_port_wiring'):
with mock.patch('neutron.db.provisioning_blocks.'
'provisioning_complete') as pc:
with mock.patch.object(ml2_db, 'get_port'):
@ -214,7 +214,7 @@ class RpcCallbacksTestCase(base.BaseTestCase):
def _test_update_device_not_bound_to_host(self, func):
self.plugin.port_bound_to_host.return_value = False
self.callbacks.notify_ha_port_status = mock.Mock()
self.callbacks.notify_l2pop_port_wiring = mock.Mock()
self.plugin._device_to_port_id.return_value = 'fake_port_id'
res = func(mock.Mock(), device='fake_device', host='fake_host')
self.plugin.port_bound_to_host.assert_called_once_with(mock.ANY,
@ -238,7 +238,7 @@ class RpcCallbacksTestCase(base.BaseTestCase):
def test_update_device_down_call_update_port_status(self):
self.plugin.update_port_status.return_value = False
self.callbacks.notify_ha_port_status = mock.Mock()
self.callbacks.notify_l2pop_port_wiring = mock.Mock()
self.plugin._device_to_port_id.return_value = 'fake_port_id'
self.assertEqual(
{'device': 'fake_device', 'exists': False},

Loading…
Cancel
Save