Add binding_deactivate method to Linux bridge agent
This commit adds a binding_deactivate method to the Linux bridge agent to receive messages from the ML2 plugin when a binding is de-activated for a port. After receiving that message, the agent un-plugs the corresponding tap interface from the port's network bridge. To support this, a binding_deactivate method is also added to the agents notifier. Finally, the activate method in the ML2 plugin is updated to use the binding_deactivate method in the agents notifier. Change-Id: I3f4e34766791c472a2c81842190094f697baa05c Partial-Bug: #1580880
This commit is contained in:
parent
390b6a531f
commit
f374697760
|
@ -0,0 +1,24 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO(mlavalle): This module should be deleted once neutron-lib containing
|
||||||
|
https://review.openstack.org/#/c/564381/ change is released.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from neutron_lib.api.definitions import portbindings_extended
|
||||||
|
|
||||||
|
|
||||||
|
PORT_BINDING = portbindings_extended.RESOURCE_NAME
|
||||||
|
|
||||||
|
ACTIVATE = 'activate'
|
||||||
|
DEACTIVATE = 'deactivate'
|
|
@ -33,6 +33,7 @@ from oslo_service import service
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
from six import moves
|
from six import moves
|
||||||
|
|
||||||
|
from neutron.agent import _topics as n_topics
|
||||||
from neutron.agent.linux import bridge_lib
|
from neutron.agent.linux import bridge_lib
|
||||||
from neutron.agent.linux import ip_lib
|
from neutron.agent.linux import ip_lib
|
||||||
from neutron.api.rpc.handlers import securitygroups_rpc as sg_rpc
|
from neutron.api.rpc.handlers import securitygroups_rpc as sg_rpc
|
||||||
|
@ -833,7 +834,8 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase):
|
||||||
consumers = [[topics.PORT, topics.UPDATE],
|
consumers = [[topics.PORT, topics.UPDATE],
|
||||||
[topics.NETWORK, topics.DELETE],
|
[topics.NETWORK, topics.DELETE],
|
||||||
[topics.NETWORK, topics.UPDATE],
|
[topics.NETWORK, topics.UPDATE],
|
||||||
[topics.SECURITY_GROUP, topics.UPDATE]]
|
[topics.SECURITY_GROUP, topics.UPDATE],
|
||||||
|
[n_topics.PORT_BINDING, n_topics.DEACTIVATE]]
|
||||||
if cfg.CONF.VXLAN.l2_population:
|
if cfg.CONF.VXLAN.l2_population:
|
||||||
consumers.append([topics.L2POPULATION, topics.UPDATE])
|
consumers.append([topics.L2POPULATION, topics.UPDATE])
|
||||||
return consumers
|
return consumers
|
||||||
|
@ -869,7 +871,8 @@ class LinuxBridgeRpcCallbacks(
|
||||||
# 1.1 Support Security Group RPC
|
# 1.1 Support Security Group RPC
|
||||||
# 1.3 Added param devices_to_update to security_groups_provider_updated
|
# 1.3 Added param devices_to_update to security_groups_provider_updated
|
||||||
# 1.4 Added support for network_update
|
# 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 network_delete(self, context, **kwargs):
|
def network_delete(self, context, **kwargs):
|
||||||
LOG.debug("network_delete received")
|
LOG.debug("network_delete received")
|
||||||
|
@ -899,6 +902,18 @@ class LinuxBridgeRpcCallbacks(
|
||||||
self.updated_devices.add(device_name)
|
self.updated_devices.add(device_name)
|
||||||
LOG.debug("port_update RPC received for port: %s", port_id)
|
LOG.debug("port_update RPC received for port: %s", port_id)
|
||||||
|
|
||||||
|
def binding_deactivate(self, context, **kwargs):
|
||||||
|
if kwargs.get('host') != cfg.CONF.host:
|
||||||
|
return
|
||||||
|
interface_name = self.agent.mgr.get_tap_device_name(
|
||||||
|
kwargs.get('port_id'))
|
||||||
|
bridge_name = self.agent.mgr.get_bridge_name(kwargs.get('network_id'))
|
||||||
|
LOG.debug("Removing device %(interface_name)s from bridge "
|
||||||
|
"%(bridge_name)s due to binding being de-activated",
|
||||||
|
{'interface_name': interface_name,
|
||||||
|
'bridge_name': bridge_name})
|
||||||
|
self.agent.mgr.remove_interface(bridge_name, interface_name)
|
||||||
|
|
||||||
def network_update(self, context, **kwargs):
|
def network_update(self, context, **kwargs):
|
||||||
network_id = kwargs['network']['id']
|
network_id = kwargs['network']['id']
|
||||||
LOG.debug("network_update message processed for network "
|
LOG.debug("network_update message processed for network "
|
||||||
|
|
|
@ -2199,7 +2199,9 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
original_context, bind_context, need_notify=True,
|
original_context, bind_context, need_notify=True,
|
||||||
try_again=True)
|
try_again=True)
|
||||||
if not try_again:
|
if not try_again:
|
||||||
self.notifier.port_delete(context, port_id)
|
self.notifier.binding_deactivate(context, port_id,
|
||||||
|
active_binding.host,
|
||||||
|
network['id'])
|
||||||
return self._make_port_binding_dict(cur_context._binding)
|
return self._make_port_binding_dict(cur_context._binding)
|
||||||
raise n_exc.PortBindingError(port_id=port_id, host=host)
|
raise n_exc.PortBindingError(port_id=port_id, host=host)
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ from oslo_log import log
|
||||||
import oslo_messaging
|
import oslo_messaging
|
||||||
from sqlalchemy.orm import exc
|
from sqlalchemy.orm import exc
|
||||||
|
|
||||||
|
from neutron.agent import _topics as n_topics
|
||||||
from neutron.api.rpc.handlers import dvr_rpc
|
from neutron.api.rpc.handlers import dvr_rpc
|
||||||
from neutron.api.rpc.handlers import securitygroups_rpc as sg_rpc
|
from neutron.api.rpc.handlers import securitygroups_rpc as sg_rpc
|
||||||
from neutron.common import rpc as n_rpc
|
from neutron.common import rpc as n_rpc
|
||||||
|
@ -383,6 +384,7 @@ class AgentNotifierApi(dvr_rpc.DVRAgentRpcApiMixin,
|
||||||
1.1 - Added get_active_networks_info, create_dhcp_port,
|
1.1 - Added get_active_networks_info, create_dhcp_port,
|
||||||
update_dhcp_port, and removed get_dhcp_port methods.
|
update_dhcp_port, and removed get_dhcp_port methods.
|
||||||
1.4 - Added network_update
|
1.4 - Added network_update
|
||||||
|
1.5 - Added binding_deactivate
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, topic):
|
def __init__(self, topic):
|
||||||
|
@ -399,6 +401,8 @@ class AgentNotifierApi(dvr_rpc.DVRAgentRpcApiMixin,
|
||||||
self.topic_network_update = topics.get_topic_name(topic,
|
self.topic_network_update = topics.get_topic_name(topic,
|
||||||
topics.NETWORK,
|
topics.NETWORK,
|
||||||
topics.UPDATE)
|
topics.UPDATE)
|
||||||
|
self.topic_port_binding_deactivate = topics.get_topic_name(
|
||||||
|
topic, n_topics.PORT_BINDING, n_topics.DEACTIVATE)
|
||||||
|
|
||||||
target = oslo_messaging.Target(topic=topic, version='1.0')
|
target = oslo_messaging.Target(topic=topic, version='1.0')
|
||||||
self.client = n_rpc.get_client(target)
|
self.client = n_rpc.get_client(target)
|
||||||
|
@ -425,3 +429,9 @@ class AgentNotifierApi(dvr_rpc.DVRAgentRpcApiMixin,
|
||||||
cctxt = self.client.prepare(topic=self.topic_network_update,
|
cctxt = self.client.prepare(topic=self.topic_network_update,
|
||||||
fanout=True, version='1.4')
|
fanout=True, version='1.4')
|
||||||
cctxt.cast(context, 'network_update', network=network)
|
cctxt.cast(context, 'network_update', network=network)
|
||||||
|
|
||||||
|
def binding_deactivate(self, context, port_id, host, network_id):
|
||||||
|
cctxt = self.client.prepare(topic=self.topic_port_binding_deactivate,
|
||||||
|
fanout=True, version='1.5')
|
||||||
|
cctxt.cast(context, 'binding_deactivate', port_id=port_id, host=host,
|
||||||
|
network_id=network_id)
|
||||||
|
|
|
@ -975,6 +975,7 @@ class TestLinuxBridgeRpcCallbacks(base.BaseTestCase):
|
||||||
segment.network_type = 'vxlan'
|
segment.network_type = 'vxlan'
|
||||||
segment.segmentation_id = 1
|
segment.segmentation_id = 1
|
||||||
self.lb_rpc.network_map['net_id'] = segment
|
self.lb_rpc.network_map['net_id'] = segment
|
||||||
|
cfg.CONF.set_default('host', 'host')
|
||||||
|
|
||||||
def test_network_delete_mapped_net(self):
|
def test_network_delete_mapped_net(self):
|
||||||
mock_net = mock.Mock()
|
mock_net = mock.Mock()
|
||||||
|
@ -1022,6 +1023,34 @@ class TestLinuxBridgeRpcCallbacks(base.BaseTestCase):
|
||||||
self.assertEqual(0, del_fn.call_count)
|
self.assertEqual(0, del_fn.call_count)
|
||||||
self.assertEqual(1, log.call_count)
|
self.assertEqual(1, log.call_count)
|
||||||
|
|
||||||
|
def test_binding_deactivate(self):
|
||||||
|
with mock.patch.object(self.lb_rpc.agent.mgr,
|
||||||
|
"get_bridge_name") as get_br_fn,\
|
||||||
|
mock.patch.object(self.lb_rpc.agent.mgr,
|
||||||
|
"get_tap_device_name") as get_tap_fn,\
|
||||||
|
mock.patch.object(self.lb_rpc.agent.mgr,
|
||||||
|
"remove_interface") as rem_intf:
|
||||||
|
get_br_fn.return_value = "br0"
|
||||||
|
get_tap_fn.return_value = "tap456"
|
||||||
|
self.lb_rpc.binding_deactivate(mock.ANY, host="host",
|
||||||
|
network_id="123", port_id="456")
|
||||||
|
get_br_fn.assert_called_once_with("123")
|
||||||
|
get_tap_fn.assert_called_once_with("456")
|
||||||
|
rem_intf.assert_called_once_with("br0", "tap456")
|
||||||
|
|
||||||
|
def test_binding_deactivate_not_for_host(self):
|
||||||
|
with mock.patch.object(self.lb_rpc.agent.mgr,
|
||||||
|
"get_bridge_name") as get_br_fn,\
|
||||||
|
mock.patch.object(self.lb_rpc.agent.mgr,
|
||||||
|
"get_tap_device_name") as get_tap_fn,\
|
||||||
|
mock.patch.object(self.lb_rpc.agent.mgr,
|
||||||
|
"remove_interface") as rem_intf:
|
||||||
|
self.lb_rpc.binding_deactivate(mock.ANY, host="other_host",
|
||||||
|
network_id="123", port_id="456")
|
||||||
|
get_br_fn.assert_not_called()
|
||||||
|
get_tap_fn.assert_not_called()
|
||||||
|
rem_intf.assert_not_called()
|
||||||
|
|
||||||
def _test_fdb_add(self, proxy_enabled=False):
|
def _test_fdb_add(self, proxy_enabled=False):
|
||||||
fdb_entries = {'net_id':
|
fdb_entries = {'net_id':
|
||||||
{'ports':
|
{'ports':
|
||||||
|
|
Loading…
Reference in New Issue