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