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