]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
Add SWIG interface generator files
authorHannes Reinecke <hare@suse.de>
Thu, 6 May 2021 06:19:32 +0000 (08:19 +0200)
committerHannes Reinecke <hare@suse.de>
Sat, 19 Jun 2021 11:36:56 +0000 (13:36 +0200)
Add files to generate a python binding via SWIG.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Makefile
src/Makefile
src/nvme/libnvme.i [new file with mode: 0644]
src/setup.py [new file with mode: 0644]

index a4dbd7dfaf79c634ca9567bd7e579041c8da36ca..2dd7137a9f6ece1e558e98a7e3591b77a1f1e598 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,9 @@ INSTALL=install
 
 default: all
 
+python: all
+       @$(MAKE) -C src python
+
 all: $(NAME).pc
        @$(MAKE) -C src
        @$(MAKE) -C test
index 19361f89ff296ab79e0d8ca0d87a6fadaa903153..c07d1fe29adf86a965e3c341985f41dc710d3f44 100644 (file)
@@ -49,6 +49,7 @@ $(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 nvme/log.c nvme/cleanup.c
+libnvme_swig := nvme/libnvme.i
 ifneq ($(CONFIG_JSONC),0)
 override libnvme_srcs += nvme/json.c
 endif
@@ -65,6 +66,9 @@ $(libnvme_objs) $(libnvme_sobjs): $(libnvme_api) $(libnvme_private) $(libccan_ob
 
 AR ?= ar
 RANLIB ?= ranlib
+SWIG ?= swig
+PYTHON ?= python3
+
 libnvme.a: $(libnvme_objs) $(libccan_objs)
        @rm -f libnvme.a
        $(QUIET_AR)$(AR) r libnvme.a $^
@@ -73,6 +77,12 @@ libnvme.a: $(libnvme_objs) $(libccan_objs)
 $(libname): $(libnvme_sobjs) $(libccan_sobjs) libnvme.map
        $(QUIET_CC)$(CC) $(SO_CFLAGS) -Wl,--version-script=libnvme.map -Wl,-soname=$(soname) -o $@ $(libnvme_sobjs) $(libccan_sobjs) $(LINK_FLAGS)
 
+libnvme_wrap.c: $(libnvme_swig)
+       $(SWIG) -python -py3 -outdir . $<
+
+python: libnvme_wrap.c setup.py
+       $(PYTHON) setup.py build
+
 install: $(all_targets)
        $(INSTALL) -D -m 644 libnvme.a $(libdir)/libnvme.a
        for i in $(libnvme_api); do $(INSTALL) -D -m 644 $$i $(includedir)/$$i; done
@@ -89,4 +99,5 @@ clean:
        rm -f $(all_targets) $(libnvme_objs) $(libnvme_sobjs) $(libccan_objs) $(libccan_sobjs) $(soname).new
        rm -f $(CCANDIR)config.h
        rm -f $(CCANDIR)tools/configurator/configurator
+       rm -f libnvme_wrap.c
        rm -f *.so* *.a *.o
diff --git a/src/nvme/libnvme.i b/src/nvme/libnvme.i
new file mode 100644 (file)
index 0000000..25eddb4
--- /dev/null
@@ -0,0 +1,515 @@
+// 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>
+ */
+
+%module libnvme
+
+%include "exception.i"
+
+%allowexception;
+
+%{
+#include <assert.h>
+#include <ccan/list/list.h>
+#include "tree.h"
+#include "fabrics.h"
+#include "private.h"
+
+static int host_iter_err = 0;
+static int subsys_iter_err = 0;
+static int ctrl_iter_err = 0;
+static int ns_iter_err = 0;
+static int connect_err = 0;
+static int discover_err = 0;
+%}
+
+%inline %{
+  struct nvme_host_iter {
+    struct nvme_root *root;
+    struct nvme_host *pos;
+  };
+
+  struct nvme_subsystem_iter {
+    struct nvme_host *host;
+    struct nvme_subsystem *pos;
+  };
+
+  struct nvme_ctrl_iter {
+    struct nvme_subsystem *subsystem;
+    struct nvme_ctrl *pos;
+  };
+
+  struct nvme_ns_iter {
+    struct nvme_subsystem *subsystem;
+    struct nvme_ctrl *ctrl;
+    struct nvme_ns *pos;
+  };
+%}
+
+%exception nvme_host_iter::__next__ {
+  assert(!host_iter_err);
+  $action
+  if (host_iter_err) {
+    host_iter_err = 0;
+    PyErr_SetString(PyExc_StopIteration, "End of list");
+    return NULL;
+  }
+}
+
+%exception nvme_subsystem_iter::__next__ {
+  assert(!subsys_iter_err);
+  $action
+  if (subsys_iter_err) {
+    subsys_iter_err = 0;
+    PyErr_SetString(PyExc_StopIteration, "End of list");
+    return NULL;
+  }
+}
+
+%exception nvme_ctrl_iter::__next__ {
+  assert(!ctrl_iter_err);
+  $action
+  if (ctrl_iter_err) {
+    ctrl_iter_err = 0;
+    PyErr_SetString(PyExc_StopIteration, "End of list");
+    return NULL;
+  }
+}
+
+%exception nvme_ns_iter::__next__ {
+  assert(!ns_iter_err);
+  $action
+  if (ns_iter_err) {
+    ns_iter_err = 0;
+    PyErr_SetString(PyExc_StopIteration, "End of list");
+    return NULL;
+  }
+}
+
+%exception nvme_ctrl::connect {
+  $action
+  if (connect_err == 1) {
+    connect_err = 0;
+    SWIG_exception(SWIG_AttributeError, "Existing controller connection");
+  } else if (connect_err) {
+    connect_err = 0;
+    SWIG_exception(SWIG_RuntimeError, "Connect failed");
+  }
+}
+
+%exception nvme_ctrl::discover {
+  $action
+  if (discover_err) {
+    discover_err = 0;
+    SWIG_exception(SWIG_RuntimeError,"Discover failed");
+  }
+}
+
+#include "tree.h"
+#include "fabrics.h"
+
+%typemap(in) struct nvme_fabrics_config * ($*1_type temp) {
+  Py_ssize_t pos = 0;
+  PyObject *key, *value;
+  char *keystr;
+  memset(&temp, 0, sizeof(struct nvme_fabrics_config));
+  temp.tos = -1;
+  temp.ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO;
+  while (PyDict_Next($input, &pos, &key, &value)) {
+    keystr = PyString_AsString(key);
+    if (!keystr)
+      continue;
+    if (!strcmp(keystr, "nr_io_queues"))
+      temp.nr_io_queues = PyLong_AsLong(value);
+    if (!strcmp(keystr, "reconnect_delay"))
+      temp.reconnect_delay = PyLong_AsLong(value);
+    if (!strcmp(keystr, "ctrl_loss_tmo"))
+      temp.ctrl_loss_tmo = PyLong_AsLong(value);
+    if (!strcmp(keystr, "keep_alive_tmo"))
+      temp.keep_alive_tmo = PyLong_AsLong(value);
+    if (!strcmp(keystr, "nr_write_queues"))
+      temp.nr_write_queues = PyLong_AsLong(value);
+    if (!strcmp(keystr, "nr_poll_queues"))
+      temp.nr_poll_queues = PyLong_AsLong(value);
+    if (!strcmp(keystr, "tos"))
+      temp.tos = PyLong_AsLong(value);
+    if (!strcmp(keystr, "duplicate_connect"))
+      temp.duplicate_connect = PyLong_AsLong(value);
+    if (!strcmp(keystr, "disable_sqflow"))
+      temp.disable_sqflow = PyLong_AsLong(value);
+    if (!strcmp(keystr, "hdr_digest"))
+      temp.hdr_digest = PyLong_AsLong(value);
+    if (!strcmp(keystr, "data_digest"))
+      temp.data_digest = PyLong_AsLong(value);
+  }
+  $1 = &temp;
+ };
+
+%typemap(out) uint8_t [8] {
+  $result = PyBytes_FromStringAndSize((char *)$1, 8);
+};
+
+%typemap(out) uint8_t [16] {
+  $result = PyBytes_FromStringAndSize((char *)$1, 16);
+};
+
+%typemap(out) struct nvmf_discovery_log * {
+  struct nvmf_discovery_log *log = $1;
+  int numrec = log? log->numrec : 0, i;
+  PyObject *obj = PyList_New(numrec);
+  if (!obj)
+    return NULL;
+  for (i = 0; i < numrec; i++) {
+    struct nvmf_disc_log_entry *e = &log->entries[i];
+    PyObject *entry = PyDict_New(), *val;
+
+    val = PyLong_FromLong(e->trtype);
+    PyDict_SetItemString(entry, "trtype", val);
+    val = PyLong_FromLong(e->adrfam);
+    PyDict_SetItemString(entry, "adrfam", val);
+    val = PyUnicode_FromString(e->traddr);
+    PyDict_SetItemString(entry, "traddr", val);
+    val = PyUnicode_FromString(e->trsvcid);
+    PyDict_SetItemString(entry, "trsvcid", val);
+    val = PyUnicode_FromString(e->subnqn);
+    PyDict_SetItemString(entry, "subnqn", val);
+    val = PyLong_FromLong(e->subtype);
+    PyDict_SetItemString(entry, "subtype", val);
+    val = PyLong_FromLong(e->treq);
+    PyDict_SetItemString(entry, "treq", val);
+    val = PyLong_FromLong(e->portid);
+    PyDict_SetItemString(entry, "portid", val);
+    val = PyLong_FromLong(e->cntlid);
+    PyDict_SetItemString(entry, "cntlid", val);
+    val = PyLong_FromLong(e->asqsz);
+    PyDict_SetItemString(entry, "asqsz", val);
+    PyList_SetItem(obj, i, entry);
+  }
+  $result = obj;
+ };
+struct nvme_root {
+  %immutable config_file;
+  char *config_file;
+};
+
+struct nvme_host {
+  %immutable hostnqn;
+  %immutable hostid;
+  char *hostnqn;
+  char *hostid;
+};
+
+struct nvme_subsystem {
+  %immutable subsysnqn;
+  %immutable model;
+  %immutable serial;
+  %immutable firmware;
+  char *subsysnqn;
+  char *model;
+  char *serial;
+  char *firmware;
+};
+
+struct nvme_ctrl {
+  %immutable transport;
+  %immutable subsysnqn;
+  %immutable traddr;
+  %immutable host_traddr;
+  %immutable trsvcid;
+  %immutable address;
+  %immutable firmware;
+  %immutable model;
+  %immutable numa_node;
+  %immutable queue_count;
+  %immutable serial;
+  %immutable sqsize;
+  char *transport;
+  char *subsysnqn;
+  char *traddr;
+  char *host_traddr;
+  char *trsvcid;
+  char *address;
+  char *firmware;
+  char *model;
+  char *numa_node;
+  char *queue_count;
+  char *serial;
+  char *sqsize;
+};
+
+struct nvme_ns {
+  %immutable nsid;
+  %immutable eui64;
+  %immutable nguid;
+  %immutable uuid;
+  unsigned int nsid;
+  uint8_t eui64[8];
+  uint8_t nguid[16];
+  uint8_t uuid[16];
+};
+
+%extend nvme_root {
+  nvme_root(const char *config_file = NULL) {
+    return nvme_scan(config_file);
+  }
+  ~nvme_root() {
+    nvme_free_tree($self);
+  }
+  struct nvme_host *hosts() {
+    return nvme_first_host($self);
+  }
+  void refresh_topology() {
+    nvme_refresh_topology($self);
+  }
+  void update_config() {
+    nvme_update_config($self);
+  }
+}
+
+%extend nvme_host_iter {
+  struct nvme_host_iter *__iter__() {
+    return $self;
+  }
+  struct nvme_host *__next__() {
+    struct nvme_host *this = $self->pos;
+
+    if (!this) {
+      host_iter_err = 1;
+      return NULL;
+    }
+    $self->pos = nvme_next_host($self->root, this);
+    return this;
+  }
+}
+
+%extend nvme_host {
+  nvme_host(struct nvme_root *r, const char *hostnqn = NULL,
+           const char *hostid = NULL) {
+    if (!hostnqn)
+      return nvme_default_host(r);
+    return nvme_lookup_host(r, hostnqn, hostid);
+  }
+  ~nvme_host() {
+    nvme_free_host($self);
+  }
+  char *__str__() {
+    static char tmp[2048];
+
+    sprintf(tmp, "nvme_host(%s,%s)", $self->hostnqn, $self->hostid);
+    return tmp;
+  }
+  struct nvme_host_iter __iter__() {
+    struct nvme_host_iter ret = { .root = nvme_host_get_root($self),
+                                    .pos = $self };
+    return ret;
+  }
+  struct nvme_subsystem *subsystems() {
+    return nvme_first_subsystem($self);
+  }
+}
+
+%extend nvme_subsystem_iter {
+  struct nvme_subsystem_iter *__iter__() {
+    return $self;
+  }
+  struct nvme_subsystem *__next__() {
+    struct nvme_subsystem *this = $self->pos;
+
+    if (!this) {
+      subsys_iter_err = 1;
+      return NULL;
+    }
+    $self->pos = nvme_next_subsystem($self->host, this);
+    return this;
+  }
+}
+
+%extend nvme_ns_iter {
+  struct nvme_ns_iter *__iter__() {
+    return $self;
+  }
+  struct nvme_ns *__next__() {
+    struct nvme_ns *this = $self->pos;
+
+    if (!this) {
+      ns_iter_err = 1;
+      return NULL;
+    }
+    if ($self->ctrl)
+      $self->pos = nvme_ctrl_next_ns($self->ctrl, this);
+    else
+      $self->pos = nvme_subsystem_next_ns($self->subsystem, this);
+    return this;
+  }
+}
+
+%extend nvme_subsystem {
+  nvme_subsystem(struct nvme_host *host, const char *subsysnqn,
+                const char *name = NULL) {
+    return nvme_lookup_subsystem(host, name, subsysnqn);
+  }
+  ~nvme_subsystem() {
+    nvme_free_subsystem($self);
+  }
+  char *__str__() {
+    static char tmp[1024];
+
+    sprintf(tmp, "nvme_subsystem(%s,%s)", $self->name,$self->subsysnqn);
+    return tmp;
+  }
+  struct nvme_subsystem_iter __iter__() {
+    struct nvme_subsystem_iter ret = { .host = nvme_subsystem_get_host($self),
+                                      .pos = $self };
+    return ret;
+  }
+  struct nvme_ctrl *controllers() {
+    return nvme_subsystem_first_ctrl($self);
+  }
+  struct nvme_ns *namespaces() {
+    return nvme_subsystem_first_ns($self);
+  }
+  %immutable name;
+  const char *name;
+  %immutable host;
+  struct nvme_host *host;
+}
+
+%{
+  const char *nvme_subsystem_name_get(struct nvme_subsystem *s) {
+    return nvme_subsystem_get_name(s);
+  }
+  struct nvme_host *nvme_subsystem_host_get(struct nvme_subsystem *s) {
+    return nvme_subsystem_get_host(s);
+  }
+%};
+
+%extend nvme_ctrl_iter {
+  struct nvme_ctrl_iter *__iter__() {
+    return $self;
+  }
+  struct nvme_ctrl *__next__() {
+    struct nvme_ctrl *this = $self->pos;
+
+    if (!this) {
+      ctrl_iter_err = 1;
+      return NULL;
+    }
+    $self->pos = nvme_subsystem_next_ctrl($self->subsystem, this);
+    return this;
+  }
+}
+
+%extend nvme_ctrl {
+  nvme_ctrl(const char *subsysnqn, const char *transport,
+           const char *traddr = NULL, const char *host_traddr = NULL,
+           const char *host_iface = NULL, const char *trsvcid = NULL) {
+    return nvme_create_ctrl(subsysnqn, transport, traddr,
+                           host_traddr, host_iface, trsvcid);
+  }
+  ~nvme_ctrl() {
+    nvme_free_ctrl($self);
+  }
+  void connect(struct nvme_host *h, struct nvme_fabrics_config *cfg = NULL) {
+    int ret;
+    const char *dev;
+
+    dev = nvme_ctrl_get_name($self);
+    if (dev && !cfg->duplicate_connect) {
+      connect_err = 1;
+      return;
+    }
+    ret = nvmf_add_ctrl(h, $self, cfg, cfg->disable_sqflow);
+    if (ret < 0) {
+      connect_err = 2;
+      return;
+    }
+  }
+  bool connected() {
+    return nvme_ctrl_get_name($self) != NULL;
+  }
+  void rescan() {
+    nvme_rescan_ctrl($self);
+  }
+  void disconnect() {
+    nvme_disconnect_ctrl($self);
+  }
+  struct nvmf_discovery_log *discover(int max_retries = 6) {
+    struct nvmf_discovery_log *logp = NULL;
+    int ret = 0;
+    ret = nvmf_get_discovery_log($self, &logp, max_retries);
+    if (ret < 0) {
+      discover_err = 1;
+      return NULL;
+    }
+    return logp;
+  }
+  char *__str__() {
+    static char tmp[1024];
+
+    if ($self->address)
+      sprintf(tmp, "nvme_ctrl(transport=%s,%s)", $self->transport,
+             $self->address);
+    else
+      sprintf(tmp, "nvme_ctrl(transport=%s)", $self->transport);
+    return tmp;
+  }
+  struct nvme_ctrl_iter __iter__() {
+    struct nvme_ctrl_iter ret = { .subsystem = nvme_ctrl_get_subsystem($self),
+                                 .pos = $self };
+    return ret;
+  }
+  struct nvme_ns *namespaces() {
+    return nvme_ctrl_first_ns($self);
+  }
+  %immutable name;
+  const char *name;
+  %immutable subsystem;
+  struct nvme_subsystem *subsystem;
+  %immutable state;
+  const char *state;
+}
+
+%{
+  const char *nvme_ctrl_name_get(struct nvme_ctrl *c) {
+    return nvme_ctrl_get_name(c);
+  }
+  struct nvme_subsystem *nvme_ctrl_subsystem_get(struct nvme_ctrl *c) {
+    return nvme_ctrl_get_subsystem(c);
+  }
+  const char *nvme_ctrl_state_get(struct nvme_ctrl *c) {
+    return nvme_ctrl_get_state(c);
+  }
+%};
+
+%extend nvme_ns {
+  nvme_ns(struct nvme_subsystem *s, unsigned int nsid) {
+    return nvme_subsystem_lookup_namespace(s, nsid);
+  }
+  ~nvme_ns() {
+    nvme_free_ns($self);
+  }
+  char *__str__() {
+    static char tmp[1024];
+
+    sprintf(tmp, "nvme_ns(%u)", $self->nsid);
+    return tmp;
+  }
+  struct nvme_ns_iter __iter__() {
+    struct nvme_ns_iter ret = { .ctrl = nvme_ns_get_ctrl($self),
+                               .subsystem = nvme_ns_get_subsystem($self),
+                               .pos = $self };
+    return ret;
+  }
+  %immutable name;
+  const char *name;
+}
+
+%{
+  const char *nvme_ns_name_get(struct nvme_ns *n) {
+    return nvme_ns_get_name(n);
+  }
+%};
diff --git a/src/setup.py b/src/setup.py
new file mode 100644 (file)
index 0000000..028eec8
--- /dev/null
@@ -0,0 +1,14 @@
+from distutils.core import setup, Extension
+
+libnvme_module = Extension('_libnvme',
+        sources=['nvme/libnvme_wrap.c'],
+        libraries=['nvme', 'json-c', 'uuid', 'systemd'], library_dirs=['./'],
+        include_dirs = ['../ccan','nvme'])
+
+setup(name='libnvme',
+      author="Hannes Reinecke",
+      author_email='hare@suse.de',
+      description='python bindings for libnvme',
+      ext_modules=[libnvme_module],
+      py_modules=["libnvme"],
+)