pci: Add utility method for getting the MAC addr

We will need to tell Neutron about the MAC address of the PF port as it
cannot set by the VIF driver.

This method lets su figure it out from sysfs

Change-Id: Iad44405488395ce08d1a893f50edfce20fdae7d2
Related-blueprint: sriov-pf-passthrough-neutron-port
This commit is contained in:
Nikola Dipanov 2015-12-30 17:25:32 +00:00
parent 410a87ae29
commit b2385fb781
2 changed files with 88 additions and 4 deletions

View File

@ -23,6 +23,7 @@ from oslo_log import log as logging
import six
from nova import exception
from nova.i18n import _LW
LOG = logging.getLogger(__name__)
@ -105,16 +106,23 @@ def is_physical_function(domain, bus, slot, function):
return False
def _get_sysfs_netdev_path(pci_addr, pf_interface):
"""Get the sysfs path based on the PCI address of the device.
Assumes a networking device - will not check for the existence of the path.
"""
if pf_interface:
return "/sys/bus/pci/devices/%s/physfn/net" % (pci_addr)
return "/sys/bus/pci/devices/%s/net" % (pci_addr)
def get_ifname_by_pci_address(pci_addr, pf_interface=False):
"""Get the interface name based on a VF's pci address
The returned interface name is either the parent PF's or that of the VF
itself based on the argument of pf_interface.
"""
if pf_interface:
dev_path = "/sys/bus/pci/devices/%s/physfn/net" % (pci_addr)
else:
dev_path = "/sys/bus/pci/devices/%s/net" % (pci_addr)
dev_path = _get_sysfs_netdev_path(pci_addr, pf_interface)
try:
dev_info = os.listdir(dev_path)
return dev_info.pop()
@ -122,6 +130,27 @@ def get_ifname_by_pci_address(pci_addr, pf_interface=False):
raise exception.PciDeviceNotFoundById(id=pci_addr)
def get_mac_by_pci_address(pci_addr, pf_interface=False):
"""Get the MAC address of the nic based on it's PCI address
Raises PciDeviceNotFoundById in case the pci device is not a NIC
"""
dev_path = _get_sysfs_netdev_path(pci_addr, pf_interface)
if_name = get_ifname_by_pci_address(pci_addr, pf_interface)
addr_file = os.path.join(dev_path, if_name, 'address')
try:
with open(addr_file) as f:
mac = next(f).strip()
return mac
except (IOError, StopIteration) as e:
LOG.warning(_LW("Could not find the expected sysfs file for "
"determining the MAC address of the PCI device "
"%(addr)s. May not be a NIC. Error: %(e)s"),
{'addr': pci_addr, 'e': e})
raise exception.PciDeviceNotFoundById(id=pci_addr)
def get_vf_num_by_pci_address(pci_addr):
"""Get the VF number based on a VF's pci address

View File

@ -17,6 +17,7 @@
import glob
import os
import fixtures
import mock
from six.moves import builtins
@ -149,6 +150,60 @@ class GetIfnameByPciAddressTestCase(test.NoDBTestCase):
)
class GetMacByPciAddressTestCase(test.NoDBTestCase):
def setUp(self):
super(GetMacByPciAddressTestCase, self).setUp()
self.pci_address = '0000:07:00.1'
self.if_name = 'enp7s0f1'
self.tmpdir = self.useFixture(fixtures.TempDir())
self.fake_file = os.path.join(self.tmpdir.path, "address")
with open(self.fake_file, "w") as f:
f.write("a0:36:9f:72:00:00\n")
@mock.patch.object(os, 'listdir')
@mock.patch.object(os.path, 'join')
def test_get_mac(self, mock_join, mock_listdir):
mock_listdir.return_value = [self.if_name]
mock_join.return_value = self.fake_file
mac = utils.get_mac_by_pci_address(self.pci_address)
mock_join.assert_called_once_with(
"/sys/bus/pci/devices/%s/net" % self.pci_address, self.if_name,
"address")
self.assertEqual("a0:36:9f:72:00:00", mac)
@mock.patch.object(os, 'listdir')
@mock.patch.object(os.path, 'join')
def test_get_mac_fails(self, mock_join, mock_listdir):
os.unlink(self.fake_file)
mock_listdir.return_value = [self.if_name]
mock_join.return_value = self.fake_file
self.assertRaises(
exception.PciDeviceNotFoundById,
utils.get_mac_by_pci_address, self.pci_address)
@mock.patch.object(os, 'listdir')
@mock.patch.object(os.path, 'join')
def test_get_mac_fails_empty(self, mock_join, mock_listdir):
with open(self.fake_file, "w") as f:
f.truncate(0)
mock_listdir.return_value = [self.if_name]
mock_join.return_value = self.fake_file
self.assertRaises(
exception.PciDeviceNotFoundById,
utils.get_mac_by_pci_address, self.pci_address)
@mock.patch.object(os, 'listdir')
@mock.patch.object(os.path, 'join')
def test_get_physical_function_mac(self, mock_join, mock_listdir):
mock_listdir.return_value = [self.if_name]
mock_join.return_value = self.fake_file
mac = utils.get_mac_by_pci_address(self.pci_address, pf_interface=True)
mock_join.assert_called_once_with(
"/sys/bus/pci/devices/%s/physfn/net" % self.pci_address,
self.if_name, "address")
self.assertEqual("a0:36:9f:72:00:00", mac)
class GetVfNumByPciAddressTestCase(test.NoDBTestCase):
def setUp(self):