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