From 6098fc7430d5c4a391fb7b5da8fe3865e1b00a2f Mon Sep 17 00:00:00 2001 From: Nate Johnston Date: Thu, 19 Jul 2018 14:17:20 -0400 Subject: [PATCH] Incorporate capability for multiple mac generation The bulk port creation scenario requires the ability to generate multiple MAC addresses for the bulk added ports. This change leverages the code added in [1] to make bulk MAC creation available. [1] https://review.openstack.org/510830 Implements: blueprint speed-up-neutron-bulk-creation Depends-On: https://review.openstack.org/613149 Change-Id: Ia769dadf69781ba511a19c52998949b668963a19 --- neutron/db/db_base_plugin_common.py | 7 +++++-- neutron/db/db_base_plugin_v2.py | 2 +- neutron/tests/common/net_helpers.py | 6 +++--- neutron/tests/unit/db/test_db_base_plugin_v2.py | 4 ++-- neutron/tests/unit/plugins/ml2/test_db.py | 17 +++++++++++++++-- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/neutron/db/db_base_plugin_common.py b/neutron/db/db_base_plugin_common.py index fc45df97856..36c427cc96d 100644 --- a/neutron/db/db_base_plugin_common.py +++ b/neutron/db/db_base_plugin_common.py @@ -15,6 +15,8 @@ import functools +import six + from neutron_lib.api.definitions import network as net_def from neutron_lib.api.definitions import port as port_def from neutron_lib.api.definitions import subnet as subnet_def @@ -88,8 +90,9 @@ class DbBasePluginCommon(common_db_mixin.CommonDbMixin): """ @staticmethod - def _generate_mac(): - return net.get_random_mac(cfg.CONF.base_mac.split(':')) + def _generate_macs(mac_count=1): + mac_maker = net.random_mac_generator(cfg.CONF.base_mac.split(':')) + return [six.next(mac_maker) for x in range(mac_count)] @db_api.CONTEXT_READER def _is_mac_in_use(self, context, network_id, mac_address): diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index 97a76f64ef1..1136bdd96e4 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -1274,7 +1274,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, raise exc.MacAddressInUse(net_id=port_data['network_id'], mac=mac_address) else: - mac_address = self._generate_mac() + mac_address = self._generate_macs()[0] db_port = models_v2.Port(mac_address=mac_address, **port_data) context.session.add(db_port) return db_port diff --git a/neutron/tests/common/net_helpers.py b/neutron/tests/common/net_helpers.py index 92adb110b36..5c383d98f1b 100644 --- a/neutron/tests/common/net_helpers.py +++ b/neutron/tests/common/net_helpers.py @@ -41,7 +41,7 @@ from neutron.agent.linux import iptables_firewall from neutron.agent.linux import utils from neutron.common import utils as common_utils from neutron.conf.agent import common as config -from neutron.db import db_base_plugin_common +from neutron.db import db_base_plugin_common as db_base from neutron.plugins.ml2.drivers.linuxbridge.agent import \ linuxbridge_neutron_agent as linuxbridge_agent from neutron.tests.common import base as common_base @@ -687,8 +687,8 @@ class PortFixture(fixtures.Fixture): super(PortFixture, self).__init__() self.bridge = bridge self.namespace = namespace - self.mac = ( - mac or db_base_plugin_common.DbBasePluginCommon._generate_mac()) + self.mac = (mac or + db_base.DbBasePluginCommon._generate_macs()[0]) self.port_id = port_id or uuidutils.generate_uuid() @abc.abstractmethod diff --git a/neutron/tests/unit/db/test_db_base_plugin_v2.py b/neutron/tests/unit/db/test_db_base_plugin_v2.py index 24f85b17225..28f17aab369 100644 --- a/neutron/tests/unit/db/test_db_base_plugin_v2.py +++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py @@ -1782,8 +1782,8 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s # simulate duplicate mac generation to make sure DBDuplicate is retried responses = ['12:34:56:78:00:00', '12:34:56:78:00:00', '12:34:56:78:00:01'] - with mock.patch.object(net, 'get_random_mac', - side_effect=responses) as grand_mac: + with mock.patch.object(net, 'random_mac_generator', + return_value=itertools.cycle(responses)) as grand_mac: with self.subnet() as s: with self.port(subnet=s) as p1, self.port(subnet=s) as p2: self.assertEqual('12:34:56:78:00:00', diff --git a/neutron/tests/unit/plugins/ml2/test_db.py b/neutron/tests/unit/plugins/ml2/test_db.py index 89c65fcb956..241b4ef6f5d 100644 --- a/neutron/tests/unit/plugins/ml2/test_db.py +++ b/neutron/tests/unit/plugins/ml2/test_db.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import re import warnings import mock @@ -50,7 +51,7 @@ class Ml2DBTestCase(testlib_api.SqlTestCase): network_obj.Network(self.ctx, id=network_id).create() def _setup_neutron_port(self, network_id, port_id): - mac_address = db_base_plugin_v2.NeutronDbPluginV2._generate_mac() + mac_address = db_base_plugin_v2.NeutronDbPluginV2._generate_macs()[0] port = port_obj.Port(self.ctx, id=port_id, network_id=network_id, @@ -287,6 +288,18 @@ class Ml2DBTestCase(testlib_api.SqlTestCase): port['mac_address']) self.assertEqual(port_id, observed_port.id) + def test_generating_multiple_mac_addresses(self): + mac_regex = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$" + + macs = db_base_plugin_v2.NeutronDbPluginV2._generate_macs() + self.assertEqual(1, len(macs)) + self.assertIsNotNone(re.search(mac_regex, macs[0])) + + macs = db_base_plugin_v2.NeutronDbPluginV2._generate_macs(5) + self.assertEqual(5, len(macs)) + for mac in macs: + self.assertIsNotNone(re.search(mac_regex, mac)) + class Ml2DvrDBTestCase(testlib_api.SqlTestCase): @@ -301,7 +314,7 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase): ports = [] for port_id in port_ids: mac_address = (db_base_plugin_v2.NeutronDbPluginV2. - _generate_mac()) + _generate_macs()[0]) port = port_obj.Port(self.ctx, id=port_id, network_id=network_id,