Add binding de-activation to OVS agent
To support multiple port bindings, the L2 agents have to have the capability to handle binding deactivation notifications from the Neutron server. This patch adds the necessary code to the OVS agent. After receiving the notification, the agent un-plugs the corresponding VIF from the integration bridge. Change-Id: I78178de2039ccabc649558de4f6549a38de90418 Partial-Bug: #1580880
This commit is contained in:
parent
be7ad302e1
commit
0694bebd6d
|
@ -124,7 +124,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
|||
# 1.2 Support DVR (Distributed Virtual Router) RPC
|
||||
# 1.3 Added param devices_to_update to security_groups_provider_updated
|
||||
# 1.4 Added support for network_update
|
||||
target = oslo_messaging.Target(version='1.4')
|
||||
# 1.5 Added binding_deactivate
|
||||
target = oslo_messaging.Target(version='1.5')
|
||||
|
||||
def __init__(self, bridge_classes, ext_manager, conf=None):
|
||||
'''Constructor.
|
||||
|
@ -174,6 +175,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
|||
self.updated_ports = set()
|
||||
# Stores port delete notifications
|
||||
self.deleted_ports = set()
|
||||
# Stores the port IDs whose binding has been deactivated
|
||||
self.deactivated_bindings = set()
|
||||
|
||||
self.network_ports = collections.defaultdict(set)
|
||||
# keeps association between ports and ofports to detect ofport change
|
||||
|
@ -414,6 +417,12 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
|||
{'network_id': network_id,
|
||||
'ports': self.network_ports[network_id]})
|
||||
|
||||
def binding_deactivate(self, context, **kwargs):
|
||||
if kwargs.get('host') != self.conf.host:
|
||||
return
|
||||
port_id = kwargs.get('port_id')
|
||||
self.deactivated_bindings.add(port_id)
|
||||
|
||||
def _clean_network_ports(self, port_id):
|
||||
for port_set in self.network_ports.values():
|
||||
if port_id in port_set:
|
||||
|
@ -444,6 +453,20 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
|||
# more secure
|
||||
self.sg_agent.remove_devices_filter(deleted_ports)
|
||||
|
||||
def process_deactivated_bindings(self, port_info):
|
||||
# don't try to deactivate bindings for removed ports since they are
|
||||
# already gone
|
||||
if 'removed' in port_info:
|
||||
self.deactivated_bindings -= port_info['removed']
|
||||
while self.deactivated_bindings:
|
||||
port_id = self.deactivated_bindings.pop()
|
||||
port = self.int_br.get_vif_port_by_id(port_id)
|
||||
if not port:
|
||||
continue
|
||||
self.int_br.delete_port(port.port_name)
|
||||
LOG.debug(("Port id %s unplugged from integration bridge because "
|
||||
"its binding was de-activated"), port_id)
|
||||
|
||||
def tunnel_update(self, context, **kwargs):
|
||||
LOG.debug("tunnel_update received")
|
||||
if not self.enable_tunneling:
|
||||
|
@ -1786,6 +1809,7 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
|||
return (polling_manager.is_polling_required or
|
||||
self.updated_ports or
|
||||
self.deleted_ports or
|
||||
self.deactivated_bindings or
|
||||
self.sg_agent.firewall_refresh_needed())
|
||||
|
||||
def _port_info_has_changes(self, port_info):
|
||||
|
@ -2075,6 +2099,7 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
|||
failed_devices, failed_ancillary_devices))
|
||||
sync = False
|
||||
self.process_deleted_ports(port_info)
|
||||
self.process_deactivated_bindings(port_info)
|
||||
ofport_changed_ports = self.update_stale_ofport_rules()
|
||||
if ofport_changed_ports:
|
||||
port_info.setdefault('updated', set()).update(
|
||||
|
|
|
@ -114,6 +114,7 @@ class TestOvsNeutronAgent(object):
|
|||
group='SECURITYGROUP')
|
||||
cfg.CONF.set_default('quitting_rpc_timeout', 10, 'AGENT')
|
||||
cfg.CONF.set_default('local_ip', '127.0.0.1', 'OVS')
|
||||
cfg.CONF.set_default('host', 'host')
|
||||
mock.patch(
|
||||
'neutron.agent.ovsdb.native.helpers.enable_connection_uri').start()
|
||||
mock.patch(
|
||||
|
@ -1218,6 +1219,34 @@ class TestOvsNeutronAgent(object):
|
|||
self.assertFalse(int_br.set_db_attribute.called)
|
||||
self.assertFalse(int_br.drop_port.called)
|
||||
|
||||
def test_binding_deactivate_not_for_host(self):
|
||||
self.agent.binding_deactivate('unused_context', port_id='id',
|
||||
host='other_host')
|
||||
self.assertEqual(set(), self.agent.deactivated_bindings)
|
||||
|
||||
def test_binding_deactivate(self):
|
||||
vif = FakeVif()
|
||||
with mock.patch.object(self.agent, 'int_br') as int_br:
|
||||
int_br.get_vif_port_by_id.return_value = vif
|
||||
self.agent.binding_deactivate('unused_context', port_id='id',
|
||||
host='host')
|
||||
self.assertEqual(set(['id']), self.agent.deactivated_bindings)
|
||||
self.agent.process_deactivated_bindings(port_info={})
|
||||
int_br.get_vif_port_by_id.assert_called_once_with('id')
|
||||
int_br.delete_port.assert_called_once_with(vif.port_name)
|
||||
self.assertEqual(set(), self.agent.deactivated_bindings)
|
||||
|
||||
def test_binding_deactivate_removed_port(self):
|
||||
with mock.patch.object(self.agent, 'int_br') as int_br:
|
||||
self.agent.binding_deactivate('unused_context', port_id='id',
|
||||
host='host')
|
||||
self.assertEqual(set(['id']), self.agent.deactivated_bindings)
|
||||
self.agent.process_deactivated_bindings(
|
||||
port_info={'removed': {'id', }})
|
||||
int_br.get_vif_port_by_id.assert_not_called()
|
||||
int_br.delete_port.assert_not_called()
|
||||
self.assertEqual(set(), self.agent.deactivated_bindings)
|
||||
|
||||
def _test_setup_physical_bridges(self, port_exists=False):
|
||||
with mock.patch.object(ip_lib.IPDevice, "exists") as devex_fn,\
|
||||
mock.patch.object(sys, "exit"),\
|
||||
|
|
Loading…
Reference in New Issue