xref: /spdk/scripts/rpc.py (revision 73bc324b0df56dc389f7030d52d3ed920b1f66b9)
1#!/usr/bin/env python3
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2016 Intel Corporation
4#  All rights reserved.
5#  Copyright (c) 2022 Dell Inc, or its subsidiaries.
6#  Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
7#
8
9import logging
10import argparse
11import importlib
12import os
13import sys
14import shlex
15import json
16
17try:
18    from shlex import quote
19except ImportError:
20    from pipes import quote
21
22sys.path.append(os.path.dirname(__file__) + '/../python')
23
24import spdk.rpc as rpc  # noqa
25from spdk.rpc.client import print_dict, print_json, JSONRPCException  # noqa
26from spdk.rpc.helpers import deprecated_aliases  # noqa
27
28
29def print_array(a):
30    print(" ".join((quote(v) for v in a)))
31
32
33if __name__ == "__main__":
34    parser = argparse.ArgumentParser(
35        description='SPDK RPC command line interface', usage='%(prog)s [options]')
36    parser.add_argument('-s', dest='server_addr',
37                        help='RPC domain socket path or IP address', default='/var/tmp/spdk.sock')
38    parser.add_argument('-p', dest='port',
39                        help='RPC port number (if server_addr is IP address)',
40                        default=5260, type=int)
41    parser.add_argument('-t', dest='timeout',
42                        help='Timeout as a floating point number expressed in seconds waiting for response. Default: 60.0',
43                        default=60.0, type=float)
44    parser.add_argument('-r', dest='conn_retries',
45                        help='Retry connecting to the RPC server N times with 0.2s interval. Default: 0',
46                        default=0, type=int)
47    parser.add_argument('-v', dest='verbose', action='store_const', const="INFO",
48                        help='Set verbose mode to INFO', default="ERROR")
49    parser.add_argument('--verbose', dest='verbose', choices=['DEBUG', 'INFO', 'ERROR'],
50                        help="""Set verbose level. """)
51    parser.add_argument('--dry-run', dest='dry_run', action='store_true', help="Display request and exit")
52    parser.set_defaults(dry_run=False)
53    parser.add_argument('--go-client', dest='go_client', action='store_true', help="Use Go client")
54    parser.set_defaults(go_client=False)
55    parser.add_argument('--server', dest='is_server', action='store_true',
56                        help="Start listening on stdin, parse each line as a regular rpc.py execution and create \
57                                a separate connection for each command. Each command's output ends with either \
58                                **STATUS=0 if the command succeeded or **STATUS=1 if it failed. --server is meant \
59                                to be used in conjunction with bash coproc, where stdin and stdout are connected to \
60                                pipes and can be used as a faster way to send RPC commands. If enabled, rpc.py \
61                                must be executed without any other parameters.")
62    parser.set_defaults(is_server=False)
63    parser.add_argument('--plugin', dest='rpc_plugin', help='Module name of plugin with additional RPC commands')
64    subparsers = parser.add_subparsers(help='RPC methods', dest='called_rpc_name', metavar='')
65
66    def framework_start_init(args):
67        rpc.framework_start_init(args.client)
68
69    p = subparsers.add_parser('framework_start_init', help='Start initialization of subsystems')
70    p.set_defaults(func=framework_start_init)
71
72    def framework_wait_init(args):
73        rpc.framework_wait_init(args.client)
74
75    p = subparsers.add_parser('framework_wait_init', help='Block until subsystems have been initialized')
76    p.set_defaults(func=framework_wait_init)
77
78    def rpc_get_methods(args):
79        print_dict(rpc.rpc_get_methods(args.client,
80                                       current=args.current,
81                                       include_aliases=args.include_aliases))
82
83    p = subparsers.add_parser('rpc_get_methods', help='Get list of supported RPC methods')
84    p.add_argument('-c', '--current', help='Get list of RPC methods only callable in the current state.', action='store_true')
85    p.add_argument('-i', '--include-aliases', help='include RPC aliases', action='store_true')
86    p.set_defaults(func=rpc_get_methods)
87
88    def spdk_get_version(args):
89        print_json(rpc.spdk_get_version(args.client))
90
91    p = subparsers.add_parser('spdk_get_version', help='Get SPDK version')
92    p.set_defaults(func=spdk_get_version)
93
94    def save_config(args):
95        rpc.save_config(args.client,
96                        sys.stdout,
97                        indent=args.indent)
98
99    p = subparsers.add_parser('save_config', help="""Write current (live) configuration of SPDK subsystems and targets to stdout.
100    """)
101    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
102    """, type=int, default=2)
103    p.set_defaults(func=save_config)
104
105    def load_config(args):
106        rpc.load_config(args.client, args.json_conf,
107                        include_aliases=args.include_aliases)
108
109    p = subparsers.add_parser('load_config', help="""Configure SPDK subsystems and targets using JSON RPC.""")
110    p.add_argument('-i', '--include-aliases', help='include RPC aliases', action='store_true')
111    p.add_argument('-j', '--json-conf', help='Valid JSON configuration', default=sys.stdin)
112    p.set_defaults(func=load_config)
113
114    def save_subsystem_config(args):
115        rpc.save_subsystem_config(args.client,
116                                  sys.stdout,
117                                  indent=args.indent,
118                                  name=args.name)
119
120    p = subparsers.add_parser('save_subsystem_config', help="""Write current (live) configuration of SPDK subsystem to stdout.
121    """)
122    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
123    """, type=int, default=2)
124    p.add_argument('-n', '--name', help='Name of subsystem', required=True)
125    p.set_defaults(func=save_subsystem_config)
126
127    def load_subsystem_config(args):
128        rpc.load_subsystem_config(args.client,
129                                  args.json_conf)
130
131    p = subparsers.add_parser('load_subsystem_config', help="""Configure SPDK subsystem using JSON RPC.""")
132    p.add_argument('-j', '--json-conf', help='Valid JSON configuration', default=sys.stdin)
133    p.set_defaults(func=load_subsystem_config)
134
135    # app
136    def spdk_kill_instance(args):
137        rpc.app.spdk_kill_instance(args.client,
138                                   sig_name=args.sig_name)
139
140    p = subparsers.add_parser('spdk_kill_instance', help='Send signal to instance')
141    p.add_argument('sig_name', help='signal will be sent to server.')
142    p.set_defaults(func=spdk_kill_instance)
143
144    def framework_monitor_context_switch(args):
145        enabled = None
146        if args.enable:
147            enabled = True
148        if args.disable:
149            enabled = False
150        print_dict(rpc.app.framework_monitor_context_switch(args.client,
151                                                            enabled=enabled))
152
153    p = subparsers.add_parser('framework_monitor_context_switch',
154                              help='Control whether the context switch monitor is enabled')
155    p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring')
156    p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring')
157    p.set_defaults(func=framework_monitor_context_switch)
158
159    def framework_get_reactors(args):
160        print_dict(rpc.app.framework_get_reactors(args.client))
161
162    p = subparsers.add_parser(
163        'framework_get_reactors', help='Display list of all reactors')
164    p.set_defaults(func=framework_get_reactors)
165
166    def framework_set_scheduler(args):
167        rpc.app.framework_set_scheduler(args.client,
168                                        name=args.name,
169                                        period=args.period,
170                                        load_limit=args.load_limit,
171                                        core_limit=args.core_limit,
172                                        core_busy=args.core_busy)
173
174    p = subparsers.add_parser(
175        'framework_set_scheduler', help='Select thread scheduler that will be activated and its period (experimental)')
176    p.add_argument('name', help="Name of a scheduler")
177    p.add_argument('-p', '--period', help="Scheduler period in microseconds", type=int)
178    p.add_argument('--load-limit', help="Scheduler load limit. Reserved for dynamic scheduler", type=int, required=False)
179    p.add_argument('--core-limit', help="Scheduler core limit. Reserved for dynamic scheduler", type=int, required=False)
180    p.add_argument('--core-busy', help="Scheduler core busy limit. Reserved for dynamic schedler", type=int, required=False)
181    p.set_defaults(func=framework_set_scheduler)
182
183    def framework_get_scheduler(args):
184        print_dict(rpc.app.framework_get_scheduler(args.client))
185
186    p = subparsers.add_parser(
187        'framework_get_scheduler', help='Display currently set scheduler and its properties.')
188    p.set_defaults(func=framework_get_scheduler)
189
190    def framework_disable_cpumask_locks(args):
191        rpc.framework_disable_cpumask_locks(args.client)
192
193    p = subparsers.add_parser('framework_disable_cpumask_locks',
194                              help='Disable CPU core lock files.')
195    p.set_defaults(func=framework_disable_cpumask_locks)
196
197    def framework_enable_cpumask_locks(args):
198        rpc.framework_enable_cpumask_locks(args.client)
199
200    p = subparsers.add_parser('framework_enable_cpumask_locks',
201                              help='Enable CPU core lock files.')
202    p.set_defaults(func=framework_enable_cpumask_locks)
203
204    # bdev
205    def bdev_set_options(args):
206        rpc.bdev.bdev_set_options(args.client,
207                                  bdev_io_pool_size=args.bdev_io_pool_size,
208                                  bdev_io_cache_size=args.bdev_io_cache_size,
209                                  bdev_auto_examine=args.bdev_auto_examine)
210
211    p = subparsers.add_parser('bdev_set_options',
212                              help="""Set options of bdev subsystem""")
213    p.add_argument('-p', '--bdev-io-pool-size', help='Number of bdev_io structures in shared buffer pool', type=int)
214    p.add_argument('-c', '--bdev-io-cache-size', help='Maximum number of bdev_io structures cached per thread', type=int)
215    group = p.add_mutually_exclusive_group()
216    group.add_argument('-e', '--enable-auto-examine', dest='bdev_auto_examine', help='Allow to auto examine', action='store_true')
217    group.add_argument('-d', '--disable-auto-examine', dest='bdev_auto_examine', help='Not allow to auto examine', action='store_false')
218    p.set_defaults(bdev_auto_examine=True)
219    p.set_defaults(func=bdev_set_options)
220
221    def bdev_examine(args):
222        rpc.bdev.bdev_examine(args.client,
223                              name=args.name)
224
225    p = subparsers.add_parser('bdev_examine',
226                              help="""examine a bdev if it exists, or will examine it after it is created""")
227    p.add_argument('-b', '--name', help='Name or alias of the bdev')
228    p.set_defaults(func=bdev_examine)
229
230    def bdev_wait_for_examine(args):
231        rpc.bdev.bdev_wait_for_examine(args.client)
232
233    p = subparsers.add_parser('bdev_wait_for_examine',
234                              help="""Report when all bdevs have been examined""")
235    p.set_defaults(func=bdev_wait_for_examine)
236
237    def bdev_compress_create(args):
238        print_json(rpc.bdev.bdev_compress_create(args.client,
239                                                 base_bdev_name=args.base_bdev_name,
240                                                 pm_path=args.pm_path,
241                                                 lb_size=args.lb_size))
242
243    p = subparsers.add_parser('bdev_compress_create', help='Add a compress vbdev')
244    p.add_argument('-b', '--base-bdev-name', help="Name of the base bdev")
245    p.add_argument('-p', '--pm-path', help="Path to persistent memory")
246    p.add_argument('-l', '--lb-size', help="Compressed vol logical block size (optional, if used must be 512 or 4096)", type=int)
247    p.set_defaults(func=bdev_compress_create)
248
249    def bdev_compress_delete(args):
250        rpc.bdev.bdev_compress_delete(args.client,
251                                      name=args.name)
252
253    p = subparsers.add_parser('bdev_compress_delete', help='Delete a compress disk')
254    p.add_argument('name', help='compress bdev name')
255    p.set_defaults(func=bdev_compress_delete)
256
257    def bdev_compress_get_orphans(args):
258        print_dict(rpc.bdev.bdev_compress_get_orphans(args.client,
259                                                      name=args.name))
260    p = subparsers.add_parser(
261        'bdev_compress_get_orphans', help='Display list of orphaned compress bdevs.')
262    p.add_argument('-b', '--name', help="Name of a comp bdev. Example: COMP_Nvme0n1", required=False)
263    p.set_defaults(func=bdev_compress_get_orphans)
264
265    def bdev_crypto_create(args):
266        print_json(rpc.bdev.bdev_crypto_create(args.client,
267                                               base_bdev_name=args.base_bdev_name,
268                                               name=args.name,
269                                               crypto_pmd=args.crypto_pmd,
270                                               key=args.key,
271                                               cipher=args.cipher,
272                                               key2=args.key2,
273                                               key_name=args.key_name))
274    p = subparsers.add_parser('bdev_crypto_create', help='Add a crypto vbdev')
275    p.add_argument('base_bdev_name', help="Name of the base bdev")
276    p.add_argument('name', help="Name of the crypto vbdev")
277    p.add_argument('-p', '--crypto-pmd', help="Name of the crypto device driver. Obsolete, see dpdk_cryptodev_set_driver", required=False)
278    p.add_argument('-k', '--key', help="Key. Obsolete, see accel_crypto_key_create", required=False)
279    p.add_argument('-c', '--cipher', help="cipher to use. Obsolete, see accel_crypto_key_create", required=False)
280    p.add_argument('-k2', '--key2', help="2nd key for cipher AES_XTS. Obsolete, see accel_crypto_key_create", default=None)
281    p.add_argument('-n', '--key-name', help="Key name to use, see accel_crypto_key_create", required=False)
282    p.set_defaults(func=bdev_crypto_create)
283
284    def bdev_crypto_delete(args):
285        rpc.bdev.bdev_crypto_delete(args.client,
286                                    name=args.name)
287
288    p = subparsers.add_parser('bdev_crypto_delete', help='Delete a crypto disk')
289    p.add_argument('name', help='crypto bdev name')
290    p.set_defaults(func=bdev_crypto_delete)
291
292    def bdev_ocf_create(args):
293        print_json(rpc.bdev.bdev_ocf_create(args.client,
294                                            name=args.name,
295                                            mode=args.mode,
296                                            cache_line_size=args.cache_line_size,
297                                            cache_bdev_name=args.cache_bdev_name,
298                                            core_bdev_name=args.core_bdev_name))
299    p = subparsers.add_parser('bdev_ocf_create', help='Add an OCF block device')
300    p.add_argument('name', help='Name of resulting OCF bdev')
301    p.add_argument('mode', help='OCF cache mode', choices=['wb', 'wt', 'pt', 'wa', 'wi', 'wo'])
302    p.add_argument(
303        '--cache-line-size',
304        help='OCF cache line size. The unit is KiB',
305        type=int,
306        choices=[4, 8, 16, 32, 64],
307        required=False
308    )
309    p.add_argument('cache_bdev_name', help='Name of underlying cache bdev')
310    p.add_argument('core_bdev_name', help='Name of underlying core bdev')
311    p.set_defaults(func=bdev_ocf_create)
312
313    def bdev_ocf_delete(args):
314        rpc.bdev.bdev_ocf_delete(args.client,
315                                 name=args.name)
316
317    p = subparsers.add_parser('bdev_ocf_delete', help='Delete an OCF block device')
318    p.add_argument('name', help='Name of OCF bdev')
319    p.set_defaults(func=bdev_ocf_delete)
320
321    def bdev_ocf_get_stats(args):
322        print_dict(rpc.bdev.bdev_ocf_get_stats(args.client,
323                                               name=args.name))
324    p = subparsers.add_parser('bdev_ocf_get_stats', help='Get statistics of chosen OCF block device')
325    p.add_argument('name', help='Name of OCF bdev')
326    p.set_defaults(func=bdev_ocf_get_stats)
327
328    def bdev_ocf_reset_stats(args):
329        print_dict(rpc.bdev.bdev_ocf_reset_stats(args.client,
330                                                 name=args.name))
331    p = subparsers.add_parser('bdev_ocf_reset_stats', help='Reset statistics of chosen OCF block device')
332    p.add_argument('name', help='Name of OCF bdev')
333    p.set_defaults(func=bdev_ocf_reset_stats)
334
335    def bdev_ocf_get_bdevs(args):
336        print_dict(rpc.bdev.bdev_ocf_get_bdevs(args.client,
337                                               name=args.name))
338    p = subparsers.add_parser('bdev_ocf_get_bdevs', help='Get list of OCF devices including unregistered ones')
339    p.add_argument('name', nargs='?', help='name of OCF vbdev or name of cache device or name of core device (optional)')
340    p.set_defaults(func=bdev_ocf_get_bdevs)
341
342    def bdev_ocf_set_cache_mode(args):
343        print_json(rpc.bdev.bdev_ocf_set_cache_mode(args.client,
344                                                    name=args.name,
345                                                    mode=args.mode))
346    p = subparsers.add_parser('bdev_ocf_set_cache_mode',
347                              help='Set cache mode of OCF block device')
348    p.add_argument('name', help='Name of OCF bdev')
349    p.add_argument('mode', help='OCF cache mode', choices=['wb', 'wt', 'pt', 'wa', 'wi', 'wo'])
350    p.set_defaults(func=bdev_ocf_set_cache_mode)
351
352    def bdev_ocf_set_seqcutoff(args):
353        rpc.bdev.bdev_ocf_set_seqcutoff(args.client,
354                                        name=args.name,
355                                        policy=args.policy,
356                                        threshold=args.threshold,
357                                        promotion_count=args.promotion_count)
358    p = subparsers.add_parser('bdev_ocf_set_seqcutoff',
359                              help='Set sequential cutoff parameters on all cores for the given OCF cache device')
360    p.add_argument('name', help='Name of OCF cache bdev')
361    p.add_argument('-t', '--threshold', type=int,
362                   help='Activation threshold [KiB]')
363    p.add_argument('-c', '--promotion-count', type=int,
364                   help='Promotion request count')
365    p.add_argument('-p', '--policy', choices=['always', 'full', 'never'], required=True,
366                   help='Sequential cutoff policy')
367    p.set_defaults(func=bdev_ocf_set_seqcutoff)
368
369    def bdev_ocf_flush_start(args):
370        rpc.bdev.bdev_ocf_flush_start(args.client, name=args.name)
371    p = subparsers.add_parser('bdev_ocf_flush_start',
372                              help='Start flushing OCF cache device')
373    p.add_argument('name', help='Name of OCF bdev')
374    p.set_defaults(func=bdev_ocf_flush_start)
375
376    def bdev_ocf_flush_status(args):
377        print_json(rpc.bdev.bdev_ocf_flush_status(args.client, name=args.name))
378    p = subparsers.add_parser('bdev_ocf_flush_status',
379                              help='Get flush status of OCF cache device')
380    p.add_argument('name', help='Name of OCF bdev')
381    p.set_defaults(func=bdev_ocf_flush_status)
382
383    def bdev_malloc_create(args):
384        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
385        print_json(rpc.bdev.bdev_malloc_create(args.client,
386                                               num_blocks=int(num_blocks),
387                                               block_size=args.block_size,
388                                               physical_block_size=args.physical_block_size,
389                                               name=args.name,
390                                               uuid=args.uuid,
391                                               optimal_io_boundary=args.optimal_io_boundary,
392                                               md_size=args.md_size,
393                                               md_interleave=args.md_interleave,
394                                               dif_type=args.dif_type,
395                                               dif_is_head_of_md=args.dif_is_head_of_md))
396    p = subparsers.add_parser('bdev_malloc_create', help='Create a bdev with malloc backend')
397    p.add_argument('-b', '--name', help="Name of the bdev")
398    p.add_argument('-u', '--uuid', help="UUID of the bdev")
399    p.add_argument(
400        'total_size', help='Size of malloc bdev in MB (float > 0)', type=float)
401    p.add_argument('block_size', help='Data block size for this bdev', type=int)
402    p.add_argument('-p', '--physical-block-size', help='Physical block size for this bdev.', type=int)
403    p.add_argument('-o', '--optimal-io-boundary', help="""Split on optimal IO boundary, in number of
404    blocks, default 0 (disabled)""", type=int)
405    p.add_argument('-m', '--md-size', type=int,
406                   help='Metadata size for this bdev (0, 8, 16, 32, 64, or 128). Default is 0.')
407    p.add_argument('-i', '--md-interleave', action='store_true',
408                   help='Metadata location, interleaved if set, and separated if omitted.')
409    p.add_argument('-t', '--dif-type', type=int, choices=[0, 1, 2, 3],
410                   help='Protection information type. Parameter --md-size needs'
411                        'to be set along --dif-type. Default=0 - no protection.')
412    p.add_argument('-d', '--dif-is-head-of-md', action='store_true',
413                   help='Protection information is in the first 8 bytes of metadata. Default=false.')
414    p.set_defaults(func=bdev_malloc_create)
415
416    def bdev_malloc_delete(args):
417        rpc.bdev.bdev_malloc_delete(args.client,
418                                    name=args.name)
419
420    p = subparsers.add_parser('bdev_malloc_delete', help='Delete a malloc disk')
421    p.add_argument('name', help='malloc bdev name')
422    p.set_defaults(func=bdev_malloc_delete)
423
424    def bdev_null_create(args):
425        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
426        if args.dif_type and not args.md_size:
427            print("ERROR: --md-size must be > 0 when --dif-type is > 0")
428            exit(1)
429        print_json(rpc.bdev.bdev_null_create(args.client,
430                                             num_blocks=num_blocks,
431                                             block_size=args.block_size,
432                                             physical_block_size=args.physical_block_size,
433                                             name=args.name,
434                                             uuid=args.uuid,
435                                             md_size=args.md_size,
436                                             dif_type=args.dif_type,
437                                             dif_is_head_of_md=args.dif_is_head_of_md))
438
439    p = subparsers.add_parser('bdev_null_create', help='Add a bdev with null backend')
440    p.add_argument('name', help='Block device name')
441    p.add_argument('-u', '--uuid', help='UUID of the bdev')
442    p.add_argument('total_size', help='Size of null bdev in MB (int > 0). Includes only data blocks.', type=int)
443    p.add_argument('block_size', help='Block size for this bdev.'
444                                      'Should be a sum of block size and metadata size if --md-size is used.', type=int)
445    p.add_argument('-p', '--physical-block-size', help='Physical block size for this bdev.', type=int)
446    p.add_argument('-m', '--md-size', type=int,
447                   help='Metadata size for this bdev. Default=0.')
448    p.add_argument('-t', '--dif-type', type=int, choices=[0, 1, 2, 3],
449                   help='Protection information type. Parameter --md-size needs'
450                        'to be set along --dif-type. Default=0 - no protection.')
451    p.add_argument('-d', '--dif-is-head-of-md', action='store_true',
452                   help='Protection information is in the first 8 bytes of metadata. Default=false.')
453    p.set_defaults(func=bdev_null_create)
454
455    def bdev_null_delete(args):
456        rpc.bdev.bdev_null_delete(args.client,
457                                  name=args.name)
458
459    p = subparsers.add_parser('bdev_null_delete', help='Delete a null bdev')
460    p.add_argument('name', help='null bdev name')
461    p.set_defaults(func=bdev_null_delete)
462
463    def bdev_null_resize(args):
464        print_json(rpc.bdev.bdev_null_resize(args.client,
465                                             name=args.name,
466                                             new_size=int(args.new_size)))
467
468    p = subparsers.add_parser('bdev_null_resize',
469                              help='Resize a null bdev')
470    p.add_argument('name', help='null bdev name')
471    p.add_argument('new_size', help='new bdev size for resize operation. The unit is MiB')
472    p.set_defaults(func=bdev_null_resize)
473
474    def bdev_aio_create(args):
475        print_json(rpc.bdev.bdev_aio_create(args.client,
476                                            filename=args.filename,
477                                            name=args.name,
478                                            block_size=args.block_size,
479                                            readonly=args.readonly))
480
481    p = subparsers.add_parser('bdev_aio_create', help='Add a bdev with aio backend')
482    p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
483    p.add_argument('name', help='Block device name')
484    p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?')
485    p.add_argument("-r", "--readonly", action='store_true', help='Set this bdev as read-only')
486    p.set_defaults(func=bdev_aio_create)
487
488    def bdev_aio_rescan(args):
489        print_json(rpc.bdev.bdev_aio_rescan(args.client,
490                                            name=args.name))
491
492    p = subparsers.add_parser('bdev_aio_rescan', help='Rescan a bdev size with aio backend')
493    p.add_argument('name', help='Block device name')
494    p.set_defaults(func=bdev_aio_rescan)
495
496    def bdev_aio_delete(args):
497        rpc.bdev.bdev_aio_delete(args.client,
498                                 name=args.name)
499
500    p = subparsers.add_parser('bdev_aio_delete', help='Delete an aio disk')
501    p.add_argument('name', help='aio bdev name')
502    p.set_defaults(func=bdev_aio_delete)
503
504    def bdev_uring_create(args):
505        print_json(rpc.bdev.bdev_uring_create(args.client,
506                                              filename=args.filename,
507                                              name=args.name,
508                                              block_size=args.block_size))
509
510    p = subparsers.add_parser('bdev_uring_create', help='Create a bdev with io_uring backend')
511    p.add_argument('filename', help='Path to device or file (ex: /dev/nvme0n1)')
512    p.add_argument('name', help='bdev name')
513    p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?')
514    p.set_defaults(func=bdev_uring_create)
515
516    def bdev_uring_delete(args):
517        rpc.bdev.bdev_uring_delete(args.client,
518                                   name=args.name)
519
520    p = subparsers.add_parser('bdev_uring_delete', help='Delete a uring bdev')
521    p.add_argument('name', help='uring bdev name')
522    p.set_defaults(func=bdev_uring_delete)
523
524    def bdev_xnvme_create(args):
525        print_json(rpc.bdev.bdev_xnvme_create(args.client,
526                                              filename=args.filename,
527                                              name=args.name,
528                                              io_mechanism=args.io_mechanism))
529
530    p = subparsers.add_parser('bdev_xnvme_create', help='Create a bdev with xNVMe backend')
531    p.add_argument('filename', help='Path to device or file (ex: /dev/nvme0n1)')
532    p.add_argument('name', help='name of xNVMe bdev to create')
533    p.add_argument('io_mechanism', help='IO mechanism to use (ex: libaio, io_uring, io_uring_cmd, etc.)')
534    p.add_argument('conserve_cpu', action='store_true', help='Whether or not to conserve CPU when polling')
535    p.set_defaults(func=bdev_xnvme_create)
536
537    def bdev_xnvme_delete(args):
538        rpc.bdev.bdev_xnvme_delete(args.client,
539                                   name=args.name)
540
541    p = subparsers.add_parser('bdev_xnvme_delete', help='Delete a xNVMe bdev')
542    p.add_argument('name', help='xNVMe bdev name')
543    p.set_defaults(func=bdev_xnvme_delete)
544
545    def bdev_nvme_set_options(args):
546        rpc.bdev.bdev_nvme_set_options(args.client,
547                                       action_on_timeout=args.action_on_timeout,
548                                       timeout_us=args.timeout_us,
549                                       timeout_admin_us=args.timeout_admin_us,
550                                       keep_alive_timeout_ms=args.keep_alive_timeout_ms,
551                                       retry_count=args.retry_count,
552                                       arbitration_burst=args.arbitration_burst,
553                                       low_priority_weight=args.low_priority_weight,
554                                       medium_priority_weight=args.medium_priority_weight,
555                                       high_priority_weight=args.high_priority_weight,
556                                       nvme_adminq_poll_period_us=args.nvme_adminq_poll_period_us,
557                                       nvme_ioq_poll_period_us=args.nvme_ioq_poll_period_us,
558                                       io_queue_requests=args.io_queue_requests,
559                                       delay_cmd_submit=args.delay_cmd_submit,
560                                       transport_retry_count=args.transport_retry_count,
561                                       bdev_retry_count=args.bdev_retry_count,
562                                       transport_ack_timeout=args.transport_ack_timeout,
563                                       ctrlr_loss_timeout_sec=args.ctrlr_loss_timeout_sec,
564                                       reconnect_delay_sec=args.reconnect_delay_sec,
565                                       fast_io_fail_timeout_sec=args.fast_io_fail_timeout_sec,
566                                       disable_auto_failback=args.disable_auto_failback,
567                                       generate_uuids=args.generate_uuids,
568                                       transport_tos=args.transport_tos,
569                                       nvme_error_stat=args.nvme_error_stat,
570                                       rdma_srq_size=args.rdma_srq_size,
571                                       io_path_stat=args.io_path_stat,
572                                       allow_accel_sequence=args.allow_accel_sequence)
573
574    p = subparsers.add_parser('bdev_nvme_set_options',
575                              help='Set options for the bdev nvme type. This is startup command.')
576    p.add_argument('-a', '--action-on-timeout',
577                   help="Action to take on command time out. Valid values are: none, reset, abort")
578    p.add_argument('-t', '--timeout-us',
579                   help="Timeout for each command, in microseconds. If 0, don't track timeouts.", type=int)
580    p.add_argument('--timeout-admin-us',
581                   help="Timeout for each admin command, in microseconds. If 0, treat same as io timeouts.", type=int)
582    p.add_argument('-k', '--keep-alive-timeout-ms',
583                   help="Keep alive timeout period in millisecond. If 0, disable keep-alive.", type=int)
584    p.add_argument('-n', '--retry-count',
585                   help='the number of attempts per I/O when an I/O fails. (deprecated, please use --transport-retry-count.)', type=int)
586    p.add_argument('--arbitration-burst',
587                   help='the value is expressed as a power of two', type=int)
588    p.add_argument('--low-priority-weight',
589                   help='the maximum number of commands that the controller may launch at one time from a low priority queue', type=int)
590    p.add_argument('--medium-priority-weight',
591                   help='the maximum number of commands that the controller may launch at one time from a medium priority queue', type=int)
592    p.add_argument('--high-priority-weight',
593                   help='the maximum number of commands that the controller may launch at one time from a high priority queue', type=int)
594    p.add_argument('-p', '--nvme-adminq-poll-period-us',
595                   help='How often the admin queue is polled for asynchronous events', type=int)
596    p.add_argument('-i', '--nvme-ioq-poll-period-us',
597                   help='How often to poll I/O queues for completions', type=int)
598    p.add_argument('-s', '--io-queue-requests',
599                   help='The number of requests allocated for each NVMe I/O queue. Default: 512', type=int)
600    p.add_argument('-d', '--disable-delay-cmd-submit',
601                   help='Disable delaying NVMe command submission, i.e. no batching of multiple commands',
602                   action='store_false', dest='delay_cmd_submit')
603    p.add_argument('-c', '--transport-retry-count',
604                   help='the number of attempts per I/O in the transport layer when an I/O fails.', type=int)
605    p.add_argument('-r', '--bdev-retry-count',
606                   help='the number of attempts per I/O in the bdev layer when an I/O fails. -1 means infinite retries.', type=int)
607    p.add_argument('-e', '--transport-ack-timeout',
608                   help="""Time to wait ack until packet retransmission for RDMA or until closes connection for TCP.
609                   Range 0-31 where 0 is driver-specific default value.""", type=int)
610    p.add_argument('-l', '--ctrlr-loss-timeout-sec',
611                   help="""Time to wait until ctrlr is reconnected before deleting ctrlr.
612                   -1 means infinite reconnect retries. 0 means no reconnect retry.
613                   If reconnect_delay_sec is zero, ctrlr_loss_timeout_sec has to be zero.
614                   If reconnect_delay_sec is non-zero, ctrlr_loss_timeout_sec has to be -1 or not less than
615                   reconnect_delay_sec.
616                   This can be overridden by bdev_nvme_attach_controller.""",
617                   type=int)
618    p.add_argument('-o', '--reconnect-delay-sec',
619                   help="""Time to delay a reconnect retry.
620                   If ctrlr_loss_timeout_sec is zero, reconnect_delay_sec has to be zero.
621                   If ctrlr_loss_timeout_sec is -1, reconnect_delay_sec has to be non-zero.
622                   If ctrlr_loss_timeout_sec is not -1 or zero, reconnect_delay_sec has to be non-zero and
623                   less than ctrlr_loss_timeout_sec.
624                   This can be overridden by bdev_nvme_attach_controller.""",
625                   type=int)
626    p.add_argument('-u', '--fast-io-fail-timeout-sec',
627                   help="""Time to wait until ctrlr is reconnected before failing I/O to ctrlr.
628                   0 means no such timeout.
629                   If fast_io_fail_timeout_sec is not zero, it has to be not less than reconnect_delay_sec and
630                   less than ctrlr_loss_timeout_sec if ctrlr_loss_timeout_sec is not -1.
631                   This can be overridden by bdev_nvme_attach_controller.""",
632                   type=int)
633    p.add_argument('-f', '--disable-auto-failback',
634                   help="""Disable automatic failback. bdev_nvme_set_preferred_path can be used to do manual failback.
635                   By default, immediately failback to the preferred I/O path if it restored.""",
636                   action='store_true')
637    p.add_argument('--generate-uuids',
638                   help="""Enable generation of unique identifiers for NVMe bdevs only if they do
639                   not provide UUID themselves. These strings are based on device serial number and
640                   namespace ID and will always be the same for that device.""", action='store_true')
641    p.add_argument('--transport-tos',
642                   help="""IPv4 Type of Service value. Only applicable for RDMA transports.
643                   The default is 0 which means no TOS is applied.""", type=int)
644    p.add_argument('-m', '--nvme-error-stat', help="Enable collecting NVMe error counts.", action='store_true')
645    p.add_argument('-q', '--rdma-srq-size',
646                   help='Set the size of a shared rdma receive queue. Default: 0 (disabled)', type=int)
647    p.add_argument('--io-path-stat',
648                   help="""Enable collecting I/O path stat of each io path.""",
649                   action='store_true')
650    p.add_argument('--allow-accel-sequence',
651                   help='''Allow NVMe bdevs to advertise support for accel sequences if the
652                   controller also supports them.''', action='store_true')
653
654    p.set_defaults(func=bdev_nvme_set_options)
655
656    def bdev_nvme_set_hotplug(args):
657        rpc.bdev.bdev_nvme_set_hotplug(args.client, enable=args.enable, period_us=args.period_us)
658
659    p = subparsers.add_parser('bdev_nvme_set_hotplug', help='Set hotplug options for bdev nvme type.')
660    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
661    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
662    p.add_argument('-r', '--period-us',
663                   help='How often the hotplug is processed for insert and remove events', type=int)
664    p.set_defaults(func=bdev_nvme_set_hotplug)
665
666    def bdev_nvme_attach_controller(args):
667        print_array(rpc.bdev.bdev_nvme_attach_controller(args.client,
668                                                         name=args.name,
669                                                         trtype=args.trtype,
670                                                         traddr=args.traddr,
671                                                         adrfam=args.adrfam,
672                                                         trsvcid=args.trsvcid,
673                                                         priority=args.priority,
674                                                         subnqn=args.subnqn,
675                                                         hostnqn=args.hostnqn,
676                                                         hostaddr=args.hostaddr,
677                                                         hostsvcid=args.hostsvcid,
678                                                         prchk_reftag=args.prchk_reftag,
679                                                         prchk_guard=args.prchk_guard,
680                                                         hdgst=args.hdgst,
681                                                         ddgst=args.ddgst,
682                                                         fabrics_timeout=args.fabrics_timeout,
683                                                         multipath=args.multipath,
684                                                         num_io_queues=args.num_io_queues,
685                                                         ctrlr_loss_timeout_sec=args.ctrlr_loss_timeout_sec,
686                                                         reconnect_delay_sec=args.reconnect_delay_sec,
687                                                         fast_io_fail_timeout_sec=args.fast_io_fail_timeout_sec,
688                                                         psk=args.psk,
689                                                         max_bdevs=args.max_bdevs))
690
691    p = subparsers.add_parser('bdev_nvme_attach_controller', help='Add bdevs with nvme backend')
692    p.add_argument('-b', '--name', help="Name of the NVMe controller, prefix for each bdev name", required=True)
693    p.add_argument('-t', '--trtype',
694                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
695    p.add_argument('-a', '--traddr',
696                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
697    p.add_argument('-f', '--adrfam',
698                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
699    p.add_argument('-s', '--trsvcid',
700                   help='NVMe-oF target trsvcid: e.g., a port number')
701    p.add_argument('-p', '--priority',
702                   help='NVMe-oF connection priority: e.g., a priority number')
703    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
704    p.add_argument('-q', '--hostnqn', help='NVMe-oF host subnqn')
705    p.add_argument('-i', '--hostaddr',
706                   help='NVMe-oF host address: e.g., an ip address')
707    p.add_argument('-c', '--hostsvcid',
708                   help='NVMe-oF host svcid: e.g., a port number')
709    p.add_argument('-r', '--prchk-reftag',
710                   help='Enable checking of PI reference tag for I/O processing.', action='store_true')
711    p.add_argument('-g', '--prchk-guard',
712                   help='Enable checking of PI guard for I/O processing.', action='store_true')
713    p.add_argument('-e', '--hdgst',
714                   help='Enable TCP header digest.', action='store_true')
715    p.add_argument('-d', '--ddgst',
716                   help='Enable TCP data digest.', action='store_true')
717    p.add_argument('--fabrics-timeout', type=int, help='Fabrics connect timeout in microseconds')
718    p.add_argument('-x', '--multipath', help='Set multipath behavior (disable, failover, multipath)')
719    p.add_argument('--num-io-queues', type=int, help='Set the number of IO queues to request during initialization.')
720    p.add_argument('-l', '--ctrlr-loss-timeout-sec',
721                   help="""Time to wait until ctrlr is reconnected before deleting ctrlr.
722                   -1 means infinite reconnect retries. 0 means no reconnect retry.
723                   If reconnect_delay_sec is zero, ctrlr_loss_timeout_sec has to be zero.
724                   If reconnect_delay_sec is non-zero, ctrlr_loss_timeout_sec has to be -1 or not less than
725                   reconnect_delay_sec.""",
726                   type=int)
727    p.add_argument('-o', '--reconnect-delay-sec',
728                   help="""Time to delay a reconnect retry.
729                   If ctrlr_loss_timeout_sec is zero, reconnect_delay_sec has to be zero.
730                   If ctrlr_loss_timeout_sec is -1, reconnect_delay_sec has to be non-zero.
731                   If ctrlr_loss_timeout_sec is not -1 or zero, reconnect_delay_sec has to be non-zero and
732                   less than ctrlr_loss_timeout_sec.""",
733                   type=int)
734    p.add_argument('-u', '--fast-io-fail-timeout-sec',
735                   help="""Time to wait until ctrlr is reconnected before failing I/O to ctrlr.
736                   0 means no such timeout.
737                   If fast_io_fail_timeout_sec is not zero, it has to be not less than reconnect_delay_sec and
738                   less than ctrlr_loss_timeout_sec if ctrlr_loss_timeout_sec is not -1.""",
739                   type=int)
740    p.add_argument('-k', '--psk',
741                   help='Set PSK file path and enable TCP SSL socket implementation.')
742    p.add_argument('-m', '--max-bdevs', type=int,
743                   help='The size of the name array for newly created bdevs. Default is 128',)
744
745    p.set_defaults(func=bdev_nvme_attach_controller)
746
747    def bdev_nvme_get_controllers(args):
748        print_dict(rpc.nvme.bdev_nvme_get_controllers(args.client,
749                                                      name=args.name))
750
751    p = subparsers.add_parser(
752        'bdev_nvme_get_controllers', help='Display current NVMe controllers list or required NVMe controller')
753    p.add_argument('-n', '--name', help="Name of the NVMe controller. Example: Nvme0", required=False)
754    p.set_defaults(func=bdev_nvme_get_controllers)
755
756    def bdev_nvme_detach_controller(args):
757        rpc.bdev.bdev_nvme_detach_controller(args.client,
758                                             name=args.name,
759                                             trtype=args.trtype,
760                                             traddr=args.traddr,
761                                             adrfam=args.adrfam,
762                                             trsvcid=args.trsvcid,
763                                             subnqn=args.subnqn,
764                                             hostaddr=args.hostaddr,
765                                             hostsvcid=args.hostsvcid)
766
767    p = subparsers.add_parser('bdev_nvme_detach_controller',
768                              help='Detach an NVMe controller and delete any associated bdevs')
769    p.add_argument('name', help="Name of the controller")
770    p.add_argument('-t', '--trtype',
771                   help='NVMe-oF target trtype: e.g., rdma, pcie')
772    p.add_argument('-a', '--traddr',
773                   help='NVMe-oF target address: e.g., an ip address or BDF')
774    p.add_argument('-f', '--adrfam',
775                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
776    p.add_argument('-s', '--trsvcid',
777                   help='NVMe-oF target trsvcid: e.g., a port number')
778    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
779    p.add_argument('-i', '--hostaddr',
780                   help='NVMe-oF host address: e.g., an ip address')
781    p.add_argument('-c', '--hostsvcid',
782                   help='NVMe-oF host svcid: e.g., a port number')
783    p.set_defaults(func=bdev_nvme_detach_controller)
784
785    def bdev_nvme_reset_controller(args):
786        rpc.bdev.bdev_nvme_reset_controller(args.client,
787                                            name=args.name,
788                                            cntlid=args.cntlid)
789
790    p = subparsers.add_parser('bdev_nvme_reset_controller',
791                              help='Reset an NVMe controller or all NVMe controllers in an NVMe bdev controller')
792    p.add_argument('name', help="Name of the NVMe controller")
793    p.add_argument('-c', '--cntlid', help="NVMe controller ID", type=int)
794    p.set_defaults(func=bdev_nvme_reset_controller)
795
796    def bdev_nvme_enable_controller(args):
797        rpc.bdev.bdev_nvme_enable_controller(args.client,
798                                             name=args.name,
799                                             cntlid=args.cntlid)
800
801    p = subparsers.add_parser('bdev_nvme_enable_controller',
802                              help='Enable an NVMe controller or all NVMe controllers in an NVMe bdev controller')
803    p.add_argument('name', help="Name of the NVMe controller")
804    p.add_argument('-c', '--cntlid', help="NVMe controller ID", type=int)
805    p.set_defaults(func=bdev_nvme_enable_controller)
806
807    def bdev_nvme_disable_controller(args):
808        rpc.bdev.bdev_nvme_disable_controller(args.client,
809                                              name=args.name,
810                                              cntlid=args.cntlid)
811
812    p = subparsers.add_parser('bdev_nvme_disable_controller',
813                              help='Disable an NVMe controller or all NVMe controllers in an NVMe bdev controller')
814    p.add_argument('name', help="Name of the NVMe controller")
815    p.add_argument('-c', '--cntlid', help="NVMe controller ID", type=int)
816    p.set_defaults(func=bdev_nvme_disable_controller)
817
818    def bdev_nvme_start_discovery(args):
819        rpc.bdev.bdev_nvme_start_discovery(args.client,
820                                           name=args.name,
821                                           trtype=args.trtype,
822                                           traddr=args.traddr,
823                                           adrfam=args.adrfam,
824                                           trsvcid=args.trsvcid,
825                                           hostnqn=args.hostnqn,
826                                           wait_for_attach=args.wait_for_attach,
827                                           attach_timeout_ms=args.attach_timeout_ms,
828                                           ctrlr_loss_timeout_sec=args.ctrlr_loss_timeout_sec,
829                                           reconnect_delay_sec=args.reconnect_delay_sec,
830                                           fast_io_fail_timeout_sec=args.fast_io_fail_timeout_sec)
831
832    p = subparsers.add_parser('bdev_nvme_start_discovery', help='Start automatic discovery')
833    p.add_argument('-b', '--name', help="Name of the NVMe controller prefix for each bdev name", required=True)
834    p.add_argument('-t', '--trtype',
835                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
836    p.add_argument('-a', '--traddr',
837                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
838    p.add_argument('-f', '--adrfam',
839                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
840    p.add_argument('-s', '--trsvcid',
841                   help='NVMe-oF target trsvcid: e.g., a port number')
842    p.add_argument('-q', '--hostnqn', help='NVMe-oF host subnqn')
843    p.add_argument('-w', '--wait-for-attach', action='store_true',
844                   help='Do not complete RPC until all discovered NVM subsystems are attached')
845    p.add_argument('-T', '--attach-timeout-ms', type=int, required=False,
846                   help="""Time to wait until the discovery and all discovered NVM subsystems
847                        are attached (default: 0, meaning wait indefinitely).  Automatically
848                        selects the --wait-for-attach option.""")
849    p.add_argument('-l', '--ctrlr-loss-timeout-sec',
850                   help="""Time to wait until ctrlr is reconnected before deleting ctrlr.
851                   -1 means infinite reconnect retries. 0 means no reconnect retry.
852                   If reconnect_delay_sec is zero, ctrlr_loss_timeout_sec has to be zero.
853                   If reconnect_delay_sec is non-zero, ctrlr_loss_timeout_sec has to be -1 or not less than
854                   reconnect_delay_sec.""",
855                   type=int)
856    p.add_argument('-o', '--reconnect-delay-sec',
857                   help="""Time to delay a reconnect retry.
858                   If ctrlr_loss_timeout_sec is zero, reconnect_delay_sec has to be zero.
859                   If ctrlr_loss_timeout_sec is -1, reconnect_delay_sec has to be non-zero.
860                   If ctrlr_loss_timeout_sec is not -1 or zero, reconnect_delay_sec has to be non-zero and
861                   less than ctrlr_loss_timeout_sec.""",
862                   type=int)
863    p.add_argument('-u', '--fast-io-fail-timeout-sec',
864                   help="""Time to wait until ctrlr is reconnected before failing I/O to ctrlr.
865                   0 means no such timeout.
866                   If fast_io_fail_timeout_sec is not zero, it has to be not less than reconnect_delay_sec and
867                   less than ctrlr_loss_timeout_sec if ctrlr_loss_timeout_sec is not -1.""",
868                   type=int)
869    p.set_defaults(func=bdev_nvme_start_discovery)
870
871    def bdev_nvme_stop_discovery(args):
872        rpc.bdev.bdev_nvme_stop_discovery(args.client, name=args.name)
873
874    p = subparsers.add_parser('bdev_nvme_stop_discovery', help='Stop automatic discovery')
875    p.add_argument('-b', '--name', help="Name of the service to stop", required=True)
876    p.set_defaults(func=bdev_nvme_stop_discovery)
877
878    def bdev_nvme_get_discovery_info(args):
879        print_dict(rpc.bdev.bdev_nvme_get_discovery_info(args.client))
880
881    p = subparsers.add_parser('bdev_nvme_get_discovery_info', help='Get information about the automatic discovery')
882    p.set_defaults(func=bdev_nvme_get_discovery_info)
883
884    def bdev_nvme_get_io_paths(args):
885        print_dict(rpc.bdev.bdev_nvme_get_io_paths(args.client, name=args.name))
886
887    p = subparsers.add_parser('bdev_nvme_get_io_paths', help='Display active I/O paths')
888    p.add_argument('-n', '--name', help="Name of the NVMe bdev", required=False)
889    p.set_defaults(func=bdev_nvme_get_io_paths)
890
891    def bdev_nvme_set_preferred_path(args):
892        rpc.bdev.bdev_nvme_set_preferred_path(args.client,
893                                              name=args.name,
894                                              cntlid=args.cntlid)
895
896    p = subparsers.add_parser('bdev_nvme_set_preferred_path',
897                              help="""Set the preferred I/O path for an NVMe bdev when in multipath mode""")
898    p.add_argument('-b', '--name', help='Name of the NVMe bdev', required=True)
899    p.add_argument('-c', '--cntlid', help='NVMe-oF controller ID', type=int, required=True)
900    p.set_defaults(func=bdev_nvme_set_preferred_path)
901
902    def bdev_nvme_set_multipath_policy(args):
903        rpc.bdev.bdev_nvme_set_multipath_policy(args.client,
904                                                name=args.name,
905                                                policy=args.policy,
906                                                selector=args.selector,
907                                                rr_min_io=args.rr_min_io)
908
909    p = subparsers.add_parser('bdev_nvme_set_multipath_policy',
910                              help="""Set multipath policy of the NVMe bdev""")
911    p.add_argument('-b', '--name', help='Name of the NVMe bdev', required=True)
912    p.add_argument('-p', '--policy', help='Multipath policy (active_passive or active_active)', required=True)
913    p.add_argument('-s', '--selector', help='Multipath selector (round_robin, queue_depth)', required=False)
914    p.add_argument('-r', '--rr-min-io',
915                   help='Number of IO to route to a path before switching to another for round-robin',
916                   type=int, required=False)
917    p.set_defaults(func=bdev_nvme_set_multipath_policy)
918
919    def bdev_nvme_get_path_iostat(args):
920        print_dict(rpc.bdev.bdev_nvme_get_path_iostat(args.client,
921                                                      name=args.name))
922
923    p = subparsers.add_parser('bdev_nvme_get_path_iostat',
924                              help="""Display current I/O statistics of all the IO paths of the blockdev. It can be
925                              called when io_path_stat is true.""")
926    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: NVMe0n1", required=True)
927    p.set_defaults(func=bdev_nvme_get_path_iostat)
928
929    def bdev_nvme_cuse_register(args):
930        rpc.bdev.bdev_nvme_cuse_register(args.client,
931                                         name=args.name)
932
933    p = subparsers.add_parser('bdev_nvme_cuse_register',
934                              help='Register CUSE devices on NVMe controller')
935    p.add_argument('-n', '--name',
936                   help='Name of the NVMe controller. Example: Nvme0', required=True)
937    p.set_defaults(func=bdev_nvme_cuse_register)
938
939    def bdev_nvme_cuse_unregister(args):
940        rpc.bdev.bdev_nvme_cuse_unregister(args.client,
941                                           name=args.name)
942
943    p = subparsers.add_parser('bdev_nvme_cuse_unregister',
944                              help='Unregister CUSE devices on NVMe controller')
945    p.add_argument('-n', '--name',
946                   help='Name of the NVMe controller. Example: Nvme0', required=True)
947    p.set_defaults(func=bdev_nvme_cuse_unregister)
948
949    def bdev_zone_block_create(args):
950        print_json(rpc.bdev.bdev_zone_block_create(args.client,
951                                                   name=args.name,
952                                                   base_bdev=args.base_bdev,
953                                                   zone_capacity=args.zone_capacity,
954                                                   optimal_open_zones=args.optimal_open_zones))
955
956    p = subparsers.add_parser('bdev_zone_block_create',
957                              help='Create virtual zone namespace device with block device backend')
958    p.add_argument('-b', '--name', help="Name of the zone device", required=True)
959    p.add_argument('-n', '--base-bdev', help='Name of underlying, non-zoned bdev', required=True)
960    p.add_argument('-z', '--zone-capacity', help='Surfaced zone capacity in blocks', type=int, required=True)
961    p.add_argument('-o', '--optimal-open-zones', help='Number of zones required to reach optimal write speed', type=int, required=True)
962    p.set_defaults(func=bdev_zone_block_create)
963
964    def bdev_zone_block_delete(args):
965        rpc.bdev.bdev_zone_block_delete(args.client,
966                                        name=args.name)
967
968    p = subparsers.add_parser('bdev_zone_block_delete', help='Delete a virtual zone namespace device')
969    p.add_argument('name', help='Virtual zone bdev name')
970    p.set_defaults(func=bdev_zone_block_delete)
971
972    def bdev_rbd_register_cluster(args):
973        config_param = None
974        if args.config_param:
975            config_param = {}
976            for entry in args.config_param:
977                parts = entry.split('=', 1)
978                if len(parts) != 2:
979                    raise Exception('--config %s not in key=value form' % entry)
980                config_param[parts[0]] = parts[1]
981        print_json(rpc.bdev.bdev_rbd_register_cluster(args.client,
982                                                      name=args.name,
983                                                      user=args.user,
984                                                      config_param=config_param,
985                                                      config_file=args.config_file,
986                                                      key_file=args.key_file,
987                                                      core_mask=args.core_mask))
988
989    p = subparsers.add_parser('bdev_rbd_register_cluster',
990                              help='Add a Rados cluster with ceph rbd backend')
991    p.add_argument('name', help="Name of the Rados cluster only known to rbd bdev")
992    p.add_argument('--user', help="Ceph user name (i.e. admin, not client.admin)", required=False)
993    p.add_argument('--config-param', action='append', metavar='key=value',
994                   help="adds a key=value configuration option for rados_conf_set (default: rely on config file)")
995    p.add_argument('--config-file', help="The file path of the Rados configuration file", required=False)
996    p.add_argument('--key-file', help="The file path of the Rados keyring file", required=False)
997    p.add_argument('--core-mask', help="Set core mask for librbd IO context threads", required=False)
998    p.set_defaults(func=bdev_rbd_register_cluster)
999
1000    def bdev_rbd_unregister_cluster(args):
1001        rpc.bdev.bdev_rbd_unregister_cluster(args.client, name=args.name)
1002
1003    p = subparsers.add_parser('bdev_rbd_unregister_cluster',
1004                              help='Unregister a Rados cluster object')
1005    p.add_argument('name', help='Name of the Rados Cluster only known to rbd bdev')
1006    p.set_defaults(func=bdev_rbd_unregister_cluster)
1007
1008    def bdev_rbd_get_clusters_info(args):
1009        print_json(rpc.bdev.bdev_rbd_get_clusters_info(args.client, name=args.name))
1010
1011    p = subparsers.add_parser('bdev_rbd_get_clusters_info',
1012                              help='Display registered Rados Cluster names and related info')
1013    p.add_argument('-b', '--name', help="Name of the registered Rados Cluster Name. Example: Cluster1", required=False)
1014    p.set_defaults(func=bdev_rbd_get_clusters_info)
1015
1016    def bdev_rbd_create(args):
1017        config = None
1018        if args.config:
1019            config = {}
1020            for entry in args.config:
1021                parts = entry.split('=', 1)
1022                if len(parts) != 2:
1023                    raise Exception('--config %s not in key=value form' % entry)
1024                config[parts[0]] = parts[1]
1025        print_json(rpc.bdev.bdev_rbd_create(args.client,
1026                                            name=args.name,
1027                                            user=args.user,
1028                                            config=config,
1029                                            pool_name=args.pool_name,
1030                                            rbd_name=args.rbd_name,
1031                                            block_size=args.block_size,
1032                                            cluster_name=args.cluster_name,
1033                                            uuid=args.uuid))
1034
1035    p = subparsers.add_parser('bdev_rbd_create', help='Add a bdev with ceph rbd backend')
1036    p.add_argument('-b', '--name', help="Name of the bdev", required=False)
1037    p.add_argument('--user', help="Ceph user name (i.e. admin, not client.admin)", required=False)
1038    p.add_argument('--config', action='append', metavar='key=value',
1039                   help="adds a key=value configuration option for rados_conf_set (default: rely on config file)")
1040    p.add_argument('pool_name', help='rbd pool name')
1041    p.add_argument('rbd_name', help='rbd image name')
1042    p.add_argument('block_size', help='rbd block size', type=int)
1043    p.add_argument('-c', '--cluster-name', help="cluster name to identify the Rados cluster", required=False)
1044    p.add_argument('-u', '--uuid', help="UUID of the bdev")
1045    p.set_defaults(func=bdev_rbd_create)
1046
1047    def bdev_rbd_delete(args):
1048        rpc.bdev.bdev_rbd_delete(args.client,
1049                                 name=args.name)
1050
1051    p = subparsers.add_parser('bdev_rbd_delete', help='Delete a rbd bdev')
1052    p.add_argument('name', help='rbd bdev name')
1053    p.set_defaults(func=bdev_rbd_delete)
1054
1055    def bdev_rbd_resize(args):
1056        print_json(rpc.bdev.bdev_rbd_resize(args.client,
1057                                            name=args.name,
1058                                            new_size=int(args.new_size)))
1059
1060    p = subparsers.add_parser('bdev_rbd_resize',
1061                              help='Resize a rbd bdev')
1062    p.add_argument('name', help='rbd bdev name')
1063    p.add_argument('new_size', help='new bdev size for resize operation. The unit is MiB')
1064    p.set_defaults(func=bdev_rbd_resize)
1065
1066    def bdev_delay_create(args):
1067        print_json(rpc.bdev.bdev_delay_create(args.client,
1068                                              base_bdev_name=args.base_bdev_name,
1069                                              name=args.name,
1070                                              uuid=args.uuid,
1071                                              avg_read_latency=args.avg_read_latency,
1072                                              p99_read_latency=args.nine_nine_read_latency,
1073                                              avg_write_latency=args.avg_write_latency,
1074                                              p99_write_latency=args.nine_nine_write_latency))
1075
1076    p = subparsers.add_parser('bdev_delay_create',
1077                              help='Add a delay bdev on existing bdev')
1078    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
1079    p.add_argument('-d', '--name', help="Name of the delay bdev", required=True)
1080    p.add_argument('-u', '--uuid', help='UUID of the bdev (optional)')
1081    p.add_argument('-r', '--avg-read-latency',
1082                   help="Average latency to apply before completing read ops (in microseconds)", required=True, type=int)
1083    p.add_argument('-t', '--nine-nine-read-latency',
1084                   help="latency to apply to 1 in 100 read ops (in microseconds)", required=True, type=int)
1085    p.add_argument('-w', '--avg-write-latency',
1086                   help="Average latency to apply before completing write ops (in microseconds)", required=True, type=int)
1087    p.add_argument('-n', '--nine-nine-write-latency',
1088                   help="latency to apply to 1 in 100 write ops (in microseconds)", required=True, type=int)
1089    p.set_defaults(func=bdev_delay_create)
1090
1091    def bdev_delay_delete(args):
1092        rpc.bdev.bdev_delay_delete(args.client,
1093                                   name=args.name)
1094
1095    p = subparsers.add_parser('bdev_delay_delete', help='Delete a delay bdev')
1096    p.add_argument('name', help='delay bdev name')
1097    p.set_defaults(func=bdev_delay_delete)
1098
1099    def bdev_delay_update_latency(args):
1100        print_json(rpc.bdev.bdev_delay_update_latency(args.client,
1101                                                      delay_bdev_name=args.delay_bdev_name,
1102                                                      latency_type=args.latency_type,
1103                                                      latency_us=args.latency_us))
1104    p = subparsers.add_parser('bdev_delay_update_latency',
1105                              help='Update one of the latency values for a given delay bdev')
1106    p.add_argument('delay_bdev_name', help='The name of the given delay bdev')
1107    p.add_argument('latency_type', help='one of: avg_read, avg_write, p99_read, p99_write. No other values accepted.')
1108    p.add_argument('latency_us', help='new latency value in microseconds.', type=int)
1109    p.set_defaults(func=bdev_delay_update_latency)
1110
1111    def bdev_error_create(args):
1112        print_json(rpc.bdev.bdev_error_create(args.client,
1113                                              base_name=args.base_name,
1114                                              uuid=args.uuid))
1115
1116    p = subparsers.add_parser('bdev_error_create', help='Add bdev with error injection backend')
1117    p.add_argument('base_name', help='base bdev name')
1118    p.add_argument('--uuid', help='UUID for this bdev', required=False)
1119    p.set_defaults(func=bdev_error_create)
1120
1121    def bdev_error_delete(args):
1122        rpc.bdev.bdev_error_delete(args.client,
1123                                   name=args.name)
1124
1125    p = subparsers.add_parser('bdev_error_delete', help='Delete an error bdev')
1126    p.add_argument('name', help='error bdev name')
1127    p.set_defaults(func=bdev_error_delete)
1128
1129    def bdev_iscsi_set_options(args):
1130        rpc.bdev.bdev_iscsi_set_options(args.client,
1131                                        timeout_sec=args.timeout_sec)
1132
1133    p = subparsers.add_parser('bdev_iscsi_set_options', help='Set options for the bdev iscsi type.')
1134    p.add_argument('-t', '--timeout-sec', help="Timeout for command, in seconds, if 0, don't track timeout.", type=int)
1135    p.set_defaults(func=bdev_iscsi_set_options)
1136
1137    def bdev_iscsi_create(args):
1138        print_json(rpc.bdev.bdev_iscsi_create(args.client,
1139                                              name=args.name,
1140                                              url=args.url,
1141                                              initiator_iqn=args.initiator_iqn))
1142
1143    p = subparsers.add_parser('bdev_iscsi_create',
1144                              help='Add bdev with iSCSI initiator backend')
1145    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
1146    p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True)
1147    p.add_argument('--url', help="iSCSI Lun URL", required=True)
1148    p.set_defaults(func=bdev_iscsi_create)
1149
1150    def bdev_iscsi_delete(args):
1151        rpc.bdev.bdev_iscsi_delete(args.client,
1152                                   name=args.name)
1153
1154    p = subparsers.add_parser('bdev_iscsi_delete', help='Delete an iSCSI bdev')
1155    p.add_argument('name', help='iSCSI bdev name')
1156    p.set_defaults(func=bdev_iscsi_delete)
1157
1158    def bdev_passthru_create(args):
1159        print_json(rpc.bdev.bdev_passthru_create(args.client,
1160                                                 base_bdev_name=args.base_bdev_name,
1161                                                 name=args.name,
1162                                                 uuid=args.uuid))
1163
1164    p = subparsers.add_parser('bdev_passthru_create', help='Add a pass through bdev on existing bdev')
1165    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
1166    p.add_argument('-p', '--name', help="Name of the pass through bdev", required=True)
1167    p.add_argument('-u', '--uuid', help="UUID of the bdev")
1168    p.set_defaults(func=bdev_passthru_create)
1169
1170    def bdev_passthru_delete(args):
1171        rpc.bdev.bdev_passthru_delete(args.client,
1172                                      name=args.name)
1173
1174    p = subparsers.add_parser('bdev_passthru_delete', help='Delete a pass through bdev')
1175    p.add_argument('name', help='pass through bdev name')
1176    p.set_defaults(func=bdev_passthru_delete)
1177
1178    def bdev_get_bdevs(args):
1179        print_dict(rpc.bdev.bdev_get_bdevs(args.client,
1180                                           name=args.name, timeout=args.timeout_ms))
1181
1182    p = subparsers.add_parser('bdev_get_bdevs',
1183                              help='Display current blockdev list or required blockdev')
1184    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
1185    p.add_argument('-t', '--timeout-ms', help="""Time in ms to wait for the bdev to appear (only used
1186    with the -b|--name option). The default timeout is 0, meaning the RPC returns immediately
1187    whether the bdev exists or not.""",
1188                   type=int, required=False)
1189    p.set_defaults(func=bdev_get_bdevs)
1190
1191    def bdev_get_iostat(args):
1192        print_dict(rpc.bdev.bdev_get_iostat(args.client,
1193                                            name=args.name,
1194                                            per_channel=args.per_channel))
1195
1196    p = subparsers.add_parser('bdev_get_iostat',
1197                              help='Display current I/O statistics of all the blockdevs or specified blockdev.')
1198    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
1199    p.add_argument('-c', '--per-channel', default=False, dest='per_channel', help='Display per channel IO stats for specified device',
1200                   action='store_true', required=False)
1201    p.set_defaults(func=bdev_get_iostat)
1202
1203    def bdev_reset_iostat(args):
1204        rpc.bdev.bdev_reset_iostat(args.client, name=args.name, mode=args.mode)
1205
1206    p = subparsers.add_parser('bdev_reset_iostat',
1207                              help='Reset I/O statistics of all the blockdevs or specified blockdev.')
1208    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
1209    p.add_argument('-m', '--mode', help="Mode to reset I/O statistics", choices=['all', 'maxmin'], required=False)
1210    p.set_defaults(func=bdev_reset_iostat)
1211
1212    def bdev_enable_histogram(args):
1213        rpc.bdev.bdev_enable_histogram(args.client, name=args.name, enable=args.enable)
1214
1215    p = subparsers.add_parser('bdev_enable_histogram',
1216                              help='Enable or disable histogram for specified bdev')
1217    p.add_argument('-e', '--enable', default=True, dest='enable', action='store_true', help='Enable histograms on specified device')
1218    p.add_argument('-d', '--disable', dest='enable', action='store_false', help='Disable histograms on specified device')
1219    p.add_argument('name', help='bdev name')
1220    p.set_defaults(func=bdev_enable_histogram)
1221
1222    def bdev_get_histogram(args):
1223        print_dict(rpc.bdev.bdev_get_histogram(args.client, name=args.name))
1224
1225    p = subparsers.add_parser('bdev_get_histogram',
1226                              help='Get histogram for specified bdev')
1227    p.add_argument('name', help='bdev name')
1228    p.set_defaults(func=bdev_get_histogram)
1229
1230    def bdev_set_qd_sampling_period(args):
1231        rpc.bdev.bdev_set_qd_sampling_period(args.client,
1232                                             name=args.name,
1233                                             period=args.period)
1234
1235    p = subparsers.add_parser('bdev_set_qd_sampling_period',
1236                              help="Enable or disable tracking of a bdev's queue depth.")
1237    p.add_argument('name', help='Blockdev name. Example: Malloc0')
1238    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
1239                   ' If set to 0, polling will be disabled.',
1240                   type=int)
1241    p.set_defaults(func=bdev_set_qd_sampling_period)
1242
1243    def bdev_set_qos_limit(args):
1244        rpc.bdev.bdev_set_qos_limit(args.client,
1245                                    name=args.name,
1246                                    rw_ios_per_sec=args.rw_ios_per_sec,
1247                                    rw_mbytes_per_sec=args.rw_mbytes_per_sec,
1248                                    r_mbytes_per_sec=args.r_mbytes_per_sec,
1249                                    w_mbytes_per_sec=args.w_mbytes_per_sec)
1250
1251    p = subparsers.add_parser('bdev_set_qos_limit',
1252                              help='Set QoS rate limit on a blockdev')
1253    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
1254    p.add_argument('--rw-ios-per-sec',
1255                   help='R/W IOs per second limit (>=1000, example: 20000). 0 means unlimited.',
1256                   type=int, required=False)
1257    p.add_argument('--rw-mbytes-per-sec',
1258                   help="R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.",
1259                   type=int, required=False)
1260    p.add_argument('--r-mbytes-per-sec',
1261                   help="Read megabytes per second limit (>=10, example: 100). 0 means unlimited.",
1262                   type=int, required=False)
1263    p.add_argument('--w-mbytes-per-sec',
1264                   help="Write megabytes per second limit (>=10, example: 100). 0 means unlimited.",
1265                   type=int, required=False)
1266    p.set_defaults(func=bdev_set_qos_limit)
1267
1268    def bdev_error_inject_error(args):
1269        rpc.bdev.bdev_error_inject_error(args.client,
1270                                         name=args.name,
1271                                         io_type=args.io_type,
1272                                         error_type=args.error_type,
1273                                         num=args.num,
1274                                         queue_depth=args.queue_depth,
1275                                         corrupt_offset=args.corrupt_offset,
1276                                         corrupt_value=args.corrupt_value)
1277
1278    p = subparsers.add_parser('bdev_error_inject_error', help='bdev inject error')
1279    p.add_argument('name', help="""the name of the error injection bdev""")
1280    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
1281    p.add_argument('error_type', help="""error_type: 'failure' 'pending' 'corrupt_data' 'nomem'""")
1282    p.add_argument(
1283        '-n', '--num', help='the number of commands you want to fail', type=int)
1284    p.add_argument(
1285        '-q', '--queue-depth', help='the queue depth at which to trigger the error', type=int)
1286    p.add_argument(
1287        '-o', '--corrupt-offset', help='the offset in bytes to xor with corrupt_value', type=int)
1288    p.add_argument(
1289        '-v', '--corrupt-value', help='the value for xor (1-255, 0 is invalid)', type=int)
1290    p.set_defaults(func=bdev_error_inject_error)
1291
1292    def bdev_nvme_apply_firmware(args):
1293        print_dict(rpc.bdev.bdev_nvme_apply_firmware(args.client,
1294                                                     bdev_name=args.bdev_name,
1295                                                     filename=args.filename))
1296
1297    p = subparsers.add_parser('bdev_nvme_apply_firmware', help='Download and commit firmware to NVMe device')
1298    p.add_argument('filename', help='filename of the firmware to download')
1299    p.add_argument('bdev_name', help='name of the NVMe device')
1300    p.set_defaults(func=bdev_nvme_apply_firmware)
1301
1302    def bdev_nvme_get_transport_statistics(args):
1303        print_dict(rpc.bdev.bdev_nvme_get_transport_statistics(args.client))
1304
1305    p = subparsers.add_parser('bdev_nvme_get_transport_statistics',
1306                              help='Get bdev_nvme poll group transport statistics')
1307    p.set_defaults(func=bdev_nvme_get_transport_statistics)
1308
1309    def bdev_nvme_get_controller_health_info(args):
1310        print_dict(rpc.bdev.bdev_nvme_get_controller_health_info(args.client,
1311                                                                 name=args.name))
1312
1313    p = subparsers.add_parser('bdev_nvme_get_controller_health_info',
1314                              help='Display health log of the required NVMe bdev controller.')
1315    p.add_argument('-c', '--name', help="Name of the NVMe bdev controller. Example: Nvme0", required=True)
1316    p.set_defaults(func=bdev_nvme_get_controller_health_info)
1317
1318    # iSCSI
1319    def iscsi_set_options(args):
1320        rpc.iscsi.iscsi_set_options(
1321            args.client,
1322            auth_file=args.auth_file,
1323            node_base=args.node_base,
1324            nop_timeout=args.nop_timeout,
1325            nop_in_interval=args.nop_in_interval,
1326            disable_chap=args.disable_chap,
1327            require_chap=args.require_chap,
1328            mutual_chap=args.mutual_chap,
1329            chap_group=args.chap_group,
1330            max_sessions=args.max_sessions,
1331            max_queue_depth=args.max_queue_depth,
1332            max_connections_per_session=args.max_connections_per_session,
1333            default_time2wait=args.default_time2wait,
1334            default_time2retain=args.default_time2retain,
1335            first_burst_length=args.first_burst_length,
1336            immediate_data=args.immediate_data,
1337            error_recovery_level=args.error_recovery_level,
1338            allow_duplicated_isid=args.allow_duplicated_isid,
1339            max_large_datain_per_connection=args.max_large_datain_per_connection,
1340            max_r2t_per_connection=args.max_r2t_per_connection,
1341            pdu_pool_size=args.pdu_pool_size,
1342            immediate_data_pool_size=args.immediate_data_pool_size,
1343            data_out_pool_size=args.data_out_pool_size)
1344
1345    p = subparsers.add_parser('iscsi_set_options',
1346                              help="""Set options of iSCSI subsystem""")
1347    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file')
1348    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
1349    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
1350    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
1351    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
1352    *** Mutually exclusive with --require-chap""", action='store_true')
1353    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
1354    *** Mutually exclusive with --disable-chap""", action='store_true')
1355    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
1356    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
1357    *** Authentication group must be precreated ***""", type=int)
1358    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
1359    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int)
1360    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
1361    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
1362    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
1363    p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int)
1364    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
1365    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
1366    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
1367    p.add_argument('-x', '--max-large-datain-per-connection', help='Max number of outstanding split read I/Os per connection', type=int)
1368    p.add_argument('-k', '--max-r2t-per-connection', help='Max number of outstanding R2Ts per connection', type=int)
1369    p.add_argument('-u', '--pdu-pool-size', help='Number of PDUs in the pool', type=int)
1370    p.add_argument('-j', '--immediate-data-pool-size', help='Number of immediate data buffers in the pool', type=int)
1371    p.add_argument('-z', '--data-out-pool-size', help='Number of data out buffers in the pool', type=int)
1372    p.set_defaults(func=iscsi_set_options)
1373
1374    def iscsi_set_discovery_auth(args):
1375        rpc.iscsi.iscsi_set_discovery_auth(
1376            args.client,
1377            disable_chap=args.disable_chap,
1378            require_chap=args.require_chap,
1379            mutual_chap=args.mutual_chap,
1380            chap_group=args.chap_group)
1381
1382    p = subparsers.add_parser('iscsi_set_discovery_auth',
1383                              help="""Set CHAP authentication for discovery session.""")
1384    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
1385    *** Mutually exclusive with --require-chap""", action='store_true')
1386    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
1387    *** Mutually exclusive with --disable-chap""", action='store_true')
1388    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
1389    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
1390    *** Authentication group must be precreated ***""", type=int)
1391    p.set_defaults(func=iscsi_set_discovery_auth)
1392
1393    def iscsi_create_auth_group(args):
1394        secrets = None
1395        if args.secrets:
1396            secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")]
1397
1398        rpc.iscsi.iscsi_create_auth_group(args.client, tag=args.tag, secrets=secrets)
1399
1400    p = subparsers.add_parser('iscsi_create_auth_group',
1401                              help='Create authentication group for CHAP authentication.')
1402    p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int)
1403    p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets
1404<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes.
1405Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False)
1406    p.set_defaults(func=iscsi_create_auth_group)
1407
1408    def iscsi_delete_auth_group(args):
1409        rpc.iscsi.iscsi_delete_auth_group(args.client, tag=args.tag)
1410
1411    p = subparsers.add_parser('iscsi_delete_auth_group',
1412                              help='Delete an authentication group.')
1413    p.add_argument('tag', help='Authentication group tag', type=int)
1414    p.set_defaults(func=iscsi_delete_auth_group)
1415
1416    def iscsi_auth_group_add_secret(args):
1417        rpc.iscsi.iscsi_auth_group_add_secret(
1418            args.client,
1419            tag=args.tag,
1420            user=args.user,
1421            secret=args.secret,
1422            muser=args.muser,
1423            msecret=args.msecret)
1424
1425    p = subparsers.add_parser('iscsi_auth_group_add_secret',
1426                              help='Add a secret to an authentication group.')
1427    p.add_argument('tag', help='Authentication group tag', type=int)
1428    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
1429    p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True)
1430    p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication')
1431    p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication')
1432    p.set_defaults(func=iscsi_auth_group_add_secret)
1433
1434    def iscsi_auth_group_remove_secret(args):
1435        rpc.iscsi.iscsi_auth_group_remove_secret(args.client, tag=args.tag, user=args.user)
1436
1437    p = subparsers.add_parser('iscsi_auth_group_remove_secret',
1438                              help='Remove a secret from an authentication group.')
1439    p.add_argument('tag', help='Authentication group tag', type=int)
1440    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
1441    p.set_defaults(func=iscsi_auth_group_remove_secret)
1442
1443    def iscsi_get_auth_groups(args):
1444        print_dict(rpc.iscsi.iscsi_get_auth_groups(args.client))
1445
1446    p = subparsers.add_parser('iscsi_get_auth_groups',
1447                              help='Display current authentication group configuration')
1448    p.set_defaults(func=iscsi_get_auth_groups)
1449
1450    def iscsi_get_portal_groups(args):
1451        print_dict(rpc.iscsi.iscsi_get_portal_groups(args.client))
1452
1453    p = subparsers.add_parser('iscsi_get_portal_groups', help='Display current portal group configuration')
1454    p.set_defaults(func=iscsi_get_portal_groups)
1455
1456    def iscsi_get_initiator_groups(args):
1457        print_dict(rpc.iscsi.iscsi_get_initiator_groups(args.client))
1458
1459    p = subparsers.add_parser('iscsi_get_initiator_groups',
1460                              help='Display current initiator group configuration')
1461    p.set_defaults(func=iscsi_get_initiator_groups)
1462
1463    def iscsi_get_target_nodes(args):
1464        print_dict(rpc.iscsi.iscsi_get_target_nodes(args.client))
1465
1466    p = subparsers.add_parser('iscsi_get_target_nodes', help='Display target nodes')
1467    p.set_defaults(func=iscsi_get_target_nodes)
1468
1469    def iscsi_create_target_node(args):
1470        luns = []
1471        for u in args.bdev_name_id_pairs.strip().split(" "):
1472            bdev_name, lun_id = u.split(":")
1473            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
1474
1475        pg_ig_maps = []
1476        for u in args.pg_ig_mappings.strip().split(" "):
1477            pg, ig = u.split(":")
1478            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1479
1480        rpc.iscsi.iscsi_create_target_node(
1481            args.client,
1482            luns=luns,
1483            pg_ig_maps=pg_ig_maps,
1484            name=args.name,
1485            alias_name=args.alias_name,
1486            queue_depth=args.queue_depth,
1487            chap_group=args.chap_group,
1488            disable_chap=args.disable_chap,
1489            require_chap=args.require_chap,
1490            mutual_chap=args.mutual_chap,
1491            header_digest=args.header_digest,
1492            data_digest=args.data_digest)
1493
1494    p = subparsers.add_parser('iscsi_create_target_node', help='Add a target node')
1495    p.add_argument('name', help='Target node name (ASCII)')
1496    p.add_argument('alias_name', help='Target node alias name (ASCII)')
1497    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
1498    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
1499    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
1500    *** The bdevs must pre-exist ***
1501    *** LUN0 (id = 0) is required ***
1502    *** bdevs names cannot contain space or colon characters ***""")
1503    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1504    Whitespace separated, quoted, mapping defined with colon
1505    separated list of "tags" (int > 0)
1506    Example: '1:1 2:2 2:1'
1507    *** The Portal/Initiator Groups must be precreated ***""")
1508    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
1509    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
1510    *** Authentication group must be precreated ***""", type=int)
1511    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
1512    *** Mutually exclusive with --require-chap ***""", action='store_true')
1513    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
1514    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1515    p.add_argument(
1516        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
1517    p.add_argument('-H', '--header-digest',
1518                   help='Header Digest should be required for this target node.', action='store_true')
1519    p.add_argument('-D', '--data-digest',
1520                   help='Data Digest should be required for this target node.', action='store_true')
1521    p.set_defaults(func=iscsi_create_target_node)
1522
1523    def iscsi_target_node_add_lun(args):
1524        rpc.iscsi.iscsi_target_node_add_lun(
1525            args.client,
1526            name=args.name,
1527            bdev_name=args.bdev_name,
1528            lun_id=args.lun_id)
1529
1530    p = subparsers.add_parser('iscsi_target_node_add_lun',
1531                              help='Add LUN to the target node')
1532    p.add_argument('name', help='Target node name (ASCII)')
1533    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
1534    *** bdev name cannot contain space or colon characters ***""")
1535    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
1536    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
1537    p.set_defaults(func=iscsi_target_node_add_lun)
1538
1539    def iscsi_target_node_set_auth(args):
1540        rpc.iscsi.iscsi_target_node_set_auth(
1541            args.client,
1542            name=args.name,
1543            chap_group=args.chap_group,
1544            disable_chap=args.disable_chap,
1545            require_chap=args.require_chap,
1546            mutual_chap=args.mutual_chap)
1547
1548    p = subparsers.add_parser('iscsi_target_node_set_auth',
1549                              help='Set CHAP authentication for the target node')
1550    p.add_argument('name', help='Target node name (ASCII)')
1551    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
1552    *** Authentication group must be precreated ***""", type=int)
1553    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
1554    *** Mutually exclusive with --require-chap ***""", action='store_true')
1555    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
1556    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1557    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
1558                   action='store_true')
1559    p.set_defaults(func=iscsi_target_node_set_auth)
1560
1561    def iscsi_target_node_add_pg_ig_maps(args):
1562        pg_ig_maps = []
1563        for u in args.pg_ig_mappings.strip().split(" "):
1564            pg, ig = u.split(":")
1565            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1566        rpc.iscsi.iscsi_target_node_add_pg_ig_maps(
1567            args.client,
1568            pg_ig_maps=pg_ig_maps,
1569            name=args.name)
1570
1571    p = subparsers.add_parser('iscsi_target_node_add_pg_ig_maps',
1572                              help='Add PG-IG maps to the target node')
1573    p.add_argument('name', help='Target node name (ASCII)')
1574    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1575    Whitespace separated, quoted, mapping defined with colon
1576    separated list of "tags" (int > 0)
1577    Example: '1:1 2:2 2:1'
1578    *** The Portal/Initiator Groups must be precreated ***""")
1579    p.set_defaults(func=iscsi_target_node_add_pg_ig_maps)
1580
1581    def iscsi_target_node_remove_pg_ig_maps(args):
1582        pg_ig_maps = []
1583        for u in args.pg_ig_mappings.strip().split(" "):
1584            pg, ig = u.split(":")
1585            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1586        rpc.iscsi.iscsi_target_node_remove_pg_ig_maps(
1587            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
1588
1589    p = subparsers.add_parser('iscsi_target_node_remove_pg_ig_maps',
1590                              help='Delete PG-IG maps from the target node')
1591    p.add_argument('name', help='Target node name (ASCII)')
1592    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1593    Whitespace separated, quoted, mapping defined with colon
1594    separated list of "tags" (int > 0)
1595    Example: '1:1 2:2 2:1'
1596    *** The Portal/Initiator Groups must be precreated ***""")
1597    p.set_defaults(func=iscsi_target_node_remove_pg_ig_maps)
1598
1599    def iscsi_target_node_set_redirect(args):
1600        rpc.iscsi.iscsi_target_node_set_redirect(
1601            args.client,
1602            name=args.name,
1603            pg_tag=args.pg_tag,
1604            redirect_host=args.redirect_host,
1605            redirect_port=args.redirect_port)
1606
1607    p = subparsers.add_parser('iscsi_target_node_set_redirect',
1608                              help="""Update redirect portal of the public portal group for the target node.
1609    Omit redirect host and port to clear previously set redirect settings.""")
1610    p.add_argument('name', help='Target node name (ASCII)')
1611    p.add_argument('pg_tag', help='Portal group tag (unique, integer > 0)', type=int)
1612    p.add_argument('-a', '--redirect-host', help='Numeric IP address for redirect portal', required=False)
1613    p.add_argument('-p', '--redirect-port', help='Numeric TCP port for redirect portal', required=False)
1614    p.set_defaults(func=iscsi_target_node_set_redirect)
1615
1616    def iscsi_target_node_request_logout(args):
1617        rpc.iscsi.iscsi_target_node_request_logout(
1618            args.client,
1619            name=args.name,
1620            pg_tag=args.pg_tag)
1621
1622    p = subparsers.add_parser('iscsi_target_node_request_logout',
1623                              help="""For the target node, request connections whose portal group tag
1624    match to logout, or request all connections if portal group tag is omitted.""")
1625    p.add_argument('name', help='Target node name (ASCII)')
1626    p.add_argument('-t', '--pg-tag', help='Portal group tag (unique, integer > 0)', type=int, required=False)
1627    p.set_defaults(func=iscsi_target_node_request_logout)
1628
1629    def iscsi_create_portal_group(args):
1630        portals = []
1631        for p in args.portal_list.strip().split(' '):
1632            ip, separator, port_cpumask = p.rpartition(':')
1633            split_port_cpumask = port_cpumask.split('@')
1634            if len(split_port_cpumask) == 1:
1635                port = port_cpumask
1636                portals.append({'host': ip, 'port': port})
1637            else:
1638                port = split_port_cpumask[0]
1639                cpumask = split_port_cpumask[1]
1640                portals.append({'host': ip, 'port': port})
1641                print("WARNING: Specifying a portal group with a CPU mask is no longer supported. Ignoring it.")
1642        rpc.iscsi.iscsi_create_portal_group(
1643            args.client,
1644            portals=portals,
1645            tag=args.tag,
1646            private=args.private,
1647            wait=args.wait)
1648
1649    p = subparsers.add_parser('iscsi_create_portal_group',
1650                              help='Add a portal group')
1651    p.add_argument(
1652        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1653    p.add_argument('portal_list', help="""List of portals in host:port format, separated by whitespace
1654    Example: '192.168.100.100:3260 192.168.100.100:3261 192.168.100.100:3262""")
1655    p.add_argument('-p', '--private', help="""Public (false) or private (true) portal group.
1656    Private portal groups do not have their portals returned by a discovery session. A public
1657    portal group may optionally specify a redirect portal for non-discovery logins. This redirect
1658    portal must be from a private portal group.""", action='store_true')
1659    p.add_argument('-w', '--wait', help="""Do not listening on portals until it is started explicitly.
1660    One major iSCSI initiator may not retry login once it failed. Hence for such initiator, listening
1661    on portals should be allowed after all associated target nodes are created.""", action='store_true')
1662    p.set_defaults(func=iscsi_create_portal_group)
1663
1664    def iscsi_start_portal_group(args):
1665        rpc.iscsi.iscsi_start_portal_group(args.client, tag=args.tag)
1666
1667    p = subparsers.add_parser('iscsi_start_portal_group',
1668                              help='Start listening on portals if it is not started yet.')
1669    p.add_argument(
1670        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1671    p.set_defaults(func=iscsi_start_portal_group)
1672
1673    def iscsi_create_initiator_group(args):
1674        initiators = []
1675        netmasks = []
1676        for i in args.initiator_list.strip().split(' '):
1677            initiators.append(i)
1678        for n in args.netmask_list.strip().split(' '):
1679            netmasks.append(n)
1680        rpc.iscsi.iscsi_create_initiator_group(
1681            args.client,
1682            tag=args.tag,
1683            initiators=initiators,
1684            netmasks=netmasks)
1685
1686    p = subparsers.add_parser('iscsi_create_initiator_group',
1687                              help='Add an initiator group')
1688    p.add_argument(
1689        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1690    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1691    enclosed in quotes.  Example: 'ANY' or 'iqn.2016-06.io.spdk:host1 iqn.2016-06.io.spdk:host2'""")
1692    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1693    Example: '255.255.0.0 255.248.0.0' etc""")
1694    p.set_defaults(func=iscsi_create_initiator_group)
1695
1696    def iscsi_initiator_group_add_initiators(args):
1697        initiators = None
1698        netmasks = None
1699        if args.initiator_list:
1700            initiators = []
1701            for i in args.initiator_list.strip().split(' '):
1702                initiators.append(i)
1703        if args.netmask_list:
1704            netmasks = []
1705            for n in args.netmask_list.strip().split(' '):
1706                netmasks.append(n)
1707        rpc.iscsi.iscsi_initiator_group_add_initiators(
1708            args.client,
1709            tag=args.tag,
1710            initiators=initiators,
1711            netmasks=netmasks)
1712
1713    p = subparsers.add_parser('iscsi_initiator_group_add_initiators',
1714                              help='Add initiators to an existing initiator group')
1715    p.add_argument(
1716        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1717    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1718    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or
1719    'iqn.2016-06.io.spdk:host1 iqn.2016-06.io.spdk:host2'""", required=False)
1720    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1721    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
1722    p.set_defaults(func=iscsi_initiator_group_add_initiators)
1723
1724    def iscsi_initiator_group_remove_initiators(args):
1725        initiators = None
1726        netmasks = None
1727        if args.initiator_list:
1728            initiators = []
1729            for i in args.initiator_list.strip().split(' '):
1730                initiators.append(i)
1731        if args.netmask_list:
1732            netmasks = []
1733            for n in args.netmask_list.strip().split(' '):
1734                netmasks.append(n)
1735        rpc.iscsi.iscsi_initiator_group_remove_initiators(
1736            args.client,
1737            tag=args.tag,
1738            initiators=initiators,
1739            netmasks=netmasks)
1740
1741    p = subparsers.add_parser('iscsi_initiator_group_remove_initiators',
1742                              help='Delete initiators from an existing initiator group')
1743    p.add_argument(
1744        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1745    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1746    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or
1747    'iqn.2016-06.io.spdk:host1 iqn.2016-06.io.spdk:host2'""", required=False)
1748    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1749    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
1750    p.set_defaults(func=iscsi_initiator_group_remove_initiators)
1751
1752    def iscsi_delete_target_node(args):
1753        rpc.iscsi.iscsi_delete_target_node(
1754            args.client, target_node_name=args.target_node_name)
1755
1756    p = subparsers.add_parser('iscsi_delete_target_node',
1757                              help='Delete a target node')
1758    p.add_argument('target_node_name',
1759                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
1760    p.set_defaults(func=iscsi_delete_target_node)
1761
1762    def iscsi_delete_portal_group(args):
1763        rpc.iscsi.iscsi_delete_portal_group(args.client, tag=args.tag)
1764
1765    p = subparsers.add_parser('iscsi_delete_portal_group',
1766                              help='Delete a portal group')
1767    p.add_argument(
1768        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1769    p.set_defaults(func=iscsi_delete_portal_group)
1770
1771    def iscsi_delete_initiator_group(args):
1772        rpc.iscsi.iscsi_delete_initiator_group(args.client, tag=args.tag)
1773
1774    p = subparsers.add_parser('iscsi_delete_initiator_group',
1775                              help='Delete an initiator group')
1776    p.add_argument(
1777        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1778    p.set_defaults(func=iscsi_delete_initiator_group)
1779
1780    def iscsi_portal_group_set_auth(args):
1781        rpc.iscsi.iscsi_portal_group_set_auth(
1782            args.client,
1783            tag=args.tag,
1784            chap_group=args.chap_group,
1785            disable_chap=args.disable_chap,
1786            require_chap=args.require_chap,
1787            mutual_chap=args.mutual_chap)
1788
1789    p = subparsers.add_parser('iscsi_portal_group_set_auth',
1790                              help='Set CHAP authentication for discovery sessions specific for the portal group')
1791    p.add_argument('tag', help='Portal group tag (unique, integer > 0)', type=int)
1792    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this portal group.
1793    *** Authentication group must be precreated ***""", type=int)
1794    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this portal group.
1795    *** Mutually exclusive with --require-chap ***""", action='store_true')
1796    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this portal group.
1797    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1798    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
1799                   action='store_true')
1800    p.set_defaults(func=iscsi_portal_group_set_auth)
1801
1802    def iscsi_get_connections(args):
1803        print_dict(rpc.iscsi.iscsi_get_connections(args.client))
1804
1805    p = subparsers.add_parser('iscsi_get_connections',
1806                              help='Display iSCSI connections')
1807    p.set_defaults(func=iscsi_get_connections)
1808
1809    def iscsi_get_options(args):
1810        print_dict(rpc.iscsi.iscsi_get_options(args.client))
1811
1812    p = subparsers.add_parser('iscsi_get_options',
1813                              help='Display iSCSI global parameters')
1814    p.set_defaults(func=iscsi_get_options)
1815
1816    def scsi_get_devices(args):
1817        print_dict(rpc.iscsi.scsi_get_devices(args.client))
1818
1819    p = subparsers.add_parser('scsi_get_devices', help='Display SCSI devices')
1820    p.set_defaults(func=scsi_get_devices)
1821
1822    # trace
1823    def trace_enable_tpoint_group(args):
1824        rpc.trace.trace_enable_tpoint_group(args.client, name=args.name)
1825
1826    p = subparsers.add_parser('trace_enable_tpoint_group',
1827                              help='enable trace on a specific tpoint group')
1828    p.add_argument(
1829        'name', help="""trace group name we want to enable in tpoint_group_mask.
1830        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1831    p.set_defaults(func=trace_enable_tpoint_group)
1832
1833    def trace_disable_tpoint_group(args):
1834        rpc.trace.trace_disable_tpoint_group(args.client, name=args.name)
1835
1836    p = subparsers.add_parser('trace_disable_tpoint_group',
1837                              help='disable trace on a specific tpoint group')
1838    p.add_argument(
1839        'name', help="""trace group name we want to disable in tpoint_group_mask.
1840        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1841    p.set_defaults(func=trace_disable_tpoint_group)
1842
1843    def trace_set_tpoint_mask(args):
1844        rpc.trace.trace_set_tpoint_mask(args.client, name=args.name, tpoint_mask=args.tpoint_mask)
1845
1846    p = subparsers.add_parser('trace_set_tpoint_mask',
1847                              help='enable tracepoint mask on a specific tpoint group')
1848    p.add_argument(
1849        'name', help="""trace group name we want to enable in tpoint_group_mask.
1850        (for example "bdev" for bdev trace group)""")
1851    p.add_argument(
1852        'tpoint_mask', help="""tracepoints to be enabled inside a given trace group.
1853        (for example value of "0x3" will enable only the first two tpoints in this group)""",
1854        type=lambda m: int(m, 16))
1855    p.set_defaults(func=trace_set_tpoint_mask)
1856
1857    def trace_clear_tpoint_mask(args):
1858        rpc.trace.trace_clear_tpoint_mask(args.client, name=args.name, tpoint_mask=args.tpoint_mask)
1859
1860    p = subparsers.add_parser('trace_clear_tpoint_mask',
1861                              help='disable tracepoint mask on a specific tpoint group')
1862    p.add_argument(
1863        'name', help="""trace group name we want to disable in tpoint_group_mask.
1864        (for example "bdev" for bdev trace group)""")
1865    p.add_argument(
1866        'tpoint_mask', help="""tracepoints to be disabled inside a given trace group.
1867        (for example value of "0x3" will disable the first two tpoints in this group)""",
1868        type=lambda m: int(m, 16))
1869    p.set_defaults(func=trace_clear_tpoint_mask)
1870
1871    def trace_get_tpoint_group_mask(args):
1872        print_dict(rpc.trace.trace_get_tpoint_group_mask(args.client))
1873
1874    p = subparsers.add_parser('trace_get_tpoint_group_mask', help='get trace point group mask')
1875    p.set_defaults(func=trace_get_tpoint_group_mask)
1876
1877    def trace_get_info(args):
1878        print_dict(rpc.trace.trace_get_info(args.client))
1879
1880    p = subparsers.add_parser('trace_get_info',
1881                              help='get name of shared memory file and list of the available trace point groups')
1882    p.set_defaults(func=trace_get_info)
1883
1884    # log
1885    def log_set_flag(args):
1886        rpc.log.log_set_flag(args.client, flag=args.flag)
1887
1888    p = subparsers.add_parser('log_set_flag', help='set log flag')
1889    p.add_argument(
1890        'flag', help='log flag we want to set. (for example "nvme").')
1891    p.set_defaults(func=log_set_flag)
1892
1893    def log_clear_flag(args):
1894        rpc.log.log_clear_flag(args.client, flag=args.flag)
1895
1896    p = subparsers.add_parser('log_clear_flag', help='clear log flag')
1897    p.add_argument(
1898        'flag', help='log flag we want to clear. (for example "nvme").')
1899    p.set_defaults(func=log_clear_flag)
1900
1901    def log_get_flags(args):
1902        print_dict(rpc.log.log_get_flags(args.client))
1903
1904    p = subparsers.add_parser('log_get_flags', help='get log flags')
1905    p.set_defaults(func=log_get_flags)
1906
1907    def log_set_level(args):
1908        rpc.log.log_set_level(args.client, level=args.level)
1909
1910    p = subparsers.add_parser('log_set_level', help='set log level')
1911    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
1912    p.set_defaults(func=log_set_level)
1913
1914    def log_get_level(args):
1915        print_dict(rpc.log.log_get_level(args.client))
1916
1917    p = subparsers.add_parser('log_get_level', help='get log level')
1918    p.set_defaults(func=log_get_level)
1919
1920    def log_set_print_level(args):
1921        rpc.log.log_set_print_level(args.client, level=args.level)
1922
1923    p = subparsers.add_parser('log_set_print_level', help='set log print level')
1924    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
1925    p.set_defaults(func=log_set_print_level)
1926
1927    def log_get_print_level(args):
1928        print_dict(rpc.log.log_get_print_level(args.client))
1929
1930    p = subparsers.add_parser('log_get_print_level', help='get log print level')
1931    p.set_defaults(func=log_get_print_level)
1932
1933    # lvol
1934    def bdev_lvol_create_lvstore(args):
1935        print_json(rpc.lvol.bdev_lvol_create_lvstore(args.client,
1936                                                     bdev_name=args.bdev_name,
1937                                                     lvs_name=args.lvs_name,
1938                                                     cluster_sz=args.cluster_sz,
1939                                                     clear_method=args.clear_method,
1940                                                     num_md_pages_per_cluster_ratio=args.md_pages_per_cluster_ratio))
1941
1942    p = subparsers.add_parser('bdev_lvol_create_lvstore', help='Add logical volume store on base bdev')
1943    p.add_argument('bdev_name', help='base bdev name')
1944    p.add_argument('lvs_name', help='name for lvol store')
1945    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
1946    p.add_argument('--clear-method', help="""Change clear method for data region.
1947        Available: none, unmap, write_zeroes""", required=False)
1948    p.add_argument('-m', '--md-pages-per-cluster-ratio', help='reserved metadata pages for each cluster', type=int, required=False)
1949    p.set_defaults(func=bdev_lvol_create_lvstore)
1950
1951    def bdev_lvol_rename_lvstore(args):
1952        rpc.lvol.bdev_lvol_rename_lvstore(args.client,
1953                                          old_name=args.old_name,
1954                                          new_name=args.new_name)
1955
1956    p = subparsers.add_parser('bdev_lvol_rename_lvstore', help='Change logical volume store name')
1957    p.add_argument('old_name', help='old name')
1958    p.add_argument('new_name', help='new name')
1959    p.set_defaults(func=bdev_lvol_rename_lvstore)
1960
1961    def bdev_lvol_grow_lvstore(args):
1962        print_dict(rpc.lvol.bdev_lvol_grow_lvstore(args.client,
1963                                                   uuid=args.uuid,
1964                                                   lvs_name=args.lvs_name))
1965
1966    p = subparsers.add_parser('bdev_lvol_grow_lvstore',
1967                              help='Grow the lvstore size to the underlying bdev size')
1968    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1969    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1970    p.set_defaults(func=bdev_lvol_grow_lvstore)
1971
1972    def bdev_lvol_create(args):
1973        print_json(rpc.lvol.bdev_lvol_create(args.client,
1974                                             lvol_name=args.lvol_name,
1975                                             size_in_mib=args.size_in_mib,
1976                                             thin_provision=args.thin_provision,
1977                                             clear_method=args.clear_method,
1978                                             uuid=args.uuid,
1979                                             lvs_name=args.lvs_name))
1980
1981    p = subparsers.add_parser('bdev_lvol_create', help='Add a bdev with an logical volume backend')
1982    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1983    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1984    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
1985    p.add_argument('-c', '--clear-method', help="""Change default data clusters clear method.
1986        Available: none, unmap, write_zeroes""", required=False)
1987    p.add_argument('lvol_name', help='name for this lvol')
1988    p.add_argument('size_in_mib', help='size in MiB for this bdev', type=int)
1989    p.set_defaults(func=bdev_lvol_create)
1990
1991    def bdev_lvol_snapshot(args):
1992        print_json(rpc.lvol.bdev_lvol_snapshot(args.client,
1993                                               lvol_name=args.lvol_name,
1994                                               snapshot_name=args.snapshot_name))
1995
1996    p = subparsers.add_parser('bdev_lvol_snapshot', help='Create a snapshot of an lvol bdev')
1997    p.add_argument('lvol_name', help='lvol bdev name')
1998    p.add_argument('snapshot_name', help='lvol snapshot name')
1999    p.set_defaults(func=bdev_lvol_snapshot)
2000
2001    def bdev_lvol_clone(args):
2002        print_json(rpc.lvol.bdev_lvol_clone(args.client,
2003                                            snapshot_name=args.snapshot_name,
2004                                            clone_name=args.clone_name))
2005
2006    p = subparsers.add_parser('bdev_lvol_clone', help='Create a clone of an lvol snapshot')
2007    p.add_argument('snapshot_name', help='lvol snapshot name')
2008    p.add_argument('clone_name', help='lvol clone name')
2009    p.set_defaults(func=bdev_lvol_clone)
2010
2011    def bdev_lvol_clone_bdev(args):
2012        print_json(rpc.lvol.bdev_lvol_clone_bdev(args.client,
2013                                                 bdev=args.bdev,
2014                                                 lvs_name=args.lvs_name,
2015                                                 clone_name=args.clone_name))
2016
2017    p = subparsers.add_parser('bdev_lvol_clone_bdev',
2018                              help='Create a clone of a non-lvol bdev')
2019    p.add_argument('bdev', help='bdev to clone')
2020    p.add_argument('lvs_name', help='logical volume store name')
2021    p.add_argument('clone_name', help='lvol clone name')
2022    p.set_defaults(func=bdev_lvol_clone_bdev)
2023
2024    def bdev_lvol_rename(args):
2025        rpc.lvol.bdev_lvol_rename(args.client,
2026                                  old_name=args.old_name,
2027                                  new_name=args.new_name)
2028
2029    p = subparsers.add_parser('bdev_lvol_rename', help='Change lvol bdev name')
2030    p.add_argument('old_name', help='lvol bdev name')
2031    p.add_argument('new_name', help='new lvol name')
2032    p.set_defaults(func=bdev_lvol_rename)
2033
2034    def bdev_lvol_inflate(args):
2035        rpc.lvol.bdev_lvol_inflate(args.client,
2036                                   name=args.name)
2037
2038    p = subparsers.add_parser('bdev_lvol_inflate', help='Make thin provisioned lvol a thick provisioned lvol')
2039    p.add_argument('name', help='lvol bdev name')
2040    p.set_defaults(func=bdev_lvol_inflate)
2041
2042    def bdev_lvol_decouple_parent(args):
2043        rpc.lvol.bdev_lvol_decouple_parent(args.client,
2044                                           name=args.name)
2045
2046    p = subparsers.add_parser('bdev_lvol_decouple_parent', help='Decouple parent of lvol')
2047    p.add_argument('name', help='lvol bdev name')
2048    p.set_defaults(func=bdev_lvol_decouple_parent)
2049
2050    def bdev_lvol_resize(args):
2051        rpc.lvol.bdev_lvol_resize(args.client,
2052                                  name=args.name,
2053                                  size_in_mib=args.size_in_mib)
2054
2055    p = subparsers.add_parser('bdev_lvol_resize', help='Resize existing lvol bdev')
2056    p.add_argument('name', help='lvol bdev name')
2057    p.add_argument('size_in_mib', help='new size in MiB for this bdev', type=int)
2058    p.set_defaults(func=bdev_lvol_resize)
2059
2060    def bdev_lvol_set_read_only(args):
2061        rpc.lvol.bdev_lvol_set_read_only(args.client,
2062                                         name=args.name)
2063
2064    p = subparsers.add_parser('bdev_lvol_set_read_only', help='Mark lvol bdev as read only')
2065    p.add_argument('name', help='lvol bdev name')
2066    p.set_defaults(func=bdev_lvol_set_read_only)
2067
2068    def bdev_lvol_delete(args):
2069        rpc.lvol.bdev_lvol_delete(args.client,
2070                                  name=args.name)
2071
2072    p = subparsers.add_parser('bdev_lvol_delete', help='Destroy a logical volume')
2073    p.add_argument('name', help='lvol bdev name')
2074    p.set_defaults(func=bdev_lvol_delete)
2075
2076    def bdev_lvol_delete_lvstore(args):
2077        rpc.lvol.bdev_lvol_delete_lvstore(args.client,
2078                                          uuid=args.uuid,
2079                                          lvs_name=args.lvs_name)
2080
2081    p = subparsers.add_parser('bdev_lvol_delete_lvstore', help='Destroy an logical volume store')
2082    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
2083    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
2084    p.set_defaults(func=bdev_lvol_delete_lvstore)
2085
2086    def bdev_lvol_get_lvstores(args):
2087        print_dict(rpc.lvol.bdev_lvol_get_lvstores(args.client,
2088                                                   uuid=args.uuid,
2089                                                   lvs_name=args.lvs_name))
2090
2091    p = subparsers.add_parser('bdev_lvol_get_lvstores', help='Display current logical volume store list')
2092    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
2093    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
2094    p.set_defaults(func=bdev_lvol_get_lvstores)
2095
2096    def bdev_lvol_get_lvols(args):
2097        print_dict(rpc.lvol.bdev_lvol_get_lvols(args.client,
2098                                                lvs_uuid=args.lvs_uuid,
2099                                                lvs_name=args.lvs_name))
2100
2101    p = subparsers.add_parser('bdev_lvol_get_lvols', help='Display current logical volume list')
2102    p.add_argument('-u', '--lvs-uuid', help='only lvols in  lvol store UUID', required=False)
2103    p.add_argument('-l', '--lvs-name', help='only lvols in lvol store name', required=False)
2104    p.set_defaults(func=bdev_lvol_get_lvols)
2105
2106    def bdev_raid_get_bdevs(args):
2107        print_json(rpc.bdev.bdev_raid_get_bdevs(args.client,
2108                                                category=args.category))
2109
2110    p = subparsers.add_parser('bdev_raid_get_bdevs',
2111                              help="""This is used to list all the raid bdev details based on the input category
2112    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
2113    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
2114    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
2115    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
2116    p.add_argument('category', help='all or online or configuring or offline')
2117    p.set_defaults(func=bdev_raid_get_bdevs)
2118
2119    def bdev_raid_create(args):
2120        base_bdevs = []
2121        for u in args.base_bdevs.strip().split(" "):
2122            base_bdevs.append(u)
2123
2124        rpc.bdev.bdev_raid_create(args.client,
2125                                  name=args.name,
2126                                  strip_size_kb=args.strip_size_kb,
2127                                  raid_level=args.raid_level,
2128                                  base_bdevs=base_bdevs,
2129                                  uuid=args.uuid)
2130    p = subparsers.add_parser('bdev_raid_create', help='Create new raid bdev')
2131    p.add_argument('-n', '--name', help='raid bdev name', required=True)
2132    p.add_argument('-z', '--strip-size-kb', help='strip size in KB', type=int)
2133    p.add_argument('-r', '--raid-level', help='raid level, raid0, raid1 and a special level concat are supported', required=True)
2134    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
2135    p.add_argument('--uuid', help='UUID for this raid bdev', required=False)
2136    p.set_defaults(func=bdev_raid_create)
2137
2138    def bdev_raid_delete(args):
2139        rpc.bdev.bdev_raid_delete(args.client,
2140                                  name=args.name)
2141    p = subparsers.add_parser('bdev_raid_delete', help='Delete existing raid bdev')
2142    p.add_argument('name', help='raid bdev name')
2143    p.set_defaults(func=bdev_raid_delete)
2144
2145    def bdev_raid_remove_base_bdev(args):
2146        rpc.bdev.bdev_raid_remove_base_bdev(args.client,
2147                                            name=args.name)
2148    p = subparsers.add_parser('bdev_raid_remove_base_bdev', help='Remove base bdev from existing raid bdev')
2149    p.add_argument('name', help='base bdev name')
2150    p.set_defaults(func=bdev_raid_remove_base_bdev)
2151
2152    # split
2153    def bdev_split_create(args):
2154        print_array(rpc.bdev.bdev_split_create(args.client,
2155                                               base_bdev=args.base_bdev,
2156                                               split_count=args.split_count,
2157                                               split_size_mb=args.split_size_mb))
2158
2159    p = subparsers.add_parser('bdev_split_create',
2160                              help="""Add given disk name to split config. If bdev with base_name
2161    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
2162    available (during examination process).""")
2163    p.add_argument('base_bdev', help='base bdev name')
2164    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int)
2165    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
2166    exceed the base bdev size.""", type=int)
2167    p.set_defaults(func=bdev_split_create)
2168
2169    def bdev_split_delete(args):
2170        rpc.bdev.bdev_split_delete(args.client,
2171                                   base_bdev=args.base_bdev)
2172
2173    p = subparsers.add_parser('bdev_split_delete', help="""Delete split config with all created splits.""")
2174    p.add_argument('base_bdev', help='base bdev name')
2175    p.set_defaults(func=bdev_split_delete)
2176
2177    # ftl
2178    def bdev_ftl_create(args):
2179        print_dict(rpc.bdev.bdev_ftl_create(args.client,
2180                                            name=args.name,
2181                                            base_bdev=args.base_bdev,
2182                                            uuid=args.uuid,
2183                                            cache=args.cache,
2184                                            overprovisioning=args.overprovisioning,
2185                                            l2p_dram_limit=args.l2p_dram_limit,
2186                                            core_mask=args.core_mask,
2187                                            fast_shutdown=args.fast_shutdown))
2188
2189    p = subparsers.add_parser('bdev_ftl_create', help='Add FTL bdev')
2190    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2191    p.add_argument('-d', '--base-bdev', help='Name of bdev used as underlying device',
2192                   required=True)
2193    p.add_argument('-u', '--uuid', help='UUID of restored bdev (not applicable when creating new '
2194                   'instance): e.g. b286d19a-0059-4709-abcd-9f7732b1567d (optional)')
2195    p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache',
2196                   required=True)
2197    p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed'
2198                   ' to user (optional); default 20', type=int)
2199    p.add_argument('--l2p-dram-limit', help='l2p size that could reside in DRAM (optional); default 2048',
2200                   type=int)
2201    p.add_argument('--core-mask', help='CPU core mask - which cores will be used for ftl core thread, '
2202                   'by default core thread will be set to the main application core (optional)')
2203    p.add_argument('-f', '--fast-shutdown', help="Enable fast shutdown", action='store_true')
2204    p.set_defaults(func=bdev_ftl_create)
2205
2206    def bdev_ftl_load(args):
2207        print_dict(rpc.bdev.bdev_ftl_load(args.client,
2208                                          name=args.name,
2209                                          base_bdev=args.base_bdev,
2210                                          uuid=args.uuid,
2211                                          cache=args.cache,
2212                                          overprovisioning=args.overprovisioning,
2213                                          l2p_dram_limit=args.l2p_dram_limit,
2214                                          core_mask=args.core_mask,
2215                                          fast_shutdown=args.fast_shutdown))
2216
2217    p = subparsers.add_parser('bdev_ftl_load', help='Load FTL bdev')
2218    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2219    p.add_argument('-d', '--base-bdev', help='Name of bdev used as underlying device',
2220                   required=True)
2221    p.add_argument('-u', '--uuid', help='UUID of restored bdev', required=True)
2222    p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache',
2223                   required=True)
2224    p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed'
2225                   ' to user (optional); default 20', type=int)
2226    p.add_argument('--l2p-dram-limit', help='l2p size that could reside in DRAM (optional); default 2048',
2227                   type=int)
2228    p.add_argument('--core-mask', help='CPU core mask - which cores will be used for ftl core thread, '
2229                   'by default core thread will be set to the main application core (optional)')
2230    p.add_argument('-f', '--fast-shutdown', help="Enable fast shutdown", action='store_true')
2231    p.set_defaults(func=bdev_ftl_load)
2232
2233    def bdev_ftl_unload(args):
2234        print_dict(rpc.bdev.bdev_ftl_unload(args.client, name=args.name, fast_shutdown=args.fast_shutdown))
2235
2236    p = subparsers.add_parser('bdev_ftl_unload', help='Unload FTL bdev')
2237    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2238    p.add_argument('-f', '--fast-shutdown', help="Fast shutdown", action='store_true')
2239    p.set_defaults(func=bdev_ftl_unload)
2240
2241    def bdev_ftl_delete(args):
2242        print_dict(rpc.bdev.bdev_ftl_delete(args.client, name=args.name, fast_shutdown=args.fast_shutdown))
2243
2244    p = subparsers.add_parser('bdev_ftl_delete', help='Delete FTL bdev')
2245    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2246    p.add_argument('-f', '--fast-shutdown', help="Fast shutdown", action='store_true')
2247    p.set_defaults(func=bdev_ftl_delete)
2248
2249    def bdev_ftl_unmap(args):
2250        print_dict(rpc.bdev.bdev_ftl_unmap(args.client, name=args.name,
2251                                           lba=args.lba,
2252                                           num_blocks=args.num_blocks))
2253
2254    p = subparsers.add_parser('bdev_ftl_unmap', help='FTL unmap')
2255    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2256    p.add_argument('--lba', help='start LBA', required=True, type=int)
2257    p.add_argument('--num-blocks', help='num blocks', required=True, type=int)
2258    p.set_defaults(func=bdev_ftl_unmap)
2259
2260    def bdev_ftl_get_stats(args):
2261        print_dict(rpc.bdev.bdev_ftl_get_stats(args.client, name=args.name))
2262
2263    p = subparsers.add_parser('bdev_ftl_get_stats', help='print ftl stats')
2264    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2265    p.set_defaults(func=bdev_ftl_get_stats)
2266
2267    # vmd
2268    def vmd_enable(args):
2269        print_dict(rpc.vmd.vmd_enable(args.client))
2270
2271    p = subparsers.add_parser('vmd_enable', aliases=['enable_vmd'], help='Enable VMD enumeration')
2272    p.set_defaults(func=vmd_enable)
2273
2274    def vmd_remove_device(args):
2275        print_dict(rpc.vmd.vmd_remove_device(args.client, addr=args.addr))
2276
2277    p = subparsers.add_parser('vmd_remove_device', help='Remove a device behind VMD')
2278    p.add_argument('addr', help='Address of the device to remove', type=str)
2279    p.set_defaults(func=vmd_remove_device)
2280
2281    def vmd_rescan(args):
2282        print_dict(rpc.vmd.vmd_rescan(args.client))
2283
2284    p = subparsers.add_parser('vmd_rescan', help='Force a rescan of the devices behind VMD')
2285    p.set_defaults(func=vmd_rescan)
2286
2287    # ublk
2288    def ublk_create_target(args):
2289        rpc.ublk.ublk_create_target(args.client,
2290                                    cpumask=args.cpumask)
2291    p = subparsers.add_parser('ublk_create_target',
2292                              help='Create spdk ublk target for ublk dev')
2293    p.add_argument('-m', '--cpumask', help='cpu mask for ublk dev')
2294    p.set_defaults(func=ublk_create_target)
2295
2296    def ublk_destroy_target(args):
2297        rpc.ublk.ublk_destroy_target(args.client)
2298    p = subparsers.add_parser('ublk_destroy_target',
2299                              help='Destroy spdk ublk target for ublk dev')
2300    p.set_defaults(func=ublk_destroy_target)
2301
2302    def ublk_start_disk(args):
2303        print(rpc.ublk.ublk_start_disk(args.client,
2304                                       bdev_name=args.bdev_name,
2305                                       ublk_id=args.ublk_id,
2306                                       num_queues=args.num_queues,
2307                                       queue_depth=args.queue_depth))
2308
2309    p = subparsers.add_parser('ublk_start_disk',
2310                              help='Export a bdev as a ublk device')
2311    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
2312    p.add_argument('ublk_id', help='ublk device id to be assigned. Example: 1.', type=int)
2313    p.add_argument('-q', '--num-queues', help="the total number of queues. Example: 1", type=int, required=False)
2314    p.add_argument('-d', '--queue-depth', help="queue depth. Example: 128", type=int, required=False)
2315    p.set_defaults(func=ublk_start_disk)
2316
2317    def ublk_stop_disk(args):
2318        rpc.ublk.ublk_stop_disk(args.client,
2319                                ublk_id=args.ublk_id)
2320
2321    p = subparsers.add_parser('ublk_stop_disk',
2322                              help='Stop a ublk device')
2323    p.add_argument('ublk_id', help='ublk device id to be deleted. Example: 1.', type=int)
2324    p.set_defaults(func=ublk_stop_disk)
2325
2326    def ublk_get_disks(args):
2327        print_dict(rpc.ublk.ublk_get_disks(args.client,
2328                                           ublk_id=args.ublk_id))
2329
2330    p = subparsers.add_parser('ublk_get_disks',
2331                              help='Display full or specified ublk device list')
2332    p.add_argument('-n', '--ublk-id', help="ublk device id. Example: 1", type=int, required=False)
2333    p.set_defaults(func=ublk_get_disks)
2334
2335    # nbd
2336    def nbd_start_disk(args):
2337        print(rpc.nbd.nbd_start_disk(args.client,
2338                                     bdev_name=args.bdev_name,
2339                                     nbd_device=args.nbd_device))
2340
2341    p = subparsers.add_parser('nbd_start_disk',
2342                              help='Export a bdev as an nbd disk')
2343    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
2344    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.', nargs='?')
2345    p.set_defaults(func=nbd_start_disk)
2346
2347    def nbd_stop_disk(args):
2348        rpc.nbd.nbd_stop_disk(args.client,
2349                              nbd_device=args.nbd_device)
2350
2351    p = subparsers.add_parser('nbd_stop_disk',
2352                              help='Stop an nbd disk')
2353    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
2354    p.set_defaults(func=nbd_stop_disk)
2355
2356    def nbd_get_disks(args):
2357        print_dict(rpc.nbd.nbd_get_disks(args.client,
2358                                         nbd_device=args.nbd_device))
2359
2360    p = subparsers.add_parser('nbd_get_disks',
2361                              help='Display full or specified nbd device list')
2362    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
2363    p.set_defaults(func=nbd_get_disks)
2364
2365    # NVMe-oF
2366    def nvmf_set_max_subsystems(args):
2367        rpc.nvmf.nvmf_set_max_subsystems(args.client,
2368                                         max_subsystems=args.max_subsystems)
2369
2370    p = subparsers.add_parser('nvmf_set_max_subsystems',
2371                              help='Set the maximum number of NVMf target subsystems')
2372    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True)
2373    p.set_defaults(func=nvmf_set_max_subsystems)
2374
2375    def nvmf_set_config(args):
2376        rpc.nvmf.nvmf_set_config(args.client,
2377                                 passthru_identify_ctrlr=args.passthru_identify_ctrlr,
2378                                 poll_groups_mask=args.poll_groups_mask,
2379                                 discovery_filter=args.discovery_filter)
2380
2381    p = subparsers.add_parser('nvmf_set_config', help='Set NVMf target config')
2382    p.add_argument('-i', '--passthru-identify-ctrlr', help="""Passthrough fields like serial number and model number
2383    when the controller has a single namespace that is an NVMe bdev""", action='store_true')
2384    p.add_argument('-m', '--poll-groups-mask', help='Set cpumask for NVMf poll groups (optional)', type=str)
2385    p.add_argument('-d', '--discovery-filter', help="""Set discovery filter (optional), possible values are: `match_any` (default) or
2386         comma separated values: `transport`, `address`, `svcid`""", type=str)
2387    p.set_defaults(func=nvmf_set_config)
2388
2389    def nvmf_create_transport(args):
2390        rpc.nvmf.nvmf_create_transport(**vars(args))
2391
2392    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
2393    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
2394    p.add_argument('-g', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2395    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
2396    p.add_argument('-m', '--max-io-qpairs-per-ctrlr', help='Max number of IO qpairs per controller', type=int)
2397    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
2398    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
2399    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
2400    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
2401    p.add_argument('-n', '--num-shared-buffers', help='The number of pooled data buffers available to the transport', type=int)
2402    p.add_argument('-b', '--buf-cache-size', help='The number of shared buffers to reserve for each poll group', type=int)
2403    p.add_argument('-z', '--zcopy', action='store_true', help='''Use zero-copy operations if the
2404    underlying bdev supports them''')
2405    p.add_argument('-d', '--num-cqe', help="""The number of CQ entries. Only used when no_srq=true.
2406    Relevant only for RDMA transport""", type=int)
2407    p.add_argument('-s', '--max-srq-depth', help='Max number of outstanding I/O per SRQ. Relevant only for RDMA transport', type=int)
2408    p.add_argument('-r', '--no-srq', action='store_true', help='Disable per-thread shared receive queue. Relevant only for RDMA transport')
2409    p.add_argument('-o', '--c2h-success', action='store_false', help='Disable C2H success optimization. Relevant only for TCP transport')
2410    p.add_argument('-f', '--dif-insert-or-strip', action='store_true', help='Enable DIF insert/strip. Relevant only for TCP transport')
2411    p.add_argument('-y', '--sock-priority', help='The sock priority of the tcp connection. Relevant only for TCP transport', type=int)
2412    p.add_argument('-l', '--acceptor-backlog', help='Pending connections allowed at one time. Relevant only for RDMA transport', type=int)
2413    p.add_argument('-x', '--abort-timeout-sec', help='Abort execution timeout value, in seconds', type=int)
2414    p.add_argument('-w', '--no-wr-batching', action='store_true', help='Disable work requests batching. Relevant only for RDMA transport')
2415    p.add_argument('-e', '--control-msg-num', help="""The number of control messages per poll group.
2416    Relevant only for TCP transport""", type=int)
2417    p.add_argument('-M', '--disable-mappable-bar0', action='store_true', help="""Disable mmap() of BAR0.
2418    Relevant only for VFIO-USER transport""")
2419    p.add_argument('-I', '--disable-adaptive-irq', action='store_true', help="""Disable adaptive interrupt feature.
2420    Relevant only for VFIO-USER transport""")
2421    p.add_argument('-S', '--disable-shadow-doorbells', action='store_true', help="""Disable shadow doorbell support.
2422    Relevant only for VFIO-USER transport""")
2423    p.add_argument('--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
2424    p.set_defaults(func=nvmf_create_transport)
2425
2426    def nvmf_get_transports(args):
2427        print_dict(rpc.nvmf.nvmf_get_transports(args.client, trtype=args.trtype, tgt_name=args.tgt_name))
2428
2429    p = subparsers.add_parser('nvmf_get_transports', help='Display nvmf transports or required transport')
2430    p.add_argument('--trtype', help='Transport type (optional)')
2431    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2432    p.set_defaults(func=nvmf_get_transports)
2433
2434    def nvmf_get_subsystems(args):
2435        print_dict(rpc.nvmf.nvmf_get_subsystems(args.client, nqn=args.nqn, tgt_name=args.tgt_name))
2436
2437    p = subparsers.add_parser('nvmf_get_subsystems', help='Display nvmf subsystems or required subsystem')
2438    p.add_argument('nqn', help='Subsystem NQN (optional)', nargs="?")
2439    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2440    p.set_defaults(func=nvmf_get_subsystems)
2441
2442    def nvmf_create_subsystem(args):
2443        rpc.nvmf.nvmf_create_subsystem(args.client,
2444                                       nqn=args.nqn,
2445                                       tgt_name=args.tgt_name,
2446                                       serial_number=args.serial_number,
2447                                       model_number=args.model_number,
2448                                       allow_any_host=args.allow_any_host,
2449                                       max_namespaces=args.max_namespaces,
2450                                       ana_reporting=args.ana_reporting,
2451                                       min_cntlid=args.min_cntlid,
2452                                       max_cntlid=args.max_cntlid)
2453
2454    p = subparsers.add_parser('nvmf_create_subsystem', help='Create an NVMe-oF subsystem')
2455    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
2456    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2457    p.add_argument("-s", "--serial-number", help="""
2458    Format:  'sn' etc
2459    Example: 'SPDK00000000000001'""")
2460    p.add_argument("-d", "--model-number", help="""
2461    Format:  'mn' etc
2462    Example: 'SPDK Controller'""")
2463    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce allowed host NQN list)")
2464    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
2465                   type=int)
2466    p.add_argument("-r", "--ana-reporting", action='store_true', help="Enable ANA reporting feature")
2467    p.add_argument("-i", "--min_cntlid", help="Minimum controller ID", type=int)
2468    p.add_argument("-I", "--max_cntlid", help="Maximum controller ID", type=int)
2469    p.set_defaults(func=nvmf_create_subsystem)
2470
2471    def nvmf_delete_subsystem(args):
2472        rpc.nvmf.nvmf_delete_subsystem(args.client,
2473                                       nqn=args.subsystem_nqn,
2474                                       tgt_name=args.tgt_name)
2475
2476    p = subparsers.add_parser('nvmf_delete_subsystem', help='Delete a nvmf subsystem')
2477    p.add_argument('subsystem_nqn',
2478                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
2479    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2480    p.set_defaults(func=nvmf_delete_subsystem)
2481
2482    def nvmf_subsystem_add_listener(args):
2483        rpc.nvmf.nvmf_subsystem_add_listener(**vars(args))
2484
2485    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
2486    p.add_argument('nqn', help='NVMe-oF subsystem NQN (\'discovery\' can be used as shortcut for discovery NQN)')
2487    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2488    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2489    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2490    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2491    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number (required for RDMA or TCP)')
2492    p.add_argument('-k', '--secure-channel', help='Immediately establish a secure channel', action="store_true")
2493    p.set_defaults(func=nvmf_subsystem_add_listener)
2494
2495    def nvmf_subsystem_remove_listener(args):
2496        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
2497                                                nqn=args.nqn,
2498                                                trtype=args.trtype,
2499                                                traddr=args.traddr,
2500                                                tgt_name=args.tgt_name,
2501                                                adrfam=args.adrfam,
2502                                                trsvcid=args.trsvcid)
2503
2504    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
2505    p.add_argument('nqn', help='NVMe-oF subsystem NQN (\'discovery\' can be used as shortcut for discovery NQN)')
2506    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2507    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2508    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2509    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2510    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number (required for TCP and RDMA transport types)')
2511    p.set_defaults(func=nvmf_subsystem_remove_listener)
2512
2513    def nvmf_subsystem_listener_set_ana_state(args):
2514        rpc.nvmf.nvmf_subsystem_listener_set_ana_state(args.client,
2515                                                       nqn=args.nqn,
2516                                                       ana_state=args.ana_state,
2517                                                       trtype=args.trtype,
2518                                                       traddr=args.traddr,
2519                                                       tgt_name=args.tgt_name,
2520                                                       adrfam=args.adrfam,
2521                                                       trsvcid=args.trsvcid,
2522                                                       anagrpid=args.anagrpid)
2523
2524    p = subparsers.add_parser('nvmf_subsystem_listener_set_ana_state', help='Set ANA state of a listener for an NVMe-oF subsystem')
2525    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2526    p.add_argument('-n', '--ana-state', help='ANA state to set: optimized, non_optimized, or inaccessible', required=True)
2527    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2528    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2529    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2530    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2531    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
2532    p.add_argument('-g', '--anagrpid', help='ANA group ID (optional)', type=int)
2533    p.set_defaults(func=nvmf_subsystem_listener_set_ana_state)
2534
2535    def nvmf_subsystem_add_ns(args):
2536        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
2537                                       nqn=args.nqn,
2538                                       bdev_name=args.bdev_name,
2539                                       tgt_name=args.tgt_name,
2540                                       ptpl_file=args.ptpl_file,
2541                                       nsid=args.nsid,
2542                                       nguid=args.nguid,
2543                                       eui64=args.eui64,
2544                                       uuid=args.uuid,
2545                                       anagrpid=args.anagrpid)
2546
2547    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
2548    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2549    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
2550    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2551    p.add_argument('-p', '--ptpl-file', help='The persistent reservation storage location (optional)', type=str)
2552    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
2553    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
2554    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
2555    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
2556    p.add_argument('-a', '--anagrpid', help='ANA group ID (optional)', type=int)
2557    p.set_defaults(func=nvmf_subsystem_add_ns)
2558
2559    def nvmf_subsystem_remove_ns(args):
2560        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
2561                                          nqn=args.nqn,
2562                                          nsid=args.nsid,
2563                                          tgt_name=args.tgt_name)
2564
2565    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
2566    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2567    p.add_argument('nsid', help='The requested NSID', type=int)
2568    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2569    p.set_defaults(func=nvmf_subsystem_remove_ns)
2570
2571    def nvmf_subsystem_add_host(args):
2572        rpc.nvmf.nvmf_subsystem_add_host(args.client,
2573                                         nqn=args.nqn,
2574                                         host=args.host,
2575                                         tgt_name=args.tgt_name,
2576                                         psk=args.psk)
2577
2578    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
2579    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2580    p.add_argument('host', help='Host NQN to allow')
2581    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2582    p.add_argument('--psk', help='Path to PSK file for TLS authentication (optional). Only applicable for TCP transport.', type=str)
2583    p.set_defaults(func=nvmf_subsystem_add_host)
2584
2585    def nvmf_subsystem_remove_host(args):
2586        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
2587                                            nqn=args.nqn,
2588                                            host=args.host,
2589                                            tgt_name=args.tgt_name)
2590
2591    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
2592    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2593    p.add_argument('host', help='Host NQN to remove')
2594    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2595    p.set_defaults(func=nvmf_subsystem_remove_host)
2596
2597    def nvmf_subsystem_allow_any_host(args):
2598        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
2599                                               nqn=args.nqn,
2600                                               disable=args.disable,
2601                                               tgt_name=args.tgt_name)
2602
2603    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
2604    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2605    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
2606    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
2607    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2608    p.set_defaults(func=nvmf_subsystem_allow_any_host)
2609
2610    def nvmf_subsystem_get_controllers(args):
2611        print_dict(rpc.nvmf.nvmf_subsystem_get_controllers(args.client,
2612                                                           nqn=args.nqn,
2613                                                           tgt_name=args.tgt_name))
2614
2615    p = subparsers.add_parser('nvmf_subsystem_get_controllers',
2616                              help='Display controllers of an NVMe-oF subsystem.')
2617    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2618    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2619    p.set_defaults(func=nvmf_subsystem_get_controllers)
2620
2621    def nvmf_subsystem_get_qpairs(args):
2622        print_dict(rpc.nvmf.nvmf_subsystem_get_qpairs(args.client,
2623                                                      nqn=args.nqn,
2624                                                      tgt_name=args.tgt_name))
2625
2626    p = subparsers.add_parser('nvmf_subsystem_get_qpairs',
2627                              help='Display queue pairs of an NVMe-oF subsystem.')
2628    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2629    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2630    p.set_defaults(func=nvmf_subsystem_get_qpairs)
2631
2632    def nvmf_subsystem_get_listeners(args):
2633        print_dict(rpc.nvmf.nvmf_subsystem_get_listeners(args.client,
2634                                                         nqn=args.nqn,
2635                                                         tgt_name=args.tgt_name))
2636
2637    p = subparsers.add_parser('nvmf_subsystem_get_listeners',
2638                              help='Display listeners of an NVMe-oF subsystem.')
2639    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2640    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2641    p.set_defaults(func=nvmf_subsystem_get_listeners)
2642
2643    def nvmf_get_stats(args):
2644        print_dict(rpc.nvmf.nvmf_get_stats(args.client, tgt_name=args.tgt_name))
2645
2646    p = subparsers.add_parser(
2647        'nvmf_get_stats', help='Display current statistics for NVMf subsystem')
2648    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2649    p.set_defaults(func=nvmf_get_stats)
2650
2651    def nvmf_set_crdt(args):
2652        print_dict(rpc.nvmf.nvmf_set_crdt(args.client, args.crdt1, args.crdt2, args.crdt3))
2653
2654    p = subparsers.add_parser(
2655        'nvmf_set_crdt',
2656        help="""Set the 3 crdt (Command Retry Delay Time) values for NVMf subsystem. All
2657        values are in units of 100 milliseconds (same as the NVM Express specification).""")
2658    p.add_argument('-t1', '--crdt1', help='Command Retry Delay Time 1, in units of 100 milliseconds', type=int)
2659    p.add_argument('-t2', '--crdt2', help='Command Retry Delay Time 2, in units of 100 milliseconds', type=int)
2660    p.add_argument('-t3', '--crdt3', help='Command Retry Delay Time 3, in units of 100 milliseconds', type=int)
2661    p.set_defaults(func=nvmf_set_crdt)
2662
2663    # subsystem
2664    def framework_get_subsystems(args):
2665        print_dict(rpc.subsystem.framework_get_subsystems(args.client))
2666
2667    p = subparsers.add_parser('framework_get_subsystems',
2668                              help="""Print subsystems array in initialization order. Each subsystem
2669    entry contain (unsorted) array of subsystems it depends on.""")
2670    p.set_defaults(func=framework_get_subsystems)
2671
2672    def framework_get_config(args):
2673        print_dict(rpc.subsystem.framework_get_config(args.client, args.name))
2674
2675    p = subparsers.add_parser('framework_get_config', help="""Print subsystem configuration""")
2676    p.add_argument('name', help='Name of subsystem to query')
2677    p.set_defaults(func=framework_get_config)
2678
2679    # vhost
2680    def vhost_controller_set_coalescing(args):
2681        rpc.vhost.vhost_controller_set_coalescing(args.client,
2682                                                  ctrlr=args.ctrlr,
2683                                                  delay_base_us=args.delay_base_us,
2684                                                  iops_threshold=args.iops_threshold)
2685
2686    p = subparsers.add_parser('vhost_controller_set_coalescing', help='Set vhost controller coalescing')
2687    p.add_argument('ctrlr', help='controller name')
2688    p.add_argument('delay_base_us', help='Base delay time', type=int)
2689    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
2690    p.set_defaults(func=vhost_controller_set_coalescing)
2691
2692    def virtio_blk_create_transport(args):
2693        rpc.vhost.virtio_blk_create_transport(**vars(args))
2694
2695    p = subparsers.add_parser('virtio_blk_create_transport',
2696                              help='Create virtio blk transport')
2697    p.add_argument('name', help='transport name')
2698    p.set_defaults(func=virtio_blk_create_transport)
2699
2700    def virtio_blk_get_transports(args):
2701        print_dict(rpc.vhost.virtio_blk_get_transports(args.client, name=args.name))
2702
2703    p = subparsers.add_parser('virtio_blk_get_transports', help='Display virtio-blk transports or requested transport')
2704    p.add_argument('--name', help='Transport name (optional)', type=str)
2705    p.set_defaults(func=virtio_blk_get_transports)
2706
2707    def vhost_create_scsi_controller(args):
2708        rpc.vhost.vhost_create_scsi_controller(args.client,
2709                                               ctrlr=args.ctrlr,
2710                                               cpumask=args.cpumask)
2711
2712    p = subparsers.add_parser('vhost_create_scsi_controller', help='Add new vhost controller')
2713    p.add_argument('ctrlr', help='controller name')
2714    p.add_argument('--cpumask', help='cpu mask for this controller')
2715    p.set_defaults(func=vhost_create_scsi_controller)
2716
2717    def vhost_scsi_controller_add_target(args):
2718        print_json(rpc.vhost.vhost_scsi_controller_add_target(args.client,
2719                                                              ctrlr=args.ctrlr,
2720                                                              scsi_target_num=args.scsi_target_num,
2721                                                              bdev_name=args.bdev_name))
2722
2723    p = subparsers.add_parser('vhost_scsi_controller_add_target', help='Add lun to vhost controller')
2724    p.add_argument('ctrlr', help='controller name where add lun')
2725    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
2726    p.add_argument('bdev_name', help='bdev name')
2727    p.set_defaults(func=vhost_scsi_controller_add_target)
2728
2729    def vhost_scsi_controller_remove_target(args):
2730        rpc.vhost.vhost_scsi_controller_remove_target(args.client,
2731                                                      ctrlr=args.ctrlr,
2732                                                      scsi_target_num=args.scsi_target_num)
2733
2734    p = subparsers.add_parser('vhost_scsi_controller_remove_target',
2735                              help='Remove target from vhost controller')
2736    p.add_argument('ctrlr', help='controller name to remove target from')
2737    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
2738    p.set_defaults(func=vhost_scsi_controller_remove_target)
2739
2740    def vhost_create_blk_controller(args):
2741        rpc.vhost.vhost_create_blk_controller(**vars(args))
2742
2743    p = subparsers.add_parser('vhost_create_blk_controller', help='Add a new vhost block controller')
2744    p.add_argument('ctrlr', help='controller name')
2745    p.add_argument('dev_name', help='device name')
2746    p.add_argument('--cpumask', help='cpu mask for this controller')
2747    p.add_argument('--transport', help='virtio blk transport name (default: vhost_user_blk)')
2748    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
2749    p.add_argument("-p", "--packed_ring", action='store_true', help='Set controller as packed ring supported')
2750    p.set_defaults(func=vhost_create_blk_controller)
2751
2752    def vhost_get_controllers(args):
2753        print_dict(rpc.vhost.vhost_get_controllers(args.client, args.name))
2754
2755    p = subparsers.add_parser('vhost_get_controllers', help='List all or specific vhost controller(s)')
2756    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
2757    p.set_defaults(func=vhost_get_controllers)
2758
2759    def vhost_delete_controller(args):
2760        rpc.vhost.vhost_delete_controller(args.client,
2761                                          ctrlr=args.ctrlr)
2762
2763    p = subparsers.add_parser('vhost_delete_controller', help='Delete a vhost controller')
2764    p.add_argument('ctrlr', help='controller name')
2765    p.set_defaults(func=vhost_delete_controller)
2766
2767    def bdev_virtio_attach_controller(args):
2768        print_array(rpc.vhost.bdev_virtio_attach_controller(args.client,
2769                                                            name=args.name,
2770                                                            trtype=args.trtype,
2771                                                            traddr=args.traddr,
2772                                                            dev_type=args.dev_type,
2773                                                            vq_count=args.vq_count,
2774                                                            vq_size=args.vq_size))
2775
2776    p = subparsers.add_parser('bdev_virtio_attach_controller',
2777                              help="""Attach virtio controller using provided
2778    transport type and device type. This will also create bdevs for any block devices connected to the
2779    controller (for example, SCSI devices for a virtio-scsi controller).
2780    Result is array of added bdevs.""")
2781    p.add_argument('name', help="Use this name as base for new created bdevs")
2782    p.add_argument('-t', '--trtype',
2783                   help='Virtio target transport type: pci or user', required=True)
2784    p.add_argument('-a', '--traddr',
2785                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
2786    p.add_argument('-d', '--dev-type',
2787                   help='Device type: blk or scsi', required=True)
2788    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
2789    p.add_argument('--vq-size', help='Size of each queue', type=int)
2790    p.set_defaults(func=bdev_virtio_attach_controller)
2791
2792    def bdev_virtio_scsi_get_devices(args):
2793        print_dict(rpc.vhost.bdev_virtio_scsi_get_devices(args.client))
2794
2795    p = subparsers.add_parser('bdev_virtio_scsi_get_devices', help='List all Virtio-SCSI devices.')
2796    p.set_defaults(func=bdev_virtio_scsi_get_devices)
2797
2798    def bdev_virtio_detach_controller(args):
2799        rpc.vhost.bdev_virtio_detach_controller(args.client,
2800                                                name=args.name)
2801
2802    p = subparsers.add_parser('bdev_virtio_detach_controller', help="""Remove a Virtio device
2803    This will delete all bdevs exposed by this device""")
2804    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
2805    p.set_defaults(func=bdev_virtio_detach_controller)
2806
2807    def bdev_virtio_blk_set_hotplug(args):
2808        rpc.vhost.bdev_virtio_blk_set_hotplug(args.client, enable=args.enable, period_us=args.period_us)
2809
2810    p = subparsers.add_parser('bdev_virtio_blk_set_hotplug', help='Set hotplug options for bdev virtio_blk type.')
2811    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
2812    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
2813    p.add_argument('-r', '--period-us',
2814                   help='How often the hotplug is processed for insert and remove events', type=int)
2815    p.set_defaults(func=bdev_virtio_blk_set_hotplug)
2816
2817    # vfio-user target
2818    def vfu_tgt_set_base_path(args):
2819        rpc.vfio_user.vfu_tgt_set_base_path(args.client, path=args.path)
2820
2821    p = subparsers.add_parser('vfu_tgt_set_base_path', help='Set socket base path.')
2822    p.add_argument('path', help='socket base path')
2823    p.set_defaults(func=vfu_tgt_set_base_path)
2824
2825    def vfu_virtio_delete_endpoint(args):
2826        rpc.vfio_user.vfu_virtio_delete_endpoint(args.client, name=args.name)
2827
2828    p = subparsers.add_parser('vfu_virtio_delete_endpoint', help='Delete the PCI device via endpoint name.')
2829    p.add_argument('name', help='Endpoint name')
2830    p.set_defaults(func=vfu_virtio_delete_endpoint)
2831
2832    def vfu_virtio_create_blk_endpoint(args):
2833        rpc.vfio_user.vfu_virtio_create_blk_endpoint(args.client,
2834                                                     name=args.name,
2835                                                     bdev_name=args.bdev_name,
2836                                                     cpumask=args.cpumask,
2837                                                     num_queues=args.num_queues,
2838                                                     qsize=args.qsize,
2839                                                     packed_ring=args.packed_ring)
2840
2841    p = subparsers.add_parser('vfu_virtio_create_blk_endpoint', help='Create virtio-blk endpoint.')
2842    p.add_argument('name', help='Name of the endpoint')
2843    p.add_argument('--bdev-name', help='block device name', type=str, required=True)
2844    p.add_argument('--cpumask', help='CPU masks')
2845    p.add_argument('--num-queues', help='number of vrings', type=int, default=0)
2846    p.add_argument('--qsize', help='number of element for each vring', type=int, default=0)
2847    p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
2848    p.set_defaults(func=vfu_virtio_create_blk_endpoint)
2849
2850    def vfu_virtio_scsi_add_target(args):
2851        rpc.vfio_user.vfu_virtio_scsi_add_target(args.client,
2852                                                 name=args.name,
2853                                                 scsi_target_num=args.scsi_target_num,
2854                                                 bdev_name=args.bdev_name)
2855
2856    p = subparsers.add_parser('vfu_virtio_scsi_add_target', help='Attach a block device to SCSI target of PCI endpoint.')
2857    p.add_argument('name', help='Name of the endpoint')
2858    p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
2859    p.add_argument('--bdev-name', help='block device name', type=str, required=True)
2860    p.set_defaults(func=vfu_virtio_scsi_add_target)
2861
2862    def vfu_virtio_scsi_remove_target(args):
2863        rpc.vfio_user.vfu_virtio_scsi_remove_target(args.client,
2864                                                    name=args.name,
2865                                                    scsi_target_num=args.scsi_target_num)
2866
2867    p = subparsers.add_parser('vfu_virtio_scsi_remove_target', help='Remove the specified SCSI target of PCI endpoint.')
2868    p.add_argument('name', help='Name of the endpoint')
2869    p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
2870    p.set_defaults(func=vfu_virtio_scsi_remove_target)
2871
2872    def vfu_virtio_create_scsi_endpoint(args):
2873        rpc.vfio_user.vfu_virtio_create_scsi_endpoint(args.client,
2874                                                      name=args.name,
2875                                                      cpumask=args.cpumask,
2876                                                      num_io_queues=args.num_io_queues,
2877                                                      qsize=args.qsize,
2878                                                      packed_ring=args.packed_ring)
2879
2880    p = subparsers.add_parser('vfu_virtio_create_scsi_endpoint', help='Create virtio-scsi endpoint.')
2881    p.add_argument('name', help='Name of the endpoint')
2882    p.add_argument('--cpumask', help='CPU masks')
2883    p.add_argument('--num-io-queues', help='number of IO vrings', type=int, default=0)
2884    p.add_argument('--qsize', help='number of element for each vring', type=int, default=0)
2885    p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
2886    p.set_defaults(func=vfu_virtio_create_scsi_endpoint)
2887
2888    # accel_fw
2889    def accel_get_opc_assignments(args):
2890        print_dict(rpc.accel.accel_get_opc_assignments(args.client))
2891
2892    p = subparsers.add_parser('accel_get_opc_assignments', help='Get list of opcode name to module assignments.')
2893    p.set_defaults(func=accel_get_opc_assignments)
2894
2895    def accel_get_module_info(args):
2896        print_dict(rpc.accel.accel_get_module_info(args.client))
2897
2898    p = subparsers.add_parser('accel_get_module_info', aliases=['accel_get_engine_info'],
2899                              help='Get list of valid module names and their operations.')
2900    p.set_defaults(func=accel_get_module_info)
2901
2902    def accel_assign_opc(args):
2903        rpc.accel.accel_assign_opc(args.client, opname=args.opname, module=args.module)
2904
2905    p = subparsers.add_parser('accel_assign_opc', help='Manually assign an operation to a module.')
2906    p.add_argument('-o', '--opname', help='opname')
2907    p.add_argument('-m', '--module', help='name of module')
2908    p.set_defaults(func=accel_assign_opc)
2909
2910    def accel_crypto_key_create(args):
2911        print_dict(rpc.accel.accel_crypto_key_create(args.client,
2912                                                     cipher=args.cipher,
2913                                                     key=args.key,
2914                                                     key2=args.key2,
2915                                                     tweak_mode=args.tweak_mode,
2916                                                     name=args.name))
2917
2918    p = subparsers.add_parser('accel_crypto_key_create', help='Create encryption key')
2919    p.add_argument('-c', '--cipher', help='cipher', required=True)
2920    p.add_argument('-k', '--key', help='key', required=True)
2921    p.add_argument('-e', '--key2', help='key2', required=False, default=None)
2922    p.add_argument('-t', '--tweak-mode', help='tweak mode', required=False, default=None)
2923    p.add_argument('-n', '--name', help='key name', required=True)
2924    p.set_defaults(func=accel_crypto_key_create)
2925
2926    def accel_crypto_key_destroy(args):
2927        print_dict(rpc.accel.accel_crypto_key_destroy(args.client,
2928                                                      key_name=args.name))
2929
2930    p = subparsers.add_parser('accel_crypto_key_destroy', help='Destroy encryption key')
2931    p.add_argument('-n', '--name', help='key name', required=True, type=str)
2932    p.set_defaults(func=accel_crypto_key_destroy)
2933
2934    def accel_crypto_keys_get(args):
2935        print_dict(rpc.accel.accel_crypto_keys_get(args.client,
2936                                                   key_name=args.key_name))
2937
2938    p = subparsers.add_parser('accel_crypto_keys_get', help='Get a list of the crypto keys')
2939    p.add_argument('-k', '--key-name', help='Get information about a specific key', type=str)
2940    p.set_defaults(func=accel_crypto_keys_get)
2941
2942    def accel_set_driver(args):
2943        rpc.accel.accel_set_driver(args.client, name=args.name)
2944
2945    p = subparsers.add_parser('accel_set_driver', help='Select accel platform driver to execute ' +
2946                              'operation chains')
2947    p.add_argument('name', help='name of the platform driver')
2948    p.set_defaults(func=accel_set_driver)
2949
2950    def accel_set_options(args):
2951        rpc.accel.accel_set_options(args.client, args.small_cache_size, args.large_cache_size,
2952                                    args.task_count, args.sequence_count, args.buf_count)
2953
2954    p = subparsers.add_parser('accel_set_options', help='Set accel framework\'s options')
2955    p.add_argument('--small-cache-size', type=int, help='Size of the small iobuf cache')
2956    p.add_argument('--large-cache-size', type=int, help='Size of the large iobuf cache')
2957    p.add_argument('--task-count', type=int, help='Maximum number of tasks per IO channel')
2958    p.add_argument('--sequence-count', type=int, help='Maximum number of sequences per IO channel')
2959    p.add_argument('--buf-count', type=int, help='Maximum number of buffers per IO channel')
2960    p.set_defaults(func=accel_set_options)
2961
2962    def accel_get_stats(args):
2963        print_dict(rpc.accel.accel_get_stats(args.client))
2964
2965    p = subparsers.add_parser('accel_get_stats', help='Display accel framework\'s statistics')
2966    p.set_defaults(func=accel_get_stats)
2967
2968    # ioat
2969    def ioat_scan_accel_module(args):
2970        rpc.ioat.ioat_scan_accel_module(args.client)
2971
2972    p = subparsers.add_parser('ioat_scan_accel_module', aliases=['ioat_scan_accel_engine'],
2973                              help='Enable IOAT accel module offload.')
2974    p.set_defaults(func=ioat_scan_accel_module)
2975
2976    # dpdk compressdev
2977    def compressdev_scan_accel_module(args):
2978        rpc.compressdev.compressdev_scan_accel_module(args.client, pmd=args.pmd)
2979
2980    p = subparsers.add_parser('compressdev_scan_accel_module', help='Scan and enable compressdev module and set pmd option.')
2981    p.add_argument('-p', '--pmd', type=int, help='0 = auto-select, 1= QAT only, 2 = mlx5_pci only')
2982    p.set_defaults(func=compressdev_scan_accel_module)
2983
2984    # dsa
2985    def dsa_scan_accel_module(args):
2986        rpc.dsa.dsa_scan_accel_module(args.client, config_kernel_mode=args.config_kernel_mode)
2987
2988    p = subparsers.add_parser('dsa_scan_accel_module', aliases=['dsa_scan_accel_engine'],
2989                              help='Set config and enable dsa accel module offload.')
2990    p.add_argument('-k', '--config-kernel-mode', help='Use Kernel mode dsa',
2991                   action='store_true', dest='config_kernel_mode')
2992    p.set_defaults(func=dsa_scan_accel_module, config_kernel_mode=None)
2993
2994    # iaa
2995    def iaa_scan_accel_module(args):
2996        rpc.iaa.iaa_scan_accel_module(args.client)
2997
2998    p = subparsers.add_parser('iaa_scan_accel_module', aliases=['iaa_scan_accel_engine'],
2999                              help='Set config and enable iaa accel module offload.')
3000    p.set_defaults(func=iaa_scan_accel_module)
3001
3002    def dpdk_cryptodev_scan_accel_module(args):
3003        rpc.dpdk_cryptodev.dpdk_cryptodev_scan_accel_module(args.client)
3004
3005    p = subparsers.add_parser('dpdk_cryptodev_scan_accel_module',
3006                              help='Enable dpdk_cryptodev accel module offload.')
3007    p.set_defaults(func=dpdk_cryptodev_scan_accel_module)
3008
3009    def dpdk_cryptodev_set_driver(args):
3010        rpc.dpdk_cryptodev.dpdk_cryptodev_set_driver(args.client,
3011                                                     driver_name=args.driver_name)
3012
3013    p = subparsers.add_parser('dpdk_cryptodev_set_driver',
3014                              help='Set the DPDK cryptodev driver.')
3015    p.add_argument('-d', '--driver-name', help='The driver, can be one of crypto_aesni_mb, crypto_qat or mlx5_pci', type=str)
3016    p.set_defaults(func=dpdk_cryptodev_set_driver)
3017
3018    def dpdk_cryptodev_get_driver(args):
3019        print_dict(rpc.dpdk_cryptodev.dpdk_cryptodev_get_driver(args.client))
3020
3021    p = subparsers.add_parser('dpdk_cryptodev_get_driver', help='Get the DPDK cryptodev driver')
3022    p.set_defaults(func=dpdk_cryptodev_get_driver)
3023
3024    # mlx5
3025    def mlx5_scan_accel_module(args):
3026        rpc.mlx5.mlx5_scan_accel_module(args.client,
3027                                        qp_size=args.qp_size,
3028                                        num_requests=args.num_requests)
3029
3030    p = subparsers.add_parser('mlx5_scan_accel_module', help='Enable mlx5 accel module.')
3031    p.add_argument('-q', '--qp-size', type=int, help='QP size')
3032    p.add_argument('-r', '--num-requests', type=int, help='Size of the shared requests pool')
3033    p.set_defaults(func=mlx5_scan_accel_module)
3034
3035    # opal
3036    def bdev_nvme_opal_init(args):
3037        rpc.nvme.bdev_nvme_opal_init(args.client,
3038                                     nvme_ctrlr_name=args.nvme_ctrlr_name,
3039                                     password=args.password)
3040
3041    p = subparsers.add_parser('bdev_nvme_opal_init', help='take ownership and activate')
3042    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
3043    p.add_argument('-p', '--password', help='password for admin')
3044    p.set_defaults(func=bdev_nvme_opal_init)
3045
3046    def bdev_nvme_opal_revert(args):
3047        rpc.nvme.bdev_nvme_opal_revert(args.client,
3048                                       nvme_ctrlr_name=args.nvme_ctrlr_name,
3049                                       password=args.password)
3050    p = subparsers.add_parser('bdev_nvme_opal_revert', help='Revert to default factory settings')
3051    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
3052    p.add_argument('-p', '--password', help='password')
3053    p.set_defaults(func=bdev_nvme_opal_revert)
3054
3055    def bdev_opal_create(args):
3056        print_json(rpc.bdev.bdev_opal_create(args.client,
3057                                             nvme_ctrlr_name=args.nvme_ctrlr_name,
3058                                             nsid=args.nsid,
3059                                             locking_range_id=args.locking_range_id,
3060                                             range_start=args.range_start,
3061                                             range_length=args.range_length,
3062                                             password=args.password))
3063
3064    p = subparsers.add_parser('bdev_opal_create', help="""Create opal bdev on specified NVMe controller""")
3065    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name', required=True)
3066    p.add_argument('-n', '--nsid', help='namespace ID (only support nsid=1 for now)', type=int, required=True)
3067    p.add_argument('-i', '--locking-range-id', help='locking range id', type=int, required=True)
3068    p.add_argument('-s', '--range-start', help='locking range start LBA', type=int, required=True)
3069    p.add_argument('-l', '--range-length', help='locking range length (in blocks)', type=int, required=True)
3070    p.add_argument('-p', '--password', help='admin password', required=True)
3071    p.set_defaults(func=bdev_opal_create)
3072
3073    def bdev_opal_get_info(args):
3074        print_dict(rpc.bdev.bdev_opal_get_info(args.client,
3075                                               bdev_name=args.bdev_name,
3076                                               password=args.password))
3077
3078    p = subparsers.add_parser('bdev_opal_get_info', help='get opal locking range info for this bdev')
3079    p.add_argument('-b', '--bdev-name', help='opal bdev')
3080    p.add_argument('-p', '--password', help='password')
3081    p.set_defaults(func=bdev_opal_get_info)
3082
3083    def bdev_opal_delete(args):
3084        rpc.bdev.bdev_opal_delete(args.client,
3085                                  bdev_name=args.bdev_name,
3086                                  password=args.password)
3087
3088    p = subparsers.add_parser('bdev_opal_delete', help="""delete a virtual opal bdev""")
3089    p.add_argument('-b', '--bdev-name', help='opal virtual bdev', required=True)
3090    p.add_argument('-p', '--password', help='admin password', required=True)
3091    p.set_defaults(func=bdev_opal_delete)
3092
3093    def bdev_opal_new_user(args):
3094        rpc.bdev.bdev_opal_new_user(args.client,
3095                                    bdev_name=args.bdev_name,
3096                                    admin_password=args.admin_password,
3097                                    user_id=args.user_id,
3098                                    user_password=args.user_password)
3099
3100    p = subparsers.add_parser('bdev_opal_new_user', help="""Add a user to opal bdev who can set lock state for this bdev""")
3101    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
3102    p.add_argument('-p', '--admin-password', help='admin password', required=True)
3103    p.add_argument('-i', '--user-id', help='ID for new user', type=int, required=True)
3104    p.add_argument('-u', '--user-password', help='password set for this user', required=True)
3105    p.set_defaults(func=bdev_opal_new_user)
3106
3107    def bdev_opal_set_lock_state(args):
3108        rpc.bdev.bdev_opal_set_lock_state(args.client,
3109                                          bdev_name=args.bdev_name,
3110                                          user_id=args.user_id,
3111                                          password=args.password,
3112                                          lock_state=args.lock_state)
3113
3114    p = subparsers.add_parser('bdev_opal_set_lock_state', help="""set lock state for an opal bdev""")
3115    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
3116    p.add_argument('-i', '--user-id', help='ID of the user who want to set lock state, either admin or a user assigned to this bdev',
3117                   type=int, required=True)
3118    p.add_argument('-p', '--password', help='password of this user', required=True)
3119    p.add_argument('-l', '--lock-state', help='lock state to set, choose from {readwrite, readonly, rwlock}', required=True)
3120    p.set_defaults(func=bdev_opal_set_lock_state)
3121
3122    # bdev_nvme_send_cmd
3123    def bdev_nvme_send_cmd(args):
3124        print_dict(rpc.nvme.bdev_nvme_send_cmd(args.client,
3125                                               name=args.nvme_name,
3126                                               cmd_type=args.cmd_type,
3127                                               data_direction=args.data_direction,
3128                                               cmdbuf=args.cmdbuf,
3129                                               data=args.data,
3130                                               metadata=args.metadata,
3131                                               data_len=args.data_length,
3132                                               metadata_len=args.metadata_length,
3133                                               timeout_ms=args.timeout_ms))
3134
3135    p = subparsers.add_parser('bdev_nvme_send_cmd', help='NVMe passthrough cmd.')
3136    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
3137    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
3138    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
3139    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
3140    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
3141    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
3142    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
3143    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
3144    p.add_argument('-T', '--timeout-ms',
3145                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int)
3146    p.set_defaults(func=bdev_nvme_send_cmd)
3147
3148    # Notifications
3149    def notify_get_types(args):
3150        print_dict(rpc.notify.notify_get_types(args.client))
3151
3152    p = subparsers.add_parser('notify_get_types', help='List available notifications that user can subscribe to.')
3153    p.set_defaults(func=notify_get_types)
3154
3155    def notify_get_notifications(args):
3156        ret = rpc.notify.notify_get_notifications(args.client,
3157                                                  id=args.id,
3158                                                  max=args.max)
3159        print_dict(ret)
3160
3161    p = subparsers.add_parser('notify_get_notifications', help='Get notifications')
3162    p.add_argument('-i', '--id', help="""First ID to start fetching from""", type=int)
3163    p.add_argument('-n', '--max', help="""Maximum number of notifications to return in response""", type=int)
3164    p.set_defaults(func=notify_get_notifications)
3165
3166    def thread_get_stats(args):
3167        print_dict(rpc.app.thread_get_stats(args.client))
3168
3169    p = subparsers.add_parser(
3170        'thread_get_stats', help='Display current statistics of all the threads')
3171    p.set_defaults(func=thread_get_stats)
3172
3173    def thread_set_cpumask(args):
3174        ret = rpc.app.thread_set_cpumask(args.client,
3175                                         id=args.id,
3176                                         cpumask=args.cpumask)
3177    p = subparsers.add_parser('thread_set_cpumask',
3178                              help="""set the cpumask of the thread whose ID matches to the
3179    specified value. The thread may be migrated to one of the specified CPUs.""")
3180    p.add_argument('-i', '--id', type=int, help='thread ID')
3181    p.add_argument('-m', '--cpumask', help='cpumask for this thread')
3182    p.set_defaults(func=thread_set_cpumask)
3183
3184    def log_enable_timestamps(args):
3185        ret = rpc.app.log_enable_timestamps(args.client,
3186                                            enabled=args.enabled)
3187    p = subparsers.add_parser('log_enable_timestamps',
3188                              help='Enable or disable timestamps.')
3189    p.add_argument('-d', '--disable', dest='enabled', default=False, action='store_false', help="Disable timestamps")
3190    p.add_argument('-e', '--enable', dest='enabled', action='store_true', help="Enable timestamps")
3191    p.set_defaults(func=log_enable_timestamps)
3192
3193    def thread_get_pollers(args):
3194        print_dict(rpc.app.thread_get_pollers(args.client))
3195
3196    p = subparsers.add_parser(
3197        'thread_get_pollers', help='Display current pollers of all the threads')
3198    p.set_defaults(func=thread_get_pollers)
3199
3200    def thread_get_io_channels(args):
3201        print_dict(rpc.app.thread_get_io_channels(args.client))
3202
3203    p = subparsers.add_parser(
3204        'thread_get_io_channels', help='Display current IO channels of all the threads')
3205    p.set_defaults(func=thread_get_io_channels)
3206
3207    def env_dpdk_get_mem_stats(args):
3208        print_dict(rpc.env_dpdk.env_dpdk_get_mem_stats(args.client))
3209
3210    p = subparsers.add_parser(
3211        'env_dpdk_get_mem_stats', help='write the dpdk memory stats to a file.')
3212    p.set_defaults(func=env_dpdk_get_mem_stats)
3213
3214    # blobfs
3215    def blobfs_detect(args):
3216        print(rpc.blobfs.blobfs_detect(args.client,
3217                                       bdev_name=args.bdev_name))
3218
3219    p = subparsers.add_parser('blobfs_detect', help='Detect whether a blobfs exists on bdev')
3220    p.add_argument('bdev_name', help='Blockdev name to detect blobfs. Example: Malloc0.')
3221    p.set_defaults(func=blobfs_detect)
3222
3223    def blobfs_create(args):
3224        print(rpc.blobfs.blobfs_create(args.client,
3225                                       bdev_name=args.bdev_name,
3226                                       cluster_sz=args.cluster_sz))
3227
3228    p = subparsers.add_parser('blobfs_create', help='Build a blobfs on bdev')
3229    p.add_argument('bdev_name', help='Blockdev name to build blobfs. Example: Malloc0.')
3230    p.add_argument('-c', '--cluster-sz',
3231                   help="""Size of cluster in bytes (Optional). Must be multiple of 4KB page size. Default and minimal value is 1M.""")
3232    p.set_defaults(func=blobfs_create)
3233
3234    def blobfs_mount(args):
3235        print(rpc.blobfs.blobfs_mount(args.client,
3236                                      bdev_name=args.bdev_name,
3237                                      mountpoint=args.mountpoint))
3238
3239    p = subparsers.add_parser('blobfs_mount', help='Mount a blobfs on bdev to host path by FUSE')
3240    p.add_argument('bdev_name', help='Blockdev name where the blobfs is. Example: Malloc0.')
3241    p.add_argument('mountpoint', help='Mountpoint path in host to mount blobfs. Example: /mnt/.')
3242    p.set_defaults(func=blobfs_mount)
3243
3244    def blobfs_set_cache_size(args):
3245        print(rpc.blobfs.blobfs_set_cache_size(args.client,
3246                                               size_in_mb=args.size_in_mb))
3247
3248    p = subparsers.add_parser('blobfs_set_cache_size', help='Set cache size for blobfs')
3249    p.add_argument('size_in_mb', help='Cache size for blobfs in megabytes.', type=int)
3250    p.set_defaults(func=blobfs_set_cache_size)
3251
3252    # sock
3253    def sock_impl_get_options(args):
3254        print_json(rpc.sock.sock_impl_get_options(args.client,
3255                                                  impl_name=args.impl))
3256
3257    p = subparsers.add_parser('sock_impl_get_options', help="""Get options of socket layer implementation""")
3258    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3259    p.set_defaults(func=sock_impl_get_options)
3260
3261    def sock_impl_set_options(args):
3262        rpc.sock.sock_impl_set_options(args.client,
3263                                       impl_name=args.impl,
3264                                       recv_buf_size=args.recv_buf_size,
3265                                       send_buf_size=args.send_buf_size,
3266                                       enable_recv_pipe=args.enable_recv_pipe,
3267                                       enable_quickack=args.enable_quickack,
3268                                       enable_placement_id=args.enable_placement_id,
3269                                       enable_zerocopy_send_server=args.enable_zerocopy_send_server,
3270                                       enable_zerocopy_send_client=args.enable_zerocopy_send_client,
3271                                       zerocopy_threshold=args.zerocopy_threshold,
3272                                       tls_version=args.tls_version,
3273                                       enable_ktls=args.enable_ktls)
3274
3275    p = subparsers.add_parser('sock_impl_set_options', help="""Set options of socket layer implementation""")
3276    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3277    p.add_argument('-r', '--recv-buf-size', help='Size of receive buffer on socket in bytes', type=int)
3278    p.add_argument('-s', '--send-buf-size', help='Size of send buffer on socket in bytes', type=int)
3279    p.add_argument('-p', '--enable-placement-id', help='Option for placement-id. 0:disable,1:incoming_napi,2:incoming_cpu', type=int)
3280    p.add_argument('--enable-recv-pipe', help='Enable receive pipe',
3281                   action='store_true', dest='enable_recv_pipe')
3282    p.add_argument('--disable-recv-pipe', help='Disable receive pipe',
3283                   action='store_false', dest='enable_recv_pipe')
3284    p.add_argument('--enable-quickack', help='Enable quick ACK',
3285                   action='store_true', dest='enable_quickack')
3286    p.add_argument('--disable-quickack', help='Disable quick ACK',
3287                   action='store_false', dest='enable_quickack')
3288    p.add_argument('--enable-zerocopy-send-server', help='Enable zerocopy on send for server sockets',
3289                   action='store_true', dest='enable_zerocopy_send_server')
3290    p.add_argument('--disable-zerocopy-send-server', help='Disable zerocopy on send for server sockets',
3291                   action='store_false', dest='enable_zerocopy_send_server')
3292    p.add_argument('--enable-zerocopy-send-client', help='Enable zerocopy on send for client sockets',
3293                   action='store_true', dest='enable_zerocopy_send_client')
3294    p.add_argument('--disable-zerocopy-send-client', help='Disable zerocopy on send for client sockets',
3295                   action='store_false', dest='enable_zerocopy_send_client')
3296    p.add_argument('--zerocopy-threshold', help='Set zerocopy_threshold in bytes', type=int)
3297    p.add_argument('--tls-version', help='TLS protocol version', type=int)
3298    p.add_argument('--enable-ktls', help='Enable Kernel TLS',
3299                   action='store_true', dest='enable_ktls')
3300    p.add_argument('--disable-ktls', help='Disable Kernel TLS',
3301                   action='store_false', dest='enable_ktls')
3302    p.set_defaults(func=sock_impl_set_options, enable_recv_pipe=None, enable_quickack=None,
3303                   enable_placement_id=None, enable_zerocopy_send_server=None, enable_zerocopy_send_client=None,
3304                   zerocopy_threshold=None, tls_version=None, enable_ktls=None)
3305
3306    def sock_set_default_impl(args):
3307        print_json(rpc.sock.sock_set_default_impl(args.client,
3308                                                  impl_name=args.impl))
3309
3310    p = subparsers.add_parser('sock_set_default_impl', help="""Set the default sock implementation""")
3311    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3312    p.set_defaults(func=sock_set_default_impl)
3313
3314    def framework_get_pci_devices(args):
3315        def splitbuf(buf, step):
3316            return [buf[i:i+step] for i in range(0, len(buf), step)]
3317
3318        devices = rpc.subsystem.framework_get_pci_devices(args.client)
3319        if not args.format_lspci:
3320            print_json(devices)
3321        else:
3322            for devid, dev in enumerate(devices):
3323                print('{} device #{}'.format(dev['address'], devid))
3324                for lineid, line in enumerate(splitbuf(dev['config_space'], 32)):
3325                    print('{:02x}: {}'.format(lineid * 16, ' '.join(splitbuf(line.lower(), 2))))
3326                print()
3327
3328    p = subparsers.add_parser('framework_get_pci_devices', help='''Get a list of attached PCI devices''')
3329    p.add_argument('--format-lspci', help='Format the output in a way to be consumed by lspci -F',
3330                   action='store_true')
3331    p.set_defaults(func=framework_get_pci_devices)
3332
3333    # bdev_nvme_add_error_injection
3334    def bdev_nvme_add_error_injection(args):
3335        print_dict(rpc.nvme.bdev_nvme_add_error_injection(args.client,
3336                                                          name=args.nvme_name,
3337                                                          cmd_type=args.cmd_type,
3338                                                          opc=args.opc,
3339                                                          do_not_submit=args.do_not_submit,
3340                                                          timeout_in_us=args.timeout_in_us,
3341                                                          err_count=args.err_count,
3342                                                          sct=args.sct,
3343                                                          sc=args.sc))
3344    p = subparsers.add_parser('bdev_nvme_add_error_injection',
3345                              help='Add a NVMe command error injection.')
3346    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""", required=True)
3347    p.add_argument('-t', '--cmd-type', help="""Type of NVMe command. Valid values are: admin, io""", required=True)
3348    p.add_argument('-o', '--opc', help="""Opcode of the NVMe command.""", required=True, type=int)
3349    p.add_argument('-s', '--do-not-submit',
3350                   help="""Set to true if request should not be submitted to the controller""",
3351                   dest="do_not_submit", action='store_true')
3352    p.add_argument('-w', '--timeout-in-us', help="""Wait specified microseconds when do_not_submit is true""", type=int)
3353    p.add_argument('-e', '--err-count', help="""Number of matching NVMe commands to inject errors""", type=int)
3354    p.add_argument('-u', '--sct', help="""Status code type""", type=int)
3355    p.add_argument('-c', '--sc', help="""Status code""", type=int)
3356    p.set_defaults(func=bdev_nvme_add_error_injection)
3357
3358    # bdev_nvme_remove_error_injection
3359    def bdev_nvme_remove_error_injection(args):
3360        print_dict(rpc.nvme.bdev_nvme_remove_error_injection(args.client,
3361                                                             name=args.nvme_name,
3362                                                             cmd_type=args.cmd_type,
3363                                                             opc=args.opc))
3364    p = subparsers.add_parser('bdev_nvme_remove_error_injection',
3365                              help='Removes a NVMe command error injection.')
3366    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""", required=True)
3367    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""", required=True)
3368    p.add_argument('-o', '--opc', help="""Opcode of the nvme cmd.""", required=True, type=int)
3369    p.set_defaults(func=bdev_nvme_remove_error_injection)
3370
3371    def bdev_daos_create(args):
3372        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
3373        print_json(rpc.bdev.bdev_daos_create(args.client,
3374                                             num_blocks=int(num_blocks),
3375                                             block_size=args.block_size,
3376                                             name=args.name,
3377                                             uuid=args.uuid,
3378                                             pool=args.pool,
3379                                             cont=args.cont,
3380                                             oclass=args.oclass))
3381    p = subparsers.add_parser('bdev_daos_create',
3382                              help='Create a bdev with DAOS backend')
3383    p.add_argument('name', help="Name of the bdev")
3384    p.add_argument('pool', help="UUID of the DAOS pool")
3385    p.add_argument('cont', help="UUID of the DAOS container")
3386    p.add_argument(
3387        'total_size', help='Size of DAOS bdev in MB (float > 0)', type=float)
3388    p.add_argument('block_size', help='Block size for this bdev', type=int)
3389    p.add_argument('-u', '--uuid', help="UUID of the bdev")
3390    p.add_argument('-o', '--oclass', help="DAOS object class")
3391    p.set_defaults(func=bdev_daos_create)
3392
3393    def bdev_daos_delete(args):
3394        rpc.bdev.bdev_daos_delete(args.client,
3395                                  name=args.name)
3396
3397    p = subparsers.add_parser('bdev_daos_delete',
3398                              help='Delete a DAOS disk')
3399    p.add_argument('name', help='DAOS bdev name')
3400    p.set_defaults(func=bdev_daos_delete)
3401
3402    def bdev_daos_resize(args):
3403        print_json(rpc.bdev.bdev_daos_resize(args.client,
3404                                             name=args.name,
3405                                             new_size=int(args.new_size)))
3406
3407    p = subparsers.add_parser('bdev_daos_resize',
3408                              help='Resize a DAOS bdev')
3409    p.add_argument('name', help='DAOS bdev name')
3410    p.add_argument('new_size', help='new bdev size for resize operation. The unit is MiB')
3411    p.set_defaults(func=bdev_daos_resize)
3412
3413    def iobuf_set_options(args):
3414        rpc.iobuf.iobuf_set_options(args.client,
3415                                    small_pool_count=args.small_pool_count,
3416                                    large_pool_count=args.large_pool_count,
3417                                    small_bufsize=args.small_bufsize,
3418                                    large_bufsize=args.large_bufsize)
3419    p = subparsers.add_parser('iobuf_set_options', help='Set iobuf pool options')
3420    p.add_argument('--small-pool-count', help='number of small buffers in the global pool', type=int)
3421    p.add_argument('--large-pool-count', help='number of large buffers in the global pool', type=int)
3422    p.add_argument('--small-bufsize', help='size of a small buffer', type=int)
3423    p.add_argument('--large-bufsize', help='size of a large buffer', type=int)
3424    p.set_defaults(func=iobuf_set_options)
3425
3426    def iobuf_get_stats(args):
3427        print_dict(rpc.iobuf.iobuf_get_stats(args.client))
3428
3429    p = subparsers.add_parser('iobuf_get_stats', help='Display iobuf statistics')
3430    p.set_defaults(func=iobuf_get_stats)
3431
3432    def bdev_nvme_start_mdns_discovery(args):
3433        rpc.bdev.bdev_nvme_start_mdns_discovery(args.client,
3434                                                name=args.name,
3435                                                svcname=args.svcname,
3436                                                hostnqn=args.hostnqn)
3437
3438    p = subparsers.add_parser('bdev_nvme_start_mdns_discovery', help='Start mdns based automatic discovery')
3439    p.add_argument('-b', '--name', help="Name of the NVMe controller prefix for each bdev name", required=True)
3440    p.add_argument('-s', '--svcname', help='Service type to discover: e.g., _nvme-disc._tcp', required=True)
3441    p.add_argument('-q', '--hostnqn', help='NVMe-oF host subnqn')
3442    p.set_defaults(func=bdev_nvme_start_mdns_discovery)
3443
3444    def bdev_nvme_stop_mdns_discovery(args):
3445        rpc.bdev.bdev_nvme_stop_mdns_discovery(args.client, name=args.name)
3446
3447    p = subparsers.add_parser('bdev_nvme_stop_mdns_discovery', help='Stop automatic mdns discovery')
3448    p.add_argument('-b', '--name', help="Name of the service to stop", required=True)
3449    p.set_defaults(func=bdev_nvme_stop_mdns_discovery)
3450
3451    def bdev_nvme_get_mdns_discovery_info(args):
3452        print_dict(rpc.bdev.bdev_nvme_get_mdns_discovery_info(args.client))
3453
3454    p = subparsers.add_parser('bdev_nvme_get_mdns_discovery_info', help='Get information about the automatic mdns discovery')
3455    p.set_defaults(func=bdev_nvme_get_mdns_discovery_info)
3456
3457    def check_called_name(name):
3458        if name in deprecated_aliases:
3459            print("{} is deprecated, use {} instead.".format(name, deprecated_aliases[name]), file=sys.stderr)
3460
3461    class dry_run_client:
3462        def call(self, method, params=None):
3463            print("Request:\n" + json.dumps({"method": method, "params": params}, indent=2))
3464
3465    def null_print(arg):
3466        pass
3467
3468    def call_rpc_func(args):
3469        args.func(args)
3470        check_called_name(args.called_rpc_name)
3471
3472    def execute_script(parser, client, fd):
3473        executed_rpc = ""
3474        for rpc_call in map(str.rstrip, fd):
3475            if not rpc_call.strip():
3476                continue
3477            executed_rpc = "\n".join([executed_rpc, rpc_call])
3478            rpc_args = shlex.split(rpc_call)
3479            if rpc_args[0][0] == '#':
3480                # Ignore lines starting with # - treat them as comments
3481                continue
3482            args = parser.parse_args(rpc_args)
3483            args.client = client
3484            try:
3485                call_rpc_func(args)
3486            except JSONRPCException as ex:
3487                print("Exception:")
3488                print(executed_rpc.strip() + " <<<")
3489                print(ex.message)
3490                exit(1)
3491
3492    def load_plugin(args):
3493        # Create temporary parser, pull out the plugin parameter, load the module, and then run the real argument parser
3494        plugin_parser = argparse.ArgumentParser(add_help=False)
3495        plugin_parser.add_argument('--plugin', dest='rpc_plugin', help='Module name of plugin with additional RPC commands')
3496
3497        rpc_module = plugin_parser.parse_known_args()[0].rpc_plugin
3498        if args is not None:
3499            rpc_module = plugin_parser.parse_known_args(args)[0].rpc_plugin
3500
3501        if rpc_module in plugins:
3502            return
3503
3504        if rpc_module is not None:
3505            try:
3506                rpc_plugin = importlib.import_module(rpc_module)
3507                try:
3508                    rpc_plugin.spdk_rpc_plugin_initialize(subparsers)
3509                    plugins.append(rpc_module)
3510                except AttributeError:
3511                    print("Module %s does not contain 'spdk_rpc_plugin_initialize' function" % rpc_module)
3512            except ModuleNotFoundError:
3513                print("Module %s not found" % rpc_module)
3514
3515    def replace_arg_underscores(args):
3516        # All option names are defined with dashes only - for example: --tgt-name
3517        # But if user used underscores, convert them to dashes (--tgt_name => --tgt-name)
3518        # SPDK was inconsistent previously and had some options with underscores, so
3519        # doing this conversion ensures backward compatibility with older scripts.
3520        for i in range(len(args)):
3521            arg = args[i]
3522            if arg.startswith('--') and "_" in arg:
3523                opt, *vals = arg.split('=')
3524                args[i] = '='.join([opt.replace('_', '-'), *vals])
3525
3526    plugins = []
3527    load_plugin(None)
3528
3529    replace_arg_underscores(sys.argv)
3530
3531    args = parser.parse_args()
3532
3533    try:
3534        use_go_client = int(os.getenv('SPDK_JSONRPC_GO_CLIENT', 0)) == 1
3535    except ValueError:
3536        use_go_client = False
3537
3538    if sys.stdin.isatty() and not hasattr(args, 'func'):
3539        # No arguments and no data piped through stdin
3540        parser.print_help()
3541        exit(1)
3542    if args.is_server:
3543        for input in sys.stdin:
3544            cmd = shlex.split(input)
3545            replace_arg_underscores(cmd)
3546            try:
3547                load_plugin(cmd)
3548                tmp_args = parser.parse_args(cmd)
3549            except SystemExit as ex:
3550                print("**STATUS=1", flush=True)
3551                continue
3552
3553            try:
3554                if use_go_client:
3555                    tmp_args.client = rpc.client.JSONRPCGoClient(tmp_args.server_addr,
3556                                                                 log_level=getattr(logging, tmp_args.verbose.upper()))
3557                else:
3558                    tmp_args.client = rpc.client.JSONRPCClient(
3559                        tmp_args.server_addr, tmp_args.port, tmp_args.timeout,
3560                        log_level=getattr(logging, tmp_args.verbose.upper()), conn_retries=tmp_args.conn_retries)
3561                call_rpc_func(tmp_args)
3562                print("**STATUS=0", flush=True)
3563            except JSONRPCException as ex:
3564                print(ex.message)
3565                print("**STATUS=1", flush=True)
3566        exit(0)
3567    elif args.dry_run:
3568        args.client = dry_run_client()
3569        print_dict = null_print
3570        print_json = null_print
3571        print_array = null_print
3572    elif args.go_client or use_go_client:
3573        try:
3574            args.client = rpc.client.JSONRPCGoClient(args.server_addr,
3575                                                     log_level=getattr(logging, args.verbose.upper()))
3576        except JSONRPCException as ex:
3577            print(ex.message)
3578            exit(1)
3579    else:
3580        try:
3581            args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.timeout,
3582                                                   log_level=getattr(logging, args.verbose.upper()),
3583                                                   conn_retries=args.conn_retries)
3584        except JSONRPCException as ex:
3585            print(ex.message)
3586            exit(1)
3587
3588    if hasattr(args, 'func'):
3589        try:
3590            call_rpc_func(args)
3591        except JSONRPCException as ex:
3592            print(ex.message)
3593            exit(1)
3594    else:
3595        execute_script(parser, args.client, sys.stdin)
3596