]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
JSON configuration file handling
authorHannes Reinecke <hare@suse.de>
Wed, 5 May 2021 11:55:39 +0000 (13:55 +0200)
committerHannes Reinecke <hare@suse.de>
Fri, 11 Jun 2021 10:18:10 +0000 (12:18 +0200)
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 <hare@suse.de>
14 files changed:
configure
examples/discover-loop.c
examples/display-columnar.c
examples/display-tree.c
examples/telemetry-listen.c
src/Makefile
src/nvme/fabrics.c
src/nvme/json.c [new file with mode: 0644]
src/nvme/private.h [new file with mode: 0644]
src/nvme/tree.c
src/nvme/tree.h
test/cpp.cc
test/test.c
test/zns.c

index 2481163184a5f6fcd296c4ff8a43c96f307d90a8..c81f48ea4df40b3eed12661f52eb47dbf4532e01 100755 (executable)
--- 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
index 4a8d140c00518f39e6f4f489d0b763c4be7ffc06..37637e24ce0874b57e77589e9553a9650b196584 100644 (file)
@@ -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;
 }
index cd3f007f16a55cb435ae95788acdb23068b1b5d5..a2a2938e1176f7ca9884164145abc650e0ff5aa0 100644 (file)
@@ -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;
 
index 66b16c276d699b3cee5eeeb4532758b385051fd7..f5bddb2c1d831ecd10a6e7fc603710a314e62ecb 100644 (file)
@@ -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;
 
index c4cde957dbedc3864002441ba4352a474ee592ec..374ffa4dbb4ab1ce97939d329d0c6deae3cdbd26 100644 (file)
@@ -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;
 
index 129e624d7474dc61e5317762d8861b740452d742..4beb13d8db47d1dddb4b5f16534f828e778aaa79 100644 (file)
@@ -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))
 
index e3497b3c1a44e2deb228b274030892d378f1c8fd..4c5970449789e27808b595d6ffe9e40d3159a798 100644 (file)
@@ -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 (file)
index 0000000..9828082
--- /dev/null
@@ -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 <hare@suse.de>
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <json-c/json.h>
+
+#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 (file)
index 0000000..bc823ab
--- /dev/null
@@ -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 <hare@suse.de>
+ */
+
+#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 */
index 5201b87a251bcf8ab3d3e0fbe584d42636d74e8c..518e89edf2dba59bdf084065854dd77b61918ab2 100644 (file)
 #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)
index 903680f000794cde83573f641ac8a0eb8a99641f..68428e9fe3adebb7358cac8b622f781ad0b0c8f3 100644 (file)
@@ -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() -
index f1463b46f595029c467416117de413a206396371..3d0a7d250df7d5a6f156a8c55f4dbee9666f9d29 100644 (file)
@@ -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;
 
index aa4e82e72015b7eaa0db2fcb698d4bc18f1c5a5c..fc9c21ef084779bd94a68d2a4ed6b768aea2e90a 100644 (file)
@@ -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;
 
index 7d854cd7457d6760fce53b8f5a51defb91196ea8..3ca55dfc7502cf976a9dfe7378d7ff532e0cb1f4 100644 (file)
@@ -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;