net_utils: Add a random mac generator
If you want to generate thousands of mac addresses for ports in the same subnet, it is much more efficient to use the generator as it will guarantee that you will not get repeated macs. It is also about 2x as fast when not counting repetition. The use case for this in Neutron is for making the bulk port creation perform all the port creation at once, without having to go one by one internally as it currently does. Implements: blueprint speed-up-neutron-bulk-creation Change-Id: I8551c88ffe3ddefe617fb052eb7ca6f0d7d85069 Signed-off-by: Antoni Segura Puimedon <antonisp@celebdor.com>
This commit is contained in:
parent
7bc2bf7392
commit
b8677baeb7
@ -11,6 +11,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import itertools
|
||||
import random
|
||||
import socket
|
||||
|
||||
@ -46,6 +47,37 @@ class TestGetRandomMac(base.BaseTestCase):
|
||||
mock_rnd.assert_called_with(8)
|
||||
|
||||
|
||||
class TestRandomMacGenerator(base.BaseTestCase):
|
||||
|
||||
def test_all_macs_generated(self):
|
||||
mac = ['aa', 'bb', 'cc', 'dd', 'ee', 'ff']
|
||||
generator = itertools.islice(net.random_mac_generator(mac), 70000)
|
||||
self.assertEqual(2**16, len(list(generator)))
|
||||
|
||||
@mock.patch.object(random, 'getrandbits', return_value=0xa2)
|
||||
def test_first_generated_mac(self, mock_rnd):
|
||||
mac = ['aa', 'bb', 'cc', '00', 'ee', 'ff']
|
||||
generator = itertools.islice(net.random_mac_generator(mac), 1)
|
||||
self.assertEqual(['aa:bb:cc:a2:a2:a2'], list(generator))
|
||||
mock_rnd.assert_called_with(8)
|
||||
|
||||
@mock.patch.object(random, 'getrandbits', return_value=0xa2)
|
||||
def test_respected_early_zeroes_generated_mac(self, mock_rnd):
|
||||
mac1 = ['00', 'bb', 'cc', '00', 'ee', 'ff']
|
||||
|
||||
generator = itertools.islice(net.random_mac_generator(mac1), 1)
|
||||
self.assertEqual(['00:bb:cc:a2:a2:a2'], list(generator))
|
||||
|
||||
mac2 = ['aa', '00', 'cc', '00', 'ee', 'ff']
|
||||
generator = itertools.islice(net.random_mac_generator(mac2), 1)
|
||||
self.assertEqual(['aa:00:cc:a2:a2:a2'], list(generator))
|
||||
|
||||
mac3 = ['aa', 'bb', '00', '00', 'ee', 'ff']
|
||||
generator = itertools.islice(net.random_mac_generator(mac3), 1)
|
||||
self.assertEqual(['aa:bb:00:a2:a2:a2'], list(generator))
|
||||
mock_rnd.assert_called_with(8)
|
||||
|
||||
|
||||
class TestPortDeviceOwner(base.BaseTestCase):
|
||||
|
||||
def test_is_port_trusted(self):
|
||||
|
@ -43,6 +43,36 @@ def get_random_mac(base_mac):
|
||||
return ':'.join(["%02x" % x for x in mac])
|
||||
|
||||
|
||||
def random_mac_generator(base_mac):
|
||||
"""Generates random mac addresses from a specified base format.
|
||||
|
||||
The first 3 octets of each MAC address will remain unchanged. If the 4th
|
||||
octet is not 00, it will also be used. The others will be randomly
|
||||
generated.
|
||||
|
||||
:param base_mac: Base mac address represented by an array of 6 strings.
|
||||
:returns: A mac address string generator.
|
||||
"""
|
||||
fixed = list(base_mac[0:3])
|
||||
to_generate = 3
|
||||
if base_mac[3] != '00':
|
||||
fixed += base_mac[3]
|
||||
to_generate = 2
|
||||
beginning = ':'.join(fixed) + ':'
|
||||
|
||||
form = '{}' + ':'.join('{:02x}' for _ in range(to_generate))
|
||||
max_macs = 2 ** (to_generate * 8)
|
||||
seen = set()
|
||||
while len(seen) < max_macs:
|
||||
numbers = [random.getrandbits(8) for _ in range(to_generate)]
|
||||
mac = form.format(beginning, *numbers)
|
||||
if mac in seen:
|
||||
continue
|
||||
else:
|
||||
seen.add(mac)
|
||||
yield mac
|
||||
|
||||
|
||||
def is_port_trusted(port):
|
||||
"""Used to determine if port can be trusted not to attack network.
|
||||
|
||||
|
8
releasenotes/notes/mac-generator-f927df2fe57300c0.yaml
Normal file
8
releasenotes/notes/mac-generator-f927df2fe57300c0.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Introduced ``neutron_lib.utils.net.random_mac_generator(basemac)``. It allows
|
||||
you to get a mac address string Python generator from the same kind of
|
||||
basemac that ``neutron_lib.utils.net.get_random_mac(basemac)`` expects. If
|
||||
there are a lot of macs to get, this will speed the process up
|
||||
significantly over generating single macs and testing for collisions.
|
Loading…
Reference in New Issue
Block a user