summaryrefslogtreecommitdiffstats
path: root/libnvme
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-06-30 22:36:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-06-30 22:36:10 +0000
commit61d0a8bdffbbb7229776d2f4f2e79ed22d21551f (patch)
tree2e249969fedce45eb37ae6314ad167595900fe38 /libnvme
parentReleasing debian version 1.4-4. (diff)
downloadlibnvme-61d0a8bdffbbb7229776d2f4f2e79ed22d21551f.tar.xz
libnvme-61d0a8bdffbbb7229776d2f4f2e79ed22d21551f.zip
Merging upstream version 1.5.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libnvme')
-rw-r--r--libnvme/meson.build20
-rw-r--r--libnvme/nvme.i253
-rw-r--r--libnvme/tests/NBFTbin0 -> 1017 bytes
-rwxr-xr-xlibnvme/tests/test-nbft.py93
4 files changed, 357 insertions, 9 deletions
diff --git a/libnvme/meson.build b/libnvme/meson.build
index 4138df3..12a601e 100644
--- a/libnvme/meson.build
+++ b/libnvme/meson.build
@@ -8,6 +8,7 @@
want_python = get_option('python')
if want_python.disabled()
build_python_bindings = false
+ py3_dep = dependency('', required: false) # Needed for muon
else
python3 = import('python').find_installation('python3')
py3_dep = python3.dependency(required: want_python)
@@ -17,11 +18,19 @@ else
endif
if build_python_bindings
+ r = run_command(swig, ['-version'], check: true) # Returns: "\nSWIG Version 4.1.1\n\nCompiled with ..."
+ swig_version = r.stdout().split('\n')[1].split()[2].strip()
+ if swig_version.version_compare('<4.1.0')
+ swig_cmd = [swig, '-python', '-py3', '-o', '@OUTPUT1@', '@INPUT0@']
+ else
+ swig_cmd = [swig, '-python', '-o', '@OUTPUT1@', '@INPUT0@']
+ endif
+
pymod_swig = custom_target(
'nvme.py',
input: ['nvme.i'],
output: ['nvme.py', 'nvme_wrap.c'],
- command: [swig, '-python', '-py3', '-o', '@OUTPUT1@', '@INPUT0@'],
+ command: swig_cmd,
install: true,
install_dir: [python3.get_install_dir(pure: false, subdir: 'libnvme'), false],
)
@@ -61,12 +70,13 @@ if build_python_bindings
test('[Python] import libnvme', python3, args: ['-c', 'from libnvme import nvme'], env: test_env, depends: pynvme_clib)
py_tests = [
- [ 'create ctrl object', files('tests/create-ctrl-obj.py') ],
- [ 'SIGSEGV during gc', files('tests/gc.py') ],
+ [ 'create ctrl object', [ files('tests/create-ctrl-obj.py'), ] ],
+ [ 'SIGSEGV during gc', [ files('tests/gc.py'), ] ],
+ [ 'Read NBFT file', [ files('tests/test-nbft.py'), '--filename', join_paths(meson.current_source_dir(), 'tests', 'NBFT') ] ],
]
foreach test: py_tests
description = test[0]
- py_script = test[1]
- test('[Python] ' + description, python3, args: [py_script, ], env: test_env, depends: pynvme_clib)
+ args = test[1]
+ test('[Python] ' + description, python3, args: args, env: test_env, depends: pynvme_clib)
endforeach
endif
diff --git a/libnvme/nvme.i b/libnvme/nvme.i
index cc939da..eb94cac 100644
--- a/libnvme/nvme.i
+++ b/libnvme/nvme.i
@@ -28,6 +28,7 @@
#include "nvme/log.h"
#include "nvme/ioctl.h"
#include "nvme/types.h"
+ #include "nvme/nbft.h"
static int host_iter_err = 0;
static int subsys_iter_err = 0;
@@ -314,7 +315,7 @@ PyObject *hostid_from_file();
PyDict_SetItemStringDecRef(entry, "asqsz", val);
val = PyLong_FromLong(e->eflags);
PyDict_SetItemStringDecRef(entry, "eflags", val);
- PyList_SetItem(obj, i, entry); /* steals ref. to entry */
+ PyList_SetItem(obj, i, entry); /* steals ref. to object - no need to decref */
}
$result = obj;
};
@@ -325,7 +326,9 @@ PyObject *hostid_from_file();
struct nvme_root {
%immutable config_file;
+ %immutable application;
char *config_file;
+ char *application;
};
struct nvme_host {
@@ -345,10 +348,12 @@ struct nvme_subsystem {
%immutable model;
%immutable serial;
%immutable firmware;
+ %immutable application;
char *subsysnqn;
char *model;
char *serial;
char *firmware;
+ char *application;
};
struct nvme_ctrl {
@@ -611,7 +616,9 @@ struct nvme_ns {
%pythonappend nvme_ctrl::connect(struct nvme_host *h,
struct nvme_fabrics_config *cfg) {
- self.__parent = h # Keep a reference to parent to ensure garbage collection happens in the right order}
+ self.__host = h # Keep a reference to parent to ensure ctrl obj gets GCed before host}
+%pythonappend nvme_ctrl::init(struct nvme_host *h, int instance) {
+ self.__host = h # Keep a reference to parent to ensure ctrl obj gets GCed before host}
%extend nvme_ctrl {
nvme_ctrl(struct nvme_root *r,
const char *subsysnqn,
@@ -733,7 +740,7 @@ struct nvme_ns {
if (!obj) Py_RETURN_NONE;
for (int i = 0; i < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; i++)
- PyList_SetItem(obj, i, PyLong_FromLong(le32_to_cpu(log.lid_support[i]))); /* steals ref. */
+ PyList_SetItem(obj, i, PyLong_FromLong(le32_to_cpu(log.lid_support[i]))); /* steals ref. to object - no need to decref */
return obj;
}
@@ -812,12 +819,250 @@ struct nvme_ns {
}
%};
+/******
+ NBFT
+ ******/
+%{
+ static PyObject *ssns_to_dict(struct nbft_info_subsystem_ns *ss)
+ {
+ unsigned int i;
+ PyObject *output = PyDict_New();
+ PyObject *hfis = PyList_New(ss->num_hfis);
+
+ for (i = 0; i < ss->num_hfis; i++)
+ PyList_SetItem(hfis, i, PyLong_FromLong(ss->hfis[i]->index - 1)); /* steals ref. to object - no need to decref */
+
+ PyDict_SetItemStringDecRef(output, "hfi_indexes", hfis);
+
+ PyDict_SetItemStringDecRef(output, "trtype", PyUnicode_FromString(ss->transport));
+ PyDict_SetItemStringDecRef(output, "traddr", PyUnicode_FromString(ss->traddr));
+ PyDict_SetItemStringDecRef(output, "trsvcid", PyUnicode_FromString(ss->trsvcid));
+ PyDict_SetItemStringDecRef(output, "subsys_port_id", PyLong_FromLong(ss->subsys_port_id));
+ PyDict_SetItemStringDecRef(output, "nsid", PyLong_FromLong(ss->nsid));
+
+ {
+ PyObject *nid;
+ switch (ss->nid_type) {
+ case NBFT_INFO_NID_TYPE_EUI64:
+ PyDict_SetItemStringDecRef(output, "nid_type", PyUnicode_FromString("eui64"));
+ nid = PyUnicode_FromFormat("%02x%02x%02x%02x%02x%02x%02x%02x",
+ ss->nid[0], ss->nid[1], ss->nid[2], ss->nid[3],
+ ss->nid[4], ss->nid[5], ss->nid[6], ss->nid[7]);
+ break;
+
+ case NBFT_INFO_NID_TYPE_NGUID:
+ PyDict_SetItemStringDecRef(output, "nid_type", PyUnicode_FromString("nguid"));
+ nid = PyUnicode_FromFormat("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ ss->nid[0], ss->nid[1], ss->nid[2], ss->nid[3],
+ ss->nid[4], ss->nid[5], ss->nid[6], ss->nid[7],
+ ss->nid[8], ss->nid[9], ss->nid[10], ss->nid[11],
+ ss->nid[12], ss->nid[13], ss->nid[14], ss->nid[15]);
+ break;
+
+ case NBFT_INFO_NID_TYPE_NS_UUID:
+ {
+ char uuid_str[NVME_UUID_LEN_STRING];
+ PyDict_SetItemStringDecRef(output, "nid_type", PyUnicode_FromString("uuid"));
+ nvme_uuid_to_string(ss->nid, uuid_str);
+ nid = PyUnicode_FromString(uuid_str);
+ break;
+ }
+
+ default:
+ nid = NULL;
+ break;
+ }
+ if (nid)
+ PyDict_SetItemStringDecRef(output, "nid", nid);
+ }
+
+ if (ss->subsys_nqn)
+ PyDict_SetItemStringDecRef(output, "subsys_nqn", PyUnicode_FromString(ss->subsys_nqn));
+
+ PyDict_SetItemStringDecRef(output, "controller_id", PyLong_FromLong(ss->controller_id));
+ PyDict_SetItemStringDecRef(output, "asqsz", PyLong_FromLong(ss->asqsz));
+
+ if (ss->dhcp_root_path_string)
+ PyDict_SetItemStringDecRef(output, "dhcp_root_path_string", PyUnicode_FromString(ss->dhcp_root_path_string));
+
+ PyDict_SetItemStringDecRef(output, "pdu_header_digest_required", PyBool_FromLong(ss->pdu_header_digest_required));
+ PyDict_SetItemStringDecRef(output, "data_digest_required", PyBool_FromLong(ss->data_digest_required));
+
+ return output;
+ }
+
+ static PyObject *hfi_to_dict(struct nbft_info_hfi *hfi)
+ {
+ PyObject *output = PyDict_New();
+
+ PyDict_SetItemStringDecRef(output, "trtype", PyUnicode_FromString(hfi->transport));
+
+ if (!strcmp(hfi->transport, "tcp")) {
+ PyDict_SetItemStringDecRef(output, "pcidev",
+ PyUnicode_FromFormat("%x:%x:%x.%x",
+ ((hfi->tcp_info.pci_sbdf & 0xffff0000) >> 16),
+ ((hfi->tcp_info.pci_sbdf & 0x0000ff00) >> 8),
+ ((hfi->tcp_info.pci_sbdf & 0x000000f8) >> 3),
+ ((hfi->tcp_info.pci_sbdf & 0x00000007) >> 0)));
+
+ PyDict_SetItemStringDecRef(output, "mac_addr",
+ PyUnicode_FromFormat("%02x:%02x:%02x:%02x:%02x:%02x",
+ hfi->tcp_info.mac_addr[0],
+ hfi->tcp_info.mac_addr[1],
+ hfi->tcp_info.mac_addr[2],
+ hfi->tcp_info.mac_addr[3],
+ hfi->tcp_info.mac_addr[4],
+ hfi->tcp_info.mac_addr[5]));
+
+ PyDict_SetItemStringDecRef(output, "vlan", PyLong_FromLong(hfi->tcp_info.vlan));
+ PyDict_SetItemStringDecRef(output, "ip_origin", PyLong_FromLong(hfi->tcp_info.ip_origin));
+ PyDict_SetItemStringDecRef(output, "ipaddr", PyUnicode_FromString(hfi->tcp_info.ipaddr));
+ PyDict_SetItemStringDecRef(output, "subnet_mask_prefix", PyLong_FromLong(hfi->tcp_info.subnet_mask_prefix));
+ PyDict_SetItemStringDecRef(output, "gateway_ipaddr", PyUnicode_FromString(hfi->tcp_info.gateway_ipaddr));
+ PyDict_SetItemStringDecRef(output, "route_metric", PyLong_FromLong(hfi->tcp_info.route_metric));
+ PyDict_SetItemStringDecRef(output, "primary_dns_ipaddr", PyUnicode_FromString(hfi->tcp_info.primary_dns_ipaddr));
+ PyDict_SetItemStringDecRef(output, "secondary_dns_ipaddr", PyUnicode_FromString(hfi->tcp_info.secondary_dns_ipaddr));
+ PyDict_SetItemStringDecRef(output, "dhcp_server_ipaddr", PyUnicode_FromString(hfi->tcp_info.dhcp_server_ipaddr));
+
+ if (hfi->tcp_info.host_name)
+ PyDict_SetItemStringDecRef(output, "host_name", PyUnicode_FromString(hfi->tcp_info.host_name));
+
+ PyDict_SetItemStringDecRef(output, "this_hfi_is_default_route", PyBool_FromLong(hfi->tcp_info.this_hfi_is_default_route));
+ PyDict_SetItemStringDecRef(output, "dhcp_override", PyBool_FromLong(hfi->tcp_info.dhcp_override));
+ }
+
+ return output;
+ }
+
+ static PyObject *discovery_to_dict(struct nbft_info_discovery *disc)
+ {
+ PyObject *output = PyDict_New();
+
+ if (disc->security)
+ PyDict_SetItemStringDecRef(output, "security_index", PyLong_FromLong(disc->security->index));
+ if (disc->hfi)
+ PyDict_SetItemStringDecRef(output, "hfi_index", PyLong_FromLong(disc->hfi->index - 1));
+ if (disc->uri)
+ PyDict_SetItemStringDecRef(output, "uri", PyUnicode_FromString(disc->uri));
+ if (disc->nqn)
+ PyDict_SetItemStringDecRef(output, "nqn", PyUnicode_FromString(disc->nqn));
+
+ return output;
+ }
+
+ static PyObject *nbft_to_pydict(struct nbft_info *nbft)
+ {
+ PyObject *val;
+ PyObject *output = PyDict_New();
+
+ {
+ PyObject *host = PyDict_New();
+
+ if (nbft->host.nqn)
+ PyDict_SetItemStringDecRef(host, "nqn", PyUnicode_FromString(nbft->host.nqn));
+ if (nbft->host.id) {
+ char uuid_str[NVME_UUID_LEN_STRING];
+ nvme_uuid_to_string((unsigned char *)nbft->host.id, uuid_str);
+ PyDict_SetItemStringDecRef(host, "id", PyUnicode_FromString(uuid_str));
+ }
+
+ PyDict_SetItemStringDecRef(host, "host_id_configured", PyBool_FromLong(nbft->host.host_id_configured));
+ PyDict_SetItemStringDecRef(host, "host_nqn_configured", PyBool_FromLong(nbft->host.host_nqn_configured));
+
+ val = PyUnicode_FromString(nbft->host.primary == NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_NOT_INDICATED ? "not indicated" :
+ nbft->host.primary == NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_UNSELECTED ? "unselected" :
+ nbft->host.primary == NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_SELECTED ? "selected" : "reserved");
+ PyDict_SetItemStringDecRef(host, "primary_admin_host_flag", val);
+
+ PyDict_SetItemStringDecRef(output, "host", host);
+ }
+
+ {
+ size_t ss_num = 0;
+ struct nbft_info_subsystem_ns **ss;
+ PyObject *subsystem;
+
+ /* First, let's find how many entries there are */
+ for (ss = nbft->subsystem_ns_list; ss && *ss; ss++)
+ ss_num++;
+
+ /* Now, let's fill the list using "(*ss)->index - 1"
+ as the index for writing to the list */
+ subsystem = PyList_New(ss_num);
+ for (ss = nbft->subsystem_ns_list; ss && *ss; ss++)
+ PyList_SetItem(subsystem, (*ss)->index - 1, ssns_to_dict(*ss)); /* steals ref. to object - no need to decref */
+
+ PyDict_SetItemStringDecRef(output, "subsystem", subsystem);
+ }
+
+ {
+ size_t hfi_num = 0;
+ struct nbft_info_hfi **hfi;
+ PyObject *hfis;
+
+ /* First, let's find how many entries there are */
+ for (hfi = nbft->hfi_list; hfi && *hfi; hfi++)
+ hfi_num++;
+
+ /* Now, let's fill the list using "(*hfi)->index - 1"
+ as the index for writing to the list */
+ hfis = PyList_New(hfi_num);
+ for (hfi = nbft->hfi_list; hfi && *hfi; hfi++)
+ PyList_SetItem(hfis, (*hfi)->index-1, hfi_to_dict(*hfi)); /* steals ref. to object - no need to decref */
+
+ PyDict_SetItemStringDecRef(output, "hfi", hfis);
+ }
+
+ {
+ size_t disc_num = 0;
+ struct nbft_info_discovery **disc;
+ PyObject *discovery;
+
+ /* First, let's find how many entries there are */
+ for (disc = nbft->discovery_list; disc && *disc; disc++)
+ disc_num++;
+
+ /* Now, let's fill the list using "(*disc)->index - 1"
+ as the index for writing to the list */
+ discovery = PyList_New(disc_num);
+ for (disc = nbft->discovery_list; disc && *disc; disc++)
+ PyList_SetItem(discovery, (*disc)->index - 1, discovery_to_dict(*disc)); /* steals ref. to object - no need to decref */
+
+ PyDict_SetItemStringDecRef(output, "discovery", discovery);
+ }
+
+ /* Security profiles are currently not implemented. */
+
+ return output;
+ }
+
+ PyObject *nbft_get(const char * filename)
+ {
+ struct nbft_info *nbft;
+ PyObject *output;
+ int ret;
+
+ ret = nvme_nbft_read(&nbft, filename);
+ if (ret) {
+ Py_RETURN_NONE;
+ }
+
+ output = nbft_to_pydict(nbft);
+ nvme_nbft_free(nbft);
+ return output;
+ }
+%};
+
+%feature("autodoc", "@return an NBFT table as a dict on success, None otherwise.\n"
+ "@param filename: file to read") nbft_get;
+PyObject *nbft_get(const char * filename);
// We want to swig all the #define and enum from types.h, but none of the structs.
+#pragma SWIG nowarn=503 // Supress warnings about unnamed struct
#define __attribute__(x)
%rename($ignore, %$isclass) ""; // ignore all classes/structs
%rename($ignore, %$isfunction) ""; // ignore all functions
%rename($ignore, %$isunion) ""; // ignore all unions
-%rename($ignore, %$isvariable ) ""; // ignore all variables
+%rename($ignore, %$isvariable) ""; // ignore all variables
%include "../src/nvme/types.h"
diff --git a/libnvme/tests/NBFT b/libnvme/tests/NBFT
new file mode 100644
index 0000000..2dea936
--- /dev/null
+++ b/libnvme/tests/NBFT
Binary files differ
diff --git a/libnvme/tests/test-nbft.py b/libnvme/tests/test-nbft.py
new file mode 100755
index 0000000..3aeeba4
--- /dev/null
+++ b/libnvme/tests/test-nbft.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: LGPL-2.1-or-later
+import os
+import unittest
+from libnvme import nvme
+from argparse import ArgumentParser
+
+
+class Testclass(unittest.TestCase):
+ def setUp(self):
+ self.expected_nbft = {
+ "discovery": [
+ {
+ "hfi_index": 0,
+ "nqn": "nqn.2014-08.org.nvmexpress.discovery",
+ "uri": "nvme+tcp://100.71.103.50:8009/",
+ }
+ ],
+ "hfi": [
+ {
+ "dhcp_override": True,
+ "dhcp_server_ipaddr": "100.71.245.254",
+ "gateway_ipaddr": "100.71.245.254",
+ "ip_origin": 82,
+ "ipaddr": "100.71.245.232",
+ "mac_addr": "b0:26:28:e8:7c:0e",
+ "pcidev": "0:40:0.0",
+ "primary_dns_ipaddr": "100.64.0.5",
+ "route_metric": 500,
+ "secondary_dns_ipaddr": "100.64.0.6",
+ "subnet_mask_prefix": 24,
+ "this_hfi_is_default_route": 1,
+ "trtype": "tcp",
+ "vlan": 0,
+ }
+ ],
+ "host": {
+ "host_id_configured": True,
+ "host_nqn_configured": True,
+ "id": "44454c4c-3400-1036-8038-b2c04f313233",
+ "nqn": "nqn.1988-11.com.dell:PowerEdge.R760.1234567",
+ "primary_admin_host_flag": "not indicated",
+ },
+ "subsystem": [
+ {
+ "asqsz": 0,
+ "controller_id": 5,
+ "data_digest_required": False,
+ "hfi_indexes": [0],
+ "nid": "c82404ed9c15f53b8ccf0968002e0fca",
+ "nid_type": "nguid",
+ "nsid": 148,
+ "pdu_header_digest_required": False,
+ "subsys_nqn": "nqn.1988-11.com.dell:powerstore:00:2a64abf1c5b81F6C4549",
+ "subsys_port_id": 0,
+ "traddr": "100.71.103.48",
+ "trsvcid": "4420",
+ "trtype": "tcp",
+ },
+ {
+ "asqsz": 0,
+ "controller_id": 4166,
+ "data_digest_required": False,
+ "hfi_indexes": [0],
+ "nid": "c82404ed9c15f53b8ccf0968002e0fca",
+ "nid_type": "nguid",
+ "nsid": 148,
+ "pdu_header_digest_required": False,
+ "subsys_nqn": "nqn.1988-11.com.dell:powerstore:00:2a64abf1c5b81F6C4549",
+ "subsys_port_id": 0,
+ "traddr": "100.71.103.49",
+ "trsvcid": "4420",
+ "trtype": "tcp",
+ },
+ ],
+ }
+
+ def test_read_nbft_file(self):
+ """Make sure we get expected data when reading from binary NBFT file"""
+ actual_nbft = nvme.nbft_get(args.filename)
+ self.assertEqual(actual_nbft, self.expected_nbft)
+
+
+if __name__ == "__main__":
+ import sys
+
+ parser = ArgumentParser(description="Test NBFT")
+ parser.add_argument("--filename", default=None, help="NBFT binary file to read")
+ parser.add_argument("unittest_args", nargs="*") # Grab everything else
+ args = parser.parse_args()
+ sys.argv[1:] = args.unittest_args
+
+ unittest.main()