├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── README.md ├── autoconf.sh ├── compile ├── configure.ac ├── files ├── Licenses ├── gdb.in ├── json.schemas │ ├── dem-dc_config-file_json-schema │ ├── dem-dc_http-only_commands │ ├── dem-ec_curl_trace.log │ ├── dem_cli_curl_trace.log │ └── dem_cli_curl_trace.sh ├── mongoose.c ├── mongoose.h ├── spdk_install.sh ├── valgrind_suppress └── wiki │ ├── picture1.png │ ├── picture2.png │ ├── picture3.png │ ├── picture4.png │ ├── picture5.png │ ├── picture6.png │ ├── picture7.png │ ├── picture8.png │ ├── picture9.png │ ├── tutorial1.png │ ├── tutorial10.png │ ├── tutorial11.png │ ├── tutorial12.png │ ├── tutorial13.png │ ├── tutorial14.png │ ├── tutorial15.png │ ├── tutorial16.png │ ├── tutorial17.png │ ├── tutorial18.png │ ├── tutorial19.png │ ├── tutorial2.png │ ├── tutorial20.png │ ├── tutorial21.png │ ├── tutorial22.png │ ├── tutorial3.png │ ├── tutorial4.png │ ├── tutorial5.png │ ├── tutorial6.png │ ├── tutorial7.png │ ├── tutorial8.png │ └── tutorial9.png ├── html ├── back.png ├── config.png ├── email.png ├── encode.js ├── encode.js.original ├── filtered.png ├── forms.js ├── index.html ├── nvme.png ├── page.png ├── pencil.png ├── plus.png ├── refresh.png ├── scripts.js ├── stylesheet.css ├── trash.png ├── unfiltered.png └── view.png ├── install-sh ├── latest.txt ├── missing ├── nvme-dem.spec.in ├── src ├── auto_connect │ ├── common.h │ └── daemon.c ├── cli │ ├── cli.c │ ├── show.c │ └── show.h ├── common │ ├── curl.c │ ├── logpages.c │ ├── nvmeof.c │ ├── parse.c │ ├── rdma.c │ └── tcp.c ├── dem │ ├── common.h │ ├── config.c │ ├── daemon.c │ ├── interfaces.c │ ├── json.c │ ├── json.h │ ├── logpages.c │ ├── pseudo_target.c │ └── restful.c ├── endpoint │ ├── common.h │ ├── configfs.c │ ├── daemon.c │ ├── etc_config.c │ ├── pseudo_target.c │ ├── restful.c │ └── spdk_config.c ├── incl │ ├── curl.h │ ├── dem.h │ ├── nvme.h │ ├── ops.h │ ├── tags.h │ ├── tcp.h │ └── utils.h └── monitor │ ├── common.h │ └── daemon.c ├── test ├── common.h ├── makefile ├── ops.h ├── rdma.c └── test.c └── usr ├── bash_completion.d └── dem-cli ├── man ├── dem-ac.8 ├── dem-cli.1 ├── dem-dm.1 ├── dem-em.8 └── dem.8 ├── nvmeof ├── nvmeof.conf └── nvmeof.service /.gitignore: -------------------------------------------------------------------------------- 1 | archive/ 2 | jansson/ 3 | mongoose/ 4 | .bin 5 | .config 6 | .signature 7 | libjansson.a 8 | .*.sw? 9 | *.vglog 10 | Makefile 11 | Makefile.in 12 | aclocal.m4 13 | autom4te.cache/ 14 | config.log 15 | config.status 16 | configure 17 | ut 18 | nvme-dem.spec 19 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Jay Sternberg 2 | Phil Cayton 3 | Rajalaxmi (Rajlaxmi) Angadi 4 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2018-09-05: migrate gitlab project to github 2 | 2018-11-15: add TCP transport 3 | 2018-11-29: add SPDK Target Endpoint Manager 4 | 2019-02-01: updated copyright 5 | 2019-04-22: add ability to create rpm packages 6 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | run the following (as root or not, it does not matter) 2 | 3 | $ ./autoconf.sh 4 | $ ./configure --prefix=/usr --sysconfdir=/etc 5 | $ make 6 | 7 | as root, run the following 8 | 9 | # make install 10 | 11 | to build packages run either of the following. note the prefix 12 | and sysconfdir options are not needed but are equivelant to the 13 | prior configure command. 14 | 15 | $ ./autoconf.sh 16 | $ ./configure 17 | $ make rpm 18 | $ make srpm 19 | 20 | the resulting packages will be in ~/rpmbuild/RPMS/x86_64 and 21 | ~/rpmbuild/SRPMS 22 | 23 | the default for prefix if not specified on the configure command 24 | is /usr/local. without specifying prefix, the sysconfdir default is 25 | /etc. if prefix is given, the sysconfdir is needed as the result 26 | without correcting it will be /usr/etc with is bad. 27 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | NVMe Distributed Endpoirt Management (DEM) Project Table of Contents: 2 | Project Components 3 | Endpoint Management Modes 4 | System Configuration 5 | Build and Installation 6 | Service Configuration 7 | Starting NVMe-oF Drivers 8 | Manually Starting - Endpoint Manger 9 | Manually Starting - DEM 10 | Manually Starting - Auto Connect 11 | Manually Starting - Discovery Monitor 12 | Configuration Methods 13 | 14 | 1. Project Components 15 | 16 | Distrubited Endpoint Manager (DEM) 17 | 18 | Primary component of DEM providing both a centralized Discovery 19 | controller and a management capabilities to configure Targets, 20 | May be used standalone or in concert with other DEM components. 21 | Purposes: 22 | 1. Collect and distribute discovery log pages 23 | 2. Configure remote NVMe resources via in-band or out-of-band 24 | interfaces 25 | 26 | Endpoint Manager (DEM-EM) 27 | Optional mechanism for In-band or out-of-band configuration of each 28 | Target used in concert with DEM 29 | 30 | Auto Connect (DEM-AC) 31 | Optional component to enable Hosts to connect to DEM and automatically 32 | connect to provisioned NVMe resources as defined by Discovery Log Pages 33 | 34 | Discovery Monitor (DEM-DM) 35 | Optional component to enable Hosts to monitor provisioned NVMe 36 | resources via DEM 37 | 38 | Command Line Interface (DEM-CLI) 39 | Mechanism to interface the DEM via console command line 40 | 41 | Web interface 42 | Mechanism to interface the DEM via HTML web interface 43 | 44 | 2. Endpoint Management Modes 45 | 46 | Local: 47 | The DEM does not configure individual Targets/Subsystems. Individual 48 | Targets must be locally configured. The DEM must be informed about 49 | Target Interfaces to connect to in order to query log-pages. 50 | Subsystems must be defined to associate log-pages for distribution. 51 | 52 | In-band: 53 | The DEM uses a designated NVMe-oF fabric interface to talk with Targets. 54 | The DEM is configured with all Individual Target Endpoint Manager (EM) 55 | interfaces to connect to. The DEM will then query Individual EM for 56 | physical fabric interface and NVMe device resources. The DEM 57 | Administrator has the ability to assign individual Target resources 58 | to NVMe-oF Port ID and Subsystems/Namespaces. 59 | 60 | Out-of-Band: 61 | The Out-of-Band management mode operates the same as In-band management 62 | mode however uses a RESTful interface to communicate with the EM. 63 | 64 | 3. System Configuration 65 | 66 | Kernel requirement: 67 | Minimum of 4.15 or Linux Distribution supporting NVMe-oF 68 | (e.g., RHEL 7.5, SUSE12 SP3) 69 | 70 | Download the kernel: 71 | $ git clone https://github.com/linux-nvme/nvme-dem.git 72 | 73 | Copy the existing /lib/modules/`uname -r`/source/.config to the downloaded 74 | kernel directory. 75 | 76 | Install the kernel 77 | 78 | Verify openssl-devel package present and installed. 79 | If not present, download and install 80 | 81 | Make 82 | Edit config file: 83 | ensure CONFIG_NVME_RDMA, CONFIG_NVME_FC, CONFIG_NVME_TARGET enabled. 84 | 85 | make and answer module questions for NVMe Target sub-modules 86 | $ make 87 | $ make modules_install 88 | $ sudo make install 89 | 90 | Ensure the system will boot to the new kernel 91 | 92 | # grep "^menuentry" /boot/grub2/grub.cfg | cut -d "'" -f2 93 | # grub2-set-default 94 | 95 | Boot the new kernel 96 | 97 | 4. Build and Installation 98 | 99 | Repository 100 | $ git clone https://gitlab.com/nvme-over-fabrics/nvme-dem.git 101 | 102 | Pulled as part of make (if not copied to mongoose/.git and jansson/.git) 103 | https://github.com/cesanta/mongoose.git 104 | https://github.com/akheron/jansson.git 105 | 106 | If target system is behind a head node and does not have access to the 107 | internet clone on a system with access, then build without installing then 108 | tar and copy tar file to remote system 109 | 110 | Libraries Required 111 | libcurl-devel librdmacm-devel libpthread-devel 112 | libuuid-devel libibverbs-devel 113 | 114 | Build and install 115 | $ ./autoconf.sh 116 | $ ./configure (optional flag: --enable-debug) 117 | $ make 118 | 119 | As root, run the following 120 | # make install 121 | 122 | Man pages for dem, dem-em, dem-ac, and dem-cli are available after install 123 | 124 | 5. Service Configuration 125 | 126 | Edit /etc/nvme/nvmeof.conf to enable appropriate component. 127 | Following is example for system as both RDMA Host and Target and using 128 | nullb0 for device and manually starting DEM 129 | 130 | PCI_HOST_LOAD=no 131 | NVMEOF_HOST_LOAD=yes 132 | RDMA_HOST_LOAD=yes 133 | FC_HOST_LOAD=no 134 | TCP_HOST_LOAD=no 135 | NVMEOF_TARGET_LOAD=yes 136 | RDMA_TARGET_LOAD=yes 137 | FC_TARGET_LOAD=no 138 | TCP_TARGET_LOAD=no 139 | NULL_BLK_TARGET_LOAD=yes 140 | START_DEM=no 141 | START_DEM_AC=no 142 | START_DEM_EM=no 143 | # DEM_AC_OPTS="-t rdma -f ipv4 -a 192.168.1.1 -s 4422" 144 | # DEM_EM_OPTS="-t rdma -f ipv4 -a 192.168.1.1 -s 22334" 145 | # DEM_EM_OPTS="-p 22345" 146 | 147 | 6. Starting NVMe-oF Drivers 148 | 149 | 1. Manually Start using nvmeof service 150 | 151 | # systemctl start nvmeof 152 | 153 | 2. Configure the system to start DEM on boot 154 | 155 | # chkconfig nvmeof on 156 | # reboot 157 | 158 | or 159 | 160 | # systemctl start nvmeof 161 | 162 | 3. If not running nvmeof service, load individual DEM drivers 163 | 164 | # modprobe configfs 165 | # modprobe nvme-rdma 166 | # modprobe nvmet-rdma 167 | # modprobe null-blk 168 | 169 | 7. Manually Starting - Endpoint Manager (dem-em) 170 | 171 | Optional mechanism for In-band or out-of-band configuration of each Target. 172 | Only needed if a systems administrator will be remotely managing remote 173 | NVMe resources. 174 | 175 | Configure fabric interface(s) the Endpoint Manager will report to the DEM 176 | (Discovery Controller). This is the fabric interface the DEM will use 177 | for NVMe-oF. This is done via files ifcfg-like files under 178 | /etc/nvme/nvmeof-dem (file ‘config’ and ‘signature’ are reserved). 179 | 180 | Example RDMA interface on IP-Address “192.168.22.1”. Note: The specification 181 | of a TRSVCID is an indication that the DEM should use this transport for 182 | Hosts to connect for retrieval of Discovery Log pages. The TRSVCID in the 183 | example below is not used by the Endpoint Manager - TRSVCID used by Target 184 | drivers are assigned by administrator through DEM configuration. This 185 | TRSVCID is only used by the DEM daemon. 186 | 187 | # Configuration file for RDMA interface 188 | TRTYPE=rdma 189 | ADRFAM=ipv4 190 | TRADDR=192.168.22.1 191 | TRSVCID=4422 # Service ID only used by DEM Discovery Controller 192 | 193 | Start Target Endpoint Manager specifying ‘management mode’. This is the 194 | mechanism the DEM will use to communicate to the DEM-EM. This is only 195 | used for configuration purposes. 196 | 197 | A. Out-of-Band management mode specifying RESTful interfaces on 198 | port 22334. 199 | 200 | # dem-em -p 22334 201 | 202 | B. In-Band management mode on rdma ipv4 address “192.168.22.1”. 203 | The Service ID is definable, but cannot be “4420” as this would 204 | conflict with the Target driver. 205 | 206 | # dem-em -t rdma -f ipv4 -a 192.168.22.1 -s 4433 207 | 208 | Starting either in-band or out-of-band DEM-EM reports enumerated devices 209 | and interfaces. 210 | 211 | If run in debug-mode the DEM-EM will not start as a daemon, and all output 212 | will be sent to stdout rather than to /var/log/… 213 | 214 | 8. Manually Starting - DEM Dicsovery Controller (dem) 215 | 216 | Configure fabric interface(s) for Host communication to DEM Discovery 217 | Controller. This is the fabric interface DEM listens on for Hosts to 218 | connect and request Discovery Log Pages. This is done via ifcfg-like 219 | files under /etc/nvme/nvmeof-dem (file ‘config’ and ‘signature’ are 220 | reserved). 221 | 222 | Example RDMA interface on IP-Address 192.168.22.2. If the TRSVCID is not 223 | present in a given configuration file, the default TRSVCID for that 224 | interface is the pre-assigned NVMe-oF ID "4420". 225 | 226 | Note 1: TRSVCID “4420” is the pre-assigned NVMe-oF ID and MAY ONLY be used 227 | if the DEM Discovery Controller is NOT co-located with an NVMe-oF Target 228 | driver. 229 | 230 | Note 2: If the DEM Discovery Controller and DEM Endpoint Manager are 231 | co-located configuration files will be used by both services to define 232 | interfaces used for communication with Hosts. 233 | 234 | # Configuration file for RDMA interface 235 | TRTYPE=rdma 236 | ADRFAM=ipv4 237 | TRADDR=192.168.22.2 238 | TRSVCID=4422 # Service ID only used by DEM Discovery Controller 239 | 240 | Starting DEM Discovery Controller specifying RESTful interfaces on a port. 241 | Default HTTP port is 22345 242 | # dem -p 243 | 244 | If run in debug-mode the DEM will not start as a daemon, and all output will 245 | be sent to stdout rather than to /var/log/… 246 | 247 | 9. Manually Starting - Auto Connect (dem-ac) 248 | 249 | Optional component to enable Hosts to connect to a Discovery controller 250 | (DEM or NVMe-oF Target) and automatically connect to provisioned NVMe 251 | resources as defined by Discovery Log Pages. 252 | 253 | Starting Auto Connect to address of the DEM Discovery Controller. 254 | 255 | # dem-ac -t rdma -f ipv4 -a 192.168.22.2 -s 4422 256 | 257 | Starting Auto Connect to address of an NVMe-oF Target Discovery Controller 258 | 259 | # dem-ac -t rdma -f ipv4 -a 192.168.22.200 -s 4420 260 | 261 | If run in debug-mode the DEM-AC will not start as a daemon, and all output 262 | will be sent to stdout rather than to /var/log/… 263 | 264 | 10. Manually Starting - Discovery Monitor (dem-dm) 265 | 266 | Optional component to enable Hosts to monitor a Discovery Controller 267 | (DEM or NVMe-oF Target) and report provisioned NVMe resources as defined 268 | by Discovery Log Pages. 269 | 270 | Starting Monitor and point it to the address of the DEM Discovery Controller. 271 | 272 | # dem-dm -t rdma -f ipv4 -a 192.168.22.2 -s 4422 273 | 274 | Starting Monitor and point it to the address of an NVMe-oF Target Discovery 275 | Controller. 276 | 277 | # dem-dm -t rdma -f ipv4 -a 192.168.22.200 -s 4420 278 | 279 | 11. Configuration Methods 280 | 281 | Web interface: Mechanism to interface with the DEM via HTTP web interface 282 | Default userid / password is 'dem' and 'nvmeof'. Web site may be remote 283 | from dem to allow bridge to lab networks 284 | 285 | Create subdirectory for DEM on the web hosting site and copy web files 286 | 287 | $ mkdir /var/www/html/dem 288 | $ cp html/* /var/www/html/dem 289 | 290 | Command Line Interface (DEM-CLI): Mechanism to interface with the DEM via 291 | console command line. dem-cli command on system running dem allows full 292 | configuration of targets and hosts Man page install and --help explains 293 | options 294 | 295 | cURL: Lowest-level mechanism to interface with the DEM. cURL may be used 296 | if you are willing to construct JSON objects Examples of cURL commands are 297 | in the Makefile 298 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nvme-dem -------------------------------------------------------------------------------- /autoconf.sh: -------------------------------------------------------------------------------- 1 | aclocal 2 | autoconf 3 | automake 4 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/compile -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(nvme-dem,1.0) 2 | AM_INIT_AUTOMAKE 3 | AC_OUTPUT(Makefile) 4 | 5 | AC_CHECK_LIB([curl], [curl_easy_init], [], 6 | [AC_MSG_ERROR(Install libcurl-devel)]) 7 | AC_CHECK_LIB([rdmacm], [rdma_create_id], [], 8 | [AC_MSG_ERROR(Install librdmacm-devel)]) 9 | AC_CHECK_LIB([ibverbs], [ibv_create_cq], [], 10 | [AC_MSG_ERROR(Install libibverbs-devel)]) 11 | AC_CHECK_LIB([pthread], [pthread_create], [], 12 | [AC_MSG_ERROR(Install libpthread-devel)]) 13 | 14 | AC_CHECK_FILE([/usr/bin/libtool], [], 15 | [AC_MSG_ERROR(Install libtool)]) 16 | 17 | AC_ARG_ENABLE(debug, 18 | AS_HELP_STRING([--enable-debug],[Turn on debugging]), 19 | [case "${enableval}" in 20 | yes) debug=true ;; 21 | no) debug=false ;; 22 | *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; 23 | esac],[debug=false]) 24 | AM_CONDITIONAL(DEBUG, test x$debug = xtrue) 25 | 26 | AC_ARG_ENABLE(nvmeof-tracing, 27 | AS_HELP_STRING([--enable-nvmeof-tracing],[Turn on tracing nvme-of commands]), 28 | [case "${enableval}" in 29 | yes) nvmeof_tracing=true ;; 30 | no) nvmeof_tracing=false ;; 31 | *) AC_MSG_ERROR(bad value ${enableval} for --enable-nvmeof-tracing) ;; 32 | esac],[nvmeof_tracing=false]) 33 | AM_CONDITIONAL(NVMEOF_TRACING, test x$nvmeof_tracing = xtrue) 34 | 35 | AC_ARG_ENABLE(extra-security-cflags, 36 | AS_HELP_STRING([--enable-extra-security-cflags], 37 | [Turn on extra_security_cflags]), 38 | [case "${enableval}" in 39 | yes) extra_security_cflags=true ;; 40 | no) extra_security_cflags=false ;; 41 | *) AC_MSG_ERROR(bad value ${enableval} for --enable-extra-security-cflags) 42 | ;; 43 | esac],[extra_security_cflags=false]) 44 | AM_CONDITIONAL(EXTRA_SECURITY_CFLAGS, test x$extra_security_cflags = xtrue) 45 | 46 | AC_ARG_WITH(spdk, AS_HELP_STRING([--with-spdk], 47 | [enable endpoint manager to support spdk target])) 48 | 49 | AC_ARG_WITH(configfs, AS_HELP_STRING([--with-configfs], 50 | [enable endpoint manager to support in-kernel target]), 51 | [], [with_configfs=yes]) 52 | 53 | AM_CONDITIONAL(SPDK, test x$with_spdk = xyes) 54 | AM_CONDITIONAL(CONFIGFS, test x$with_configfs = xyes) 55 | 56 | AM_CONDITIONAL([LOCAL_PREFIX], [test "${prefix##*/}" == "local"]) 57 | 58 | AS_IF(test x$with_spdk = xyes, [ 59 | AC_CHECK_FILE([/usr/lib/libspdk.so], [], 60 | [AC_MSG_ERROR(Install spdk)]) 61 | AC_CHECK_FILE([/usr/lib/libspdk_rpc.so], [], 62 | [AC_MSG_ERROR(Install spdk --with-rdma)]) 63 | AC_CHECK_FILE([/usr/lib/libdpdk.a], [], 64 | [AC_MSG_ERROR(Install dpdk)]) 65 | AC_CHECK_FILE([/usr/lib64/libpciaccess.so], [], 66 | AC_CHECK_FILE([/usr/lib64/libpciaccess.so], [], 67 | [AC_MSG_ERROR(Install libpciaccess)])) 68 | ]) 69 | 70 | AS_IF(test x$with_configfs = xyes, [], AS_IF(test x$with_spdk = xyes, [], 71 | [AC_MSG_ERROR(Must provide --with-configfs and/or --with-spdk)])) 72 | 73 | AC_MSG_CHECKING([for picky compilers - unused fopen return values]) 74 | AC_LANG_WERROR 75 | AC_COMPILE_IFELSE([ 76 | AC_LANG_PROGRAM([[#include ]], 77 | [[freopen("/dev/null", "w+", stdout); ]])], 78 | [AC_MSG_RESULT([no])], 79 | [AC_MSG_RESULT([yes]) 80 | picky_compiler_fopen="yes"]) 81 | AM_CONDITIONAL(PICKY_COMPILER_FOPEN, test x$picky_compiler_fopen = xyes) 82 | 83 | AC_MSG_CHECKING([for picky compilers - sprintf overflow/truncate]) 84 | AC_LANG_WERROR 85 | AC_COMPILE_IFELSE([ 86 | AC_LANG_PROGRAM([[#include ]], 87 | [[ char x[4]; sprintf(x, "%s", "12345678"); ]])], 88 | [AC_MSG_RESULT([no])], 89 | [AC_MSG_RESULT([yes]) 90 | picky_compiler_sprintf="yes"]) 91 | AM_CONDITIONAL(PICKY_COMPILER_SPRINTF, test x$picky_compiler_sprintf = xyes) 92 | 93 | AC_CONFIG_FILES([nvme-dem.spec]) 94 | AC_OUTPUT 95 | -------------------------------------------------------------------------------- /files/Licenses: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/Licenses -------------------------------------------------------------------------------- /files/gdb.in: -------------------------------------------------------------------------------- 1 | set args -t rdma -f ipv4 -a 192.168.22.2 -s 44222 2 | 3 | handle SIGTERM nostop noprint 4 | l init_listener 5 | b 243 6 | r 7 | -------------------------------------------------------------------------------- /files/json.schemas/dem-dc_config-file_json-schema: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema.v1_2_0.json", 3 | "title": "#NVMe_of.DEM", 4 | "definitions": { 5 | "MgmtMode": { 6 | "enum": [ 7 | "localmgmt", 8 | "LocalMgmt", 9 | "LOCALMGMT", 10 | "outofbandmgmt", 11 | "OutOfBandMgmt", 12 | "OUTOFBANDMGMT", 13 | "inbandmgmt", 14 | "InBandMgmt", 15 | "INBANDMGMT" 16 | ] 17 | }, 18 | "TransportType": { 19 | "enum": [ 20 | "rdma", 21 | "Rdma", 22 | "RDMA", 23 | "fc", 24 | "FC", 25 | "tcp", 26 | "TCP" 27 | ] 28 | }, 29 | "AddressType": { 30 | "enum": [ 31 | "IPv4", 32 | "ipv4", 33 | "IPV4", 34 | "IPv6", 35 | "ipv6", 36 | "IPV6", 37 | "FC", 38 | "fc" 39 | ] 40 | }, 41 | "Address": { 42 | "type": "string", 43 | "pattern": "^(((([0-9]{1,2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])[.]){3}(([0-9]{1,2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])))|(([0-9a-fA-F]{0,4}[:]){5}[0-9a-fA-F]{0,4})|(([0-9a-fA-F]{2}[:]){7}[0-9a-fA-F]{2}))$", 44 | "description": "pattern only allows proper IPv4, IPv6, FC addresses" 45 | }, 46 | "PortID": { 47 | "type": "object", 48 | "additionalProperties": false, 49 | "properties": { 50 | "PORTID": { 51 | "type": "integer" 52 | }, 53 | "TRTYPE": { 54 | "$ref": "#/definitions/TransportType" 55 | }, 56 | "ADRFAM": { 57 | "$ref": "#/definitions/AddressType" 58 | }, 59 | "TREQ": { 60 | "type": "integer" 61 | }, 62 | "TRADDR": { 63 | "$ref": "#/definitions/Address" 64 | }, 65 | "TRSVCID": { 66 | "type": "integer" 67 | } 68 | } 69 | }, 70 | "InBandInterface": { 71 | "type": "object", 72 | "additionalProperties": false, 73 | "properties": { 74 | "TRTYPE": { 75 | "$ref": "#/definitions/TransportType" 76 | }, 77 | "ADRFAM": { 78 | "$ref": "#/definitions/AddressType" 79 | }, 80 | "TRADDR": { 81 | "$ref": "#/definitions/Address" 82 | }, 83 | "TRSVCID": { 84 | "type": "integer" 85 | } 86 | } 87 | }, 88 | "OutOfBandInterface": { 89 | "type": "object", 90 | "additionalProperties": false, 91 | "properties": { 92 | "FAMILY": { 93 | "$ref": "#/definitions/AddressType" 94 | }, 95 | "ADDRESS": { 96 | "$ref": "#/definitions/Address" 97 | }, 98 | "PORT": { 99 | "type": "integer" 100 | } 101 | } 102 | }, 103 | "Interface": { 104 | "type": "object", 105 | "additionalProperties": false, 106 | "properties": { 107 | "TRTYPE": { 108 | "$ref": "#/definitions/TransportType" 109 | }, 110 | "ADRFAM": { 111 | "$ref": "#/definitions/AddressType" 112 | }, 113 | "TRADDR": { 114 | "$ref": "#/definitions/Address" 115 | } 116 | } 117 | }, 118 | "NVMeDrive": { 119 | "additionalProperties": false, 120 | "properties": { 121 | "DeviceID": { 122 | "type": "integer" 123 | }, 124 | "NSID": { 125 | "type": "integer" 126 | }, 127 | "DeviceNSID": { 128 | "type": "integer" 129 | } 130 | } 131 | }, 132 | "NQN": { 133 | "type": "string", 134 | "pattern": "^[-.0-9a-zA-Z_:@+]{6,128}$" 135 | }, 136 | "Interfaces": { 137 | "type": "array", 138 | "additionalItems": { 139 | "$ref": "#/definitions/Interface" 140 | }, 141 | "items": [ 142 | { 143 | "$ref": "#/definitions/Interface" 144 | } 145 | ] 146 | }, 147 | "Host": { 148 | "additionalProperties": false, 149 | "properties": { 150 | "Alias": { 151 | "$ref": "http://redfish.dmtf.org/schemas/v1/Resource.json#/definitions/Name" 152 | }, 153 | "HOSTNQN": { 154 | "$ref": "#/definitions/NQN" 155 | } 156 | } 157 | }, 158 | "Subsystem": { 159 | "type": "object", 160 | "additionalProperties": false, 161 | "properties": { 162 | "SUBNQN": { 163 | "$ref": "#/definitions/NQN" 164 | }, 165 | "AllowAnyHost": { 166 | "type": "integer" 167 | }, 168 | "NSIDs": { 169 | "type": "array", 170 | "additionalItems": { 171 | "$ref": "#/definitions/NVMeDrive" 172 | }, 173 | "items": [ 174 | { 175 | "$ref": "#/definitions/NVMeDrive" 176 | } 177 | ] 178 | }, 179 | "Interfaces": { 180 | "type": "array", 181 | "additionalItems": { 182 | "$ref": "#/definitions/Interface" 183 | }, 184 | "items": [ 185 | { 186 | "$ref": "#/definitions/Interface" 187 | } 188 | ] 189 | }, 190 | "Hosts": { 191 | "type": "array", 192 | "additionalItems": { 193 | "$ref": "http://redfish.dmtf.org/schemas/v1/Resource.json#/definitions/Name" 194 | }, 195 | "items": [ 196 | { 197 | "$ref": "http://redfish.dmtf.org/schemas/v1/Resource.json#/definitions/Name" 198 | } 199 | ] 200 | } 201 | } 202 | }, 203 | "Target": { 204 | "type": "object", 205 | "additionalProperties": false, 206 | "properties": { 207 | "Alias": { 208 | "type": "string" 209 | }, 210 | "Refresh": { 211 | "type": "integer" 212 | }, 213 | "PortIDs": { 214 | "type": "array", 215 | "additionalItems": { 216 | "$ref": "#/definitions/PortID" 217 | }, 218 | "items": [ 219 | { 220 | "$ref": "#/definitions/PortID" 221 | } 222 | ] 223 | }, 224 | "Subsystems": { 225 | "type": "array", 226 | "additionalItems": { 227 | "$ref": "#/definitions/Subsystem" 228 | }, 229 | "items": [ 230 | { 231 | "$ref": "#/definitions/Subsystem" 232 | } 233 | ] 234 | }, 235 | "NSDevices": { 236 | "type": "array", 237 | "additionalItems": { 238 | "$ref": "#/definitions/NVMeDrive" 239 | }, 240 | "items": [ 241 | { 242 | "$ref": "#/definitions/NVMeDrive" 243 | } 244 | ] 245 | }, 246 | "Interfaces": { 247 | "type": "array", 248 | "additionalItems": { 249 | "$ref": "#/definitions/Interface" 250 | }, 251 | "items": [ 252 | { 253 | "$ref": "#/definitions/Interface" 254 | } 255 | ] 256 | }, 257 | "MgmtMode": { 258 | "$ref": "#/definitions/MgmtMode" 259 | }, 260 | "Interface": { 261 | "oneOf": [ 262 | { 263 | "$ref": "#/definitions/OutOfBandInterface" 264 | }, 265 | { 266 | "$ref": "#/definitions/InBandInterface" 267 | } 268 | ] 269 | } 270 | } 271 | }, 272 | "Group": { 273 | "type": "object", 274 | "additionalProperties": false, 275 | "properties": { 276 | "Name": { 277 | "$ref": "http://redfish.dmtf.org/schemas/v1/Resource.json#/definitions/Name" 278 | }, 279 | "Hosts": { 280 | "type": "array", 281 | "items": { 282 | "$ref": "http://redfish.dmtf.org/schemas/v1/Resource.json#/definitions/Name" 283 | } 284 | }, 285 | "Targets": { 286 | "type": "array", 287 | "items": { 288 | "$ref": "http://redfish.dmtf.org/schemas/v1/Resource.json#/definitions/Name" 289 | } 290 | } 291 | } 292 | }, 293 | "Hosts": { 294 | "type": "array", 295 | "additionalItems": { 296 | "$ref": "#/definitions/Host" 297 | }, 298 | "items": [ 299 | { 300 | "$ref": "#/definitions/Host" 301 | } 302 | ] 303 | }, 304 | "Targets": { 305 | "type": "array", 306 | "additionalItems": { 307 | "$ref": "#/definitions/Target" 308 | }, 309 | "items": [ 310 | { 311 | "$ref": "#/definitions/Target" 312 | } 313 | ] 314 | }, 315 | "Groups": { 316 | "type": "array", 317 | "additionalItems": { 318 | "$ref": "#/definitions/Group" 319 | }, 320 | "items": [ 321 | { 322 | "$ref": "#/definitions/Group" 323 | } 324 | ] 325 | } 326 | }, 327 | "additionalProperties": false, 328 | "properties": { 329 | "Groups": { 330 | "$ref": "#/definitions/Groups" 331 | }, 332 | "Hosts": { 333 | "$ref": "#/definitions/Hosts" 334 | }, 335 | "Targets": { 336 | "$ref": "#/definitions/Targets" 337 | } 338 | }, 339 | "copyright": "Copyright 2017-2019 Intel Corporation Dual BSD/GPLv2" 340 | } 341 | -------------------------------------------------------------------------------- /files/json.schemas/dem-dc_http-only_commands: -------------------------------------------------------------------------------- 1 | POST /target/tgt_host01/reconfig 2 | -------------------------------------------------------------------------------- /files/json.schemas/dem-ec_curl_trace.log: -------------------------------------------------------------------------------- 1 | handle_http_request(716) GET /nsdev 2 | handle_http_request(716) GET /interface 3 | handle_http_request(716) DELETE /target 4 | handle_http_request(716) POST /portid/1 5 | handle_http_request(719) 6 | {"TRTYPE":"rdma","ADRFAM":"ipv4","TRADDR":"192.168.22.1","TRSVCID":4420} 7 | handle_http_request(716) POST /portid/2 8 | handle_http_request(719) 9 | {"TRTYPE":"tcp","ADRFAM":"ipv4","TRADDR":"192.168.22.1","TRSVCID":4430} 10 | handle_http_request(716) POST /subsystem 11 | handle_http_request(719) {"SUBNQN":"host01subsys1","AllowAnyHost":1} 12 | handle_http_request(716) POST /subsystem/host01subsys1/namespace 13 | handle_http_request(719) {"NSID":1,"DeviceID":0,"DeviceNSID":1} 14 | handle_http_request(716) POST /subsystem/host01subsys1/portid 15 | handle_http_request(719) {"PORTID":1} 16 | handle_http_request(716) POST /subsystem/host01subsys1/portid 17 | handle_http_request(719) {"PORTID":2} 18 | handle_http_request(716) POST /subsystem 19 | handle_http_request(719) {"SUBNQN":"host01subsys2","AllowAnyHost":0} 20 | handle_http_request(716) POST /subsystem/host01subsys2/namespace 21 | handle_http_request(719) {"NSID":2,"DeviceID":-1,"DeviceNSID":0} 22 | handle_http_request(716) POST /host 23 | handle_http_request(719) {"HOSTNQN":"host02nqn"} 24 | handle_http_request(716) POST /subsystem/host01subsys2/host 25 | handle_http_request(719) {"HOSTNQN":"host02nqn"} 26 | handle_http_request(716) POST /subsystem/host01subsys2/portid 27 | handle_http_request(719) {"PORTID":1} 28 | handle_http_request(716) POST /subsystem/host01subsys2/portid 29 | handle_http_request(719) {"PORTID":2} 30 | handle_http_request(716) POST /subsystem 31 | handle_http_request(719) {"SUBNQN":"host01subsys3","AllowAnyHost":1} 32 | handle_http_request(716) POST /subsystem/host01subsys3/namespace 33 | handle_http_request(719) {"NSID":1,"DeviceID":-1,"DeviceNSID":0} 34 | handle_http_request(716) POST /subsystem/host01subsys3/portid 35 | handle_http_request(719) {"PORTID":1} 36 | handle_http_request(716) POST /subsystem/host01subsys3/portid 37 | handle_http_request(719) {"PORTID":2} 38 | 39 | -------------------------------------------------------------------------------- /files/json.schemas/dem_cli_curl_trace.log: -------------------------------------------------------------------------------- 1 | ------------------------ 2 | dem config 3 | ------------------------ 4 | GET http://127.0.0.1:22345/dem 5 | {"Interfaces":[{"ID":0,"TRTYPE":"rdma","ADRFAM":"ipv4","TRADDR":"192.168.22.2","TRSVCID":"4422"}]} 6 | ------------------------ 7 | dem list group 8 | ------------------------ 9 | GET http://127.0.0.1:22345/group 10 | {"Groups":[]} 11 | ------------------------ 12 | dem add group g1 13 | ------------------------ 14 | POST http://127.0.0.1:22345/group/g1 15 | Group 'g1' added 16 | ------------------------ 17 | dem set group g2 18 | ------------------------ 19 | PUT http://127.0.0.1:22345/group 20 | << {"Name":"g2"} >> 21 | Group 'g2' added 22 | ------------------------ 23 | dem list group 24 | ------------------------ 25 | GET http://127.0.0.1:22345/group 26 | {"Groups":["g1","g2"]} 27 | ------------------------ 28 | dem get group g1 29 | ------------------------ 30 | GET http://127.0.0.1:22345/group/g1 31 | {"Name": "g1", "Targets": [], "Hosts": []} 32 | ------------------------ 33 | dem delete group g1 34 | ------------------------ 35 | DELETE http://127.0.0.1:22345/group/g1 36 | Group 'g1' deleted 37 | ------------------------ 38 | dem rename group g2 g1 39 | ------------------------ 40 | PATCH http://127.0.0.1:22345/group/g2 41 | << {"Name":"g1" } >> 42 | Group 'g1' updated 43 | ------------------------ 44 | dem add target t1 45 | ------------------------ 46 | POST http://127.0.0.1:22345/target/t1 47 | Target 't1' added 48 | ------------------------ 49 | dem set target t2 50 | ------------------------ 51 | PUT http://127.0.0.1:22345/target 52 | << {"Alias":"t2"} >> 53 | Target 't2' added 54 | ------------------------ 55 | dem list target 56 | ------------------------ 57 | GET http://127.0.0.1:22345/target 58 | {"Targets":["t1","t2"]} 59 | ------------------------ 60 | dem get target t1 61 | ------------------------ 62 | GET http://127.0.0.1:22345/target/t1 63 | {"Alias": "t1", "PortIDs": [], "Subsystems": []} 64 | ------------------------ 65 | dem delete target t1 66 | ------------------------ 67 | DELETE http://127.0.0.1:22345/target/t1 68 | Target 't1' deleted 69 | ------------------------ 70 | dem rename target t2 t1 71 | ------------------------ 72 | PATCH http://127.0.0.1:22345/target/t2 73 | << {"Alias":"t1"} >> 74 | Target 't1' updated 75 | ------------------------ 76 | dem set mode t1 local 77 | ------------------------ 78 | PATCH http://127.0.0.1:22345/target/t1 79 | << {"MgmtMode":"LocalMgmt"} >> 80 | Target 't1' updated 81 | ------------------------ 82 | dem set interface t1 ipv4 1.1.1.1 4422 83 | ------------------------ 84 | PATCH http://127.0.0.1:22345/target/t1 85 | << {"Interface":{"FAMILY":"ipv4","ADDRESS":"1.1.1.1","PORT":4422}} >> 86 | Target 't1' updated 87 | ------------------------ 88 | dem set refresh t1 0 89 | ------------------------ 90 | PATCH http://127.0.0.1:22345/target/t1 91 | << {"Refresh":0} >> 92 | Target 't1' updated 93 | ------------------------ 94 | dem refresh target t1 95 | ------------------------ 96 | POST http://127.0.0.1:22345/target/t1/refresh 97 | Target 't1' refreshed 98 | ------------------------ 99 | dem link target t1 g1 100 | ------------------------ 101 | POST http://127.0.0.1:22345/group/g1/target/t1 102 | Group 'g1' updated 103 | ------------------------ 104 | dem get group g1 105 | ------------------------ 106 | GET http://127.0.0.1:22345/group/g1 107 | {"Name": "g1", "Hosts": [], "Targets": ["t1"]} 108 | ------------------------ 109 | dem unlink target t1 g1 110 | ------------------------ 111 | DELETE http://127.0.0.1:22345/group/g1/target/t1 112 | Group 'g1' updated 113 | ------------------------ 114 | dem add subsystem t1 subsys2 115 | ------------------------ 116 | POST http://127.0.0.1:22345/target/t1/subsystem/subsys2 117 | Subsystem 'subsys2' added to in Target 't1' 118 | ------------------------ 119 | dem set subsystem t1 subsys1 0 120 | ------------------------ 121 | PUT http://127.0.0.1:22345/target/t1/subsystem 122 | << {"SUBNQN":"subsys1","AllowAnyHost":0} >> 123 | Subsystem 'subsys1' added to in Target 't1' 124 | ------------------------ 125 | dem edit subsystem t1 subsys1 0 126 | ------------------------ 127 | PUT http://127.0.0.1:22345/target/t1/subsystem/subsys1 128 | << {"AllowAnyHost":0} >> 129 | Subsystem 'subsys1' updated in in Target 't1' 130 | ------------------------ 131 | dem delete subsystem t1 subsys1 132 | ------------------------ 133 | DELETE http://127.0.0.1:22345/target/t1/subsystem/subsys1 134 | Subsystem 'subsys1' deleted from Target 't1' 135 | ------------------------ 136 | dem rename subsystem t1 subsys2 subsys1 137 | ------------------------ 138 | PATCH http://127.0.0.1:22345/target/t1/subsystem/subsys2 139 | << {"SUBNQN":"subsys1"} >> 140 | Subsystem 'subsys2' updated in in Target 't1' 141 | ------------------------ 142 | dem set portid t1 1 rdma ipv4 1.1.1.1 4420 143 | ------------------------ 144 | PUT http://127.0.0.1:22345/target/t1/portid 145 | << {"PORTID":1,"TRTYPE":"rdma","ADRFAM":"ipv4","TRADDR":"1.1.1.1","TRSVCID":4420} >> 146 | PORTID '1' updated in Target 't1' 147 | ------------------------ 148 | dem edit portid t1 1 rdma ipv4 1.1.1.1 4420 149 | ------------------------ 150 | PUT http://127.0.0.1:22345/target/t1/portid/1 151 | << {"TRTYPE":"rdma","ADRFAM":"ipv4","TRADDR":"1.1.1.1","TRSVCID":4420} >> 152 | PORTID '1' updated in Target 't1' 153 | ------------------------ 154 | dem delete portid t1 1 155 | ------------------------ 156 | DELETE http://127.0.0.1:22345/target/t1/portid/1 157 | PORTID '1' deleted from Target 't1' 158 | ------------------------ 159 | dem set portid t1 1 rdma ipv4 1.1.1.1 4420 160 | ------------------------ 161 | PUT http://127.0.0.1:22345/target/t1/portid 162 | << {"PORTID":1,"TRTYPE":"rdma","ADRFAM":"ipv4","TRADDR":"1.1.1.1","TRSVCID":4420} >> 163 | PORTID '1' updated in Target 't1' 164 | ------------------------ 165 | dem set host h1 hostnqn 166 | ------------------------ 167 | PUT http://127.0.0.1:22345/host 168 | << {"Alias":"h1","HOSTNQN":"hostnqn"} >> 169 | Host 'h1' added 170 | ------------------------ 171 | dem set acl t1 subsys1 h1 172 | ------------------------ 173 | PUT http://127.0.0.1:22345/target/t1/subsystem/subsys1/host 174 | << {"Alias":"h1"} >> 175 | Host 'h1' added for Subsystem 'subsys1' in Target 't1' 176 | ------------------------ 177 | dem delete acl t1 subsys1 h1 178 | ------------------------ 179 | DELETE http://127.0.0.1:22345/target/t1/subsystem/subsys1/host/h1 180 | Host 'h1' deleted from Subsystem 'subsys1' for Alias 't1' 181 | ------------------------ 182 | dem delete host h1 183 | ------------------------ 184 | DELETE http://127.0.0.1:22345/host/h1 185 | Host 'h1' deleted 186 | ------------------------ 187 | dem set ns t1 subsys1 1 nullb0 0 188 | ------------------------ 189 | PUT http://127.0.0.1:22345/target/t1/subsystem/subsys1/nsid 190 | << {"NSID":1,"DeviceID":-1,"DeviceNSID":0} >> 191 | NSID 1 updated in Subsystem 'subsys1' of Target 't1' 192 | ------------------------ 193 | dem get target t1 194 | ------------------------ 195 | GET http://127.0.0.1:22345/target/t1 196 | {"Alias": "t1", "PortIDs": [{"PORTID": 1, "TRTYPE": "rdma", "TRADDR": "1.1.1.1", "ADRFAM": "ipv4", "TRSVCID": 4420}], "Subsystems": [{"SUBNQN": "subsys1", "AllowAnyHost": 1, "Hosts": [], "NSIDs": [{"NSID": 1, "DeviceID": -1, "DeviceNSID": 0}]}], "MgmtMode": "LocalMgmt", "Refresh": 0} 197 | ------------------------ 198 | dem delete ns t1 subsys1 1 199 | ------------------------ 200 | DELETE http://127.0.0.1:22345/target/t1/subsystem/subsys1/nsid/1 201 | NSID '1' deleted from Subsystem 'subsys1' in Target 't1' 202 | ------------------------ 203 | dem add host h1 204 | ------------------------ 205 | POST http://127.0.0.1:22345/host/h1 206 | Host 'h1' added 207 | ------------------------ 208 | dem list host 209 | ------------------------ 210 | GET http://127.0.0.1:22345/host 211 | {"Hosts":["h1"]} 212 | ------------------------ 213 | dem get host h1 214 | ------------------------ 215 | GET http://127.0.0.1:22345/host/h1 216 | {"Alias": "h1", "Shared": [{"Alias": "t1", "SUBNQN": "subsys1"}], "Restricted": []} 217 | ------------------------ 218 | dem set host h2 hostnqn 219 | ------------------------ 220 | PUT http://127.0.0.1:22345/host 221 | << {"Alias":"h2","HOSTNQN":"hostnqn"} >> 222 | Host 'h2' added 223 | ------------------------ 224 | dem edit host h2 hostnqn 225 | ------------------------ 226 | PUT http://127.0.0.1:22345/host/h2 227 | << {"HOSTNQN":"hostnqn"} >> 228 | Host 'h2' updated 229 | ------------------------ 230 | dem get host h1 231 | ------------------------ 232 | GET http://127.0.0.1:22345/host/h1 233 | {"Alias": "h1", "Shared": [{"Alias": "t1", "SUBNQN": "subsys1"}], "Restricted": []} 234 | ------------------------ 235 | dem delete host h1 236 | ------------------------ 237 | DELETE http://127.0.0.1:22345/host/h1 238 | Host 'h1' deleted 239 | ------------------------ 240 | dem rename host h2 h1 241 | ------------------------ 242 | PATCH http://127.0.0.1:22345/host/h2 243 | << {"Alias":"h1"} >> 244 | Host 'h1' updated 245 | ------------------------ 246 | dem link host h1 g1 247 | ------------------------ 248 | POST http://127.0.0.1:22345/group/g1/host/h1 249 | Group 'g1' updated 250 | ------------------------ 251 | dem get group g1 252 | ------------------------ 253 | GET http://127.0.0.1:22345/group/g1 254 | {"Name": "g1", "Hosts": ["h1"], "Targets": []} 255 | ------------------------ 256 | dem unlink host h1 g1 257 | ------------------------ 258 | DELETE http://127.0.0.1:22345/group/g1/host/h1 259 | Group 'g1' updated 260 | ------------------------ 261 | dem shutdown 262 | ------------------------ 263 | POST http://127.0.0.1:22345/dem/shutdown 264 | DEM Discovery controller shutting down 265 | -------------------------------------------------------------------------------- /files/json.schemas/dem_cli_curl_trace.sh: -------------------------------------------------------------------------------- 1 | exec_dem() { 2 | echo dem $* 3 | echo "------------------------" >>dem_cli_curl_trace.log 4 | echo dem $* >>dem_cli_curl_trace.log 5 | echo "------------------------" >>dem_cli_curl_trace.log 6 | dem -rcf $* >>dem_cli_curl_trace.log 7 | } 8 | echo -n >dem_cli_curl_trace.log 9 | 10 | exec_dem config 11 | exec_dem list group 12 | exec_dem add group g1 13 | exec_dem set group g2 14 | exec_dem list group 15 | exec_dem get group g1 16 | exec_dem delete group g1 17 | exec_dem rename group g2 g1 18 | exec_dem add target t1 19 | exec_dem set target t2 20 | exec_dem list target 21 | exec_dem get target t1 22 | exec_dem delete target t1 23 | exec_dem rename target t2 t1 24 | exec_dem set mode t1 local 25 | exec_dem set interface t1 ipv4 1.1.1.1 4422 26 | exec_dem set refresh t1 0 27 | exec_dem refresh target t1 28 | exec_dem link target t1 g1 29 | exec_dem get group g1 30 | exec_dem unlink target t1 g1 31 | exec_dem add subsystem t1 subsys2 32 | exec_dem set subsystem t1 subsys1 0 33 | exec_dem edit subsystem t1 subsys1 0 34 | exec_dem delete subsystem t1 subsys1 35 | exec_dem rename subsystem t1 subsys2 subsys1 36 | exec_dem set portid t1 1 rdma ipv4 1.1.1.1 4420 37 | exec_dem edit portid t1 1 rdma ipv4 1.1.1.1 4420 38 | exec_dem delete portid t1 1 39 | exec_dem set portid t1 1 rdma ipv4 1.1.1.1 4420 40 | exec_dem set host h1 hostnqn 41 | exec_dem set acl t1 subsys1 h1 42 | exec_dem delete acl t1 subsys1 h1 43 | exec_dem delete host h1 44 | exec_dem set ns t1 subsys1 1 nullb0 0 45 | exec_dem get target t1 46 | exec_dem delete ns t1 subsys1 1 47 | exec_dem add host h1 48 | exec_dem list host 49 | exec_dem get host h1 50 | exec_dem set host h2 hostnqn 51 | exec_dem edit host h2 hostnqn 52 | exec_dem get host h1 53 | exec_dem delete host h1 54 | exec_dem rename host h2 h1 55 | exec_dem link host h1 g1 56 | exec_dem get group g1 57 | exec_dem unlink host h1 g1 58 | exec_dem shutdown 59 | -------------------------------------------------------------------------------- /files/mongoose.c: -------------------------------------------------------------------------------- 1 | /* 2 | * stub mongoose functions used to remove real code for klocwork scans 3 | */ 4 | 5 | #include 6 | #include 7 | #include "mongoose.h" 8 | #include "common.h" 9 | 10 | struct mg_connection; 11 | 12 | time_t mg_mgr_poll(struct mg_mgr *mgr, int milli) 13 | { 14 | UNUSED(mgr); 15 | UNUSED(milli); 16 | 17 | return (time_t) 0; 18 | } 19 | 20 | void mg_mgr_free(struct mg_mgr *mgr) 21 | { 22 | UNUSED(mgr); 23 | } 24 | 25 | void mg_mgr_init(struct mg_mgr *mgr, void *user_data) 26 | { 27 | UNUSED(mgr); 28 | UNUSED(user_data); 29 | } 30 | 31 | struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, 32 | mg_event_handler_t handler, 33 | struct mg_bind_opts opts) 34 | { 35 | UNUSED(mgr); 36 | UNUSED(address); 37 | UNUSED(handler); 38 | UNUSED(opts); 39 | 40 | return NULL; 41 | } 42 | 43 | void mg_set_protocol_http_websocket(struct mg_connection *nc) 44 | { 45 | UNUSED(nc); 46 | } 47 | 48 | int mg_printf(struct mg_connection *mgr, const char *fmt, ...) 49 | { 50 | UNUSED(mgr); 51 | UNUSED(fmt); 52 | 53 | return 0; 54 | } 55 | 56 | struct mg_str mg_mk_str_n(const char *s, size_t len) 57 | { 58 | const struct mg_str mg_static_str = { 0 }; 59 | UNUSED(s); 60 | UNUSED(len); 61 | return mg_static_str; 62 | } 63 | 64 | int mg_vcmp(const struct mg_str *str2, const char *str1) 65 | { 66 | UNUSED(str1); 67 | UNUSED(str2); 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /files/spdk_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin//bash 2 | 3 | if [ ! -e spdk/.git ] ; then 4 | git clone https://github.com/spdk/dpdk.git 5 | fi 6 | 7 | cd dpdk 8 | 9 | make defconfig 10 | make 11 | sudo make install prefix=/usr 12 | 13 | cd .. 14 | 15 | if [ ! -e spdk/.git ] ; then 16 | git clone https://github.com/spdk/spdk.git 17 | fi 18 | 19 | cd spdk 20 | 21 | ./configure --enable-debug --with-rdma --with-shared \ 22 | --with-dpdk=/usr --disable-tests --prefix=/usr 23 | make 24 | sudo make install 25 | 26 | sudo ldconfig 27 | -------------------------------------------------------------------------------- /files/valgrind_suppress: -------------------------------------------------------------------------------- 1 | # dl-open suppressions 2 | 3 | { 4 | Skip unwind->_dl_open-_dl_check_map_versions-calloc 5 | Memcheck:Leak 6 | match-leak-kinds: reachable 7 | fun:calloc 8 | fun:_dl_check_map_versions 9 | fun:dl_open_worker 10 | fun:_dl_catch_error 11 | fun:_dl_open 12 | fun:dlopen_doit 13 | fun:_dl_catch_error 14 | fun:_dlerror_run 15 | fun:dlopen@@GLIBC_2.2.5 16 | fun:??? 17 | fun:??? 18 | fun:??? 19 | } 20 | 21 | { 22 | Skip unwind->_dl_open-_dl_new_object-calloc 23 | Memcheck:Leak 24 | match-leak-kinds: reachable 25 | fun:calloc 26 | fun:_dl_new_object 27 | fun:_dl_map_object_from_fd 28 | fun:_dl_map_object 29 | fun:dl_open_worker 30 | fun:_dl_catch_error 31 | fun:_dl_open 32 | fun:dlopen_doit 33 | fun:_dl_catch_error 34 | fun:_dlerror_run 35 | fun:dlopen@@GLIBC_2.2.5 36 | fun:??? 37 | } 38 | 39 | { 40 | Skip unwind->_dl_open-_dl_load_cache_lookup-malloc 41 | Memcheck:Leak 42 | match-leak-kinds: reachable 43 | fun:malloc 44 | fun:strdup 45 | fun:_dl_load_cache_lookup 46 | fun:_dl_map_object 47 | fun:dl_open_worker 48 | fun:_dl_catch_error 49 | fun:_dl_open 50 | fun:dlopen_doit 51 | fun:_dl_catch_error 52 | fun:_dlerror_run 53 | fun:dlopen@@GLIBC_2.2.5 54 | fun:??? 55 | } 56 | 57 | { 58 | Skip unwind->_dl_open-_dl_new_object-malloc 59 | Memcheck:Leak 60 | match-leak-kinds: reachable 61 | fun:malloc 62 | fun:_dl_new_object 63 | fun:_dl_map_object_from_fd 64 | fun:_dl_map_object 65 | fun:dl_open_worker 66 | fun:_dl_catch_error 67 | fun:_dl_open 68 | fun:dlopen_doit 69 | fun:_dl_catch_error 70 | fun:_dlerror_run 71 | fun:dlopen@@GLIBC_2.2.5 72 | fun:??? 73 | } 74 | 75 | { 76 | Skip unwind->_dl_open-_dl_init-malloc 77 | Memcheck:Leak 78 | match-leak-kinds: reachable 79 | fun:malloc 80 | fun:??? 81 | fun:_dl_init 82 | fun:dl_open_worker 83 | fun:_dl_catch_error 84 | fun:_dl_open 85 | fun:dlopen_doit 86 | fun:_dl_catch_error 87 | fun:_dlerror_run 88 | fun:dlopen@@GLIBC_2.2.5 89 | fun:??? 90 | fun:??? 91 | } 92 | 93 | { 94 | Skip unwind->_dl_open-_dl_allocate_tls 95 | Memcheck:Leak 96 | match-leak-kinds: possible 97 | fun:calloc 98 | fun:_dl_allocate_tls 99 | fun:pthread_create@@GLIBC_2.2.5 100 | fun:init_interface_threads 101 | fun:main 102 | } 103 | 104 | # ibv_get_device_list false positived confirmed by ofi verbs maintainer 105 | 106 | { 107 | Skip unwind->fi_ibv_getinfo-realloc 108 | Memcheck:Leak 109 | match-leak-kinds: reachable 110 | fun:malloc 111 | fun:realloc 112 | fun:??? 113 | fun:??? 114 | fun:??? 115 | fun:pthread_once 116 | fun:ibv_get_device_list 117 | fun:fi_ibv_have_device 118 | fun:fi_ibv_init_info 119 | fun:fi_ibv_getinfo 120 | fun:fi_getinfo@@FABRIC_1.1 121 | fun:init_listener 122 | } 123 | 124 | { 125 | Skip unwind->fi_ibv_getinfo-calloc 126 | Memcheck:Leak 127 | match-leak-kinds: reachable 128 | fun:calloc 129 | fun:??? 130 | fun:??? 131 | fun:??? 132 | fun:??? 133 | fun:pthread_once 134 | fun:ibv_get_device_list 135 | fun:fi_ibv_have_device 136 | fun:fi_ibv_init_info 137 | fun:fi_ibv_getinfo 138 | fun:fi_getinfo@@FABRIC_1.1 139 | fun:init_listener 140 | } 141 | 142 | { 143 | Skip unwind->fi_ibv_getinfo-ibv_fork_init 144 | Memcheck:Leak 145 | match-leak-kinds: reachable 146 | fun:malloc 147 | fun:ibv_fork_init 148 | fun:fi_ibv_init_info 149 | fun:fi_ibv_getinfo 150 | fun:fi_getinfo@@FABRIC_1.1 151 | fun:init_listener 152 | fun:start_pseudo_target 153 | fun:interface_thread 154 | fun:start_thread 155 | fun:clone 156 | } 157 | 158 | { 159 | Skip unwind->fi_ibv_getinfo-rdma_get_devices 160 | Memcheck:Leak 161 | match-leak-kinds: reachable 162 | fun:calloc 163 | fun:??? 164 | fun:??? 165 | fun:??? 166 | fun:??? 167 | fun:??? 168 | fun:rdma_get_devices 169 | fun:fi_ibv_init_info 170 | fun:fi_ibv_getinfo 171 | fun:fi_getinfo@@FABRIC_1.1 172 | fun:init_listener 173 | fun:start_pseudo_target 174 | } 175 | -------------------------------------------------------------------------------- /files/wiki/picture1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/picture1.png -------------------------------------------------------------------------------- /files/wiki/picture2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/picture2.png -------------------------------------------------------------------------------- /files/wiki/picture3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/picture3.png -------------------------------------------------------------------------------- /files/wiki/picture4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/picture4.png -------------------------------------------------------------------------------- /files/wiki/picture5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/picture5.png -------------------------------------------------------------------------------- /files/wiki/picture6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/picture6.png -------------------------------------------------------------------------------- /files/wiki/picture7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/picture7.png -------------------------------------------------------------------------------- /files/wiki/picture8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/picture8.png -------------------------------------------------------------------------------- /files/wiki/picture9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/picture9.png -------------------------------------------------------------------------------- /files/wiki/tutorial1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial1.png -------------------------------------------------------------------------------- /files/wiki/tutorial10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial10.png -------------------------------------------------------------------------------- /files/wiki/tutorial11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial11.png -------------------------------------------------------------------------------- /files/wiki/tutorial12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial12.png -------------------------------------------------------------------------------- /files/wiki/tutorial13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial13.png -------------------------------------------------------------------------------- /files/wiki/tutorial14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial14.png -------------------------------------------------------------------------------- /files/wiki/tutorial15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial15.png -------------------------------------------------------------------------------- /files/wiki/tutorial16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial16.png -------------------------------------------------------------------------------- /files/wiki/tutorial17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial17.png -------------------------------------------------------------------------------- /files/wiki/tutorial18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial18.png -------------------------------------------------------------------------------- /files/wiki/tutorial19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial19.png -------------------------------------------------------------------------------- /files/wiki/tutorial2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial2.png -------------------------------------------------------------------------------- /files/wiki/tutorial20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial20.png -------------------------------------------------------------------------------- /files/wiki/tutorial21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial21.png -------------------------------------------------------------------------------- /files/wiki/tutorial22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial22.png -------------------------------------------------------------------------------- /files/wiki/tutorial3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial3.png -------------------------------------------------------------------------------- /files/wiki/tutorial4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial4.png -------------------------------------------------------------------------------- /files/wiki/tutorial5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial5.png -------------------------------------------------------------------------------- /files/wiki/tutorial6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial6.png -------------------------------------------------------------------------------- /files/wiki/tutorial7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial7.png -------------------------------------------------------------------------------- /files/wiki/tutorial8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial8.png -------------------------------------------------------------------------------- /files/wiki/tutorial9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/files/wiki/tutorial9.png -------------------------------------------------------------------------------- /html/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/back.png -------------------------------------------------------------------------------- /html/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/config.png -------------------------------------------------------------------------------- /html/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/email.png -------------------------------------------------------------------------------- /html/encode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * based on http://www.webtoolkit.info/ 3 | **/ 4 | var Base64={encode:function(r){var o,n=r+":"+r,t=0,e=0;for(t+=6,t+=e+=4,e+=6,t*=2,t+=6,""!=o&&(o=""),i=0;i0;)o+=x._l(--i); 6 | for(i=t;i>0;)o+=x._u(--i);for(i=e;i>0;)o+=x._n(--i);for(o+="+/=",n=x._d(n,o),o="",i=0;i>2, 9 | a=(3&i)<<4|(n=r.charCodeAt(h++))>>4,f=(15&n)<<2|(t=r.charCodeAt(h++))>>6,c=63&t,isNaN(n)?f=c=64:isNaN(t)&&(c=64), 10 | C=C+o.charAt(e)+o.charAt(a)+o.charAt(f)+o.charAt(c);return C},_u:function(r){return x._k(r+1+64)}, 11 | _l:function(r){return x._k(r+1+96)},_n:function(r){return x._k(r+48)},_d:function(r,o){var i,n,t,e,a,f,c="",C=0; 12 | for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");C>4, 13 | n=(15&e)<<4|(a=o.indexOf(r.charAt(C++)))>>2,t=(3&a)<<6|(f=o.indexOf(r.charAt(C++))),c+=String.fromCharCode(i), 14 | 64!=a&&(c+=String.fromCharCode(n)),64!=f&&(c+=String.fromCharCode(t));return c=x._ud(c)},_ue:function(r){ 15 | r=r.replace(/\r\n/g,"\n");for(var o="",i=0;i127&&n<2048?(o+=String.fromCharCode(n>>6|192), 17 | o+=String.fromCharCode(63&n|128)):(o+=String.fromCharCode(n>>12|224),o+=String.fromCharCode(n>>6&63|128), 18 | o+=String.fromCharCode(63&n|128))}return o},_ud:function(r){for(var o="",i=0,n=c1=c2=0;i191&&n<224?(c2=r.charCodeAt(i+1), 20 | o+=String.fromCharCode((31&n)<<6|63&c2),i+=2):(c2=r.charCodeAt(i+1),c3=r.charCodeAt(i+2), 21 | o+=String.fromCharCode((15&n)<<12|(63&c2)<<6|63&c3),i+=3);return o}}; -------------------------------------------------------------------------------- /html/encode.js.original: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Base64 encode / decode 4 | * http://www.webtoolkit.info/ 5 | * 6 | **/ 7 | var Base64 = { 8 | encode : function (input) { 9 | var key; 10 | var str = input + ":" + input; 11 | var numAlpha = 0; 12 | var numNumeric = 0; 13 | var extras = "+/="; 14 | 15 | numAlpha += 6; 16 | numNumeric += 4; 17 | numAlpha += numNumeric; 18 | numNumeric += 6; 19 | numAlpha *= 2; 20 | numAlpha += 6; 21 | 22 | key = ""; 23 | for (i = 0; i < numAlpha;) key += x._u(i++); 24 | for (i = 0; i < numAlpha;) key += x._l(i++); 25 | for (i = 0; i < numNumeric;) key += x._n(i++); 26 | key += extras; 27 | 28 | str = x._e(str, key); 29 | 30 | key = ""; 31 | for (i = numAlpha; i > 0;) key += x._l(--i); 32 | for (i = numAlpha; i > 0;) key += x._u(--i); 33 | for (i = numNumeric; i > 0;) key += x._n(--i); 34 | key += extras; 35 | 36 | str = x._d(str, key); 37 | 38 | key = ""; 39 | for (i = 0; i < numNumeric;) key += x._n(i++); 40 | for (i = 0; i < numAlpha;) key += x._u(i++); 41 | for (i = 0; i < numAlpha;) key += x._l(i++); 42 | key += extras 43 | 44 | return x._e(str, key); 45 | } 46 | } 47 | var x = { 48 | _k: function (i) { return String.fromCharCode(i); }, 49 | 50 | _e: function (input, key) { 51 | var output = ""; 52 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 53 | var i = 0; 54 | input = x._ue(input, key); 55 | while (i < input.length) { 56 | chr1 = input.charCodeAt(i++); 57 | chr2 = input.charCodeAt(i++); 58 | chr3 = input.charCodeAt(i++); 59 | enc1 = chr1 >> 2; 60 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 61 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 62 | enc4 = chr3 & 63; 63 | if (isNaN(chr2)) { 64 | enc3 = enc4 = 64; 65 | } else if (isNaN(chr3)) { 66 | enc4 = 64; 67 | } 68 | output = output + 69 | key.charAt(enc1) + key.charAt(enc2) + 70 | key.charAt(enc3) + key.charAt(enc4); 71 | } 72 | return output; 73 | }, 74 | 75 | _u: function (i) { return x._k(i + 1 + 0x20 * 2); }, 76 | _l: function (i) { return x._k(i + 1 + 0x20 * 3); }, 77 | _n: function (i) { return x._k(i + 3 * 16); }, 78 | 79 | _d: function (input, key) { 80 | var output = ""; 81 | var chr1, chr2, chr3; 82 | var enc1, enc2, enc3, enc4; 83 | var i = 0; 84 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 85 | while (i < input.length) { 86 | enc1 = key.indexOf(input.charAt(i++)); 87 | enc2 = key.indexOf(input.charAt(i++)); 88 | enc3 = key.indexOf(input.charAt(i++)); 89 | enc4 = key.indexOf(input.charAt(i++)); 90 | chr1 = (enc1 << 2) | (enc2 >> 4); 91 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 92 | chr3 = ((enc3 & 3) << 6) | enc4; 93 | output = output + String.fromCharCode(chr1); 94 | if (enc3 != 64) { 95 | output = output + String.fromCharCode(chr2); 96 | } 97 | if (enc4 != 64) { 98 | output = output + String.fromCharCode(chr3); 99 | } 100 | } 101 | output = x._ud(output); 102 | return output; 103 | }, 104 | 105 | _ue : function (string) { 106 | string = string.replace(/\r\n/g,"\n"); 107 | var utftext = ""; 108 | for (var n = 0; n < string.length; n++) { 109 | var c = string.charCodeAt(n); 110 | if (c < 128) { 111 | utftext += String.fromCharCode(c); 112 | } 113 | else if((c > 127) && (c < 2048)) { 114 | utftext += String.fromCharCode((c >> 6) | 192); 115 | utftext += String.fromCharCode((c & 63) | 128); 116 | } 117 | else { 118 | utftext += String.fromCharCode((c >> 12) | 224); 119 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 120 | utftext += String.fromCharCode((c & 63) | 128); 121 | } 122 | } 123 | return utftext; 124 | }, 125 | 126 | _ud : function (utftext) { 127 | var string = ""; 128 | var i = 0; 129 | var c = c1 = c2 = 0; 130 | while ( i < utftext.length ) { 131 | c = utftext.charCodeAt(i); 132 | if (c < 128) { 133 | string += String.fromCharCode(c); 134 | i++; 135 | } 136 | else if((c > 191) && (c < 224)) { 137 | c2 = utftext.charCodeAt(i+1); 138 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); 139 | i += 2; 140 | } 141 | else { 142 | c2 = utftext.charCodeAt(i+1); 143 | c3 = utftext.charCodeAt(i+2); 144 | string += String.fromCharCode(((c & 15) << 12) | 145 | ((c2 & 63) << 6) | (c3 & 63)); 146 | i += 3; 147 | } 148 | } 149 | return string; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /html/filtered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/filtered.png -------------------------------------------------------------------------------- /html/forms.js: -------------------------------------------------------------------------------- 1 | $(function() { $(document).tooltip(); }); 2 | 3 | $("#loginForm").submit(function(event) { 4 | var fields = $( ":input" ).serializeArray(); 5 | sessionStorage.setItem("dem_addr", fields[0].value); 6 | sessionStorage.setItem("dem_port", fields[1].value); 7 | 8 | var auth = make_basic_auth(fields[2].value, fields[3].value); 9 | sessionStorage.setItem("dem_auth", auth); 10 | 11 | checkAddress(); 12 | }); 13 | 14 | function updateForm() { 15 | var newuser, newpswd1, newpswd2; 16 | var olduser, oldpswd; 17 | 18 | $("#updateError").html(""); 19 | 20 | olduser = $("#olduser").val().trim(); 21 | if (olduser == "") { 22 | $("#updateError").html("All fields are manditory"); 23 | $(":input#olduser").focus(); 24 | return 1; 25 | } 26 | 27 | oldpswd = $("#oldpswd").val().trim(); 28 | if (oldpswd == "") { 29 | $("#updateError").html("All fields are manditory"); 30 | $("#oldpswd").focus(); 31 | return 1; 32 | } 33 | 34 | newuser = $("#newuser").val().trim(); 35 | if (newuser == "") { 36 | $("#updateError").html("All fields are manditory"); 37 | $("#newuser").focus(); 38 | return 1; 39 | } 40 | 41 | newpswd1 = $("#newpswd1").val().trim(); 42 | if (newpswd1 == "") { 43 | $("#updateError").html("All fields are manditory"); 44 | $("#newpswd1").focus(); 45 | return 1; 46 | } 47 | 48 | newpswd2 = $("#newpswd2").val().trim(); 49 | if (newpswd2 == "") { 50 | $("#updateError").html("All fields are manditory"); 51 | $("#newpswd2").focus(); 52 | return 1; 53 | } 54 | 55 | if (newpswd1 != newpswd2) { 56 | $("#updateError").html("New Passwords does not match"); 57 | $("#newpswd1").val(""); 58 | $("#newpswd2").val(""); 59 | $("#newpswd1").focus(); 60 | return 1; 61 | } 62 | 63 | var oldauth = make_basic_auth(olduser, oldpswd); 64 | var newauth = make_basic_auth(newuser, newpswd1); 65 | 66 | if (sessionStorage.getItem("dem_auth") != oldauth) { 67 | $("#updateError").html("Invalid user or password"); 68 | $("#oldpswd").val(""); 69 | $("#olduser").focus(); 70 | return 1; 71 | } 72 | 73 | $("#editVerb").html("POST"); 74 | $("#editUri").html("dem/signature"); 75 | $("#objectType").html("dem"); 76 | $("#parentUri").html("reset"); 77 | $("#objectValue").html(newauth.substring(6)); 78 | 79 | if (!sendRequest()) { 80 | $("#updateError").html("Failed to send update"); 81 | return 1; 82 | } 83 | 84 | $("#olduser").val(""); 85 | $("#oldpswd").val(""); 86 | $("#newuser").val(""); 87 | $("#newpswd1").val(""); 88 | $("#newpswd2").val(""); 89 | 90 | return 0; 91 | } 92 | 93 | /* When the user clicks on the button, 94 | toggle between hiding and showing the dropdown content */ 95 | function showDropdown(id) { 96 | var dropdowns = document.getElementsByClassName("dropdown-content"); 97 | var i; 98 | for (i = 0; i < dropdowns.length; i++) { 99 | var openDropdown = dropdowns[i]; 100 | if (openDropdown.classList.contains('show')) { 101 | openDropdown.classList.remove('show'); 102 | } 103 | } 104 | document.getElementById(id).classList.toggle("show"); 105 | } 106 | 107 | // Close the dropdown if the user clicks outside of it 108 | window.onclick = function(event) { 109 | var isDropButton = false; 110 | if (event.target.matches == undefined) 111 | isDropButton = event.target.className == "dropbtn"; 112 | else 113 | isDropButton = event.target.matches('.dropbtn'); 114 | if (!isDropButton) { 115 | var dropdowns = document.getElementsByClassName("dropdown-content"); 116 | var i; 117 | for (i = 0; i < dropdowns.length; i++) { 118 | var openDropdown = dropdowns[i]; 119 | if (openDropdown.classList.contains('show')) { 120 | openDropdown.classList.remove('show'); 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |

