Merge "netutils: Use ethtool ioctl to get permanent mac address"
This commit is contained in:
commit
b51cc75ff3
@ -34,6 +34,13 @@ LLDP_ETHERTYPE = 0x88cc
|
||||
IFF_PROMISC = 0x100
|
||||
SIOCGIFFLAGS = 0x8913
|
||||
SIOCSIFFLAGS = 0x8914
|
||||
# SIOCETHTOOL from linux/sockios.h
|
||||
SIOCETHTOOL = 0x8946
|
||||
# ETHTOOL_GPERMADDR from linux/ethtool.h
|
||||
ETHTOOL_GPERMADDR = 0x00000020
|
||||
# MAX_ADDR_LEN from linux/netdevice.h
|
||||
MAX_ADDR_LEN = 32
|
||||
|
||||
INFINIBAND_ADDR_LEN = 59
|
||||
|
||||
# LLDP definitions needed to extract vlan information
|
||||
@ -45,10 +52,25 @@ dot1_VLAN_NAME = "03"
|
||||
VLAN_ID_LEN = len(LLDP_802dot1_OUI + dot1_VLAN_NAME)
|
||||
|
||||
|
||||
class ethtoolPermAddr(ctypes.Structure):
|
||||
"""Class for getting interface permanent MAC address"""
|
||||
_fields_ = [("cmd", ctypes.c_uint32),
|
||||
("size", ctypes.c_uint32),
|
||||
("data", ctypes.c_uint8 * MAX_ADDR_LEN)]
|
||||
|
||||
|
||||
class ifreq_data(ctypes.Union):
|
||||
_fields_ = [("ifr_flags", ctypes.c_short),
|
||||
(
|
||||
"ifr_data_ethtool_perm_addr",
|
||||
ctypes.POINTER(ethtoolPermAddr))]
|
||||
|
||||
|
||||
class ifreq(ctypes.Structure):
|
||||
"""Class for setting flags on a socket."""
|
||||
"""Class for ioctl on socket."""
|
||||
_anonymous_ = ("ifr_data",)
|
||||
_fields_ = [("ifr_ifrn", ctypes.c_char * 16),
|
||||
("ifr_flags", ctypes.c_short)]
|
||||
("ifr_data", ifreq_data)]
|
||||
|
||||
|
||||
class RawPromiscuousSockets(object):
|
||||
@ -236,6 +258,23 @@ def get_ipv6_addr(interface_id):
|
||||
|
||||
|
||||
def get_mac_addr(interface_id):
|
||||
"""Retrieve permanent mac address, if unable to fallback to default one"""
|
||||
try:
|
||||
data = ethtoolPermAddr(cmd=ETHTOOL_GPERMADDR, size=MAX_ADDR_LEN)
|
||||
ifr = ifreq(ifr_ifrn=interface_id.encode())
|
||||
ifr.ifr_data_ethtool_perm_addr = ctypes.pointer(data)
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
|
||||
fcntl.ioctl(sock.fileno(), SIOCETHTOOL, ifr)
|
||||
# if not full of zeros
|
||||
if any(data.data[:data.size]):
|
||||
# kernel updates size to actual address size during ioctl call
|
||||
permaddr = [f'{b:02x}' for b in data.data[:data.size]]
|
||||
return ':'.join(permaddr)
|
||||
except OSError:
|
||||
pass
|
||||
LOG.warning("Failed to get permanent mac address for interface %s, "
|
||||
"falling back to default mac address",
|
||||
interface_id)
|
||||
return get_default_ip_addr(socket.AF_PACKET, interface_id)
|
||||
|
||||
|
||||
|
@ -6279,6 +6279,7 @@ class TestCollectSystemLogs(base.IronicAgentTest):
|
||||
FakeAddr = namedtuple('FakeAddr', ('family', 'address'))
|
||||
|
||||
|
||||
@mock.patch.object(netutils, 'get_mac_addr', autospec=True)
|
||||
@mock.patch.object(hardware.GenericHardwareManager, '_get_system_lshw_dict',
|
||||
autospec=True, return_value={'id': 'host'})
|
||||
@mock.patch.object(hardware, 'get_managers', autospec=True,
|
||||
@ -6303,7 +6304,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
mocked_lshw.return_value = json.loads(hws.LSHW_JSON_OUTPUT_V2[0])
|
||||
mocked_listdir.return_value = ['lo', 'eth0', 'foobar']
|
||||
mocked_exists.side_effect = [False, False, True, True]
|
||||
@ -6327,6 +6329,10 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_INET6, 'fd00:1000::101')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'eth0': '00:0c:29:8c:11:b1',
|
||||
}.get(iface)
|
||||
mocked_execute.return_value = ('em0\n', '')
|
||||
mock_has_carrier.return_value = True
|
||||
interfaces = self.hardware.list_network_interfaces()
|
||||
@ -6348,7 +6354,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
mocked_listdir.return_value = ['lo', 'eth0']
|
||||
mocked_exists.side_effect = [False, False, True]
|
||||
mocked_open.return_value.__enter__ = lambda s: s
|
||||
@ -6367,6 +6374,10 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_PACKET, '00:0c:29:8c:11:b1')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'eth0': '00:0c:29:8c:11:b1',
|
||||
}.get(iface)
|
||||
mocked_execute.return_value = ('em0\n', '')
|
||||
mock_has_carrier.return_value = True
|
||||
interfaces = self.hardware.list_network_interfaces()
|
||||
@ -6390,7 +6401,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
CONF.set_override('collect_lldp', True)
|
||||
mocked_listdir.return_value = ['lo', 'eth0']
|
||||
mocked_exists.side_effect = [False, False, True]
|
||||
@ -6410,6 +6422,10 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_PACKET, '00:0c:29:8c:11:b1')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'eth0': '00:0c:29:8c:11:b1',
|
||||
}.get(iface)
|
||||
mocked_lldp_info.return_value = {'eth0': [
|
||||
(0, b''),
|
||||
(1, b'\x04\x88Z\x92\xecTY'),
|
||||
@ -6444,7 +6460,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
CONF.set_override('collect_lldp', True)
|
||||
mocked_listdir.return_value = ['lo', 'eth0']
|
||||
mocked_exists.side_effect = [False, False, True]
|
||||
@ -6464,6 +6481,10 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_PACKET, '00:0c:29:8c:11:b1')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'eth0': '00:0c:29:8c:11:b1',
|
||||
}.get(iface)
|
||||
mocked_lldp_info.side_effect = Exception('Boom!')
|
||||
mocked_execute.return_value = ('em0\n', '')
|
||||
mock_has_carrier.return_value = True
|
||||
@ -6485,7 +6506,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
|
||||
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
|
||||
mocked_listdir.return_value = ['lo', 'eth0']
|
||||
@ -6506,6 +6528,10 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_PACKET, '00:0c:29:8c:11:b1')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'eth0': '00:0c:29:8c:11:b1',
|
||||
}.get(iface)
|
||||
mocked_execute.return_value = ('em0\n', '')
|
||||
mock_has_carrier.return_value = False
|
||||
interfaces = self.hardware.list_network_interfaces()
|
||||
@ -6526,7 +6552,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
mocked_listdir.return_value = ['lo', 'eth0']
|
||||
mocked_exists.side_effect = [False, False, True]
|
||||
mocked_open.return_value.__enter__ = lambda s: s
|
||||
@ -6546,6 +6573,10 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_PACKET, '00:0c:29:8c:11:b1')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'eth0': '00:0c:29:8c:11:b1',
|
||||
}.get(iface)
|
||||
mocked_execute.return_value = ('em0\n', '')
|
||||
mock_has_carrier.return_value = True
|
||||
interfaces = self.hardware.list_network_interfaces()
|
||||
@ -6567,7 +6598,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
mocked_listdir.return_value = ['lo', 'bond0']
|
||||
mocked_exists.side_effect = [False, False, True]
|
||||
mocked_open.return_value.__enter__ = lambda s: s
|
||||
@ -6586,6 +6618,10 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_PACKET, '00:0c:29:8c:11:b1')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'bond0': '00:0c:29:8c:11:b1',
|
||||
}.get(iface)
|
||||
mocked_execute.return_value = ('\n', '')
|
||||
mock_has_carrier.return_value = True
|
||||
interfaces = self.hardware.list_network_interfaces()
|
||||
@ -6610,7 +6646,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
mocked_listdir.return_value = ['lo', 'eth0']
|
||||
mocked_exists.side_effect = [False, False, True]
|
||||
mocked_open.return_value.__enter__ = lambda s: s
|
||||
@ -6629,6 +6666,10 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_PACKET, '00:0c:29:8c:11:b1')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'eth0': '00:0c:29:8c:11:b1',
|
||||
}.get(iface)
|
||||
mocked_execute.return_value = ('em0\n', '')
|
||||
mock_has_carrier.return_value = True
|
||||
mock_get_pci.return_value = '0000:02:00.0'
|
||||
@ -6654,7 +6695,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
CONF.set_override('enable_vlan_interfaces', 'eth0.100')
|
||||
mocked_listdir.return_value = ['lo', 'eth0']
|
||||
mocked_exists.side_effect = [False, False, True]
|
||||
@ -6679,6 +6721,11 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_PACKET, '00:0c:29:8c:11:b1')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'eth0': '00:0c:29:8c:11:b1',
|
||||
'eth0.100': '00:0c:29:8c:11:b1',
|
||||
}.get(iface)
|
||||
mocked_execute.return_value = ('em0\n', '')
|
||||
mock_has_carrier.return_value = True
|
||||
interfaces = self.hardware.list_network_interfaces()
|
||||
@ -6702,7 +6749,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
CONF.set_override('collect_lldp', True)
|
||||
CONF.set_override('enable_vlan_interfaces', 'eth0')
|
||||
mocked_listdir.return_value = ['lo', 'eth0']
|
||||
@ -6734,6 +6782,12 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
FakeAddr(socket.AF_PACKET, '00:0c:29:8c:11:c2')
|
||||
]
|
||||
}
|
||||
mocked_get_mac_addr.side_effect = lambda iface: {
|
||||
'lo': '00:00:00:00:00:00',
|
||||
'eth0': '00:0c:29:8c:11:b1',
|
||||
'eth0.100': '00:0c:29:8c:11:c1',
|
||||
'eth0.101': '00:0c:29:8c:11:c2',
|
||||
}.get(iface)
|
||||
mocked_lldp_info.return_value = {'eth0': [
|
||||
(0, b''),
|
||||
(127, b'\x00\x80\xc2\x03\x00d\x08vlan-100'),
|
||||
@ -6767,7 +6821,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
CONF.set_override('collect_lldp', True)
|
||||
CONF.set_override('enable_vlan_interfaces', 'enp0s1')
|
||||
mocked_listdir.return_value = ['lo', 'eth0']
|
||||
@ -6805,7 +6860,8 @@ class TestListNetworkInterfaces(base.IronicAgentTest):
|
||||
mocked_listdir,
|
||||
mocked_net_if_addrs,
|
||||
mockedget_managers,
|
||||
mocked_lshw):
|
||||
mocked_lshw,
|
||||
mocked_get_mac_addr):
|
||||
CONF.set_override('collect_lldp', True)
|
||||
CONF.set_override('enable_vlan_interfaces', 'all')
|
||||
mocked_listdir.return_value = ['lo', 'eth0', 'eth1']
|
||||
|
@ -0,0 +1,9 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixes IPA collecting the effective MAC address of NICs instead of the
|
||||
pesistent MAC address. In case it fails to fetch the persistent address
|
||||
falls back to effective MAC address.
|
||||
See https://bugs.launchpad.net/ironic-python-agent/+bug/2103450 for
|
||||
details.
|
||||
|
Loading…
x
Reference in New Issue
Block a user