// 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"