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