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