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