1#!/usr/bin/env python3 2 3from rpc.client import print_dict, print_json, JSONRPCException 4from rpc.helpers import deprecated_aliases 5 6import logging 7import argparse 8import rpc 9import sys 10import shlex 11import json 12 13try: 14 from shlex import quote 15except ImportError: 16 from pipes import quote 17 18 19def print_array(a): 20 print(" ".join((quote(v) for v in a))) 21 22 23if __name__ == "__main__": 24 parser = argparse.ArgumentParser( 25 description='SPDK RPC command line interface') 26 parser.add_argument('-s', dest='server_addr', 27 help='RPC domain socket path or IP address', default='/var/tmp/spdk.sock') 28 parser.add_argument('-p', dest='port', 29 help='RPC port number (if server_addr is IP address)', 30 default=5260, type=int) 31 parser.add_argument('-t', dest='timeout', 32 help='Timeout as a floating point number expressed in seconds waiting for response. Default: 60.0', 33 default=60.0, type=float) 34 parser.add_argument('-v', dest='verbose', action='store_const', const="INFO", 35 help='Set verbose mode to INFO', default="ERROR") 36 parser.add_argument('--verbose', dest='verbose', choices=['DEBUG', 'INFO', 'ERROR'], 37 help="""Set verbose level. """) 38 parser.add_argument('--dry_run', dest='dry_run', action='store_true', help="Display request and exit") 39 parser.set_defaults(dry_run=False) 40 subparsers = parser.add_subparsers(help='RPC methods', dest='called_rpc_name') 41 42 def start_subsystem_init(args): 43 rpc.start_subsystem_init(args.client) 44 45 p = subparsers.add_parser('start_subsystem_init', help='Start initialization of subsystems') 46 p.set_defaults(func=start_subsystem_init) 47 48 def wait_subsystem_init(args): 49 rpc.wait_subsystem_init(args.client) 50 51 p = subparsers.add_parser('wait_subsystem_init', help='Block until subsystems have been initialized') 52 p.set_defaults(func=wait_subsystem_init) 53 54 def rpc_get_methods(args): 55 print_dict(rpc.rpc_get_methods(args.client, 56 current=args.current)) 57 58 p = subparsers.add_parser('rpc_get_methods', help='Get list of supported RPC methods', aliases=['get_rpc_methods']) 59 p.add_argument('-c', '--current', help='Get list of RPC methods only callable in the current state.', action='store_true') 60 p.set_defaults(func=rpc_get_methods) 61 62 def get_spdk_version(args): 63 print_json(rpc.get_spdk_version(args.client)) 64 65 p = subparsers.add_parser('get_spdk_version', help='Get SPDK version') 66 p.set_defaults(func=get_spdk_version) 67 68 def save_config(args): 69 rpc.save_config(args.client, 70 sys.stdout, 71 indent=args.indent) 72 73 p = subparsers.add_parser('save_config', help="""Write current (live) configuration of SPDK subsystems and targets to stdout. 74 """) 75 p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2. 76 """, type=int, default=2) 77 p.set_defaults(func=save_config) 78 79 def load_config(args): 80 rpc.load_config(args.client, sys.stdin) 81 82 p = subparsers.add_parser('load_config', help="""Configure SPDK subsystems and targets using JSON RPC read from stdin.""") 83 p.set_defaults(func=load_config) 84 85 def save_subsystem_config(args): 86 rpc.save_subsystem_config(args.client, 87 sys.stdout, 88 indent=args.indent, 89 name=args.name) 90 91 p = subparsers.add_parser('save_subsystem_config', help="""Write current (live) configuration of SPDK subsystem to stdout. 92 """) 93 p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2. 94 """, type=int, default=2) 95 p.add_argument('-n', '--name', help='Name of subsystem', required=True) 96 p.set_defaults(func=save_subsystem_config) 97 98 def load_subsystem_config(args): 99 rpc.load_subsystem_config(args.client, 100 sys.stdin) 101 102 p = subparsers.add_parser('load_subsystem_config', help="""Configure SPDK subsystem using JSON RPC read from stdin.""") 103 p.set_defaults(func=load_subsystem_config) 104 105 # app 106 def kill_instance(args): 107 rpc.app.kill_instance(args.client, 108 sig_name=args.sig_name) 109 110 p = subparsers.add_parser('kill_instance', help='Send signal to instance') 111 p.add_argument('sig_name', help='signal will be sent to server.') 112 p.set_defaults(func=kill_instance) 113 114 def context_switch_monitor(args): 115 enabled = None 116 if args.enable: 117 enabled = True 118 if args.disable: 119 enabled = False 120 print_dict(rpc.app.context_switch_monitor(args.client, 121 enabled=enabled)) 122 123 p = subparsers.add_parser('context_switch_monitor', help='Control whether the context switch monitor is enabled') 124 p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring') 125 p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring') 126 p.set_defaults(func=context_switch_monitor) 127 128 # bdev 129 def set_bdev_options(args): 130 rpc.bdev.set_bdev_options(args.client, 131 bdev_io_pool_size=args.bdev_io_pool_size, 132 bdev_io_cache_size=args.bdev_io_cache_size) 133 134 p = subparsers.add_parser('set_bdev_options', help="""Set options of bdev subsystem""") 135 p.add_argument('-p', '--bdev-io-pool-size', help='Number of bdev_io structures in shared buffer pool', type=int) 136 p.add_argument('-c', '--bdev-io-cache-size', help='Maximum number of bdev_io structures cached per thread', type=int) 137 p.set_defaults(func=set_bdev_options) 138 139 def construct_compress_bdev(args): 140 print_json(rpc.bdev.construct_compress_bdev(args.client, 141 base_bdev_name=args.base_bdev_name, 142 pm_path=args.pm_path)) 143 p = subparsers.add_parser('construct_compress_bdev', 144 help='Add a compress vbdev') 145 p.add_argument('-b', '--base_bdev_name', help="Name of the base bdev") 146 p.add_argument('-p', '--pm_path', help="Path to persistent memory") 147 p.set_defaults(func=construct_compress_bdev) 148 149 def delete_compress_bdev(args): 150 rpc.bdev.delete_compress_bdev(args.client, 151 name=args.name) 152 153 p = subparsers.add_parser('delete_compress_bdev', help='Delete a compress disk') 154 p.add_argument('name', help='compress bdev name') 155 p.set_defaults(func=delete_compress_bdev) 156 157 def set_compress_pmd(args): 158 rpc.bdev.set_compress_pmd(args.client, 159 pmd=args.pmd) 160 p = subparsers.add_parser('set_compress_pmd', help='Set pmd option for a compress disk') 161 p.add_argument('-p', '--pmd', type=int, help='0 = auto-select, 1= QAT only, 2 = ISAL only') 162 p.set_defaults(func=set_compress_pmd) 163 164 def construct_crypto_bdev(args): 165 print_json(rpc.bdev.construct_crypto_bdev(args.client, 166 base_bdev_name=args.base_bdev_name, 167 name=args.name, 168 crypto_pmd=args.crypto_pmd, 169 key=args.key)) 170 p = subparsers.add_parser('construct_crypto_bdev', 171 help='Add a crypto vbdev') 172 p.add_argument('base_bdev_name', help="Name of the base bdev") 173 p.add_argument('name', help="Name of the crypto vbdev") 174 p.add_argument('crypto_pmd', help="Name of the crypto device driver") 175 p.add_argument('key', help="Key") 176 p.set_defaults(func=construct_crypto_bdev) 177 178 def delete_crypto_bdev(args): 179 rpc.bdev.delete_crypto_bdev(args.client, 180 name=args.name) 181 182 p = subparsers.add_parser('delete_crypto_bdev', help='Delete a crypto disk') 183 p.add_argument('name', help='crypto bdev name') 184 p.set_defaults(func=delete_crypto_bdev) 185 186 def construct_ocf_bdev(args): 187 print_json(rpc.bdev.construct_ocf_bdev(args.client, 188 name=args.name, 189 mode=args.mode, 190 cache_bdev_name=args.cache_bdev_name, 191 core_bdev_name=args.core_bdev_name)) 192 p = subparsers.add_parser('construct_ocf_bdev', 193 help='Add an OCF block device') 194 p.add_argument('name', help='Name of resulting OCF bdev') 195 p.add_argument('mode', help='OCF cache mode', choices=['wb', 'wt', 'pt']) 196 p.add_argument('cache_bdev_name', help='Name of underlying cache bdev') 197 p.add_argument('core_bdev_name', help='Name of unerlying core bdev') 198 p.set_defaults(func=construct_ocf_bdev) 199 200 def delete_ocf_bdev(args): 201 rpc.bdev.delete_ocf_bdev(args.client, 202 name=args.name) 203 204 p = subparsers.add_parser('delete_ocf_bdev', 205 help='Delete an OCF block device') 206 p.add_argument('name', help='Name of OCF bdev') 207 p.set_defaults(func=delete_ocf_bdev) 208 209 def get_ocf_stats(args): 210 print_dict(rpc.bdev.get_ocf_stats(args.client, 211 name=args.name)) 212 p = subparsers.add_parser('get_ocf_stats', 213 help='Get statistics of chosen OCF block device') 214 p.add_argument('name', help='Name of OCF bdev') 215 p.set_defaults(func=get_ocf_stats) 216 217 def get_ocf_bdevs(args): 218 print_dict(rpc.bdev.get_ocf_bdevs(args.client, 219 name=args.name)) 220 p = subparsers.add_parser('get_ocf_bdevs', 221 help='Get list of OCF devices including unregistered ones') 222 p.add_argument('name', nargs='?', default=None, help='name of OCF vbdev or name of cache device or name of core device (optional)') 223 p.set_defaults(func=get_ocf_bdevs) 224 225 def construct_malloc_bdev(args): 226 num_blocks = (args.total_size * 1024 * 1024) // args.block_size 227 print_json(rpc.bdev.construct_malloc_bdev(args.client, 228 num_blocks=int(num_blocks), 229 block_size=args.block_size, 230 name=args.name, 231 uuid=args.uuid)) 232 p = subparsers.add_parser('construct_malloc_bdev', 233 help='Add a bdev with malloc backend') 234 p.add_argument('-b', '--name', help="Name of the bdev") 235 p.add_argument('-u', '--uuid', help="UUID of the bdev") 236 p.add_argument( 237 'total_size', help='Size of malloc bdev in MB (float > 0)', type=float) 238 p.add_argument('block_size', help='Block size for this bdev', type=int) 239 p.set_defaults(func=construct_malloc_bdev) 240 241 def delete_malloc_bdev(args): 242 rpc.bdev.delete_malloc_bdev(args.client, 243 name=args.name) 244 245 p = subparsers.add_parser('delete_malloc_bdev', help='Delete a malloc disk') 246 p.add_argument('name', help='malloc bdev name') 247 p.set_defaults(func=delete_malloc_bdev) 248 249 def construct_null_bdev(args): 250 num_blocks = (args.total_size * 1024 * 1024) // args.block_size 251 print_json(rpc.bdev.construct_null_bdev(args.client, 252 num_blocks=num_blocks, 253 block_size=args.block_size, 254 name=args.name, 255 uuid=args.uuid)) 256 257 p = subparsers.add_parser('construct_null_bdev', 258 help='Add a bdev with null backend') 259 p.add_argument('name', help='Block device name') 260 p.add_argument('-u', '--uuid', help='UUID of the bdev') 261 p.add_argument( 262 'total_size', help='Size of null bdev in MB (int > 0)', type=int) 263 p.add_argument('block_size', help='Block size for this bdev', type=int) 264 p.set_defaults(func=construct_null_bdev) 265 266 def delete_null_bdev(args): 267 rpc.bdev.delete_null_bdev(args.client, 268 name=args.name) 269 270 p = subparsers.add_parser('delete_null_bdev', help='Delete a null bdev') 271 p.add_argument('name', help='null bdev name') 272 p.set_defaults(func=delete_null_bdev) 273 274 def construct_aio_bdev(args): 275 print_json(rpc.bdev.construct_aio_bdev(args.client, 276 filename=args.filename, 277 name=args.name, 278 block_size=args.block_size)) 279 280 p = subparsers.add_parser('construct_aio_bdev', 281 help='Add a bdev with aio backend') 282 p.add_argument('filename', help='Path to device or file (ex: /dev/sda)') 283 p.add_argument('name', help='Block device name') 284 p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?', default=0) 285 p.set_defaults(func=construct_aio_bdev) 286 287 def delete_aio_bdev(args): 288 rpc.bdev.delete_aio_bdev(args.client, 289 name=args.name) 290 291 p = subparsers.add_parser('delete_aio_bdev', help='Delete an aio disk') 292 p.add_argument('name', help='aio bdev name') 293 p.set_defaults(func=delete_aio_bdev) 294 295 def set_bdev_nvme_options(args): 296 rpc.bdev.set_bdev_nvme_options(args.client, 297 action_on_timeout=args.action_on_timeout, 298 timeout_us=args.timeout_us, 299 retry_count=args.retry_count, 300 nvme_adminq_poll_period_us=args.nvme_adminq_poll_period_us, 301 nvme_ioq_poll_period_us=args.nvme_ioq_poll_period_us) 302 303 p = subparsers.add_parser('set_bdev_nvme_options', 304 help='Set options for the bdev nvme type. This is startup command.') 305 p.add_argument('-a', '--action-on-timeout', 306 help="Action to take on command time out. Valid valies are: none, reset, abort") 307 p.add_argument('-t', '--timeout-us', 308 help="Timeout for each command, in microseconds. If 0, don't track timeouts.", type=int) 309 p.add_argument('-n', '--retry-count', 310 help='the number of attempts per I/O when an I/O fails', type=int) 311 p.add_argument('-p', '--nvme-adminq-poll-period-us', 312 help='How often the admin queue is polled for asynchronous events', type=int) 313 p.add_argument('-i', '--nvme-ioq-poll-period-us', 314 help='How often to poll I/O queues for completions', type=int) 315 p.set_defaults(func=set_bdev_nvme_options) 316 317 def set_bdev_nvme_hotplug(args): 318 rpc.bdev.set_bdev_nvme_hotplug(args.client, enable=args.enable, period_us=args.period_us) 319 320 p = subparsers.add_parser('set_bdev_nvme_hotplug', 321 help='Set hotplug options for bdev nvme type.') 322 p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)") 323 p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug") 324 p.add_argument('-r', '--period-us', 325 help='How often the hotplug is processed for insert and remove events', type=int) 326 p.set_defaults(func=set_bdev_nvme_hotplug) 327 328 def construct_nvme_bdev(args): 329 print_array(rpc.bdev.construct_nvme_bdev(args.client, 330 name=args.name, 331 trtype=args.trtype, 332 traddr=args.traddr, 333 adrfam=args.adrfam, 334 trsvcid=args.trsvcid, 335 subnqn=args.subnqn, 336 hostnqn=args.hostnqn, 337 hostaddr=args.hostaddr, 338 hostsvcid=args.hostsvcid, 339 prchk_reftag=args.prchk_reftag, 340 prchk_guard=args.prchk_guard)) 341 342 p = subparsers.add_parser('construct_nvme_bdev', 343 help='Add bdevs with nvme backend') 344 p.add_argument('-b', '--name', help="Name of the NVMe controller, prefix for each bdev name", required=True) 345 p.add_argument('-t', '--trtype', 346 help='NVMe-oF target trtype: e.g., rdma, pcie', required=True) 347 p.add_argument('-a', '--traddr', 348 help='NVMe-oF target address: e.g., an ip address or BDF', required=True) 349 p.add_argument('-f', '--adrfam', 350 help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host') 351 p.add_argument('-s', '--trsvcid', 352 help='NVMe-oF target trsvcid: e.g., a port number') 353 p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn') 354 p.add_argument('-q', '--hostnqn', help='NVMe-oF host subnqn') 355 p.add_argument('-i', '--hostaddr', 356 help='NVMe-oF host address: e.g., an ip address') 357 p.add_argument('-c', '--hostsvcid', 358 help='NVMe-oF host svcid: e.g., a port number') 359 p.add_argument('-r', '--prchk-reftag', 360 help='Enable checking of PI reference tag for I/O processing.', action='store_true') 361 p.add_argument('-g', '--prchk-guard', 362 help='Enable checking of PI guard for I/O processing.', action='store_true') 363 p.set_defaults(func=construct_nvme_bdev) 364 365 def get_nvme_controllers(args): 366 print_dict(rpc.nvme.get_nvme_controllers(args.client, 367 name=args.name)) 368 369 p = subparsers.add_parser( 370 'get_nvme_controllers', help='Display current NVMe controllers list or required NVMe controller') 371 p.add_argument('-n', '--name', help="Name of the NVMe controller. Example: Nvme0", required=False) 372 p.set_defaults(func=get_nvme_controllers) 373 374 def delete_nvme_controller(args): 375 rpc.bdev.delete_nvme_controller(args.client, 376 name=args.name) 377 378 p = subparsers.add_parser('delete_nvme_controller', 379 help='Delete a NVMe controller using controller name') 380 p.add_argument('name', help="Name of the controller") 381 p.set_defaults(func=delete_nvme_controller) 382 383 def construct_rbd_bdev(args): 384 config = None 385 if args.config: 386 config = {} 387 for entry in args.config: 388 parts = entry.split('=', 1) 389 if len(parts) != 2: 390 raise Exception('--config %s not in key=value form' % entry) 391 config[parts[0]] = parts[1] 392 print_json(rpc.bdev.construct_rbd_bdev(args.client, 393 name=args.name, 394 user=args.user, 395 config=config, 396 pool_name=args.pool_name, 397 rbd_name=args.rbd_name, 398 block_size=args.block_size)) 399 400 p = subparsers.add_parser('construct_rbd_bdev', 401 help='Add a bdev with ceph rbd backend') 402 p.add_argument('-b', '--name', help="Name of the bdev", required=False) 403 p.add_argument('--user', help="Ceph user name (i.e. admin, not client.admin)", required=False) 404 p.add_argument('--config', action='append', metavar='key=value', 405 help="adds a key=value configuration option for rados_conf_set (default: rely on config file)") 406 p.add_argument('pool_name', help='rbd pool name') 407 p.add_argument('rbd_name', help='rbd image name') 408 p.add_argument('block_size', help='rbd block size', type=int) 409 p.set_defaults(func=construct_rbd_bdev) 410 411 def delete_rbd_bdev(args): 412 rpc.bdev.delete_rbd_bdev(args.client, 413 name=args.name) 414 415 p = subparsers.add_parser('delete_rbd_bdev', help='Delete a rbd bdev') 416 p.add_argument('name', help='rbd bdev name') 417 p.set_defaults(func=delete_rbd_bdev) 418 419 def bdev_delay_create(args): 420 print_json(rpc.bdev.bdev_delay_create(args.client, 421 base_bdev_name=args.base_bdev_name, 422 name=args.name, 423 avg_read_latency=args.avg_read_latency, 424 p99_read_latency=args.nine_nine_read_latency, 425 avg_write_latency=args.avg_write_latency, 426 p99_write_latency=args.nine_nine_write_latency)) 427 428 p = subparsers.add_parser('bdev_delay_create', 429 help='Add a delay bdev on existing bdev') 430 p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True) 431 p.add_argument('-d', '--name', help="Name of the delay bdev", required=True) 432 p.add_argument('-r', '--avg-read-latency', help="Average latency to apply before completing read ops", required=True, type=int) 433 p.add_argument('-t', '--nine-nine-read-latency', help="latency to apply to 1 in 100 read ops", required=True, type=int) 434 p.add_argument('-w', '--avg-write-latency', help="Average latency to apply before completing write ops", required=True, type=int) 435 p.add_argument('-n', '--nine-nine-write-latency', help="latency to apply to 1 in 100 write ops", required=True, type=int) 436 p.set_defaults(func=bdev_delay_create) 437 438 def bdev_delay_delete(args): 439 rpc.bdev.bdev_delay_delete(args.client, 440 name=args.name) 441 442 p = subparsers.add_parser('bdev_delay_delete', help='Delete a delay bdev') 443 p.add_argument('name', help='delay bdev name') 444 p.set_defaults(func=bdev_delay_delete) 445 446 def construct_error_bdev(args): 447 print_json(rpc.bdev.construct_error_bdev(args.client, 448 base_name=args.base_name)) 449 450 p = subparsers.add_parser('construct_error_bdev', 451 help='Add bdev with error injection backend') 452 p.add_argument('base_name', help='base bdev name') 453 p.set_defaults(func=construct_error_bdev) 454 455 def delete_error_bdev(args): 456 rpc.bdev.delete_error_bdev(args.client, 457 name=args.name) 458 459 p = subparsers.add_parser('delete_error_bdev', help='Delete an error bdev') 460 p.add_argument('name', help='error bdev name') 461 p.set_defaults(func=delete_error_bdev) 462 463 def construct_iscsi_bdev(args): 464 print_json(rpc.bdev.construct_iscsi_bdev(args.client, 465 name=args.name, 466 url=args.url, 467 initiator_iqn=args.initiator_iqn)) 468 469 p = subparsers.add_parser('construct_iscsi_bdev', 470 help='Add bdev with iSCSI initiator backend') 471 p.add_argument('-b', '--name', help="Name of the bdev", required=True) 472 p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True) 473 p.add_argument('--url', help="iSCSI Lun URL", required=True) 474 p.set_defaults(func=construct_iscsi_bdev) 475 476 def delete_iscsi_bdev(args): 477 rpc.bdev.delete_iscsi_bdev(args.client, 478 name=args.name) 479 480 p = subparsers.add_parser('delete_iscsi_bdev', help='Delete an iSCSI bdev') 481 p.add_argument('name', help='iSCSI bdev name') 482 p.set_defaults(func=delete_iscsi_bdev) 483 484 def construct_pmem_bdev(args): 485 print_json(rpc.bdev.construct_pmem_bdev(args.client, 486 pmem_file=args.pmem_file, 487 name=args.name)) 488 489 p = subparsers.add_parser('construct_pmem_bdev', help='Add a bdev with pmem backend') 490 p.add_argument('pmem_file', help='Path to pmemblk pool file') 491 p.add_argument('-n', '--name', help='Block device name', required=True) 492 p.set_defaults(func=construct_pmem_bdev) 493 494 def delete_pmem_bdev(args): 495 rpc.bdev.delete_pmem_bdev(args.client, 496 name=args.name) 497 498 p = subparsers.add_parser('delete_pmem_bdev', help='Delete a pmem bdev') 499 p.add_argument('name', help='pmem bdev name') 500 p.set_defaults(func=delete_pmem_bdev) 501 502 def construct_passthru_bdev(args): 503 print_json(rpc.bdev.construct_passthru_bdev(args.client, 504 base_bdev_name=args.base_bdev_name, 505 name=args.name)) 506 507 p = subparsers.add_parser('construct_passthru_bdev', 508 help='Add a pass through bdev on existing bdev') 509 p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True) 510 p.add_argument('-p', '--name', help="Name of the pass through bdev", required=True) 511 p.set_defaults(func=construct_passthru_bdev) 512 513 def delete_passthru_bdev(args): 514 rpc.bdev.delete_passthru_bdev(args.client, 515 name=args.name) 516 517 p = subparsers.add_parser('delete_passthru_bdev', help='Delete a pass through bdev') 518 p.add_argument('name', help='pass through bdev name') 519 p.set_defaults(func=delete_passthru_bdev) 520 521 def get_bdevs(args): 522 print_dict(rpc.bdev.get_bdevs(args.client, 523 name=args.name)) 524 525 p = subparsers.add_parser( 526 'get_bdevs', help='Display current blockdev list or required blockdev') 527 p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False) 528 p.set_defaults(func=get_bdevs) 529 530 def get_bdevs_iostat(args): 531 print_dict(rpc.bdev.get_bdevs_iostat(args.client, 532 name=args.name)) 533 534 p = subparsers.add_parser( 535 'get_bdevs_iostat', help='Display current I/O statistics of all the blockdevs or required blockdev.') 536 p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False) 537 p.set_defaults(func=get_bdevs_iostat) 538 539 def enable_bdev_histogram(args): 540 rpc.bdev.enable_bdev_histogram(args.client, name=args.name, enable=args.enable) 541 542 p = subparsers.add_parser('enable_bdev_histogram', help='Enable or disable histogram for specified bdev') 543 p.add_argument('-e', '--enable', default=True, dest='enable', action='store_true', help='Enable histograms on specified device') 544 p.add_argument('-d', '--disable', dest='enable', action='store_false', help='Disable histograms on specified device') 545 p.add_argument('name', help='bdev name') 546 p.set_defaults(func=enable_bdev_histogram) 547 548 def get_bdev_histogram(args): 549 print_dict(rpc.bdev.get_bdev_histogram(args.client, name=args.name)) 550 551 p = subparsers.add_parser('get_bdev_histogram', help='Get histogram for specified bdev') 552 p.add_argument('name', help='bdev name') 553 p.set_defaults(func=get_bdev_histogram) 554 555 def set_bdev_qd_sampling_period(args): 556 rpc.bdev.set_bdev_qd_sampling_period(args.client, 557 name=args.name, 558 period=args.period) 559 560 p = subparsers.add_parser('set_bdev_qd_sampling_period', help="Enable or disable tracking of a bdev's queue depth.") 561 p.add_argument('name', help='Blockdev name. Example: Malloc0') 562 p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.' 563 ' If set to 0, polling will be disabled.', 564 type=int) 565 p.set_defaults(func=set_bdev_qd_sampling_period) 566 567 def set_bdev_qos_limit(args): 568 rpc.bdev.set_bdev_qos_limit(args.client, 569 name=args.name, 570 rw_ios_per_sec=args.rw_ios_per_sec, 571 rw_mbytes_per_sec=args.rw_mbytes_per_sec, 572 r_mbytes_per_sec=args.r_mbytes_per_sec, 573 w_mbytes_per_sec=args.w_mbytes_per_sec) 574 575 p = subparsers.add_parser('set_bdev_qos_limit', help='Set QoS rate limit on a blockdev') 576 p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0') 577 p.add_argument('--rw_ios_per_sec', 578 help='R/W IOs per second limit (>=10000, example: 20000). 0 means unlimited.', 579 type=int, required=False) 580 p.add_argument('--rw_mbytes_per_sec', 581 help="R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.", 582 type=int, required=False) 583 p.add_argument('--r_mbytes_per_sec', 584 help="Read megabytes per second limit (>=10, example: 100). 0 means unlimited.", 585 type=int, required=False) 586 p.add_argument('--w_mbytes_per_sec', 587 help="Write megabytes per second limit (>=10, example: 100). 0 means unlimited.", 588 type=int, required=False) 589 p.set_defaults(func=set_bdev_qos_limit) 590 591 def bdev_inject_error(args): 592 rpc.bdev.bdev_inject_error(args.client, 593 name=args.name, 594 io_type=args.io_type, 595 error_type=args.error_type, 596 num=args.num) 597 598 p = subparsers.add_parser('bdev_inject_error', help='bdev inject error') 599 p.add_argument('name', help="""the name of the error injection bdev""") 600 p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""") 601 p.add_argument('error_type', help="""error_type: 'failure' 'pending'""") 602 p.add_argument( 603 '-n', '--num', help='the number of commands you want to fail', type=int, default=1) 604 p.set_defaults(func=bdev_inject_error) 605 606 def apply_firmware(args): 607 print_dict(rpc.bdev.apply_firmware(args.client, 608 bdev_name=args.bdev_name, 609 filename=args.filename)) 610 611 p = subparsers.add_parser('apply_firmware', help='Download and commit firmware to NVMe device') 612 p.add_argument('filename', help='filename of the firmware to download') 613 p.add_argument('bdev_name', help='name of the NVMe device') 614 p.set_defaults(func=apply_firmware) 615 616 # iSCSI 617 def set_iscsi_options(args): 618 rpc.iscsi.set_iscsi_options( 619 args.client, 620 auth_file=args.auth_file, 621 node_base=args.node_base, 622 nop_timeout=args.nop_timeout, 623 nop_in_interval=args.nop_in_interval, 624 disable_chap=args.disable_chap, 625 require_chap=args.require_chap, 626 mutual_chap=args.mutual_chap, 627 chap_group=args.chap_group, 628 max_sessions=args.max_sessions, 629 max_queue_depth=args.max_queue_depth, 630 max_connections_per_session=args.max_connections_per_session, 631 default_time2wait=args.default_time2wait, 632 default_time2retain=args.default_time2retain, 633 first_burst_length=args.first_burst_length, 634 immediate_data=args.immediate_data, 635 error_recovery_level=args.error_recovery_level, 636 allow_duplicated_isid=args.allow_duplicated_isid) 637 638 p = subparsers.add_parser('set_iscsi_options', help="""Set options of iSCSI subsystem""") 639 p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file') 640 p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node') 641 p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int) 642 p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int) 643 p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled. 644 *** Mutually exclusive with --require-chap""", action='store_true') 645 p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required. 646 *** Mutually exclusive with --disable-chap""", action='store_true') 647 p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true') 648 p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session. 649 *** Authentication group must be precreated ***""", type=int) 650 p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int) 651 p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int) 652 p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int) 653 p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int) 654 p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int) 655 p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int) 656 p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true') 657 p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int) 658 p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true') 659 p.set_defaults(func=set_iscsi_options) 660 661 def set_iscsi_discovery_auth(args): 662 rpc.iscsi.set_iscsi_discovery_auth( 663 args.client, 664 disable_chap=args.disable_chap, 665 require_chap=args.require_chap, 666 mutual_chap=args.mutual_chap, 667 chap_group=args.chap_group) 668 669 p = subparsers.add_parser('set_iscsi_discovery_auth', help="""Set CHAP authentication for discovery session.""") 670 p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled. 671 *** Mutually exclusive with --require-chap""", action='store_true') 672 p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required. 673 *** Mutually exclusive with --disable-chap""", action='store_true') 674 p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true') 675 p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session. 676 *** Authentication group must be precreated ***""", type=int) 677 p.set_defaults(func=set_iscsi_discovery_auth) 678 679 def add_iscsi_auth_group(args): 680 secrets = None 681 if args.secrets: 682 secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")] 683 684 rpc.iscsi.add_iscsi_auth_group(args.client, tag=args.tag, secrets=secrets) 685 686 p = subparsers.add_parser('add_iscsi_auth_group', help='Add authentication group for CHAP authentication.') 687 p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int) 688 p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets 689<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes. 690Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False) 691 p.set_defaults(func=add_iscsi_auth_group) 692 693 def delete_iscsi_auth_group(args): 694 rpc.iscsi.delete_iscsi_auth_group(args.client, tag=args.tag) 695 696 p = subparsers.add_parser('delete_iscsi_auth_group', help='Delete an authentication group.') 697 p.add_argument('tag', help='Authentication group tag', type=int) 698 p.set_defaults(func=delete_iscsi_auth_group) 699 700 def add_secret_to_iscsi_auth_group(args): 701 rpc.iscsi.add_secret_to_iscsi_auth_group( 702 args.client, 703 tag=args.tag, 704 user=args.user, 705 secret=args.secret, 706 muser=args.muser, 707 msecret=args.msecret) 708 709 p = subparsers.add_parser('add_secret_to_iscsi_auth_group', help='Add a secret to an authentication group.') 710 p.add_argument('tag', help='Authentication group tag', type=int) 711 p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True) 712 p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True) 713 p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication') 714 p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication') 715 p.set_defaults(func=add_secret_to_iscsi_auth_group) 716 717 def delete_secret_from_iscsi_auth_group(args): 718 rpc.iscsi.delete_secret_from_iscsi_auth_group(args.client, tag=args.tag, user=args.user) 719 720 p = subparsers.add_parser('delete_secret_from_iscsi_auth_group', help='Delete a secret from an authentication group.') 721 p.add_argument('tag', help='Authentication group tag', type=int) 722 p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True) 723 p.set_defaults(func=delete_secret_from_iscsi_auth_group) 724 725 def get_iscsi_auth_groups(args): 726 print_dict(rpc.iscsi.get_iscsi_auth_groups(args.client)) 727 728 p = subparsers.add_parser('get_iscsi_auth_groups', 729 help='Display current authentication group configuration') 730 p.set_defaults(func=get_iscsi_auth_groups) 731 732 def get_portal_groups(args): 733 print_dict(rpc.iscsi.get_portal_groups(args.client)) 734 735 p = subparsers.add_parser( 736 'get_portal_groups', help='Display current portal group configuration') 737 p.set_defaults(func=get_portal_groups) 738 739 def get_initiator_groups(args): 740 print_dict(rpc.iscsi.get_initiator_groups(args.client)) 741 742 p = subparsers.add_parser('get_initiator_groups', 743 help='Display current initiator group configuration') 744 p.set_defaults(func=get_initiator_groups) 745 746 def get_target_nodes(args): 747 print_dict(rpc.iscsi.get_target_nodes(args.client)) 748 749 p = subparsers.add_parser('get_target_nodes', help='Display target nodes') 750 p.set_defaults(func=get_target_nodes) 751 752 def construct_target_node(args): 753 luns = [] 754 for u in args.bdev_name_id_pairs.strip().split(" "): 755 bdev_name, lun_id = u.split(":") 756 luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)}) 757 758 pg_ig_maps = [] 759 for u in args.pg_ig_mappings.strip().split(" "): 760 pg, ig = u.split(":") 761 pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)}) 762 763 rpc.iscsi.construct_target_node( 764 args.client, 765 luns=luns, 766 pg_ig_maps=pg_ig_maps, 767 name=args.name, 768 alias_name=args.alias_name, 769 queue_depth=args.queue_depth, 770 chap_group=args.chap_group, 771 disable_chap=args.disable_chap, 772 require_chap=args.require_chap, 773 mutual_chap=args.mutual_chap, 774 header_digest=args.header_digest, 775 data_digest=args.data_digest) 776 777 p = subparsers.add_parser('construct_target_node', 778 help='Add a target node') 779 p.add_argument('name', help='Target node name (ASCII)') 780 p.add_argument('alias_name', help='Target node alias name (ASCII)') 781 p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed 782 in quotes. Format: 'bdev_name0:id0 bdev_name1:id1' etc 783 Example: 'Malloc0:0 Malloc1:1 Malloc5:2' 784 *** The bdevs must pre-exist *** 785 *** LUN0 (id = 0) is required *** 786 *** bdevs names cannot contain space or colon characters ***""") 787 p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings 788 Whitespace separated, quoted, mapping defined with colon 789 separated list of "tags" (int > 0) 790 Example: '1:1 2:2 2:1' 791 *** The Portal/Initiator Groups must be precreated ***""") 792 p.add_argument('queue_depth', help='Desired target queue depth', type=int) 793 p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node. 794 *** Authentication group must be precreated ***""", type=int, default=0) 795 p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node. 796 *** Mutually exclusive with --require-chap ***""", action='store_true') 797 p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node. 798 *** Mutually exclusive with --disable-chap ***""", action='store_true') 799 p.add_argument( 800 '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true') 801 p.add_argument('-H', '--header-digest', 802 help='Header Digest should be required for this target node.', action='store_true') 803 p.add_argument('-D', '--data-digest', 804 help='Data Digest should be required for this target node.', action='store_true') 805 p.set_defaults(func=construct_target_node) 806 807 def target_node_add_lun(args): 808 rpc.iscsi.target_node_add_lun( 809 args.client, 810 name=args.name, 811 bdev_name=args.bdev_name, 812 lun_id=args.lun_id) 813 814 p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node') 815 p.add_argument('name', help='Target node name (ASCII)') 816 p.add_argument('bdev_name', help="""bdev name enclosed in quotes. 817 *** bdev name cannot contain space or colon characters ***""") 818 p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0) 819 *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False) 820 p.set_defaults(func=target_node_add_lun) 821 822 def set_iscsi_target_node_auth(args): 823 rpc.iscsi.set_iscsi_target_node_auth( 824 args.client, 825 name=args.name, 826 chap_group=args.chap_group, 827 disable_chap=args.disable_chap, 828 require_chap=args.require_chap, 829 mutual_chap=args.mutual_chap) 830 831 p = subparsers.add_parser('set_iscsi_target_node_auth', help='Set CHAP authentication for the target node') 832 p.add_argument('name', help='Target node name (ASCII)') 833 p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node. 834 *** Authentication group must be precreated ***""", type=int, default=0) 835 p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node. 836 *** Mutually exclusive with --require-chap ***""", action='store_true') 837 p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node. 838 *** Mutually exclusive with --disable-chap ***""", action='store_true') 839 p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', 840 action='store_true') 841 p.set_defaults(func=set_iscsi_target_node_auth) 842 843 def add_pg_ig_maps(args): 844 pg_ig_maps = [] 845 for u in args.pg_ig_mappings.strip().split(" "): 846 pg, ig = u.split(":") 847 pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)}) 848 rpc.iscsi.add_pg_ig_maps( 849 args.client, 850 pg_ig_maps=pg_ig_maps, 851 name=args.name) 852 853 p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node') 854 p.add_argument('name', help='Target node name (ASCII)') 855 p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings 856 Whitespace separated, quoted, mapping defined with colon 857 separated list of "tags" (int > 0) 858 Example: '1:1 2:2 2:1' 859 *** The Portal/Initiator Groups must be precreated ***""") 860 p.set_defaults(func=add_pg_ig_maps) 861 862 def delete_pg_ig_maps(args): 863 pg_ig_maps = [] 864 for u in args.pg_ig_mappings.strip().split(" "): 865 pg, ig = u.split(":") 866 pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)}) 867 rpc.iscsi.delete_pg_ig_maps( 868 args.client, pg_ig_maps=pg_ig_maps, name=args.name) 869 870 p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node') 871 p.add_argument('name', help='Target node name (ASCII)') 872 p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings 873 Whitespace separated, quoted, mapping defined with colon 874 separated list of "tags" (int > 0) 875 Example: '1:1 2:2 2:1' 876 *** The Portal/Initiator Groups must be precreated ***""") 877 p.set_defaults(func=delete_pg_ig_maps) 878 879 def add_portal_group(args): 880 portals = [] 881 for p in args.portal_list.strip().split(' '): 882 ip, separator, port_cpumask = p.rpartition(':') 883 split_port_cpumask = port_cpumask.split('@') 884 if len(split_port_cpumask) == 1: 885 port = port_cpumask 886 portals.append({'host': ip, 'port': port}) 887 else: 888 port = split_port_cpumask[0] 889 cpumask = split_port_cpumask[1] 890 portals.append({'host': ip, 'port': port, 'cpumask': cpumask}) 891 rpc.iscsi.add_portal_group( 892 args.client, 893 portals=portals, 894 tag=args.tag) 895 896 p = subparsers.add_parser('add_portal_group', help='Add a portal group') 897 p.add_argument( 898 'tag', help='Portal group tag (unique, integer > 0)', type=int) 899 p.add_argument('portal_list', help="""List of portals in host:port@cpumask format, separated by whitespace 900 (cpumask is optional and can be skipped) 901 Example: '192.168.100.100:3260 192.168.100.100:3261 192.168.100.100:3262@0x1""") 902 p.set_defaults(func=add_portal_group) 903 904 def add_initiator_group(args): 905 initiators = [] 906 netmasks = [] 907 for i in args.initiator_list.strip().split(' '): 908 initiators.append(i) 909 for n in args.netmask_list.strip().split(' '): 910 netmasks.append(n) 911 rpc.iscsi.add_initiator_group( 912 args.client, 913 tag=args.tag, 914 initiators=initiators, 915 netmasks=netmasks) 916 917 p = subparsers.add_parser('add_initiator_group', 918 help='Add an initiator group') 919 p.add_argument( 920 'tag', help='Initiator group tag (unique, integer > 0)', type=int) 921 p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses, 922 enclosed in quotes. Example: 'ANY' or '127.0.0.1 192.168.200.100'""") 923 p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes. 924 Example: '255.255.0.0 255.248.0.0' etc""") 925 p.set_defaults(func=add_initiator_group) 926 927 def add_initiators_to_initiator_group(args): 928 initiators = None 929 netmasks = None 930 if args.initiator_list: 931 initiators = [] 932 for i in args.initiator_list.strip().split(' '): 933 initiators.append(i) 934 if args.netmask_list: 935 netmasks = [] 936 for n in args.netmask_list.strip().split(' '): 937 netmasks.append(n) 938 rpc.iscsi.add_initiators_to_initiator_group( 939 args.client, 940 tag=args.tag, 941 initiators=initiators, 942 netmasks=netmasks) 943 944 p = subparsers.add_parser('add_initiators_to_initiator_group', 945 help='Add initiators to an existing initiator group') 946 p.add_argument( 947 'tag', help='Initiator group tag (unique, integer > 0)', type=int) 948 p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses, 949 enclosed in quotes. This parameter can be omitted. Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False) 950 p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes. 951 This parameter can be omitted. Example: '255.255.0.0 255.248.0.0' etc""", required=False) 952 p.set_defaults(func=add_initiators_to_initiator_group) 953 954 def delete_initiators_from_initiator_group(args): 955 initiators = None 956 netmasks = None 957 if args.initiator_list: 958 initiators = [] 959 for i in args.initiator_list.strip().split(' '): 960 initiators.append(i) 961 if args.netmask_list: 962 netmasks = [] 963 for n in args.netmask_list.strip().split(' '): 964 netmasks.append(n) 965 rpc.iscsi.delete_initiators_from_initiator_group( 966 args.client, 967 tag=args.tag, 968 initiators=initiators, 969 netmasks=netmasks) 970 971 p = subparsers.add_parser('delete_initiators_from_initiator_group', 972 help='Delete initiators from an existing initiator group') 973 p.add_argument( 974 'tag', help='Initiator group tag (unique, integer > 0)', type=int) 975 p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses, 976 enclosed in quotes. This parameter can be omitted. Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False) 977 p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes. 978 This parameter can be omitted. Example: '255.255.0.0 255.248.0.0' etc""", required=False) 979 p.set_defaults(func=delete_initiators_from_initiator_group) 980 981 def delete_target_node(args): 982 rpc.iscsi.delete_target_node( 983 args.client, target_node_name=args.target_node_name) 984 985 p = subparsers.add_parser('delete_target_node', 986 help='Delete a target node') 987 p.add_argument('target_node_name', 988 help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.') 989 p.set_defaults(func=delete_target_node) 990 991 def delete_portal_group(args): 992 rpc.iscsi.delete_portal_group(args.client, tag=args.tag) 993 994 p = subparsers.add_parser('delete_portal_group', 995 help='Delete a portal group') 996 p.add_argument( 997 'tag', help='Portal group tag (unique, integer > 0)', type=int) 998 p.set_defaults(func=delete_portal_group) 999 1000 def delete_initiator_group(args): 1001 rpc.iscsi.delete_initiator_group(args.client, tag=args.tag) 1002 1003 p = subparsers.add_parser('delete_initiator_group', 1004 help='Delete an initiator group') 1005 p.add_argument( 1006 'tag', help='Initiator group tag (unique, integer > 0)', type=int) 1007 p.set_defaults(func=delete_initiator_group) 1008 1009 def get_iscsi_connections(args): 1010 print_dict(rpc.iscsi.get_iscsi_connections(args.client)) 1011 1012 p = subparsers.add_parser('get_iscsi_connections', 1013 help='Display iSCSI connections') 1014 p.set_defaults(func=get_iscsi_connections) 1015 1016 def get_iscsi_global_params(args): 1017 print_dict(rpc.iscsi.get_iscsi_global_params(args.client)) 1018 1019 p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters') 1020 p.set_defaults(func=get_iscsi_global_params) 1021 1022 def get_scsi_devices(args): 1023 print_dict(rpc.iscsi.get_scsi_devices(args.client)) 1024 1025 p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices') 1026 p.set_defaults(func=get_scsi_devices) 1027 1028 # trace 1029 def enable_tpoint_group(args): 1030 rpc.trace.enable_tpoint_group(args.client, name=args.name) 1031 1032 p = subparsers.add_parser('enable_tpoint_group', help='enable trace on a specific tpoint group') 1033 p.add_argument( 1034 'name', help="""trace group name we want to enable in tpoint_group_mask. 1035 (for example "bdev" for bdev trace group, "all" for all trace groups).""") 1036 p.set_defaults(func=enable_tpoint_group) 1037 1038 def disable_tpoint_group(args): 1039 rpc.trace.disable_tpoint_group(args.client, name=args.name) 1040 1041 p = subparsers.add_parser('disable_tpoint_group', help='disable trace on a specific tpoint group') 1042 p.add_argument( 1043 'name', help="""trace group name we want to disable in tpoint_group_mask. 1044 (for example "bdev" for bdev trace group, "all" for all trace groups).""") 1045 p.set_defaults(func=disable_tpoint_group) 1046 1047 def get_tpoint_group_mask(args): 1048 print_dict(rpc.trace.get_tpoint_group_mask(args.client)) 1049 1050 p = subparsers.add_parser('get_tpoint_group_mask', help='get trace point group mask') 1051 p.set_defaults(func=get_tpoint_group_mask) 1052 1053 # log 1054 def set_log_flag(args): 1055 rpc.log.set_log_flag(args.client, flag=args.flag) 1056 1057 p = subparsers.add_parser('set_log_flag', help='set log flag', aliases=['set_trace_flag']) 1058 p.add_argument( 1059 'flag', help='log flag we want to set. (for example "nvme").') 1060 p.set_defaults(func=set_log_flag) 1061 1062 def clear_log_flag(args): 1063 rpc.log.clear_log_flag(args.client, flag=args.flag) 1064 1065 p = subparsers.add_parser('clear_log_flag', help='clear log flag', aliases=['clear_trace_flag']) 1066 p.add_argument( 1067 'flag', help='log flag we want to clear. (for example "nvme").') 1068 p.set_defaults(func=clear_log_flag) 1069 1070 def get_log_flags(args): 1071 print_dict(rpc.log.get_log_flags(args.client)) 1072 1073 p = subparsers.add_parser('get_log_flags', help='get log flags', aliases=['get_trace_flags']) 1074 p.set_defaults(func=get_log_flags) 1075 1076 def set_log_level(args): 1077 rpc.log.set_log_level(args.client, level=args.level) 1078 1079 p = subparsers.add_parser('set_log_level', help='set log level') 1080 p.add_argument('level', help='log level we want to set. (for example "DEBUG").') 1081 p.set_defaults(func=set_log_level) 1082 1083 def get_log_level(args): 1084 print_dict(rpc.log.get_log_level(args.client)) 1085 1086 p = subparsers.add_parser('get_log_level', help='get log level') 1087 p.set_defaults(func=get_log_level) 1088 1089 def set_log_print_level(args): 1090 rpc.log.set_log_print_level(args.client, level=args.level) 1091 1092 p = subparsers.add_parser('set_log_print_level', help='set log print level') 1093 p.add_argument('level', help='log print level we want to set. (for example "DEBUG").') 1094 p.set_defaults(func=set_log_print_level) 1095 1096 def get_log_print_level(args): 1097 print_dict(rpc.log.get_log_print_level(args.client)) 1098 1099 p = subparsers.add_parser('get_log_print_level', help='get log print level') 1100 p.set_defaults(func=get_log_print_level) 1101 1102 # lvol 1103 def construct_lvol_store(args): 1104 print_json(rpc.lvol.construct_lvol_store(args.client, 1105 bdev_name=args.bdev_name, 1106 lvs_name=args.lvs_name, 1107 cluster_sz=args.cluster_sz, 1108 clear_method=args.clear_method)) 1109 1110 p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev') 1111 p.add_argument('bdev_name', help='base bdev name') 1112 p.add_argument('lvs_name', help='name for lvol store') 1113 p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False) 1114 p.add_argument('--clear-method', help="""Change clear method for data region. 1115 Available: none, unmap, write_zeroes""", required=False) 1116 p.set_defaults(func=construct_lvol_store) 1117 1118 def rename_lvol_store(args): 1119 rpc.lvol.rename_lvol_store(args.client, 1120 old_name=args.old_name, 1121 new_name=args.new_name) 1122 1123 p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name') 1124 p.add_argument('old_name', help='old name') 1125 p.add_argument('new_name', help='new name') 1126 p.set_defaults(func=rename_lvol_store) 1127 1128 def construct_lvol_bdev(args): 1129 print_json(rpc.lvol.construct_lvol_bdev(args.client, 1130 lvol_name=args.lvol_name, 1131 size=args.size * 1024 * 1024, 1132 thin_provision=args.thin_provision, 1133 clear_method=args.clear_method, 1134 uuid=args.uuid, 1135 lvs_name=args.lvs_name)) 1136 1137 p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend') 1138 p.add_argument('-u', '--uuid', help='lvol store UUID', required=False) 1139 p.add_argument('-l', '--lvs-name', help='lvol store name', required=False) 1140 p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned') 1141 p.add_argument('-c', '--clear-method', help="""Change default data clusters clear method. 1142 Available: none, unmap, write_zeroes""", required=False) 1143 p.add_argument('lvol_name', help='name for this lvol') 1144 p.add_argument('size', help='size in MiB for this bdev', type=int) 1145 p.set_defaults(func=construct_lvol_bdev) 1146 1147 def snapshot_lvol_bdev(args): 1148 print_json(rpc.lvol.snapshot_lvol_bdev(args.client, 1149 lvol_name=args.lvol_name, 1150 snapshot_name=args.snapshot_name)) 1151 1152 p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev') 1153 p.add_argument('lvol_name', help='lvol bdev name') 1154 p.add_argument('snapshot_name', help='lvol snapshot name') 1155 p.set_defaults(func=snapshot_lvol_bdev) 1156 1157 def clone_lvol_bdev(args): 1158 print_json(rpc.lvol.clone_lvol_bdev(args.client, 1159 snapshot_name=args.snapshot_name, 1160 clone_name=args.clone_name)) 1161 1162 p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot') 1163 p.add_argument('snapshot_name', help='lvol snapshot name') 1164 p.add_argument('clone_name', help='lvol clone name') 1165 p.set_defaults(func=clone_lvol_bdev) 1166 1167 def rename_lvol_bdev(args): 1168 rpc.lvol.rename_lvol_bdev(args.client, 1169 old_name=args.old_name, 1170 new_name=args.new_name) 1171 1172 p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name') 1173 p.add_argument('old_name', help='lvol bdev name') 1174 p.add_argument('new_name', help='new lvol name') 1175 p.set_defaults(func=rename_lvol_bdev) 1176 1177 def inflate_lvol_bdev(args): 1178 rpc.lvol.inflate_lvol_bdev(args.client, 1179 name=args.name) 1180 1181 p = subparsers.add_parser('inflate_lvol_bdev', help='Make thin provisioned lvol a thick provisioned lvol') 1182 p.add_argument('name', help='lvol bdev name') 1183 p.set_defaults(func=inflate_lvol_bdev) 1184 1185 def decouple_parent_lvol_bdev(args): 1186 rpc.lvol.decouple_parent_lvol_bdev(args.client, 1187 name=args.name) 1188 1189 p = subparsers.add_parser('decouple_parent_lvol_bdev', help='Decouple parent of lvol') 1190 p.add_argument('name', help='lvol bdev name') 1191 p.set_defaults(func=decouple_parent_lvol_bdev) 1192 1193 def resize_lvol_bdev(args): 1194 rpc.lvol.resize_lvol_bdev(args.client, 1195 name=args.name, 1196 size=args.size * 1024 * 1024) 1197 1198 p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev') 1199 p.add_argument('name', help='lvol bdev name') 1200 p.add_argument('size', help='new size in MiB for this bdev', type=int) 1201 p.set_defaults(func=resize_lvol_bdev) 1202 1203 def set_read_only_lvol_bdev(args): 1204 rpc.lvol.set_read_only_lvol_bdev(args.client, 1205 name=args.name) 1206 1207 p = subparsers.add_parser('set_read_only_lvol_bdev', help='Mark lvol bdev as read only') 1208 p.add_argument('name', help='lvol bdev name') 1209 p.set_defaults(func=set_read_only_lvol_bdev) 1210 1211 def destroy_lvol_bdev(args): 1212 rpc.lvol.destroy_lvol_bdev(args.client, 1213 name=args.name) 1214 1215 p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume') 1216 p.add_argument('name', help='lvol bdev name') 1217 p.set_defaults(func=destroy_lvol_bdev) 1218 1219 def destroy_lvol_store(args): 1220 rpc.lvol.destroy_lvol_store(args.client, 1221 uuid=args.uuid, 1222 lvs_name=args.lvs_name) 1223 1224 p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store') 1225 p.add_argument('-u', '--uuid', help='lvol store UUID', required=False) 1226 p.add_argument('-l', '--lvs-name', help='lvol store name', required=False) 1227 p.set_defaults(func=destroy_lvol_store) 1228 1229 def get_lvol_stores(args): 1230 print_dict(rpc.lvol.get_lvol_stores(args.client, 1231 uuid=args.uuid, 1232 lvs_name=args.lvs_name)) 1233 1234 p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list') 1235 p.add_argument('-u', '--uuid', help='lvol store UUID', required=False) 1236 p.add_argument('-l', '--lvs-name', help='lvol store name', required=False) 1237 p.set_defaults(func=get_lvol_stores) 1238 1239 def get_raid_bdevs(args): 1240 print_array(rpc.bdev.get_raid_bdevs(args.client, 1241 category=args.category)) 1242 1243 p = subparsers.add_parser('get_raid_bdevs', help="""This is used to list all the raid bdev names based on the input category 1244 requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether 1245 they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring' 1246 is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered 1247 with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""") 1248 p.add_argument('category', help='all or online or configuring or offline') 1249 p.set_defaults(func=get_raid_bdevs) 1250 1251 def construct_raid_bdev(args): 1252 base_bdevs = [] 1253 for u in args.base_bdevs.strip().split(" "): 1254 base_bdevs.append(u) 1255 1256 rpc.bdev.construct_raid_bdev(args.client, 1257 name=args.name, 1258 strip_size=args.strip_size, 1259 strip_size_kb=args.strip_size_kb, 1260 raid_level=args.raid_level, 1261 base_bdevs=base_bdevs) 1262 p = subparsers.add_parser('construct_raid_bdev', help='Construct new raid bdev') 1263 p.add_argument('-n', '--name', help='raid bdev name', required=True) 1264 p.add_argument('-s', '--strip-size', help='strip size in KB (deprecated)', type=int) 1265 p.add_argument('-z', '--strip-size_kb', help='strip size in KB', type=int) 1266 p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', type=int, required=True) 1267 p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True) 1268 p.set_defaults(func=construct_raid_bdev) 1269 1270 def destroy_raid_bdev(args): 1271 rpc.bdev.destroy_raid_bdev(args.client, 1272 name=args.name) 1273 p = subparsers.add_parser('destroy_raid_bdev', help='Destroy existing raid bdev') 1274 p.add_argument('name', help='raid bdev name') 1275 p.set_defaults(func=destroy_raid_bdev) 1276 1277 # split 1278 def construct_split_vbdev(args): 1279 print_array(rpc.bdev.construct_split_vbdev(args.client, 1280 base_bdev=args.base_bdev, 1281 split_count=args.split_count, 1282 split_size_mb=args.split_size_mb)) 1283 1284 p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name 1285 name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became 1286 available (during examination process).""") 1287 p.add_argument('base_bdev', help='base bdev name') 1288 p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0) 1289 p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not 1290 exceed the base bdev size.""", type=int) 1291 p.set_defaults(func=construct_split_vbdev) 1292 1293 def destruct_split_vbdev(args): 1294 rpc.bdev.destruct_split_vbdev(args.client, 1295 base_bdev=args.base_bdev) 1296 1297 p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""") 1298 p.add_argument('base_bdev', help='base bdev name') 1299 p.set_defaults(func=destruct_split_vbdev) 1300 1301 # ftl 1302 ftl_valid_limits = ('crit', 'high', 'low', 'start') 1303 1304 def construct_ftl_bdev(args): 1305 def parse_limits(limits, arg_dict, key_suffix=''): 1306 for limit in limits.split(','): 1307 key, value = limit.split(':', 1) 1308 if key in ftl_valid_limits: 1309 arg_dict['limit_' + key + key_suffix] = int(value) 1310 else: 1311 raise ValueError('Limit {} is not supported'.format(key)) 1312 1313 arg_limits = {} 1314 if args.limit_threshold: 1315 parse_limits(args.limit_threshold, arg_limits, '_threshold') 1316 1317 if args.limit: 1318 parse_limits(args.limit, arg_limits) 1319 1320 print_dict(rpc.bdev.construct_ftl_bdev(args.client, 1321 name=args.name, 1322 trtype=args.trtype, 1323 traddr=args.traddr, 1324 punits=args.punits, 1325 uuid=args.uuid, 1326 cache=args.cache, 1327 allow_open_bands=args.allow_open_bands, 1328 overprovisioning=args.overprovisioning, 1329 **arg_limits)) 1330 1331 p = subparsers.add_parser('construct_ftl_bdev', 1332 help='Add FTL bdev') 1333 p.add_argument('-b', '--name', help="Name of the bdev", required=True) 1334 p.add_argument('-t', '--trtype', 1335 help='NVMe target trtype: e.g., pcie', default='pcie') 1336 p.add_argument('-a', '--traddr', 1337 help='NVMe target address: e.g., an ip address or BDF', required=True) 1338 p.add_argument('-l', '--punits', help='Parallel unit range in the form of start-end: e.g. 4-8', 1339 required=True) 1340 p.add_argument('-u', '--uuid', help='UUID of restored bdev (not applicable when creating new ' 1341 'instance): e.g. b286d19a-0059-4709-abcd-9f7732b1567d (optional)') 1342 p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache (optional)') 1343 p.add_argument('-o', '--allow_open_bands', help='Restoring after dirty shutdown without cache will' 1344 ' result in partial data recovery, instead of error', action='store_true') 1345 p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed' 1346 ' to user (optional)', type=int) 1347 1348 limits = p.add_argument_group('Defrag limits', 'Configures defrag limits and thresholds for' 1349 ' levels ' + str(ftl_valid_limits)[1:-1]) 1350 limits.add_argument('--limit', help='Percentage of allowed user versus internal writes at given' 1351 ' levels, e.g. crit:0,high:20,low:80') 1352 limits.add_argument('--limit-threshold', help='Number of free bands triggering a given level of' 1353 ' write limiting e.g. crit:1,high:2,low:3,start:4') 1354 p.set_defaults(func=construct_ftl_bdev) 1355 1356 def delete_ftl_bdev(args): 1357 print_dict(rpc.bdev.delete_ftl_bdev(args.client, name=args.name)) 1358 1359 p = subparsers.add_parser('delete_ftl_bdev', help='Delete FTL bdev') 1360 p.add_argument('-b', '--name', help="Name of the bdev", required=True) 1361 p.set_defaults(func=delete_ftl_bdev) 1362 1363 # vmd 1364 def enable_vmd(args): 1365 print_dict(rpc.vmd.enable_vmd(args.client)) 1366 1367 p = subparsers.add_parser('enable_vmd', help='Enable VMD enumeration') 1368 p.set_defaults(func=enable_vmd) 1369 1370 # nbd 1371 def start_nbd_disk(args): 1372 print(rpc.nbd.start_nbd_disk(args.client, 1373 bdev_name=args.bdev_name, 1374 nbd_device=args.nbd_device)) 1375 1376 p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk') 1377 p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.') 1378 p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.', nargs='?') 1379 p.set_defaults(func=start_nbd_disk) 1380 1381 def stop_nbd_disk(args): 1382 rpc.nbd.stop_nbd_disk(args.client, 1383 nbd_device=args.nbd_device) 1384 1385 p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk') 1386 p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.') 1387 p.set_defaults(func=stop_nbd_disk) 1388 1389 def get_nbd_disks(args): 1390 print_dict(rpc.nbd.get_nbd_disks(args.client, 1391 nbd_device=args.nbd_device)) 1392 1393 p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list') 1394 p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False) 1395 p.set_defaults(func=get_nbd_disks) 1396 1397 # net 1398 def add_ip_address(args): 1399 rpc.net.add_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr) 1400 1401 p = subparsers.add_parser('add_ip_address', help='Add IP address') 1402 p.add_argument('ifc_index', help='ifc index of the nic device.', type=int) 1403 p.add_argument('ip_addr', help='ip address will be added.') 1404 p.set_defaults(func=add_ip_address) 1405 1406 def delete_ip_address(args): 1407 rpc.net.delete_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr) 1408 1409 p = subparsers.add_parser('delete_ip_address', help='Delete IP address') 1410 p.add_argument('ifc_index', help='ifc index of the nic device.', type=int) 1411 p.add_argument('ip_addr', help='ip address will be deleted.') 1412 p.set_defaults(func=delete_ip_address) 1413 1414 def get_interfaces(args): 1415 print_dict(rpc.net.get_interfaces(args.client)) 1416 1417 p = subparsers.add_parser( 1418 'get_interfaces', help='Display current interface list') 1419 p.set_defaults(func=get_interfaces) 1420 1421 # NVMe-oF 1422 def set_nvmf_target_max_subsystems(args): 1423 rpc.nvmf.set_nvmf_target_max_subsystems(args.client, 1424 max_subsystems=args.max_subsystems) 1425 1426 p = subparsers.add_parser('set_nvmf_target_max_subsystems', help='Set the maximum number of NVMf target subsystems') 1427 p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True) 1428 p.set_defaults(func=set_nvmf_target_max_subsystems) 1429 1430 def set_nvmf_target_config(args): 1431 rpc.nvmf.set_nvmf_target_config(args.client, 1432 acceptor_poll_rate=args.acceptor_poll_rate, 1433 conn_sched=args.conn_sched) 1434 1435 p = subparsers.add_parser('set_nvmf_target_config', help='Set NVMf target config') 1436 p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int) 1437 p.add_argument('-s', '--conn-sched', help="""'roundrobin' - Schedule the incoming connections from any host 1438 on the cores in a round robin manner (Default). 'hostip' - Schedule all the incoming connections from a 1439 specific host IP on to the same core. Connections from different IP will be assigned to cores in a round 1440 robin manner. 'transport' - Schedule the connection according to the transport characteristics.""") 1441 p.set_defaults(func=set_nvmf_target_config) 1442 1443 def nvmf_create_transport(args): 1444 rpc.nvmf.nvmf_create_transport(args.client, 1445 trtype=args.trtype, 1446 max_queue_depth=args.max_queue_depth, 1447 max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr, 1448 in_capsule_data_size=args.in_capsule_data_size, 1449 max_io_size=args.max_io_size, 1450 io_unit_size=args.io_unit_size, 1451 max_aq_depth=args.max_aq_depth, 1452 num_shared_buffers=args.num_shared_buffers, 1453 buf_cache_size=args.buf_cache_size, 1454 max_srq_depth=args.max_srq_depth, 1455 no_srq=args.no_srq, 1456 c2h_success=args.c2h_success, 1457 dif_insert_or_strip=args.dif_insert_or_strip, 1458 sock_priority=args.sock_priority) 1459 1460 p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport') 1461 p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True) 1462 p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int) 1463 p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int) 1464 p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int) 1465 p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int) 1466 p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int) 1467 p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int) 1468 p.add_argument('-n', '--num-shared-buffers', help='The number of pooled data buffers available to the transport', type=int) 1469 p.add_argument('-b', '--buf-cache-size', help='The number of shared buffers to reserve for each poll group', type=int) 1470 p.add_argument('-s', '--max-srq-depth', help='Max number of outstanding I/O per SRQ. Relevant only for RDMA transport', type=int) 1471 p.add_argument('-r', '--no-srq', action='store_true', help='Disable per-thread shared receive queue. Relevant only for RDMA transport') 1472 p.add_argument('-o', '--c2h-success', action='store_false', help='Disable C2H success optimization. Relevant only for TCP transport') 1473 p.add_argument('-f', '--dif-insert-or-strip', action='store_true', help='Enable DIF insert/strip. Relevant only for TCP transport') 1474 p.add_argument('-y', '--sock-priority', help='The sock priority of the tcp connection. Relevant only for TCP transport', type=int) 1475 p.set_defaults(func=nvmf_create_transport) 1476 1477 def get_nvmf_transports(args): 1478 print_dict(rpc.nvmf.get_nvmf_transports(args.client)) 1479 1480 p = subparsers.add_parser('get_nvmf_transports', 1481 help='Display nvmf transports') 1482 p.set_defaults(func=get_nvmf_transports) 1483 1484 def get_nvmf_subsystems(args): 1485 print_dict(rpc.nvmf.get_nvmf_subsystems(args.client)) 1486 1487 p = subparsers.add_parser('get_nvmf_subsystems', 1488 help='Display nvmf subsystems') 1489 p.set_defaults(func=get_nvmf_subsystems) 1490 1491 def nvmf_subsystem_create(args): 1492 rpc.nvmf.nvmf_subsystem_create(args.client, 1493 nqn=args.nqn, 1494 serial_number=args.serial_number, 1495 model_number=args.model_number, 1496 allow_any_host=args.allow_any_host, 1497 max_namespaces=args.max_namespaces) 1498 1499 p = subparsers.add_parser('nvmf_subsystem_create', help='Create an NVMe-oF subsystem') 1500 p.add_argument('nqn', help='Subsystem NQN (ASCII)') 1501 p.add_argument("-s", "--serial-number", help=""" 1502 Format: 'sn' etc 1503 Example: 'SPDK00000000000001'""", default='00000000000000000000') 1504 p.add_argument("-d", "--model-number", help=""" 1505 Format: 'mn' etc 1506 Example: 'SPDK Controller'""", default='SPDK bdev Controller') 1507 p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)") 1508 p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed", 1509 type=int, default=0) 1510 p.set_defaults(func=nvmf_subsystem_create) 1511 1512 def delete_nvmf_subsystem(args): 1513 rpc.nvmf.delete_nvmf_subsystem(args.client, 1514 nqn=args.subsystem_nqn) 1515 1516 p = subparsers.add_parser('delete_nvmf_subsystem', 1517 help='Delete a nvmf subsystem') 1518 p.add_argument('subsystem_nqn', 1519 help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.') 1520 p.set_defaults(func=delete_nvmf_subsystem) 1521 1522 def nvmf_subsystem_add_listener(args): 1523 rpc.nvmf.nvmf_subsystem_add_listener(args.client, 1524 nqn=args.nqn, 1525 trtype=args.trtype, 1526 traddr=args.traddr, 1527 adrfam=args.adrfam, 1528 trsvcid=args.trsvcid) 1529 1530 p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem') 1531 p.add_argument('nqn', help='NVMe-oF subsystem NQN') 1532 p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True) 1533 p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True) 1534 p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host') 1535 p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number') 1536 p.set_defaults(func=nvmf_subsystem_add_listener) 1537 1538 def nvmf_subsystem_remove_listener(args): 1539 rpc.nvmf.nvmf_subsystem_remove_listener(args.client, 1540 nqn=args.nqn, 1541 trtype=args.trtype, 1542 traddr=args.traddr, 1543 adrfam=args.adrfam, 1544 trsvcid=args.trsvcid) 1545 1546 p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem') 1547 p.add_argument('nqn', help='NVMe-oF subsystem NQN') 1548 p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True) 1549 p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True) 1550 p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host') 1551 p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number') 1552 p.set_defaults(func=nvmf_subsystem_remove_listener) 1553 1554 def nvmf_subsystem_add_ns(args): 1555 rpc.nvmf.nvmf_subsystem_add_ns(args.client, 1556 nqn=args.nqn, 1557 bdev_name=args.bdev_name, 1558 ptpl_file=args.ptpl_file, 1559 nsid=args.nsid, 1560 nguid=args.nguid, 1561 eui64=args.eui64, 1562 uuid=args.uuid) 1563 1564 p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem') 1565 p.add_argument('nqn', help='NVMe-oF subsystem NQN') 1566 p.add_argument('bdev_name', help='The name of the bdev that will back this namespace') 1567 p.add_argument('-p', '--ptpl-file', help='The persistent reservation storage location (optional)', type=str) 1568 p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int) 1569 p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)') 1570 p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)') 1571 p.add_argument('-u', '--uuid', help='Namespace UUID (optional)') 1572 p.set_defaults(func=nvmf_subsystem_add_ns) 1573 1574 def nvmf_subsystem_remove_ns(args): 1575 rpc.nvmf.nvmf_subsystem_remove_ns(args.client, 1576 nqn=args.nqn, 1577 nsid=args.nsid) 1578 1579 p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem') 1580 p.add_argument('nqn', help='NVMe-oF subsystem NQN') 1581 p.add_argument('nsid', help='The requested NSID', type=int) 1582 p.set_defaults(func=nvmf_subsystem_remove_ns) 1583 1584 def nvmf_subsystem_add_host(args): 1585 rpc.nvmf.nvmf_subsystem_add_host(args.client, 1586 nqn=args.nqn, 1587 host=args.host) 1588 1589 p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem') 1590 p.add_argument('nqn', help='NVMe-oF subsystem NQN') 1591 p.add_argument('host', help='Host NQN to allow') 1592 p.set_defaults(func=nvmf_subsystem_add_host) 1593 1594 def nvmf_subsystem_remove_host(args): 1595 rpc.nvmf.nvmf_subsystem_remove_host(args.client, 1596 nqn=args.nqn, 1597 host=args.host) 1598 1599 p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem') 1600 p.add_argument('nqn', help='NVMe-oF subsystem NQN') 1601 p.add_argument('host', help='Host NQN to remove') 1602 p.set_defaults(func=nvmf_subsystem_remove_host) 1603 1604 def nvmf_subsystem_allow_any_host(args): 1605 rpc.nvmf.nvmf_subsystem_allow_any_host(args.client, 1606 nqn=args.nqn, 1607 disable=args.disable) 1608 1609 p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem') 1610 p.add_argument('nqn', help='NVMe-oF subsystem NQN') 1611 p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host') 1612 p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host') 1613 p.set_defaults(func=nvmf_subsystem_allow_any_host) 1614 1615 def nvmf_get_stats(args): 1616 print_dict(rpc.nvmf.nvmf_get_stats(args.client)) 1617 1618 p = subparsers.add_parser( 1619 'nvmf_get_stats', help='Display current statistics for NVMf subsystem') 1620 p.set_defaults(func=nvmf_get_stats) 1621 1622 # pmem 1623 def create_pmem_pool(args): 1624 num_blocks = int((args.total_size * 1024 * 1024) / args.block_size) 1625 rpc.pmem.create_pmem_pool(args.client, 1626 pmem_file=args.pmem_file, 1627 num_blocks=num_blocks, 1628 block_size=args.block_size) 1629 1630 p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool') 1631 p.add_argument('pmem_file', help='Path to pmemblk pool file') 1632 p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int) 1633 p.add_argument('block_size', help='Block size for this pmem pool', type=int) 1634 p.set_defaults(func=create_pmem_pool) 1635 1636 def pmem_pool_info(args): 1637 print_dict(rpc.pmem.pmem_pool_info(args.client, 1638 pmem_file=args.pmem_file)) 1639 1640 p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency') 1641 p.add_argument('pmem_file', help='Path to pmemblk pool file') 1642 p.set_defaults(func=pmem_pool_info) 1643 1644 def delete_pmem_pool(args): 1645 rpc.pmem.delete_pmem_pool(args.client, 1646 pmem_file=args.pmem_file) 1647 1648 p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool') 1649 p.add_argument('pmem_file', help='Path to pmemblk pool file') 1650 p.set_defaults(func=delete_pmem_pool) 1651 1652 # subsystem 1653 def get_subsystems(args): 1654 print_dict(rpc.subsystem.get_subsystems(args.client)) 1655 1656 p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem 1657 entry contain (unsorted) array of subsystems it depends on.""") 1658 p.set_defaults(func=get_subsystems) 1659 1660 def get_subsystem_config(args): 1661 print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name)) 1662 1663 p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""") 1664 p.add_argument('name', help='Name of subsystem to query') 1665 p.set_defaults(func=get_subsystem_config) 1666 1667 # vhost 1668 def set_vhost_controller_coalescing(args): 1669 rpc.vhost.set_vhost_controller_coalescing(args.client, 1670 ctrlr=args.ctrlr, 1671 delay_base_us=args.delay_base_us, 1672 iops_threshold=args.iops_threshold) 1673 1674 p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing') 1675 p.add_argument('ctrlr', help='controller name') 1676 p.add_argument('delay_base_us', help='Base delay time', type=int) 1677 p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int) 1678 p.set_defaults(func=set_vhost_controller_coalescing) 1679 1680 def construct_vhost_scsi_controller(args): 1681 rpc.vhost.construct_vhost_scsi_controller(args.client, 1682 ctrlr=args.ctrlr, 1683 cpumask=args.cpumask) 1684 1685 p = subparsers.add_parser( 1686 'construct_vhost_scsi_controller', help='Add new vhost controller') 1687 p.add_argument('ctrlr', help='controller name') 1688 p.add_argument('--cpumask', help='cpu mask for this controller') 1689 p.set_defaults(func=construct_vhost_scsi_controller) 1690 1691 def add_vhost_scsi_lun(args): 1692 print_json(rpc.vhost.add_vhost_scsi_lun(args.client, 1693 ctrlr=args.ctrlr, 1694 scsi_target_num=args.scsi_target_num, 1695 bdev_name=args.bdev_name)) 1696 1697 p = subparsers.add_parser('add_vhost_scsi_lun', 1698 help='Add lun to vhost controller') 1699 p.add_argument('ctrlr', help='conntroller name where add lun') 1700 p.add_argument('scsi_target_num', help='scsi_target_num', type=int) 1701 p.add_argument('bdev_name', help='bdev name') 1702 p.set_defaults(func=add_vhost_scsi_lun) 1703 1704 def remove_vhost_scsi_target(args): 1705 rpc.vhost.remove_vhost_scsi_target(args.client, 1706 ctrlr=args.ctrlr, 1707 scsi_target_num=args.scsi_target_num) 1708 1709 p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller') 1710 p.add_argument('ctrlr', help='controller name to remove target from') 1711 p.add_argument('scsi_target_num', help='scsi_target_num', type=int) 1712 p.set_defaults(func=remove_vhost_scsi_target) 1713 1714 def construct_vhost_blk_controller(args): 1715 rpc.vhost.construct_vhost_blk_controller(args.client, 1716 ctrlr=args.ctrlr, 1717 dev_name=args.dev_name, 1718 cpumask=args.cpumask, 1719 readonly=args.readonly) 1720 1721 p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller') 1722 p.add_argument('ctrlr', help='controller name') 1723 p.add_argument('dev_name', help='device name') 1724 p.add_argument('--cpumask', help='cpu mask for this controller') 1725 p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only') 1726 p.set_defaults(func=construct_vhost_blk_controller) 1727 1728 def construct_vhost_nvme_controller(args): 1729 rpc.vhost.construct_vhost_nvme_controller(args.client, 1730 ctrlr=args.ctrlr, 1731 io_queues=args.io_queues, 1732 cpumask=args.cpumask) 1733 1734 p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller') 1735 p.add_argument('ctrlr', help='controller name') 1736 p.add_argument('io_queues', help='number of IO queues for the controller', type=int) 1737 p.add_argument('--cpumask', help='cpu mask for this controller') 1738 p.set_defaults(func=construct_vhost_nvme_controller) 1739 1740 def add_vhost_nvme_ns(args): 1741 rpc.vhost.add_vhost_nvme_ns(args.client, 1742 ctrlr=args.ctrlr, 1743 bdev_name=args.bdev_name) 1744 1745 p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller') 1746 p.add_argument('ctrlr', help='conntroller name where add a Namespace') 1747 p.add_argument('bdev_name', help='block device name for a new Namespace') 1748 p.set_defaults(func=add_vhost_nvme_ns) 1749 1750 def get_vhost_controllers(args): 1751 print_dict(rpc.vhost.get_vhost_controllers(args.client, args.name)) 1752 1753 p = subparsers.add_parser('get_vhost_controllers', help='List all or specific vhost controller(s)') 1754 p.add_argument('-n', '--name', help="Name of vhost controller", required=False) 1755 p.set_defaults(func=get_vhost_controllers) 1756 1757 def remove_vhost_controller(args): 1758 rpc.vhost.remove_vhost_controller(args.client, 1759 ctrlr=args.ctrlr) 1760 1761 p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller') 1762 p.add_argument('ctrlr', help='controller name') 1763 p.set_defaults(func=remove_vhost_controller) 1764 1765 def construct_virtio_dev(args): 1766 print_array(rpc.vhost.construct_virtio_dev(args.client, 1767 name=args.name, 1768 trtype=args.trtype, 1769 traddr=args.traddr, 1770 dev_type=args.dev_type, 1771 vq_count=args.vq_count, 1772 vq_size=args.vq_size)) 1773 1774 p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided 1775 transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by 1776 remote side. Result is array of added bdevs.""") 1777 p.add_argument('name', help="Use this name as base for new created bdevs") 1778 p.add_argument('-t', '--trtype', 1779 help='Virtio target transport type: pci or user', required=True) 1780 p.add_argument('-a', '--traddr', 1781 help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True) 1782 p.add_argument('-d', '--dev-type', 1783 help='Device type: blk or scsi', required=True) 1784 p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int) 1785 p.add_argument('--vq-size', help='Size of each queue', type=int) 1786 p.set_defaults(func=construct_virtio_dev) 1787 1788 def get_virtio_scsi_devs(args): 1789 print_dict(rpc.vhost.get_virtio_scsi_devs(args.client)) 1790 1791 p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.') 1792 p.set_defaults(func=get_virtio_scsi_devs) 1793 1794 def remove_virtio_bdev(args): 1795 rpc.vhost.remove_virtio_bdev(args.client, 1796 name=args.name) 1797 1798 p = subparsers.add_parser('remove_virtio_bdev', help="""Remove a Virtio device 1799 This will delete all bdevs exposed by this device""") 1800 p.add_argument('name', help='Virtio device name. E.g. VirtioUser0') 1801 p.set_defaults(func=remove_virtio_bdev) 1802 1803 # ioat 1804 def scan_ioat_copy_engine(args): 1805 pci_whitelist = [] 1806 if args.pci_whitelist: 1807 for w in args.pci_whitelist.strip().split(" "): 1808 pci_whitelist.append(w) 1809 rpc.ioat.scan_ioat_copy_engine(args.client, pci_whitelist) 1810 1811 p = subparsers.add_parser('scan_ioat_copy_engine', help='Set scan and enable IOAT copy engine offload.') 1812 p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in 1813 domain:bus:device.function format or domain.bus.device.function format""") 1814 p.set_defaults(func=scan_ioat_copy_engine) 1815 1816 # send_nvme_cmd 1817 def send_nvme_cmd(args): 1818 print_dict(rpc.nvme.send_nvme_cmd(args.client, 1819 name=args.nvme_name, 1820 cmd_type=args.cmd_type, 1821 data_direction=args.data_direction, 1822 cmdbuf=args.cmdbuf, 1823 data=args.data, 1824 metadata=args.metadata, 1825 data_len=args.data_length, 1826 metadata_len=args.metadata_length, 1827 timeout_ms=args.timeout_ms)) 1828 1829 p = subparsers.add_parser('send_nvme_cmd', help='NVMe passthrough cmd.') 1830 p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""") 1831 p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""") 1832 p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""") 1833 p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""") 1834 p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""") 1835 p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""") 1836 p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int) 1837 p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int) 1838 p.add_argument('-T', '--timeout-ms', 1839 help="""Command execution timeout value, in milliseconds, if 0, don't track timeout""", type=int, default=0) 1840 p.set_defaults(func=send_nvme_cmd) 1841 1842 # Notifications 1843 def get_notification_types(args): 1844 print_dict(rpc.notify.get_notification_types(args.client)) 1845 1846 p = subparsers.add_parser('get_notification_types', help='List available notifications that user can subscribe to.') 1847 p.set_defaults(func=get_notification_types) 1848 1849 def get_notifications(args): 1850 ret = rpc.notify.get_notifications(args.client, 1851 id=args.id, 1852 max=args.max) 1853 print_dict(ret) 1854 1855 p = subparsers.add_parser('get_notifications', help='Get notifications') 1856 p.add_argument('-i', '--id', help="""First ID to start fetching from""", type=int) 1857 p.add_argument('-n', '--max', help="""Maximum number of notifications to return in response""", type=int) 1858 p.set_defaults(func=get_notifications) 1859 1860 def thread_get_stats(args): 1861 print_dict(rpc.app.thread_get_stats(args.client)) 1862 1863 p = subparsers.add_parser( 1864 'thread_get_stats', help='Display current statistics of all the threads') 1865 p.set_defaults(func=thread_get_stats) 1866 1867 def check_called_name(name): 1868 if name in deprecated_aliases: 1869 print("{} is deprecated, use {} instead.".format(name, deprecated_aliases[name]), file=sys.stderr) 1870 1871 class dry_run_client: 1872 def call(self, method, params=None): 1873 print("Request:\n" + json.dumps({"method": method, "params": params}, indent=2)) 1874 1875 def null_print(arg): 1876 pass 1877 1878 def call_rpc_func(args): 1879 args.func(args) 1880 check_called_name(args.called_rpc_name) 1881 1882 def execute_script(parser, client, fd): 1883 executed_rpc = "" 1884 for rpc_call in map(str.rstrip, fd): 1885 if not rpc_call.strip(): 1886 continue 1887 executed_rpc = "\n".join([executed_rpc, rpc_call]) 1888 args = parser.parse_args(shlex.split(rpc_call)) 1889 args.client = client 1890 try: 1891 call_rpc_func(args) 1892 except JSONRPCException as ex: 1893 print("Exception:") 1894 print(executed_rpc.strip() + " <<<") 1895 print(ex.message) 1896 exit(1) 1897 1898 args = parser.parse_args() 1899 if args.dry_run: 1900 args.client = dry_run_client() 1901 print_dict = null_print 1902 print_json = null_print 1903 print_array = null_print 1904 else: 1905 args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.timeout, log_level=getattr(logging, args.verbose.upper())) 1906 if hasattr(args, 'func'): 1907 try: 1908 call_rpc_func(args) 1909 except JSONRPCException as ex: 1910 print(ex) 1911 exit(1) 1912 elif sys.stdin.isatty(): 1913 # No arguments and no data piped through stdin 1914 parser.print_help() 1915 exit(1) 1916 else: 1917 execute_script(parser, args.client, sys.stdin) 1918