diff --git a/.gitignore b/.gitignore index 5add3b2..3555f05 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ /nvme-cli-2.2.1.tar.gz /nvme-cli-2.3.tar.gz /nvme-cli-2.4.tar.gz +/nvme-cli-2.5.tar.gz diff --git a/nvme-cli-2.5-nbft-make-lookup_ctrl-function-public.patch b/nvme-cli-2.5-nbft-make-lookup_ctrl-function-public.patch deleted file mode 100644 index 78529b9..0000000 --- a/nvme-cli-2.5-nbft-make-lookup_ctrl-function-public.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 34c197e0ac2d57734ab775f00b2d0758aca7b82f Mon Sep 17 00:00:00 2001 -From: John Meneghini -Date: Fri, 14 Apr 2023 10:53:58 -0400 -Subject: [PATCH 01/11] nbft: make lookup_ctrl function public - -To prepare for the addition of nbft functionality fixup the fabrics -declarations. - -Signed-off-by: John Meneghini ---- - fabrics.c | 12 ++---------- - fabrics.h | 10 ++++++++++ - 2 files changed, 12 insertions(+), 10 deletions(-) - -diff --git a/fabrics.c b/fabrics.c -index f8078e59..80827b16 100644 ---- a/fabrics.c -+++ b/fabrics.c -@@ -43,6 +43,7 @@ - #include "libnvme.h" - #include "nvme-print.h" - #include "nvme-print-json.h" -+#include "fabrics.h" - - #define PATH_NVMF_DISC SYSCONFDIR "/nvme/discovery.conf" - #define PATH_NVMF_CONFIG SYSCONFDIR "/nvme/config.json" -@@ -110,15 +111,6 @@ static const char *nvmf_config_file = "Use specified JSON configuration file or - OPT_FLAG("data-digest", 'G', &c.data_digest, nvmf_data_digest), \ - OPT_FLAG("tls", 0, &c.tls, nvmf_tls) \ - --struct tr_config { -- const char *subsysnqn; -- const char *transport; -- const char *traddr; -- const char *host_traddr; -- const char *host_iface; -- const char *trsvcid; --}; -- - /* - * Compare two C strings and handle NULL pointers gracefully. - * If either of the two strings is NULL, return 0 -@@ -202,7 +194,7 @@ static nvme_ctrl_t lookup_discovery_ctrl(nvme_root_t r, struct tr_config *trcfg) - return __lookup_ctrl(r, trcfg, disc_ctrl_config_match); - } - --static nvme_ctrl_t lookup_ctrl(nvme_root_t r, struct tr_config *trcfg) -+nvme_ctrl_t lookup_ctrl(nvme_root_t r, struct tr_config *trcfg) - { - return __lookup_ctrl(r, trcfg, ctrl_config_match); - } -diff --git a/fabrics.h b/fabrics.h -index d1e16fc5..02cebf5d 100644 ---- a/fabrics.h -+++ b/fabrics.h -@@ -2,6 +2,16 @@ - #ifndef _FABRICS_H - #define _FABRICS_H - -+struct tr_config { -+ const char *subsysnqn; -+ const char *transport; -+ const char *traddr; -+ const char *host_traddr; -+ const char *host_iface; -+ const char *trsvcid; -+}; -+ -+extern nvme_ctrl_t lookup_ctrl(nvme_root_t r, struct tr_config *trcfg); - extern int nvmf_discover(const char *desc, int argc, char **argv, bool connect); - extern int nvmf_connect(const char *desc, int argc, char **argv); - extern int nvmf_disconnect(const char *desc, int argc, char **argv); --- -2.39.2 - diff --git a/nvme-cli-2.5-nbft.patch b/nvme-cli-2.5-nbft.patch deleted file mode 100644 index e54da19..0000000 --- a/nvme-cli-2.5-nbft.patch +++ /dev/null @@ -1,451 +0,0 @@ -From a71a08532b5f06ee19ee2ff118a23cec4ecb6719 Mon Sep 17 00:00:00 2001 -From: Stuart Hayes -Date: Wed, 15 Jun 2022 11:42:50 -0500 -Subject: [PATCH 02/11] nbft: added NBFT v1.0 table support - -Added support for parsing the contents of the NBFT table (per NVMe-oF -boot specification v1.0) with the connect-all and discover commands. - -nvme discover/connect-all --nbft ignore /etc/nvme config and use NBFT tables -nvme discover/connect-all --no-nbft ignore NBFT tables and use /etc/nvme config -nvme discover/connect-all --nbft-path= user-defined path for NBFT tables - -Signed-off-by: Stuart Hayes -Signed-off-by: Martin Belanger - -Use the new nbft public API. - -Signed-off-by: Tomas Bzatek -Signed-off-by: Martin Wilck -Signed-off-by: John Meneghini ---- - Documentation/nvme-connect-all.txt | 25 ++++ - Documentation/nvme-discover.txt | 27 +++- - fabrics.c | 17 +++ - meson.build | 1 + - nbft.c | 202 +++++++++++++++++++++++++++++ - nbft.h | 19 +++ - 6 files changed, 290 insertions(+), 1 deletion(-) - create mode 100644 nbft.c - create mode 100644 nbft.h - -diff --git a/Documentation/nvme-connect-all.txt b/Documentation/nvme-connect-all.txt -index 44bb4f94..cbb7ca6c 100644 ---- a/Documentation/nvme-connect-all.txt -+++ b/Documentation/nvme-connect-all.txt -@@ -35,6 +35,9 @@ SYNOPSIS - [--tls ] - [--quiet | -S] - [--dump-config | -O] -+ [--nbft] -+ [--no-nbft] -+ [--nbft-path=] - - DESCRIPTION - ----------- -@@ -198,6 +201,16 @@ OPTIONS - --dump-config:: - Print out resulting JSON configuration file to stdout. - -+--nbft:: -+ Only look at NBFT tables -+ -+--no-nbft:: -+ Do not look at NBFT tables -+ -+--nbft-path=:: -+ Use a user-defined path to the NBFT tables -+ -+ - - EXAMPLES - -------- -@@ -210,6 +223,18 @@ the RDMA network. Port 4420 is used by default: - --hostnqn=host1-rogue-nqn - ------------ - + -+* Issue a 'nvme connect-all' command using the default system defined NBFT tables: -++ -+----------- -+# nvme connect-all --nbft -+------------ -++ -+* Issue a 'nvme connect-all' command with a user-defined path for the NBFT table: -++ -+----------- -+# nvme connet-all --nbft-path=/sys/firmware/acpi/tables/NBFT1 -+------------ -++ - * Issue a 'nvme connect-all' command using a @SYSCONFDIR@/nvme/discovery.conf file: - + - ----------- -diff --git a/Documentation/nvme-discover.txt b/Documentation/nvme-discover.txt -index d4df75c2..b040c688 100644 ---- a/Documentation/nvme-discover.txt -+++ b/Documentation/nvme-discover.txt -@@ -37,6 +37,9 @@ SYNOPSIS - [--dump-config | -O] - [--output-format= | -o ] - [--force] -+ [--nbft] -+ [--no-nbft] -+ [--nbft-path=] - - DESCRIPTION - ----------- -@@ -68,7 +71,7 @@ Note that the base NVMe specification defines the NQN (NVMe Qualified - Name) format which an NVMe endpoint (device, subsystem, etc) must - follow to guarantee a unique name under the NVMe standard. - In particular, the Host NQN uniquely identifies the NVMe Host, and --may be used by the the Discovery Controller to control what NVMe Target -+may be used by the Discovery Controller to control what NVMe Target - resources are allocated to the NVMe Host for a connection. - - A Discovery Controller has it's own NQN defined in the NVMe-over-Fabrics -@@ -229,6 +232,16 @@ OPTIONS - Combined with --persistent flag, always create new - persistent discovery connection. - -+--nbft:: -+ Only look at NBFT tables -+ -+--no-nbft:: -+ Do not look at NBFT tables -+ -+--nbft-path=:: -+ Use a user-defined path to the NBFT tables -+ -+ - EXAMPLES - -------- - * Query the Discover Controller with IP4 address 192.168.1.3 for all -@@ -240,6 +253,18 @@ Port 4420 is used by default: - --hostnqn=host1-rogue-nqn - ------------ - + -+* Issue a 'nvme discover' command using the default system defined NBFT tables: -++ -+----------- -+# nvme discover --nbft -+------------ -++ -+* Issue a 'nvme discover' command with a user-defined path for the NBFT table: -++ -+----------- -+# nvme discover --nbft-path=/sys/firmware/acpi/tables/NBFT1 -+------------ -++ - * Issue a 'nvme discover' command using a @SYSCONFDIR@/nvme/discovery.conf file: - + - ----------- -diff --git a/fabrics.c b/fabrics.c -index 80827b16..0edbd299 100644 ---- a/fabrics.c -+++ b/fabrics.c -@@ -40,6 +40,7 @@ - - #include "common.h" - #include "nvme.h" -+#include "nbft.h" - #include "libnvme.h" - #include "nvme-print.h" - #include "nvme-print-json.h" -@@ -710,6 +711,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) - { - char *subsysnqn = NVME_DISC_SUBSYS_NAME; - char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL; -+ char *hostnqn_arg, *hostid_arg; - char *transport = NULL, *traddr = NULL, *trsvcid = NULL; - char *config_file = PATH_NVMF_CONFIG; - char *hnqn = NULL, *hid = NULL; -@@ -724,6 +726,8 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) - char *device = NULL; - bool force = false; - bool json_config = false; -+ bool nbft = false, nonbft = false; -+ char *nbft_path = NBFT_SYSFS_PATH; - - OPT_ARGS(opts) = { - OPT_STRING("device", 'd', "DEV", &device, "use existing discovery controller device"), -@@ -736,6 +740,9 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) - OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), - OPT_FLAG("dump-config", 'O', &dump_config, "Dump configuration file to stdout"), - OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation"), -+ OPT_FLAG("nbft", 0, &nbft, "Only look at NBFT tables"), -+ OPT_FLAG("no-nbft", 0, &nonbft, "Do not look at NBFT tables"), -+ OPT_STRING("nbft-path", 0, "STR", &nbft_path, "user-defined path for NBFT tables"), - OPT_END() - }; - -@@ -768,6 +775,8 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) - if (!nvme_read_config(r, config_file)) - json_config = true; - -+ hostnqn_arg = hostnqn; -+ hostid_arg = hostid; - if (!hostnqn) - hostnqn = hnqn = nvmf_hostnqn_from_file(); - if (!hostnqn) -@@ -789,6 +798,14 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) - nvme_host_set_dhchap_key(h, hostkey); - - if (!device && !transport && !traddr) { -+ if (!nonbft) -+ discover_from_nbft(r, hostnqn_arg, hostid_arg, -+ hostnqn, hostid, desc, connect, -+ &cfg, nbft_path, flags, verbose); -+ -+ if (nbft) -+ goto out_free; -+ - if (json_config) - ret = discover_from_json_config_file(r, h, desc, - connect, &cfg, -diff --git a/meson.build b/meson.build -index 43ce5f9b..7ec357a9 100644 ---- a/meson.build -+++ b/meson.build -@@ -240,6 +240,7 @@ incdir = include_directories(['ccan']) - - ################################################################################ - sources = [ -+ 'nbft.c', - 'fabrics.c', - 'nvme.c', - 'nvme-models.c', -diff --git a/nbft.c b/nbft.c -new file mode 100644 -index 00000000..14347287 ---- /dev/null -+++ b/nbft.c -@@ -0,0 +1,202 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include -+#include -+#include -+ -+#include "nvme.h" -+#include "nbft.h" -+#include "libnvme.h" -+#include "fabrics.h" -+ -+#define NBFT_SYSFS_FILENAME "NBFT*" -+ -+static void print_connect_msg(nvme_ctrl_t c) -+{ -+ printf("device: %s\n", nvme_ctrl_get_name(c)); -+} -+ -+static void json_connect_msg(nvme_ctrl_t c) -+{ -+ struct json_object *root; -+ -+ root = json_create_object(); -+ json_object_add_value_string(root, "device", nvme_ctrl_get_name(c)); -+ -+ json_print_object(root, NULL); -+ printf("\n"); -+ json_free_object(root); -+} -+ -+int nbft_filter(const struct dirent *dent) -+{ -+ return !fnmatch(NBFT_SYSFS_FILENAME, dent->d_name, FNM_PATHNAME); -+} -+ -+int read_nbft_files(struct list_head *nbft_list, char *path) -+{ -+ struct dirent **dent; -+ char filename[PATH_MAX]; -+ int i, count, ret; -+ struct nbft_file_entry *entry; -+ struct nbft_info *nbft; -+ -+ count = scandir(path, &dent, nbft_filter, NULL); -+ if (count < 0) { -+ fprintf(stderr, "Failed to open %s.\n", path); -+ return -1; -+ } -+ -+ for (i = 0; i < count; i++) { -+ snprintf(filename, sizeof(filename), "%s/%s", path, dent[i]->d_name); -+ ret = nvme_nbft_read(&nbft, filename); -+ if (!ret) { -+ entry = calloc(1, sizeof(*entry)); -+ entry->nbft = nbft; -+ list_add_tail(nbft_list, &entry->node); -+ } -+ free(dent[i]); -+ } -+ free(dent); -+ return 0; -+} -+ -+void free_nbfts(struct list_head *nbft_list) -+{ -+ struct nbft_file_entry *entry; -+ -+ while ((entry = list_pop(nbft_list, struct nbft_file_entry, node))) { -+ nvme_nbft_free(entry->nbft); -+ free(entry); -+ } -+} -+ -+int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, -+ char *hostnqn_sys, char *hostid_sys, -+ const char *desc, bool connect, -+ const struct nvme_fabrics_config *cfg, char *nbft_path, -+ enum nvme_print_flags flags, bool verbose) -+{ -+ char *hostnqn = NULL, *hostid = NULL, *host_traddr = NULL; -+ nvme_host_t h; -+ nvme_ctrl_t c; -+ int ret, i; -+ struct list_head nbft_list; -+ struct nbft_file_entry *entry; -+ struct nbft_info_subsystem_ns **ss; -+ struct nbft_info_hfi *hfi; -+ -+ if (!connect) -+ /* to do: print discovery-type info from NBFT tables */ -+ return 0; -+ -+ list_head_init(&nbft_list); -+ ret = read_nbft_files(&nbft_list, nbft_path); -+ if (ret) -+ goto out_free_2; -+ -+ list_for_each(&nbft_list, entry, node) -+ for (ss = entry->nbft->subsystem_ns_list; ss && *ss; ss++) -+ for (i = 0; i < (*ss)->num_hfis; i++) { -+ nvme_ctrl_t cl; -+ -+ hfi = (*ss)->hfis[i]; -+ if (hostnqn_arg) -+ hostnqn = hostnqn_arg; -+ else { -+ hostnqn = entry->nbft->host.nqn; -+ if (!hostnqn) -+ hostnqn = hostnqn_sys; -+ } -+ -+ if (hostid_arg) -+ hostid = hostid_arg; -+ else if (*entry->nbft->host.id) { -+ hostid = (char *)util_uuid_to_string(entry->nbft->host.id); -+ if (!hostid) -+ hostid = hostid_sys; -+ } -+ -+ h = nvme_lookup_host(r, hostnqn, hostid); -+ if (!h) { -+ errno = ENOMEM; -+ goto out_free; -+ } -+ -+ if (!cfg->host_traddr) { -+ host_traddr = NULL; -+ if (!strncmp((*ss)->transport, "tcp", 3)) -+ host_traddr = hfi->tcp_info.ipaddr; -+ } -+ -+ struct tr_config trcfg = { -+ .subsysnqn = (*ss)->subsys_nqn, -+ .transport = (*ss)->transport, -+ .traddr = (*ss)->traddr, -+ .host_traddr = host_traddr, -+ .host_iface = NULL, -+ .trsvcid = (*ss)->trsvcid, -+ }; -+ -+ /* Already connected ? */ -+ cl = lookup_ctrl(r, &trcfg); -+ if (cl && nvme_ctrl_get_name(cl)) -+ continue; -+ -+ c = nvme_create_ctrl(r, (*ss)->subsys_nqn, (*ss)->transport, -+ (*ss)->traddr, host_traddr, NULL, -+ (*ss)->trsvcid); -+ if (!c) { -+ errno = ENOMEM; -+ goto out_free; -+ } -+ -+ errno = 0; -+ ret = nvmf_add_ctrl(h, c, cfg); -+ -+ /* -+ * With TCP/DHCP, it can happen that the OS -+ * obtains a different local IP address than the -+ * firmware had. Retry without host_traddr. -+ */ -+ if (ret == -1 && errno == ENVME_CONNECT_WRITE && -+ !strcmp((*ss)->transport, "tcp") && -+ strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { -+ nvme_free_ctrl(c); -+ -+ trcfg.host_traddr = NULL; -+ cl = lookup_ctrl(r, &trcfg); -+ if (cl && nvme_ctrl_get_name(cl)) -+ continue; -+ -+ c = nvme_create_ctrl(r, (*ss)->subsys_nqn, (*ss)->transport, -+ (*ss)->traddr, -+ NULL, NULL, (*ss)->trsvcid); -+ if (!c) { -+ errno = ENOMEM; -+ goto out_free; -+ } -+ errno = 0; -+ ret = nvmf_add_ctrl(h, c, cfg); -+ if (ret == 0 && verbose >= 1) -+ fprintf(stderr, -+ "connect with host_traddr=\"%s\" failed, success after omitting host_traddr\n", -+ host_traddr); -+ } -+ -+ if (ret) -+ fprintf(stderr, "no controller found\n"); -+ else { -+ if (flags == NORMAL) -+ print_connect_msg(c); -+ else if (flags == JSON) -+ json_connect_msg(c); -+ } -+out_free: -+ if (errno == ENOMEM) -+ goto out_free_2; -+ } -+out_free_2: -+ free_nbfts(&nbft_list); -+ return errno; -+} -diff --git a/nbft.h b/nbft.h -new file mode 100644 -index 00000000..0e09733f ---- /dev/null -+++ b/nbft.h -@@ -0,0 +1,19 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+ -+#include -+ -+#define NBFT_SYSFS_PATH "/sys/firmware/acpi/tables" -+ -+struct nbft_file_entry { -+ struct list_node node; -+ struct nbft_info *nbft; -+}; -+ -+int read_nbft_files(struct list_head *nbft_list, char *path); -+void free_nbfts(struct list_head *nbft_list); -+ -+extern int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, -+ char *hostnqn_sys, char *hostid_sys, -+ const char *desc, bool connect, -+ const struct nvme_fabrics_config *cfg, char *nbft_path, -+ enum nvme_print_flags flags, bool verbose); --- -2.39.2 - diff --git a/nvme-cli-2.5-nbft_plugin.patch b/nvme-cli-2.5-nbft_plugin.patch deleted file mode 100644 index b70d26e..0000000 --- a/nvme-cli-2.5-nbft_plugin.patch +++ /dev/null @@ -1,640 +0,0 @@ -From 23daeedc53be9b5225cc6806434888c0a7a8e9bf Mon Sep 17 00:00:00 2001 -From: Stuart Hayes -Date: Fri, 14 Apr 2023 22:01:07 -0400 -Subject: [PATCH 03/11] nbft: add the nbft show plugin - -Display contents of the ACPI NBFT files. - -Usage: nvme nbft show [OPTIONS] - -Options: - [ --output-format=, -o ] --- Output format: normal|json - [ --subsystem, -s ] --- show NBFT subsystems - [ --hfi, -H ] --- show NBFT HFIs - [ --discovery, -d ] --- show NBFT discovery controllers - [ --nbft-path= ] --- user-defined path for NBFT tables - -Signed-off-by: Stuart Hayes -Signed-off-by: Martin Wilck -Signed-off-by: John Meneghini ---- - plugins/meson.build | 1 + - plugins/nbft/nbft-plugin.c | 568 +++++++++++++++++++++++++++++++++++++ - plugins/nbft/nbft-plugin.h | 18 ++ - 3 files changed, 587 insertions(+) - create mode 100644 plugins/nbft/nbft-plugin.c - create mode 100644 plugins/nbft/nbft-plugin.h - -diff --git a/plugins/meson.build b/plugins/meson.build -index 2cf2486f..38b7cded 100644 ---- a/plugins/meson.build -+++ b/plugins/meson.build -@@ -12,6 +12,7 @@ if json_c_dep.found() - 'plugins/intel/intel-nvme.c', - 'plugins/memblaze/memblaze-nvme.c', - 'plugins/micron/micron-nvme.c', -+ 'plugins/nbft/nbft-plugin.c', - 'plugins/netapp/netapp-nvme.c', - 'plugins/nvidia/nvidia-nvme.c', - 'plugins/scaleflux/sfx-nvme.c', -diff --git a/plugins/nbft/nbft-plugin.c b/plugins/nbft/nbft-plugin.c -new file mode 100644 -index 00000000..6ae2525a ---- /dev/null -+++ b/plugins/nbft/nbft-plugin.c -@@ -0,0 +1,568 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include -+#include -+#include -+ -+#include "nvme-print.h" -+#include "nvme.h" -+#include "nbft.h" -+#include "libnvme.h" -+#include "fabrics.h" -+ -+#define CREATE_CMD -+#include "nbft-plugin.h" -+ -+static const char dash[100] = {[0 ... 98] = '-', [99] = '\0'}; -+ -+#define PCI_SEGMENT(sbdf) ((sbdf & 0xffff0000) >> 16) -+#define PCI_BUS(sbdf) ((sbdf & 0x0000ff00) >> 8) -+#define PCI_DEV(sbdf) ((sbdf & 0x000000f8) >> 3) -+#define PCI_FUNC(sbdf) ((sbdf & 0x00000007) >> 0) -+ -+static const char *pci_sbdf_to_string(__u16 pci_sbdf) -+{ -+ static char pcidev[13]; -+ -+ snprintf(pcidev, sizeof(pcidev), "%x:%x:%x.%x", -+ PCI_SEGMENT(pci_sbdf), -+ PCI_BUS(pci_sbdf), -+ PCI_DEV(pci_sbdf), -+ PCI_FUNC(pci_sbdf)); -+ return pcidev; -+} -+ -+static char *mac_addr_to_string(unsigned char mac_addr[6]) -+{ -+ static char mac_string[18]; -+ -+ snprintf(mac_string, sizeof(mac_string), "%02x:%02x:%02x:%02x:%02x:%02x", -+ mac_addr[0], -+ mac_addr[1], -+ mac_addr[2], -+ mac_addr[3], -+ mac_addr[4], -+ mac_addr[5]); -+ return mac_string; -+} -+ -+static json_object *hfi_to_json(struct nbft_info_hfi *hfi) -+{ -+ struct json_object *hfi_json; -+ -+ hfi_json = json_create_object(); -+ if (!hfi_json) -+ return NULL; -+ -+ if (json_object_add_value_int(hfi_json, "index", hfi->index) -+ || json_object_add_value_string(hfi_json, "transport", hfi->transport)) -+ goto fail; -+ -+ if (strcmp(hfi->transport, "tcp") == 0) { -+ if (json_object_add_value_string(hfi_json, "pcidev", -+ pci_sbdf_to_string(hfi->tcp_info.pci_sbdf)) -+ || json_object_add_value_string(hfi_json, "mac_addr", -+ mac_addr_to_string(hfi->tcp_info.mac_addr)) -+ || json_object_add_value_int(hfi_json, "vlan", -+ hfi->tcp_info.vlan) -+ || json_object_add_value_int(hfi_json, "ip_origin", -+ hfi->tcp_info.ip_origin) -+ || json_object_add_value_string(hfi_json, "ipaddr", -+ hfi->tcp_info.ipaddr) -+ || json_object_add_value_int(hfi_json, "subnet_mask_prefix", -+ hfi->tcp_info.subnet_mask_prefix) -+ || json_object_add_value_string(hfi_json, "gateway_ipaddr", -+ hfi->tcp_info.gateway_ipaddr) -+ || json_object_add_value_int(hfi_json, "route_metric", -+ hfi->tcp_info.route_metric) -+ || json_object_add_value_string(hfi_json, "primary_dns_ipaddr", -+ hfi->tcp_info.primary_dns_ipaddr) -+ || json_object_add_value_string(hfi_json, "secondary_dns_ipaddr", -+ hfi->tcp_info.secondary_dns_ipaddr) -+ || json_object_add_value_string(hfi_json, "dhcp_server_ipaddr", -+ hfi->tcp_info.dhcp_server_ipaddr) -+ || (hfi->tcp_info.host_name -+ && json_object_add_value_string(hfi_json, "host_name", -+ hfi->tcp_info.host_name)) -+ || json_object_add_value_int(hfi_json, "this_hfi_is_default_route", -+ hfi->tcp_info.this_hfi_is_default_route) -+ || json_object_add_value_int(hfi_json, "dhcp_override", -+ hfi->tcp_info.dhcp_override)) -+ goto fail; -+ else -+ return hfi_json; -+ } -+fail: -+ json_free_object(hfi_json); -+ return NULL; -+} -+ -+static json_object *ssns_to_json(struct nbft_info_subsystem_ns *ss) -+{ -+ struct json_object *ss_json; -+ struct json_object *hfi_array_json; -+ char json_str[40]; -+ char *json_str_p; -+ int i; -+ -+ ss_json = json_create_object(); -+ if (!ss_json) -+ return NULL; -+ -+ hfi_array_json = json_create_array(); -+ if (!hfi_array_json) -+ goto fail; -+ -+ for (i = 0; i < ss->num_hfis; i++) -+ if (json_array_add_value_object(hfi_array_json, -+ json_object_new_int(ss->hfis[i]->index))) -+ goto fail; -+ -+ if (json_object_add_value_int(ss_json, "index", ss->index) -+ || json_object_add_value_int(ss_json, "num_hfis", ss->num_hfis) -+ || json_object_object_add(ss_json, "hfis", hfi_array_json) -+ || json_object_add_value_string(ss_json, "transport", ss->transport) -+ || json_object_add_value_string(ss_json, "traddr", ss->traddr) -+ || json_object_add_value_string(ss_json, "trsvcid", ss->trsvcid) -+ || json_object_add_value_int(ss_json, "subsys_port_id", ss->subsys_port_id) -+ || json_object_add_value_int(ss_json, "nsid", ss->nsid)) -+ goto fail; -+ -+ memset(json_str, 0, sizeof(json_str)); -+ json_str_p = json_str; -+ -+ switch (ss->nid_type) { -+ case NBFT_INFO_NID_TYPE_EUI64: -+ if (json_object_add_value_string(ss_json, "nid_type", "eui64")) -+ goto fail; -+ for (i = 0; i < 8; i++) -+ json_str_p += sprintf(json_str_p, "%02x", ss->nid[i]); -+ break; -+ -+ case NBFT_INFO_NID_TYPE_NGUID: -+ if (json_object_add_value_string(ss_json, "nid_type", "nguid")) -+ goto fail; -+ for (i = 0; i < 16; i++) -+ json_str_p += sprintf(json_str_p, "%02x", ss->nid[i]); -+ break; -+ -+ case NBFT_INFO_NID_TYPE_NS_UUID: -+ if (json_object_add_value_string(ss_json, "nid_type", "uuid")) -+ goto fail; -+ nvme_uuid_to_string(ss->nid, json_str); -+ break; -+ -+ default: -+ break; -+ } -+ if (json_object_add_value_string(ss_json, "nid", json_str)) -+ goto fail; -+ -+ if ((ss->subsys_nqn -+ && json_object_add_value_string(ss_json, "subsys_nqn", ss->subsys_nqn)) -+ || json_object_add_value_int(ss_json, "controller_id", ss->controller_id) -+ || json_object_add_value_int(ss_json, "asqsz", ss->asqsz) -+ || (ss->dhcp_root_path_string -+ && json_object_add_value_string(ss_json, "dhcp_root_path_string", -+ ss->dhcp_root_path_string)) -+ || json_object_add_value_int(ss_json, "pdu_header_digest_required", -+ ss->pdu_header_digest_required) -+ || json_object_add_value_int(ss_json, "data_digest_required", -+ ss->data_digest_required)) -+ goto fail; -+ -+ return ss_json; -+fail: -+ json_free_object(ss_json); -+ return NULL; -+} -+ -+static json_object *discovery_to_json(struct nbft_info_discovery *disc) -+{ -+ struct json_object *disc_json; -+ -+ disc_json = json_create_object(); -+ if (!disc_json) -+ return NULL; -+ -+ if (json_object_add_value_int(disc_json, "index", disc->index) -+ || (disc->security -+ && json_object_add_value_int(disc_json, "security", disc->security->index)) -+ || (disc->hfi -+ && json_object_add_value_int(disc_json, "hfi", disc->hfi->index)) -+ || (disc->uri -+ && json_object_add_value_string(disc_json, "uri", disc->uri)) -+ || (disc->nqn -+ && json_object_add_value_string(disc_json, "nqn", disc->nqn))) { -+ json_free_object(disc_json); -+ return NULL; -+ } else -+ return disc_json; -+} -+ -+static const char *primary_admin_host_flag_to_str(unsigned int primary) -+{ -+ static const char * const str[] = { -+ [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_NOT_INDICATED] = "not indicated", -+ [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_UNSELECTED] = "unselected", -+ [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_SELECTED] = "selected", -+ [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED] = "reserved", -+ }; -+ -+ if (primary > NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED) -+ return "INVALID"; -+ return str[primary]; -+} -+ -+static struct json_object *nbft_to_json(struct nbft_info *nbft, bool show_subsys, -+ bool show_hfi, bool show_discovery) -+{ -+ struct json_object *nbft_json, *host_json; -+ -+ nbft_json = json_create_object(); -+ if (!nbft_json) -+ return NULL; -+ -+ if (json_object_add_value_string(nbft_json, "filename", nbft->filename)) -+ goto fail; -+ -+ host_json = json_create_object(); -+ if (!host_json) -+ goto fail; -+ if ((nbft->host.nqn -+ && json_object_add_value_string(host_json, "nqn", nbft->host.nqn)) -+ || (nbft->host.id -+ && json_object_add_value_string(host_json, "id", -+ util_uuid_to_string(nbft->host.id)))) -+ goto fail; -+ json_object_add_value_int(host_json, "host_id_configured", -+ nbft->host.host_id_configured); -+ json_object_add_value_int(host_json, "host_nqn_configured", -+ nbft->host.host_nqn_configured); -+ json_object_add_value_string(host_json, "primary_admin_host_flag", -+ primary_admin_host_flag_to_str(nbft->host.primary)); -+ if (json_object_object_add(nbft_json, "host", host_json)) { -+ json_free_object(host_json); -+ goto fail; -+ } -+ -+ if (show_subsys) { -+ struct json_object *subsys_array_json, *subsys_json; -+ struct nbft_info_subsystem_ns **ss; -+ -+ subsys_array_json = json_create_array(); -+ if (!subsys_array_json) -+ goto fail; -+ for (ss = nbft->subsystem_ns_list; ss && *ss; ss++) { -+ subsys_json = ssns_to_json(*ss); -+ if (!subsys_json) -+ goto fail; -+ if (json_object_array_add(subsys_array_json, subsys_json)) { -+ json_free_object(subsys_json); -+ goto fail; -+ } -+ } -+ if (json_object_object_add(nbft_json, "subsystem", subsys_array_json)) { -+ json_free_object(subsys_array_json); -+ goto fail; -+ } -+ } -+ if (show_hfi) { -+ struct json_object *hfi_array_json, *hfi_json; -+ struct nbft_info_hfi **hfi; -+ -+ hfi_array_json = json_create_array(); -+ if (!hfi_array_json) -+ goto fail; -+ for (hfi = nbft->hfi_list; hfi && *hfi; hfi++) { -+ hfi_json = hfi_to_json(*hfi); -+ if (!hfi_json) -+ goto fail; -+ if (json_object_array_add(hfi_array_json, hfi_json)) { -+ json_free_object(hfi_json); -+ goto fail; -+ } -+ } -+ if (json_object_object_add(nbft_json, "hfi", hfi_array_json)) { -+ json_free_object(hfi_array_json); -+ goto fail; -+ } -+ } -+ if (show_discovery) { -+ struct json_object *discovery_array_json, *discovery_json; -+ struct nbft_info_discovery **disc; -+ -+ discovery_array_json = json_create_array(); -+ if (!discovery_array_json) -+ goto fail; -+ for (disc = nbft->discovery_list; disc && *disc; disc++) { -+ discovery_json = discovery_to_json(*disc); -+ if (!discovery_json) -+ goto fail; -+ if (json_object_array_add(discovery_array_json, discovery_json)) { -+ json_free_object(discovery_json); -+ goto fail; -+ } -+ } -+ if (json_object_object_add(nbft_json, "discovery", discovery_array_json)) { -+ json_free_object(discovery_array_json); -+ goto fail; -+ } -+ } -+ return nbft_json; -+fail: -+ json_free_object(nbft_json); -+ return NULL; -+} -+ -+static int json_show_nbfts(struct list_head *nbft_list, bool show_subsys, -+ bool show_hfi, bool show_discovery) -+{ -+ struct json_object *nbft_json_array, *nbft_json; -+ struct nbft_file_entry *entry; -+ -+ nbft_json_array = json_create_array(); -+ if (!nbft_json_array) -+ return ENOMEM; -+ -+ list_for_each(nbft_list, entry, node) { -+ nbft_json = nbft_to_json(entry->nbft, show_subsys, show_hfi, show_discovery); -+ if (!nbft_json) -+ goto fail; -+ if (json_object_array_add(nbft_json_array, nbft_json)) { -+ json_free_object(nbft_json); -+ goto fail; -+ } -+ } -+ -+ json_print_object(nbft_json_array, NULL); -+ printf("\n"); -+ json_free_object(nbft_json_array); -+ return 0; -+fail: -+ json_free_object(nbft_json_array); -+ return ENOMEM; -+} -+ -+static void print_nbft_hfi_info(struct nbft_info *nbft) -+{ -+ struct nbft_info_hfi **hfi; -+ unsigned int ip_width = 8, gw_width = 8, dns_width = 8; -+ -+ hfi = nbft->hfi_list; -+ if (!hfi || !*hfi) -+ return; -+ -+ for (; *hfi; hfi++) { -+ unsigned int len; -+ -+ len = strlen((*hfi)->tcp_info.ipaddr); -+ if (len > ip_width) -+ ip_width = len; -+ len = strlen((*hfi)->tcp_info.gateway_ipaddr); -+ if (len > gw_width) -+ gw_width = len; -+ len = strlen((*hfi)->tcp_info.primary_dns_ipaddr); -+ if (len > dns_width) -+ dns_width = len; -+ } -+ -+ printf("\nNBFT HFIs:\n\n"); -+ printf("%-3.3s|%-4.4s|%-10.10s|%-17.17s|%-4.4s|%-*.*s|%-4.4s|%-*.*s|%-*.*s\n", -+ "Idx", "Trsp", "PCI Addr", "MAC Addr", "DHCP", -+ ip_width, ip_width, "IP Addr", "Mask", -+ gw_width, gw_width, "Gateway", dns_width, dns_width, "DNS"); -+ printf("%-.3s+%-.4s+%-.10s+%-.17s+%-.4s+%-.*s+%-.4s+%-.*s+%-.*s\n", -+ dash, dash, dash, dash, dash, ip_width, dash, dash, -+ gw_width, dash, dns_width, dash); -+ for (hfi = nbft->hfi_list; *hfi; hfi++) -+ printf("%-3d|%-4.4s|%-10.10s|%-17.17s|%-4.4s|%-*.*s|%-4d|%-*.*s|%-*.*s\n", -+ (*hfi)->index, -+ (*hfi)->transport, -+ pci_sbdf_to_string((*hfi)->tcp_info.pci_sbdf), -+ mac_addr_to_string((*hfi)->tcp_info.mac_addr), -+ (*hfi)->tcp_info.dhcp_override ? "yes" : "no", -+ ip_width, ip_width, (*hfi)->tcp_info.ipaddr, -+ (*hfi)->tcp_info.subnet_mask_prefix, -+ gw_width, gw_width, (*hfi)->tcp_info.gateway_ipaddr, -+ dns_width, dns_width, (*hfi)->tcp_info.primary_dns_ipaddr); -+} -+ -+static void print_nbft_discovery_info(struct nbft_info *nbft) -+{ -+ struct nbft_info_discovery **disc; -+ unsigned int nqn_width = 20, uri_width = 12; -+ -+ disc = nbft->discovery_list; -+ if (!disc || !*disc) -+ return; -+ -+ for (; *disc; disc++) { -+ size_t len; -+ -+ len = strlen((*disc)->uri); -+ if (len > uri_width) -+ uri_width = len; -+ len = strlen((*disc)->nqn); -+ if (len > nqn_width) -+ nqn_width = len; -+ } -+ -+ printf("\nNBFT Discovery Controllers:\n\n"); -+ printf("%-3.3s|%-*.*s|%-*.*s\n", "Idx", uri_width, uri_width, "URI", -+ nqn_width, nqn_width, "NQN"); -+ printf("%-.3s+%-.*s+%-.*s\n", dash, uri_width, dash, nqn_width, dash); -+ for (disc = nbft->discovery_list; *disc; disc++) -+ printf("%-3d|%-*.*s|%-*.*s\n", (*disc)->index, -+ uri_width, uri_width, (*disc)->uri, -+ nqn_width, nqn_width, (*disc)->nqn); -+} -+ -+#define HFIS_LEN 20 -+static size_t print_hfis(const struct nbft_info_subsystem_ns *ss, char buf[HFIS_LEN]) -+{ -+ char hfi_buf[HFIS_LEN]; -+ size_t len, ofs; -+ int i; -+ -+ len = snprintf(hfi_buf, sizeof(hfi_buf), "%d", ss->hfis[0]->index); -+ for (i = 1; i < ss->num_hfis; i++) { -+ ofs = len; -+ len += snprintf(hfi_buf + ofs, sizeof(hfi_buf) - ofs, ",%d", -+ ss->hfis[i]->index); -+ /* -+ * If the list doesn't fit in HFIS_LEN characters, -+ * truncate and end with "..." -+ */ -+ if (len >= sizeof(hfi_buf)) { -+ while (ofs < sizeof(hfi_buf) - 1) -+ hfi_buf[ofs++] = '.'; -+ hfi_buf[ofs] = '\0'; -+ len = sizeof(hfi_buf) - 1; -+ break; -+ } -+ } -+ if (buf) -+ memcpy(buf, hfi_buf, len + 1); -+ return len; -+} -+ -+ -+static void print_nbft_subsys_info(struct nbft_info *nbft) -+{ -+ struct nbft_info_subsystem_ns **ss; -+ unsigned int nqn_width = 20, adr_width = 8, hfi_width = 4; -+ -+ ss = nbft->subsystem_ns_list; -+ if (!ss || !*ss) -+ return; -+ for (; *ss; ss++) { -+ size_t len; -+ -+ len = strlen((*ss)->subsys_nqn); -+ if (len > nqn_width) -+ nqn_width = len; -+ len = strlen((*ss)->traddr); -+ if (len > adr_width) -+ adr_width = len; -+ len = print_hfis(*ss, NULL); -+ if (len > hfi_width) -+ hfi_width = len; -+ } -+ -+ printf("\nNBFT Subsystems:\n\n"); -+ printf("%-3.3s|%-*.*s|%-4.4s|%-*.*s|%-5.5s|%-*.*s\n", -+ "Idx", nqn_width, nqn_width, "NQN", -+ "Trsp", adr_width, adr_width, "Address", "SvcId", hfi_width, hfi_width, "HFIs"); -+ printf("%-.3s+%-.*s+%-.4s+%-.*s+%-.5s+%-.*s\n", -+ dash, nqn_width, dash, dash, adr_width, dash, dash, hfi_width, dash); -+ for (ss = nbft->subsystem_ns_list; *ss; ss++) { -+ char hfi_buf[HFIS_LEN]; -+ -+ print_hfis(*ss, hfi_buf); -+ printf("%-3d|%-*.*s|%-4.4s|%-*.*s|%-5.5s|%-*.*s\n", -+ (*ss)->index, nqn_width, nqn_width, (*ss)->subsys_nqn, -+ (*ss)->transport, adr_width, adr_width, (*ss)->traddr, -+ (*ss)->trsvcid, hfi_width, hfi_width, hfi_buf); -+ } -+} -+ -+static void normal_show_nbft(struct nbft_info *nbft, bool show_subsys, -+ bool show_hfi, bool show_discovery) -+{ -+ printf("%s:\n", nbft->filename); -+ if ((!nbft->hfi_list || !*nbft->hfi_list) && -+ (!nbft->security_list || !*nbft->security_list) && -+ (!nbft->discovery_list || !*nbft->discovery_list) && -+ (!nbft->subsystem_ns_list || !*nbft->subsystem_ns_list)) -+ printf("(empty)\n"); -+ else { -+ if (show_subsys) -+ print_nbft_subsys_info(nbft); -+ if (show_hfi) -+ print_nbft_hfi_info(nbft); -+ if (show_discovery) -+ print_nbft_discovery_info(nbft); -+ } -+} -+ -+static void normal_show_nbfts(struct list_head *nbft_list, bool show_subsys, -+ bool show_hfi, bool show_discovery) -+{ -+ bool not_first = false; -+ struct nbft_file_entry *entry; -+ -+ list_for_each(nbft_list, entry, node) { -+ if (not_first) -+ printf("\n"); -+ normal_show_nbft(entry->nbft, show_subsys, show_hfi, show_discovery); -+ not_first = true; -+ } -+} -+ -+int show_nbft(int argc, char **argv, struct command *cmd, struct plugin *plugin) -+{ -+ const char *desc = "Display contents of the ACPI NBFT files."; -+ struct list_head nbft_list; -+ char *format = "normal"; -+ char *nbft_path = NBFT_SYSFS_PATH; -+ enum nvme_print_flags flags = -1; -+ int ret; -+ bool show_subsys = false, show_hfi = false, show_discovery = false; -+ -+ OPT_ARGS(opts) = { -+ OPT_FMT("output-format", 'o', &format, "Output format: normal|json"), -+ OPT_FLAG("subsystem", 's', &show_subsys, "show NBFT subsystems"), -+ OPT_FLAG("hfi", 'H', &show_hfi, "show NBFT HFIs"), -+ OPT_FLAG("discovery", 'd', &show_discovery, "show NBFT discovery controllers"), -+ OPT_STRING("nbft-path", 0, "STR", &nbft_path, "user-defined path for NBFT tables"), -+ OPT_END() -+ }; -+ -+ ret = argconfig_parse(argc, argv, desc, opts); -+ if (ret) -+ return ret; -+ -+ if (!(show_subsys || show_hfi || show_discovery)) -+ show_subsys = show_hfi = show_discovery = true; -+ -+ if (!strcmp(format, "")) -+ flags = -1; -+ else if (!strcmp(format, "normal")) -+ flags = NORMAL; -+ else if (!strcmp(format, "json")) -+ flags = JSON; -+ else -+ return EINVAL; -+ -+ list_head_init(&nbft_list); -+ ret = read_nbft_files(&nbft_list, nbft_path); -+ if (!ret) { -+ if (flags == NORMAL) -+ normal_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery); -+ else if (flags == JSON) -+ ret = json_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery); -+ free_nbfts(&nbft_list); -+ } -+ return ret; -+} -diff --git a/plugins/nbft/nbft-plugin.h b/plugins/nbft/nbft-plugin.h -new file mode 100644 -index 00000000..018349d9 ---- /dev/null -+++ b/plugins/nbft/nbft-plugin.h -@@ -0,0 +1,18 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+#undef CMD_INC_FILE -+#define CMD_INC_FILE plugins/nbft/nbft-plugin -+ -+#if !defined(NBFT) || defined(CMD_HEADER_MULTI_READ) -+#define NBFT -+ -+#include "cmd.h" -+ -+PLUGIN(NAME("nbft", "ACPI NBFT table extensions", NVME_VERSION), -+ COMMAND_LIST( -+ ENTRY("show", "Show contents of ACPI NBFT tables", show_nbft) -+ ) -+); -+ -+#endif -+ -+#include "define_cmd.h" --- -2.39.2 - diff --git a/nvme-cli.spec b/nvme-cli.spec index 06bb083..00a530b 100644 --- a/nvme-cli.spec +++ b/nvme-cli.spec @@ -2,18 +2,14 @@ %{!?version_no_tilde: %define version_no_tilde %{shrink:%(echo '%{version}' | tr '~' '-')}} Name: nvme-cli -Version: 2.4 -Release: 2%{?dist} +Version: 2.5 +Release: 1%{?dist} Summary: NVMe management command line interface License: GPLv2 URL: https://github.com/linux-nvme/nvme-cli Source0: %{url}/archive/v%{version_no_tilde}/%{name}-%{version_no_tilde}.tar.gz -Patch100: nvme-cli-2.5-nbft-make-lookup_ctrl-function-public.patch -Patch101: nvme-cli-2.5-nbft.patch -Patch102: nvme-cli-2.5-nbft_plugin.patch - BuildRequires: meson >= 0.50.0 BuildRequires: gcc gcc-c++ BuildRequires: systemd-devel @@ -21,7 +17,7 @@ BuildRequires: systemd-rpm-macros BuildRequires: zlib-devel BuildRequires: openssl-devel -BuildRequires: libnvme-devel >= 1.4-2 +BuildRequires: libnvme-devel >= 1.5 BuildRequires: json-c-devel >= 0.13 %if (0%{?rhel} == 0) @@ -44,7 +40,7 @@ nvme-cli provides NVM-Express user space tooling for Linux. %build -%meson -Dudevrulesdir=%{_udevrulesdir} -Dsystemddir=%{_unitdir} -Ddocs=all -Ddocs-build=true -Dhtmldir=%{_pkgdocdir} +%meson -Dudevrulesdir=%{_udevrulesdir} -Dsystemddir=%{_unitdir} -Dpdc-enabled=true -Ddocs=all -Ddocs-build=true -Dhtmldir=%{_pkgdocdir} %meson_build @@ -87,6 +83,9 @@ rm -rf %{buildroot}%{_pkgdocdir}/nvme %changelog +* Tue Jul 04 2023 Tomas Bzatek - 2.5-1 +- Update to 2.5 + * Thu Apr 20 2023 Tomas Bzatek - 2.4-2 - Backport the NBFT support from git master diff --git a/sources b/sources index edbc0db..f820245 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (nvme-cli-2.4.tar.gz) = 155667a0b91e15267e3f991a30cf1d4ae26cb4c53b20c002e3d3341496dd463397e1afbfefcd7a8df88370d28417940ce44a060bda87c04482bbe3be4e901b73 +SHA512 (nvme-cli-2.5.tar.gz) = 50c557e86e95b27a0ad57779c33bbb847e12dd45c30e792f5ce1d52dedd4bc704ac25fa0af2fdebd281c9dfe0059f7ed7c1620fccfde9323f6f9a97afdf8c3cb