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