diff --git a/os_brick/initiator/connectors/nvmeof.py b/os_brick/initiator/connectors/nvmeof.py index 31e9761a3..ac905f1f3 100644 --- a/os_brick/initiator/connectors/nvmeof.py +++ b/os_brick/initiator/connectors/nvmeof.py @@ -398,8 +398,9 @@ class Target(object): # Unlike "nvme list-subsys -o json" sysfs addr is separated by a comma sysfs_portals: list[tuple[Optional[str], Optional[str], + Optional[Union[str, utils.Anything]], Optional[Union[str, utils.Anything]]]] = [ - (f'traddr={p.address},trsvcid={p.port}', p.transport, hostnqn) + (p.address, p.port, p.transport, hostnqn) for p in self.portals ] known_names: list[str] = [p.controller for p in self.portals @@ -421,7 +422,19 @@ class Target(object): # The right subsystem, but must also be the right portal ctrl_transport = sysfs_property('transport', ctrl_path) - ctrl_addr = sysfs_property('address', ctrl_path) + + # Address in sysfs may contain src_addr in some systems. Parse and + # only use destination addr and port + address = sysfs_property('address', ctrl_path) + if not address: + LOG.error("Couldn't read address for %s", ctrl_path) + continue + ctrl_address = dict((x.split('=') + for x in address.split(','))) + + ctrl_addr = ctrl_address['traddr'] + ctrl_port = ctrl_address['trsvcid'] + # hostnqn value not present in all OSs. Ignore when not present ctrl_hostnqn = sysfs_property('hostnqn', ctrl_path) or utils.ANY # Warn once per target for OS not presenting the hostnqn on sysfs @@ -430,7 +443,7 @@ class Target(object): "Controller may be incorrectly matched.") warned = True - ctrl_portal = (ctrl_addr, ctrl_transport, ctrl_hostnqn) + ctrl_portal = (ctrl_addr, ctrl_port, ctrl_transport, ctrl_hostnqn) try: index = sysfs_portals.index(ctrl_portal) diff --git a/os_brick/tests/initiator/connectors/test_nvmeof.py b/os_brick/tests/initiator/connectors/test_nvmeof.py index 5321a6dbb..e13e70773 100644 --- a/os_brick/tests/initiator/connectors/test_nvmeof.py +++ b/os_brick/tests/initiator/connectors/test_nvmeof.py @@ -469,9 +469,11 @@ class TargetTestCase(test_base.TestCase): self.target.set_portals_controllers() mock_glob.assert_not_called() + @ddt.data('traddr=portal2,trsvcid=port2', + 'traddr=portal2,trsvcid=port2,src_addr=myip') @mock.patch.object(nvmeof, 'sysfs_property') @mock.patch('glob.glob') - def test_set_portals_controllers(self, mock_glob, mock_sysfs): + def test_set_portals_controllers(self, addr, mock_glob, mock_sysfs): """Look in sysfs for the device paths.""" portal = nvmeof.Portal(self.target, 'portal4', 'port4', 'tcp') portal.controller = 'nvme0' @@ -494,7 +496,7 @@ class TargetTestCase(test_base.TestCase): # nvme3 matches first portal but not the host_nqn self.target.nqn, 'rdma', 'traddr=portal2,trsvcid=port2', 'badnqn', # nvme4 matches first portal - self.target.nqn, 'tcp', 'traddr=portal2,trsvcid=port2', 'nqn', + self.target.nqn, 'tcp', addr, 'nqn', # nvme5 simulates OS doesn't have the hostnqn attribute self.target.nqn, 'tcp', 'traddr=portal5,trsvcid=port5', None, ] diff --git a/releasenotes/notes/nvmeof-new-address-56044523cf8fc203.yaml b/releasenotes/notes/nvmeof-new-address-56044523cf8fc203.yaml new file mode 100644 index 000000000..07b84d8f3 --- /dev/null +++ b/releasenotes/notes/nvmeof-new-address-56044523cf8fc203.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + NVMe-oF connector `bug #2035811 + `_: Fixed + attaching volumes on systems using newer NVMe kernel modules that present + additional information in ``/sys/class/nvme/nvme#/address``. +