summaryrefslogtreecommitdiffstats
path: root/src/spdk/scripts/rpc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/spdk/scripts/rpc
parentInitial commit. (diff)
downloadceph-upstream/18.2.2.tar.xz
ceph-upstream/18.2.2.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/scripts/rpc')
-rw-r--r--src/spdk/scripts/rpc/__init__.py201
-rw-r--r--src/spdk/scripts/rpc/app.py78
-rw-r--r--src/spdk/scripts/rpc/bdev.py1105
-rw-r--r--src/spdk/scripts/rpc/blobfs.py57
-rw-r--r--src/spdk/scripts/rpc/client.py183
-rw-r--r--src/spdk/scripts/rpc/env_dpdk.py8
-rw-r--r--src/spdk/scripts/rpc/helpers.py16
-rw-r--r--src/spdk/scripts/rpc/idxd.py8
-rw-r--r--src/spdk/scripts/rpc/ioat.py17
-rw-r--r--src/spdk/scripts/rpc/iscsi.py558
-rw-r--r--src/spdk/scripts/rpc/log.py75
-rw-r--r--src/spdk/scripts/rpc/lvol.py228
-rw-r--r--src/spdk/scripts/rpc/nbd.py25
-rw-r--r--src/spdk/scripts/rpc/net.py35
-rw-r--r--src/spdk/scripts/rpc/notify.py30
-rw-r--r--src/spdk/scripts/rpc/nvme.py87
-rw-r--r--src/spdk/scripts/rpc/nvmf.py483
-rw-r--r--src/spdk/scripts/rpc/pmem.py35
-rw-r--r--src/spdk/scripts/rpc/sock.py41
-rw-r--r--src/spdk/scripts/rpc/subsystem.py12
-rw-r--r--src/spdk/scripts/rpc/trace.py33
-rw-r--r--src/spdk/scripts/rpc/vhost.py190
-rw-r--r--src/spdk/scripts/rpc/vmd.py3
23 files changed, 3508 insertions, 0 deletions
diff --git a/src/spdk/scripts/rpc/__init__.py b/src/spdk/scripts/rpc/__init__.py
new file mode 100644
index 000000000..f764d7ae5
--- /dev/null
+++ b/src/spdk/scripts/rpc/__init__.py
@@ -0,0 +1,201 @@
+import json
+import os
+import sys
+
+from io import IOBase as io
+
+from . import app
+from . import bdev
+from . import blobfs
+from . import env_dpdk
+from . import idxd
+from . import ioat
+from . import iscsi
+from . import log
+from . import lvol
+from . import nbd
+from . import net
+from . import notify
+from . import nvme
+from . import nvmf
+from . import pmem
+from . import subsystem
+from . import trace
+from . import vhost
+from . import vmd
+from . import sock
+from . import client as rpc_client
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('start_subsystem_init')
+def framework_start_init(client):
+ """Start initialization of subsystems"""
+ return client.call('framework_start_init')
+
+
+@deprecated_alias('wait_subsystem_init')
+def framework_wait_init(client):
+ """Block until subsystems have been initialized"""
+ return client.call('framework_wait_init')
+
+
+@deprecated_alias("get_rpc_methods")
+def rpc_get_methods(client, current=None, include_aliases=None):
+ """Get list of supported RPC methods.
+ Args:
+ current: Get list of RPC methods only callable in the current state.
+ include_aliases: Include aliases in the list with RPC methods.
+ """
+ params = {}
+
+ if current:
+ params['current'] = current
+ if include_aliases:
+ params['include_aliases'] = include_aliases
+
+ return client.call('rpc_get_methods', params)
+
+
+@deprecated_alias("get_spdk_version")
+def spdk_get_version(client):
+ """Get SPDK version"""
+ return client.call('spdk_get_version')
+
+
+def _json_dump(config, fd, indent):
+ if indent is None:
+ indent = 2
+ elif indent < 0:
+ indent = None
+ json.dump(config, fd, indent=indent)
+ fd.write('\n')
+
+
+def _json_load(j):
+ if j == sys.stdin or isinstance(j, io):
+ json_conf = json.load(j)
+ elif os.path.exists(j):
+ with open(j, "r") as j:
+ json_conf = json.load(j)
+ else:
+ json_conf = json.loads(j)
+ return json_conf
+
+
+def save_config(client, fd, indent=2):
+ """Write current (live) configuration of SPDK subsystems and targets to stdout.
+ Args:
+ fd: opened file descriptor where data will be saved
+ indent: Indent level. Value less than 0 mean compact mode.
+ Default indent level is 2.
+ """
+ config = {
+ 'subsystems': []
+ }
+
+ for elem in client.call('framework_get_subsystems'):
+ cfg = {
+ 'subsystem': elem['subsystem'],
+ 'config': client.call('framework_get_config', {"name": elem['subsystem']})
+ }
+ config['subsystems'].append(cfg)
+
+ _json_dump(config, fd, indent)
+
+
+def load_config(client, fd, include_aliases=False):
+ """Configure SPDK subsystems and targets using JSON RPC read from stdin.
+ Args:
+ fd: opened file descriptor where data will be taken from
+ """
+ json_config = _json_load(fd)
+
+ # remove subsystems with no config
+ subsystems = json_config['subsystems']
+ for subsystem in list(subsystems):
+ if not subsystem['config']:
+ subsystems.remove(subsystem)
+
+ # check if methods in the config file are known
+ allowed_methods = client.call('rpc_get_methods', {'include_aliases': include_aliases})
+ if not subsystems and 'framework_start_init' in allowed_methods:
+ framework_start_init(client)
+ return
+
+ for subsystem in list(subsystems):
+ config = subsystem['config']
+ for elem in list(config):
+ if 'method' not in elem or elem['method'] not in allowed_methods:
+ raise rpc_client.JSONRPCException("Unknown method was included in the config file")
+
+ while subsystems:
+ allowed_methods = client.call('rpc_get_methods', {'current': True,
+ 'include_aliases': include_aliases})
+ allowed_found = False
+
+ for subsystem in list(subsystems):
+ config = subsystem['config']
+ for elem in list(config):
+ if 'method' not in elem or elem['method'] not in allowed_methods:
+ continue
+
+ client.call(elem['method'], elem['params'])
+ config.remove(elem)
+ allowed_found = True
+
+ if not config:
+ subsystems.remove(subsystem)
+
+ if 'framework_start_init' in allowed_methods:
+ framework_start_init(client)
+ allowed_found = True
+
+ if not allowed_found:
+ break
+
+ if subsystems:
+ print("Some configs were skipped because the RPC state that can call them passed over.")
+
+
+def save_subsystem_config(client, fd, indent=2, name=None):
+ """Write current (live) configuration of SPDK subsystem to stdout.
+ Args:
+ fd: opened file descriptor where data will be saved
+ indent: Indent level. Value less than 0 mean compact mode.
+ Default is indent level 2.
+ """
+ cfg = {
+ 'subsystem': name,
+ 'config': client.call('framework_get_config', {"name": name})
+ }
+
+ _json_dump(cfg, fd, indent)
+
+
+def load_subsystem_config(client, fd):
+ """Configure SPDK subsystem using JSON RPC read from stdin.
+ Args:
+ fd: opened file descriptor where data will be taken from
+ """
+ subsystem = _json_load(fd)
+
+ if not subsystem['config']:
+ return
+
+ allowed_methods = client.call('rpc_get_methods')
+ config = subsystem['config']
+ for elem in list(config):
+ if 'method' not in elem or elem['method'] not in allowed_methods:
+ raise rpc_client.JSONRPCException("Unknown method was included in the config file")
+
+ allowed_methods = client.call('rpc_get_methods', {'current': True})
+ for elem in list(config):
+ if 'method' not in elem or elem['method'] not in allowed_methods:
+ continue
+
+ client.call(elem['method'], elem['params'])
+ config.remove(elem)
+
+ if config:
+ print("Some configs were skipped because they cannot be called in the current RPC state.")
diff --git a/src/spdk/scripts/rpc/app.py b/src/spdk/scripts/rpc/app.py
new file mode 100644
index 000000000..9412de17d
--- /dev/null
+++ b/src/spdk/scripts/rpc/app.py
@@ -0,0 +1,78 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('kill_instance')
+def spdk_kill_instance(client, sig_name):
+ """Send a signal to the SPDK process.
+
+ Args:
+ sig_name: signal to send ("SIGINT", "SIGTERM", "SIGQUIT", "SIGHUP", or "SIGKILL")
+ """
+ params = {'sig_name': sig_name}
+ return client.call('spdk_kill_instance', params)
+
+
+@deprecated_alias('context_switch_monitor')
+def framework_monitor_context_switch(client, enabled=None):
+ """Query or set state of context switch monitoring.
+
+ Args:
+ enabled: True to enable monitoring; False to disable monitoring; None to query (optional)
+
+ Returns:
+ Current context switch monitoring state (after applying enabled flag).
+ """
+ params = {}
+ if enabled is not None:
+ params['enabled'] = enabled
+ return client.call('framework_monitor_context_switch', params)
+
+
+def framework_get_reactors(client):
+ """Query list of all reactors.
+
+ Returns:
+ List of all reactors.
+ """
+ return client.call('framework_get_reactors')
+
+
+def thread_get_stats(client):
+ """Query threads statistics.
+
+ Returns:
+ Current threads statistics.
+ """
+ return client.call('thread_get_stats')
+
+
+def thread_set_cpumask(client, id, cpumask):
+ """Set the cpumask of the thread whose ID matches to the specified value.
+
+ Args:
+ id: thread ID
+ cpumask: cpumask for this thread
+
+ Returns:
+ True or False
+ """
+ params = {'id': id, 'cpumask': cpumask}
+ return client.call('thread_set_cpumask', params)
+
+
+def thread_get_pollers(client):
+ """Query current pollers.
+
+ Returns:
+ Current pollers.
+ """
+ return client.call('thread_get_pollers')
+
+
+def thread_get_io_channels(client):
+ """Query current IO channels.
+
+ Returns:
+ Current IO channels.
+ """
+ return client.call('thread_get_io_channels')
diff --git a/src/spdk/scripts/rpc/bdev.py b/src/spdk/scripts/rpc/bdev.py
new file mode 100644
index 000000000..8c669c0b2
--- /dev/null
+++ b/src/spdk/scripts/rpc/bdev.py
@@ -0,0 +1,1105 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('set_bdev_options')
+def bdev_set_options(client, bdev_io_pool_size=None, bdev_io_cache_size=None, bdev_auto_examine=None):
+ """Set parameters for the bdev subsystem.
+
+ Args:
+ bdev_io_pool_size: number of bdev_io structures in shared buffer pool (optional)
+ bdev_io_cache_size: maximum number of bdev_io structures cached per thread (optional)
+ bdev_auto_examine: if set to false, the bdev layer will not examine every disks automatically (optional)
+ """
+ params = {}
+
+ if bdev_io_pool_size:
+ params['bdev_io_pool_size'] = bdev_io_pool_size
+ if bdev_io_cache_size:
+ params['bdev_io_cache_size'] = bdev_io_cache_size
+ if bdev_auto_examine is not None:
+ params["bdev_auto_examine"] = bdev_auto_examine
+
+ return client.call('bdev_set_options', params)
+
+
+@deprecated_alias('construct_compress_bdev')
+def bdev_compress_create(client, base_bdev_name, pm_path, lb_size):
+ """Construct a compress virtual block device.
+
+ Args:
+ base_bdev_name: name of the underlying base bdev
+ pm_path: path to persistent memory
+ lb_size: logical block size for the compressed vol in bytes. Must be 4K or 512.
+
+ Returns:
+ Name of created virtual block device.
+ """
+ params = {'base_bdev_name': base_bdev_name, 'pm_path': pm_path, 'lb_size': lb_size}
+
+ return client.call('bdev_compress_create', params)
+
+
+@deprecated_alias('delete_compress_bdev')
+def bdev_compress_delete(client, name):
+ """Delete compress virtual block device.
+
+ Args:
+ name: name of compress vbdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_compress_delete', params)
+
+
+@deprecated_alias('set_compress_pmd')
+def compress_set_pmd(client, pmd):
+ """Set pmd options for the bdev compress.
+
+ Args:
+ pmd: 0 = auto-select, 1 = QAT, 2 = ISAL
+ """
+ params = {'pmd': pmd}
+
+ return client.call('compress_set_pmd', params)
+
+
+def bdev_compress_get_orphans(client, name=None):
+ """Get a list of comp bdevs that do not have a pmem file (aka orphaned).
+
+ Args:
+ name: comp bdev name to query (optional; if omitted, query all comp bdevs)
+
+ Returns:
+ List of comp bdev names.
+ """
+ params = {}
+ if name:
+ params['name'] = name
+ return client.call('bdev_compress_get_orphans', params)
+
+
+@deprecated_alias('construct_crypto_bdev')
+def bdev_crypto_create(client, base_bdev_name, name, crypto_pmd, key, cipher=None, key2=None):
+ """Construct a crypto virtual block device.
+
+ Args:
+ base_bdev_name: name of the underlying base bdev
+ name: name for the crypto vbdev
+ crypto_pmd: name of of the DPDK crypto driver to use
+ key: key
+
+ Returns:
+ Name of created virtual block device.
+ """
+ params = {'base_bdev_name': base_bdev_name, 'name': name, 'crypto_pmd': crypto_pmd, 'key': key}
+ if cipher:
+ params['cipher'] = cipher
+ if key2:
+ params['key2'] = key2
+ return client.call('bdev_crypto_create', params)
+
+
+@deprecated_alias('delete_crypto_bdev')
+def bdev_crypto_delete(client, name):
+ """Delete crypto virtual block device.
+
+ Args:
+ name: name of crypto vbdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_crypto_delete', params)
+
+
+@deprecated_alias('construct_ocf_bdev')
+def bdev_ocf_create(client, name, mode, cache_bdev_name, core_bdev_name):
+ """Add an OCF block device
+
+ Args:
+ name: name of constructed OCF bdev
+ mode: OCF cache mode: {'wb', 'wt', 'pt', 'wa', 'wi', 'wo'}
+ cache_bdev_name: name of underlying cache bdev
+ core_bdev_name: name of underlying core bdev
+
+ Returns:
+ Name of created block device
+ """
+ params = {'name': name, 'mode': mode, 'cache_bdev_name': cache_bdev_name, 'core_bdev_name': core_bdev_name}
+
+ return client.call('bdev_ocf_create', params)
+
+
+@deprecated_alias('delete_ocf_bdev')
+def bdev_ocf_delete(client, name):
+ """Delete an OCF device
+
+ Args:
+ name: name of OCF bdev
+
+ """
+ params = {'name': name}
+
+ return client.call('bdev_ocf_delete', params)
+
+
+@deprecated_alias('get_ocf_stats')
+def bdev_ocf_get_stats(client, name):
+ """Get statistics of chosen OCF block device
+
+ Args:
+ name: name of OCF bdev
+
+ Returns:
+ Statistics as json object
+ """
+ params = {'name': name}
+
+ return client.call('bdev_ocf_get_stats', params)
+
+
+@deprecated_alias('get_ocf_stats')
+def bdev_ocf_get_bdevs(client, name=None):
+ """Get list of OCF devices including unregistered ones
+
+ Args:
+ name: name of OCF vbdev or name of cache device or name of core device (optional)
+
+ Returns:
+ Array of OCF devices with their current status
+ """
+ params = None
+ if name:
+ params = {'name': name}
+ return client.call('bdev_ocf_get_bdevs', params)
+
+
+@deprecated_alias('construct_malloc_bdev')
+def bdev_malloc_create(client, num_blocks, block_size, name=None, uuid=None):
+ """Construct a malloc block device.
+
+ Args:
+ num_blocks: size of block device in blocks
+ block_size: block size of device; must be a power of 2 and at least 512
+ name: name of block device (optional)
+ uuid: UUID of block device (optional)
+
+ Returns:
+ Name of created block device.
+ """
+ params = {'num_blocks': num_blocks, 'block_size': block_size}
+ if name:
+ params['name'] = name
+ if uuid:
+ params['uuid'] = uuid
+ return client.call('bdev_malloc_create', params)
+
+
+@deprecated_alias('delete_malloc_bdev')
+def bdev_malloc_delete(client, name):
+ """Delete malloc block device.
+
+ Args:
+ bdev_name: name of malloc bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_malloc_delete', params)
+
+
+@deprecated_alias('construct_null_bdev')
+def bdev_null_create(client, num_blocks, block_size, name, uuid=None, md_size=None,
+ dif_type=None, dif_is_head_of_md=None):
+ """Construct a null block device.
+
+ Args:
+ num_blocks: size of block device in blocks
+ block_size: block size of device; data part size must be a power of 2 and at least 512
+ name: name of block device
+ uuid: UUID of block device (optional)
+ md_size: metadata size of device (optional)
+ dif_type: protection information type (optional)
+ dif_is_head_of_md: protection information is in the first 8 bytes of metadata (optional)
+
+ Returns:
+ Name of created block device.
+ """
+ params = {'name': name, 'num_blocks': num_blocks,
+ 'block_size': block_size}
+ if uuid:
+ params['uuid'] = uuid
+ if md_size:
+ params['md_size'] = md_size
+ if dif_type:
+ params['dif_type'] = dif_type
+ if dif_is_head_of_md:
+ params['dif_is_head_of_md'] = dif_is_head_of_md
+ return client.call('bdev_null_create', params)
+
+
+@deprecated_alias('delete_null_bdev')
+def bdev_null_delete(client, name):
+ """Remove null bdev from the system.
+
+ Args:
+ name: name of null bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_null_delete', params)
+
+
+@deprecated_alias('get_raid_bdevs')
+def bdev_raid_get_bdevs(client, category):
+ """Get list of raid bdevs based on category
+
+ Args:
+ category: any one of all or online or configuring or offline
+
+ Returns:
+ List of raid bdev names
+ """
+ params = {'category': category}
+ return client.call('bdev_raid_get_bdevs', params)
+
+
+@deprecated_alias('construct_raid_bdev')
+def bdev_raid_create(client, name, raid_level, base_bdevs, strip_size=None, strip_size_kb=None):
+ """Create raid bdev. Either strip size arg will work but one is required.
+
+ Args:
+ name: user defined raid bdev name
+ strip_size (deprecated): strip size of raid bdev in KB, supported values like 8, 16, 32, 64, 128, 256, etc
+ strip_size_kb: strip size of raid bdev in KB, supported values like 8, 16, 32, 64, 128, 256, etc
+ raid_level: raid level of raid bdev, supported values 0
+ base_bdevs: Space separated names of Nvme bdevs in double quotes, like "Nvme0n1 Nvme1n1 Nvme2n1"
+
+ Returns:
+ None
+ """
+ params = {'name': name, 'raid_level': raid_level, 'base_bdevs': base_bdevs}
+
+ if strip_size:
+ params['strip_size'] = strip_size
+
+ if strip_size_kb:
+ params['strip_size_kb'] = strip_size_kb
+
+ return client.call('bdev_raid_create', params)
+
+
+@deprecated_alias('destroy_raid_bdev')
+def bdev_raid_delete(client, name):
+ """Delete raid bdev
+
+ Args:
+ name: raid bdev name
+
+ Returns:
+ None
+ """
+ params = {'name': name}
+ return client.call('bdev_raid_delete', params)
+
+
+@deprecated_alias('construct_aio_bdev')
+def bdev_aio_create(client, filename, name, block_size=None):
+ """Construct a Linux AIO block device.
+
+ Args:
+ filename: path to device or file (ex: /dev/sda)
+ name: name of block device
+ block_size: block size of device (optional; autodetected if omitted)
+
+ Returns:
+ Name of created block device.
+ """
+ params = {'name': name,
+ 'filename': filename}
+
+ if block_size:
+ params['block_size'] = block_size
+
+ return client.call('bdev_aio_create', params)
+
+
+@deprecated_alias('delete_aio_bdev')
+def bdev_aio_delete(client, name):
+ """Remove aio bdev from the system.
+
+ Args:
+ bdev_name: name of aio bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_aio_delete', params)
+
+
+def bdev_uring_create(client, filename, name, block_size=None):
+ """Create a bdev with Linux io_uring backend.
+
+ Args:
+ filename: path to device or file (ex: /dev/nvme0n1)
+ name: name of bdev
+ block_size: block size of device (optional; autodetected if omitted)
+
+ Returns:
+ Name of created bdev.
+ """
+ params = {'name': name,
+ 'filename': filename}
+
+ if block_size:
+ params['block_size'] = block_size
+
+ return client.call('bdev_uring_create', params)
+
+
+def bdev_uring_delete(client, name):
+ """Delete a uring bdev.
+
+ Args:
+ name: name of uring bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_uring_delete', params)
+
+
+@deprecated_alias('set_bdev_nvme_options')
+def bdev_nvme_set_options(client, action_on_timeout=None, timeout_us=None, retry_count=None,
+ arbitration_burst=None, low_priority_weight=None,
+ medium_priority_weight=None, high_priority_weight=None,
+ nvme_adminq_poll_period_us=None, nvme_ioq_poll_period_us=None, io_queue_requests=None,
+ delay_cmd_submit=None):
+ """Set options for the bdev nvme. This is startup command.
+
+ Args:
+ action_on_timeout: action to take on command time out. Valid values are: none, reset, abort (optional)
+ timeout_us: Timeout for each command, in microseconds. If 0, don't track timeouts (optional)
+ retry_count: The number of attempts per I/O when an I/O fails (optional)
+ arbitration_burst: The value is expressed as a power of two (optional)
+ low_prioity_weight: The number of commands that may be executed from the low priority queue at one time (optional)
+ medium_prioity_weight: The number of commands that may be executed from the medium priority queue at one time (optional)
+ high_prioity_weight: The number of commands that may be executed from the high priority queue at one time (optional)
+ nvme_adminq_poll_period_us: How often the admin queue is polled for asynchronous events in microseconds (optional)
+ nvme_ioq_poll_period_us: How often to poll I/O queues for completions in microseconds (optional)
+ io_queue_requests: The number of requests allocated for each NVMe I/O queue. Default: 512 (optional)
+ delay_cmd_submit: Enable delayed NVMe command submission to allow batching of multiple commands (optional)
+ """
+ params = {}
+
+ if action_on_timeout:
+ params['action_on_timeout'] = action_on_timeout
+
+ if timeout_us:
+ params['timeout_us'] = timeout_us
+
+ if retry_count:
+ params['retry_count'] = retry_count
+
+ if arbitration_burst:
+ params['arbitration_burst'] = arbitration_burst
+
+ if low_priority_weight:
+ params['low_priority_weight'] = low_priority_weight
+
+ if medium_priority_weight:
+ params['medium_priority_weight'] = medium_priority_weight
+
+ if high_priority_weight:
+ params['high_priority_weight'] = high_priority_weight
+
+ if nvme_adminq_poll_period_us:
+ params['nvme_adminq_poll_period_us'] = nvme_adminq_poll_period_us
+
+ if nvme_ioq_poll_period_us:
+ params['nvme_ioq_poll_period_us'] = nvme_ioq_poll_period_us
+
+ if io_queue_requests:
+ params['io_queue_requests'] = io_queue_requests
+
+ if delay_cmd_submit is not None:
+ params['delay_cmd_submit'] = delay_cmd_submit
+
+ return client.call('bdev_nvme_set_options', params)
+
+
+@deprecated_alias('set_bdev_nvme_hotplug')
+def bdev_nvme_set_hotplug(client, enable, period_us=None):
+ """Set options for the bdev nvme. This is startup command.
+
+ Args:
+ enable: True to enable hotplug, False to disable.
+ period_us: how often the hotplug is processed for insert and remove events. Set 0 to reset to default. (optional)
+ """
+ params = {'enable': enable}
+
+ if period_us:
+ params['period_us'] = period_us
+
+ return client.call('bdev_nvme_set_hotplug', params)
+
+
+@deprecated_alias('construct_nvme_bdev')
+def bdev_nvme_attach_controller(client, name, trtype, traddr, adrfam=None, trsvcid=None,
+ priority=None, subnqn=None, hostnqn=None, hostaddr=None,
+ hostsvcid=None, prchk_reftag=None, prchk_guard=None):
+ """Construct block device for each NVMe namespace in the attached controller.
+
+ Args:
+ name: bdev name prefix; "n" + namespace ID will be appended to create unique names
+ trtype: transport type ("PCIe", "RDMA")
+ traddr: transport address (PCI BDF or IP address)
+ adrfam: address family ("IPv4", "IPv6", "IB", or "FC") (optional for PCIe)
+ trsvcid: transport service ID (port number for IP-based addresses; optional for PCIe)
+ priority: transport connection priority (Sock priority for TCP-based transports; optional)
+ subnqn: subsystem NQN to connect to (optional)
+ hostnqn: NQN to connect from (optional)
+ hostaddr: host transport address (IP address for IP-based transports, NULL for PCIe or FC; optional)
+ hostsvcid: host transport service ID (port number for IP-based transports, NULL for PCIe or FC; optional)
+ prchk_reftag: Enable checking of PI reference tag for I/O processing (optional)
+ prchk_guard: Enable checking of PI guard for I/O processing (optional)
+
+ Returns:
+ Names of created block devices.
+ """
+ params = {'name': name,
+ 'trtype': trtype,
+ 'traddr': traddr}
+
+ if hostnqn:
+ params['hostnqn'] = hostnqn
+
+ if hostaddr:
+ params['hostaddr'] = hostaddr
+
+ if hostsvcid:
+ params['hostsvcid'] = hostsvcid
+
+ if adrfam:
+ params['adrfam'] = adrfam
+
+ if trsvcid:
+ params['trsvcid'] = trsvcid
+
+ if priority:
+ params['priority'] = priority
+
+ if subnqn:
+ params['subnqn'] = subnqn
+
+ if prchk_reftag:
+ params['prchk_reftag'] = prchk_reftag
+
+ if prchk_guard:
+ params['prchk_guard'] = prchk_guard
+
+ return client.call('bdev_nvme_attach_controller', params)
+
+
+@deprecated_alias('delete_nvme_controller')
+def bdev_nvme_detach_controller(client, name):
+ """Detach NVMe controller and delete any associated bdevs.
+
+ Args:
+ name: controller name
+ """
+
+ params = {'name': name}
+ return client.call('bdev_nvme_detach_controller', params)
+
+
+def bdev_nvme_cuse_register(client, name):
+ """Register CUSE devices on NVMe controller.
+
+ Args:
+ name: Name of the operating NVMe controller
+ """
+ params = {'name': name}
+
+ return client.call('bdev_nvme_cuse_register', params)
+
+
+def bdev_nvme_cuse_unregister(client, name):
+ """Unregister CUSE devices on NVMe controller.
+
+ Args:
+ name: Name of the operating NVMe controller
+ """
+ params = {'name': name}
+
+ return client.call('bdev_nvme_cuse_unregister', params)
+
+
+def bdev_zone_block_create(client, name, base_bdev, zone_capacity, optimal_open_zones):
+ """Creates a virtual zone device on top of existing non-zoned bdev.
+
+ Args:
+ name: Zone device name
+ base_bdev: Base Nvme bdev name
+ zone_capacity: Surfaced zone capacity in blocks
+ optimal_open_zones: Number of zones required to reach optimal write speed (optional, default: 1)
+
+ Returns:
+ Name of created block device.
+ """
+ params = {'name': name,
+ 'base_bdev': base_bdev,
+ 'zone_capacity': zone_capacity,
+ 'optimal_open_zones': optimal_open_zones}
+
+ return client.call('bdev_zone_block_create', params)
+
+
+def bdev_zone_block_delete(client, name):
+ """Remove block zone bdev from the system.
+
+ Args:
+ name: name of block zone bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_zone_block_delete', params)
+
+
+@deprecated_alias('construct_rbd_bdev')
+def bdev_rbd_create(client, pool_name, rbd_name, block_size, name=None, user=None, config=None):
+ """Create a Ceph RBD block device.
+
+ Args:
+ pool_name: Ceph RBD pool name
+ rbd_name: Ceph RBD image name
+ block_size: block size of RBD volume
+ name: name of block device (optional)
+ user: Ceph user name (optional)
+ config: map of config keys to values (optional)
+
+ Returns:
+ Name of created block device.
+ """
+ params = {
+ 'pool_name': pool_name,
+ 'rbd_name': rbd_name,
+ 'block_size': block_size,
+ }
+
+ if name:
+ params['name'] = name
+ if user is not None:
+ params['user_id'] = user
+ if config is not None:
+ params['config'] = config
+
+ return client.call('bdev_rbd_create', params)
+
+
+@deprecated_alias('delete_rbd_bdev')
+def bdev_rbd_delete(client, name):
+ """Remove rbd bdev from the system.
+
+ Args:
+ name: name of rbd bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_rbd_delete', params)
+
+
+def bdev_rbd_resize(client, name, new_size):
+ """Resize rbd bdev in the system.
+
+ Args:
+ name: name of rbd bdev to resize
+ new_size: new bdev size of resize operation. The unit is MiB
+ """
+ params = {
+ 'name': name,
+ 'new_size': new_size,
+ }
+ return client.call('bdev_rbd_resize', params)
+
+
+@deprecated_alias('construct_error_bdev')
+def bdev_error_create(client, base_name):
+ """Construct an error injection block device.
+
+ Args:
+ base_name: base bdev name
+ """
+ params = {'base_name': base_name}
+ return client.call('bdev_error_create', params)
+
+
+def bdev_delay_create(client, base_bdev_name, name, avg_read_latency, p99_read_latency, avg_write_latency, p99_write_latency):
+ """Construct a delay block device.
+
+ Args:
+ base_bdev_name: name of the existing bdev
+ name: name of block device
+ avg_read_latency: complete 99% of read ops with this delay
+ p99_read_latency: complete 1% of read ops with this delay
+ avg_write_latency: complete 99% of write ops with this delay
+ p99_write_latency: complete 1% of write ops with this delay
+
+ Returns:
+ Name of created block device.
+ """
+ params = {
+ 'base_bdev_name': base_bdev_name,
+ 'name': name,
+ 'avg_read_latency': avg_read_latency,
+ 'p99_read_latency': p99_read_latency,
+ 'avg_write_latency': avg_write_latency,
+ 'p99_write_latency': p99_write_latency,
+ }
+ return client.call('bdev_delay_create', params)
+
+
+def bdev_delay_delete(client, name):
+ """Remove delay bdev from the system.
+
+ Args:
+ name: name of delay bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_delay_delete', params)
+
+
+def bdev_delay_update_latency(client, delay_bdev_name, latency_type, latency_us):
+ """Update the latency value for a delay block device
+
+ Args:
+ delay_bdev_name: name of the delay bdev
+ latency_type: 'one of: avg_read, avg_write, p99_read, p99_write. No other values accepted.'
+ latency_us: 'new latency value.'
+
+ Returns:
+ True if successful, or a specific error otherwise.
+ """
+ params = {
+ 'delay_bdev_name': delay_bdev_name,
+ 'latency_type': latency_type,
+ 'latency_us': latency_us,
+ }
+ return client.call('bdev_delay_update_latency', params)
+
+
+@deprecated_alias('delete_error_bdev')
+def bdev_error_delete(client, name):
+ """Remove error bdev from the system.
+
+ Args:
+ bdev_name: name of error bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_error_delete', params)
+
+
+@deprecated_alias('construct_iscsi_bdev')
+def bdev_iscsi_create(client, name, url, initiator_iqn):
+ """Construct an iSCSI block device.
+
+ Args:
+ name: name of block device
+ url: iSCSI URL
+ initiator_iqn: IQN name to be used by initiator
+
+ Returns:
+ Name of created block device.
+ """
+ params = {
+ 'name': name,
+ 'url': url,
+ 'initiator_iqn': initiator_iqn,
+ }
+ return client.call('bdev_iscsi_create', params)
+
+
+@deprecated_alias('delete_iscsi_bdev')
+def bdev_iscsi_delete(client, name):
+ """Remove iSCSI bdev from the system.
+
+ Args:
+ bdev_name: name of iSCSI bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_iscsi_delete', params)
+
+
+@deprecated_alias('construct_pmem_bdev')
+def bdev_pmem_create(client, pmem_file, name):
+ """Construct a libpmemblk block device.
+
+ Args:
+ pmem_file: path to pmemblk pool file
+ name: name of block device
+
+ Returns:
+ Name of created block device.
+ """
+ params = {
+ 'pmem_file': pmem_file,
+ 'name': name
+ }
+ return client.call('bdev_pmem_create', params)
+
+
+@deprecated_alias('delete_pmem_bdev')
+def bdev_pmem_delete(client, name):
+ """Remove pmem bdev from the system.
+
+ Args:
+ name: name of pmem bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_pmem_delete', params)
+
+
+@deprecated_alias('construct_passthru_bdev')
+def bdev_passthru_create(client, base_bdev_name, name):
+ """Construct a pass-through block device.
+
+ Args:
+ base_bdev_name: name of the existing bdev
+ name: name of block device
+
+ Returns:
+ Name of created block device.
+ """
+ params = {
+ 'base_bdev_name': base_bdev_name,
+ 'name': name,
+ }
+ return client.call('bdev_passthru_create', params)
+
+
+@deprecated_alias('delete_passthru_bdev')
+def bdev_passthru_delete(client, name):
+ """Remove pass through bdev from the system.
+
+ Args:
+ name: name of pass through bdev to delete
+ """
+ params = {'name': name}
+ return client.call('bdev_passthru_delete', params)
+
+
+def bdev_opal_create(client, nvme_ctrlr_name, nsid, locking_range_id, range_start, range_length, password):
+ """Create opal virtual block devices from a base nvme bdev.
+
+ Args:
+ nvme_ctrlr_name: name of the nvme ctrlr
+ nsid: namespace ID of nvme ctrlr
+ locking_range_id: locking range ID corresponding to this virtual bdev
+ range_start: start address of this locking range
+ range_length: length of this locking range
+ password: admin password of base nvme bdev
+
+ Returns:
+ Name of the new created block devices.
+ """
+ params = {
+ 'nvme_ctrlr_name': nvme_ctrlr_name,
+ 'nsid': nsid,
+ 'locking_range_id': locking_range_id,
+ 'range_start': range_start,
+ 'range_length': range_length,
+ 'password': password,
+ }
+
+ return client.call('bdev_opal_create', params)
+
+
+def bdev_opal_get_info(client, bdev_name, password):
+ """Get opal locking range info.
+
+ Args:
+ bdev_name: name of opal vbdev to get info
+ password: admin password
+
+ Returns:
+ Locking range info.
+ """
+ params = {
+ 'bdev_name': bdev_name,
+ 'password': password,
+ }
+
+ return client.call('bdev_opal_get_info', params)
+
+
+def bdev_opal_delete(client, bdev_name, password):
+ """Delete opal virtual bdev from the system.
+
+ Args:
+ bdev_name: name of opal vbdev to delete
+ password: admin password of base nvme bdev
+ """
+ params = {
+ 'bdev_name': bdev_name,
+ 'password': password,
+ }
+
+ return client.call('bdev_opal_delete', params)
+
+
+def bdev_opal_new_user(client, bdev_name, admin_password, user_id, user_password):
+ """Add a user to opal bdev who can set lock state for this bdev.
+
+ Args:
+ bdev_name: name of opal vbdev
+ admin_password: admin password
+ user_id: ID of the user who will be added to this opal bdev
+ user_password: password set for this user
+ """
+ params = {
+ 'bdev_name': bdev_name,
+ 'admin_password': admin_password,
+ 'user_id': user_id,
+ 'user_password': user_password,
+ }
+
+ return client.call('bdev_opal_new_user', params)
+
+
+def bdev_opal_set_lock_state(client, bdev_name, user_id, password, lock_state):
+ """set lock state for an opal bdev.
+
+ Args:
+ bdev_name: name of opal vbdev
+ user_id: ID of the user who will set lock state
+ password: password of the user
+ lock_state: lock state to set
+ """
+ params = {
+ 'bdev_name': bdev_name,
+ 'user_id': user_id,
+ 'password': password,
+ 'lock_state': lock_state,
+ }
+
+ return client.call('bdev_opal_set_lock_state', params)
+
+
+@deprecated_alias('construct_split_vbdev')
+def bdev_split_create(client, base_bdev, split_count, split_size_mb=None):
+ """Create split block devices from a base bdev.
+
+ Args:
+ base_bdev: name of bdev to split
+ split_count: number of split bdevs to create
+ split_size_mb: size of each split volume in MiB (optional)
+
+ Returns:
+ List of created block devices.
+ """
+ params = {
+ 'base_bdev': base_bdev,
+ 'split_count': split_count,
+ }
+ if split_size_mb:
+ params['split_size_mb'] = split_size_mb
+
+ return client.call('bdev_split_create', params)
+
+
+@deprecated_alias('destruct_split_vbdev')
+def bdev_split_delete(client, base_bdev):
+ """Delete split block devices.
+
+ Args:
+ base_bdev: name of previously split bdev
+ """
+ params = {
+ 'base_bdev': base_bdev,
+ }
+
+ return client.call('bdev_split_delete', params)
+
+
+@deprecated_alias('construct_ftl_bdev')
+def bdev_ftl_create(client, name, base_bdev, **kwargs):
+ """Construct FTL bdev
+
+ Args:
+ name: name of the bdev
+ base_bdev: name of the base bdev
+ kwargs: optional parameters
+ """
+ params = {'name': name,
+ 'base_bdev': base_bdev}
+ for key, value in kwargs.items():
+ if value is not None:
+ params[key] = value
+
+ return client.call('bdev_ftl_create', params)
+
+
+@deprecated_alias('delete_ftl_bdev')
+def bdev_ftl_delete(client, name):
+ """Delete FTL bdev
+
+ Args:
+ name: name of the bdev
+ """
+ params = {'name': name}
+
+ return client.call('bdev_ftl_delete', params)
+
+
+def bdev_ocssd_create(client, ctrlr_name, bdev_name, nsid=None, range=None):
+ """Creates Open Channel zoned bdev on specified Open Channel controller
+
+ Args:
+ ctrlr_name: name of the OC NVMe controller
+ bdev_name: name of the bdev to create
+ nsid: namespace ID
+ range: parallel unit range
+ """
+ params = {'ctrlr_name': ctrlr_name,
+ 'bdev_name': bdev_name}
+
+ if nsid is not None:
+ params['nsid'] = nsid
+
+ if range is not None:
+ params['range'] = range
+
+ return client.call('bdev_ocssd_create', params)
+
+
+def bdev_ocssd_delete(client, name):
+ """Deletes Open Channel bdev
+
+ Args:
+ name: name of the bdev
+ """
+ params = {'name': name}
+
+ return client.call('bdev_ocssd_delete', params)
+
+
+@deprecated_alias('get_bdevs')
+def bdev_get_bdevs(client, name=None):
+ """Get information about block devices.
+
+ Args:
+ name: bdev name to query (optional; if omitted, query all bdevs)
+
+ Returns:
+ List of bdev information objects.
+ """
+ params = {}
+ if name:
+ params['name'] = name
+ return client.call('bdev_get_bdevs', params)
+
+
+@deprecated_alias('get_bdevs_iostat')
+def bdev_get_iostat(client, name=None):
+ """Get I/O statistics for block devices.
+
+ Args:
+ name: bdev name to query (optional; if omitted, query all bdevs)
+
+ Returns:
+ I/O statistics for the requested block devices.
+ """
+ params = {}
+ if name:
+ params['name'] = name
+ return client.call('bdev_get_iostat', params)
+
+
+@deprecated_alias('enable_bdev_histogram')
+def bdev_enable_histogram(client, name, enable):
+ """Control whether histogram is enabled for specified bdev.
+
+ Args:
+ bdev_name: name of bdev
+ """
+ params = {'name': name, "enable": enable}
+ return client.call('bdev_enable_histogram', params)
+
+
+@deprecated_alias('get_bdev_histogram')
+def bdev_get_histogram(client, name):
+ """Get histogram for specified bdev.
+
+ Args:
+ bdev_name: name of bdev
+ """
+ params = {'name': name}
+ return client.call('bdev_get_histogram', params)
+
+
+@deprecated_alias('bdev_inject_error')
+def bdev_error_inject_error(client, name, io_type, error_type, num=1):
+ """Inject an error via an error bdev.
+
+ Args:
+ name: name of error bdev
+ io_type: one of "clear", "read", "write", "unmap", "flush", or "all"
+ error_type: one of "failure" or "pending"
+ num: number of commands to fail
+ """
+ params = {
+ 'name': name,
+ 'io_type': io_type,
+ 'error_type': error_type,
+ 'num': num,
+ }
+
+ return client.call('bdev_error_inject_error', params)
+
+
+@deprecated_alias('set_bdev_qd_sampling_period')
+def bdev_set_qd_sampling_period(client, name, period):
+ """Enable queue depth tracking on a specified bdev.
+
+ Args:
+ name: name of a bdev on which to track queue depth.
+ period: period (in microseconds) at which to update the queue depth reading. If set to 0, polling will be disabled.
+ """
+
+ params = {}
+ params['name'] = name
+ params['period'] = period
+ return client.call('bdev_set_qd_sampling_period', params)
+
+
+@deprecated_alias('set_bdev_qos_limit')
+def bdev_set_qos_limit(
+ client,
+ name,
+ rw_ios_per_sec=None,
+ rw_mbytes_per_sec=None,
+ r_mbytes_per_sec=None,
+ w_mbytes_per_sec=None):
+ """Set QoS rate limit on a block device.
+
+ Args:
+ name: name of block device
+ rw_ios_per_sec: R/W IOs per second limit (>=10000, example: 20000). 0 means unlimited.
+ rw_mbytes_per_sec: R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.
+ r_mbytes_per_sec: Read megabytes per second limit (>=10, example: 100). 0 means unlimited.
+ w_mbytes_per_sec: Write megabytes per second limit (>=10, example: 100). 0 means unlimited.
+ """
+ params = {}
+ params['name'] = name
+ if rw_ios_per_sec is not None:
+ params['rw_ios_per_sec'] = rw_ios_per_sec
+ if rw_mbytes_per_sec is not None:
+ params['rw_mbytes_per_sec'] = rw_mbytes_per_sec
+ if r_mbytes_per_sec is not None:
+ params['r_mbytes_per_sec'] = r_mbytes_per_sec
+ if w_mbytes_per_sec is not None:
+ params['w_mbytes_per_sec'] = w_mbytes_per_sec
+ return client.call('bdev_set_qos_limit', params)
+
+
+@deprecated_alias('apply_firmware')
+def bdev_nvme_apply_firmware(client, bdev_name, filename):
+ """Download and commit firmware to NVMe device.
+
+ Args:
+ bdev_name: name of NVMe block device
+ filename: filename of the firmware to download
+ """
+ params = {
+ 'filename': filename,
+ 'bdev_name': bdev_name,
+ }
+ return client.call('bdev_nvme_apply_firmware', params)
diff --git a/src/spdk/scripts/rpc/blobfs.py b/src/spdk/scripts/rpc/blobfs.py
new file mode 100644
index 000000000..a064afecf
--- /dev/null
+++ b/src/spdk/scripts/rpc/blobfs.py
@@ -0,0 +1,57 @@
+def blobfs_detect(client, bdev_name):
+ """Detect whether a blobfs exists on bdev.
+
+ Args:
+ bdev_name: block device name to detect blobfs
+
+ Returns:
+ True if a blobfs exists on the bdev; False otherwise.
+ """
+ params = {
+ 'bdev_name': bdev_name
+ }
+ return client.call('blobfs_detect', params)
+
+
+def blobfs_create(client, bdev_name, cluster_sz=None):
+ """Build blobfs on bdev.
+
+ Args:
+ bdev_name: block device name to build blobfs
+ cluster_sz: Size of cluster in bytes (Optional). Must be multiple of 4KB page size. Default and minimal value is 1M.
+ """
+ params = {
+ 'bdev_name': bdev_name
+ }
+ if cluster_sz:
+ params['cluster_sz'] = cluster_sz
+ return client.call('blobfs_create', params)
+
+
+def blobfs_mount(client, bdev_name, mountpoint):
+ """Mount blobfs on bdev by FUSE.
+
+ Args:
+ bdev_name: block device name where the blobfs is
+ mountpoint: Mountpoint path in host to mount blobfs
+ """
+ params = {
+ 'bdev_name': bdev_name,
+ 'mountpoint': mountpoint
+ }
+ return client.call('blobfs_mount', params)
+
+
+def blobfs_set_cache_size(client, size_in_mb):
+ """Set cache size for the blobstore filesystem.
+
+ Args:
+ size_in_mb: Cache size in megabytes
+
+ Returns:
+ True if cache size is set successfully; False if failed to set.
+ """
+ params = {
+ 'size_in_mb': size_in_mb
+ }
+ return client.call('blobfs_set_cache_size', params)
diff --git a/src/spdk/scripts/rpc/client.py b/src/spdk/scripts/rpc/client.py
new file mode 100644
index 000000000..52ba8d216
--- /dev/null
+++ b/src/spdk/scripts/rpc/client.py
@@ -0,0 +1,183 @@
+import json
+import socket
+import time
+import os
+import logging
+import copy
+
+
+def print_dict(d):
+ print(json.dumps(d, indent=2))
+
+
+def print_json(s):
+ print(json.dumps(s, indent=2).strip('"'))
+
+
+class JSONRPCException(Exception):
+ def __init__(self, message):
+ self.message = message
+
+
+class JSONRPCClient(object):
+ def __init__(self, addr, port=None, timeout=60.0, **kwargs):
+ self.sock = None
+ ch = logging.StreamHandler()
+ ch.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
+ ch.setLevel(logging.DEBUG)
+ self._logger = logging.getLogger("JSONRPCClient(%s)" % addr)
+ self._logger.addHandler(ch)
+ self.log_set_level(kwargs.get('log_level', logging.ERROR))
+ connect_retries = kwargs.get('conn_retries', 0)
+
+ self.timeout = timeout
+ self._request_id = 0
+ self._recv_buf = ""
+ self._reqs = []
+
+ for i in range(connect_retries):
+ try:
+ self._connect(addr, port)
+ return
+ except Exception as e:
+ # ignore and retry in 200ms
+ time.sleep(0.2)
+
+ # try one last time without try/except
+ self._connect(addr, port)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exception_type, exception_value, traceback):
+ self.close()
+
+ def _connect(self, addr, port):
+ try:
+ if os.path.exists(addr):
+ self._logger.debug("Trying to connect to UNIX socket: %s", addr)
+ self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ self.sock.connect(addr)
+ elif port:
+ if ':' in addr:
+ self._logger.debug("Trying to connect to IPv6 address addr:%s, port:%i", addr, port)
+ for res in socket.getaddrinfo(addr, port, socket.AF_INET6, socket.SOCK_STREAM, socket.SOL_TCP):
+ af, socktype, proto, canonname, sa = res
+ self.sock = socket.socket(af, socktype, proto)
+ self.sock.connect(sa)
+ else:
+ self._logger.debug("Trying to connect to IPv4 address addr:%s, port:%i'", addr, port)
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.connect((addr, port))
+ else:
+ raise socket.error("Unix socket '%s' does not exist" % addr)
+ except socket.error as ex:
+ raise JSONRPCException("Error while connecting to %s\n"
+ "Error details: %s" % (addr, ex))
+
+ def get_logger(self):
+ return self._logger
+
+ """Set logging level
+
+ Args:
+ lvl: Log level to set as accepted by logger.setLevel
+ """
+ def log_set_level(self, lvl):
+ self._logger.info("Setting log level to %s", lvl)
+ self._logger.setLevel(lvl)
+ self._logger.info("Log level set to %s", lvl)
+
+ def close(self):
+ if getattr(self, "sock", None):
+ self.sock.shutdown(socket.SHUT_RDWR)
+ self.sock.close()
+ self.sock = None
+
+ def add_request(self, method, params):
+ self._request_id += 1
+ req = {
+ 'jsonrpc': '2.0',
+ 'method': method,
+ 'id': self._request_id
+ }
+
+ if params:
+ req['params'] = copy.deepcopy(params)
+
+ self._logger.debug("append request:\n%s\n", json.dumps(req))
+ self._reqs.append(req)
+ return self._request_id
+
+ def flush(self):
+ self._logger.debug("Flushing buffer")
+ # TODO: We can drop indent parameter
+ reqstr = "\n".join(json.dumps(req, indent=2) for req in self._reqs)
+ self._reqs = []
+ self._logger.info("Requests:\n%s\n", reqstr)
+ self.sock.sendall(reqstr.encode("utf-8"))
+
+ def send(self, method, params=None):
+ id = self.add_request(method, params)
+ self.flush()
+ return id
+
+ def decode_one_response(self):
+ try:
+ self._logger.debug("Trying to decode response '%s'", self._recv_buf)
+ buf = self._recv_buf.lstrip()
+ obj, idx = json.JSONDecoder().raw_decode(buf)
+ self._recv_buf = buf[idx:]
+ return obj
+ except ValueError:
+ self._logger.debug("Partial response")
+ return None
+
+ def recv(self):
+ start_time = time.process_time()
+ response = self.decode_one_response()
+ while not response:
+ try:
+ timeout = self.timeout - (time.process_time() - start_time)
+ self.sock.settimeout(timeout)
+ newdata = self.sock.recv(4096)
+ if not newdata:
+ self.sock.close()
+ self.sock = None
+ raise JSONRPCException("Connection closed with partial response:\n%s\n" % self._recv_buf)
+ self._recv_buf += newdata.decode("utf-8")
+ response = self.decode_one_response()
+ except socket.timeout:
+ break # throw exception after loop to avoid Python freaking out about nested exceptions
+ except ValueError:
+ continue # incomplete response; keep buffering
+
+ if not response:
+ raise JSONRPCException("Timeout while waiting for response:\n%s\n" % self._recv_buf)
+
+ self._logger.info("response:\n%s\n", json.dumps(response, indent=2))
+ return response
+
+ def call(self, method, params={}):
+ self._logger.debug("call('%s')" % method)
+ req_id = self.send(method, params)
+ try:
+ response = self.recv()
+ except JSONRPCException as e:
+ """ Don't expect response to kill """
+ if not self.sock and method == "spdk_kill_instance":
+ self._logger.info("Connection terminated but ignoring since method is '%s'" % method)
+ return {}
+ else:
+ raise e
+
+ if 'error' in response:
+ params["method"] = method
+ params["req_id"] = req_id
+ msg = "\n".join(["request:", "%s" % json.dumps(params, indent=2),
+ "Got JSON-RPC error response",
+ "response:",
+ json.dumps(response['error'], indent=2)])
+ raise JSONRPCException(msg)
+
+ return response['result']
diff --git a/src/spdk/scripts/rpc/env_dpdk.py b/src/spdk/scripts/rpc/env_dpdk.py
new file mode 100644
index 000000000..f2c098e52
--- /dev/null
+++ b/src/spdk/scripts/rpc/env_dpdk.py
@@ -0,0 +1,8 @@
+def env_dpdk_get_mem_stats(client):
+ """Dump the applications memory stats to a file.
+
+ Returns:
+ The path to the file where the stats are written.
+ """
+
+ return client.call('env_dpdk_get_mem_stats')
diff --git a/src/spdk/scripts/rpc/helpers.py b/src/spdk/scripts/rpc/helpers.py
new file mode 100644
index 000000000..d931fcf14
--- /dev/null
+++ b/src/spdk/scripts/rpc/helpers.py
@@ -0,0 +1,16 @@
+import sys
+
+deprecated_aliases = {}
+
+
+def deprecated_alias(old_name):
+ def wrap(f):
+ def old_f(*args, **kwargs):
+ ret = f(*args, **kwargs)
+ print("{} is deprecated, use {} instead.".format(old_name, f.__name__), file=sys.stderr)
+ return ret
+ old_f.__name__ = old_name
+ deprecated_aliases[old_name] = f.__name__
+ setattr(sys.modules[f.__module__], old_name, old_f)
+ return f
+ return wrap
diff --git a/src/spdk/scripts/rpc/idxd.py b/src/spdk/scripts/rpc/idxd.py
new file mode 100644
index 000000000..3e076c68e
--- /dev/null
+++ b/src/spdk/scripts/rpc/idxd.py
@@ -0,0 +1,8 @@
+def idxd_scan_accel_engine(client, config_number):
+ """Scan and enable IDXD accel engine.
+
+ Args:
+ config_number: Pre-defined configuration number, see docs.
+ """
+ params = {'config_number': config_number}
+ return client.call('idxd_scan_accel_engine', params)
diff --git a/src/spdk/scripts/rpc/ioat.py b/src/spdk/scripts/rpc/ioat.py
new file mode 100644
index 000000000..ae43a3c3f
--- /dev/null
+++ b/src/spdk/scripts/rpc/ioat.py
@@ -0,0 +1,17 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('ioat_scan_copy_engine')
+@deprecated_alias('scan_ioat_copy_engine')
+def ioat_scan_accel_engine(client, pci_whitelist):
+ """Scan and enable IOAT accel engine.
+
+ Args:
+ pci_whitelist: Python list of PCI addresses in
+ domain:bus:device.function format or
+ domain.bus.device.function format
+ """
+ params = {}
+ if pci_whitelist:
+ params['pci_whitelist'] = pci_whitelist
+ return client.call('ioat_scan_accel_engine', params)
diff --git a/src/spdk/scripts/rpc/iscsi.py b/src/spdk/scripts/rpc/iscsi.py
new file mode 100644
index 000000000..6d64b6185
--- /dev/null
+++ b/src/spdk/scripts/rpc/iscsi.py
@@ -0,0 +1,558 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('set_iscsi_options')
+def iscsi_set_options(
+ client,
+ auth_file=None,
+ node_base=None,
+ nop_timeout=None,
+ nop_in_interval=None,
+ disable_chap=None,
+ require_chap=None,
+ mutual_chap=None,
+ chap_group=None,
+ max_sessions=None,
+ max_queue_depth=None,
+ max_connections_per_session=None,
+ default_time2wait=None,
+ default_time2retain=None,
+ first_burst_length=None,
+ immediate_data=None,
+ error_recovery_level=None,
+ allow_duplicated_isid=None):
+ """Set iSCSI target options.
+
+ Args:
+ auth_file: Path to CHAP shared secret file (optional)
+ node_base: Prefix of the name of iSCSI target node (optional)
+ nop_timeout: Timeout in seconds to nop-in request to the initiator (optional)
+ nop_in_interval: Time interval in secs between nop-in requests by the target (optional)
+ disable_chap: CHAP for discovery session should be disabled (optional)
+ require_chap: CHAP for discovery session should be required
+ mutual_chap: CHAP for discovery session should be mutual
+ chap_group: Authentication group ID for discovery session
+ max_sessions: Maximum number of sessions in the host
+ max_queue_depth: Maximum number of outstanding I/Os per queue
+ max_connections_per_session: Negotiated parameter, MaxConnections
+ default_time2wait: Negotiated parameter, DefaultTime2Wait
+ default_time2retain: Negotiated parameter, DefaultTime2Retain
+ first_burst_length: Negotiated parameter, FirstBurstLength
+ immediate_data: Negotiated parameter, ImmediateData
+ error_recovery_level: Negotiated parameter, ErrorRecoveryLevel
+ allow_duplicated_isid: Allow duplicated initiator session ID
+
+ Returns:
+ True or False
+ """
+ params = {}
+
+ if auth_file:
+ params['auth_file'] = auth_file
+ if node_base:
+ params['node_base'] = node_base
+ if nop_timeout:
+ params['nop_timeout'] = nop_timeout
+ if nop_in_interval:
+ params['nop_in_interval'] = nop_in_interval
+ if disable_chap:
+ params['disable_chap'] = disable_chap
+ if require_chap:
+ params['require_chap'] = require_chap
+ if mutual_chap:
+ params['mutual_chap'] = mutual_chap
+ if chap_group:
+ params['chap_group'] = chap_group
+ if max_sessions:
+ params['max_sessions'] = max_sessions
+ if max_queue_depth:
+ params['max_queue_depth'] = max_queue_depth
+ if max_connections_per_session:
+ params['max_connections_per_session'] = max_connections_per_session
+ if default_time2wait:
+ params['default_time2wait'] = default_time2wait
+ if default_time2retain:
+ params['default_time2retain'] = default_time2retain
+ if first_burst_length:
+ params['first_burst_length'] = first_burst_length
+ if immediate_data:
+ params['immediate_data'] = immediate_data
+ if error_recovery_level:
+ params['error_recovery_level'] = error_recovery_level
+ if allow_duplicated_isid:
+ params['allow_duplicated_isid'] = allow_duplicated_isid
+
+ return client.call('iscsi_set_options', params)
+
+
+@deprecated_alias('set_iscsi_discovery_auth')
+def iscsi_set_discovery_auth(
+ client,
+ disable_chap=None,
+ require_chap=None,
+ mutual_chap=None,
+ chap_group=None):
+ """Set CHAP authentication for discovery service.
+
+ Args:
+ disable_chap: CHAP for discovery session should be disabled (optional)
+ require_chap: CHAP for discovery session should be required (optional)
+ mutual_chap: CHAP for discovery session should be mutual (optional)
+ chap_group: Authentication group ID for discovery session (optional)
+
+ Returns:
+ True or False
+ """
+ params = {}
+
+ if disable_chap:
+ params['disable_chap'] = disable_chap
+ if require_chap:
+ params['require_chap'] = require_chap
+ if mutual_chap:
+ params['mutual_chap'] = mutual_chap
+ if chap_group:
+ params['chap_group'] = chap_group
+
+ return client.call('iscsi_set_discovery_auth', params)
+
+
+@deprecated_alias('get_iscsi_auth_groups')
+def iscsi_get_auth_groups(client):
+ """Display current authentication group configuration.
+
+ Returns:
+ List of current authentication group configuration.
+ """
+ return client.call('iscsi_get_auth_groups')
+
+
+@deprecated_alias('get_portal_groups')
+def iscsi_get_portal_groups(client):
+ """Display current portal group configuration.
+
+ Returns:
+ List of current portal group configuration.
+ """
+ return client.call('iscsi_get_portal_groups')
+
+
+@deprecated_alias('get_initiator_groups')
+def iscsi_get_initiator_groups(client):
+ """Display current initiator group configuration.
+
+ Returns:
+ List of current initiator group configuration.
+ """
+ return client.call('iscsi_get_initiator_groups')
+
+
+@deprecated_alias('get_target_nodes')
+def iscsi_get_target_nodes(client):
+ """Display target nodes.
+
+ Returns:
+ List of ISCSI target node objects.
+ """
+ return client.call('iscsi_get_target_nodes')
+
+
+@deprecated_alias('construct_target_node')
+def iscsi_create_target_node(
+ client,
+ luns,
+ pg_ig_maps,
+ name,
+ alias_name,
+ queue_depth,
+ chap_group=None,
+ disable_chap=None,
+ require_chap=None,
+ mutual_chap=None,
+ header_digest=None,
+ data_digest=None):
+ """Add a target node.
+
+ Args:
+ luns: List of bdev_name_id_pairs, e.g. [{"bdev_name": "Malloc1", "lun_id": 1}]
+ pg_ig_maps: List of pg_ig_mappings, e.g. [{"pg_tag": pg, "ig_tag": ig}]
+ name: Target node name (ASCII)
+ alias_name: Target node alias name (ASCII)
+ queue_depth: Desired target queue depth
+ chap_group: Authentication group ID for this target node
+ disable_chap: CHAP authentication should be disabled for this target node
+ require_chap: CHAP authentication should be required for this target node
+ mutual_chap: CHAP authentication should be mutual/bidirectional
+ header_digest: Header Digest should be required for this target node
+ data_digest: Data Digest should be required for this target node
+
+ Returns:
+ True or False
+ """
+ params = {
+ 'name': name,
+ 'alias_name': alias_name,
+ 'pg_ig_maps': pg_ig_maps,
+ 'luns': luns,
+ 'queue_depth': queue_depth,
+ }
+
+ if chap_group:
+ params['chap_group'] = chap_group
+ if disable_chap:
+ params['disable_chap'] = disable_chap
+ if require_chap:
+ params['require_chap'] = require_chap
+ if mutual_chap:
+ params['mutual_chap'] = mutual_chap
+ if header_digest:
+ params['header_digest'] = header_digest
+ if data_digest:
+ params['data_digest'] = data_digest
+ return client.call('iscsi_create_target_node', params)
+
+
+@deprecated_alias('target_node_add_lun')
+def iscsi_target_node_add_lun(client, name, bdev_name, lun_id=None):
+ """Add LUN to the target node.
+
+ Args:
+ name: Target node name (ASCII)
+ bdev_name: bdev name
+ lun_id: LUN ID (integer >= 0)
+
+ Returns:
+ True or False
+ """
+ params = {
+ 'name': name,
+ 'bdev_name': bdev_name,
+ }
+ if lun_id:
+ params['lun_id'] = lun_id
+ return client.call('iscsi_target_node_add_lun', params)
+
+
+@deprecated_alias('set_iscsi_target_node_auth')
+def iscsi_target_node_set_auth(
+ client,
+ name,
+ chap_group=None,
+ disable_chap=None,
+ require_chap=None,
+ mutual_chap=None):
+ """Set CHAP authentication for the target node.
+
+ Args:
+ name: Target node name (ASCII)
+ chap_group: Authentication group ID for this target node
+ disable_chap: CHAP authentication should be disabled for this target node
+ require_chap: CHAP authentication should be required for this target node
+ mutual_chap: CHAP authentication should be mutual/bidirectional
+
+ Returns:
+ True or False
+ """
+ params = {
+ 'name': name,
+ }
+
+ if chap_group:
+ params['chap_group'] = chap_group
+ if disable_chap:
+ params['disable_chap'] = disable_chap
+ if require_chap:
+ params['require_chap'] = require_chap
+ if mutual_chap:
+ params['mutual_chap'] = mutual_chap
+ return client.call('iscsi_target_node_set_auth', params)
+
+
+@deprecated_alias('add_iscsi_auth_group')
+def iscsi_create_auth_group(client, tag, secrets=None):
+ """Create authentication group for CHAP authentication.
+
+ Args:
+ tag: Authentication group tag (unique, integer > 0).
+ secrets: Array of secrets objects (optional).
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag}
+
+ if secrets:
+ params['secrets'] = secrets
+ return client.call('iscsi_create_auth_group', params)
+
+
+@deprecated_alias('delete_iscsi_auth_group')
+def iscsi_delete_auth_group(client, tag):
+ """Delete an authentication group.
+
+ Args:
+ tag: Authentication group tag (unique, integer > 0)
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag}
+ return client.call('iscsi_delete_auth_group', params)
+
+
+@deprecated_alias('add_secret_to_iscsi_auth_group')
+def iscsi_auth_group_add_secret(client, tag, user, secret, muser=None, msecret=None):
+ """Add a secret to an authentication group.
+
+ Args:
+ tag: Authentication group tag (unique, integer > 0)
+ user: User name for one-way CHAP authentication
+ secret: Secret for one-way CHAP authentication
+ muser: User name for mutual CHAP authentication (optional)
+ msecret: Secret for mutual CHAP authentication (optional)
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag, 'user': user, 'secret': secret}
+
+ if muser:
+ params['muser'] = muser
+ if msecret:
+ params['msecret'] = msecret
+ return client.call('iscsi_auth_group_add_secret', params)
+
+
+@deprecated_alias('delete_secret_from_iscsi_auth_group')
+def iscsi_auth_group_remove_secret(client, tag, user):
+ """Remove a secret from an authentication group.
+
+ Args:
+ tag: Authentication group tag (unique, integer > 0)
+ user: User name for one-way CHAP authentication
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag, 'user': user}
+ return client.call('iscsi_auth_group_remove_secret', params)
+
+
+@deprecated_alias('delete_pg_ig_maps')
+def iscsi_target_node_remove_pg_ig_maps(client, pg_ig_maps, name):
+ """Delete PG-IG maps from the target node.
+
+ Args:
+ pg_ig_maps: List of pg_ig_mappings, e.g. [{"pg_tag": pg, "ig_tag": ig}]
+ name: Target node alias name (ASCII)
+
+ Returns:
+ True or False
+ """
+ params = {
+ 'name': name,
+ 'pg_ig_maps': pg_ig_maps,
+ }
+ return client.call('iscsi_target_node_remove_pg_ig_maps', params)
+
+
+@deprecated_alias('add_pg_ig_maps')
+def iscsi_target_node_add_pg_ig_maps(client, pg_ig_maps, name):
+ """Add PG-IG maps to the target node.
+
+ Args:
+ pg_ig_maps: List of pg_ig_mappings, e.g. [{"pg_tag": pg, "ig_tag": ig}]
+ name: Target node alias name (ASCII)
+
+ Returns:
+ True or False
+ """
+ params = {
+ 'name': name,
+ 'pg_ig_maps': pg_ig_maps,
+ }
+ return client.call('iscsi_target_node_add_pg_ig_maps', params)
+
+
+@deprecated_alias('add_portal_group')
+def iscsi_create_portal_group(client, portals, tag):
+ """Add a portal group.
+
+ Args:
+ portals: List of portals, e.g. [{'host': ip, 'port': port}]
+ tag: Initiator group tag (unique, integer > 0)
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag, 'portals': portals}
+ return client.call('iscsi_create_portal_group', params)
+
+
+@deprecated_alias('add_initiator_group')
+def iscsi_create_initiator_group(client, tag, initiators, netmasks):
+ """Add an initiator group.
+
+ Args:
+ tag: Initiator group tag (unique, integer > 0)
+ initiators: List of initiator hostnames or IP addresses, e.g. ["127.0.0.1","192.168.200.100"]
+ netmasks: List of initiator netmasks, e.g. ["255.255.0.0","255.248.0.0"]
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag, 'initiators': initiators, 'netmasks': netmasks}
+ return client.call('iscsi_create_initiator_group', params)
+
+
+@deprecated_alias('add_initiators_to_initiator_group')
+def iscsi_initiator_group_add_initiators(
+ client,
+ tag,
+ initiators=None,
+ netmasks=None):
+ """Add initiators to an existing initiator group.
+
+ Args:
+ tag: Initiator group tag (unique, integer > 0)
+ initiators: List of initiator hostnames or IP addresses, e.g. ["127.0.0.1","192.168.200.100"]
+ netmasks: List of initiator netmasks, e.g. ["255.255.0.0","255.248.0.0"]
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag}
+
+ if initiators:
+ params['initiators'] = initiators
+ if netmasks:
+ params['netmasks'] = netmasks
+ return client.call('iscsi_initiator_group_add_initiators', params)
+
+
+@deprecated_alias('delete_initiators_from_initiator_group')
+def iscsi_initiator_group_remove_initiators(
+ client, tag, initiators=None, netmasks=None):
+ """Delete initiators from an existing initiator group.
+
+ Args:
+ tag: Initiator group tag (unique, integer > 0)
+ initiators: List of initiator hostnames or IP addresses, e.g. ["127.0.0.1","192.168.200.100"]
+ netmasks: List of initiator netmasks, e.g. ["255.255.0.0","255.248.0.0"]
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag}
+
+ if initiators:
+ params['initiators'] = initiators
+ if netmasks:
+ params['netmasks'] = netmasks
+ return client.call('iscsi_initiator_group_remove_initiators', params)
+
+
+@deprecated_alias('delete_target_node')
+def iscsi_delete_target_node(client, target_node_name):
+ """Delete a target node.
+
+ Args:
+ target_node_name: Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.
+
+ Returns:
+ True or False
+ """
+ params = {'name': target_node_name}
+ return client.call('iscsi_delete_target_node', params)
+
+
+@deprecated_alias('delete_portal_group')
+def iscsi_delete_portal_group(client, tag):
+ """Delete a portal group.
+
+ Args:
+ tag: Portal group tag (unique, integer > 0)
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag}
+ return client.call('iscsi_delete_portal_group', params)
+
+
+@deprecated_alias('delete_initiator_group')
+def iscsi_delete_initiator_group(client, tag):
+ """Delete an initiator group.
+
+ Args:
+ tag: Initiator group tag (unique, integer > 0)
+
+ Returns:
+ True or False
+ """
+ params = {'tag': tag}
+ return client.call('iscsi_delete_initiator_group', params)
+
+
+def iscsi_portal_group_set_auth(
+ client,
+ tag,
+ chap_group=None,
+ disable_chap=None,
+ require_chap=None,
+ mutual_chap=None):
+ """Set CHAP authentication for discovery sessions specific for the portal group.
+
+ Args:
+ tag: Portal group tag (unique, integer > 0)
+ chap_group: Authentication group ID for this portal group
+ disable_chap: CHAP authentication should be disabled for this portal group
+ require_chap: CHAP authentication should be required for this portal group
+ mutual_chap: CHAP authentication should be mutual/bidirectional
+
+ Returns:
+ True or False
+ """
+ params = {
+ 'tag': tag,
+ }
+
+ if chap_group:
+ params['chap_group'] = chap_group
+ if disable_chap:
+ params['disable_chap'] = disable_chap
+ if require_chap:
+ params['require_chap'] = require_chap
+ if mutual_chap:
+ params['mutual_chap'] = mutual_chap
+ return client.call('iscsi_portal_group_set_auth', params)
+
+
+@deprecated_alias('get_iscsi_connections')
+def iscsi_get_connections(client):
+ """Display iSCSI connections.
+
+ Returns:
+ List of iSCSI connection.
+ """
+ return client.call('iscsi_get_connections')
+
+
+@deprecated_alias('get_iscsi_global_params')
+def iscsi_get_options(client):
+ """Display iSCSI global parameters.
+
+ Returns:
+ List of iSCSI global parameter.
+ """
+ return client.call('iscsi_get_options')
+
+
+@deprecated_alias('get_iscsi_devices')
+def scsi_get_devices(client):
+ """Display SCSI devices.
+
+ Returns:
+ List of SCSI device.
+ """
+ return client.call('scsi_get_devices')
diff --git a/src/spdk/scripts/rpc/log.py b/src/spdk/scripts/rpc/log.py
new file mode 100644
index 000000000..ee40bf833
--- /dev/null
+++ b/src/spdk/scripts/rpc/log.py
@@ -0,0 +1,75 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('set_log_flag')
+def log_set_flag(client, flag):
+ """Set log flag.
+
+ Args:
+ flag: log flag we want to set. (for example "nvme")
+ """
+ params = {'flag': flag}
+ return client.call('log_set_flag', params)
+
+
+@deprecated_alias('clear_log_flag')
+def log_clear_flag(client, flag):
+ """Clear log flag.
+
+ Args:
+ flag: log flag we want to clear. (for example "nvme")
+ """
+ params = {'flag': flag}
+ return client.call('log_clear_flag', params)
+
+
+@deprecated_alias('get_log_flags')
+def log_get_flags(client):
+ """Get log flags
+
+ Returns:
+ List of log flags
+ """
+ return client.call('log_get_flags')
+
+
+@deprecated_alias('set_log_level')
+def log_set_level(client, level):
+ """Set log level.
+
+ Args:
+ level: log level we want to set. (for example "DEBUG")
+ """
+ params = {'level': level}
+ return client.call('log_set_level', params)
+
+
+@deprecated_alias('get_log_level')
+def log_get_level(client):
+ """Get log level
+
+ Returns:
+ Current log level
+ """
+ return client.call('log_get_level')
+
+
+@deprecated_alias('set_log_print_level')
+def log_set_print_level(client, level):
+ """Set log print level.
+
+ Args:
+ level: log print level we want to set. (for example "DEBUG")
+ """
+ params = {'level': level}
+ return client.call('log_set_print_level', params)
+
+
+@deprecated_alias('get_log_print_level')
+def log_get_print_level(client):
+ """Get log print level
+
+ Returns:
+ Current log print level
+ """
+ return client.call('log_get_print_level')
diff --git a/src/spdk/scripts/rpc/lvol.py b/src/spdk/scripts/rpc/lvol.py
new file mode 100644
index 000000000..1c31f5eda
--- /dev/null
+++ b/src/spdk/scripts/rpc/lvol.py
@@ -0,0 +1,228 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('construct_lvol_store')
+def bdev_lvol_create_lvstore(client, bdev_name, lvs_name, cluster_sz=None, clear_method=None):
+ """Construct a logical volume store.
+
+ Args:
+ bdev_name: bdev on which to construct logical volume store
+ lvs_name: name of the logical volume store to create
+ cluster_sz: cluster size of the logical volume store in bytes (optional)
+ clear_method: Change clear method for data region. Available: none, unmap, write_zeroes (optional)
+
+ Returns:
+ UUID of created logical volume store.
+ """
+ params = {'bdev_name': bdev_name, 'lvs_name': lvs_name}
+ if cluster_sz:
+ params['cluster_sz'] = cluster_sz
+ if clear_method:
+ params['clear_method'] = clear_method
+ return client.call('bdev_lvol_create_lvstore', params)
+
+
+@deprecated_alias('rename_lvol_store')
+def bdev_lvol_rename_lvstore(client, old_name, new_name):
+ """Rename a logical volume store.
+
+ Args:
+ old_name: existing logical volume store name
+ new_name: new logical volume store name
+ """
+ params = {
+ 'old_name': old_name,
+ 'new_name': new_name
+ }
+ return client.call('bdev_lvol_rename_lvstore', params)
+
+
+@deprecated_alias('construct_lvol_bdev')
+def bdev_lvol_create(client, lvol_name, size, thin_provision=False, uuid=None, lvs_name=None, clear_method=None):
+ """Create a logical volume on a logical volume store.
+
+ Args:
+ lvol_name: name of logical volume to create
+ size: desired size of logical volume in bytes (will be rounded up to a multiple of cluster size)
+ thin_provision: True to enable thin provisioning
+ uuid: UUID of logical volume store to create logical volume on (optional)
+ lvs_name: name of logical volume store to create logical volume on (optional)
+
+ Either uuid or lvs_name must be specified, but not both.
+
+ Returns:
+ Name of created logical volume block device.
+ """
+ if (uuid and lvs_name) or (not uuid and not lvs_name):
+ raise ValueError("Either uuid or lvs_name must be specified, but not both")
+
+ params = {'lvol_name': lvol_name, 'size': size}
+ if thin_provision:
+ params['thin_provision'] = thin_provision
+ if uuid:
+ params['uuid'] = uuid
+ if lvs_name:
+ params['lvs_name'] = lvs_name
+ if clear_method:
+ params['clear_method'] = clear_method
+ return client.call('bdev_lvol_create', params)
+
+
+@deprecated_alias('snapshot_lvol_bdev')
+def bdev_lvol_snapshot(client, lvol_name, snapshot_name):
+ """Capture a snapshot of the current state of a logical volume.
+
+ Args:
+ lvol_name: logical volume to create a snapshot from
+ snapshot_name: name for the newly created snapshot
+
+ Returns:
+ Name of created logical volume snapshot.
+ """
+ params = {
+ 'lvol_name': lvol_name,
+ 'snapshot_name': snapshot_name
+ }
+ return client.call('bdev_lvol_snapshot', params)
+
+
+@deprecated_alias('clone_lvol_bdev')
+def bdev_lvol_clone(client, snapshot_name, clone_name):
+ """Create a logical volume based on a snapshot.
+
+ Args:
+ snapshot_name: snapshot to clone
+ clone_name: name of logical volume to create
+
+ Returns:
+ Name of created logical volume clone.
+ """
+ params = {
+ 'snapshot_name': snapshot_name,
+ 'clone_name': clone_name
+ }
+ return client.call('bdev_lvol_clone', params)
+
+
+@deprecated_alias('rename_lvol_bdev')
+def bdev_lvol_rename(client, old_name, new_name):
+ """Rename a logical volume.
+
+ Args:
+ old_name: existing logical volume name
+ new_name: new logical volume name
+ """
+ params = {
+ 'old_name': old_name,
+ 'new_name': new_name
+ }
+ return client.call('bdev_lvol_rename', params)
+
+
+@deprecated_alias('resize_lvol_bdev')
+def bdev_lvol_resize(client, name, size):
+ """Resize a logical volume.
+
+ Args:
+ name: name of logical volume to resize
+ size: desired size of logical volume in bytes (will be rounded up to a multiple of cluster size)
+ """
+ params = {
+ 'name': name,
+ 'size': size,
+ }
+ return client.call('bdev_lvol_resize', params)
+
+
+@deprecated_alias('set_read_only_lvol_bdev')
+def bdev_lvol_set_read_only(client, name):
+ """Mark logical volume as read only.
+
+ Args:
+ name: name of logical volume to set as read only
+ """
+ params = {
+ 'name': name,
+ }
+ return client.call('bdev_lvol_set_read_only', params)
+
+
+@deprecated_alias('destroy_lvol_bdev')
+def bdev_lvol_delete(client, name):
+ """Destroy a logical volume.
+
+ Args:
+ name: name of logical volume to destroy
+ """
+ params = {
+ 'name': name,
+ }
+ return client.call('bdev_lvol_delete', params)
+
+
+@deprecated_alias('inflate_lvol_bdev')
+def bdev_lvol_inflate(client, name):
+ """Inflate a logical volume.
+
+ Args:
+ name: name of logical volume to inflate
+ """
+ params = {
+ 'name': name,
+ }
+ return client.call('bdev_lvol_inflate', params)
+
+
+@deprecated_alias('decouple_parent_lvol_bdev')
+def bdev_lvol_decouple_parent(client, name):
+ """Decouple parent of a logical volume.
+
+ Args:
+ name: name of logical volume to decouple parent
+ """
+ params = {
+ 'name': name,
+ }
+ return client.call('bdev_lvol_decouple_parent', params)
+
+
+@deprecated_alias('destroy_lvol_store')
+def bdev_lvol_delete_lvstore(client, uuid=None, lvs_name=None):
+ """Destroy a logical volume store.
+
+ Args:
+ uuid: UUID of logical volume store to destroy (optional)
+ lvs_name: name of logical volume store to destroy (optional)
+
+ Either uuid or lvs_name must be specified, but not both.
+ """
+ if (uuid and lvs_name) or (not uuid and not lvs_name):
+ raise ValueError("Exactly one of uuid or lvs_name must be specified")
+
+ params = {}
+ if uuid:
+ params['uuid'] = uuid
+ if lvs_name:
+ params['lvs_name'] = lvs_name
+ return client.call('bdev_lvol_delete_lvstore', params)
+
+
+@deprecated_alias('get_lvol_stores')
+def bdev_lvol_get_lvstores(client, uuid=None, lvs_name=None):
+ """List logical volume stores.
+
+ Args:
+ uuid: UUID of logical volume store to retrieve information about (optional)
+ lvs_name: name of logical volume store to retrieve information about (optional)
+
+ Either uuid or lvs_name may be specified, but not both.
+ If both uuid and lvs_name are omitted, information about all logical volume stores is returned.
+ """
+ if (uuid and lvs_name):
+ raise ValueError("Exactly one of uuid or lvs_name may be specified")
+ params = {}
+ if uuid:
+ params['uuid'] = uuid
+ if lvs_name:
+ params['lvs_name'] = lvs_name
+ return client.call('bdev_lvol_get_lvstores', params)
diff --git a/src/spdk/scripts/rpc/nbd.py b/src/spdk/scripts/rpc/nbd.py
new file mode 100644
index 000000000..55e57d11e
--- /dev/null
+++ b/src/spdk/scripts/rpc/nbd.py
@@ -0,0 +1,25 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('start_nbd_disk')
+def nbd_start_disk(client, bdev_name, nbd_device):
+ params = {
+ 'bdev_name': bdev_name
+ }
+ if nbd_device:
+ params['nbd_device'] = nbd_device
+ return client.call('nbd_start_disk', params)
+
+
+@deprecated_alias('stop_nbd_disk')
+def nbd_stop_disk(client, nbd_device):
+ params = {'nbd_device': nbd_device}
+ return client.call('nbd_stop_disk', params)
+
+
+@deprecated_alias('get_nbd_disks')
+def nbd_get_disks(client, nbd_device=None):
+ params = {}
+ if nbd_device:
+ params['nbd_device'] = nbd_device
+ return client.call('nbd_get_disks', params)
diff --git a/src/spdk/scripts/rpc/net.py b/src/spdk/scripts/rpc/net.py
new file mode 100644
index 000000000..7c479bba8
--- /dev/null
+++ b/src/spdk/scripts/rpc/net.py
@@ -0,0 +1,35 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('add_ip_address')
+def net_interface_add_ip_address(client, ifc_index, ip_addr):
+ """Add IP address.
+
+ Args:
+ ifc_index: ifc index of the nic device (int)
+ ip_addr: ip address will be added
+ """
+ params = {'ifc_index': ifc_index, 'ip_address': ip_addr}
+ return client.call('net_interface_add_ip_address', params)
+
+
+@deprecated_alias('delete_ip_address')
+def net_interface_delete_ip_address(client, ifc_index, ip_addr):
+ """Delete IP address.
+
+ Args:
+ ifc_index: ifc index of the nic device (int)
+ ip_addr: ip address will be deleted
+ """
+ params = {'ifc_index': ifc_index, 'ip_address': ip_addr}
+ return client.call('net_interface_delete_ip_address', params)
+
+
+@deprecated_alias('get_interfaces')
+def net_get_interfaces(client):
+ """Display current interface list
+
+ Returns:
+ List of current interface
+ """
+ return client.call('net_get_interfaces')
diff --git a/src/spdk/scripts/rpc/notify.py b/src/spdk/scripts/rpc/notify.py
new file mode 100644
index 000000000..4907447c0
--- /dev/null
+++ b/src/spdk/scripts/rpc/notify.py
@@ -0,0 +1,30 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('get_notification_types')
+def notify_get_types(client):
+ return client.call("notify_get_types")
+
+
+@deprecated_alias('get_notifications')
+def notify_get_notifications(client,
+ id=None,
+ max=None):
+ """
+
+ Args:
+ id First ID to start fetching from
+ max Maximum number of notifications to return in response
+
+ Return:
+ Notifications array
+ """
+
+ params = {}
+ if id:
+ params['id'] = id
+
+ if max:
+ params['max'] = max
+
+ return client.call("notify_get_notifications", params)
diff --git a/src/spdk/scripts/rpc/nvme.py b/src/spdk/scripts/rpc/nvme.py
new file mode 100644
index 000000000..e9a0ba6bb
--- /dev/null
+++ b/src/spdk/scripts/rpc/nvme.py
@@ -0,0 +1,87 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('send_nvme_cmd')
+def bdev_nvme_send_cmd(client, name, cmd_type, data_direction, cmdbuf,
+ data=None, metadata=None,
+ data_len=None, metadata_len=None,
+ timeout_ms=None):
+ """Send one NVMe command
+
+ Args:
+ name: Name of the operating NVMe controller
+ cmd_type: Type of nvme cmd. Valid values are: admin, io
+ data_direction: Direction of data transfer. Valid values are: c2h, h2c
+ cmdbuf: NVMe command encoded by base64 urlsafe
+ data: Data transferring to controller from host, encoded by base64 urlsafe
+ metadata: metadata transferring to controller from host, encoded by base64 urlsafe
+ data_length: Data length required to transfer from controller to host
+ metadata_length: Metadata length required to transfer from controller to host
+ timeout-ms: Command execution timeout value, in milliseconds, if 0, don't track timeout
+
+ Returns:
+ NVMe completion queue entry, requested data and metadata, all are encoded by base64 urlsafe.
+ """
+ params = {'name': name,
+ 'cmd_type': cmd_type,
+ 'data_direction': data_direction,
+ 'cmdbuf': cmdbuf}
+
+ if data:
+ params['data'] = data
+ if metadata:
+ params['metadata'] = metadata
+ if data_len:
+ params['data_len'] = data_len
+ if metadata_len:
+ params['metadata_len'] = metadata_len
+ if timeout_ms:
+ params['timeout_ms'] = timeout_ms
+
+ return client.call('bdev_nvme_send_cmd', params)
+
+
+@deprecated_alias('get_nvme_controllers')
+def bdev_nvme_get_controllers(client, name=None):
+ """Get information about NVMe controllers.
+
+ Args:
+ name: NVMe controller name to query (optional; if omitted, query all NVMe controllers)
+
+ Returns:
+ List of NVMe controller information objects.
+ """
+ params = {}
+ if name:
+ params['name'] = name
+ return client.call('bdev_nvme_get_controllers', params)
+
+
+def bdev_nvme_opal_init(client, nvme_ctrlr_name, password):
+ """Init nvme opal. Take ownership and activate
+
+ Args:
+ nvme_ctrlr_name: name of nvme ctrlr
+ password: password to init opal
+ """
+ params = {
+ 'nvme_ctrlr_name': nvme_ctrlr_name,
+ 'password': password,
+ }
+
+ return client.call('bdev_nvme_opal_init', params)
+
+
+def bdev_nvme_opal_revert(client, nvme_ctrlr_name, password):
+ """Revert opal to default factory settings. Erase all data.
+
+ Args:
+ nvme_ctrlr_name: name of nvme ctrlr
+ password: password
+ """
+ params = {
+ 'nvme_ctrlr_name': nvme_ctrlr_name,
+ 'password': password,
+ }
+
+ return client.call('bdev_nvme_opal_revert', params)
diff --git a/src/spdk/scripts/rpc/nvmf.py b/src/spdk/scripts/rpc/nvmf.py
new file mode 100644
index 000000000..7b2bc3bb6
--- /dev/null
+++ b/src/spdk/scripts/rpc/nvmf.py
@@ -0,0 +1,483 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('set_nvmf_target_max_subsystems')
+def nvmf_set_max_subsystems(client,
+ max_subsystems=None):
+ """Set NVMe-oF target options.
+
+ Args:
+ max_subsystems: Maximum number of NVMe-oF subsystems (e.g. 1024)
+
+ Returns:
+ True or False
+ """
+ params = {}
+
+ params['max_subsystems'] = max_subsystems
+ return client.call('nvmf_set_max_subsystems', params)
+
+
+@deprecated_alias('set_nvmf_target_config')
+def nvmf_set_config(client,
+ acceptor_poll_rate=None,
+ conn_sched=None,
+ passthru_identify_ctrlr=None):
+ """Set NVMe-oF target subsystem configuration.
+
+ Args:
+ acceptor_poll_rate: Acceptor poll period in microseconds (optional)
+ conn_sched: (Deprecated) Ignored
+
+ Returns:
+ True or False
+ """
+ params = {}
+
+ if acceptor_poll_rate:
+ params['acceptor_poll_rate'] = acceptor_poll_rate
+ if conn_sched:
+ print("WARNING: conn_sched is deprecated and ignored.")
+ if passthru_identify_ctrlr:
+ admin_cmd_passthru = {}
+ admin_cmd_passthru['identify_ctrlr'] = passthru_identify_ctrlr
+ params['admin_cmd_passthru'] = admin_cmd_passthru
+
+ return client.call('nvmf_set_config', params)
+
+
+def nvmf_create_target(client,
+ name,
+ max_subsystems=0):
+ """Create a new NVMe-oF Target.
+
+ Args:
+ name: Must be unique within the application
+ max_subsystems: Maximum number of NVMe-oF subsystems (e.g. 1024). default: 0 (Uses SPDK_NVMF_DEFAULT_MAX_SUBSYSTEMS).
+
+ Returns:
+ The name of the new target.
+ """
+ params = {}
+
+ params['name'] = name
+ params['max_subsystems'] = max_subsystems
+ return client.call("nvmf_create_target", params)
+
+
+def nvmf_delete_target(client,
+ name):
+ """Destroy an NVMe-oF Target.
+
+ Args:
+ name: The name of the target you wish to destroy
+
+ Returns:
+ True on success or False
+ """
+ params = {}
+
+ params['name'] = name
+ return client.call("nvmf_delete_target", params)
+
+
+def nvmf_get_targets(client):
+ """Get a list of all the NVMe-oF targets in this application
+
+ Returns:
+ An array of target names.
+ """
+
+ return client.call("nvmf_get_targets")
+
+
+def nvmf_create_transport(client,
+ trtype,
+ tgt_name=None,
+ max_queue_depth=None,
+ max_qpairs_per_ctrlr=None,
+ max_io_qpairs_per_ctrlr=None,
+ in_capsule_data_size=None,
+ max_io_size=None,
+ io_unit_size=None,
+ max_aq_depth=None,
+ num_shared_buffers=None,
+ buf_cache_size=None,
+ max_srq_depth=None,
+ no_srq=False,
+ c2h_success=True,
+ dif_insert_or_strip=None,
+ sock_priority=None,
+ acceptor_backlog=None,
+ abort_timeout_sec=None):
+ """NVMf Transport Create options.
+
+ Args:
+ trtype: Transport type (ex. RDMA)
+ max_queue_depth: Max number of outstanding I/O per queue (optional)
+ max_qpairs_per_ctrlr: Max number of SQ and CQ per controller (optional, deprecated, use max_io_qpairs_per_ctrlr)
+ max_io_qpairs_per_ctrlr: Max number of IO qpairs per controller (optional)
+ in_capsule_data_size: Maximum in-capsule data size in bytes (optional)
+ max_io_size: Maximum I/O data size in bytes (optional)
+ io_unit_size: I/O unit size in bytes (optional)
+ max_aq_depth: Max size admin quque per controller (optional)
+ num_shared_buffers: The number of pooled data buffers available to the transport (optional)
+ buf_cache_size: The number of shared buffers to reserve for each poll group (optional)
+ max_srq_depth: Max number of outstanding I/O per shared receive queue - RDMA specific (optional)
+ no_srq: Boolean flag to disable SRQ even for devices that support it - RDMA specific (optional)
+ c2h_success: Boolean flag to disable the C2H success optimization - TCP specific (optional)
+ dif_insert_or_strip: Boolean flag to enable DIF insert/strip for I/O - TCP specific (optional)
+ acceptor_backlog: Pending connections allowed at one time - RDMA specific (optional)
+ abort_timeout_sec: Abort execution timeout value, in seconds (optional)
+
+ Returns:
+ True or False
+ """
+ params = {}
+
+ params['trtype'] = trtype
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+ if max_queue_depth:
+ params['max_queue_depth'] = max_queue_depth
+ if max_qpairs_per_ctrlr:
+ print("WARNING: max_qpairs_per_ctrlr is deprecated, please use max_io_qpairs_per_ctrlr.")
+ params['max_qpairs_per_ctrlr'] = max_qpairs_per_ctrlr
+ if max_io_qpairs_per_ctrlr:
+ params['max_io_qpairs_per_ctrlr'] = max_io_qpairs_per_ctrlr
+ if in_capsule_data_size:
+ params['in_capsule_data_size'] = in_capsule_data_size
+ if max_io_size:
+ params['max_io_size'] = max_io_size
+ if io_unit_size:
+ params['io_unit_size'] = io_unit_size
+ if max_aq_depth:
+ params['max_aq_depth'] = max_aq_depth
+ if num_shared_buffers:
+ params['num_shared_buffers'] = num_shared_buffers
+ if buf_cache_size:
+ params['buf_cache_size'] = buf_cache_size
+ if max_srq_depth:
+ params['max_srq_depth'] = max_srq_depth
+ if no_srq:
+ params['no_srq'] = no_srq
+ if c2h_success is not None:
+ params['c2h_success'] = c2h_success
+ if dif_insert_or_strip:
+ params['dif_insert_or_strip'] = dif_insert_or_strip
+ if sock_priority:
+ params['sock_priority'] = sock_priority
+ if acceptor_backlog is not None:
+ params['acceptor_backlog'] = acceptor_backlog
+ if abort_timeout_sec:
+ params['abort_timeout_sec'] = abort_timeout_sec
+ return client.call('nvmf_create_transport', params)
+
+
+@deprecated_alias('get_nvmf_transports')
+def nvmf_get_transports(client, tgt_name=None):
+ """Get list of NVMe-oF transports.
+ Args:
+ tgt_name: name of the parent NVMe-oF target (optional).
+
+ Returns:
+ List of NVMe-oF transport objects.
+ """
+
+ params = {}
+
+ if tgt_name:
+ params = {
+ 'tgt_name': tgt_name,
+ }
+
+ return client.call('nvmf_get_transports', params)
+
+
+@deprecated_alias('get_nvmf_subsystems')
+def nvmf_get_subsystems(client, tgt_name=None):
+ """Get list of NVMe-oF subsystems.
+ Args:
+ tgt_name: name of the parent NVMe-oF target (optional).
+
+ Returns:
+ List of NVMe-oF subsystem objects.
+ """
+
+ params = {}
+
+ if tgt_name:
+ params = {
+ 'tgt_name': tgt_name,
+ }
+
+ return client.call('nvmf_get_subsystems', params)
+
+
+@deprecated_alias('nvmf_subsystem_create')
+def nvmf_create_subsystem(client,
+ nqn,
+ serial_number,
+ tgt_name=None,
+ model_number='SPDK bdev Controller',
+ allow_any_host=False,
+ max_namespaces=0):
+ """Construct an NVMe over Fabrics target subsystem.
+
+ Args:
+ nqn: Subsystem NQN.
+ tgt_name: name of the parent NVMe-oF target (optional).
+ serial_number: Serial number of virtual controller.
+ model_number: Model number of virtual controller.
+ allow_any_host: Allow any host (True) or enforce allowed host whitelist (False). Default: False.
+ max_namespaces: Maximum number of namespaces that can be attached to the subsystem (optional). Default: 0 (Unlimited).
+
+ Returns:
+ True or False
+ """
+ params = {
+ 'nqn': nqn,
+ }
+
+ if serial_number:
+ params['serial_number'] = serial_number
+
+ if model_number:
+ params['model_number'] = model_number
+
+ if allow_any_host:
+ params['allow_any_host'] = True
+
+ if max_namespaces:
+ params['max_namespaces'] = max_namespaces
+
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+
+ return client.call('nvmf_create_subsystem', params)
+
+
+def nvmf_subsystem_add_listener(client, nqn, trtype, traddr, trsvcid, adrfam, tgt_name=None):
+ """Add a new listen address to an NVMe-oF subsystem.
+
+ Args:
+ nqn: Subsystem NQN.
+ trtype: Transport type ("RDMA").
+ traddr: Transport address.
+ trsvcid: Transport service ID.
+ tgt_name: name of the parent NVMe-oF target (optional).
+ adrfam: Address family ("IPv4", "IPv6", "IB", or "FC").
+
+ Returns:
+ True or False
+ """
+ listen_address = {'trtype': trtype,
+ 'traddr': traddr,
+ 'trsvcid': trsvcid}
+
+ if adrfam:
+ listen_address['adrfam'] = adrfam
+
+ params = {'nqn': nqn,
+ 'listen_address': listen_address}
+
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+
+ return client.call('nvmf_subsystem_add_listener', params)
+
+
+def nvmf_subsystem_remove_listener(
+ client,
+ nqn,
+ trtype,
+ traddr,
+ trsvcid,
+ adrfam,
+ tgt_name=None):
+ """Remove existing listen address from an NVMe-oF subsystem.
+
+ Args:
+ nqn: Subsystem NQN.
+ trtype: Transport type ("RDMA").
+ traddr: Transport address.
+ trsvcid: Transport service ID.
+ tgt_name: name of the parent NVMe-oF target (optional).
+ adrfam: Address family ("IPv4", "IPv6", "IB", or "FC").
+
+ Returns:
+ True or False
+ """
+ listen_address = {'trtype': trtype,
+ 'traddr': traddr,
+ 'trsvcid': trsvcid}
+
+ if adrfam:
+ listen_address['adrfam'] = adrfam
+
+ params = {'nqn': nqn,
+ 'listen_address': listen_address}
+
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+
+ return client.call('nvmf_subsystem_remove_listener', params)
+
+
+def nvmf_subsystem_add_ns(client, nqn, bdev_name, tgt_name=None, ptpl_file=None, nsid=None, nguid=None, eui64=None, uuid=None):
+ """Add a namespace to a subsystem.
+
+ Args:
+ nqn: Subsystem NQN.
+ bdev_name: Name of bdev to expose as a namespace.
+ tgt_name: name of the parent NVMe-oF target (optional).
+ nsid: Namespace ID (optional).
+ nguid: 16-byte namespace globally unique identifier in hexadecimal (optional).
+ eui64: 8-byte namespace EUI-64 in hexadecimal (e.g. "ABCDEF0123456789") (optional).
+ uuid: Namespace UUID (optional).
+
+ Returns:
+ The namespace ID
+ """
+ ns = {'bdev_name': bdev_name}
+
+ if ptpl_file:
+ ns['ptpl_file'] = ptpl_file
+
+ if nsid:
+ ns['nsid'] = nsid
+
+ if nguid:
+ ns['nguid'] = nguid
+
+ if eui64:
+ ns['eui64'] = eui64
+
+ if uuid:
+ ns['uuid'] = uuid
+
+ params = {'nqn': nqn,
+ 'namespace': ns}
+
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+
+ return client.call('nvmf_subsystem_add_ns', params)
+
+
+def nvmf_subsystem_remove_ns(client, nqn, nsid, tgt_name=None):
+ """Remove a existing namespace from a subsystem.
+
+ Args:
+ nqn: Subsystem NQN.
+ nsid: Namespace ID.
+ tgt_name: name of the parent NVMe-oF target (optional).
+
+ Returns:
+ True or False
+ """
+ params = {'nqn': nqn,
+ 'nsid': nsid}
+
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+
+ return client.call('nvmf_subsystem_remove_ns', params)
+
+
+def nvmf_subsystem_add_host(client, nqn, host, tgt_name=None):
+ """Add a host NQN to the whitelist of allowed hosts.
+
+ Args:
+ nqn: Subsystem NQN.
+ host: Host NQN to add to the list of allowed host NQNs
+ tgt_name: name of the parent NVMe-oF target (optional).
+
+ Returns:
+ True or False
+ """
+ params = {'nqn': nqn,
+ 'host': host}
+
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+
+ return client.call('nvmf_subsystem_add_host', params)
+
+
+def nvmf_subsystem_remove_host(client, nqn, host, tgt_name=None):
+ """Remove a host NQN from the whitelist of allowed hosts.
+
+ Args:
+ nqn: Subsystem NQN.
+ host: Host NQN to remove to the list of allowed host NQNs
+ tgt_name: name of the parent NVMe-oF target (optional).
+
+ Returns:
+ True or False
+ """
+ params = {'nqn': nqn,
+ 'host': host}
+
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+
+ return client.call('nvmf_subsystem_remove_host', params)
+
+
+def nvmf_subsystem_allow_any_host(client, nqn, disable, tgt_name=None):
+ """Configure a subsystem to allow any host to connect or to enforce the host NQN whitelist.
+
+ Args:
+ nqn: Subsystem NQN.
+ disable: Allow any host (true) or enforce allowed host whitelist (false).
+ tgt_name: name of the parent NVMe-oF target (optional).
+
+ Returns:
+ True or False
+ """
+ params = {'nqn': nqn, 'allow_any_host': False if disable else True}
+
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+
+ return client.call('nvmf_subsystem_allow_any_host', params)
+
+
+@deprecated_alias('delete_nvmf_subsystem')
+def nvmf_delete_subsystem(client, nqn, tgt_name=None):
+ """Delete an existing NVMe-oF subsystem.
+
+ Args:
+ nqn: Subsystem NQN.
+ tgt_name: name of the parent NVMe-oF target (optional).
+
+ Returns:
+ True or False
+ """
+ params = {'nqn': nqn}
+
+ if tgt_name:
+ params['tgt_name'] = tgt_name
+
+ return client.call('nvmf_delete_subsystem', params)
+
+
+def nvmf_get_stats(client, tgt_name=None):
+ """Query NVMf statistics.
+
+ Args:
+ tgt_name: name of the parent NVMe-oF target (optional).
+
+ Returns:
+ Current NVMf statistics.
+ """
+
+ params = {}
+
+ if tgt_name:
+ params = {
+ 'tgt_name': tgt_name,
+ }
+
+ return client.call('nvmf_get_stats', params)
diff --git a/src/spdk/scripts/rpc/pmem.py b/src/spdk/scripts/rpc/pmem.py
new file mode 100644
index 000000000..403674cf1
--- /dev/null
+++ b/src/spdk/scripts/rpc/pmem.py
@@ -0,0 +1,35 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('create_pmem_pool')
+def bdev_pmem_create_pool(client, pmem_file, num_blocks, block_size):
+ """Create pmem pool at specified path.
+ Args:
+ pmem_file: path at which to create pmem pool
+ num_blocks: number of blocks for created pmem pool file
+ block_size: block size for pmem pool file
+ """
+ params = {'pmem_file': pmem_file,
+ 'num_blocks': num_blocks,
+ 'block_size': block_size}
+ return client.call('bdev_pmem_create_pool', params)
+
+
+@deprecated_alias('pmem_pool_info')
+def bdev_pmem_get_pool_info(client, pmem_file):
+ """Get details about pmem pool.
+ Args:
+ pmem_file: path to pmem pool
+ """
+ params = {'pmem_file': pmem_file}
+ return client.call('bdev_pmem_get_pool_info', params)
+
+
+@deprecated_alias('delete_pmem_pool')
+def bdev_pmem_delete_pool(client, pmem_file):
+ """Delete pmem pool.
+ Args:
+ pmem_file: path to pmem pool
+ """
+ params = {'pmem_file': pmem_file}
+ return client.call('bdev_pmem_delete_pool', params)
diff --git a/src/spdk/scripts/rpc/sock.py b/src/spdk/scripts/rpc/sock.py
new file mode 100644
index 000000000..34d7f100d
--- /dev/null
+++ b/src/spdk/scripts/rpc/sock.py
@@ -0,0 +1,41 @@
+def sock_impl_get_options(client, impl_name=None):
+ """Get parameters for the socket layer implementation.
+
+ Args:
+ impl_name: name of socket implementation, e.g. posix
+ """
+ params = {}
+
+ params['impl_name'] = impl_name
+
+ return client.call('sock_impl_get_options', params)
+
+
+def sock_impl_set_options(client,
+ impl_name=None,
+ recv_buf_size=None,
+ send_buf_size=None,
+ enable_recv_pipe=None,
+ enable_zerocopy_send=None):
+ """Set parameters for the socket layer implementation.
+
+ Args:
+ impl_name: name of socket implementation, e.g. posix
+ recv_buf_size: size of socket receive buffer in bytes (optional)
+ send_buf_size: size of socket send buffer in bytes (optional)
+ enable_recv_pipe: enable or disable receive pipe (optional)
+ enable_zerocopy_send: enable or disable zerocopy on send (optional)
+ """
+ params = {}
+
+ params['impl_name'] = impl_name
+ if recv_buf_size is not None:
+ params['recv_buf_size'] = recv_buf_size
+ if send_buf_size is not None:
+ params['send_buf_size'] = send_buf_size
+ if enable_recv_pipe is not None:
+ params['enable_recv_pipe'] = enable_recv_pipe
+ if enable_zerocopy_send is not None:
+ params['enable_zerocopy_send'] = enable_zerocopy_send
+
+ return client.call('sock_impl_set_options', params)
diff --git a/src/spdk/scripts/rpc/subsystem.py b/src/spdk/scripts/rpc/subsystem.py
new file mode 100644
index 000000000..a52adbf6b
--- /dev/null
+++ b/src/spdk/scripts/rpc/subsystem.py
@@ -0,0 +1,12 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('get_subsystems')
+def framework_get_subsystems(client):
+ return client.call('framework_get_subsystems')
+
+
+@deprecated_alias('get_subsystem_config')
+def framework_get_config(client, name):
+ params = {'name': name}
+ return client.call('framework_get_config', params)
diff --git a/src/spdk/scripts/rpc/trace.py b/src/spdk/scripts/rpc/trace.py
new file mode 100644
index 000000000..60667b5e8
--- /dev/null
+++ b/src/spdk/scripts/rpc/trace.py
@@ -0,0 +1,33 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('enable_tpoint_group')
+def trace_enable_tpoint_group(client, name):
+ """Enable trace on a specific tpoint group.
+
+ Args:
+ name: trace group name we want to enable in tpoint_group_mask. (for example "bdev").
+ """
+ params = {'name': name}
+ return client.call('trace_enable_tpoint_group', params)
+
+
+@deprecated_alias('disable_tpoint_group')
+def trace_disable_tpoint_group(client, name):
+ """Disable trace on a specific tpoint group.
+
+ Args:
+ name: trace group name we want to disable in tpoint_group_mask. (for example "bdev").
+ """
+ params = {'name': name}
+ return client.call('trace_disable_tpoint_group', params)
+
+
+@deprecated_alias('get_tpoint_group_mask')
+def trace_get_tpoint_group_mask(client):
+ """Get trace point group mask
+
+ Returns:
+ List of trace point group mask
+ """
+ return client.call('trace_get_tpoint_group_mask')
diff --git a/src/spdk/scripts/rpc/vhost.py b/src/spdk/scripts/rpc/vhost.py
new file mode 100644
index 000000000..b2e0a846c
--- /dev/null
+++ b/src/spdk/scripts/rpc/vhost.py
@@ -0,0 +1,190 @@
+from .helpers import deprecated_alias
+
+
+@deprecated_alias('set_vhost_controller_coalescing')
+def vhost_controller_set_coalescing(client, ctrlr, delay_base_us, iops_threshold):
+ """Set coalescing for vhost controller.
+ Args:
+ ctrlr: controller name
+ delay_base_us: base delay time
+ iops_threshold: IOPS threshold when coalescing is enabled
+ """
+ params = {
+ 'ctrlr': ctrlr,
+ 'delay_base_us': delay_base_us,
+ 'iops_threshold': iops_threshold,
+ }
+ return client.call('vhost_controller_set_coalescing', params)
+
+
+@deprecated_alias('construct_vhost_scsi_controller')
+def vhost_create_scsi_controller(client, ctrlr, cpumask=None):
+ """Create a vhost scsi controller.
+ Args:
+ ctrlr: controller name
+ cpumask: cpu mask for this controller
+ """
+ params = {'ctrlr': ctrlr}
+
+ if cpumask:
+ params['cpumask'] = cpumask
+
+ return client.call('vhost_create_scsi_controller', params)
+
+
+@deprecated_alias('add_vhost_scsi_lun')
+def vhost_scsi_controller_add_target(client, ctrlr, scsi_target_num, bdev_name):
+ """Add LUN to vhost scsi controller target.
+ Args:
+ ctrlr: controller name
+ scsi_target_num: target number to use
+ bdev_name: name of bdev to add to target
+ """
+ params = {
+ 'ctrlr': ctrlr,
+ 'scsi_target_num': scsi_target_num,
+ 'bdev_name': bdev_name,
+ }
+ return client.call('vhost_scsi_controller_add_target', params)
+
+
+@deprecated_alias('remove_vhost_scsi_target')
+def vhost_scsi_controller_remove_target(client, ctrlr, scsi_target_num):
+ """Remove target from vhost scsi controller.
+ Args:
+ ctrlr: controller name to remove target from
+ scsi_target_num: number of target to remove from controller
+ """
+ params = {
+ 'ctrlr': ctrlr,
+ 'scsi_target_num': scsi_target_num
+ }
+ return client.call('vhost_scsi_controller_remove_target', params)
+
+
+@deprecated_alias('construct_vhost_nvme_controller')
+def vhost_create_nvme_controller(client, ctrlr, io_queues, cpumask=None):
+ """Construct vhost NVMe controller.
+ Args:
+ ctrlr: controller name
+ io_queues: number of IO queues for the controller
+ cpumask: cpu mask for this controller
+ """
+ params = {
+ 'ctrlr': ctrlr,
+ 'io_queues': io_queues
+ }
+
+ if cpumask:
+ params['cpumask'] = cpumask
+
+ return client.call('vhost_create_nvme_controller', params)
+
+
+@deprecated_alias('add_vhost_nvme_ns')
+def vhost_nvme_controller_add_ns(client, ctrlr, bdev_name):
+ """Add namespace to vhost nvme controller.
+ Args:
+ ctrlr: controller name where to add a namespace
+ bdev_name: block device name for a new namespace
+ """
+ params = {
+ 'ctrlr': ctrlr,
+ 'bdev_name': bdev_name,
+ }
+
+ return client.call('vhost_nvme_controller_add_ns', params)
+
+
+@deprecated_alias('construct_vhost_blk_controller')
+def vhost_create_blk_controller(client, ctrlr, dev_name, cpumask=None, readonly=None, packed_ring=None):
+ """Create vhost BLK controller.
+ Args:
+ ctrlr: controller name
+ dev_name: device name to add to controller
+ cpumask: cpu mask for this controller
+ readonly: set controller as read-only
+ packed_ring: support controller packed_ring
+ """
+ params = {
+ 'ctrlr': ctrlr,
+ 'dev_name': dev_name,
+ }
+ if cpumask:
+ params['cpumask'] = cpumask
+ if readonly:
+ params['readonly'] = readonly
+ if packed_ring:
+ params['packed_ring'] = packed_ring
+ return client.call('vhost_create_blk_controller', params)
+
+
+@deprecated_alias('get_vhost_controllers')
+def vhost_get_controllers(client, name=None):
+ """Get information about configured vhost controllers.
+
+ Args:
+ name: controller name to query (optional; if omitted, query all controllers)
+
+ Returns:
+ List of vhost controllers.
+ """
+ params = {}
+ if name:
+ params['name'] = name
+ return client.call('vhost_get_controllers', params)
+
+
+@deprecated_alias('remove_vhost_controller')
+def vhost_delete_controller(client, ctrlr):
+ """Delete vhost controller from configuration.
+ Args:
+ ctrlr: controller name to remove
+ """
+ params = {'ctrlr': ctrlr}
+ return client.call('vhost_delete_controller', params)
+
+
+@deprecated_alias('construct_virtio_dev')
+def bdev_virtio_attach_controller(client, name, trtype, traddr, dev_type, vq_count=None, vq_size=None):
+ """Attaches virtio controller using
+ provided transport type and device type.
+ This will also create bdevs for any block
+ devices connected to that controller.
+ Args:
+ name: name base for new created bdevs
+ trtype: virtio target transport type: pci or user
+ traddr: transport type specific target address: e.g. UNIX
+ domain socket path or BDF
+ dev_type: device type: blk or scsi
+ vq_count: number of virtual queues to be used
+ vq_size: size of each queue
+ """
+ params = {
+ 'name': name,
+ 'trtype': trtype,
+ 'traddr': traddr,
+ 'dev_type': dev_type
+ }
+ if vq_count:
+ params['vq_count'] = vq_count
+ if vq_size:
+ params['vq_size'] = vq_size
+ return client.call('bdev_virtio_attach_controller', params)
+
+
+@deprecated_alias('remove_virtio_bdev ')
+def bdev_virtio_detach_controller(client, name):
+ """Remove a Virtio device
+ This will delete all bdevs exposed by this device.
+ Args:
+ name: virtio device name
+ """
+ params = {'name': name}
+ return client.call('bdev_virtio_detach_controller', params)
+
+
+@deprecated_alias('get_virtio_scsi_devs')
+def bdev_virtio_scsi_get_devices(client):
+ """Get list of virtio scsi devices."""
+ return client.call('bdev_virtio_scsi_get_devices')
diff --git a/src/spdk/scripts/rpc/vmd.py b/src/spdk/scripts/rpc/vmd.py
new file mode 100644
index 000000000..067271ef1
--- /dev/null
+++ b/src/spdk/scripts/rpc/vmd.py
@@ -0,0 +1,3 @@
+def enable_vmd(client):
+ """Enable VMD enumeration."""
+ return client.call('enable_vmd')