From: Hannes Reinecke Date: Wed, 5 May 2021 11:55:39 +0000 (+0200) Subject: JSON configuration file handling X-Git-Tag: v1.0-rc0~129^2~2 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=31b4ee1f287e6bb112dadd28c65910a9e628c2e7;p=users%2Fsagi%2Flibnvme.git JSON configuration file handling Add functions 'json_read_config()' and 'json_update_config()' to read and write configuration informations from or to a JSON file. Signed-off-by: Hannes Reinecke --- diff --git a/configure b/configure index 24811631..c81f48ea 100755 --- a/configure +++ b/configure @@ -31,6 +31,8 @@ for opt do ;; --disable-uuid) disable_uuid=1 ;; + --disable-json) disable_json=1 + ;; *) echo "ERROR: unkown option $opt" echo "Try '$0 --help' for more information" @@ -68,6 +70,7 @@ Options: [defaults in brackets after descriptions] --datadir=PATH install shared data in PATH [$datadir] --disable-systemd do not link against libsystemd --disable-uuid do not link against libuuid + --disable-json do not link against libjson-c EOF exit 0 fi @@ -202,6 +205,17 @@ if [ -z "$disable_systemd" ] ; then fi print_config "systemd" "${systemd}" +########################################## +# check for libjson-c +libjsonc="no" +if [ -z "$disable_json" ] ; then + ${ld} -o /dev/null -ljson-c >/dev/null 2>&1 + if [ $? -eq 0 ]; then + libjsonc="yes" + fi +fi +print_config "libjson-c" "${libjsonc}" + ########################################## # check for c++ cpp="no" @@ -221,6 +235,11 @@ if test "$systemd" = "yes"; then output_sym "CONFIG_SYSTEMD" echo "override LDFLAGS += -lsystemd" >> $config_host_mak fi +if test "$libjsonc" = "yes"; then + output_sym "CONFIG_JSONC" + echo "override LDFLAGS += -ljson-c" >> $config_host_mak + echo "override LIB_DEPENDS += json-c" >> $config_host_mak +fi if test "$cpp" = "yes"; then output_mak "CONFIG_CPLUSPLUS" "y" fi diff --git a/examples/discover-loop.c b/examples/discover-loop.c index 4a8d140c..37637e24 100644 --- a/examples/discover-loop.c +++ b/examples/discover-loop.c @@ -50,17 +50,14 @@ int main() nvme_root_t r; nvme_host_t h; nvme_ctrl_t c; - char *hnqn, *hid; int ret; struct nvme_fabrics_config cfg = { .tos = -1, }; - r = nvme_scan(); - hnqn = nvmf_hostnqn_from_file(); - hid = nvmf_hostid_from_file(); - h = nvme_lookup_host(r, hnqn, hid); + r = nvme_scan(NULL); + h = nvme_default_host(r); if (!h) { fprintf(stderr, "Failed to allocated memory\n"); return ENOMEM; @@ -86,6 +83,5 @@ int main() print_discover_log(log); nvme_free_tree(r); - free(hnqn); return 0; } diff --git a/examples/display-columnar.c b/examples/display-columnar.c index cd3f007f..a2a2938e 100644 --- a/examples/display-columnar.c +++ b/examples/display-columnar.c @@ -23,7 +23,7 @@ int main() nvme_path_t p; nvme_ns_t n; - r = nvme_scan(); + r = nvme_scan(NULL); if (!r) return -1; diff --git a/examples/display-tree.c b/examples/display-tree.c index 66b16c27..f5bddb2c 100644 --- a/examples/display-tree.c +++ b/examples/display-tree.c @@ -22,7 +22,7 @@ int main() nvme_path_t p, _p; nvme_ns_t n, _n; - r = nvme_scan(); + r = nvme_scan(NULL); if (!r) return -1; diff --git a/examples/telemetry-listen.c b/examples/telemetry-listen.c index c4cde957..374ffa4d 100644 --- a/examples/telemetry-listen.c +++ b/examples/telemetry-listen.c @@ -129,7 +129,7 @@ int main() nvme_host_t h; nvme_root_t r; - r = nvme_scan(); + r = nvme_scan(NULL); if (!r) return EXIT_FAILURE; diff --git a/src/Makefile b/src/Makefile index 129e624d..4beb13d8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -49,6 +49,9 @@ $(libccan_objs) $(libccan_sobjs): $(libccan_headers) $(CCANDIR)config.h libnvme_priv := nvme/private.h libnvme_api := libnvme.h nvme/types.h nvme/ioctl.h nvme/filters.h nvme/tree.h nvme/util.h nvme/fabrics.h libnvme_srcs := nvme/ioctl.c nvme/filters.c nvme/fabrics.c nvme/util.c nvme/tree.c +ifneq ($(CONFIG_JSONC),0) +override libnvme_srcs += nvme/json.c +endif libnvme_objs := $(patsubst %.c,%.ol,$(libnvme_srcs)) libnvme_sobjs := $(patsubst %.c,%.os,$(libnvme_srcs)) diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c index e3497b3c..4c597044 100644 --- a/src/nvme/fabrics.c +++ b/src/nvme/fabrics.c @@ -31,6 +31,7 @@ #include "fabrics.h" #include "ioctl.h" #include "util.h" +#include "private.h" #define NVMF_HOSTID_SIZE 37 diff --git a/src/nvme/json.c b/src/nvme/json.c new file mode 100644 index 00000000..98280822 --- /dev/null +++ b/src/nvme/json.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * This file is part of libnvme. + * Copyright (c) 2021 SUSE Software Solutions + * + * Authors: Hannes Reinecke + */ + +#include +#include +#include + +#include + +#include "fabrics.h" +#include "private.h" + +#define json_object_add_value_string(o, k, v) \ + json_object_object_add(o, k, json_object_new_string(v)) +#define json_object_add_value_int(o, k, v) \ + json_object_object_add(o, k, json_object_new_int(v)) +#define json_object_add_value_bool(o, k, v) \ + json_object_object_add(o, k, json_object_new_boolean(v)) +#define json_object_add_value_string(o, k, v) \ + json_object_object_add(o, k, json_object_new_string(v)) + +#define JSON_UPDATE_INT_OPTION(c, k, a, o) \ + if (!strcmp(# a, k ) && !c->a) c->a = json_object_get_int(o); +#define JSON_UPDATE_BOOL_OPTION(c, k, a, o) \ + if (!strcmp(# a, k ) && !c->a) c->a = json_object_get_boolean(o); + +static void json_update_attributes(nvme_ctrl_t c, + struct json_object *ctrl_obj) +{ + struct nvme_fabrics_config *cfg = nvme_ctrl_get_config(c); + + json_object_object_foreach(ctrl_obj, key_str, val_obj) { + JSON_UPDATE_INT_OPTION(cfg, key_str, + nr_io_queues, val_obj); + JSON_UPDATE_INT_OPTION(cfg, key_str, + nr_write_queues, val_obj); + JSON_UPDATE_INT_OPTION(cfg, key_str, + nr_poll_queues, val_obj); + JSON_UPDATE_INT_OPTION(cfg, key_str, + queue_size, val_obj); + JSON_UPDATE_INT_OPTION(cfg, key_str, + keep_alive_tmo, val_obj); + JSON_UPDATE_INT_OPTION(cfg, key_str, + reconnect_delay, val_obj); + if (!strcmp("ctrl_loss_tmo", key_str) && + cfg->ctrl_loss_tmo != NVMF_DEF_CTRL_LOSS_TMO) + cfg->ctrl_loss_tmo = json_object_get_int(val_obj); + if (!strcmp("tos", key_str) && cfg->tos != -1) + cfg->tos = json_object_get_int(val_obj); + JSON_UPDATE_BOOL_OPTION(cfg, key_str, + duplicate_connect, val_obj); + JSON_UPDATE_BOOL_OPTION(cfg, key_str, + disable_sqflow, val_obj); + JSON_UPDATE_BOOL_OPTION(cfg, key_str, + hdr_digest, val_obj); + JSON_UPDATE_BOOL_OPTION(cfg, key_str, + data_digest, val_obj); + if (!strcmp("persistent", key_str) && + !nvme_ctrl_is_persistent(c)) + nvme_ctrl_set_persistent(c, true); + } +} + +static void json_parse_port(nvme_subsystem_t s, struct json_object *port_obj) +{ + nvme_ctrl_t c; + struct json_object *attr_obj; + const char *transport, *traddr = NULL; + const char *host_traddr = NULL, *trsvcid = NULL; + + attr_obj = json_object_object_get(port_obj, "transport"); + if (!attr_obj) + return; + transport = json_object_get_string(attr_obj); + attr_obj = json_object_object_get(port_obj, "traddr"); + if (attr_obj) + traddr = json_object_get_string(attr_obj); + attr_obj = json_object_object_get(port_obj, "host_traddr"); + if (attr_obj) + host_traddr = json_object_get_string(attr_obj); + attr_obj = json_object_object_get(port_obj, "trsvcid"); + if (attr_obj) + trsvcid = json_object_get_string(attr_obj); + c = nvme_lookup_ctrl(s, transport, traddr, + host_traddr, trsvcid); + if (c) { + json_update_attributes(c, port_obj); + } +} + +static void json_parse_subsys(nvme_host_t h, struct json_object *subsys_obj) +{ + struct json_object *nqn_obj, *port_array; + nvme_subsystem_t s; + const char *nqn; + int p; + + nqn_obj = json_object_object_get(subsys_obj, "nqn"); + if (!nqn_obj) + return; + nqn = json_object_get_string(nqn_obj); + s = nvme_lookup_subsystem(h, NULL, nqn); + port_array = json_object_object_get(subsys_obj, "ports"); + if (!port_array) + return; + for (p = 0; p < json_object_array_length(port_array); p++) { + struct json_object *port_obj; + + port_obj = json_object_array_get_idx(port_array, p); + json_parse_port(s, port_obj); + } +} + +static void json_parse_host(nvme_root_t r, struct json_object *host_obj) +{ + struct json_object *attr_obj, *subsys_array, *subsys_obj; + nvme_host_t h; + const char *hostnqn, *hostid = NULL; + int s; + + attr_obj = json_object_object_get(host_obj, "hostnqn"); + if (!attr_obj) + return; + hostnqn = json_object_get_string(attr_obj); + attr_obj = json_object_object_get(host_obj, "hostid"); + if (attr_obj) + hostid = json_object_get_string(attr_obj); + h = nvme_lookup_host(r, hostnqn, hostid); + subsys_array = json_object_object_get(host_obj, "subsystems"); + if (!subsys_array) + return; + for (s = 0; s < json_object_array_length(subsys_array); s++) { + subsys_obj = json_object_array_get_idx(subsys_array, s); + json_parse_subsys(h, subsys_obj); + } +} + +void json_read_config(nvme_root_t r, const char *config_file) +{ + struct json_object *json_root, *host_obj; + int h; + + json_root = json_object_from_file(config_file); + if (!json_root) { + fprintf(stderr, "Failed to read %s, %s\n", + config_file, json_util_get_last_err()); + return; + } + for (h = 0; h < json_object_array_length(json_root); h++) { + host_obj = json_object_array_get_idx(json_root, h); + json_parse_host(r, host_obj); + } + json_object_put(json_root); +} + +#define JSON_STRING_OPTION(c, p, o) \ + if ((c)->o && strcmp((c)->o, "none")) \ + json_object_add_value_string((p), # o , (c)->o) +#define JSON_INT_OPTION(c, p, o, d) \ + if ((c)->o != d) json_object_add_value_int((p), # o , (c)->o) +#define JSON_BOOL_OPTION(c, p, o) \ + if ((c)->o) json_object_add_value_bool((p), # o , (c)->o) + +static void json_update_port(struct json_object *ctrl_array, nvme_ctrl_t c) +{ + struct nvme_fabrics_config *cfg = nvme_ctrl_get_config(c); + struct json_object *port_obj = json_object_new_object(); + const char *transport, *value; + + transport = nvme_ctrl_get_transport(c); + json_object_add_value_string(port_obj, "transport", transport); + value = nvme_ctrl_get_traddr(c); + if (value) + json_object_add_value_string(port_obj, "traddr", value); + value = nvme_ctrl_get_host_traddr(c); + if (value) + json_object_add_value_string(port_obj, "host_traddr", value); + value = nvme_ctrl_get_trsvcid(c); + if (value) + json_object_add_value_string(port_obj, "trsvcid", value); + JSON_INT_OPTION(cfg, port_obj, nr_io_queues, 0); + JSON_INT_OPTION(cfg, port_obj, nr_write_queues, 0); + JSON_INT_OPTION(cfg, port_obj, nr_poll_queues, 0); + JSON_INT_OPTION(cfg, port_obj, queue_size, 0); + JSON_INT_OPTION(cfg, port_obj, keep_alive_tmo, 0); + JSON_INT_OPTION(cfg, port_obj, reconnect_delay, 0); + if (strcmp(transport, "loop")) + JSON_INT_OPTION(cfg, port_obj, ctrl_loss_tmo, + NVMF_DEF_CTRL_LOSS_TMO); + JSON_INT_OPTION(cfg, port_obj, tos, -1); + JSON_BOOL_OPTION(cfg, port_obj, duplicate_connect); + JSON_BOOL_OPTION(cfg, port_obj, disable_sqflow); + JSON_BOOL_OPTION(cfg, port_obj, hdr_digest); + JSON_BOOL_OPTION(cfg, port_obj, data_digest); + if (nvme_ctrl_is_persistent(c)) + json_object_add_value_bool(port_obj, "persistent", true); + json_object_array_add(ctrl_array, port_obj); +} + +static void json_update_subsys(struct json_object *subsys_array, + nvme_subsystem_t s) +{ + nvme_ctrl_t c; + const char *subsysnqn = nvme_subsystem_get_nqn(s); + struct json_object *subsys_obj = json_object_new_object(); + struct json_object *port_array; + + /* Skip discovery subsystems as the nqn is not unique */ + if (!strcmp(subsysnqn, NVME_DISC_SUBSYS_NAME)) + return; + + json_object_add_value_string(subsys_obj, "nqn", + nvme_subsystem_get_nqn(s)); + port_array = json_object_new_array(); + nvme_subsystem_for_each_ctrl(s, c) { + json_update_port(port_array, c); + } + if (json_object_array_length(port_array)) + json_object_object_add(subsys_obj, "ports", port_array); + else + json_object_put(port_array); + json_object_array_add(subsys_array, subsys_obj); +} + +void json_update_config(nvme_root_t r, const char *config_file) +{ + nvme_host_t h; + struct json_object *json_root, *host_obj; + struct json_object *subsys_array; + + json_root = json_object_new_array(); + nvme_for_each_host(r, h) { + nvme_subsystem_t s; + const char *hostid; + + host_obj = json_object_new_object(); + json_object_add_value_string(host_obj, "hostnqn", + nvme_host_get_hostnqn(h)); + hostid = nvme_host_get_hostid(h); + if (hostid) + json_object_add_value_string(host_obj, "hostid", + hostid); + subsys_array = json_object_new_array(); + nvme_for_each_subsystem(h, s) { + json_update_subsys(subsys_array, s); + } + if (json_object_array_length(subsys_array)) + json_object_object_add(host_obj, "subsystems", + subsys_array); + else + json_object_put(subsys_array); + json_object_array_add(json_root, host_obj); + } + if (json_object_to_file_ext(config_file, json_root, + JSON_C_TO_STRING_PRETTY) < 0) { + fprintf(stderr, "Failed to write %s, %s\n", + config_file, json_util_get_last_err()); + } + json_object_put(json_root); +} diff --git a/src/nvme/private.h b/src/nvme/private.h new file mode 100644 index 00000000..bc823abb --- /dev/null +++ b/src/nvme/private.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * This file is part of libnvme. + * Copyright (c) 2021 SUSE Software Solutions + * + * Authors: Hannes Reinecke + */ + +#ifndef _LIBNVME_PRIVATE_H +#define _LIBNVME_PRIVATE_H + +int nvme_set_attr(const char *dir, const char *attr, const char *value); + +void json_read_config(nvme_root_t r, const char *config_file); + +void json_update_config(nvme_root_t r, const char *config_file); + +#endif /* _LIBNVME_PRIVATE_H */ diff --git a/src/nvme/tree.c b/src/nvme/tree.c index 5201b87a..518e89ed 100644 --- a/src/nvme/tree.c +++ b/src/nvme/tree.c @@ -23,13 +23,10 @@ #include "filters.h" #include "util.h" #include "fabrics.h" - -/* XXX: Make a place for private declarations */ -extern int nvme_set_attr(const char *dir, const char *attr, const char *value); +#include "private.h" static struct nvme_host *default_host; -nvme_host_t nvme_default_host(nvme_root_t r); static void nvme_free_host(struct nvme_host *h); static void nvme_free_subsystem(struct nvme_subsystem *s); static int nvme_subsystem_scan_namespace(struct nvme_subsystem *s, char *name); @@ -196,9 +193,13 @@ nvme_root_t nvme_scan_filter(nvme_scan_filter_t f) return r; } -nvme_root_t nvme_scan() +nvme_root_t nvme_scan(const char *config_file) { - return nvme_scan_filter(NULL); + nvme_root_t r = nvme_scan_filter(NULL); + + if (r && config_file) + json_read_config(r, config_file); + return r; } nvme_host_t nvme_first_host(nvme_root_t r) diff --git a/src/nvme/tree.h b/src/nvme/tree.h index 903680f0..68428e9f 100644 --- a/src/nvme/tree.h +++ b/src/nvme/tree.h @@ -946,12 +946,21 @@ const char *nvme_host_get_hostnqn(nvme_host_t h); */ const char *nvme_host_get_hostid(nvme_host_t h); +/** + * nvme_default_host() - + * @root: + * + * Return: + */ +nvme_host_t nvme_default_host(nvme_root_t r); + /** * nvme_scan() - + * @config_file: * * Return: */ -nvme_root_t nvme_scan(void); +nvme_root_t nvme_scan(const char *config_file); /** * nvme_refresh_topology() - diff --git a/test/cpp.cc b/test/cpp.cc index f1463b46..3d0a7d25 100644 --- a/test/cpp.cc +++ b/test/cpp.cc @@ -18,7 +18,7 @@ int main() nvme_path_t p; nvme_ns_t n; - r = nvme_scan(); + r = nvme_scan(NULL); if (!r) return -1; diff --git a/test/test.c b/test/test.c index aa4e82e7..fc9c21ef 100644 --- a/test/test.c +++ b/test/test.c @@ -342,7 +342,7 @@ int main(int argc, char **argv) printf("\n"); nvme_free_tree(r); - r = nvme_scan(); + r = nvme_scan(NULL); if (!r) return -1; diff --git a/test/zns.c b/test/zns.c index 7d854cd7..3ca55dfc 100644 --- a/test/zns.c +++ b/test/zns.c @@ -61,7 +61,7 @@ int main() nvme_ctrl_t c; nvme_ns_t n; - r = nvme_scan(); + r = nvme_scan(NULL); if (!r) return -1;