From 4a78c722aa4c6cbf6fafb5c1c5773531710ab013 Mon Sep 17 00:00:00 2001 From: Martin Roy Date: Mon, 21 Nov 2016 16:15:50 -0500 Subject: [PATCH] Make the get_random_mac more versatile The past version was not well documented and could use a little dusting. This new version offers a custom OUI size. This is a random code enhancement. Change-Id: If2539f94b5479f0d6afa64c973082cbe8c5309ac --- neutron_lib/tests/unit/utils/test_net.py | 41 ++++++++++++++++-------- neutron_lib/utils/net.py | 15 +++++---- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/neutron_lib/tests/unit/utils/test_net.py b/neutron_lib/tests/unit/utils/test_net.py index d051765fa..bf83efe72 100644 --- a/neutron_lib/tests/unit/utils/test_net.py +++ b/neutron_lib/tests/unit/utils/test_net.py @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import random import socket import mock @@ -31,18 +32,32 @@ class TestGetHostname(base.BaseTestCase): class TestGetRandomMac(base.BaseTestCase): - def _test_get_random_mac(self, base_mac, startswith_len): - random_mac = net.get_random_mac(base_mac.split(':')) - self.assertEqual(base_mac[:startswith_len], - random_mac[:startswith_len]) - self.assertEqual(len(base_mac), len(random_mac)) - for i in random_mac.split(':'): - int(i, 16) + def test_full_prefix_does_nothing(self): + mac = net.get_random_mac(['aa', 'bb', 'cc', 'dd', 'ee', 'ff']) - def test_get_random_mac_with_three_octets(self): - base_mac = 'fa:16:3e:00:00:00' - self._test_get_random_mac(base_mac, 9) + self.assertEqual('aa:bb:cc:dd:ee:ff', mac) - def test_get_random_mac_with_four_octets(self): - base_mac = 'fa:16:3e:fe:00:00' - self._test_get_random_mac(base_mac, 12) + @mock.patch.object(random, 'randint', side_effect=[0x11]) + def test_5_octets_prefix_replaces_1_part(self, mock_rnd): + mac = net.get_random_mac(['aa', 'bb', 'cc', 'dd', 'ee', '00']) + + self.assertEqual('aa:bb:cc:dd:ee:11', mac) + + mock_rnd.assert_called_with(0x00, 0xff) + + @mock.patch.object(random, 'randint', + side_effect=[0x01, 0x02, 0x03, 0x04, 0x05]) + def test_1_octets_prefix_replaces_5_parts(self, mock_rnd): + mac = net.get_random_mac(['aa', '00', '00', '00', '00', '00']) + + self.assertEqual('aa:01:02:03:04:05', mac) + + mock_rnd.assert_called_with(0x00, 0xff) + + @mock.patch.object(random, 'randint', return_value=0xa2) + def test_no_prefix_replaces_all_parts(self, mock_rnd): + mac = net.get_random_mac(['00', '00', '00', '00', '00', '00']) + + self.assertEqual('a2:a2:a2:a2:a2:a2', mac) + + mock_rnd.assert_called_with(0x00, 0xff) diff --git a/neutron_lib/utils/net.py b/neutron_lib/utils/net.py index 3dd5167f4..55996cf8e 100644 --- a/neutron_lib/utils/net.py +++ b/neutron_lib/utils/net.py @@ -26,12 +26,13 @@ def get_hostname(): def get_random_mac(base_mac): """Get a random MAC address string of the specified base format. - :param base_mac: The base MAC address format for the MAC address string. + Any part that is '00' will be randomized + + :param base_mac: Base MAC address represented by an array of 6 strings/int :returns: The MAC address string. """ - mac = [int(base_mac[0], 16), int(base_mac[1], 16), - int(base_mac[2], 16), random.randint(0x00, 0xff), - random.randint(0x00, 0xff), random.randint(0x00, 0xff)] - if base_mac[3] != '00': - mac[3] = int(base_mac[3], 16) - return ':'.join(["%02x" % x for x in mac]) + + return ':'.join( + "{:02x}".format(random.randint(0x00, 0xff))if p == '00' else p + for p in base_mac + )