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