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