Distributed Endpoint Management 19 | 20 | 22 | 23 |

24 |

an implementation of a Centrialized NVMe-oF Discovery Controller

25 |
26 | 83 | 105 |
106 | 109 | 112 | 115 | 118 | 121 |
122 | 124 | 126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | 144 |
145 | 148 |
149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /html/nvme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/nvme.png -------------------------------------------------------------------------------- /html/page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/page.png -------------------------------------------------------------------------------- /html/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/pencil.png -------------------------------------------------------------------------------- /html/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/plus.png -------------------------------------------------------------------------------- /html/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/refresh.png -------------------------------------------------------------------------------- /html/stylesheet.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: 'Lato', 'Arial', sans-serif; 4 | } 5 | 6 | .container { 7 | overflow: hidden; 8 | } 9 | 10 | .container a { 11 | float: right; 12 | font-size: 18px; 13 | color: white; 14 | text-align: center; 15 | padding: 0; 16 | text-decoration: none; 17 | } 18 | 19 | .dropbtn { 20 | overflow: hidden; 21 | font-size: 14px; 22 | font-weight: bold; 23 | background-color: #0071c5; 24 | border-color:#444; 25 | color: white; 26 | padding: 0; 27 | border-width: 1px; 28 | min-width:74px; 29 | min-height:26px; 30 | cursor: pointer; 31 | } 32 | 33 | .dropbtn:hover, .dropbtn:focus { 34 | background-color: #66b5ff; 35 | color: #004280; 36 | } 37 | 38 | .dropdown-menu { 39 | position: relative; 40 | float: right; 41 | display: inline-block; 42 | } 43 | 44 | .static-menu { 45 | position: relative; 46 | float: left; 47 | width: 100%; 48 | display: inline-block; 49 | background-color: #0071c5; 50 | height: 26px; 51 | } 52 | 53 | .dropdown-content { 54 | display: none; 55 | position: absolute; 56 | font-size: 16px; 57 | font-weight: bold; 58 | background-color: #66b5ff; 59 | min-width: 80px; 60 | overflow: auto; 61 | box-shadow: 0 8px 16px 0 #004280; 62 | z-index: 1; 63 | } 64 | 65 | .dropdown-content a { 66 | color: #004280; 67 | padding: 5px 14px; 68 | font-size: 14px; 69 | cursor: pointer; 70 | text-decoration: none; 71 | display: block; 72 | } 73 | 74 | .dropdown-menu a:hover { 75 | background-color: #004280; 76 | color:white; 77 | } 78 | 79 | .show { 80 | display:block; 81 | } 82 | 83 | h1 { 84 | font-size: 1.2em; 85 | padding-left: .5em; 86 | } 87 | 88 | h2 { 89 | background-color: #0071c5; 90 | color: white; 91 | min-height: 38px; 92 | padding: 14px 0 0 14px; 93 | margin-top: 15px; 94 | } 95 | 96 | h3 { 97 | font-size: 1.2em; 98 | margin: 0 0 .7em 2em; 99 | } 100 | 101 | h4 { 102 | padding: 6px 32px; 103 | font-size: 12px; 104 | margin: 0; 105 | background-color: #66b5ff; 106 | color: #004280; 107 | } 108 | 109 | h5 { 110 | margin: 0; 111 | font-size: 1.1em; 112 | position: relative; 113 | left: 2em; 114 | } 115 | 116 | .header { 117 | font-weight: bold; 118 | } 119 | 120 | #workspace { 121 | display: none; 122 | } 123 | 124 | .addrForm { 125 | margin-bottom:-18px; 126 | } 127 | 128 | .data { 129 | margin: .2em 0 0 2em; 130 | } 131 | 132 | .innerform, .updateform { 133 | font-family: Arial; 134 | border: solid; 135 | margin-top: 0; 136 | margin-bottom: 20px; 137 | padding: 12px 20px 14px 24px; 138 | border-width: 4px; 139 | border-color: #004280; 140 | line-height: 45px; 141 | } 142 | 143 | .innerform { 144 | width: 320px; 145 | } 146 | 147 | .updateform { 148 | width: 350px; 149 | } 150 | 151 | .bg { 152 | padding: 1px 15px; 153 | background-color: #004280; 154 | min-width:800px; 155 | } 156 | 157 | .footer { 158 | font-family: Arial; 159 | margin: 0; 160 | padding: 0 9px 6px 0; 161 | color: white; 162 | font-size: 10px; 163 | text-align: right; 164 | } 165 | 166 | .hilite1 { 167 | color: orange; 168 | font-weight: bold; 169 | } 170 | 171 | .hilite2 { 172 | color: yellow; 173 | font-weight: bold; 174 | } 175 | 176 | .error { 177 | color: orangered; 178 | font-weight: bold; 179 | } 180 | 181 | #err { 182 | color: orangered; 183 | font-size: smaller; 184 | font-weight: bold; 185 | } 186 | 187 | .alert { 188 | block: none; 189 | min-width: 36em; 190 | min-height: 13em; 191 | z-index: 10; 192 | position: absolute; 193 | top: 8em; 194 | left: 7em; 195 | background-color: orangered; 196 | font-size: x-large; 197 | font-weight: bolder; 198 | color: white; 199 | padding-top: 3em; 200 | padding-left: 3em; 201 | } 202 | 203 | .page { 204 | margin-bottom: -14px; 205 | } 206 | 207 | .content { 208 | margin: 0 0 20px 0; 209 | padding: 30px 12px; 210 | color: #004280; 211 | background-color: #fafafa; 212 | min-height: 445px; 213 | } 214 | 215 | .details h5 { 216 | left: 0; 217 | } 218 | 219 | .details p { 220 | margin: 15px 0; 221 | } 222 | 223 | .details { 224 | position: relative; 225 | left: 5em; 226 | } 227 | 228 | .subtext { 229 | position: relative; 230 | font-size: .9em; 231 | font-weight: normal; 232 | } 233 | 234 | .subdetails { 235 | padding-left: 1.3em; 236 | } 237 | 238 | .comments { 239 | padding-left: 1.6em; 240 | } 241 | 242 | .logpages { 243 | padding-left: 4.6em; 244 | } 245 | 246 | .icon { 247 | height: 16px; 248 | width: 16px; 249 | cursor:pointer; 250 | } 251 | 252 | .email { 253 | font-size: 20px; 254 | } 255 | 256 | .email img { 257 | height:24px; 258 | position: relative; 259 | padding-right: 2px; 260 | top: 4px; 261 | } 262 | 263 | .one-column { 264 | position: relative; 265 | top: .7em; /* same as bottom in h3 */ 266 | left:-6px; 267 | margin-bottom: 2em; 268 | } 269 | 270 | .two-columns { 271 | column-count: 2; 272 | -moz-column-count: 2; 273 | -webkil-column-count: 2; 274 | position: relative; 275 | top: .7em; /* same as bottom in h3 */ 276 | left:-6px; 277 | margin-bottom: 2em; 278 | } 279 | 280 | .three-columns { 281 | column-count: 3; 282 | -moz-column-count: 3; 283 | -webkil-column-count: 3; 284 | position: relative; 285 | top: .7em; /* same as bottom in h3 */ 286 | left:-6px; 287 | margin-bottom: 2em; 288 | } 289 | 290 | .overlay { 291 | height: 100%; 292 | width: 0; 293 | position: fixed; 294 | z-index: 1; 295 | top: 0; 296 | left: 0; 297 | background-color: rgb(0,0,0); 298 | background-color: rgba(60,60,60, 0.9); 299 | overflow-x: hidden; 300 | transition: 0.5s; 301 | } 302 | 303 | .overlay-content { 304 | position: relative; 305 | min-width:760px; 306 | min-height: 422px; 307 | top: 4em; 308 | left: 3em; 309 | width: 80%; 310 | color: #ccc; 311 | background-color: rgb(20,20,20); 312 | background-color: rgba(40,40,40, 0.9); 313 | font-size: 18px; 314 | margin-top: 30px; 315 | height:60%; 316 | padding: 1em 2em; 317 | } 318 | 319 | .units { 320 | position: absolute; 321 | left: 20em; 322 | } 323 | 324 | a.closebtn, a.savebtn { 325 | transition: 0.3s; 326 | } 327 | 328 | a.closebtn:hover, a.closebtn:focus { 329 | color: #f00; 330 | } 331 | 332 | a.savebtn:hover, a.savebtn:focus { 333 | color: #0f0; 334 | } 335 | 336 | .closebtn { 337 | position: absolute; 338 | top: 20px; 339 | right: 35px; 340 | padding: 8px; 341 | text-decoration: none; 342 | font-size: 38px; 343 | color: #c00; 344 | display: block; 345 | } 346 | .savebtn { 347 | position: absolute; 348 | top: 20px; 349 | right: 80px; 350 | padding: 8px; 351 | text-decoration: none; 352 | font-size: 38px; 353 | color: #0b0; 354 | display: block; 355 | } 356 | 357 | @media screen and (max-height: 450px) { 358 | .overlay .closebtn { 359 | font-size: 32px; 360 | top: 15px; 361 | right: 30px; 362 | } 363 | .overlay .savebtn { 364 | font-size: 32px; 365 | top: 15px; 366 | right: 70px; 367 | } 368 | } 369 | 370 | input[type=text], input[type=number], input[type=password] { 371 | width: 12em; 372 | position: absolute; 373 | left: 11em; 374 | padding-left: .3em; 375 | margin-top: 11px; 376 | } 377 | 378 | .updateform input[type=text], .updateform input[type=password] { 379 | left: 18em; 380 | } 381 | 382 | .overlay input[type=text] { 383 | width: 70%; 384 | position: absolute; 385 | left: 12em; 386 | font-size: 18px; 387 | padding-left: .3em; 388 | margin-top: -1px; 389 | } 390 | 391 | .overlay input[type=checkbox] { 392 | position: absolute; 393 | left: 16em; 394 | } 395 | 396 | .overlay select { 397 | position: absolute; 398 | left: 12em; 399 | width: 8em; 400 | font-size: 18px; 401 | padding: .1em 0 .1em .3em; 402 | } 403 | 404 | .overlay input[type=number] { 405 | width: 6em; 406 | position: absolute; 407 | left: 12em; 408 | font-size: 18px; 409 | padding-left: .3em; 410 | margin-top: -1px; 411 | } 412 | 413 | .filter { 414 | display: block; 415 | position: relative; 416 | padding-left: 25px; 417 | margin-bottom: 12px; 418 | cursor: pointer; 419 | font-size: 12px; 420 | -webkit-user-select: none; 421 | -moz-user-select: none; 422 | -ms-user-select: none; 423 | user-select: none; 424 | } 425 | 426 | #filteredmenu, #unfilteredmenu { 427 | min-width: 16px; 428 | min-height: 16px; 429 | height: 16px; 430 | margin-right: 1em; 431 | margin-left: .7em; 432 | } 433 | 434 | #Filter.dropdown-content { 435 | float: left; 436 | width: 12.5em; 437 | position: sticky; 438 | padding: 8px 0px 3px 8px; 439 | overflow: initial; 440 | } 441 | 442 | .filter input { 443 | position: absolute; 444 | opacity: 0; 445 | } 446 | /* Create a custom radio button */ 447 | .checkmark { 448 | position: absolute; 449 | top: 0; 450 | left: 0; 451 | height: 16px; 452 | width: 16px; 453 | background-color: #eee; 454 | border-radius: 50%; 455 | } 456 | /* On mouse-over, add a grey background color */ 457 | .filter:hover input ~ .checkmark { 458 | background-color: #0071c5; 459 | } 460 | /* When the radio button is checked, add a blue background */ 461 | .filter input:checked ~ .checkmark { 462 | background-color: #004280; 463 | } 464 | /* Create the indicator (the dot/circle - hidden when not checked) */ 465 | .checkmark:after { 466 | content: ""; 467 | position: absolute; 468 | display: none; 469 | } 470 | /* Show the indicator (dot/circle) when checked */ 471 | .filter input:checked ~ .checkmark:after { 472 | display: block; 473 | } 474 | /* Style the indicator (dot/circle) */ 475 | .filter .checkmark:after { 476 | top: 5px; 477 | left: 5px; 478 | width: 6px; 479 | height: 6px; 480 | border-radius: 50%; 481 | background: #ccc; 482 | } 483 | -------------------------------------------------------------------------------- /html/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/trash.png -------------------------------------------------------------------------------- /html/unfiltered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/unfiltered.png -------------------------------------------------------------------------------- /html/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/html/view.png -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/install-sh -------------------------------------------------------------------------------- /latest.txt: -------------------------------------------------------------------------------- 1 | nvme-dem-1.0.0.tar.gz 2 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-nvme/nvme-dem/0d22bd8684d978f3902109b645fbfe99d03a587c/missing -------------------------------------------------------------------------------- /nvme-dem.spec.in: -------------------------------------------------------------------------------- 1 | Name: nvme-dem 2 | Version: @VERSION@ 3 | Release: 0 4 | Summary: NVMe over Fabrics Distributed Endpoint Management suite 5 | 6 | Group: User-mode Administrative Tools 7 | License: GPLv2 or BSD 8 | Url: http://www.github.com/linux-nvme/%{name} 9 | Source: http://www.github.com/linux-nvme/%{name}-%{version}.tar.gz 10 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 11 | 12 | %description 13 | NVMe over Fabrics (NVMe-oF) Distributed Endpoint Management (dem) is an 14 | implementation of a centralized Discovery controller providing remote 15 | configuration and provisioning of remote NVMe resources. 16 | 17 | %prep 18 | %setup -q -n %{name}-%{version} 19 | 20 | %build 21 | %configure %{configopts} 22 | 23 | %install 24 | rm -rf %{buildroot} 25 | %makeinstall 26 | 27 | %clean 28 | rm -rf %{buildroot} 29 | 30 | %files 31 | %defattr(-,root,root,-) 32 | %dir /etc/nvme/ 33 | %{_prefix}/local/share/bash_completion.d/dem-cli 34 | %{_bindir}/dem-cli 35 | %{_bindir}/dem-dm 36 | %{_bindir}/dem-em 37 | %{_bindir}/dem-ac 38 | %{_bindir}/dem 39 | %{_sysconfdir}/nvme/nvmeof.conf 40 | %{_sysconfdir}/nvme/nvmeof-dem 41 | %{_libexecdir}/nvmeof 42 | %{_prefix}/lib/systemd/system/nvmeof.service 43 | %{_mandir}/man1/dem-cli.1.gz 44 | %{_mandir}/man1/dem-dm.1.gz 45 | %{_mandir}/man8/dem-em.8.gz 46 | %{_mandir}/man8/dem-ac.8.gz 47 | %{_mandir}/man8/dem.8.gz 48 | %doc AUTHORS COPYING README 49 | 50 | %changelog 51 | * Mon Apr 22 2019 created spec file 52 | - Release 1.0.0 53 | -------------------------------------------------------------------------------- /src/auto_connect/common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #ifndef __COMMON_H__ 36 | #define __COMMON_H__ 37 | 38 | #define unlikely __glibc_unlikely 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #include "nvme.h" 54 | #include "utils.h" 55 | #include "ops.h" 56 | #include "dem.h" 57 | 58 | #define DELAY 480 /* ms */ 59 | #define SECONDS (1000000 / DELAY) 60 | #define KEEP_ALIVE_COUNTER 4 /* x DELAY */ 61 | #define CONNECT_RETRY_COUNTER (60 * SECONDS) 62 | 63 | #define NVME_FABRICS_DEV "/dev/nvme-fabrics" 64 | #define SYS_CLASS_PATH "/sys/class/nvme-fabrics/ctl/" 65 | #define SYS_CLASS_ADDR_FILE "address" 66 | #define SYS_CLASS_TRTYPE_FILE "transport" 67 | #define SYS_CLASS_SUBNQN_FILE "subsysnqn" 68 | #define NVME_FABRICS_FMT \ 69 | "transport=%s,traddr=%s,trsvcid=%s,nqn=%s,hostnqn=%s" 70 | 71 | struct target; 72 | 73 | struct portid { 74 | struct linked_list node; 75 | int portid; 76 | char type[CONFIG_TYPE_SIZE + 1]; 77 | char family[CONFIG_FAMILY_SIZE + 1]; 78 | char address[CONFIG_ADDRESS_SIZE + 1]; 79 | char port[CONFIG_PORT_SIZE + 1]; 80 | int port_num; 81 | int addr[ADDR_LEN]; 82 | int adrfam; 83 | int trtype; 84 | int valid; 85 | }; 86 | 87 | struct host_iface { 88 | char type[CONFIG_TYPE_SIZE + 1]; 89 | char family[CONFIG_FAMILY_SIZE + 1]; 90 | char address[CONFIG_ADDRESS_SIZE + 1]; 91 | int addr[ADDR_LEN]; 92 | char port[CONFIG_PORT_SIZE + 1]; 93 | struct xp_pep *listener; 94 | struct xp_ops *ops; 95 | }; 96 | 97 | struct inb_iface { 98 | struct target *target; 99 | struct portid portid; 100 | struct endpoint ep; 101 | int connected; 102 | }; 103 | 104 | struct oob_iface { 105 | char address[CONFIG_ADDRESS_SIZE + 1]; 106 | int port; 107 | }; 108 | 109 | union sc_iface { 110 | struct oob_iface oob; 111 | struct inb_iface inb; 112 | }; 113 | 114 | struct fabric_iface { 115 | struct linked_list node; 116 | char type[CONFIG_TYPE_SIZE + 1]; 117 | char fam[CONFIG_FAMILY_SIZE + 1]; 118 | char addr[CONFIG_ADDRESS_SIZE + 1]; 119 | int valid; 120 | }; 121 | 122 | struct logpage { 123 | struct linked_list node; 124 | struct portid *portid; 125 | struct nvmf_disc_rsp_page_entry e; 126 | int valid; 127 | int connected; 128 | }; 129 | 130 | struct subsystem { 131 | struct linked_list node; 132 | struct linked_list logpage_list; 133 | struct target *target; 134 | char nqn[MAX_NQN_SIZE + 1]; 135 | }; 136 | 137 | struct target { 138 | struct linked_list node; 139 | struct linked_list subsys_list; 140 | char alias[MAX_ALIAS_SIZE + 1]; 141 | int mgmt_mode; 142 | union sc_iface sc_iface; 143 | }; 144 | 145 | int init_interfaces(void); 146 | void *interface_thread(void *arg); 147 | 148 | void build_target_list(void); 149 | void init_targets(void); 150 | void cleanup_targets(void); 151 | void get_host_nqn(void *context, void *haddr, char *nqn); 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /src/cli/show.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | void show_target_data(json_t *parent); 36 | void show_target_list(json_t *parent, int indent); 37 | void show_host_data(json_t *parent); 38 | void show_host_list(json_t *parent, int indent); 39 | void show_group_data(json_t *parent); 40 | void show_group_list(json_t *parent); 41 | void show_config(json_t *parent); 42 | void show_usage_data(json_t *parent); 43 | 44 | #ifndef UNUSED 45 | #define UNUSED(x) ((void) x) 46 | #endif 47 | -------------------------------------------------------------------------------- /src/common/curl.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: DUAL GPL-2.0/BSD 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "curl.h" 42 | 43 | #ifdef DEM_CLI 44 | static int curl_show_results = 1; 45 | #else 46 | extern int curl_show_results; 47 | #endif 48 | 49 | struct curl_context { 50 | CURL *curl; 51 | char *write_data; /* used in write_cb */ 52 | size_t write_sz; 53 | char *read_data; /* used in read_cb */ 54 | int read_sz; 55 | }; 56 | 57 | static struct curl_context *ctx; 58 | static int debug_curl; 59 | 60 | #ifdef CURLINFO_CONTENT_LENGTH_DOWNLOAD_T 61 | #define CURLINFO_CONTENT_LENGTH CURLINFO_CONTENT_LENGTH_DOWNLOAD_T 62 | #else 63 | #define CURLINFO_CONTENT_LENGTH CURLINFO_CONTENT_LENGTH_DOWNLOAD 64 | #endif 65 | 66 | static size_t read_cb(char *p, size_t size, size_t n, void *stream) 67 | { 68 | int len = size * n; 69 | int cnt; 70 | 71 | if (ctx != stream || !ctx->read_sz) 72 | cnt = 0; 73 | else if (len > ctx->read_sz) { 74 | memcpy(p, ctx->read_data, ctx->read_sz); 75 | cnt = ctx->read_sz; 76 | ctx->read_sz = 0; 77 | } else { 78 | memcpy(p, ctx->read_data, len); 79 | ctx->read_data += len; 80 | ctx->read_sz -= len; 81 | cnt = len; 82 | } 83 | 84 | return cnt; 85 | } 86 | 87 | static size_t write_cb(void *contents, size_t size, size_t n, void *stream) 88 | { 89 | size_t bytes = size * n; 90 | 91 | if (ctx != stream) 92 | return 0; 93 | 94 | ctx->write_data = realloc(ctx->write_data, ctx->write_sz + bytes + 1); 95 | if (ctx->write_data == NULL) { 96 | fprintf(stderr, "unable to alloc memory for new data\n"); 97 | return 0; 98 | } 99 | 100 | memcpy(&(ctx->write_data[ctx->write_sz]), contents, bytes); 101 | ctx->write_sz += bytes; 102 | ctx->write_data[ctx->write_sz] = 0; 103 | 104 | return bytes; 105 | } 106 | 107 | int init_curl(int debug) 108 | { 109 | CURL *curl; 110 | 111 | debug_curl = debug; 112 | 113 | ctx = malloc(sizeof(*ctx)); 114 | if (!ctx) { 115 | fprintf(stderr, "unable to alloc memory for curl context\n"); 116 | return -ENOMEM; 117 | } 118 | 119 | curl_global_init(CURL_GLOBAL_ALL); 120 | 121 | curl = curl_easy_init(); 122 | if (!curl) { 123 | fprintf(stderr, "unable to init curl"); 124 | free(ctx); 125 | return -EINVAL; 126 | } 127 | 128 | /* will be grown as needed by the realloc in write_cb */ 129 | ctx->write_data = malloc(1); 130 | if (!ctx->write_data) 131 | return -ENOMEM; 132 | 133 | ctx->write_sz = 0; /* no data at this point */ 134 | ctx->write_data[0] = 0; 135 | 136 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (void *) write_cb); 137 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) ctx); 138 | curl_easy_setopt(curl, CURLOPT_READFUNCTION, (void *) read_cb); 139 | curl_easy_setopt(curl, CURLOPT_READDATA, (void *) ctx); 140 | 141 | ctx->curl = curl; 142 | 143 | return 0; 144 | } 145 | 146 | void cleanup_curl(void) 147 | { 148 | CURL *curl = ctx->curl; 149 | 150 | curl_easy_cleanup(curl); 151 | 152 | curl_global_cleanup(); 153 | 154 | free(ctx->write_data); 155 | free(ctx); 156 | } 157 | 158 | static int exec_curl(char *url, char **p) 159 | { 160 | CURL *curl = ctx->curl; 161 | CURLcode ret; 162 | curl_off_t bytes; 163 | 164 | curl_easy_setopt(curl, CURLOPT_URL, url); 165 | #ifndef DEM_CLI 166 | curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); 167 | #endif 168 | 169 | ret = curl_easy_perform(curl); 170 | 171 | if (ret == CURLE_OK) { 172 | curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH, &bytes); 173 | *p = strndup(ctx->write_data, bytes); 174 | } else if (ret == CURLE_COULDNT_CONNECT) { 175 | fprintf(stderr, "curl returned error %s (%d) errno %d\n", 176 | curl_easy_strerror(ret), ret, errno); 177 | ret = -errno; 178 | } else 179 | ret = -EINVAL; 180 | 181 | if (ctx->write_sz) { 182 | free(ctx->write_data); 183 | ctx->write_data = malloc(1); 184 | if (!ctx->write_data) 185 | return -ENOMEM; 186 | 187 | ctx->write_sz = 0; 188 | ctx->write_data[0] = 0; 189 | } 190 | 191 | return ret; 192 | } 193 | 194 | int exec_get(char *url, char **result) 195 | { 196 | CURL *curl = ctx->curl; 197 | int ret; 198 | 199 | curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); 200 | 201 | if (debug_curl) 202 | printf("GET %s\n", url); 203 | 204 | ret = exec_curl(url, result); 205 | 206 | curl_easy_setopt(curl, CURLOPT_HTTPGET, 0); 207 | 208 | return ret; 209 | } 210 | 211 | int exec_put(char *url, char *data, int len) 212 | { 213 | CURL *curl = ctx->curl; 214 | char *result; 215 | int ret; 216 | 217 | curl_easy_setopt(curl, CURLOPT_PUT, 1); 218 | 219 | ctx->read_data = data; 220 | ctx->read_sz = len; 221 | 222 | if (debug_curl) { 223 | printf("PUT %s\n", url); 224 | if (len) 225 | printf("<< %.*s >>\n", len, data); 226 | } 227 | 228 | ret = exec_curl(url, &result); 229 | 230 | curl_easy_setopt(curl, CURLOPT_PUT, 0); 231 | 232 | if (ret) 233 | return ret; 234 | 235 | if (curl_show_results) 236 | printf("%s\n", result); 237 | 238 | free(result); 239 | 240 | return 0; 241 | } 242 | 243 | int exec_post(char *url, char *data, int len) 244 | { 245 | CURL *curl = ctx->curl; 246 | char *result; 247 | int ret; 248 | 249 | curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1); 250 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); 251 | curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); 252 | 253 | if (debug_curl) { 254 | printf("POST %s\n", url); 255 | if (len) 256 | printf("<< %.*s >>\n", len, data); 257 | } 258 | 259 | ret = exec_curl(url, &result); 260 | 261 | curl_easy_setopt(curl, CURLOPT_HTTPPOST, 0); 262 | 263 | if (ret) 264 | return ret; 265 | 266 | if (curl_show_results) 267 | printf("%s\n", result); 268 | 269 | free(result); 270 | 271 | return 0; 272 | } 273 | 274 | int exec_delete(char *url) 275 | { 276 | CURL *curl = ctx->curl; 277 | char *result; 278 | int ret; 279 | 280 | curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); 281 | 282 | if (debug_curl) 283 | printf("DELETE %s\n", url); 284 | 285 | ret = exec_curl(url, &result); 286 | 287 | curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL); 288 | 289 | if (ret) 290 | return ret; 291 | 292 | if (curl_show_results) 293 | printf("%s\n", result); 294 | 295 | free(result); 296 | 297 | return 0; 298 | } 299 | 300 | int exec_delete_ex(char *url, char *data, int len) 301 | { 302 | CURL *curl = ctx->curl; 303 | char *result; 304 | int ret; 305 | 306 | curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); 307 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); 308 | curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); 309 | 310 | if (debug_curl) { 311 | printf("DELETE %s\n", url); 312 | if (len) 313 | printf("<< %.*s >>\n", len, data); 314 | } 315 | 316 | ret = exec_curl(url, &result); 317 | 318 | curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL); 319 | 320 | if (ret) 321 | return ret; 322 | 323 | if (curl_show_results) 324 | printf("%s\n", result); 325 | 326 | free(result); 327 | 328 | return 0; 329 | } 330 | 331 | int exec_patch(char *url, char *data, int len) 332 | { 333 | CURL *curl = ctx->curl; 334 | char *result; 335 | int ret; 336 | 337 | curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH"); 338 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); 339 | curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); 340 | 341 | if (debug_curl) { 342 | printf("PATCH %s\n", url); 343 | if (len) 344 | printf("<< %.*s >>\n", len, data); 345 | } 346 | 347 | ret = exec_curl(url, &result); 348 | 349 | curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL); 350 | 351 | if (ret) 352 | return ret; 353 | 354 | if (curl_show_results) 355 | printf("%s\n", result); 356 | 357 | free(result); 358 | 359 | return 0; 360 | } 361 | -------------------------------------------------------------------------------- /src/common/logpages.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: DUAL GPL-2.0/BSD 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "common.h" 43 | 44 | static inline void trim(char *p, int len) 45 | { 46 | int i; 47 | for (i = 0; i < len && *p; i++, p++) 48 | if (*p == ' ') { 49 | *p = 0; 50 | break; 51 | } 52 | } 53 | 54 | int get_logpages(struct ctrl_queue *dq, struct nvmf_disc_rsp_page_hdr **logp, 55 | u32 *numrec) 56 | { 57 | struct nvmf_disc_rsp_page_hdr *hdr; 58 | struct nvmf_disc_rsp_page_entry *log; 59 | unsigned int log_size = 0; 60 | unsigned long genctr; 61 | size_t offset; 62 | u32 i; 63 | int ret; 64 | 65 | offset = offsetof(struct nvmf_disc_rsp_page_hdr, numrec); 66 | log_size = offset + sizeof(hdr->numrec); 67 | log_size = round_up(log_size, sizeof(u32)); 68 | 69 | ret = send_get_log_page(&dq->ep, log_size, &hdr); 70 | if (ret) { 71 | print_err("failed to fetch number of discovery log entries"); 72 | return -ENODATA; 73 | } 74 | 75 | genctr = le64toh(hdr->genctr); 76 | *numrec = le32toh(hdr->numrec); 77 | 78 | free(hdr); 79 | 80 | if (*numrec == 0) { 81 | #ifdef DEBUG_LOG_PAGES_VERBOSE 82 | print_err("no discovery log on target %s", dq->target->alias); 83 | #endif 84 | *logp = NULL; 85 | return 0; 86 | } 87 | 88 | #ifdef DEBUG_LOG_PAGES_VERBOSE 89 | print_debug("number of records to fetch is %d", *numrec); 90 | #endif 91 | 92 | log_size = sizeof(struct nvmf_disc_rsp_page_hdr) + 93 | sizeof(struct nvmf_disc_rsp_page_entry) * *numrec; 94 | 95 | ret = send_get_log_page(&dq->ep, log_size, &hdr); 96 | if (ret) { 97 | print_err("failed to fetch discovery log entries"); 98 | return -ENODATA; 99 | } 100 | 101 | if ((*numrec != le32toh(hdr->numrec)) || 102 | (genctr != le64toh(hdr->genctr))) { 103 | print_err("# records for last two get log pages not equal"); 104 | return -EINVAL; 105 | } 106 | 107 | for (i = 0, log = hdr->entries; i < *numrec; i++, log++) { 108 | trim(log->traddr, NVMF_TRADDR_SIZE); 109 | trim(log->subnqn, NVMF_NQN_FIELD_LEN); 110 | trim(log->trsvcid, NVMF_TRSVCID_SIZE); 111 | } 112 | 113 | *logp = hdr; 114 | 115 | return 0; 116 | } 117 | 118 | void print_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) 119 | { 120 | #ifdef DEBUG_LOG_PAGES 121 | int i; 122 | struct nvmf_disc_rsp_page_entry *e; 123 | 124 | #ifdef DEBUG_LOG_PAGES_VERBOSE 125 | print_debug("%s %d, %s %" PRIu64, 126 | "Discovery Log Number of Records", numrec, 127 | "Generation counter", (uint64_t) le64toh(log->genctr)); 128 | #endif 129 | 130 | for (i = 0; i < numrec; i++) { 131 | e = &log->entries[i]; 132 | 133 | #ifdef DEBUG_LOG_PAGES_VERBOSE 134 | print_info("=====Discovery Log Entry %d======", i); 135 | #endif 136 | print_info("subnqn: %s", e->subnqn); 137 | print_info("portid: %d", e->portid); 138 | print_info("trtype: %s", trtype_str(e->trtype)); 139 | print_info("adrfam: %s", adrfam_str(e->adrfam)); 140 | print_info("traddr: %s", e->traddr); 141 | print_info("trsvcid: %s", e->trsvcid); 142 | print_info("treq: %s", treq_str(e->treq)); 143 | print_info("subtype: %s", subtype_str(e->subtype)); 144 | 145 | switch (e->trtype) { 146 | case NVMF_TRTYPE_RDMA: 147 | print_info(" rdma_prtype: %s", 148 | prtype_str(e->tsas.rdma.prtype)); 149 | print_info(" rdma_qptype: %s", 150 | qptype_str(e->tsas.rdma.qptype)); 151 | print_info(" rdma_cms: %s", 152 | cms_str(e->tsas.rdma.cms)); 153 | print_info(" rdma_pkey: 0x%04x", 154 | e->tsas.rdma.pkey); 155 | break; 156 | } 157 | } 158 | #else 159 | UNUSED(log); 160 | UNUSED(numrec); 161 | #endif 162 | } 163 | -------------------------------------------------------------------------------- /src/common/parse.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: DUAL GPL-2.0/BSD 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include "common.h" 40 | #include "tags.h" 41 | 42 | #define is_whitespace(c) (c == ' ' || c == '\t' || c == '\r') 43 | #define is_quote(c) (c == '\'' || c == '"') 44 | #define is_eol(c) (c == '\n' || c == EOF) 45 | 46 | #define COMMENT '#' 47 | #define EQUAL '=' 48 | #define MAX_EQUAL 2 49 | 50 | #define IPV4_LEN 4 51 | #define IPV4_WIDTH 3 52 | #define IPV4_CHAR '.' 53 | 54 | #define IPV6_LEN 8 55 | #define IPV6_WIDTH 4 56 | #define IPV6_CHAR ':' 57 | 58 | #define FC_LEN 8 59 | #define FC_WIDTH 2 60 | #define FC_CHAR ':' 61 | 62 | static int consume_line(FILE *fd) 63 | { 64 | char c; 65 | 66 | while (!feof(fd)) { 67 | c = fgetc(fd); 68 | if (is_eol(c)) 69 | return 0; 70 | } 71 | return 1; 72 | } 73 | 74 | static int consume_whitespace(FILE *fd) 75 | { 76 | char c; 77 | 78 | while (!feof(fd)) { 79 | c = fgetc(fd); 80 | if (c == COMMENT) 81 | return 1; 82 | 83 | if (!is_whitespace(c) || is_eol(c)) { 84 | ungetc(c, fd); 85 | return 0; 86 | } 87 | } 88 | return 1; 89 | } 90 | 91 | static int parse_word(FILE *fd, char *word, int n) 92 | { 93 | char c, *p = word; 94 | int quoted = 0; 95 | 96 | while (!feof(fd)) { 97 | c = fgetc(fd); 98 | if (c == COMMENT && !quoted) 99 | break; 100 | 101 | if (is_quote(c)) { 102 | quoted = ~quoted; 103 | continue; 104 | } 105 | 106 | if (is_whitespace(c) || is_eol(c) || c == EQUAL) { 107 | ungetc(c, fd); 108 | break; 109 | } 110 | 111 | *p++ = c; 112 | 113 | if (--n == 0) 114 | break; 115 | } 116 | 117 | if (p == word) 118 | return 1; 119 | 120 | *p = 0; 121 | 122 | return 0; 123 | } 124 | 125 | static int parse_equal(FILE *fd, char *word, int n) 126 | { 127 | char c, *p = word; 128 | 129 | while (!feof(fd)) { 130 | c = fgetc(fd); 131 | if (c == COMMENT) 132 | break; 133 | 134 | if (c != EQUAL) { 135 | ungetc(c, fd); 136 | break; 137 | } 138 | 139 | *p++ = c; 140 | 141 | if (--n == 0) 142 | break; 143 | } 144 | 145 | if (p == word) 146 | return 1; 147 | 148 | *p = 0; 149 | 150 | return 0; 151 | } 152 | 153 | int parse_line(FILE *fd, char *tag, int tag_max, char *value, int value_max) 154 | { 155 | char equal[MAX_EQUAL + 1]; 156 | int ret; 157 | 158 | ret = consume_whitespace(fd); 159 | if (ret) 160 | goto out; 161 | 162 | ret = parse_word(fd, tag, tag_max); 163 | if (ret) 164 | goto out; 165 | 166 | ret = consume_whitespace(fd); 167 | if (ret) 168 | goto out; 169 | 170 | ret = parse_equal(fd, equal, MAX_EQUAL); 171 | if (ret) 172 | goto out; 173 | 174 | if (strcmp(equal, "=") != 0) { 175 | ret = -1; 176 | goto out; 177 | } 178 | 179 | ret = consume_whitespace(fd); 180 | if (ret) 181 | goto out; 182 | 183 | ret = parse_word(fd, value, value_max); 184 | out: 185 | consume_line(fd); 186 | 187 | return ret; 188 | } 189 | 190 | static int string_to_addr(char *p, int *addr, int len, int width, char delim) 191 | { 192 | char nibble[8]; 193 | int i, j, n, z; 194 | 195 | n = strlen(p) + 1; 196 | 197 | for (z = j = i = 0; i < n && j < len; i++, p++) { 198 | if (*p == delim || *p == 0 || *p == '/') { 199 | if (z) { 200 | if (z > width) 201 | return -1; 202 | nibble[z] = 0; 203 | z = 0; 204 | addr[j] = atoi(nibble); 205 | } else 206 | addr[j] = 0; 207 | 208 | j++; 209 | 210 | if (*p == '/') 211 | break; 212 | } else 213 | nibble[z++] = *p; 214 | } 215 | 216 | for (; j < len; j++) 217 | addr[j] = 0; 218 | 219 | if (i < n && *p == '/') { 220 | *p++ = 0; 221 | return atoi(p); 222 | } 223 | 224 | return 0; 225 | } 226 | 227 | int ipv4_to_addr(char *p, int *addr) 228 | { 229 | return string_to_addr(p, addr, IPV4_LEN, IPV4_WIDTH, IPV4_CHAR); 230 | } 231 | 232 | int ipv6_to_addr(char *p, int *addr) 233 | { 234 | return string_to_addr(p, addr, IPV6_LEN, IPV6_WIDTH, IPV6_CHAR); 235 | } 236 | 237 | int fc_to_addr(char *p, int *addr) 238 | { 239 | return string_to_addr(p, addr, FC_LEN, FC_WIDTH, FC_CHAR); 240 | } 241 | 242 | static const char *arg_str(const char * const *strings, size_t array_size, 243 | size_t idx) 244 | { 245 | if (idx < array_size && strings[idx]) 246 | return strings[idx]; 247 | 248 | return "unrecognized"; 249 | } 250 | 251 | static const char * const trtypes[] = { 252 | [NVMF_TRTYPE_RDMA] = "rdma", 253 | [NVMF_TRTYPE_FC] = "fc", 254 | [NVMF_TRTYPE_LOOP] = "loop", 255 | [NVMF_TRTYPE_TCP] = "tcp", 256 | }; 257 | 258 | const char *trtype_str(u8 trtype) 259 | { 260 | return arg_str(trtypes, NUM_ENTRIES(trtypes), trtype); 261 | } 262 | 263 | static const char * const adrfams[] = { 264 | [NVMF_ADDR_FAMILY_PCI] = "pci", 265 | [NVMF_ADDR_FAMILY_IP4] = "ipv4", 266 | [NVMF_ADDR_FAMILY_IP6] = "ipv6", 267 | [NVMF_ADDR_FAMILY_IB] = "ib", 268 | [NVMF_ADDR_FAMILY_FC] = "fc", 269 | }; 270 | 271 | const char *adrfam_str(u8 adrfam) 272 | { 273 | return arg_str(adrfams, NUM_ENTRIES(adrfams), adrfam); 274 | } 275 | 276 | static const char * const subtypes[] = { 277 | [NVME_NQN_DISC] = "discovery subsystem", 278 | [NVME_NQN_NVME] = "nvme subsystem", 279 | }; 280 | 281 | const char *subtype_str(u8 subtype) 282 | { 283 | return arg_str(subtypes, NUM_ENTRIES(subtypes), subtype); 284 | } 285 | 286 | static const char * const treqs[] = { 287 | [NVMF_TREQ_NOT_SPECIFIED] = "not specified", 288 | [NVMF_TREQ_REQUIRED] = "required", 289 | [NVMF_TREQ_NOT_REQUIRED] = "not required", 290 | }; 291 | 292 | const char *treq_str(u8 treq) 293 | { 294 | return arg_str(treqs, NUM_ENTRIES(treqs), treq); 295 | } 296 | 297 | static const char * const prtypes[] = { 298 | [NVMF_RDMA_PRTYPE_NOT_SPECIFIED] = "not specified", 299 | [NVMF_RDMA_PRTYPE_IB] = "infiniband", 300 | [NVMF_RDMA_PRTYPE_ROCE] = "roce", 301 | [NVMF_RDMA_PRTYPE_ROCEV2] = "roce-v2", 302 | [NVMF_RDMA_PRTYPE_IWARP] = "iwarp", 303 | }; 304 | 305 | const char *prtype_str(u8 prtype) 306 | { 307 | return arg_str(prtypes, NUM_ENTRIES(prtypes), prtype); 308 | } 309 | 310 | static const char * const qptypes[] = { 311 | [NVMF_RDMA_QPTYPE_CONNECTED] = "connected", 312 | [NVMF_RDMA_QPTYPE_DATAGRAM] = "datagram", 313 | }; 314 | 315 | const char *qptype_str(u8 qptype) 316 | { 317 | return arg_str(qptypes, NUM_ENTRIES(qptypes), qptype); 318 | } 319 | 320 | static const char * const cms[] = { 321 | [NVMF_RDMA_CMS_RDMA_CM] = "rdma-cm", 322 | }; 323 | 324 | const char *cms_str(u8 cm) 325 | { 326 | return arg_str(cms, NUM_ENTRIES(cms), cm); 327 | } 328 | 329 | u8 to_trtype(char *str) 330 | { 331 | if (strcmp(str, TRTYPE_STR_RDMA) == 0) 332 | return NVMF_TRTYPE_RDMA; 333 | if (strcmp(str, TRTYPE_STR_FC) == 0) 334 | return NVMF_TRTYPE_FC; 335 | if (strcmp(str, TRTYPE_STR_TCP) == 0) 336 | return NVMF_TRTYPE_TCP; 337 | return 0; 338 | } 339 | 340 | u8 to_adrfam(char *str) 341 | { 342 | if (strcmp(str, ADRFAM_STR_IPV4) == 0) 343 | return NVMF_ADDR_FAMILY_IP4; 344 | if (strcmp(str, ADRFAM_STR_IPV6) == 0) 345 | return NVMF_ADDR_FAMILY_IP6; 346 | if (strcmp(str, ADRFAM_STR_FC) == 0) 347 | return NVMF_ADDR_FAMILY_FC; 348 | return 0; 349 | } 350 | -------------------------------------------------------------------------------- /src/dem/common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #ifndef __COMMON_H__ 36 | #define __COMMON_H__ 37 | 38 | #define unlikely __glibc_unlikely 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #include "nvme.h" 54 | #include "utils.h" 55 | #include "ops.h" 56 | #include "json.h" 57 | #include "tags.h" 58 | #include "dem.h" 59 | 60 | #define JSARRAY "\"%s\":[" 61 | #define JSEMPTYARRAY "\"%s\":[]" 62 | #define JSSTR "\"%s\":\"%s\"" 63 | #define JSINT "\"%s\":%lld" 64 | #define JSINDX "\"%s\":%d" 65 | #define JSENTRY "%s\"%s\"" 66 | 67 | extern int debug; 68 | extern int curl_show_results; 69 | extern int num_interfaces; 70 | extern struct host_iface *interfaces; 71 | extern struct linked_list *aen_req_list; 72 | extern struct linked_list *target_list; 73 | extern struct linked_list *group_list; 74 | extern struct linked_list *host_list; 75 | 76 | #define PATH_NVME_FABRICS "/dev/nvme-fabrics" 77 | #define PATH_NVMF_DEM_DISC "/etc/nvme/nvmeof-dem/" 78 | #define NUM_CONFIG_ITEMS 3 79 | #define CONFIG_TYPE_SIZE 8 80 | #define CONFIG_FAMILY_SIZE 8 81 | #define CONFIG_ADDRESS_SIZE 40 82 | #define CONFIG_PORT_SIZE 8 83 | #define CONFIG_DEVICE_SIZE 256 84 | #define LARGEST_TAG 8 85 | #define LARGEST_VAL 40 86 | #define ADDR_LEN 16 /* IPV6 is current longest address */ 87 | #define DISCOVERY_CTRL_NQN "DEM_Discovery_Controller" 88 | 89 | enum {RESTRICTED = 0, ALLOW_ANY = 1, UNDEFINED_ACCESS = -1}; 90 | enum {GROUP_EVENT = 0, PORT_EVENT, SUBSYS_EVENT, ACL_EVENT}; 91 | 92 | #define is_restricted(subsys) (subsys->access == RESTRICTED) 93 | 94 | struct target; 95 | 96 | struct portid { 97 | struct linked_list node; 98 | int portid; 99 | char type[CONFIG_TYPE_SIZE + 1]; 100 | char family[CONFIG_FAMILY_SIZE + 1]; 101 | char address[CONFIG_ADDRESS_SIZE + 1]; 102 | char port[CONFIG_PORT_SIZE + 1]; 103 | int port_num; 104 | int addr[ADDR_LEN]; 105 | int treq; 106 | int adrfam; 107 | int trtype; 108 | int valid; 109 | int kato; 110 | }; 111 | 112 | struct host_iface { 113 | char type[CONFIG_TYPE_SIZE + 1]; 114 | char family[CONFIG_FAMILY_SIZE + 1]; 115 | char address[CONFIG_ADDRESS_SIZE + 1]; 116 | int addr[ADDR_LEN]; 117 | char port[CONFIG_PORT_SIZE + 1]; 118 | struct xp_pep *listener; 119 | struct xp_ops *ops; 120 | }; 121 | 122 | struct oob_iface { 123 | char address[CONFIG_ADDRESS_SIZE + 1]; 124 | int port; 125 | }; 126 | 127 | struct host { 128 | struct linked_list node; 129 | struct subsystem *subsystem; 130 | char alias[MAX_ALIAS_SIZE + 1]; 131 | char nqn[MAX_NQN_SIZE + 1]; 132 | }; 133 | 134 | struct ns { 135 | struct linked_list node; 136 | int nsid; 137 | int devid; 138 | int devns; 139 | // TODO add bits for multipath and partitions 140 | }; 141 | 142 | struct logpage { 143 | struct linked_list node; 144 | struct portid *portid; 145 | struct nvmf_disc_rsp_page_entry e; 146 | int valid; 147 | }; 148 | 149 | struct subsystem { 150 | struct linked_list node; 151 | struct linked_list host_list; 152 | struct linked_list ns_list; 153 | struct linked_list logpage_list; 154 | struct target *target; 155 | char nqn[MAX_NQN_SIZE + 1]; 156 | int access; 157 | }; 158 | 159 | struct nsdev { 160 | struct linked_list node; 161 | int nsdev; 162 | int nsid; 163 | int valid; 164 | // TODO add bits for multipath and partitions 165 | }; 166 | 167 | struct fabric_iface { 168 | struct linked_list node; 169 | char type[CONFIG_TYPE_SIZE + 1]; 170 | char fam[CONFIG_FAMILY_SIZE + 1]; 171 | char addr[CONFIG_ADDRESS_SIZE + 1]; 172 | int valid; 173 | }; 174 | 175 | union sc_iface { 176 | struct oob_iface oob; 177 | struct ctrl_queue inb; 178 | }; 179 | 180 | struct target { 181 | struct linked_list node; 182 | struct linked_list subsys_list; 183 | struct linked_list portid_list; 184 | struct linked_list device_list; 185 | struct linked_list discovery_queue_list; 186 | struct linked_list unattached_logpage_list; 187 | struct linked_list fabric_iface_list; 188 | struct host_iface *iface; 189 | json_t *json; 190 | union sc_iface sc_iface; 191 | char alias[MAX_ALIAS_SIZE + 1]; 192 | int mgmt_mode; 193 | int refresh; 194 | int log_page_retry_count; 195 | int refresh_countdown; 196 | int kato_countdown; 197 | bool group_member; 198 | }; 199 | 200 | struct group { 201 | struct linked_list node; 202 | struct linked_list target_list; 203 | char name[MAX_ALIAS_SIZE + 1]; 204 | }; 205 | 206 | struct group_target_link { 207 | struct linked_list node; 208 | struct target *target; 209 | }; 210 | 211 | struct group_host_link { 212 | struct linked_list node; 213 | struct group *group; 214 | char alias[MAX_ALIAS_SIZE + 1]; 215 | char nqn[MAX_NQN_SIZE + 1]; 216 | }; 217 | 218 | struct event_notification { 219 | struct linked_list node; 220 | struct endpoint *ep; 221 | struct event_notification *req; 222 | char nqn[MAX_NQN_SIZE + 1]; 223 | int valid; 224 | }; 225 | 226 | struct mg_connection; 227 | struct mg_str; 228 | 229 | extern char shared_nqn[]; 230 | 231 | extern struct mg_str s_signature_user; 232 | extern struct mg_str *s_signature; 233 | 234 | void shutdown_dem(void); 235 | void handle_http_request(struct mg_connection *c, void *ev_data); 236 | 237 | int init_json(char *filename); 238 | void cleanup_json(void); 239 | void json_spinlock(void); 240 | void json_spinunlock(void); 241 | 242 | int init_interfaces(void); 243 | void *interface_thread(void *arg); 244 | 245 | int start_pseudo_target(struct host_iface *iface); 246 | int run_pseudo_target(struct endpoint *ep, void *id); 247 | 248 | void build_lists(void); 249 | struct group *init_group(char *name); 250 | void add_host_to_group(struct group *group, char *alias); 251 | void add_target_to_group(struct group *group, char *alias); 252 | bool shared_group(struct target *target, char *nqn); 253 | bool indirect_shared_group(struct target *target, char *alias); 254 | struct target *find_target(char *alias); 255 | 256 | struct subsystem *new_subsys(struct target *target, char *nqn); 257 | 258 | void refresh_log_pages(struct target *target); 259 | void fetch_log_pages(struct ctrl_queue *dq); 260 | void del_unattached_logpage_list(struct target *target); 261 | 262 | void create_discovery_queue(struct target *target, struct subsystem *subsys, 263 | struct portid *portid); 264 | int target_reconfig(char *alias); 265 | int target_refresh(char *alias); 266 | int target_usage(char *alias, char **results); 267 | int target_logpage(char *alias, char **results); 268 | int host_logpage(char *alias, char **results); 269 | 270 | int get_config(struct target *target); 271 | int config_target(struct target *target); 272 | 273 | struct target *alloc_target(char *alias); 274 | 275 | int get_mgmt_mode(char *mode); 276 | 277 | #endif 278 | -------------------------------------------------------------------------------- /src/dem/json.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #include 36 | 37 | struct target; 38 | struct subsystem; 39 | struct ns; 40 | struct portid; 41 | struct host; 42 | union sc_iface; 43 | struct nsdev; 44 | struct fabric_iface; 45 | 46 | struct json_context *get_json_context(void); 47 | void store_json_config_file(void); 48 | 49 | int list_json_group(char **resp); 50 | int show_json_group(char *grp, char **resp); 51 | int add_json_group(char *grp, char *resp); 52 | int update_json_group(char *grp, char *data, char *resp, char *new_name); 53 | int set_json_group_target(char *alias, char *data, char *resp); 54 | int set_json_group_host(char *host, char *data, char *resp); 55 | int del_json_group(char *grp, char *resp); 56 | int set_json_group_member(char *group, char *data, char *alias, char *tag, 57 | char *parent_tag, char *resp, char *_alias); 58 | int del_json_group_member(char *group, char *member, char *tag, 59 | char *parent_tag, char *resp); 60 | 61 | int add_json_target(char *alias, char *resp); 62 | int update_json_target(char *alias, char *data, char *resp, 63 | struct target *target); 64 | int list_json_target(char *query, char **resp); 65 | int show_json_target(char *alias, char **resp); 66 | int del_json_target(char *alias, char *resp); 67 | 68 | int add_json_host(char *alias, char *resp); 69 | int update_json_host(char *alias, char *data, char *resp, 70 | char *newalias, char *nqn); 71 | int list_json_host(char **resp); 72 | int show_json_host(char *alias, char **resp); 73 | int del_json_host(char *alias, char *resp, char *nqn); 74 | int get_json_host_nqn(char *host, char *nqn); 75 | 76 | int set_json_subsys(char *alias, char *subnqn, char *data, char *resp, 77 | struct subsystem *subsys); 78 | int del_json_subsys(char *alias, char *subnqn, char *resp); 79 | 80 | int set_json_inb_interface(char *target, char *data, char *resp, 81 | union sc_iface *face); 82 | int set_json_oob_interface(char *target, char *data, char *resp, 83 | union sc_iface *face); 84 | int set_json_portid(char *target, int id, char *data, char *resp, 85 | struct portid *portid); 86 | int del_json_portid(char *alias, int id, char *resp); 87 | 88 | int set_json_ns(char *alias, char *subnqn, char *data, char *resp, 89 | struct ns *ns); 90 | int del_json_ns(char *alias, char *subnqn, int ns, char *resp); 91 | int set_json_acl(char *tgt, char *subnqn, char *alias, char *data, 92 | char *resp, char *newalias, char *hostnqn); 93 | int del_json_acl(char *alias, char *subnqn, char *host, char *resp); 94 | 95 | int list_group(char *resp); 96 | int show_group(char *grp, char *resp); 97 | int add_group(char *grp, char *resp); 98 | int update_group(char *grp, char *data, char *resp); 99 | int set_group_target(char *alias, char *data, char *resp); 100 | int set_group_host(char *host, char *data, char *resp); 101 | int del_group(char *grp, char *resp); 102 | int set_group_member(char *group, char *data, char *alias, char *tag, 103 | char *parent_tag, char *resp); 104 | int del_group_member(char *group, char *member, char *tag, char *parent_tag, 105 | char *resp); 106 | 107 | int add_target(char *alias, char *resp); 108 | int update_target(char *target, char *data, char *resp); 109 | int list_target(char *query, char *resp); 110 | int show_target(char *alias, char *resp); 111 | int del_target(char *alias, char *resp); 112 | 113 | int add_host(char *host, char *resp); 114 | int update_host(char *host, char *data, char *resp); 115 | int list_host(char *resp); 116 | int show_host(char *host, char *resp); 117 | int del_host(char *host, char *resp); 118 | 119 | int set_subsys(char *alias, char *subnqn, char *data, char *resp); 120 | int del_subsys(char *alias, char *subnqn, char *resp); 121 | 122 | int set_interface(char *target, char *data, char *resp); 123 | int set_portid(char *target, int portid, char *data, 124 | char *resp); 125 | int del_portid(char *alias, int portid, char *resp); 126 | 127 | int set_ns(char *alias, char *subnqn, char *data, char *resp); 128 | int del_ns(char *alias, char *subnqn, int ns, char *resp); 129 | 130 | int link_host(char *alias, char *subnqn, char *host, char *data, char *resp); 131 | int unlink_host(char *alias, char *subnqn, char *host, char *resp); 132 | 133 | int set_json_oob_nsdevs(struct target *target, char *data); 134 | int set_json_oob_interfaces(struct target *target, char *data); 135 | 136 | int set_json_inb_nsdev(struct target *target, struct nsdev *nsdev); 137 | int init_json_inb_fabric_iface(struct target *target); 138 | int set_json_inb_fabric_iface(struct target *target, 139 | struct fabric_iface *iface); 140 | 141 | int update_signature(char *data, char *resp); 142 | 143 | #define MAX_STRING 128 144 | 145 | struct json_context { 146 | pthread_spinlock_t lock; 147 | json_t *root; 148 | char filename[128]; 149 | }; 150 | 151 | /* json parsing helpers */ 152 | 153 | #define json_set_string(x, y, z) \ 154 | do { \ 155 | tmp = json_object_get(x, y); \ 156 | if (tmp) \ 157 | json_string_set(tmp, z); \ 158 | else \ 159 | json_object_set_new(x, y, json_string(z)); \ 160 | } while (0) 161 | #define json_set_int(x, y, z) \ 162 | do {\ 163 | tmp = json_object_get(x, y); \ 164 | if (tmp) \ 165 | json_integer_set(tmp, z); \ 166 | else \ 167 | json_object_set_new(x, y, json_integer(z)); \ 168 | } while (0) 169 | #define json_get_subgroup(x, y, z) \ 170 | do { \ 171 | if (json_is_object(x)) { \ 172 | z = json_object_get(x, y); \ 173 | if (!z) {\ 174 | z = json_object(); \ 175 | json_object_set_new(x, y, z); \ 176 | } else if (!json_is_object(z)) \ 177 | fprintf(stderr, \ 178 | "%s(%d) Bad Target expect object\n", \ 179 | __func__, __LINE__), z = NULL; \ 180 | } else \ 181 | fprintf(stderr, "%s(%d) Bad Group Object\n", \ 182 | __func__, __LINE__), z = NULL; \ 183 | } while (0) 184 | #define json_get_array(x, y, z) \ 185 | do { \ 186 | if (json_is_object(x)) { \ 187 | z = json_object_get(x, y); \ 188 | if (!z) { \ 189 | z = json_array(); \ 190 | json_object_set_new(x, y, z); \ 191 | } else if (!json_is_array(z)) \ 192 | fprintf(stderr, \ 193 | "%s(%d) Bad Target expect array\n", \ 194 | __func__, __LINE__), z = NULL; \ 195 | } else \ 196 | fprintf(stderr, "%s(%d) Bad Group Object\n", \ 197 | __func__, __LINE__), z = NULL; \ 198 | } while (0) 199 | #define json_update_string(w, x, y, z) \ 200 | do { \ 201 | z = json_object_get(x, y); \ 202 | if (z) { \ 203 | if (json_is_object(w)) \ 204 | json_set_string(w, y, \ 205 | json_string_value(z)); \ 206 | else \ 207 | fprintf(stderr, "%s(%d) Bad type\n", \ 208 | __func__, __LINE__); \ 209 | } \ 210 | } while (0) 211 | #define json_update_int(w, x, y, z) \ 212 | do { \ 213 | z = json_object_get(x, y); \ 214 | if (z) { \ 215 | if (json_is_object(w)) \ 216 | json_set_int(w, y, \ 217 | json_integer_value(z)); \ 218 | else \ 219 | fprintf(stderr, "%s(%d) Bad type\n", \ 220 | __func__, __LINE__); \ 221 | } \ 222 | } while (0) 223 | #define json_update_string_ex(w, x, y, z, res) \ 224 | do { \ 225 | z = json_object_get(x, y); \ 226 | if (z) { \ 227 | if (json_is_object(w)) { \ 228 | json_set_string(w, y, \ 229 | json_string_value(z)); \ 230 | strcpy(res, (char *) json_string_value(z)); \ 231 | } else \ 232 | fprintf(stderr, "%s(%d) Bad type\n", \ 233 | __func__, __LINE__); \ 234 | } \ 235 | } while (0) 236 | #define json_update_int_ex(w, x, y, z, res) \ 237 | do { \ 238 | z = json_object_get(x, y); \ 239 | if (z) { \ 240 | if (json_is_object(w)) { \ 241 | json_set_int(w, y, \ 242 | json_integer_value(z)); \ 243 | res = json_integer_value(z); \ 244 | } else \ 245 | fprintf(stderr, "%s(%d) Bad type\n", \ 246 | __func__, __LINE__); \ 247 | } \ 248 | } while (0) 249 | 250 | /* json output helpers */ 251 | 252 | #define JSARRAY "\"%s\":[" 253 | #define JSEMPTYARRAY "\"%s\":[]" 254 | #define JSSTR "\"%s\":\"%s\"" 255 | #define JSINT "\"%s\":%lld" 256 | 257 | #define array_json_string(obj, p, i, n) \ 258 | do { \ 259 | n = sprintf(p, "%s\"%s\"", i ? "," : "", \ 260 | json_string_value(obj)); \ 261 | p += n; \ 262 | } while (0) 263 | #define start_json_array(tag, p, n) \ 264 | do { \ 265 | n = sprintf(p, JSARRAY, tag); \ 266 | p += n; \ 267 | } while (0) 268 | #define end_json_array(p, n) \ 269 | do { \ 270 | n = sprintf(p, "]"); \ 271 | p += n; \ 272 | } while (0) 273 | -------------------------------------------------------------------------------- /src/dem/logpages.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: DUAL GPL-2.0/BSD 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "common.h" 44 | 45 | void del_unattached_logpage_list(struct target *target) 46 | { 47 | struct logpage *lp, *n; 48 | 49 | list_for_each_entry_safe(lp, n, &target->unattached_logpage_list, 50 | node) { 51 | list_del(&lp->node); 52 | free(lp); 53 | } 54 | } 55 | 56 | static inline void invalidate_log_pages(struct target *target) 57 | { 58 | struct subsystem *subsys; 59 | struct logpage *logpage; 60 | 61 | list_for_each_entry(subsys, &target->subsys_list, node) 62 | list_for_each_entry(logpage, &subsys->logpage_list, node) 63 | logpage->valid = 0; 64 | 65 | del_unattached_logpage_list(target); 66 | } 67 | 68 | static inline int match_logpage(struct logpage *logpage, 69 | struct nvmf_disc_rsp_page_entry *e) 70 | { 71 | if (strcmp(e->traddr, logpage->e.traddr) || 72 | strcmp(e->trsvcid, logpage->e.trsvcid) || 73 | e->trtype != logpage->e.trtype || 74 | e->adrfam != logpage->e.adrfam) 75 | return 0; 76 | return 1; 77 | } 78 | 79 | static inline void store_logpage(struct logpage *logpage, 80 | struct nvmf_disc_rsp_page_entry *e, 81 | struct ctrl_queue *dq) 82 | { 83 | logpage->e = *e; 84 | logpage->valid = 1; 85 | logpage->portid = dq->portid; 86 | } 87 | 88 | static void save_log_pages(struct nvmf_disc_rsp_page_hdr *log, int numrec, 89 | struct target *target, struct ctrl_queue *dq) 90 | { 91 | int i; 92 | int found; 93 | int create; 94 | struct subsystem *subsys; 95 | struct logpage *logpage, *lp; 96 | struct nvmf_disc_rsp_page_entry *e; 97 | 98 | for (i = 0; i < numrec; i++) { 99 | e = &log->entries[i]; 100 | found = 0; 101 | create = 1; 102 | list_for_each_entry(subsys, &target->subsys_list, node) 103 | if ((strcmp(subsys->nqn, e->subnqn) == 0)) { 104 | found = 1; 105 | list_for_each_entry(logpage, 106 | &subsys->logpage_list, 107 | node) 108 | if (match_logpage(logpage, e)) { 109 | store_logpage(logpage, e, dq); 110 | create = 0; 111 | goto next; 112 | } 113 | next: 114 | break; 115 | } 116 | 117 | if (!create) 118 | continue; 119 | 120 | logpage = malloc(sizeof(*logpage)); 121 | if (!logpage) { 122 | print_err("alloc new logpage failed"); 123 | return; 124 | } 125 | 126 | store_logpage(logpage, e, dq); 127 | 128 | if (found) { 129 | list_add_tail(&logpage->node, &subsys->logpage_list); 130 | continue; 131 | } 132 | 133 | list_for_each_entry(lp, &target->unattached_logpage_list, node) 134 | if (!strcmp(lp->e.subnqn, e->subnqn) && 135 | match_logpage(lp, e)) { 136 | found = 1; 137 | free(logpage); 138 | break; 139 | } 140 | 141 | if (!found) 142 | list_add_tail(&logpage->node, 143 | &target->unattached_logpage_list); 144 | } 145 | } 146 | 147 | void fetch_log_pages(struct ctrl_queue *dq) 148 | { 149 | struct nvmf_disc_rsp_page_hdr *log = NULL; 150 | struct target *target = dq->target; 151 | u32 num_records = 0; 152 | 153 | if (get_logpages(dq, &log, &num_records)) { 154 | print_err("get logpages for target %s failed", target->alias); 155 | return; 156 | } 157 | 158 | save_log_pages(log, num_records, target, dq); 159 | 160 | print_discovery_log(log, num_records); 161 | 162 | free(log); 163 | } 164 | 165 | static int target_with_allow_any_subsys(struct target *target) 166 | { 167 | struct subsystem *subsys; 168 | 169 | list_for_each_entry(subsys, &target->subsys_list, node) 170 | if (!is_restricted(subsys)) 171 | return 1; 172 | 173 | return 0; 174 | } 175 | 176 | static int avilable_dq(struct ctrl_queue *dq) 177 | { 178 | if (!dq->subsys) 179 | return target_with_allow_any_subsys(dq->target); 180 | 181 | return !list_empty(&dq->subsys->host_list); 182 | } 183 | 184 | void refresh_log_pages(struct target *target) 185 | { 186 | struct ctrl_queue *dq; 187 | 188 | invalidate_log_pages(target); 189 | 190 | list_for_each_entry(dq, &target->discovery_queue_list, node) { 191 | if (!dq->connected) { 192 | if (!avilable_dq(dq)) 193 | continue; 194 | if (connect_ctrl(dq)) { 195 | target->log_page_retry_count = LOG_PAGE_RETRY; 196 | continue; 197 | } 198 | } 199 | 200 | fetch_log_pages(dq); 201 | 202 | if (dq->failed_kato) 203 | disconnect_ctrl(dq, 0); 204 | } 205 | } 206 | 207 | static void format_logpage(char *buf, struct nvmf_disc_rsp_page_entry *e) 208 | { 209 | int n; 210 | char *p = buf; 211 | 212 | n = sprintf(p, "

subnqn=\"%s\" ", e->subnqn); 213 | p += n; 214 | n = sprintf(p, "subtype=\"%s\" ", subtype_str(e->subtype)); 215 | p += n; 216 | n = sprintf(p, "portid=%d ", e->portid); 217 | p += n; 218 | n = sprintf(p, "trtype=\"%s\" ", trtype_str(e->trtype)); 219 | p += n; 220 | n = sprintf(p, "adrfam=\"%s\" ", adrfam_str(e->adrfam)); 221 | p += n; 222 | n = sprintf(p, "traddr=%s ", e->traddr); 223 | p += n; 224 | n = sprintf(p, "trsvcid=%s ", e->trsvcid); 225 | p += n; 226 | n = sprintf(p, "treq=\"%s\"
", treq_str(e->treq)); 227 | p += n; 228 | 229 | switch (e->trtype) { 230 | case NVMF_TRTYPE_RDMA: 231 | n = sprintf(p, "   rdma: "); 232 | p += n; 233 | n = sprintf(p, "prtype=\"%s\" ", 234 | prtype_str(e->tsas.rdma.prtype)); 235 | p += n; 236 | n = sprintf(p, "qptype=\"%s\" ", 237 | qptype_str(e->tsas.rdma.qptype)); 238 | p += n; 239 | n = sprintf(p, "cms=\"%s\" ", cms_str(e->tsas.rdma.cms)); 240 | p += n; 241 | n = sprintf(p, "pkey=0x%04x", e->tsas.rdma.pkey); 242 | p += n; 243 | break; 244 | } 245 | n = sprintf(p, "

"); 246 | p += n; 247 | } 248 | 249 | int target_logpage(char *alias, char **resp) 250 | { 251 | struct target *target; 252 | struct subsystem *subsys; 253 | struct logpage *logpage; 254 | char buf[MAX_BODY_SIZE + 1]; 255 | char *p = *resp; 256 | u64 n, len = 0; 257 | u64 bytes = MAX_BODY_SIZE; 258 | 259 | list_for_each_entry(target, target_list, node) 260 | if (!strcmp(target->alias, alias)) 261 | goto found; 262 | 263 | return -ENOENT; 264 | found: 265 | list_for_each_entry(subsys, &target->subsys_list, node) 266 | list_for_each_entry(logpage, &subsys->logpage_list, node) { 267 | if (!logpage->valid) 268 | continue; 269 | 270 | format_logpage(buf, &logpage->e); 271 | 272 | if ((len + strlen(buf)) > bytes) { 273 | bytes += MAX_BODY_SIZE; 274 | p = realloc(*resp, bytes); 275 | if (!p) 276 | return -ENOMEM; 277 | *resp = p; 278 | p += len; 279 | } 280 | strcpy(p, buf); 281 | n = strlen(buf); 282 | p += n; 283 | len += n; 284 | } 285 | 286 | if (list_empty(&target->unattached_logpage_list)) 287 | goto out; 288 | 289 | sprintf(buf, "

Unattached Log Pages

"); 290 | if ((len + strlen(buf)) > bytes) { 291 | bytes += MAX_BODY_SIZE; 292 | p = realloc(*resp, bytes); 293 | if (!p) 294 | return -ENOMEM; 295 | *resp = p; 296 | p += len; 297 | } 298 | strcpy(p, buf); 299 | n = strlen(buf); 300 | p += n; 301 | len += n; 302 | 303 | list_for_each_entry(logpage, &target->unattached_logpage_list, node) { 304 | format_logpage(buf, &logpage->e); 305 | 306 | if ((len + strlen(buf)) > bytes) { 307 | bytes += MAX_BODY_SIZE; 308 | p = realloc(*resp, bytes); 309 | if (!p) 310 | return -ENOMEM; 311 | *resp = p; 312 | p += len; 313 | } 314 | strcpy(p, buf); 315 | n = strlen(buf); 316 | p += n; 317 | len += n; 318 | } 319 | 320 | out: 321 | if (!len) 322 | sprintf(*resp, "No valid Log Pages"); 323 | 324 | return 0; 325 | } 326 | 327 | int host_logpage(char *alias, char **resp) 328 | { 329 | struct host *host; 330 | struct target *target; 331 | struct subsystem *subsys; 332 | struct logpage *logpage; 333 | char buf[MAX_BODY_SIZE + 1]; 334 | char *p = *resp; 335 | u64 n, len = 0; 336 | u64 bytes = MAX_BODY_SIZE; 337 | 338 | list_for_each_entry(target, target_list, node) { 339 | if (target->group_member && 340 | !indirect_shared_group(target, alias)) 341 | continue; 342 | 343 | list_for_each_entry(subsys, &target->subsys_list, node) { 344 | if (!is_restricted(subsys)) 345 | goto found; 346 | 347 | list_for_each_entry(host, &subsys->host_list, node) 348 | if (!strcmp(alias, host->alias)) 349 | goto found; 350 | continue; 351 | found: 352 | list_for_each_entry(logpage, &subsys->logpage_list, 353 | node) { 354 | if (!logpage->valid) 355 | continue; 356 | 357 | format_logpage(buf, &logpage->e); 358 | 359 | if ((len + strlen(buf)) > bytes) { 360 | bytes += MAX_BODY_SIZE; 361 | p = realloc(*resp, bytes); 362 | if (!p) 363 | return -ENOMEM; 364 | *resp = p; 365 | p += len; 366 | } 367 | strcpy(p, buf); 368 | n = strlen(buf); 369 | p += n; 370 | len += n; 371 | } 372 | } 373 | } 374 | 375 | if (!len) 376 | sprintf(*resp, "No valid Log Pages"); 377 | 378 | return 0; 379 | } 380 | -------------------------------------------------------------------------------- /src/endpoint/common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #ifndef __COMMON_H__ 36 | #define __COMMON_H__ 37 | 38 | #define unlikely __glibc_unlikely 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include "nvme.h" 53 | #include "utils.h" 54 | #include "dem.h" 55 | 56 | extern int debug; 57 | extern struct linked_list *devices; 58 | extern struct linked_list *interfaces; 59 | 60 | #define IPV4_LEN 4 61 | #define IPV4_OFFSET 4 62 | #define IPV4_DELIM "." 63 | 64 | #define IPV6_LEN 8 65 | #define IPV6_OFFSET 8 66 | #define IPV6_DELIM ":" 67 | 68 | #define FC_LEN 8 69 | #define FC_OFFSET 4 70 | #define FC_DELIM ":" 71 | 72 | struct host { 73 | struct linked_list node; 74 | struct subsystem *subsystem; 75 | char nqn[MAX_NQN_SIZE + 1]; 76 | }; 77 | 78 | struct nsdev { 79 | struct linked_list node; 80 | int devid; 81 | int nsid; 82 | }; 83 | 84 | struct oob_iface { 85 | char type[CONFIG_TYPE_SIZE + 1]; 86 | char family[CONFIG_FAMILY_SIZE + 1]; 87 | char address[CONFIG_ADDRESS_SIZE + 1]; 88 | }; 89 | 90 | struct inb_iface { 91 | char type[CONFIG_TYPE_SIZE + 1]; 92 | char family[CONFIG_FAMILY_SIZE + 1]; 93 | char address[CONFIG_ADDRESS_SIZE + 1]; 94 | int addr[ADDR_LEN]; 95 | char port[CONFIG_PORT_SIZE + 1]; 96 | struct endpoint ep; 97 | struct xp_pep *listener; 98 | struct xp_ops *ops; 99 | int connected; 100 | }; 101 | 102 | struct host_iface { 103 | char type[CONFIG_TYPE_SIZE + 1]; 104 | char family[CONFIG_FAMILY_SIZE + 1]; 105 | char address[CONFIG_ADDRESS_SIZE + 1]; 106 | int addr[ADDR_LEN]; 107 | char port[CONFIG_PORT_SIZE + 1]; 108 | int port_num; 109 | int adrfam; 110 | struct endpoint ep; 111 | struct xp_pep *listener; 112 | struct xp_ops *ops; 113 | }; 114 | 115 | struct interface { 116 | struct linked_list node; 117 | int is_oob; 118 | union { 119 | struct oob_iface oob; 120 | struct inb_iface inb; 121 | } u; 122 | }; 123 | 124 | struct portid { 125 | struct linked_list node; 126 | int portid; 127 | char type[CONFIG_TYPE_SIZE + 1]; 128 | char family[CONFIG_FAMILY_SIZE + 1]; 129 | char address[CONFIG_ADDRESS_SIZE + 1]; 130 | char port[CONFIG_PORT_SIZE + 1]; 131 | int port_num; 132 | int addr[ADDR_LEN]; 133 | }; 134 | 135 | struct _portid { 136 | struct linked_list node; 137 | struct portid *portid; 138 | }; 139 | 140 | struct subsystem { 141 | struct linked_list node; 142 | struct linked_list host_list; 143 | struct linked_list portid_list; 144 | char nqn[MAX_NQN_SIZE + 1]; 145 | int allowany; 146 | }; 147 | 148 | struct target { 149 | struct host_iface *iface; 150 | char alias[MAX_ALIAS_SIZE + 1]; 151 | int mgmt_mode; 152 | int refresh; 153 | int log_page_retry_count; 154 | int refresh_countdown; 155 | int kato_countdown; 156 | }; 157 | 158 | struct ops { 159 | int (*delete_subsys)(char *subsys); 160 | int (*create_subsys)(char *subsys, int allowany); 161 | int (*create_ns)(char *subsys, int nsid, int devid, int devnsid); 162 | int (*delete_ns)(char *subsys, int nsid); 163 | int (*create_host)(char *host); 164 | int (*delete_host)(char *host); 165 | int (*create_portid)(int portid, char *fam, char *typ, int req, 166 | char *addr, int svcid); 167 | int (*delete_portid)(int portid); 168 | int (*link_host_to_subsys)(char *subsys, char *host); 169 | int (*unlink_host_from_subsys)(char *subsys, char *host); 170 | int (*link_port_to_subsys)(char *subsys, int portid); 171 | int (*unlink_port_from_subsys)(char *subsys, int portid); 172 | int (*enumerate_devices)(void); 173 | void (*reset_config)(void); 174 | int (*start_targets)(void); 175 | void (*stop_targets)(void); 176 | }; 177 | 178 | extern struct ops *ops; 179 | 180 | #ifdef CONFIG_CONFIGFS 181 | struct ops *cfgfs_register_ops(void); 182 | #endif 183 | 184 | #ifdef CONFIG_SPDK 185 | struct ops *spdk_register_ops(void); 186 | #endif 187 | 188 | struct mg_connection; 189 | 190 | void shutdown_dem(void); 191 | void handle_http_request(struct mg_connection *c, void *ev_data); 192 | 193 | void *interface_thread(void *arg); 194 | int start_pseudo_target(struct host_iface *iface); 195 | int run_pseudo_target(struct endpoint *ep, void *id); 196 | 197 | int enumerate_devices(void); 198 | int enumerate_interfaces(void); 199 | void free_devices(void); 200 | void free_interfaces(void); 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /src/endpoint/etc_config.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: DUAL GPL-2.0/BSD 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #define _GNU_SOURCE 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "common.h" 45 | #include "tags.h" 46 | 47 | static void addr_to_ipv4(__u8 *addr, char *str) 48 | { 49 | int i, n; 50 | 51 | addr += IPV4_OFFSET; 52 | for (i = 0; i < IPV4_LEN; i++, addr++, str += n) 53 | n = sprintf(str, "%s%u", i ? "." : "", *addr); 54 | } 55 | 56 | static void addr_to_ipv6(__u8 *_addr, char *str) 57 | { 58 | __u16 *addr; 59 | int i, n; 60 | 61 | _addr += IPV6_OFFSET; 62 | addr = (__u16 *) _addr; 63 | 64 | for (i = 0; i < IPV6_LEN; i++, addr++, str += n) 65 | n = sprintf(str, "%s%x", i ? IPV6_DELIM : "", 66 | htons(*addr)); 67 | } 68 | 69 | static void addr_to_fc(__u8 *addr, char *str) 70 | { 71 | int i, n; 72 | 73 | addr += FC_OFFSET; 74 | for (i = 0; i < FC_LEN; i++, addr++, str += n) 75 | n = sprintf(str, "%s%u", i ? FC_DELIM : "", *addr); 76 | } 77 | 78 | static void read_dem_config(FILE *fd, struct portid *iface) 79 | { 80 | int ret; 81 | char tag[LARGEST_TAG + 1]; 82 | char val[LARGEST_VAL + 1]; 83 | 84 | ret = parse_line(fd, tag, LARGEST_TAG, val, LARGEST_VAL); 85 | if (ret) 86 | return; 87 | 88 | if (strcasecmp(tag, TAG_TYPE) == 0) 89 | strncpy(iface->type, val, CONFIG_TYPE_SIZE); 90 | else if (strcasecmp(tag, TAG_FAMILY) == 0) 91 | strncpy(iface->family, val, CONFIG_FAMILY_SIZE); 92 | else if (strcasecmp(tag, TAG_ADDRESS) == 0) 93 | strncpy(iface->address, val, CONFIG_ADDRESS_SIZE); 94 | } 95 | 96 | int enumerate_interfaces(void) 97 | { 98 | struct dirent *entry; 99 | DIR *dir; 100 | FILE *fd; 101 | char config_file[FILENAME_MAX + 1]; 102 | struct portid *iface; 103 | int cnt = 0; 104 | int adrfam = 0; 105 | int ret; 106 | 107 | dir = opendir(PATH_NVMF_DEM_DISC); 108 | if (unlikely(!dir)) 109 | return -errno; 110 | 111 | for_each_dir(entry, dir) { 112 | if ((strcmp(entry->d_name, CONFIG_FILENAME) == 0) || 113 | (strcmp(entry->d_name, SIGNATURE_FILE_FILENAME) == 0)) 114 | continue; 115 | 116 | snprintf(config_file, FILENAME_MAX, "%s%s", 117 | PATH_NVMF_DEM_DISC, entry->d_name); 118 | 119 | fd = fopen(config_file, "r"); 120 | if (fd == NULL) 121 | continue; 122 | 123 | iface = malloc(sizeof(*iface)); 124 | if (!iface) { 125 | fclose(fd); 126 | cnt = -ENOMEM; 127 | free_interfaces(); 128 | goto out2; 129 | } 130 | 131 | memset(iface, 0, sizeof(*iface)); 132 | 133 | while (!feof(fd)) 134 | read_dem_config(fd, iface); 135 | 136 | fclose(fd); 137 | 138 | if (!valid_trtype(iface->type)) { 139 | print_info("Invalid trtype"); 140 | free(iface); 141 | continue; 142 | } 143 | 144 | adrfam = set_adrfam(iface->family); 145 | if (!adrfam) { 146 | print_info("Invalid adrfam"); 147 | free(iface); 148 | continue; 149 | } 150 | 151 | switch (adrfam) { 152 | case NVMF_ADDR_FAMILY_IP4: 153 | ret = ipv4_to_addr(iface->address, iface->addr); 154 | break; 155 | case NVMF_ADDR_FAMILY_IP6: 156 | ret = ipv6_to_addr(iface->address, iface->addr); 157 | break; 158 | case NVMF_ADDR_FAMILY_FC: 159 | ret = fc_to_addr(iface->address, iface->addr); 160 | break; 161 | default: 162 | ret = -EINVAL; 163 | } 164 | 165 | if (ret < 0) { 166 | print_err("ignored invalid traddr %s", iface->address); 167 | free(iface); 168 | continue; 169 | } 170 | 171 | print_debug("adding interface for %s %s %s", 172 | iface->type, iface->family, iface->address); 173 | 174 | list_add_tail(&iface->node, interfaces); 175 | cnt++; 176 | } 177 | out2: 178 | return cnt; 179 | } 180 | 181 | void free_interfaces(void) 182 | { 183 | struct linked_list *p; 184 | struct linked_list *n; 185 | struct portid *iface; 186 | 187 | list_for_each_safe(p, n, interfaces) { 188 | list_del(p); 189 | iface = container_of(p, struct portid, node); 190 | free(iface); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/incl/curl.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | int init_curl(int debug); 36 | void cleanup_curl(void); 37 | int exec_get(char *url, char **result); 38 | int exec_delete(char *url); 39 | int exec_delete_ex(char *url, char *data, int len); 40 | int exec_put(char *url, char *data, int len); 41 | int exec_post(char *url, char *data, int len); 42 | int exec_patch(char *url, char *data, int len); 43 | -------------------------------------------------------------------------------- /src/incl/dem.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #ifndef __DEM_H__ 36 | #define __DEM_H__ 37 | 38 | #include 39 | 40 | #define unlikely __glibc_unlikely 41 | 42 | #define NVMF_UUID_FMT "nqn.2014-08.org.nvmexpress:uuid:%s" 43 | 44 | #define PAGE_SIZE 4096 45 | #define BUF_SIZE 4096 46 | #define BODY_SIZE 1024 47 | #define NVMF_DQ_DEPTH 2 48 | #define IDLE_TIMEOUT 100 49 | #define MINUTES (60 * 1000) /* convert ms to minutes */ 50 | #define LOG_PAGE_RETRY 200 51 | 52 | #define NULLB_DEVID -1 53 | 54 | #define CONFIG_DIR "/etc/nvme/nvmeof-dem/" 55 | #define CONFIG_FILENAME "config" 56 | #define SIGNATURE_FILE_FILENAME "signature" 57 | #define CONFIG_FILE (CONFIG_DIR CONFIG_FILENAME) 58 | #define SIGNATURE_FILE (CONFIG_DIR SIGNATURE_FILE_FILENAME) 59 | 60 | extern int stopped; 61 | 62 | enum { DISCONNECTED, CONNECTED }; 63 | 64 | static inline u32 get_unaligned_le24(const u8 *p) 65 | { 66 | return (u32) p[0] | (u32) p[1] << 8 | (u32) p[2] << 16; 67 | } 68 | 69 | static inline u32 get_unaligned_le32(const u8 *p) 70 | { 71 | return (u32) p[0] | (u32) p[1] << 8 | 72 | (u32) p[2] << 16 | (u32) p[3] << 24; 73 | } 74 | 75 | static inline int msec_delta(struct timeval t0) 76 | { 77 | struct timeval t1; 78 | 79 | gettimeofday(&t1, NULL); 80 | 81 | return (t1.tv_sec - t0.tv_sec) * 1000 + 82 | (t1.tv_usec - t0.tv_usec) / 1000; 83 | } 84 | 85 | #define UUID_LEN 36 86 | #define UUID_PARTS 6 87 | #define UUID_FORMAT "%08X-%04X-%04X-%04X-%08X%04X" 88 | 89 | #define U32_MASK 0xFFFFFFFF 90 | #define U16_MASK 0XFFFF 91 | #define U14_MASK 0X3FFF 92 | #define U12_MASK 0x0FFF 93 | 94 | static inline void gen_uuid(char *uuid) 95 | { 96 | struct timespec t; 97 | u32 p[UUID_PARTS]; 98 | u32 mask[UUID_PARTS] = { 99 | U32_MASK, U16_MASK, U12_MASK, U14_MASK, U32_MASK, U16_MASK }; 100 | int i; 101 | 102 | clock_gettime(CLOCK_REALTIME, &t); 103 | 104 | srand(t.tv_nsec); 105 | 106 | for (i = 0; i < UUID_PARTS; i++) 107 | p[i] = rand() & mask[i]; 108 | 109 | p[2] |= 0x4000; 110 | p[3] |= 0x8000; 111 | 112 | snprintf(uuid, UUID_LEN + 1, UUID_FORMAT, 113 | U32_MASK & p[0], U16_MASK & p[1], U16_MASK & p[2], 114 | U16_MASK & p[3], U32_MASK & p[4], U16_MASK & p[5]); 115 | } 116 | 117 | #define PATH_NVME_FABRICS "/dev/nvme-fabrics" 118 | #define PATH_NVMF_DEM_DISC "/etc/nvme/nvmeof-dem/" 119 | #define NUM_CONFIG_ITEMS 3 120 | #define CONFIG_TYPE_SIZE 8 121 | #define CONFIG_FAMILY_SIZE 8 122 | #define CONFIG_ADDRESS_SIZE 40 123 | #define CONFIG_PORT_SIZE 8 124 | #define CONFIG_DEVICE_SIZE 256 125 | #define LARGEST_TAG 8 126 | #define LARGEST_VAL 40 127 | #define ADDR_LEN 16 /* IPV6 is current longest address */ 128 | 129 | #define MAX_BODY_SIZE 1024 130 | #define MAX_URI_SIZE 128 131 | #define MAX_NQN_SIZE 256 132 | #define MAX_ALIAS_SIZE 64 133 | 134 | #ifndef AF_IPV4 135 | #define AF_IPV4 1 136 | #define AF_IPV6 2 137 | #endif 138 | 139 | #ifndef AF_FC 140 | #define AF_FC 3 141 | #endif 142 | 143 | struct target; 144 | struct host_iface; 145 | struct portid; 146 | struct subsystem; 147 | 148 | struct qe { 149 | struct xp_qe *qe; 150 | u8 *buf; 151 | }; 152 | 153 | struct endpoint { 154 | struct xp_ep *ep; 155 | struct xp_mr *mr; 156 | struct xp_mr *data_mr; 157 | struct xp_ops *ops; 158 | struct nvme_command *cmd; 159 | struct qe *qe; 160 | void *data; 161 | char nqn[MAX_NQN_SIZE + 1]; 162 | int state; 163 | int csts; 164 | }; 165 | 166 | struct ctrl_queue { 167 | struct linked_list node; 168 | struct portid *portid; 169 | struct target *target; 170 | struct subsystem *subsys; 171 | struct endpoint ep; 172 | char hostnqn[MAX_NQN_SIZE + 1]; 173 | int connected; 174 | int failed_kato; 175 | }; 176 | 177 | enum { VALID_LOGPAGE = 0, DELETED_LOGPAGE, NEW_LOGPAGE }; 178 | 179 | enum { LOCAL_MGMT = 0, IN_BAND_MGMT, OUT_OF_BAND_MGMT, DISCOVERY_CTRL }; 180 | 181 | int parse_line(FILE *fd, char *tag, int tag_max, char *value, int value_max); 182 | 183 | int ipv4_to_addr(char *p, int *addr); 184 | int ipv6_to_addr(char *p, int *addr); 185 | int fc_to_addr(char *p, int *addr); 186 | 187 | int connect_ctrl(struct ctrl_queue *ctrl); 188 | void disconnect_ctrl(struct ctrl_queue *ctrl, int shutdown); 189 | int client_connect(struct endpoint *ep, void *data, int bytes); 190 | void disconnect_endpoint(struct endpoint *ep, int shutdown); 191 | 192 | int send_get_log_page(struct endpoint *ep, int log_size, 193 | struct nvmf_disc_rsp_page_hdr **log); 194 | int send_get_features(struct endpoint *ep, u8 fid, u64 *result); 195 | int send_set_features(struct endpoint *ep, u8 fid, u32 dword11); 196 | int send_async_event_request(struct endpoint *ep); 197 | int send_keep_alive(struct endpoint *ep); 198 | int send_mi_send(struct endpoint *ep, int cid, int len, void *data); 199 | int send_mi_receive(struct endpoint *ep, int cid, int len, void **data); 200 | 201 | int send_del_target(struct target *target); 202 | 203 | int process_nvme_rsp(struct endpoint *ep, int ignore_status, u64 *result); 204 | 205 | void print_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec); 206 | int get_logpages(struct ctrl_queue *dq, struct nvmf_disc_rsp_page_hdr **logp, 207 | u32 *numrec); 208 | 209 | const char *trtype_str(u8 trtype); 210 | const char *adrfam_str(u8 adrfam); 211 | const char *subtype_str(u8 subtype); 212 | const char *treq_str(u8 treq); 213 | const char *prtype_str(u8 prtype); 214 | const char *qptype_str(u8 qptype); 215 | const char *cms_str(u8 cm); 216 | u8 to_trtype(char *str); 217 | u8 to_adrfam(char *str); 218 | 219 | void dump(u8 *buf, int len); 220 | 221 | #endif 222 | -------------------------------------------------------------------------------- /src/incl/ops.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #ifndef __OPS_H__ 36 | #define __OPS_H__ 37 | 38 | #include 39 | 40 | #include "tags.h" 41 | 42 | struct xp_ep; 43 | struct xp_pep; 44 | struct xp_qe; 45 | struct xp_mr; 46 | 47 | struct xp_ops { 48 | int (*init_endpoint)(struct xp_ep **ep, int depth); 49 | int (*create_endpoint)(struct xp_ep **ep, void *id, int depth); 50 | void (*destroy_endpoint)(struct xp_ep *ep); 51 | int (*init_listener)(struct xp_pep **pep, char *port); 52 | void (*destroy_listener)(struct xp_pep *pep); 53 | int (*wait_for_connection)(struct xp_pep *pep, void **id); 54 | int (*accept_connection)(struct xp_ep *ep); 55 | int (*reject_connection)(struct xp_ep *ep, void *data, int len); 56 | int (*client_connect)(struct xp_ep *ep, struct sockaddr *dst, 57 | void *data, int len); 58 | int (*rma_read)(struct xp_ep *ep, void *buf, u64 addr, u64 len, 59 | u32 key, struct xp_mr *mr); 60 | int (*rma_write)(struct xp_ep *ep, void *buf, u64 addr, u64 len, 61 | u32 key, struct xp_mr *mr, struct nvme_command *cmd); 62 | int (*repost_recv)(struct xp_ep *ep, struct xp_qe *qe); 63 | int (*post_msg)(struct xp_ep *ep, void *msg, int len, 64 | struct xp_mr *mr); 65 | int (*send_msg)(struct xp_ep *ep, void *msg, int len, 66 | struct xp_mr *mr); 67 | int (*send_rsp)(struct xp_ep *ep, void *msg, int len, 68 | struct xp_mr *mr); 69 | int (*poll_for_msg)(struct xp_ep *ep, struct xp_qe **qe, void **msg, 70 | int *bytes); 71 | int (*alloc_key)(struct xp_ep *ep, void *buf, int len, 72 | struct xp_mr **mr); 73 | u32 (*remote_key)(struct xp_mr *mr); 74 | int (*dealloc_key)(struct xp_mr *mr); 75 | int (*build_connect_data)(void **req, char *hostnqn); 76 | void (*set_sgl)(struct nvme_command *cmd, u8 opcode, int len, 77 | void *data, int key); 78 | }; 79 | 80 | struct xp_ops *rdma_register_ops(void); 81 | struct xp_ops *tcp_register_ops(void); 82 | 83 | static inline struct xp_ops *register_ops(char *type) 84 | { 85 | if (!type || !*type) 86 | return NULL; 87 | 88 | if (strcmp(type, TRTYPE_STR_RDMA) == 0) 89 | return rdma_register_ops(); 90 | 91 | if (strcmp(type, TRTYPE_STR_TCP) == 0) 92 | return tcp_register_ops(); 93 | 94 | return NULL; 95 | } 96 | 97 | #endif /* __OPS_H__ */ 98 | -------------------------------------------------------------------------------- /src/incl/tags.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #ifndef __TAGS_H__ 36 | #define __TAGS_H__ 37 | 38 | #define TAG_GROUPS "Groups" 39 | #define TAG_GROUP "Group" 40 | #define TAG_TARGETS "Targets" 41 | #define TAG_TARGET "Target" 42 | #define TAG_HOSTS "Hosts" 43 | #define TAG_HOST "Host" 44 | #define TAG_ALIAS "Alias" 45 | #define TAG_REFRESH "Refresh" 46 | #define TAG_TRANSPORT "Transport" 47 | #define TAG_TYPE "TRTYPE" 48 | #define TAG_FAMILY "ADRFAM" 49 | #define TAG_ADDRESS "TRADDR" 50 | #define TAG_TRSVCID "TRSVCID" 51 | #define TAG_TREQ "TREQ" 52 | #define TAG_PORTID "PORTID" 53 | #define TAG_PORTIDS "PortIDs" 54 | #define TAG_SUBSYSTEMS "Subsystems" 55 | #define TAG_SUBSYSTEM "Subsystem" 56 | #define TAG_SUBNQN "SUBNQN" 57 | #define TAG_HOSTNQN "HOSTNQN" 58 | #define TAG_ALLOW_ANY "AllowAnyHost" 59 | #define TAG_INTERFACES "Interfaces" 60 | #define TAG_INTERFACE "Interface" 61 | #define TAG_NAME "Name" 62 | #define TAG_DEVID "DeviceID" 63 | #define TAG_DEVNSID "DeviceNSID" 64 | #define TAG_NSID "NSID" 65 | #define TAG_NSIDS "NSIDs" 66 | #define TAG_NAMESPACE "Namespace" 67 | #define TAG_IFFAMILY "FAMILY" 68 | #define TAG_IFADDRESS "ADDRESS" 69 | #define TAG_IFPORT "PORT" 70 | #define TAG_SHARED "Shared" 71 | #define TAG_RESTRICTED "Restricted" 72 | #define TAG_MGMT_MODE "MgmtMode" 73 | #define TAG_OUT_OF_BAND_MGMT "OutOfBandMgmt" 74 | #define TAG_LOCAL_MGMT "LocalMgmt" 75 | #define TAG_IN_BAND_MGMT "InBandMgmt" 76 | 77 | /* Endport Config specific */ 78 | #define TAG_NSDEVS "NSDevices" 79 | #define URI_NSDEV "nsdev" 80 | #define URI_NAMESPACE "namespace" 81 | #define URI_CONFIG "config" 82 | 83 | /* JSON config specific */ 84 | #define TAG_ID "ID" 85 | #define TAG_PORT "PORT" 86 | #define TAG_NEW "NEW" 87 | #define TAG_OLD "OLD" 88 | 89 | #define URI_GROUP "group" 90 | #define URI_TARGET "target" 91 | #define URI_HOST "host" 92 | #define URI_DEM "dem" 93 | #define URI_V1 "v1" 94 | #define URI_SUBSYSTEM "subsystem" 95 | #define URI_PORTID "portid" 96 | #define URI_NSID "nsid" 97 | #define URI_INTERFACE "interface" 98 | #define URI_TRANSPORT "transport" 99 | #define URI_SIGNATURE "signature" 100 | #define URI_LOG_PAGE "logpage" 101 | #define URI_USAGE "usage" 102 | #define URI_PARM_MODE "mode=" 103 | #define URI_PARM_FABRIC "fabric=" 104 | 105 | #define GROUP_LEN (sizeof(URI_GROUP) - 1) 106 | #define TARGET_LEN (sizeof(URI_TARGET) - 1) 107 | #define HOST_LEN (sizeof(URI_HOST) - 1) 108 | #define DEM_LEN (sizeof(URI_DEM) - 1) 109 | #define V1_LEN (sizeof(URI_V1) - 1) 110 | #define PARM_MODE_LEN (sizeof(URI_PARM_MODE) - 1) 111 | #define PARM_FABRIC_LEN (sizeof(URI_PARM_FABRIC) - 1) 112 | 113 | #define METHOD_SHUTDOWN "shutdown" 114 | #define METHOD_REFRESH "refresh" 115 | #define METHOD_RECONFIG "reconfig" 116 | 117 | #define DEFAULT_HTTP_ADDR "127.0.0.1" 118 | #define DEFAULT_HTTP_PORT "22345" 119 | 120 | #define TRTYPE_STR_RDMA "rdma" 121 | #define TRTYPE_STR_FC "fc" 122 | #define TRTYPE_STR_TCP "tcp" 123 | 124 | #define ADRFAM_STR_IPV4 "ipv4" 125 | #define ADRFAM_STR_IPV6 "ipv6" 126 | #define ADRFAM_STR_FC "fc" 127 | 128 | #define NULL_BLK_DEVID -1 129 | #define INVALID_DEVID -2 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /src/incl/tcp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #ifndef __NVME_TCP_H__ 36 | #define __NVME_TCP_H__ 37 | 38 | enum nvme_tcp_connect_fmt { 39 | NVME_TCP_CONNECT_FMT_1_0 = 0x0, 40 | }; 41 | 42 | enum nvme_tcp_pdu_type { 43 | NVME_TCP_ICREQ = 0x0, 44 | NVME_TCP_ICRESP = 0x1, 45 | NVME_TCP_H2CTERMREQ = 0x2, 46 | NVME_TCP_C2HTERMREQ = 0x3, 47 | NVME_TCP_CAPSULECMD = 0x4, 48 | NVME_TCP_CAPSULERESP = 0x5, 49 | NVME_TCP_H2CDATA = 0x6, 50 | NVME_TCP_C2HDATA = 0x7, 51 | NVME_TCP_R2T = 0x9, 52 | }; 53 | 54 | enum nvme_tcp_pdu_formatversion { 55 | NVME_TCP_PDU_FORMAT_VER = 0x0, 56 | }; 57 | 58 | enum { 59 | NVME_TCP_SINGLE_INFLIGHT_READY_TO_XMIT = 1, 60 | }; 61 | 62 | struct nvme_tcp_common_hdr { 63 | __u8 pdu_type; 64 | __u8 flags; 65 | __u8 hlen; 66 | __u8 pdo; 67 | __le32 plen; 68 | }; 69 | 70 | struct nvme_tcp_icreq_pdu { 71 | struct nvme_tcp_common_hdr c_hdr; 72 | __le16 pfv; 73 | __u8 hpda; 74 | __u8 dgst; 75 | __le32 maxr2t; 76 | __u8 rsvd[112]; 77 | }; 78 | 79 | struct nvme_tcp_icresp_pdu { 80 | struct nvme_tcp_common_hdr c_hdr; 81 | __le16 pfv; 82 | __u8 cpda; 83 | __u8 dgst; 84 | __le32 maxh2c; 85 | __u8 rsvd[112]; 86 | }; 87 | 88 | struct nvme_tcp_cmd_capsule_pdu { 89 | struct nvme_tcp_common_hdr c_hdr; 90 | struct nvme_command cmd; 91 | }; 92 | 93 | struct nvme_tcp_resp_capsule_pdu { 94 | struct nvme_tcp_common_hdr c_hdr; 95 | struct nvme_completion cqe; 96 | }; 97 | 98 | struct nvme_tcp_data_pdu { 99 | struct nvme_tcp_common_hdr c_hdr; 100 | __u16 cccid; 101 | __u16 ttag; 102 | __le32 data_offset; 103 | __le32 data_length; 104 | __u8 rsvd[4]; 105 | }; 106 | 107 | union nvme_tcp_pdu { 108 | struct nvme_tcp_icreq_pdu conn_req; 109 | struct nvme_tcp_icresp_pdu conn_rep; 110 | struct nvme_tcp_cmd_capsule_pdu cmd; 111 | struct nvme_tcp_resp_capsule_pdu comp; 112 | struct nvme_tcp_data_pdu data; 113 | }; 114 | 115 | #endif /* __NVME_TCP_H__ */ 116 | -------------------------------------------------------------------------------- /src/incl/utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #ifndef _UTILS_H 36 | #define _UTILS_H 37 | 38 | #include "tags.h" 39 | 40 | #define NUM_ENTRIES(x) (int)(sizeof(x) / sizeof(x[0])) 41 | 42 | typedef __signed__ char __s8; 43 | typedef unsigned char __u8; 44 | 45 | typedef __signed__ short __s16; 46 | typedef unsigned short __u16; 47 | 48 | typedef __signed__ int __s32; 49 | typedef unsigned int __u32; 50 | 51 | #ifdef __GNUC__ 52 | __extension__ typedef __signed__ long long __s64; 53 | __extension__ typedef unsigned long long __u64; 54 | #else 55 | typedef __signed__ long long __s64; 56 | typedef unsigned long long __u64; 57 | #endif 58 | 59 | #define u8 __u8 60 | #define u16 __u16 61 | #define u32 __u32 62 | #define u64 __u64 63 | 64 | /* complex for_each that checkpatch has issues with but is correct and 65 | * used in multiple include files in the kernel 66 | */ 67 | #define for_each_dir(entry, subdir) \ 68 | while ((entry = readdir(subdir)) != NULL) \ 69 | if (strcmp(entry->d_name, ".") && \ 70 | strcmp(entry->d_name, "..")) 71 | 72 | /* simple linked list functions */ 73 | 74 | struct linked_list { 75 | struct linked_list *next, *prev; 76 | }; 77 | 78 | #define LINKED_LIST_INIT(name) { &(name), &(name) } 79 | 80 | #define LINKED_LIST(name) \ 81 | struct linked_list name = LINKED_LIST_INIT(name) 82 | 83 | #define INIT_LINKED_LIST(ptr) do { \ 84 | (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 85 | } while (0) 86 | 87 | static inline void __list_add(struct linked_list *entry, 88 | struct linked_list *prev, 89 | struct linked_list *next) 90 | { 91 | next->prev = entry; 92 | entry->next = next; 93 | entry->prev = prev; 94 | prev->next = entry; 95 | } 96 | 97 | static inline void list_add(struct linked_list *entry, struct linked_list *list) 98 | { 99 | __list_add(entry, list, list->next); 100 | } 101 | 102 | static inline void list_add_tail(struct linked_list *entry, 103 | struct linked_list *list) 104 | { 105 | __list_add(entry, list->prev, list); 106 | } 107 | 108 | static inline void list_del(struct linked_list *entry) 109 | { 110 | entry->next->prev = entry->prev; 111 | entry->prev->next = entry->next; 112 | } 113 | 114 | static inline int list_empty(const struct linked_list *list) 115 | { 116 | return list->next == list; 117 | } 118 | 119 | #define offset_of(type, member) ((size_t) &((type *)0)->member) 120 | 121 | #define container_of(ptr, type, member) ({ \ 122 | const typeof(((type *)0)->member) (*__mptr) = (ptr); \ 123 | (type *)((char *) __mptr - offset_of(type, member)); \ 124 | }) 125 | 126 | #define list_entry(entry, type, member) container_of(entry, type, member) 127 | 128 | #define list_first_entry(ptr, type, member) \ 129 | list_entry((ptr)->next, type, member) 130 | 131 | #define list_for_each(entry, list) \ 132 | for (entry = (list)->next; entry != (list); entry = entry->next) 133 | 134 | #define list_for_each_safe(entry, tmp, list) \ 135 | for (entry = (list)->next, tmp = entry->next; entry != (list); \ 136 | entry = tmp, tmp = entry->next) 137 | 138 | #define list_for_each_entry(entry, list, member) \ 139 | for (entry = list_entry((list)->next, typeof(*entry), member); \ 140 | &entry->member != (list); \ 141 | entry = list_entry(entry->member.next, typeof(*entry), member)) 142 | 143 | #define list_for_each_entry_safe(entry, tmp, list, member) \ 144 | for (entry = list_entry((list)->next, typeof(*entry), member), \ 145 | tmp = list_entry(entry->member.next, typeof(*entry), member); \ 146 | &entry->member != (list); \ 147 | entry = tmp, \ 148 | tmp = list_entry(tmp->member.next, typeof(*tmp), member)) 149 | 150 | #define print_debug(f, x...) \ 151 | do { \ 152 | if (debug) { \ 153 | printf("%s(%d) " f "\n", __func__, __LINE__, ##x); \ 154 | fflush(stdout); \ 155 | } \ 156 | } while (0) 157 | #define print_trace()\ 158 | do { \ 159 | printf("%s(%d)\n", __func__, __LINE__); \ 160 | fflush(stdout); \ 161 | } while (0) 162 | #define print_info(f, x...)\ 163 | do { \ 164 | printf(f "\n", ##x); \ 165 | fflush(stdout); \ 166 | } while (0) 167 | #define print_err(f, x...)\ 168 | do { \ 169 | fprintf(stderr, "Error: " f "\n", ##x); \ 170 | fflush(stderr); \ 171 | } while (0) 172 | #define print_errno(s, e)\ 173 | print_err("%s - %s (%d)", s, strerror(((e) < 0) ? -(e) : (e)), e) 174 | 175 | #define UNUSED(x) ((void) x) 176 | 177 | #define min(x, y) ((x < y) ? x : y) 178 | 179 | #define __round_mask(x, y) ((__typeof__(x))((y) - 1)) 180 | #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) 181 | 182 | #define valid_delim ", " 183 | #define valid_trtype_str TRTYPE_STR_RDMA valid_delim TRTYPE_STR_TCP 184 | #define valid_adrfam_str ADRFAM_STR_IPV4 valid_delim \ 185 | ADRFAM_STR_IPV6 186 | 187 | static inline int set_adrfam(char *family) 188 | { 189 | if (strcmp(family, ADRFAM_STR_IPV4) == 0) 190 | return NVMF_ADDR_FAMILY_IP4; 191 | 192 | if (strcmp(family, ADRFAM_STR_IPV6) == 0) 193 | return NVMF_ADDR_FAMILY_IP6; 194 | 195 | return 0; 196 | } 197 | 198 | static inline int valid_trtype(char *type) 199 | { 200 | return (!strcmp(type, TRTYPE_STR_RDMA) || 201 | !strcmp(type, TRTYPE_STR_TCP)); 202 | } 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /src/monitor/common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: DUAL GPL-2.0/BSD */ 2 | /* 3 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 4 | * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. 5 | * 6 | * This software is available to you under a choice of one of two 7 | * licenses. You may choose to be licensed under the terms of the GNU 8 | * General Public License (GPL) Version 2, available from the file 9 | * COPYING in the main directory of this source tree, or the 10 | * BSD license below: 11 | * 12 | * Redistribution and use in source and binary forms, with or 13 | * without modification, are permitted provided that the following 14 | * conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above 17 | * copyright notice, this list of conditions and the following 18 | * disclaimer. 19 | * 20 | * - Redistributions in binary form must reproduce the above 21 | * copyright notice, this list of conditions and the following 22 | * disclaimer in the documentation and/or other materials 23 | * provided with the distribution. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | #ifndef __COMMON_H__ 36 | #define __COMMON_H__ 37 | 38 | #define unlikely __glibc_unlikely 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include "nvme.h" 53 | #include "utils.h" 54 | #include "ops.h" 55 | #include "dem.h" 56 | 57 | #define DELAY 480 /* ms */ 58 | #define SECONDS (1000000 / DELAY) 59 | #define KEEP_ALIVE_COUNTER 4 /* x DELAY */ 60 | #define CONNECT_RETRY_COUNTER (60 * SECONDS) 61 | 62 | #define NVME_FABRICS_DEV "/dev/nvme-fabrics" 63 | #define SYS_CLASS_PATH "/sys/class/nvme-fabrics/ctl/" 64 | #define SYS_CLASS_ADDR_FILE "address" 65 | #define SYS_CLASS_TRTYPE_FILE "transport" 66 | #define SYS_CLASS_SUBNQN_FILE "subsysnqn" 67 | #define NVME_FABRICS_FMT \ 68 | "transport=%s,traddr=%s,trsvcid=%s,nqn=%s,hostnqn=%s" 69 | 70 | extern int debug; 71 | 72 | struct target; 73 | 74 | struct portid { 75 | struct linked_list node; 76 | int portid; 77 | char type[CONFIG_TYPE_SIZE + 1]; 78 | char family[CONFIG_FAMILY_SIZE + 1]; 79 | char address[CONFIG_ADDRESS_SIZE + 1]; 80 | char port[CONFIG_PORT_SIZE + 1]; 81 | int port_num; 82 | int addr[ADDR_LEN]; 83 | int adrfam; 84 | int trtype; 85 | int valid; 86 | }; 87 | 88 | struct host_iface { 89 | char type[CONFIG_TYPE_SIZE + 1]; 90 | char family[CONFIG_FAMILY_SIZE + 1]; 91 | char address[CONFIG_ADDRESS_SIZE + 1]; 92 | int addr[ADDR_LEN]; 93 | char port[CONFIG_PORT_SIZE + 1]; 94 | struct xp_pep *listener; 95 | struct xp_ops *ops; 96 | }; 97 | 98 | struct inb_iface { 99 | struct target *target; 100 | struct portid portid; 101 | struct endpoint ep; 102 | int connected; 103 | }; 104 | 105 | struct oob_iface { 106 | char address[CONFIG_ADDRESS_SIZE + 1]; 107 | int port; 108 | }; 109 | 110 | union sc_iface { 111 | struct oob_iface oob; 112 | struct inb_iface inb; 113 | }; 114 | 115 | struct fabric_iface { 116 | struct linked_list node; 117 | char type[CONFIG_TYPE_SIZE + 1]; 118 | char fam[CONFIG_FAMILY_SIZE + 1]; 119 | char addr[CONFIG_ADDRESS_SIZE + 1]; 120 | int valid; 121 | }; 122 | 123 | struct logpage { 124 | struct linked_list node; 125 | struct portid *portid; 126 | struct nvmf_disc_rsp_page_entry e; 127 | int valid; 128 | int connected; 129 | }; 130 | 131 | struct subsystem { 132 | struct linked_list node; 133 | struct linked_list logpage_list; 134 | struct target *target; 135 | char nqn[MAX_NQN_SIZE + 1]; 136 | }; 137 | 138 | struct target { 139 | struct linked_list node; 140 | struct linked_list subsys_list; 141 | char alias[MAX_ALIAS_SIZE + 1]; 142 | int mgmt_mode; 143 | union sc_iface sc_iface; 144 | }; 145 | 146 | int init_interfaces(void); 147 | void *interface_thread(void *arg); 148 | 149 | void build_target_list(void); 150 | void init_targets(void); 151 | void cleanup_targets(void); 152 | void get_host_nqn(void *context, void *haddr, char *nqn); 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /test/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 3 | * Copyright (c) 2017-2019 Intel Corporation, Inc. 4 | * 5 | * This software is available to you under a choice of one of two 6 | * licenses. You may choose to be licensed under the terms of the GNU 7 | * General Public License (GPL) Version 2, available from the file 8 | * COPYING in the main directory of this source tree, or the 9 | * BSD license below: 10 | * 11 | * Redistribution and use in source and binary forms, with or 12 | * without modification, are permitted provided that the following 13 | * conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above 16 | * copyright notice, this list of conditions and the following 17 | * disclaimer. 18 | * 19 | * - Redistributions in binary form must reproduce the above 20 | * copyright notice, this list of conditions and the following 21 | * disclaimer in the documentation and/or other materials 22 | * provided with the distribution. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | * SOFTWARE. 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | extern int stopped; 39 | enum { DISCONNECTED = 0, CONNECTED }; 40 | 41 | #define print_err(f, a...) printf("%s:%d " f "\n", __func__, __LINE__, ##a) 42 | 43 | #define PAGE_SIZE 4096 44 | 45 | #define u64 __u64 46 | #define u32 __u32 47 | #define u16 __u16 48 | #define u8 __u8 49 | 50 | -------------------------------------------------------------------------------- /test/makefile: -------------------------------------------------------------------------------- 1 | .SILENT: 2 | 3 | .PHONY: all 4 | all: ut 5 | 6 | ut: rdma.c test.c ops.h makefile 7 | echo CC rdma.c test.c 8 | gcc -O0 -g rdma.c test.c -o $@ -lrdmacm -libverbs 9 | 10 | .PHONY: clean 11 | clean: 12 | -rm -f ut 13 | 14 | .PHONY: archive 15 | archive: clean 16 | tar cz -f archive/`date +%y%m%d_%H%M`.tgz M* *.[ch] 17 | -------------------------------------------------------------------------------- /test/ops.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 3 | * Copyright (c) 2017-2019 Intel Corporation, Inc. 4 | * 5 | * This software is available to you under a choice of one of two 6 | * licenses. You may choose to be licensed under the terms of the GNU 7 | * General Public License (GPL) Version 2, available from the file 8 | * COPYING in the main directory of this source tree, or the 9 | * BSD license below: 10 | * 11 | * Redistribution and use in source and binary forms, with or 12 | * without modification, are permitted provided that the following 13 | * conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above 16 | * copyright notice, this list of conditions and the following 17 | * disclaimer. 18 | * 19 | * - Redistributions in binary form must reproduce the above 20 | * copyright notice, this list of conditions and the following 21 | * disclaimer in the documentation and/or other materials 22 | * provided with the distribution. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | * SOFTWARE. 32 | */ 33 | 34 | #ifndef __OPS_H__ 35 | #define __OPS_H__ 36 | 37 | #include 38 | 39 | struct xp_ep; 40 | struct xp_pep; 41 | struct xp_qe; 42 | struct xp_mr; 43 | 44 | struct xp_ops { 45 | int (*init_endpoint)(struct xp_ep **ep, int depth); 46 | int (*create_endpoint)(struct xp_ep **ep, void *id, int depth); 47 | void (*destroy_endpoint)(struct xp_ep *ep); 48 | int (*init_listener)(struct xp_pep **pep, char *srvc); 49 | void (*destroy_listener)(struct xp_pep *pep); 50 | int (*wait_for_connection)(struct xp_pep *pep, void **id); 51 | int (*accept_connection)(struct xp_ep *ep); 52 | int (*reject_connection)(struct xp_ep *ep, void *data, int len); 53 | int (*client_connect)(struct xp_ep *ep, struct sockaddr *dst, 54 | void *data, int len); 55 | int (*rma_read)(struct xp_ep *ep, void *buf, u64 addr, u64 len, 56 | u32 key, struct xp_mr *mr); 57 | int (*rma_write)(struct xp_ep *ep, void *buf, u64 addr, u64 len, 58 | u32 key, struct xp_mr *mr); 59 | int (*repost_recv)(struct xp_ep *ep, struct xp_qe *qe); 60 | int (*post_msg)(struct xp_ep *ep, void *msg, int len, 61 | struct xp_mr *mr); 62 | int (*send_msg)(struct xp_ep *ep, void *msg, int len, 63 | struct xp_mr *mr); 64 | int (*poll_for_msg)(struct xp_ep *ep, struct xp_qe **qe, void **msg, 65 | int *bytes); 66 | int (*alloc_key)(struct xp_ep *ep, void *buf, int len, 67 | struct xp_mr **mr); 68 | u32 (*remote_key)(struct xp_mr *mr); 69 | int (*dealloc_key)(struct xp_mr *mr); 70 | }; 71 | 72 | struct xp_ops *rdma_register_ops(void); 73 | 74 | #endif /* __OPS_H__ */ 75 | -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NVMe over Fabrics Distributed Endpoint Management (NVMe-oF DEM). 3 | * Copyright (c) 2017-2019 Intel Corporation, Inc. 4 | * 5 | * This software is available to you under a choice of one of two 6 | * licenses. You may choose to be licensed under the terms of the GNU 7 | * General Public License (GPL) Version 2, available from the file 8 | * COPYING in the main directory of this source tree, or the 9 | * BSD license below: 10 | * 11 | * Redistribution and use in source and binary forms, with or 12 | * without modification, are permitted provided that the following 13 | * conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above 16 | * copyright notice, this list of conditions and the following 17 | * disclaimer. 18 | * 19 | * - Redistributions in binary form must reproduce the above 20 | * copyright notice, this list of conditions and the following 21 | * disclaimer in the documentation and/or other materials 22 | * provided with the distribution. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | * SOFTWARE. 32 | */ 33 | 34 | #include "common.h" 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "ops.h" 42 | 43 | int stopped; 44 | 45 | struct qe { 46 | struct xp_qe *ctx; 47 | }; 48 | 49 | struct endpoint { 50 | struct xp_ep *ctx; 51 | __u8 state; 52 | __u64 depth; 53 | }; 54 | 55 | struct listener { 56 | struct xp_pep *ctx; 57 | __u8 state; 58 | }; 59 | 60 | 61 | void signal_handler(int ev) 62 | { 63 | exit(0); 64 | } 65 | 66 | int wait_for_msg(struct endpoint *ep, struct qe *qe, void **msg, 67 | int *bytes, struct xp_ops *ops) 68 | { 69 | int ret; 70 | 71 | do { 72 | ret = ops->poll_for_msg(ep->ctx, &qe->ctx, msg, bytes); 73 | if (ret && ret != -EAGAIN) { 74 | printf("poll_for_msg returned %d\n", ret); 75 | goto out; 76 | } 77 | } while (ret == -EAGAIN); 78 | out: 79 | return ret; 80 | } 81 | 82 | void act_as_server(struct xp_ops *ops, void *cmd, void *data, int size) 83 | { 84 | int ret; 85 | struct listener pep = { 0 }; 86 | struct endpoint ep = { 0 }; 87 | struct qe qe; 88 | void *id; 89 | int bytes = 5; 90 | char *srvc = "22666"; 91 | int depth = 3; 92 | void *req = "hello"; 93 | char *expect; 94 | u64 addr = 0; 95 | u32 key, len; 96 | void *msg; 97 | struct xp_mr *mr = NULL, *data_mr; 98 | 99 | ret = ops->init_listener(&pep.ctx, srvc); 100 | if (ret) { 101 | print_err("init_listener returned %d", ret); 102 | return; 103 | } 104 | 105 | while (!stopped) { 106 | ret = ops->wait_for_connection(pep.ctx, &id); 107 | if (ret) { 108 | print_err("wait_for_connection returned %d", ret); 109 | break; 110 | } 111 | 112 | ret = ops->create_endpoint(&ep.ctx, id, depth); 113 | if (ret) { 114 | print_err("create_endpoint returned %d", ret); 115 | break; 116 | } 117 | 118 | ret = ops->accept_connection(ep.ctx); 119 | if (ret) { 120 | print_err("accept_connection returned %d", ret); 121 | break; 122 | } 123 | 124 | ret = ops->alloc_key(ep.ctx, cmd, size, &mr); 125 | if (ret) { 126 | print_err("alloc_key returned %d", ret); 127 | break; 128 | } 129 | 130 | ret = ops->alloc_key(ep.ctx, data, size, &data_mr); 131 | if (ret) { 132 | print_err("alloc_key returned %d", ret); 133 | break; 134 | } 135 | 136 | sprintf(cmd, "hello"); 137 | ops->send_msg(ep.ctx, cmd, 5, mr); 138 | 139 | ret = wait_for_msg(&ep, &qe, &msg, &bytes, ops); 140 | if (ret) { 141 | printf("wait_for_msg returned %d\n", ret); 142 | break; 143 | } 144 | 145 | if ((bytes != 5) || strncmp(msg, "HELLO", 5)) { 146 | printf("unexpected: '%s`\n", (char *) msg); 147 | break; 148 | } 149 | 150 | ret = wait_for_msg(&ep, &qe, &msg, &bytes, ops); 151 | 152 | if (strncmp(msg, "READ ", 5)) { 153 | printf("unexpected: '%s`\n", (char *) msg); 154 | break; 155 | } 156 | 157 | expect = index(msg, ' '); 158 | addr = atoi(++expect); 159 | 160 | expect = index(expect, ' '); 161 | key = atoi(++expect); 162 | 163 | expect = index(expect, ' '); 164 | len = strlen(++expect); 165 | 166 | ret = ops->rma_read(ep.ctx, data, addr, size, key, data_mr); 167 | if (ret) { 168 | printf("rma_read returned %d\n", ret); 169 | break; 170 | } 171 | 172 | if (strncmp(data, expect, len)) { 173 | printf("data '%s' != '%s'\n", data, expect); 174 | ret = -EBADE; 175 | break; 176 | } 177 | 178 | len = sprintf(data, "!! WROTE THIS !!"); 179 | ret = ops->rma_write(ep.ctx, data, addr, size, key, data_mr); 180 | if (ret) { 181 | printf("rma_read returned %d\n", ret); 182 | break; 183 | } 184 | 185 | sprintf(cmd, "done."); 186 | ops->send_msg(ep.ctx, cmd, 5, mr); 187 | 188 | stopped = 1; 189 | } 190 | 191 | if (ret) 192 | printf("server unit test failed %d\n", ret); 193 | else 194 | printf("server unit test passed\n"); 195 | 196 | if (mr) 197 | ops->dealloc_key(mr); 198 | if (data_mr) 199 | ops->dealloc_key(data_mr); 200 | 201 | ops->destroy_endpoint(ep.ctx); 202 | ops->destroy_listener(pep.ctx); 203 | } 204 | 205 | void act_as_client(struct xp_ops *ops, void *cmd, void *data, int size) 206 | { 207 | int ret; 208 | struct endpoint ep = { 0 }; 209 | struct qe qe; 210 | void *id; 211 | int bytes = 5; 212 | char *srvc = "22666"; 213 | int depth = 1; 214 | void *req = "hello"; 215 | char *expect; 216 | u64 addr = 0; 217 | u32 key, len; 218 | void *msg; 219 | struct xp_mr *mr = NULL, *data_mr; 220 | struct sockaddr dest = { 0 }; 221 | struct sockaddr_in *dest_in = (struct sockaddr_in *) &dest; 222 | 223 | dest_in->sin_port = htons(atoi(srvc)); 224 | dest_in->sin_family = AF_INET; 225 | inet_pton(AF_INET, "192.168.22.2", &dest_in->sin_addr); 226 | 227 | ret = ops->init_endpoint(&ep.ctx, depth); 228 | if (ret) { 229 | print_err("init_endpoint returned %d", ret); 230 | return; 231 | } 232 | 233 | //bytes = build_connect_data(&req); 234 | 235 | ret = ops->client_connect(ep.ctx, &dest, req, bytes); 236 | if (ret) { 237 | printf("client connect failed %d\n", -ret); 238 | goto out; 239 | } 240 | 241 | ret = ops->alloc_key(ep.ctx, cmd, size, &mr); 242 | if (ret) 243 | goto out; 244 | 245 | ret = wait_for_msg(&ep, &qe, &msg, &bytes, ops); 246 | if (ret) { 247 | printf("wait_for_msg returned %d\n", ret); 248 | goto out; 249 | } 250 | 251 | if ((bytes != 5) || strncmp(msg, "hello", 5)) { 252 | printf("unexpected: '%s`\n", (char *) msg); 253 | goto out; 254 | } 255 | 256 | sprintf(cmd, "HELLO"); 257 | ops->send_msg(ep.ctx, cmd, 5, mr); 258 | 259 | sprintf(data, "!! READ THIS !!"); 260 | 261 | ret = ops->alloc_key(ep.ctx, data, size, &data_mr); 262 | if (ret) 263 | goto out2; 264 | 265 | len = sprintf(cmd, "READ %u %u %s", 266 | data, ops->remote_key(data_mr), data); 267 | 268 | ops->send_msg(ep.ctx, cmd, len, mr); 269 | 270 | ret = wait_for_msg(&ep, &qe, &msg, &bytes, ops); 271 | if (ret) { 272 | printf("wait_for_msg returned %d\n", ret); 273 | goto out3; 274 | } 275 | 276 | if (strcmp(data, "!! WROTE THIS !!")) { 277 | printf("unexpected: '%s'\n", data); 278 | goto out3; 279 | } 280 | 281 | printf("client unit test passed\n"); 282 | 283 | stopped = 1; 284 | 285 | out3: 286 | ops->dealloc_key(data_mr); 287 | out2: 288 | ops->dealloc_key(mr); 289 | out: 290 | ops->destroy_endpoint(ep.ctx); 291 | } 292 | 293 | int main(int argc, char *argv) 294 | { 295 | struct xp_ops *ops; 296 | void *cmd; 297 | void *data; 298 | int size = PAGE_SIZE; 299 | 300 | ops = rdma_register_ops(); 301 | 302 | if (posix_memalign(&cmd, PAGE_SIZE, size)) { 303 | print_err("no memory for command buffer, errno %d", errno); 304 | return -1; 305 | } 306 | memset(cmd, 0, size); 307 | 308 | if (posix_memalign(&data, PAGE_SIZE, size)) { 309 | print_err("no memory for data buffer, errno %d", errno); 310 | return -1; 311 | } 312 | memset(data, 0, size); 313 | 314 | signal(SIGINT, signal_handler); 315 | 316 | stopped = 0; 317 | 318 | if (argc > 1) 319 | act_as_server(ops, cmd, data, size); 320 | else 321 | act_as_client(ops, cmd, data, size); 322 | 323 | free(cmd); 324 | free(data); 325 | return 0; 326 | } 327 | -------------------------------------------------------------------------------- /usr/bash_completion.d/dem-cli: -------------------------------------------------------------------------------- 1 | # dem-cli bash completion script 2 | # vim:ts=2:sw=2:et: 3 | 4 | # main complete function 5 | _dem-cli() 6 | { 7 | local cur="${COMP_WORDS[COMP_CWORD]}" 8 | 9 | COMPREPLY=() 10 | 11 | local i=0 12 | local max=0 13 | local skip=0 14 | while [ x${COMP_WORDS[$max]} != x ] ; do max=$((max+1)) ; done 15 | 16 | for i in `seq 1 $max` ; do 17 | if [ $skip -eq 1 ] ; then 18 | skip=0 19 | continue 20 | fi 21 | 22 | if [ "${COMP_WORDS[$i]:0:1}" == "-" ] ; then 23 | case "${COMP_WORDS[$i]:1:1}" in 24 | g) 25 | if [ $i -lt $max -a "${COMP_WORDS[$((i+1))]:0:1}" != "-" ] ; then 26 | skip=1 27 | fi 28 | ;; 29 | s) 30 | if [ $i -lt $max -a "${COMP_WORDS[$((i+1))]:0:1}" != "-" ] ; then 31 | skip=1 32 | fi 33 | ;; 34 | p) 35 | if [ $i -lt $max -a "${COMP_WORDS[$((i+1))]:0:1}" != "-" ] ; then 36 | skip=1 37 | fi 38 | ;; 39 | esac 40 | else 41 | break 42 | fi 43 | done 44 | 45 | if [ $COMP_CWORD -lt $((max-1)) ] ; then 46 | return 0 47 | fi 48 | 49 | local options="-r -p -s -c -f -j -?" 50 | 51 | if [ $i -le $max -a $i -gt $COMP_CWORD -a "$cur" == "-" ] ; then 52 | COMPREPLY=($(compgen -W "$options" -- "$cur")) 53 | return 0 54 | fi 55 | 56 | if [ $i -le $max ] ; then 57 | case "${COMP_WORDS[$((COMP_CWORD-1))]:0:2}" in 58 | -g) 59 | if [ $i == $COMP_CWORD ] ; then 60 | COMPREPLY=($(compgen -W "local" -- "$cur")) 61 | return 0 62 | fi 63 | ;; 64 | -s) 65 | if [ $i == $COMP_CWORD ] ; then 66 | COMPREPLY=($(compgen -W "127.0.0.1" -- "$cur")) 67 | return 0 68 | fi 69 | ;; 70 | -p) 71 | if [ $i == $COMP_CWORD ] ; then 72 | COMPREPLY=($(compgen -W "22345" -- "$cur")) 73 | return 0 74 | fi 75 | ;; 76 | esac 77 | if [ "${cur:0:1}" == "-" -a ${#cur} -le 2 ] ; then 78 | COMPREPLY=($(compgen -W "$options" -- "$cur")) 79 | return 0 80 | fi 81 | fi 82 | 83 | 84 | local n="$((COMP_CWORD-i+1))" 85 | local lst="[]" 86 | local verb 87 | local obj 88 | 89 | COMPREPLY=("") 90 | 91 | if [ $n -eq 1 ] ; then 92 | lst=`${COMP_WORDS[0]} | grep "^ dem-cli " | awk '{print $2}' | sort -u` 93 | if [ "${#lst}" -ne 0 ]; then 94 | COMPREPLY=($(compgen -W "$lst" -- "$cur")) 95 | fi 96 | elif [ $n -eq 2 ] ; then 97 | verb="${COMP_WORDS[$i]}" 98 | lst=`${COMP_WORDS[0]} | grep "^ dem-cli $verb " | awk '{print $3}' | sort -u` 99 | if [ "${#lst}" -ne 0 ]; then 100 | COMPREPLY=($(compgen -W "$lst" -- "$cur")) 101 | fi 102 | elif [ $n -gt 2 ] ; then 103 | verb="${COMP_WORDS[$i]}" 104 | obj="${COMP_WORDS[$((i+1))]}" 105 | lst=(`${COMP_WORDS[0]} | grep "^ dem-cli $verb $obj " | sed -e "s/^..dem-cli [a-z]* [a-z]* //;s/{.*//;s//]/g"`) 106 | n=$((n-3)) 107 | if [ ${#lst[$n]} -ne 0 ] ; then 108 | COMPREPLY=($(compgen -W "${lst[$n]}" -- "$cur")) 109 | fi 110 | fi 111 | 112 | return 0 113 | } 114 | 115 | complete -F _dem-cli -o default dem-cli 116 | -------------------------------------------------------------------------------- /usr/man/dem-ac.8: -------------------------------------------------------------------------------- 1 | .\" dem-ac.8 -- 2 | .\" Copyright 2018-2019 Intel Corporation, Inc. 3 | .\" May be distributed under the GNU General Public License 4 | .TH DEM-AC 8 "February 2019" "nvmeof-dem" "System Administration" 5 | .SH NAME 6 | dem-ac \- 7 | Distributed Endpoint Management - Auto Connect 8 | .SH SYNOPSIS 9 | .B dem-ac 10 | can be used on an NVMe-oF Host to use a Discovery controller to automatically 11 | connect to Subsystems within a NVMe-oF network. The Discovery controller may 12 | provided by the Distributed Endpoint Manager (DEM) or may be provided by a 13 | single Endpoint. 14 | .SH DESCRIPTION 15 | .B dem-ac 16 | is a program that can run as a daemon or standalone on a NVMe-oF Host that 17 | will connect to a Discovery controller to retrieve the log pages of the 18 | Subsystems to which that Host has access. The program with then attempt to 19 | connect to each Subsystem to establish a persistent connection that Subsystem 20 | to appear as a local NMVe device to the Host. 21 | 22 | .SH PARAMETERS 23 | .TP 24 | .I -d 25 | enable debug prints in log files 26 | .TP 27 | .I -S 28 | run as a standalone process (default is daemon) 29 | .TP 30 | .I -h 31 | the Host NQN to use for connecting to be the Discovery controller 32 | .TP 33 | .B Discovery controller info: 34 | .TP 35 | .I -t 36 | transport type to use, i.e. rdma, tcp, fc (see help for default) 37 | .TP 38 | .I -f 39 | address family, i.e. ipv4, ipv6, fc (see help for default) 40 | .TP 41 | .I -a 42 | transport address to use, must match address family definition of an address 43 | (see help for default) 44 | .TP 45 | .I -s 46 | transport service id (a.k.a. Port Number) to use. (see help for default) 47 | 48 | .SH SEE ALSO 49 | .BR dem-cli (1), 50 | .BR dem_dm (1), 51 | .BR dem (8), 52 | .BR dem-em (8), 53 | .SH AVAILABILITY 54 | The dem-ac command is part of the nvmeof-dem package and is available from 55 | http://github.com/linux-nvme/nvme-dem. 56 | -------------------------------------------------------------------------------- /usr/man/dem-cli.1: -------------------------------------------------------------------------------- 1 | .\" dem-cli.1 -- 2 | .\" Copyright 2018-2019 Intel Corporation, Inc. 3 | .\" May be distributed under the GNU General Public License 4 | .TH DEM-CLI 1 "February 2019" "nvmeof-dem" "System Administration" 5 | .SH NAME 6 | dem-cli \- 7 | Distributed Endpoint Management - Command-line interface 8 | .SH SYNOPSIS 9 | .B dem-cli 10 | is the command-line interface used to manage and configure NVMe-oF networks 11 | using Distributed Endpoint Management 12 | .SH DESCRIPTION 13 | .B dem-cli 14 | is a program that interacts with a Distributed Endpoint Manager (DEM) to 15 | manage the configuration of the NVMe-oF network. The interface uses RESTful 16 | commands to communicate with the Discovery 17 | controller. 18 | 19 | .SH PARAMETERS 20 | .TP 21 | .I -s 22 | network address of the DEM (defaulti: 127.0.0.1) 23 | .TP 24 | .I -p 25 | port of the DEM (see help for default) 26 | .TP 27 | .I -f 28 | force deleted i.e. do not ask 'Are you sure' 29 | .TP 30 | .I -j 31 | display the results in json format (default is to display in human-readable 32 | format) 33 | .TP 34 | .I -r 35 | display the results in raw (unmodified) format (used for debugging) 36 | .TP 37 | .I -c 38 | show the curl commands (used for debugging) 39 | 40 | .SH SEE ALSO 41 | .BR dem_dm (1), 42 | .BR dem (8), 43 | .BR dem-ac (8), 44 | .BR dem-em 45 | .SH AVAILABILITY 46 | The dem-cli command is part of the nvmeof-dem package and is available from 47 | http://github.com/linux-nvme/nvme-dem. 48 | -------------------------------------------------------------------------------- /usr/man/dem-dm.1: -------------------------------------------------------------------------------- 1 | .\" dem-dm.8 -- 2 | .\" Copyright 2018-2019 Intel Corporation, Inc. 3 | .\" May be distributed under the GNU General Public License 4 | .TH DEM-DM 8 "February 2019" "nvmeof-dem" "System Administration" 5 | .SH NAME 6 | dem-dm \- 7 | Distributed Endpoint Management - Discovery Monitor 8 | .SH SYNOPSIS 9 | .B dem-dm 10 | can be used on an NVMe-oF Host to use a Discovery controller to monitor 11 | available Subsystems within a NVMe-oF network. The Discovery controller may be 12 | provided by the Distributed Endpoint Manager (DEM) or may be provided by a 13 | single Endpoint. 14 | .SH DESCRIPTION 15 | .B dem-dm 16 | will monitor a Discovery controller to retrieve the log pages of the 17 | Subsystems to which that Host has access. The program with then determine 18 | if there were any changes to the log pages. If the were new or modified pages, 19 | the entire log page will be displayed. If a log page is remove, a simple 20 | message indicating the subsystem nqn was deleted would be displayed. 21 | 22 | .SH PARAMETERS 23 | .TP 24 | .I -d 25 | enable debug prints in log files 26 | .TP 27 | .I -h 28 | the Host NQN to use for connecting to be the Discovery controller 29 | .TP 30 | .B Discovery controller info: 31 | .TP 32 | .I -t 33 | transport type to use, i.e. rdma, tcp, fc (see help for default) 34 | .TP 35 | .I -f 36 | address family, i.e. ipv4, ipv6, fc (see help for default) 37 | .TP 38 | .I -a 39 | transport address to use, must match address family definition of an address 40 | (see help for default) 41 | .TP 42 | .I -s 43 | transport service id (a.k.a. Port Number) to use. (see help for default) 44 | 45 | .SH SEE ALSO 46 | .BR dem-cli (1), 47 | .BR dem (8), 48 | .BR dem-em (8), 49 | .BR dem-ac (8), 50 | .SH AVAILABILITY 51 | The dem-dm command is part of the nvmeof-dem package and is available from 52 | http://github.com/linux-nvme/nvme-dem. 53 | -------------------------------------------------------------------------------- /usr/man/dem-em.8: -------------------------------------------------------------------------------- 1 | .\" dem-em.8 -- 2 | .\" Copyright 2018-2019 Intel Corporation, Inc. 3 | .\" May be distributed under the GNU General Public License 4 | .TH DEM-EM 8 "February 2019" "nvmeof-dem" "System Administration" 5 | .SH NAME 6 | dem-em \- 7 | Distributed Endpoint Management - Endpoint Manager 8 | .SH SYNOPSIS 9 | .B dem-em 10 | is used on an Endpoint to allow remote configure NVMe-oF 11 | resources to be exports on the NVMe-of network using Distributed Endpoint 12 | Management 13 | .SH DESCRIPTION 14 | .B dem-em 15 | is a program that can run as a daemon or standalone to interact with a 16 | Distributed Endpoint Manager (DEM) to configure the Endpoint's Subsystems and 17 | Port IDs. DEM may configure the Endpoint In-Band over the same 18 | fabric used to Hosts use to connect to the Subsystems or Out-of-Band over 19 | a secure TCP network using a RESTful interface. 20 | 21 | This program doesnot provide log pages or access to the Subsystem it mananger. 22 | 23 | .SH PARAMETERS 24 | .TP 25 | .I -d 26 | enable debug prints in log files 27 | .TP 28 | .I -S 29 | run as a standalone process (default is daemon) 30 | .TP 31 | .B Out-of-Band Management Mode 32 | .TP 33 | .I -p 34 | port from RESTful interface (see help for default) 35 | .TP 36 | .I -r 37 | root for RESTful interface (see help for default) 38 | .TP 39 | .I -c 40 | cert file for RESTful interface use with ssl (default is to not use ssl) 41 | .TP 42 | .B In-Band Management Mode 43 | .TP 44 | .I -t 45 | transport type to use, i.e. rdma, tcp, fc (see help for default) 46 | .TP 47 | .I -f 48 | address family, i.e. ipv4, ipv6, fc (see help for default) 49 | .TP 50 | .I -a 51 | transport address to use, must match address family definition of an address 52 | (see help for default) 53 | .TP 54 | .I -s 55 | transport service id (a.k.a. Port Number) to use. (see help for default) 56 | 57 | .SH SEE ALSO 58 | .BR dem-cli (1), 59 | .BR dem_dm (1), 60 | .BR dem-ac (8), 61 | .BR dem (8), 62 | .SH AVAILABILITY 63 | The dem-em command is part of the nvmeof-dem package and is available from 64 | http://github.com/linux-nvme/nvme-dem. 65 | -------------------------------------------------------------------------------- /usr/man/dem.8: -------------------------------------------------------------------------------- 1 | .\" dem.8 -- 2 | .\" Copyright 2018-2019 Intel Corporation, Inc. 3 | .\" May be distributed under the GNU General Public License 4 | .TH DEM 8 "February 2019" "nvmeof-dem" "System Administration" 5 | .SH NAME 6 | dem \- 7 | Distributed Endpoint Management 8 | .SH SYNOPSIS 9 | .B dem 10 | is the core component of the Distributed Endpoint Management suite of tools. 11 | The 12 | .B dem 13 | is used to manage and configure NVMe-oF networks. 14 | .SH DESCRIPTION 15 | .B dem 16 | is a program that can run as a daemon or standalone to interact with NVMe-oF 17 | Hosts and Endpoints to configure Enpoint Subsystems and Port IDs; collect log 18 | pages; and diseminate them to Hosts. 19 | 20 | This command doesn't manipulate enclosure components or network configurations. 21 | 22 | .SH PARAMETERS 23 | .TP 24 | .I -d 25 | enable debug prints in log files 26 | .TP 27 | .I -s 28 | run as a standalone process (default is do run as a daemon) 29 | .TP 30 | .I -p 31 | port from RESTful interface (see help for default) 32 | .TP 33 | .I -r 34 | root for RESTful interface (default is /) 35 | .TP 36 | .I -c 37 | cert file for RESTful interface use with ssl 38 | 39 | .SH CONFIGURATION 40 | Configuration files defining the individual interfaces the Discover controller 41 | will use are located in 42 | .B /etc/nvme/nvmeof-dem 43 | and are similar to the ifcfg files. Lines may be commented out using bash 44 | comment syntax of starting the line with a pound sign (#). The parameters in 45 | these files are: 46 | .RS 47 | .TP 48 | .I TRTYPE=[rdma|tcp|fc] 49 | the transport type of the fabric for this interface 50 | .TP 51 | .I ADRFAM=[ipv4|ipv6|fc] 52 | the address family for this interface 53 | .TP 54 | .I TRADDR=

55 | the transport address of this interface 56 | .TP 57 | .I TRSVCID= 58 | the transport service id of this interface 59 | .RE 60 | 61 | The web interface login is stored in the file 62 | .B signature 63 | and is stored encrypted so neither the user id nor password are ever 64 | maintained or used in plain text. 65 | 66 | The Endpoint configuration is kept in JSON format in the file 67 | .B config 68 | and the schema for this file can be found in the gitlab repository. 69 | .SH LOG FILES 70 | When running as a daemon, log files are stored in the 71 | .B /var/log 72 | directory. Error messages are logged in 73 | .B dem_debug.log 74 | file and debug messages are logged in 75 | .B dem.log 76 | file. 77 | 78 | .SH SEE ALSO 79 | .BR dem_cli (1), 80 | .BR dem_dm (1), 81 | .BR dem-ac (8), 82 | .BR dem-em (8), 83 | .SH AVAILABILITY 84 | The dem command is part of the nvmeof-dem package and is available from 85 | http://github.com/linux-nvme/nvme-dem. 86 | -------------------------------------------------------------------------------- /usr/nvmeof: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Bring up the NVMe-oF stack 4 | # 5 | # This is usually run automatically by systemd after a hardware activation 6 | # event in udev has triggered a start of the nvmeof.service unit 7 | # 8 | # file: /usr/libexec/nvmeof 9 | 10 | shopt -s nullglob 11 | 12 | CONFIG=/etc/nvme/nvmeof.conf 13 | 14 | LOAD_NVMEOF_MODULES="nvme_core" 15 | 16 | if [ -f $CONFIG ]; then 17 | . $CONFIG 18 | 19 | if [ "${PCI_HOST_LOAD}" == "yes" ]; then 20 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvme" 21 | fi 22 | 23 | if [ "${NVMEOF_HOST_LOAD}" == "yes" ]; then 24 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvme" 25 | 26 | if [ "${RDMA_HOST_LOAD}" == "yes" ]; then 27 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvme_rdma" 28 | fi 29 | 30 | if [ "${FC_HOST_LOAD}" == "yes" ]; then 31 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvme_fc" 32 | fi 33 | 34 | if [ "${TCP_HOST_LOAD}" == "yes" ]; then 35 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvme_tcp" 36 | fi 37 | fi 38 | 39 | if [ "${NVMEOF_TARGET_LOAD}" == "yes" ]; then 40 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvmet" 41 | 42 | if [ "${RDMA_TARGET_LOAD}" == "yes" ]; then 43 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvmet_rdma" 44 | fi 45 | 46 | if [ "${FC_TARGET_LOAD}" == "yes" ]; then 47 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvmet_fc" 48 | fi 49 | 50 | if [ "${NULL_BLK_TARGET_LOAD}" == "yes" ]; then 51 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES null_blk" 52 | fi 53 | 54 | if [ "${TCP_TARGET_LOAD}" == "yes" ]; then 55 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvmet_tcp" 56 | fi 57 | fi 58 | else 59 | LOAD_NVMEOF_MODULES="$LOAD_NVMEOF_MODULES nvme" 60 | fi 61 | 62 | # If module $1 is loaded return - 0 else - 1 63 | is_module() 64 | { 65 | /sbin/lsmod | grep -w "$1" > /dev/null 2>&1 66 | return $? 67 | } 68 | 69 | load_modules() 70 | { 71 | local RC=0 72 | 73 | for module in $*; do 74 | if ! is_module $module; then 75 | echo Loading $module 76 | /sbin/modprobe $module 77 | res=$? 78 | RC=$[ $RC + $res ] 79 | if [ $res -ne 0 ]; then 80 | echo "ERROR: Failed to load module $module" 81 | fi 82 | fi 83 | done 84 | } 85 | 86 | unload_modules() 87 | { 88 | modprobe -r nvme_rdma 2>/dev/null 89 | modprobe -r nvme_tcp 2>/dev/null 90 | modprobe -r nvme_fc 2>/dev/null 91 | modprobe -r nvmet_rdma 2>/dev/null 92 | modprobe -r nvmet_tcp 2>/dev/null 93 | modprobe -r nvmet_fc 2>/dev/null 94 | modprobe -r null_blk 2>/dev/null 95 | modprobe -r nvmet 2>/dev/null 96 | modprobe -r nvme 2>/dev/null 97 | modprobe -r nvme_core 2>/dev/null 98 | 99 | res=$? 100 | RC=$[ $RC + $res ] 101 | } 102 | 103 | kill_daemon() 104 | { 105 | PROC=`ps -ef | grep dem | grep -v grep | awk '{print $2}'` 106 | if [ ${#PROC} -ne 0 ] ; then 107 | kill -9 $PROC 108 | fi 109 | } 110 | 111 | start_service() 112 | { 113 | load_modules $LOAD_NVMEOF_MODULES 114 | RC=$[ $RC + $? ] 115 | 116 | if [ "${START_DEM_AC}" == "yes" ]; then 117 | if [ `/usr/bin/dem-ac --help | grep -c ^-d` -eq 1 ] ; then 118 | DEM_HAC_OPTS="$DEM_AC_OPTS -d" 119 | fi 120 | /usr/bin/dem-ac $DEM_AC_OPTS 121 | res=$? 122 | RC=$[ $RC + $res ] 123 | fi 124 | 125 | if [ "${START_DEM}" == "yes" ]; then 126 | if [ `/usr/bin/dem --help | grep -c ^-d` -eq 1 ] ; then 127 | DEM_OPTS="$DEM_OPTS -d" 128 | fi 129 | /usr/bin/dem $DEM_OPTS 130 | res=$? 131 | RC=$[ $RC + $res ] 132 | fi 133 | 134 | if [ "${START_DEM_EM}" == "yes" ]; then 135 | if [ `/usr/bin/dem-em, --help | grep -c ^-d` -eq 1 ] ; then 136 | DEM_EM_OPTS="$DEM_EM_OPTS -d" 137 | fi 138 | /usr/bin/dem-em $DEM_EM_OPTS 139 | res=$? 140 | RC=$[ $RC + $res ] 141 | fi 142 | } 143 | 144 | cleanup_sysfs() 145 | { 146 | if [ -e /sys/class/nvme-fabrics/ctl/ ] ; then 147 | cd /sys/class/nvme-fabrics/ctl/ 148 | for i in `find . -name delete_controller` ; do echo 1 > $i ; done 149 | fi 150 | 151 | if [ -e /sys/kernel/config/nvmet/hosts ] ; then 152 | cd /sys/kernel/config/nvmet/hosts 153 | for i in `ls` ; do 154 | rmdir $i 155 | done 156 | fi 157 | 158 | if [ -e /sys/kernel/config/nvmet/ports ] ; then 159 | cd /sys/kernel/config/nvmet/ports 160 | for i in `ls` ; do 161 | rm -f $i/subsystems/* 162 | rmdir $i 163 | done 164 | fi 165 | 166 | if [ -e /sys/kernel/config/nvmet/subsystems/ ] ; then 167 | cd /sys/kernel/config/nvmet/subsystems/ 168 | for i in `ls` ; do 169 | cd $i/namespaces 170 | for j in `ls` ; do 171 | echo -n 0 > $j/enable 172 | rmdir $j 173 | done 174 | cd ../.. 175 | rmdir $i 176 | done 177 | fi 178 | } 179 | 180 | stop_service() 181 | { 182 | kill_daemon 183 | 184 | cleanup_sysfs 185 | 186 | unload_modules 187 | } 188 | 189 | RC=0 190 | 191 | if [ x$1 == xstop ] ; then 192 | stop_service 193 | else 194 | start_service 195 | fi 196 | 197 | exit $RC 198 | -------------------------------------------------------------------------------- /usr/nvmeof.conf: -------------------------------------------------------------------------------- 1 | PCI_HOST_LOAD=no 2 | NVMEOF_HOST_LOAD=yes 3 | RDMA_HOST_LOAD=yes 4 | FC_HOST_LOAD=no 5 | TCP_HOST_LOAD=no 6 | NVMEOF_TARGET_LOAD=yes 7 | RDMA_TARGET_LOAD=yes 8 | FC_TARGET_LOAD=no 9 | TCP_TARGET_LOAD=no 10 | NULL_BLK_TARGET_LOAD=yes 11 | START_DEM=no 12 | START_DEM_AC=no 13 | START_DEM_EM=no 14 | #DEM_AC_OPTS="-t rdma -f ipv4 -a 192.168.1.1 -s 4422" 15 | #DEM_EM_OPTS="-t rdma -f ipv4 -a 192.168.1.1 -s 4444" 16 | #DEM_EM_OPTS="-p 22334" 17 | #DEM_OPTS="-p 22345" 18 | -------------------------------------------------------------------------------- /usr/nvmeof.service: -------------------------------------------------------------------------------- 1 | # file: /usr/lib/systemd/system/nvmeof.service 2 | 3 | [Unit] 4 | Description=NVMe-oF stack (kernel dirvers and user-mode daemons) 5 | Documentation=file:/etc/nvme/nvmeof.conf 6 | Conflicts=emergency.target emergency.service 7 | After=network.target 8 | 9 | [Service] 10 | Type=oneshot 11 | RemainAfterExit=yes 12 | ExecStart=/usr/libexec/nvmeof 13 | ExecStop=/usr/libexec/nvmeof stop 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | --------------------------------------------------------------------------------