From 068a45420f2c98887e220b45e946cc7074da550e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 21:22:29 +0200 Subject: Adding upstream version 1.8. Signed-off-by: Daniel Baumann --- libnvme/nvme.i | 1068 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1068 insertions(+) create mode 100644 libnvme/nvme.i (limited to 'libnvme/nvme.i') diff --git a/libnvme/nvme.i b/libnvme/nvme.i new file mode 100644 index 0000000..eb94cac --- /dev/null +++ b/libnvme/nvme.i @@ -0,0 +1,1068 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * This file is part of libnvme. + * Copyright (c) 2021 SUSE Software Solutions + * + * Authors: Hannes Reinecke + */ + +%module(docstring="Python bindings for libnvme") nvme +%feature("autodoc", "1"); + +%include "exception.i" + +%allowexception; + +%rename(root) nvme_root; +%rename(host) nvme_host; +%rename(ctrl) nvme_ctrl; +%rename(subsystem) nvme_subsystem; +%rename(ns) nvme_ns; + +%{ + #include + #include + #include "nvme/tree.h" + #include "nvme/fabrics.h" + #include "nvme/private.h" + #include "nvme/log.h" + #include "nvme/ioctl.h" + #include "nvme/types.h" + #include "nvme/nbft.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; + + static void PyDict_SetItemStringDecRef(PyObject * p, const char *key, PyObject *val) { + PyDict_SetItemString(p, key, val); /* Does NOT steal reference to val .. */ + Py_XDECREF(val); /* .. therefore decrement ref. count. */ + } + PyObject *hostnqn_from_file() { + char * val = nvmf_hostnqn_from_file(); + PyObject * obj = PyUnicode_FromString(val); + free(val); + return obj; + } + PyObject *hostid_from_file() { + char * val = nvmf_hostid_from_file(); + PyObject * obj = PyUnicode_FromString(val); + free(val); + return obj; + } +%} +PyObject *hostnqn_from_file(); +PyObject *hostid_from_file(); + +%inline %{ + struct host_iter { + struct nvme_root *root; + struct nvme_host *pos; + }; + + struct subsystem_iter { + struct nvme_host *host; + struct nvme_subsystem *pos; + }; + + struct ctrl_iter { + struct nvme_subsystem *subsystem; + struct nvme_ctrl *pos; + }; + + struct ns_iter { + struct nvme_subsystem *subsystem; + struct nvme_ctrl *ctrl; + struct nvme_ns *pos; + }; +%} + +%exception host_iter::__next__ { + host_iter_err = 0; + $action /* $action sets host_iter_err to non-zero value on failure */ + if (host_iter_err) { + PyErr_SetString(PyExc_StopIteration, "End of list"); + return NULL; + } +} + +%exception subsystem_iter::__next__ { + subsys_iter_err = 0; + $action /* $action sets subsys_iter_err to non-zero value on failure */ + if (subsys_iter_err) { + PyErr_SetString(PyExc_StopIteration, "End of list"); + return NULL; + } +} + +%exception ctrl_iter::__next__ { + ctrl_iter_err = 0; + $action /* $action sets ctrl_iter_err to non-zero value on failure */ + if (ctrl_iter_err) { + PyErr_SetString(PyExc_StopIteration, "End of list"); + return NULL; + } +} + +%exception ns_iter::__next__ { + ns_iter_err = 0; + $action /* $action sets ns_iter_err to non-zero value on failure */ + if (ns_iter_err) { + PyErr_SetString(PyExc_StopIteration, "End of list"); + return NULL; + } +} + +%exception nvme_ctrl::connect { + connect_err = 0; + errno = 0; + $action /* $action sets connect_err to non-zero value on failure */ + if (connect_err == 1) { + SWIG_exception(SWIG_AttributeError, "Existing controller connection"); + } else if (connect_err) { + const char *errstr = nvme_errno_to_string(errno); + if (errstr) { + SWIG_exception(SWIG_RuntimeError, errstr); + } else { + SWIG_exception(SWIG_RuntimeError, "Connect failed"); + } + } +} + +%exception nvme_ctrl::discover { + discover_err = 0; + $action /* $action sets discover_err to non-zero value on failure */ + if (discover_err) { + SWIG_exception(SWIG_RuntimeError, "Discover failed"); + } +} + +%typemap(in) struct nvme_fabrics_config *($*1_type temp){ + Py_ssize_t pos = 0; + PyObject * key,*value; + memset(&temp, 0, sizeof(temp)); + temp.tos = -1; + temp.ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO; + while (PyDict_Next($input, &pos, &key, &value)) { + if (!PyUnicode_CompareWithASCIIString(key, "host_traddr")) { + temp.host_traddr = PyBytes_AsString(value); + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "host_iface")) { + temp.host_iface = PyBytes_AsString(value); + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "nr_io_queues")) { + temp.nr_io_queues = PyLong_AsLong(value); + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "reconnect_delay")) { + temp.reconnect_delay = PyLong_AsLong(value); + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "ctrl_loss_tmo")) { + temp.ctrl_loss_tmo = PyLong_AsLong(value); + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "keep_alive_tmo")) { + temp.keep_alive_tmo = PyLong_AsLong(value); + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "nr_write_queues")) { + temp.nr_write_queues = PyLong_AsLong(value); + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "nr_poll_queues")) { + temp.nr_poll_queues = PyLong_AsLong(value); + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "tos")) { + temp.tos = PyLong_AsLong(value); + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "duplicate_connect")) { + temp.duplicate_connect = PyObject_IsTrue(value) ? true : false; + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "disable_sqflow")) { + temp.disable_sqflow = PyObject_IsTrue(value) ? true : false; + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "hdr_digest")) { + temp.hdr_digest = PyObject_IsTrue(value) ? true : false; + continue; + } + if (!PyUnicode_CompareWithASCIIString(key, "data_digest")) { + temp.data_digest = PyObject_IsTrue(value) ? true : false; + continue; + } + } + $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(newfree) struct nvmf_discovery_log * { + if ($1) free($1); +} + +%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; + + switch (e->trtype) { + case NVMF_TRTYPE_UNSPECIFIED: + val = PyUnicode_FromString("unspecified"); + break; + case NVMF_TRTYPE_RDMA: + val = PyUnicode_FromString("rdma"); + break; + case NVMF_TRTYPE_FC: + val = PyUnicode_FromString("fc"); + break; + case NVMF_TRTYPE_TCP: + val = PyUnicode_FromString("tcp"); + break; + case NVMF_TRTYPE_LOOP: + val = PyUnicode_FromString("loop"); + break; + default: + val = PyLong_FromLong(e->trtype); + } + PyDict_SetItemStringDecRef(entry, "trtype", val); + + switch (e->adrfam) { + case NVMF_ADDR_FAMILY_PCI: + val = PyUnicode_FromString("pci"); + break; + case NVMF_ADDR_FAMILY_IP4: + val = PyUnicode_FromString("ipv4"); + break; + case NVMF_ADDR_FAMILY_IP6: + val = PyUnicode_FromString("ipv6"); + break; + case NVMF_ADDR_FAMILY_IB: + val = PyUnicode_FromString("infiniband"); + break; + case NVMF_ADDR_FAMILY_FC: + val = PyUnicode_FromString("fc"); + break; + default: + val = PyLong_FromLong(e->adrfam); + } + PyDict_SetItemStringDecRef(entry, "adrfam", val); + + val = PyUnicode_FromString(e->traddr); + PyDict_SetItemStringDecRef(entry, "traddr", val); + val = PyUnicode_FromString(e->trsvcid); + PyDict_SetItemStringDecRef(entry, "trsvcid", val); + val = PyUnicode_FromString(e->subnqn); + PyDict_SetItemStringDecRef(entry, "subnqn", val); + + switch (e->subtype) { + case NVME_NQN_DISC: + val = PyUnicode_FromString("referral"); + break; + case NVME_NQN_NVME: + val = PyUnicode_FromString("nvme"); + break; + case NVME_NQN_CURR: + val = PyUnicode_FromString("discovery"); + break; + default: + val = PyLong_FromLong(e->subtype); + } + PyDict_SetItemStringDecRef(entry, "subtype", val); + + switch (e->treq) { + case NVMF_TREQ_NOT_SPECIFIED: + val = PyUnicode_FromString("not specified"); + break; + case NVMF_TREQ_REQUIRED: + val = PyUnicode_FromString("required"); + break; + case NVMF_TREQ_NOT_REQUIRED: + val = PyUnicode_FromString("not required"); + break; + case NVMF_TREQ_DISABLE_SQFLOW: + val = PyUnicode_FromString("disable sqflow"); + break; + default: + val = PyLong_FromLong(e->treq); + } + PyDict_SetItemStringDecRef(entry, "treq", val); + + val = PyLong_FromLong(e->portid); + PyDict_SetItemStringDecRef(entry, "portid", val); + val = PyLong_FromLong(e->cntlid); + PyDict_SetItemStringDecRef(entry, "cntlid", val); + val = PyLong_FromLong(e->asqsz); + PyDict_SetItemStringDecRef(entry, "asqsz", val); + val = PyLong_FromLong(e->eflags); + PyDict_SetItemStringDecRef(entry, "eflags", val); + PyList_SetItem(obj, i, entry); /* steals ref. to object - no need to decref */ + } + $result = obj; +}; + +#include "tree.h" +#include "fabrics.h" +#define STR_OR_NONE(str) (!(str) ? "None" : str) + +struct nvme_root { + %immutable config_file; + %immutable application; + char *config_file; + char *application; +}; + +struct nvme_host { + %immutable hostnqn; + %immutable hostid; + %immutable hostsymname; + char *hostnqn; + char *hostid; + char *hostsymname; + %extend { + char *dhchap_key; + } +}; + +struct nvme_subsystem { + %immutable subsysnqn; + %immutable model; + %immutable serial; + %immutable firmware; + %immutable application; + char *subsysnqn; + char *model; + char *serial; + char *firmware; + char *application; +}; + +struct nvme_ctrl { + %immutable sysfs_dir; + %immutable address; + %immutable firmware; + %immutable model; + %immutable numa_node; + %immutable queue_count; + %immutable serial; + %immutable sqsize; + %immutable transport; + %immutable subsysnqn; + %immutable traddr; + %immutable trsvcid; + %immutable dhchap_host_key; + %immutable dhchap_key; + %immutable cntrltype; + %immutable dctype; + %immutable discovery_ctrl; + %immutable discovered; + %immutable persistent; + char *sysfs_dir; + char *address; + char *firmware; + char *model; + char *numa_node; + char *queue_count; + char *serial; + char *sqsize; + char *transport; + char *subsysnqn; + char *traddr; + char *trsvcid; + %extend { + char *dhchap_host_key: + char *dhchap_key; + } + char *cntrltype; + char *dctype; + bool discovery_ctrl; + bool discovered; + bool persistent; +}; + +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); + } + void log_level(const char *level) { + int log_level = DEFAULT_LOGLEVEL; + if (!strcmp(level, "debug")) log_level = LOG_DEBUG; + else if (!strcmp(level, "info")) log_level = LOG_INFO; + else if (!strcmp(level, "notice")) log_level = LOG_NOTICE; + else if (!strcmp(level, "warning")) log_level = LOG_WARNING; + else if (!strcmp(level, "err")) log_level = LOG_ERR; + else if (!strcmp(level, "crit")) log_level = LOG_CRIT; + else if (!strcmp(level, "alert")) log_level = LOG_ALERT; + else if (!strcmp(level, "emerg")) log_level = LOG_EMERG; + nvme_init_logging($self, log_level, false, false); + } + struct nvme_host *hosts() { + return nvme_first_host($self); + } + void refresh_topology() { + nvme_refresh_topology($self); + } + void update_config() { + nvme_update_config($self); + } + void dump_config() { + nvme_dump_config($self); + } +} + +%extend host_iter { + struct 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; + } +} + +%define SET_SYMNAME_DOCSTRING +"@brief Set or Clear Host's Symbolic Name + +@param hostsymname: A symbolic name, or None to clear the symbolic name. +@type hostsymname: str|None + +@return: None" +%enddef + +%pythonappend nvme_host::nvme_host(struct nvme_root *r, + const char *hostnqn, + const char *hostid, + const char *hostkey, + const char *hostsymname) { + self.__parent = r # Keep a reference to parent to ensure garbage collection happens in the right order} +%extend nvme_host { + nvme_host(struct nvme_root *r, + const char *hostnqn = NULL, + const char *hostid = NULL, + const char *hostkey = NULL, + const char *hostsymname = NULL) { + nvme_host_t h = hostnqn ? nvme_lookup_host(r, hostnqn, hostid) : nvme_default_host(r); + if (hostsymname) + nvme_host_set_hostsymname(h, hostsymname); + if (hostkey) + nvme_host_set_dhchap_key(h, hostkey); + return h; + } + ~nvme_host() { + nvme_free_host($self); + } + %feature("autodoc", SET_SYMNAME_DOCSTRING) set_symname; + void set_symname(const char *hostsymname) { + nvme_host_set_hostsymname($self, hostsymname); + } + + PyObject* __str__() { + return PyUnicode_FromFormat("nvme.host(%s,%s)", STR_OR_NONE($self->hostnqn), STR_OR_NONE($self->hostid)); + } + struct host_iter __iter__() { + struct host_iter ret = { + .root = nvme_host_get_root($self), + .pos = $self + }; + return ret; + } + struct nvme_subsystem* subsystems() { + return nvme_first_subsystem($self); + } +} + +%{ + const char *nvme_host_dhchap_key_get(struct nvme_host *h) { + return nvme_host_get_dhchap_key(h); + } + void nvme_host_dhchap_key_set(struct nvme_host *h, char *key) { + nvme_host_set_dhchap_key(h, key); + } +%}; + +%extend subsystem_iter { + struct 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 ns_iter { + struct 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; + } +} + +%pythonappend nvme_subsystem::nvme_subsystem(struct nvme_host *host, + const char *subsysnqn, + const char *name) { + self.__parent = host # Keep a reference to parent to ensure garbage collection happens in the right order} +%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); + } + PyObject *__str__() { + return PyUnicode_FromFormat("nvme.subsystem(%s,%s)", STR_OR_NONE($self->name), STR_OR_NONE($self->subsysnqn)); + } + struct subsystem_iter __iter__() { + struct 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 ctrl_iter { + struct 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; + } +} + +%pythonappend nvme_ctrl::connect(struct nvme_host *h, + struct nvme_fabrics_config *cfg) { + self.__host = h # Keep a reference to parent to ensure ctrl obj gets GCed before host} +%pythonappend nvme_ctrl::init(struct nvme_host *h, int instance) { + self.__host = h # Keep a reference to parent to ensure ctrl obj gets GCed before host} +%extend nvme_ctrl { + nvme_ctrl(struct nvme_root *r, + 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(r, subsysnqn, transport, traddr, + host_traddr, host_iface, trsvcid); + } + ~nvme_ctrl() { + nvme_free_ctrl($self); + } + + void discovery_ctrl_set(bool discovery) { + nvme_ctrl_set_discovery_ctrl($self, discovery); + } + + bool init(struct nvme_host *h, int instance) { + return nvme_init_ctrl(h, $self, instance) == 0; + } + + 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; + } + + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ + ret = nvmf_add_ctrl(h, $self, cfg); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ + + if (ret < 0) { + connect_err = 2; + return; + } + } + bool connected() { + return nvme_ctrl_get_name($self) != NULL; + } + void persistent_set(bool persistent) { + nvme_ctrl_set_persistent($self, persistent); + } + void rescan() { + nvme_rescan_ctrl($self); + } + void disconnect() { + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ + nvme_disconnect_ctrl($self); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ + } + + %feature("autodoc", "@return: True if controller supports explicit registration. False otherwise.") is_registration_supported; + bool is_registration_supported() { + return nvmf_is_registration_supported($self); + } + + %feature("autodoc", "@return None on success or Error string on error.") registration_ctlr; + PyObject *registration_ctlr(enum nvmf_dim_tas tas) { + __u32 result; + int status; + + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ + status = nvmf_register_ctrl($self, NVMF_DIM_TAS_REGISTER, &result); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ + + if (status != NVME_SC_SUCCESS) { + /* On error, return an error message */ + return (status < 0) ? + PyUnicode_FromFormat("Status:0x%04x - %s", status, nvme_status_to_string(status, false)) : + PyUnicode_FromFormat("Result:0x%04x, Status:0x%04x - %s", result, status, nvme_status_to_string(status, false)); + } + + /* On success, return None */ + Py_RETURN_NONE; + } + + %newobject discover; + struct nvmf_discovery_log *discover(int lsp = 0, int max_retries = 6) { + struct nvmf_discovery_log *logp; + struct nvme_get_discovery_args args = { + .c = $self, + .args_size = sizeof(args), + .max_retries = max_retries, + .result = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lsp = lsp, + }; + + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ + logp = nvmf_get_discovery_wargs(&args); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ + + if (logp == NULL) discover_err = 1; + return logp; + } + + %feature("autodoc", "@return: List of supported log pages") supported_log_pages; + PyObject *supported_log_pages(bool rae = true) { + struct nvme_supported_log_pages log; + PyObject *obj = NULL; + int ret = 0; + + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ + ret = nvme_get_log_supported_log_pages(nvme_ctrl_get_fd($self), rae, &log); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ + + if (ret < 0) { + Py_RETURN_NONE; + } + + obj = PyList_New(NVME_LOG_SUPPORTED_LOG_PAGES_MAX); + if (!obj) Py_RETURN_NONE; + + for (int i = 0; i < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; i++) + PyList_SetItem(obj, i, PyLong_FromLong(le32_to_cpu(log.lid_support[i]))); /* steals ref. to object - no need to decref */ + + return obj; + } + + PyObject* __str__() { + return $self->address ? + PyUnicode_FromFormat("nvme_ctrl(transport=%s,%s)", STR_OR_NONE($self->transport), STR_OR_NONE($self->address)) : + PyUnicode_FromFormat("nvme_ctrl(transport=%s)", STR_OR_NONE($self->transport)); + } + struct ctrl_iter __iter__() { + struct 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); + } + const char *nvme_ctrl_dhchap_key_get(struct nvme_ctrl *c) { + return nvme_ctrl_get_dhchap_key(c); + } + void nvme_ctrl_dhchap_key_set(struct nvme_ctrl *c, const char *key) { + nvme_ctrl_set_dhchap_key(c, key); + } + const char *nvme_ctrl_dhchap_host_key_get(struct nvme_ctrl *c) { + return nvme_ctrl_get_dhchap_host_key(c); + } +%}; + +%pythonappend nvme_ns::nvme_ns(struct nvme_subsystem *s, + unsigned int nsid) { + self.__parent = s # Keep a reference to parent to ensure garbage collection happens in the right order} +%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); + } + PyObject *__str__() { + return PyUnicode_FromFormat("nvme.ns(%u)", $self->nsid); + } + struct ns_iter __iter__() { + struct 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); + } +%}; + +/****** + NBFT + ******/ +%{ + static PyObject *ssns_to_dict(struct nbft_info_subsystem_ns *ss) + { + unsigned int i; + PyObject *output = PyDict_New(); + PyObject *hfis = PyList_New(ss->num_hfis); + + for (i = 0; i < ss->num_hfis; i++) + PyList_SetItem(hfis, i, PyLong_FromLong(ss->hfis[i]->index - 1)); /* steals ref. to object - no need to decref */ + + PyDict_SetItemStringDecRef(output, "hfi_indexes", hfis); + + PyDict_SetItemStringDecRef(output, "trtype", PyUnicode_FromString(ss->transport)); + PyDict_SetItemStringDecRef(output, "traddr", PyUnicode_FromString(ss->traddr)); + PyDict_SetItemStringDecRef(output, "trsvcid", PyUnicode_FromString(ss->trsvcid)); + PyDict_SetItemStringDecRef(output, "subsys_port_id", PyLong_FromLong(ss->subsys_port_id)); + PyDict_SetItemStringDecRef(output, "nsid", PyLong_FromLong(ss->nsid)); + + { + PyObject *nid; + switch (ss->nid_type) { + case NBFT_INFO_NID_TYPE_EUI64: + PyDict_SetItemStringDecRef(output, "nid_type", PyUnicode_FromString("eui64")); + nid = PyUnicode_FromFormat("%02x%02x%02x%02x%02x%02x%02x%02x", + ss->nid[0], ss->nid[1], ss->nid[2], ss->nid[3], + ss->nid[4], ss->nid[5], ss->nid[6], ss->nid[7]); + break; + + case NBFT_INFO_NID_TYPE_NGUID: + PyDict_SetItemStringDecRef(output, "nid_type", PyUnicode_FromString("nguid")); + nid = PyUnicode_FromFormat("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + ss->nid[0], ss->nid[1], ss->nid[2], ss->nid[3], + ss->nid[4], ss->nid[5], ss->nid[6], ss->nid[7], + ss->nid[8], ss->nid[9], ss->nid[10], ss->nid[11], + ss->nid[12], ss->nid[13], ss->nid[14], ss->nid[15]); + break; + + case NBFT_INFO_NID_TYPE_NS_UUID: + { + char uuid_str[NVME_UUID_LEN_STRING]; + PyDict_SetItemStringDecRef(output, "nid_type", PyUnicode_FromString("uuid")); + nvme_uuid_to_string(ss->nid, uuid_str); + nid = PyUnicode_FromString(uuid_str); + break; + } + + default: + nid = NULL; + break; + } + if (nid) + PyDict_SetItemStringDecRef(output, "nid", nid); + } + + if (ss->subsys_nqn) + PyDict_SetItemStringDecRef(output, "subsys_nqn", PyUnicode_FromString(ss->subsys_nqn)); + + PyDict_SetItemStringDecRef(output, "controller_id", PyLong_FromLong(ss->controller_id)); + PyDict_SetItemStringDecRef(output, "asqsz", PyLong_FromLong(ss->asqsz)); + + if (ss->dhcp_root_path_string) + PyDict_SetItemStringDecRef(output, "dhcp_root_path_string", PyUnicode_FromString(ss->dhcp_root_path_string)); + + PyDict_SetItemStringDecRef(output, "pdu_header_digest_required", PyBool_FromLong(ss->pdu_header_digest_required)); + PyDict_SetItemStringDecRef(output, "data_digest_required", PyBool_FromLong(ss->data_digest_required)); + + return output; + } + + static PyObject *hfi_to_dict(struct nbft_info_hfi *hfi) + { + PyObject *output = PyDict_New(); + + PyDict_SetItemStringDecRef(output, "trtype", PyUnicode_FromString(hfi->transport)); + + if (!strcmp(hfi->transport, "tcp")) { + PyDict_SetItemStringDecRef(output, "pcidev", + PyUnicode_FromFormat("%x:%x:%x.%x", + ((hfi->tcp_info.pci_sbdf & 0xffff0000) >> 16), + ((hfi->tcp_info.pci_sbdf & 0x0000ff00) >> 8), + ((hfi->tcp_info.pci_sbdf & 0x000000f8) >> 3), + ((hfi->tcp_info.pci_sbdf & 0x00000007) >> 0))); + + PyDict_SetItemStringDecRef(output, "mac_addr", + PyUnicode_FromFormat("%02x:%02x:%02x:%02x:%02x:%02x", + hfi->tcp_info.mac_addr[0], + hfi->tcp_info.mac_addr[1], + hfi->tcp_info.mac_addr[2], + hfi->tcp_info.mac_addr[3], + hfi->tcp_info.mac_addr[4], + hfi->tcp_info.mac_addr[5])); + + PyDict_SetItemStringDecRef(output, "vlan", PyLong_FromLong(hfi->tcp_info.vlan)); + PyDict_SetItemStringDecRef(output, "ip_origin", PyLong_FromLong(hfi->tcp_info.ip_origin)); + PyDict_SetItemStringDecRef(output, "ipaddr", PyUnicode_FromString(hfi->tcp_info.ipaddr)); + PyDict_SetItemStringDecRef(output, "subnet_mask_prefix", PyLong_FromLong(hfi->tcp_info.subnet_mask_prefix)); + PyDict_SetItemStringDecRef(output, "gateway_ipaddr", PyUnicode_FromString(hfi->tcp_info.gateway_ipaddr)); + PyDict_SetItemStringDecRef(output, "route_metric", PyLong_FromLong(hfi->tcp_info.route_metric)); + PyDict_SetItemStringDecRef(output, "primary_dns_ipaddr", PyUnicode_FromString(hfi->tcp_info.primary_dns_ipaddr)); + PyDict_SetItemStringDecRef(output, "secondary_dns_ipaddr", PyUnicode_FromString(hfi->tcp_info.secondary_dns_ipaddr)); + PyDict_SetItemStringDecRef(output, "dhcp_server_ipaddr", PyUnicode_FromString(hfi->tcp_info.dhcp_server_ipaddr)); + + if (hfi->tcp_info.host_name) + PyDict_SetItemStringDecRef(output, "host_name", PyUnicode_FromString(hfi->tcp_info.host_name)); + + PyDict_SetItemStringDecRef(output, "this_hfi_is_default_route", PyBool_FromLong(hfi->tcp_info.this_hfi_is_default_route)); + PyDict_SetItemStringDecRef(output, "dhcp_override", PyBool_FromLong(hfi->tcp_info.dhcp_override)); + } + + return output; + } + + static PyObject *discovery_to_dict(struct nbft_info_discovery *disc) + { + PyObject *output = PyDict_New(); + + if (disc->security) + PyDict_SetItemStringDecRef(output, "security_index", PyLong_FromLong(disc->security->index)); + if (disc->hfi) + PyDict_SetItemStringDecRef(output, "hfi_index", PyLong_FromLong(disc->hfi->index - 1)); + if (disc->uri) + PyDict_SetItemStringDecRef(output, "uri", PyUnicode_FromString(disc->uri)); + if (disc->nqn) + PyDict_SetItemStringDecRef(output, "nqn", PyUnicode_FromString(disc->nqn)); + + return output; + } + + static PyObject *nbft_to_pydict(struct nbft_info *nbft) + { + PyObject *val; + PyObject *output = PyDict_New(); + + { + PyObject *host = PyDict_New(); + + if (nbft->host.nqn) + PyDict_SetItemStringDecRef(host, "nqn", PyUnicode_FromString(nbft->host.nqn)); + if (nbft->host.id) { + char uuid_str[NVME_UUID_LEN_STRING]; + nvme_uuid_to_string((unsigned char *)nbft->host.id, uuid_str); + PyDict_SetItemStringDecRef(host, "id", PyUnicode_FromString(uuid_str)); + } + + PyDict_SetItemStringDecRef(host, "host_id_configured", PyBool_FromLong(nbft->host.host_id_configured)); + PyDict_SetItemStringDecRef(host, "host_nqn_configured", PyBool_FromLong(nbft->host.host_nqn_configured)); + + val = PyUnicode_FromString(nbft->host.primary == NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_NOT_INDICATED ? "not indicated" : + nbft->host.primary == NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_UNSELECTED ? "unselected" : + nbft->host.primary == NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_SELECTED ? "selected" : "reserved"); + PyDict_SetItemStringDecRef(host, "primary_admin_host_flag", val); + + PyDict_SetItemStringDecRef(output, "host", host); + } + + { + size_t ss_num = 0; + struct nbft_info_subsystem_ns **ss; + PyObject *subsystem; + + /* First, let's find how many entries there are */ + for (ss = nbft->subsystem_ns_list; ss && *ss; ss++) + ss_num++; + + /* Now, let's fill the list using "(*ss)->index - 1" + as the index for writing to the list */ + subsystem = PyList_New(ss_num); + for (ss = nbft->subsystem_ns_list; ss && *ss; ss++) + PyList_SetItem(subsystem, (*ss)->index - 1, ssns_to_dict(*ss)); /* steals ref. to object - no need to decref */ + + PyDict_SetItemStringDecRef(output, "subsystem", subsystem); + } + + { + size_t hfi_num = 0; + struct nbft_info_hfi **hfi; + PyObject *hfis; + + /* First, let's find how many entries there are */ + for (hfi = nbft->hfi_list; hfi && *hfi; hfi++) + hfi_num++; + + /* Now, let's fill the list using "(*hfi)->index - 1" + as the index for writing to the list */ + hfis = PyList_New(hfi_num); + for (hfi = nbft->hfi_list; hfi && *hfi; hfi++) + PyList_SetItem(hfis, (*hfi)->index-1, hfi_to_dict(*hfi)); /* steals ref. to object - no need to decref */ + + PyDict_SetItemStringDecRef(output, "hfi", hfis); + } + + { + size_t disc_num = 0; + struct nbft_info_discovery **disc; + PyObject *discovery; + + /* First, let's find how many entries there are */ + for (disc = nbft->discovery_list; disc && *disc; disc++) + disc_num++; + + /* Now, let's fill the list using "(*disc)->index - 1" + as the index for writing to the list */ + discovery = PyList_New(disc_num); + for (disc = nbft->discovery_list; disc && *disc; disc++) + PyList_SetItem(discovery, (*disc)->index - 1, discovery_to_dict(*disc)); /* steals ref. to object - no need to decref */ + + PyDict_SetItemStringDecRef(output, "discovery", discovery); + } + + /* Security profiles are currently not implemented. */ + + return output; + } + + PyObject *nbft_get(const char * filename) + { + struct nbft_info *nbft; + PyObject *output; + int ret; + + ret = nvme_nbft_read(&nbft, filename); + if (ret) { + Py_RETURN_NONE; + } + + output = nbft_to_pydict(nbft); + nvme_nbft_free(nbft); + return output; + } +%}; + +%feature("autodoc", "@return an NBFT table as a dict on success, None otherwise.\n" + "@param filename: file to read") nbft_get; +PyObject *nbft_get(const char * filename); + +// We want to swig all the #define and enum from types.h, but none of the structs. +#pragma SWIG nowarn=503 // Supress warnings about unnamed struct +#define __attribute__(x) +%rename($ignore, %$isclass) ""; // ignore all classes/structs +%rename($ignore, %$isfunction) ""; // ignore all functions +%rename($ignore, %$isunion) ""; // ignore all unions +%rename($ignore, %$isvariable) ""; // ignore all variables + +%include "../src/nvme/types.h" -- cgit v1.2.3