From: Hannes Reinecke Date: Thu, 6 May 2021 06:19:32 +0000 (+0200) Subject: Add SWIG interface generator files X-Git-Tag: v1.0-rc0~124^2~3 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=c6cbf0e6b1ffe2a9ac13a148e3543eec41c04424;p=users%2Fsagi%2Flibnvme.git Add SWIG interface generator files Add files to generate a python binding via SWIG. Signed-off-by: Hannes Reinecke --- diff --git a/Makefile b/Makefile index a4dbd7df..2dd7137a 100644 --- 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 diff --git a/src/Makefile b/src/Makefile index 19361f89..c07d1fe2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 index 00000000..25eddb44 --- /dev/null +++ b/src/nvme/libnvme.i @@ -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 + */ + +%module libnvme + +%include "exception.i" + +%allowexception; + +%{ +#include +#include +#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 index 00000000..028eec89 --- /dev/null +++ b/src/setup.py @@ -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"], +)