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