summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBence Romsics <bence.romsics@gmail.com>2020-06-25 16:36:49 +0200
committerBence Romsics <bence.romsics@gmail.com>2020-06-29 17:15:16 +0200
commitbbf6898b90b78ea36d6f70e4af21ccd4cb1a2b46 (patch)
tree3d988aa50c3611e57355f44bea07b0b6eba510a9
parentbc562f3393e976e7086642f03ef62a914a9b2dcc (diff)
downloadoslo-utils-bbf6898b90b78ea36d6f70e4af21ccd4cb1a2b46.tar.gz
New method in netutils: get_mac_addr_by_ipv6
This method is practically the reverse of get_ipv6_addr_by_EUI64(), so we can extract the MAC address from IPv6 addresses that were generated from interface identifiers. Change-Id: I48720d38649104f9f2f0a8fd208f2aac7548644e Related-Change: https://review.opendev.org/718729
-rw-r--r--oslo_utils/netutils.py29
-rw-r--r--oslo_utils/tests/test_netutils.py33
-rw-r--r--releasenotes/notes/netutils-get_mac_addr_by_ipv6-c3ce6a35a69f7c2b.yaml5
3 files changed, 67 insertions, 0 deletions
diff --git a/oslo_utils/netutils.py b/oslo_utils/netutils.py
index 26e16dc..af06a43 100644
--- a/oslo_utils/netutils.py
+++ b/oslo_utils/netutils.py
@@ -193,6 +193,35 @@ def get_ipv6_addr_by_EUI64(prefix, mac):
'EUI-64: %s') % prefix)
+def get_mac_addr_by_ipv6(ipv6, dialect=netaddr.mac_unix_expanded):
+ """Extract MAC address from interface identifier based IPv6 address.
+
+ For example from link-local addresses (fe80::/10) generated from MAC.
+
+ :param ipv6: An interface identifier (i.e. mostly MAC) based IPv6
+ address as a netaddr.IPAddress() object.
+ :param dialect: The netaddr dialect of the the object returned.
+ Defaults to netaddr.mac_unix_expanded.
+ :returns: A MAC address as a netaddr.EUI() object.
+
+ See also:
+ * https://tools.ietf.org/html/rfc4291#appendix-A
+ * https://tools.ietf.org/html/rfc4291#section-2.5.6
+
+ .. versionadded:: 4.3.0
+ """
+ return netaddr.EUI(int(
+ # out of the lowest 8 bytes (byte positions 8-1)
+ # delete the middle 2 bytes (5-4, 0xff_fe)
+ # by shifting the highest 3 bytes to the right by 2 bytes (8-6 -> 6-4)
+ (((ipv6 & 0xff_ff_ff_00_00_00_00_00) >> 16) +
+ # adding the lowest 3 bytes as they are (3-1)
+ (ipv6 & 0xff_ff_ff)) ^
+ # then invert the universal/local bit
+ 0x02_00_00_00_00_00),
+ dialect=dialect)
+
+
def is_ipv6_enabled():
"""Check if IPv6 support is enabled on the platform.
diff --git a/oslo_utils/tests/test_netutils.py b/oslo_utils/tests/test_netutils.py
index 31d9c75..260e1b1 100644
--- a/oslo_utils/tests/test_netutils.py
+++ b/oslo_utils/tests/test_netutils.py
@@ -17,6 +17,7 @@ import contextlib
import socket
from unittest import mock
+import netaddr
import netifaces
from oslotest import base as test_base
import six
@@ -357,6 +358,38 @@ class IPv6byEUI64TestCase(test_base.BaseTestCase):
netutils.get_ipv6_addr_by_EUI64(prefix, mac))
+class MACbyIPv6TestCase(test_base.BaseTestCase):
+ """Unit tests to extract MAC from IPv6."""
+
+ def test_reverse_generate_IPv6_by_EUI64(self):
+ self.assertEqual(
+ netaddr.EUI('00:16:3e:33:44:55'),
+ netutils.get_mac_addr_by_ipv6(
+ netaddr.IPAddress('2001:db8::216:3eff:fe33:4455')),
+ )
+
+ def test_random_qemu_mac(self):
+ self.assertEqual(
+ netaddr.EUI('52:54:00:42:02:19'),
+ netutils.get_mac_addr_by_ipv6(
+ netaddr.IPAddress('fe80::5054:ff:fe42:219')),
+ )
+
+ def test_local(self):
+ self.assertEqual(
+ netaddr.EUI('02:00:00:00:00:00'),
+ netutils.get_mac_addr_by_ipv6(
+ netaddr.IPAddress('fe80::ff:fe00:0')),
+ )
+
+ def test_universal(self):
+ self.assertEqual(
+ netaddr.EUI('00:00:00:00:00:00'),
+ netutils.get_mac_addr_by_ipv6(
+ netaddr.IPAddress('fe80::200:ff:fe00:0')),
+ )
+
+
@contextlib.contextmanager
def mock_file_content(content):
# Allows StringIO to act like a context manager-enabled file.
diff --git a/releasenotes/notes/netutils-get_mac_addr_by_ipv6-c3ce6a35a69f7c2b.yaml b/releasenotes/notes/netutils-get_mac_addr_by_ipv6-c3ce6a35a69f7c2b.yaml
new file mode 100644
index 0000000..396ed99
--- /dev/null
+++ b/releasenotes/notes/netutils-get_mac_addr_by_ipv6-c3ce6a35a69f7c2b.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ New method ``netutils.get_mac_addr_by_ipv6(ipv6, dialect)`` extracts
+ the MAC address from IPv6 addresses generated from MACs.