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