From 8ab42758b3505e208694cffc5c0e8a1f9019ec3d Mon Sep 17 00:00:00 2001 From: Vivekanandan Narasimhan Date: Tue, 5 Aug 2014 11:36:35 -0700 Subject: [PATCH] Fix to enable L2pop to serve DVR This change fixes the information used by the L2pop driver to populate l2pop rules that enables DVR to route packets across compute servers that have tenant VMs that belong to different networks. It also fixes the case where VMs were not able to obtain IP Addresses when such VMs are on DVR hosted subnets. Change-Id: Ib630e57c186da60eb15f9ffa6b1b0bfa74f48caa Closes-Bug: #1350485 Closes-Bug: #1352857 --- neutron/plugins/ml2/driver_context.py | 16 +++- .../plugins/ml2/drivers/l2pop/mech_driver.py | 6 +- neutron/tests/unit/ml2/test_driver_context.py | 94 +++++++++++++++++++ 3 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 neutron/tests/unit/ml2/test_driver_context.py diff --git a/neutron/plugins/ml2/driver_context.py b/neutron/plugins/ml2/driver_context.py index ef3c225751..2cbc9b5611 100644 --- a/neutron/plugins/ml2/driver_context.py +++ b/neutron/plugins/ml2/driver_context.py @@ -161,9 +161,15 @@ class DvrPortContext(PortContext): original_port=original_port) @property - def bound_host(self): + def host(self): if self._port['device_owner'] == constants.DEVICE_OWNER_DVR_INTERFACE: - agent_host = self._binding.host - else: - agent_host = self._port['binding:host_id'] - return agent_host + return self._binding.host + + return super(DvrPortContext, self).host + + @property + def status(self): + if self._port['device_owner'] == constants.DEVICE_OWNER_DVR_INTERFACE: + return self._binding.status + + return super(DvrPortContext, self).status diff --git a/neutron/plugins/ml2/drivers/l2pop/mech_driver.py b/neutron/plugins/ml2/drivers/l2pop/mech_driver.py index 65dbf6cc0a..18141cd862 100644 --- a/neutron/plugins/ml2/drivers/l2pop/mech_driver.py +++ b/neutron/plugins/ml2/drivers/l2pop/mech_driver.py @@ -83,8 +83,12 @@ class L2populationMechanismDriver(api.MechanismDriver, def _fixed_ips_changed(self, context, orig, port, diff_ips): orig_ips, port_ips = diff_ips + if (port['device_owner'] == const.DEVICE_OWNER_DVR_INTERFACE): + agent_host = context.host + else: + agent_host = context.original_host port_infos = self._get_port_infos( - context, orig, context.original_host) + context, orig, agent_host) if not port_infos: return agent, agent_host, agent_ip, segment, port_fdb_entries = port_infos diff --git a/neutron/tests/unit/ml2/test_driver_context.py b/neutron/tests/unit/ml2/test_driver_context.py new file mode 100644 index 0000000000..9400f62e96 --- /dev/null +++ b/neutron/tests/unit/ml2/test_driver_context.py @@ -0,0 +1,94 @@ +# Copyright (c) 2013 OpenStack Foundation +# All Rights Reserved. +# +# 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. + +import mock + +from neutron.common import constants +from neutron.extensions import portbindings +from neutron.plugins.ml2 import driver_context +from neutron.tests import base + + +class TestDvrPortContext(base.BaseTestCase): + + def test_host(self): + plugin = mock.Mock() + plugin_context = mock.Mock() + network = mock.MagicMock() + binding = mock.Mock() + + port = {'device_owner': constants.DEVICE_OWNER_DVR_INTERFACE} + binding.host = 'foohost' + + with mock.patch.object(driver_context.db, 'get_network_segments'): + ctx = driver_context.DvrPortContext(plugin, + plugin_context, + port, + network, + binding) + self.assertEqual('foohost', ctx.host) + + def test_host_super(self): + plugin = mock.Mock() + plugin_context = mock.Mock() + network = mock.MagicMock() + binding = mock.Mock() + + port = {'device_owner': 'compute', + portbindings.HOST_ID: 'host'} + binding.host = 'foohost' + + with mock.patch.object(driver_context.db, 'get_network_segments'): + ctx = driver_context.DvrPortContext(plugin, + plugin_context, + port, + network, + binding) + self.assertEqual('host', ctx.host) + + def test_status(self): + plugin = mock.Mock() + plugin_context = mock.Mock() + network = mock.MagicMock() + binding = mock.Mock() + + port = {'device_owner': constants.DEVICE_OWNER_DVR_INTERFACE} + binding.status = 'foostatus' + + with mock.patch.object(driver_context.db, 'get_network_segments'): + ctx = driver_context.DvrPortContext(plugin, + plugin_context, + port, + network, + binding) + self.assertEqual('foostatus', ctx.status) + + def test_status_super(self): + plugin = mock.Mock() + plugin_context = mock.Mock() + network = mock.MagicMock() + binding = mock.Mock() + + port = {'device_owner': 'compute', + 'status': 'status'} + binding.status = 'foostatus' + + with mock.patch.object(driver_context.db, 'get_network_segments'): + ctx = driver_context.DvrPortContext(plugin, + plugin_context, + port, + network, + binding) + self.assertEqual('status', ctx.status)