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