xref: /spdk/scripts/rpc.py (revision 92595a58eb16a95c4aea95a3e32855d0fa4fd42a)
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.set_defaults(func=nvmf_subsystem_add_listener)
2450
2451    def nvmf_subsystem_remove_listener(args):
2452        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
2453                                                nqn=args.nqn,
2454                                                trtype=args.trtype,
2455                                                traddr=args.traddr,
2456                                                tgt_name=args.tgt_name,
2457                                                adrfam=args.adrfam,
2458                                                trsvcid=args.trsvcid)
2459
2460    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
2461    p.add_argument('nqn', help='NVMe-oF subsystem NQN (\'discovery\' can be used as shortcut for discovery NQN)')
2462    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2463    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2464    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2465    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2466    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number (required for TCP and RDMA transport types)')
2467    p.set_defaults(func=nvmf_subsystem_remove_listener)
2468
2469    def nvmf_subsystem_listener_set_ana_state(args):
2470        rpc.nvmf.nvmf_subsystem_listener_set_ana_state(args.client,
2471                                                       nqn=args.nqn,
2472                                                       ana_state=args.ana_state,
2473                                                       trtype=args.trtype,
2474                                                       traddr=args.traddr,
2475                                                       tgt_name=args.tgt_name,
2476                                                       adrfam=args.adrfam,
2477                                                       trsvcid=args.trsvcid,
2478                                                       anagrpid=args.anagrpid)
2479
2480    p = subparsers.add_parser('nvmf_subsystem_listener_set_ana_state', help='Set ANA state of a listener for an NVMe-oF subsystem')
2481    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2482    p.add_argument('-n', '--ana-state', help='ANA state to set: optimized, non_optimized, or inaccessible', required=True)
2483    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2484    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2485    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2486    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2487    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
2488    p.add_argument('-g', '--anagrpid', help='ANA group ID (optional)', type=int)
2489    p.set_defaults(func=nvmf_subsystem_listener_set_ana_state)
2490
2491    def nvmf_subsystem_add_ns(args):
2492        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
2493                                       nqn=args.nqn,
2494                                       bdev_name=args.bdev_name,
2495                                       tgt_name=args.tgt_name,
2496                                       ptpl_file=args.ptpl_file,
2497                                       nsid=args.nsid,
2498                                       nguid=args.nguid,
2499                                       eui64=args.eui64,
2500                                       uuid=args.uuid,
2501                                       anagrpid=args.anagrpid)
2502
2503    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
2504    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2505    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
2506    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2507    p.add_argument('-p', '--ptpl-file', help='The persistent reservation storage location (optional)', type=str)
2508    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
2509    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
2510    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
2511    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
2512    p.add_argument('-a', '--anagrpid', help='ANA group ID (optional)', type=int)
2513    p.set_defaults(func=nvmf_subsystem_add_ns)
2514
2515    def nvmf_subsystem_remove_ns(args):
2516        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
2517                                          nqn=args.nqn,
2518                                          nsid=args.nsid,
2519                                          tgt_name=args.tgt_name)
2520
2521    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
2522    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2523    p.add_argument('nsid', help='The requested NSID', type=int)
2524    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2525    p.set_defaults(func=nvmf_subsystem_remove_ns)
2526
2527    def nvmf_subsystem_add_host(args):
2528        rpc.nvmf.nvmf_subsystem_add_host(args.client,
2529                                         nqn=args.nqn,
2530                                         host=args.host,
2531                                         tgt_name=args.tgt_name)
2532
2533    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
2534    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2535    p.add_argument('host', help='Host NQN to allow')
2536    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2537    p.set_defaults(func=nvmf_subsystem_add_host)
2538
2539    def nvmf_subsystem_remove_host(args):
2540        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
2541                                            nqn=args.nqn,
2542                                            host=args.host,
2543                                            tgt_name=args.tgt_name)
2544
2545    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
2546    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2547    p.add_argument('host', help='Host NQN to remove')
2548    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2549    p.set_defaults(func=nvmf_subsystem_remove_host)
2550
2551    def nvmf_subsystem_allow_any_host(args):
2552        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
2553                                               nqn=args.nqn,
2554                                               disable=args.disable,
2555                                               tgt_name=args.tgt_name)
2556
2557    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
2558    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2559    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
2560    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
2561    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2562    p.set_defaults(func=nvmf_subsystem_allow_any_host)
2563
2564    def nvmf_subsystem_get_controllers(args):
2565        print_dict(rpc.nvmf.nvmf_subsystem_get_controllers(args.client,
2566                                                           nqn=args.nqn,
2567                                                           tgt_name=args.tgt_name))
2568
2569    p = subparsers.add_parser('nvmf_subsystem_get_controllers',
2570                              help='Display controllers of an NVMe-oF subsystem.')
2571    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2572    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2573    p.set_defaults(func=nvmf_subsystem_get_controllers)
2574
2575    def nvmf_subsystem_get_qpairs(args):
2576        print_dict(rpc.nvmf.nvmf_subsystem_get_qpairs(args.client,
2577                                                      nqn=args.nqn,
2578                                                      tgt_name=args.tgt_name))
2579
2580    p = subparsers.add_parser('nvmf_subsystem_get_qpairs',
2581                              help='Display queue pairs of an NVMe-oF subsystem.')
2582    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2583    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2584    p.set_defaults(func=nvmf_subsystem_get_qpairs)
2585
2586    def nvmf_subsystem_get_listeners(args):
2587        print_dict(rpc.nvmf.nvmf_subsystem_get_listeners(args.client,
2588                                                         nqn=args.nqn,
2589                                                         tgt_name=args.tgt_name))
2590
2591    p = subparsers.add_parser('nvmf_subsystem_get_listeners',
2592                              help='Display listeners of an NVMe-oF subsystem.')
2593    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2594    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2595    p.set_defaults(func=nvmf_subsystem_get_listeners)
2596
2597    def nvmf_get_stats(args):
2598        print_dict(rpc.nvmf.nvmf_get_stats(args.client, tgt_name=args.tgt_name))
2599
2600    p = subparsers.add_parser(
2601        'nvmf_get_stats', help='Display current statistics for NVMf subsystem')
2602    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2603    p.set_defaults(func=nvmf_get_stats)
2604
2605    def nvmf_set_crdt(args):
2606        print_dict(rpc.nvmf.nvmf_set_crdt(args.client, args.crdt1, args.crdt2, args.crdt3))
2607
2608    p = subparsers.add_parser(
2609        'nvmf_set_crdt',
2610        help="""Set the 3 crdt (Command Retry Delay Time) values for NVMf subsystem. All
2611        values are in units of 100 milliseconds (same as the NVM Express specification).""")
2612    p.add_argument('-t1', '--crdt1', help='Command Retry Delay Time 1, in units of 100 milliseconds', type=int)
2613    p.add_argument('-t2', '--crdt2', help='Command Retry Delay Time 2, in units of 100 milliseconds', type=int)
2614    p.add_argument('-t3', '--crdt3', help='Command Retry Delay Time 3, in units of 100 milliseconds', type=int)
2615    p.set_defaults(func=nvmf_set_crdt)
2616
2617    # subsystem
2618    def framework_get_subsystems(args):
2619        print_dict(rpc.subsystem.framework_get_subsystems(args.client))
2620
2621    p = subparsers.add_parser('framework_get_subsystems',
2622                              help="""Print subsystems array in initialization order. Each subsystem
2623    entry contain (unsorted) array of subsystems it depends on.""")
2624    p.set_defaults(func=framework_get_subsystems)
2625
2626    def framework_get_config(args):
2627        print_dict(rpc.subsystem.framework_get_config(args.client, args.name))
2628
2629    p = subparsers.add_parser('framework_get_config', help="""Print subsystem configuration""")
2630    p.add_argument('name', help='Name of subsystem to query')
2631    p.set_defaults(func=framework_get_config)
2632
2633    # vhost
2634    def vhost_controller_set_coalescing(args):
2635        rpc.vhost.vhost_controller_set_coalescing(args.client,
2636                                                  ctrlr=args.ctrlr,
2637                                                  delay_base_us=args.delay_base_us,
2638                                                  iops_threshold=args.iops_threshold)
2639
2640    p = subparsers.add_parser('vhost_controller_set_coalescing', help='Set vhost controller coalescing')
2641    p.add_argument('ctrlr', help='controller name')
2642    p.add_argument('delay_base_us', help='Base delay time', type=int)
2643    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
2644    p.set_defaults(func=vhost_controller_set_coalescing)
2645
2646    def virtio_blk_create_transport(args):
2647        rpc.vhost.virtio_blk_create_transport(**vars(args))
2648
2649    p = subparsers.add_parser('virtio_blk_create_transport',
2650                              help='Create virtio blk transport')
2651    p.add_argument('name', help='transport name')
2652    p.set_defaults(func=virtio_blk_create_transport)
2653
2654    def virtio_blk_get_transports(args):
2655        print_dict(rpc.vhost.virtio_blk_get_transports(args.client, name=args.name))
2656
2657    p = subparsers.add_parser('virtio_blk_get_transports', help='Display virtio-blk transports or requested transport')
2658    p.add_argument('--name', help='Transport name (optional)', type=str)
2659    p.set_defaults(func=virtio_blk_get_transports)
2660
2661    def vhost_create_scsi_controller(args):
2662        rpc.vhost.vhost_create_scsi_controller(args.client,
2663                                               ctrlr=args.ctrlr,
2664                                               cpumask=args.cpumask)
2665
2666    p = subparsers.add_parser('vhost_create_scsi_controller', help='Add new vhost controller')
2667    p.add_argument('ctrlr', help='controller name')
2668    p.add_argument('--cpumask', help='cpu mask for this controller')
2669    p.set_defaults(func=vhost_create_scsi_controller)
2670
2671    def vhost_scsi_controller_add_target(args):
2672        print_json(rpc.vhost.vhost_scsi_controller_add_target(args.client,
2673                                                              ctrlr=args.ctrlr,
2674                                                              scsi_target_num=args.scsi_target_num,
2675                                                              bdev_name=args.bdev_name))
2676
2677    p = subparsers.add_parser('vhost_scsi_controller_add_target', help='Add lun to vhost controller')
2678    p.add_argument('ctrlr', help='controller name where add lun')
2679    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
2680    p.add_argument('bdev_name', help='bdev name')
2681    p.set_defaults(func=vhost_scsi_controller_add_target)
2682
2683    def vhost_scsi_controller_remove_target(args):
2684        rpc.vhost.vhost_scsi_controller_remove_target(args.client,
2685                                                      ctrlr=args.ctrlr,
2686                                                      scsi_target_num=args.scsi_target_num)
2687
2688    p = subparsers.add_parser('vhost_scsi_controller_remove_target',
2689                              help='Remove target from vhost controller')
2690    p.add_argument('ctrlr', help='controller name to remove target from')
2691    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
2692    p.set_defaults(func=vhost_scsi_controller_remove_target)
2693
2694    def vhost_create_blk_controller(args):
2695        rpc.vhost.vhost_create_blk_controller(**vars(args))
2696
2697    p = subparsers.add_parser('vhost_create_blk_controller', help='Add a new vhost block controller')
2698    p.add_argument('ctrlr', help='controller name')
2699    p.add_argument('dev_name', help='device name')
2700    p.add_argument('--cpumask', help='cpu mask for this controller')
2701    p.add_argument('--transport', help='virtio blk transport name (default: vhost_user_blk)')
2702    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
2703    p.add_argument("-p", "--packed_ring", action='store_true', help='Set controller as packed ring supported')
2704    p.add_argument("-l", "--packed_ring_recovery", action='store_true', help='Enable packed ring live recovery')
2705    p.set_defaults(func=vhost_create_blk_controller)
2706
2707    def vhost_get_controllers(args):
2708        print_dict(rpc.vhost.vhost_get_controllers(args.client, args.name))
2709
2710    p = subparsers.add_parser('vhost_get_controllers', help='List all or specific vhost controller(s)')
2711    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
2712    p.set_defaults(func=vhost_get_controllers)
2713
2714    def vhost_delete_controller(args):
2715        rpc.vhost.vhost_delete_controller(args.client,
2716                                          ctrlr=args.ctrlr)
2717
2718    p = subparsers.add_parser('vhost_delete_controller', help='Delete a vhost controller')
2719    p.add_argument('ctrlr', help='controller name')
2720    p.set_defaults(func=vhost_delete_controller)
2721
2722    def bdev_virtio_attach_controller(args):
2723        print_array(rpc.vhost.bdev_virtio_attach_controller(args.client,
2724                                                            name=args.name,
2725                                                            trtype=args.trtype,
2726                                                            traddr=args.traddr,
2727                                                            dev_type=args.dev_type,
2728                                                            vq_count=args.vq_count,
2729                                                            vq_size=args.vq_size))
2730
2731    p = subparsers.add_parser('bdev_virtio_attach_controller',
2732                              help="""Attach virtio controller using provided
2733    transport type and device type. This will also create bdevs for any block devices connected to the
2734    controller (for example, SCSI devices for a virtio-scsi controller).
2735    Result is array of added bdevs.""")
2736    p.add_argument('name', help="Use this name as base for new created bdevs")
2737    p.add_argument('-t', '--trtype',
2738                   help='Virtio target transport type: pci or user', required=True)
2739    p.add_argument('-a', '--traddr',
2740                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
2741    p.add_argument('-d', '--dev-type',
2742                   help='Device type: blk or scsi', required=True)
2743    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
2744    p.add_argument('--vq-size', help='Size of each queue', type=int)
2745    p.set_defaults(func=bdev_virtio_attach_controller)
2746
2747    def bdev_virtio_scsi_get_devices(args):
2748        print_dict(rpc.vhost.bdev_virtio_scsi_get_devices(args.client))
2749
2750    p = subparsers.add_parser('bdev_virtio_scsi_get_devices', help='List all Virtio-SCSI devices.')
2751    p.set_defaults(func=bdev_virtio_scsi_get_devices)
2752
2753    def bdev_virtio_detach_controller(args):
2754        rpc.vhost.bdev_virtio_detach_controller(args.client,
2755                                                name=args.name)
2756
2757    p = subparsers.add_parser('bdev_virtio_detach_controller', help="""Remove a Virtio device
2758    This will delete all bdevs exposed by this device""")
2759    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
2760    p.set_defaults(func=bdev_virtio_detach_controller)
2761
2762    def bdev_virtio_blk_set_hotplug(args):
2763        rpc.vhost.bdev_virtio_blk_set_hotplug(args.client, enable=args.enable, period_us=args.period_us)
2764
2765    p = subparsers.add_parser('bdev_virtio_blk_set_hotplug', help='Set hotplug options for bdev virtio_blk type.')
2766    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
2767    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
2768    p.add_argument('-r', '--period-us',
2769                   help='How often the hotplug is processed for insert and remove events', type=int)
2770    p.set_defaults(func=bdev_virtio_blk_set_hotplug)
2771
2772    # vfio-user target
2773    def vfu_tgt_set_base_path(args):
2774        rpc.vfio_user.vfu_tgt_set_base_path(args.client, path=args.path)
2775
2776    p = subparsers.add_parser('vfu_tgt_set_base_path', help='Set socket base path.')
2777    p.add_argument('path', help='socket base path')
2778    p.set_defaults(func=vfu_tgt_set_base_path)
2779
2780    def vfu_virtio_delete_endpoint(args):
2781        rpc.vfio_user.vfu_virtio_delete_endpoint(args.client, name=args.name)
2782
2783    p = subparsers.add_parser('vfu_virtio_delete_endpoint', help='Delete the PCI device via endpoint name.')
2784    p.add_argument('name', help='Endpoint name')
2785    p.set_defaults(func=vfu_virtio_delete_endpoint)
2786
2787    def vfu_virtio_create_blk_endpoint(args):
2788        rpc.vfio_user.vfu_virtio_create_blk_endpoint(args.client,
2789                                                     name=args.name,
2790                                                     bdev_name=args.bdev_name,
2791                                                     cpumask=args.cpumask,
2792                                                     num_queues=args.num_queues,
2793                                                     qsize=args.qsize,
2794                                                     packed_ring=args.packed_ring)
2795
2796    p = subparsers.add_parser('vfu_virtio_create_blk_endpoint', help='Create virtio-blk endpoint.')
2797    p.add_argument('name', help='Name of the endpoint')
2798    p.add_argument('--bdev-name', help='block device name', type=str, required=True)
2799    p.add_argument('--cpumask', help='CPU masks')
2800    p.add_argument('--num-queues', help='number of vrings', type=int, default=0)
2801    p.add_argument('--qsize', help='number of element for each vring', type=int, default=0)
2802    p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
2803    p.set_defaults(func=vfu_virtio_create_blk_endpoint)
2804
2805    def vfu_virtio_scsi_add_target(args):
2806        rpc.vfio_user.vfu_virtio_scsi_add_target(args.client,
2807                                                 name=args.name,
2808                                                 scsi_target_num=args.scsi_target_num,
2809                                                 bdev_name=args.bdev_name)
2810
2811    p = subparsers.add_parser('vfu_virtio_scsi_add_target', help='Attach a block device to SCSI target of PCI endpoint.')
2812    p.add_argument('name', help='Name of the endpoint')
2813    p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
2814    p.add_argument('--bdev-name', help='block device name', type=str, required=True)
2815    p.set_defaults(func=vfu_virtio_scsi_add_target)
2816
2817    def vfu_virtio_scsi_remove_target(args):
2818        rpc.vfio_user.vfu_virtio_scsi_remove_target(args.client,
2819                                                    name=args.name,
2820                                                    scsi_target_num=args.scsi_target_num)
2821
2822    p = subparsers.add_parser('vfu_virtio_scsi_remove_target', help='Remove the specified SCSI target of PCI endpoint.')
2823    p.add_argument('name', help='Name of the endpoint')
2824    p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
2825    p.set_defaults(func=vfu_virtio_scsi_remove_target)
2826
2827    def vfu_virtio_create_scsi_endpoint(args):
2828        rpc.vfio_user.vfu_virtio_create_scsi_endpoint(args.client,
2829                                                      name=args.name,
2830                                                      cpumask=args.cpumask,
2831                                                      num_io_queues=args.num_io_queues,
2832                                                      qsize=args.qsize,
2833                                                      packed_ring=args.packed_ring)
2834
2835    p = subparsers.add_parser('vfu_virtio_create_scsi_endpoint', help='Create virtio-scsi endpoint.')
2836    p.add_argument('name', help='Name of the endpoint')
2837    p.add_argument('--cpumask', help='CPU masks')
2838    p.add_argument('--num-io-queues', help='number of IO vrings', type=int, default=0)
2839    p.add_argument('--qsize', help='number of element for each vring', type=int, default=0)
2840    p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
2841    p.set_defaults(func=vfu_virtio_create_scsi_endpoint)
2842
2843    # accel_fw
2844    def accel_get_opc_assignments(args):
2845        print_dict(rpc.accel.accel_get_opc_assignments(args.client))
2846
2847    p = subparsers.add_parser('accel_get_opc_assignments', help='Get list of opcode name to module assignments.')
2848    p.set_defaults(func=accel_get_opc_assignments)
2849
2850    def accel_get_module_info(args):
2851        print_dict(rpc.accel.accel_get_module_info(args.client))
2852
2853    p = subparsers.add_parser('accel_get_module_info', help='Get list of valid module names and their operations.')
2854    p.set_defaults(func=accel_get_module_info)
2855
2856    def accel_assign_opc(args):
2857        rpc.accel.accel_assign_opc(args.client, opname=args.opname, module=args.module)
2858
2859    p = subparsers.add_parser('accel_assign_opc', help='Manually assign an operation to a module.')
2860    p.add_argument('-o', '--opname', help='opname')
2861    p.add_argument('-m', '--module', help='name of module')
2862    p.set_defaults(func=accel_assign_opc)
2863
2864    def accel_crypto_key_create(args):
2865        print_dict(rpc.accel.accel_crypto_key_create(args.client,
2866                                                     cipher=args.cipher,
2867                                                     key=args.key,
2868                                                     key2=args.key2,
2869                                                     tweak_mode=args.tweak_mode,
2870                                                     name=args.name))
2871
2872    p = subparsers.add_parser('accel_crypto_key_create', help='Create encryption key')
2873    p.add_argument('-c', '--cipher', help='cipher', required=True)
2874    p.add_argument('-k', '--key', help='key', required=True)
2875    p.add_argument('-e', '--key2', help='key2', required=False, default=None)
2876    p.add_argument('-t', '--tweak-mode', help='tweak mode', required=False, default=None)
2877    p.add_argument('-n', '--name', help='key name', required=True)
2878    p.set_defaults(func=accel_crypto_key_create)
2879
2880    def accel_crypto_key_destroy(args):
2881        print_dict(rpc.accel.accel_crypto_key_destroy(args.client,
2882                                                      key_name=args.name))
2883
2884    p = subparsers.add_parser('accel_crypto_key_destroy', help='Destroy encryption key')
2885    p.add_argument('-n', '--name', help='key name', required=True, type=str)
2886    p.set_defaults(func=accel_crypto_key_destroy)
2887
2888    def accel_crypto_keys_get(args):
2889        print_dict(rpc.accel.accel_crypto_keys_get(args.client,
2890                                                   key_name=args.key_name))
2891
2892    p = subparsers.add_parser('accel_crypto_keys_get', help='Get a list of the crypto keys')
2893    p.add_argument('-k', '--key-name', help='Get information about a specific key', type=str)
2894    p.set_defaults(func=accel_crypto_keys_get)
2895
2896    def accel_set_driver(args):
2897        rpc.accel.accel_set_driver(args.client, name=args.name)
2898
2899    p = subparsers.add_parser('accel_set_driver', help='Select accel platform driver to execute ' +
2900                              'operation chains')
2901    p.add_argument('name', help='name of the platform driver')
2902    p.set_defaults(func=accel_set_driver)
2903
2904    def accel_set_options(args):
2905        rpc.accel.accel_set_options(args.client, args.small_cache_size, args.large_cache_size,
2906                                    args.task_count, args.sequence_count, args.buf_count)
2907
2908    p = subparsers.add_parser('accel_set_options', help='Set accel framework\'s options')
2909    p.add_argument('--small-cache-size', type=int, help='Size of the small iobuf cache')
2910    p.add_argument('--large-cache-size', type=int, help='Size of the large iobuf cache')
2911    p.add_argument('--task-count', type=int, help='Maximum number of tasks per IO channel')
2912    p.add_argument('--sequence-count', type=int, help='Maximum number of sequences per IO channel')
2913    p.add_argument('--buf-count', type=int, help='Maximum number of buffers per IO channel')
2914    p.set_defaults(func=accel_set_options)
2915
2916    def accel_get_stats(args):
2917        print_dict(rpc.accel.accel_get_stats(args.client))
2918
2919    p = subparsers.add_parser('accel_get_stats', help='Display accel framework\'s statistics')
2920    p.set_defaults(func=accel_get_stats)
2921
2922    # ioat
2923    def ioat_scan_accel_module(args):
2924        rpc.ioat.ioat_scan_accel_module(args.client)
2925
2926    p = subparsers.add_parser('ioat_scan_accel_module', help='Enable IOAT accel module offload.')
2927    p.set_defaults(func=ioat_scan_accel_module)
2928
2929    # dpdk compressdev
2930    def compressdev_scan_accel_module(args):
2931        rpc.compressdev.compressdev_scan_accel_module(args.client, pmd=args.pmd)
2932
2933    p = subparsers.add_parser('compressdev_scan_accel_module', help='Scan and enable compressdev module and set pmd option.')
2934    p.add_argument('-p', '--pmd', type=int, help='0 = auto-select, 1= QAT only, 2 = mlx5_pci only')
2935    p.set_defaults(func=compressdev_scan_accel_module)
2936
2937    # dsa
2938    def dsa_scan_accel_module(args):
2939        rpc.dsa.dsa_scan_accel_module(args.client, config_kernel_mode=args.config_kernel_mode)
2940
2941    p = subparsers.add_parser('dsa_scan_accel_module',
2942                              help='Set config and enable dsa accel module offload.')
2943    p.add_argument('-k', '--config-kernel-mode', help='Use Kernel mode dsa',
2944                   action='store_true', dest='config_kernel_mode')
2945    p.set_defaults(func=dsa_scan_accel_module, config_kernel_mode=None)
2946
2947    # iaa
2948    def iaa_scan_accel_module(args):
2949        rpc.iaa.iaa_scan_accel_module(args.client)
2950
2951    p = subparsers.add_parser('iaa_scan_accel_module',
2952                              help='Set config and enable iaa accel module offload.')
2953    p.set_defaults(func=iaa_scan_accel_module)
2954
2955    def dpdk_cryptodev_scan_accel_module(args):
2956        rpc.dpdk_cryptodev.dpdk_cryptodev_scan_accel_module(args.client)
2957
2958    p = subparsers.add_parser('dpdk_cryptodev_scan_accel_module',
2959                              help='Enable dpdk_cryptodev accel module offload.')
2960    p.set_defaults(func=dpdk_cryptodev_scan_accel_module)
2961
2962    def dpdk_cryptodev_set_driver(args):
2963        rpc.dpdk_cryptodev.dpdk_cryptodev_set_driver(args.client,
2964                                                     driver_name=args.driver_name)
2965
2966    p = subparsers.add_parser('dpdk_cryptodev_set_driver',
2967                              help='Set the DPDK cryptodev driver.')
2968    p.add_argument('-d', '--driver-name', help='The driver, can be one of crypto_aesni_mb, crypto_qat or mlx5_pci', type=str)
2969    p.set_defaults(func=dpdk_cryptodev_set_driver)
2970
2971    def dpdk_cryptodev_get_driver(args):
2972        print_dict(rpc.dpdk_cryptodev.dpdk_cryptodev_get_driver(args.client))
2973
2974    p = subparsers.add_parser('dpdk_cryptodev_get_driver', help='Get the DPDK cryptodev driver')
2975    p.set_defaults(func=dpdk_cryptodev_get_driver)
2976
2977    # mlx5
2978    def mlx5_scan_accel_module(args):
2979        rpc.mlx5.mlx5_scan_accel_module(args.client,
2980                                        qp_size=args.qp_size,
2981                                        num_requests=args.num_requests)
2982
2983    p = subparsers.add_parser('mlx5_scan_accel_module', help='Enable mlx5 accel module.')
2984    p.add_argument('-q', '--qp-size', type=int, help='QP size')
2985    p.add_argument('-r', '--num-requests', type=int, help='Size of the shared requests pool')
2986    p.set_defaults(func=mlx5_scan_accel_module)
2987
2988    # opal
2989    def bdev_nvme_opal_init(args):
2990        rpc.nvme.bdev_nvme_opal_init(args.client,
2991                                     nvme_ctrlr_name=args.nvme_ctrlr_name,
2992                                     password=args.password)
2993
2994    p = subparsers.add_parser('bdev_nvme_opal_init', help='take ownership and activate')
2995    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
2996    p.add_argument('-p', '--password', help='password for admin')
2997    p.set_defaults(func=bdev_nvme_opal_init)
2998
2999    def bdev_nvme_opal_revert(args):
3000        rpc.nvme.bdev_nvme_opal_revert(args.client,
3001                                       nvme_ctrlr_name=args.nvme_ctrlr_name,
3002                                       password=args.password)
3003    p = subparsers.add_parser('bdev_nvme_opal_revert', help='Revert to default factory settings')
3004    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
3005    p.add_argument('-p', '--password', help='password')
3006    p.set_defaults(func=bdev_nvme_opal_revert)
3007
3008    def bdev_opal_create(args):
3009        print_json(rpc.bdev.bdev_opal_create(args.client,
3010                                             nvme_ctrlr_name=args.nvme_ctrlr_name,
3011                                             nsid=args.nsid,
3012                                             locking_range_id=args.locking_range_id,
3013                                             range_start=args.range_start,
3014                                             range_length=args.range_length,
3015                                             password=args.password))
3016
3017    p = subparsers.add_parser('bdev_opal_create', help="""Create opal bdev on specified NVMe controller""")
3018    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name', required=True)
3019    p.add_argument('-n', '--nsid', help='namespace ID (only support nsid=1 for now)', type=int, required=True)
3020    p.add_argument('-i', '--locking-range-id', help='locking range id', type=int, required=True)
3021    p.add_argument('-s', '--range-start', help='locking range start LBA', type=int, required=True)
3022    p.add_argument('-l', '--range-length', help='locking range length (in blocks)', type=int, required=True)
3023    p.add_argument('-p', '--password', help='admin password', required=True)
3024    p.set_defaults(func=bdev_opal_create)
3025
3026    def bdev_opal_get_info(args):
3027        print_dict(rpc.bdev.bdev_opal_get_info(args.client,
3028                                               bdev_name=args.bdev_name,
3029                                               password=args.password))
3030
3031    p = subparsers.add_parser('bdev_opal_get_info', help='get opal locking range info for this bdev')
3032    p.add_argument('-b', '--bdev-name', help='opal bdev')
3033    p.add_argument('-p', '--password', help='password')
3034    p.set_defaults(func=bdev_opal_get_info)
3035
3036    def bdev_opal_delete(args):
3037        rpc.bdev.bdev_opal_delete(args.client,
3038                                  bdev_name=args.bdev_name,
3039                                  password=args.password)
3040
3041    p = subparsers.add_parser('bdev_opal_delete', help="""delete a virtual opal bdev""")
3042    p.add_argument('-b', '--bdev-name', help='opal virtual bdev', required=True)
3043    p.add_argument('-p', '--password', help='admin password', required=True)
3044    p.set_defaults(func=bdev_opal_delete)
3045
3046    def bdev_opal_new_user(args):
3047        rpc.bdev.bdev_opal_new_user(args.client,
3048                                    bdev_name=args.bdev_name,
3049                                    admin_password=args.admin_password,
3050                                    user_id=args.user_id,
3051                                    user_password=args.user_password)
3052
3053    p = subparsers.add_parser('bdev_opal_new_user', help="""Add a user to opal bdev who can set lock state for this bdev""")
3054    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
3055    p.add_argument('-p', '--admin-password', help='admin password', required=True)
3056    p.add_argument('-i', '--user-id', help='ID for new user', type=int, required=True)
3057    p.add_argument('-u', '--user-password', help='password set for this user', required=True)
3058    p.set_defaults(func=bdev_opal_new_user)
3059
3060    def bdev_opal_set_lock_state(args):
3061        rpc.bdev.bdev_opal_set_lock_state(args.client,
3062                                          bdev_name=args.bdev_name,
3063                                          user_id=args.user_id,
3064                                          password=args.password,
3065                                          lock_state=args.lock_state)
3066
3067    p = subparsers.add_parser('bdev_opal_set_lock_state', help="""set lock state for an opal bdev""")
3068    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
3069    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',
3070                   type=int, required=True)
3071    p.add_argument('-p', '--password', help='password of this user', required=True)
3072    p.add_argument('-l', '--lock-state', help='lock state to set, choose from {readwrite, readonly, rwlock}', required=True)
3073    p.set_defaults(func=bdev_opal_set_lock_state)
3074
3075    # bdev_nvme_send_cmd
3076    def bdev_nvme_send_cmd(args):
3077        print_dict(rpc.nvme.bdev_nvme_send_cmd(args.client,
3078                                               name=args.nvme_name,
3079                                               cmd_type=args.cmd_type,
3080                                               data_direction=args.data_direction,
3081                                               cmdbuf=args.cmdbuf,
3082                                               data=args.data,
3083                                               metadata=args.metadata,
3084                                               data_len=args.data_length,
3085                                               metadata_len=args.metadata_length,
3086                                               timeout_ms=args.timeout_ms))
3087
3088    p = subparsers.add_parser('bdev_nvme_send_cmd', help='NVMe passthrough cmd.')
3089    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
3090    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
3091    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
3092    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
3093    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
3094    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
3095    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
3096    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
3097    p.add_argument('-T', '--timeout-ms',
3098                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int)
3099    p.set_defaults(func=bdev_nvme_send_cmd)
3100
3101    # Notifications
3102    def notify_get_types(args):
3103        print_dict(rpc.notify.notify_get_types(args.client))
3104
3105    p = subparsers.add_parser('notify_get_types', help='List available notifications that user can subscribe to.')
3106    p.set_defaults(func=notify_get_types)
3107
3108    def notify_get_notifications(args):
3109        ret = rpc.notify.notify_get_notifications(args.client,
3110                                                  id=args.id,
3111                                                  max=args.max)
3112        print_dict(ret)
3113
3114    p = subparsers.add_parser('notify_get_notifications', help='Get notifications')
3115    p.add_argument('-i', '--id', help="""First ID to start fetching from""", type=int)
3116    p.add_argument('-n', '--max', help="""Maximum number of notifications to return in response""", type=int)
3117    p.set_defaults(func=notify_get_notifications)
3118
3119    def thread_get_stats(args):
3120        print_dict(rpc.app.thread_get_stats(args.client))
3121
3122    p = subparsers.add_parser(
3123        'thread_get_stats', help='Display current statistics of all the threads')
3124    p.set_defaults(func=thread_get_stats)
3125
3126    def thread_set_cpumask(args):
3127        ret = rpc.app.thread_set_cpumask(args.client,
3128                                         id=args.id,
3129                                         cpumask=args.cpumask)
3130    p = subparsers.add_parser('thread_set_cpumask',
3131                              help="""set the cpumask of the thread whose ID matches to the
3132    specified value. The thread may be migrated to one of the specified CPUs.""")
3133    p.add_argument('-i', '--id', type=int, help='thread ID')
3134    p.add_argument('-m', '--cpumask', help='cpumask for this thread')
3135    p.set_defaults(func=thread_set_cpumask)
3136
3137    def log_enable_timestamps(args):
3138        ret = rpc.app.log_enable_timestamps(args.client,
3139                                            enabled=args.enabled)
3140    p = subparsers.add_parser('log_enable_timestamps',
3141                              help='Enable or disable timestamps.')
3142    p.add_argument('-d', '--disable', dest='enabled', default=False, action='store_false', help="Disable timestamps")
3143    p.add_argument('-e', '--enable', dest='enabled', action='store_true', help="Enable timestamps")
3144    p.set_defaults(func=log_enable_timestamps)
3145
3146    def thread_get_pollers(args):
3147        print_dict(rpc.app.thread_get_pollers(args.client))
3148
3149    p = subparsers.add_parser(
3150        'thread_get_pollers', help='Display current pollers of all the threads')
3151    p.set_defaults(func=thread_get_pollers)
3152
3153    def thread_get_io_channels(args):
3154        print_dict(rpc.app.thread_get_io_channels(args.client))
3155
3156    p = subparsers.add_parser(
3157        'thread_get_io_channels', help='Display current IO channels of all the threads')
3158    p.set_defaults(func=thread_get_io_channels)
3159
3160    def env_dpdk_get_mem_stats(args):
3161        print_dict(rpc.env_dpdk.env_dpdk_get_mem_stats(args.client))
3162
3163    p = subparsers.add_parser(
3164        'env_dpdk_get_mem_stats', help='write the dpdk memory stats to a file.')
3165    p.set_defaults(func=env_dpdk_get_mem_stats)
3166
3167    # blobfs
3168    def blobfs_detect(args):
3169        print(rpc.blobfs.blobfs_detect(args.client,
3170                                       bdev_name=args.bdev_name))
3171
3172    p = subparsers.add_parser('blobfs_detect', help='Detect whether a blobfs exists on bdev')
3173    p.add_argument('bdev_name', help='Blockdev name to detect blobfs. Example: Malloc0.')
3174    p.set_defaults(func=blobfs_detect)
3175
3176    def blobfs_create(args):
3177        print(rpc.blobfs.blobfs_create(args.client,
3178                                       bdev_name=args.bdev_name,
3179                                       cluster_sz=args.cluster_sz))
3180
3181    p = subparsers.add_parser('blobfs_create', help='Build a blobfs on bdev')
3182    p.add_argument('bdev_name', help='Blockdev name to build blobfs. Example: Malloc0.')
3183    p.add_argument('-c', '--cluster-sz',
3184                   help="""Size of cluster in bytes (Optional). Must be multiple of 4KB page size. Default and minimal value is 1M.""")
3185    p.set_defaults(func=blobfs_create)
3186
3187    def blobfs_mount(args):
3188        print(rpc.blobfs.blobfs_mount(args.client,
3189                                      bdev_name=args.bdev_name,
3190                                      mountpoint=args.mountpoint))
3191
3192    p = subparsers.add_parser('blobfs_mount', help='Mount a blobfs on bdev to host path by FUSE')
3193    p.add_argument('bdev_name', help='Blockdev name where the blobfs is. Example: Malloc0.')
3194    p.add_argument('mountpoint', help='Mountpoint path in host to mount blobfs. Example: /mnt/.')
3195    p.set_defaults(func=blobfs_mount)
3196
3197    def blobfs_set_cache_size(args):
3198        print(rpc.blobfs.blobfs_set_cache_size(args.client,
3199                                               size_in_mb=args.size_in_mb))
3200
3201    p = subparsers.add_parser('blobfs_set_cache_size', help='Set cache size for blobfs')
3202    p.add_argument('size_in_mb', help='Cache size for blobfs in megabytes.', type=int)
3203    p.set_defaults(func=blobfs_set_cache_size)
3204
3205    # sock
3206    def sock_impl_get_options(args):
3207        print_json(rpc.sock.sock_impl_get_options(args.client,
3208                                                  impl_name=args.impl))
3209
3210    p = subparsers.add_parser('sock_impl_get_options', help="""Get options of socket layer implementation""")
3211    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3212    p.set_defaults(func=sock_impl_get_options)
3213
3214    def sock_impl_set_options(args):
3215        rpc.sock.sock_impl_set_options(args.client,
3216                                       impl_name=args.impl,
3217                                       recv_buf_size=args.recv_buf_size,
3218                                       send_buf_size=args.send_buf_size,
3219                                       enable_recv_pipe=args.enable_recv_pipe,
3220                                       enable_quickack=args.enable_quickack,
3221                                       enable_placement_id=args.enable_placement_id,
3222                                       enable_zerocopy_send_server=args.enable_zerocopy_send_server,
3223                                       enable_zerocopy_send_client=args.enable_zerocopy_send_client,
3224                                       zerocopy_threshold=args.zerocopy_threshold,
3225                                       tls_version=args.tls_version,
3226                                       enable_ktls=args.enable_ktls,
3227                                       psk_key=args.psk_key,
3228                                       psk_identity=args.psk_identity)
3229
3230    p = subparsers.add_parser('sock_impl_set_options', help="""Set options of socket layer implementation""")
3231    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3232    p.add_argument('-r', '--recv-buf-size', help='Size of receive buffer on socket in bytes', type=int)
3233    p.add_argument('-s', '--send-buf-size', help='Size of send buffer on socket in bytes', type=int)
3234    p.add_argument('-p', '--enable-placement-id', help='Option for placement-id. 0:disable,1:incoming_napi,2:incoming_cpu', type=int)
3235    p.add_argument('--enable-recv-pipe', help='Enable receive pipe',
3236                   action='store_true', dest='enable_recv_pipe')
3237    p.add_argument('--disable-recv-pipe', help='Disable receive pipe',
3238                   action='store_false', dest='enable_recv_pipe')
3239    p.add_argument('--enable-quickack', help='Enable quick ACK',
3240                   action='store_true', dest='enable_quickack')
3241    p.add_argument('--disable-quickack', help='Disable quick ACK',
3242                   action='store_false', dest='enable_quickack')
3243    p.add_argument('--enable-zerocopy-send-server', help='Enable zerocopy on send for server sockets',
3244                   action='store_true', dest='enable_zerocopy_send_server')
3245    p.add_argument('--disable-zerocopy-send-server', help='Disable zerocopy on send for server sockets',
3246                   action='store_false', dest='enable_zerocopy_send_server')
3247    p.add_argument('--enable-zerocopy-send-client', help='Enable zerocopy on send for client sockets',
3248                   action='store_true', dest='enable_zerocopy_send_client')
3249    p.add_argument('--disable-zerocopy-send-client', help='Disable zerocopy on send for client sockets',
3250                   action='store_false', dest='enable_zerocopy_send_client')
3251    p.add_argument('--zerocopy-threshold', help='Set zerocopy_threshold in bytes', type=int)
3252    p.add_argument('--tls-version', help='TLS protocol version', type=int)
3253    p.add_argument('--enable-ktls', help='Enable Kernel TLS',
3254                   action='store_true', dest='enable_ktls')
3255    p.add_argument('--disable-ktls', help='Disable Kernel TLS',
3256                   action='store_false', dest='enable_ktls')
3257    p.add_argument('--psk-key', help='Set default PSK KEY', dest='psk_key')
3258    p.add_argument('--psk-identity', help='Set default PSK ID', dest='psk_identity')
3259    p.set_defaults(func=sock_impl_set_options, enable_recv_pipe=None, enable_quickack=None,
3260                   enable_placement_id=None, enable_zerocopy_send_server=None, enable_zerocopy_send_client=None,
3261                   zerocopy_threshold=None, tls_version=None, enable_ktls=None, psk_key=None, psk_identity=None)
3262
3263    def sock_set_default_impl(args):
3264        print_json(rpc.sock.sock_set_default_impl(args.client,
3265                                                  impl_name=args.impl))
3266
3267    p = subparsers.add_parser('sock_set_default_impl', help="""Set the default sock implementation""")
3268    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3269    p.set_defaults(func=sock_set_default_impl)
3270
3271    def framework_get_pci_devices(args):
3272        def splitbuf(buf, step):
3273            return [buf[i:i+step] for i in range(0, len(buf), step)]
3274
3275        devices = rpc.subsystem.framework_get_pci_devices(args.client)
3276        if not args.format_lspci:
3277            print_json(devices)
3278        else:
3279            for devid, dev in enumerate(devices):
3280                print('{} device #{}'.format(dev['address'], devid))
3281                for lineid, line in enumerate(splitbuf(dev['config_space'], 32)):
3282                    print('{:02x}: {}'.format(lineid * 16, ' '.join(splitbuf(line.lower(), 2))))
3283                print()
3284
3285    p = subparsers.add_parser('framework_get_pci_devices', help='''Get a list of attached PCI devices''')
3286    p.add_argument('--format-lspci', help='Format the output in a way to be consumed by lspci -F',
3287                   action='store_true')
3288    p.set_defaults(func=framework_get_pci_devices)
3289
3290    # bdev_nvme_add_error_injection
3291    def bdev_nvme_add_error_injection(args):
3292        print_dict(rpc.nvme.bdev_nvme_add_error_injection(args.client,
3293                                                          name=args.nvme_name,
3294                                                          cmd_type=args.cmd_type,
3295                                                          opc=args.opc,
3296                                                          do_not_submit=args.do_not_submit,
3297                                                          timeout_in_us=args.timeout_in_us,
3298                                                          err_count=args.err_count,
3299                                                          sct=args.sct,
3300                                                          sc=args.sc))
3301    p = subparsers.add_parser('bdev_nvme_add_error_injection',
3302                              help='Add a NVMe command error injection.')
3303    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""", required=True)
3304    p.add_argument('-t', '--cmd-type', help="""Type of NVMe command. Valid values are: admin, io""", required=True)
3305    p.add_argument('-o', '--opc', help="""Opcode of the NVMe command.""", required=True, type=int)
3306    p.add_argument('-s', '--do-not-submit',
3307                   help="""Set to true if request should not be submitted to the controller""",
3308                   dest="do_not_submit", action='store_true')
3309    p.add_argument('-w', '--timeout-in-us', help="""Wait specified microseconds when do_not_submit is true""", type=int)
3310    p.add_argument('-e', '--err-count', help="""Number of matching NVMe commands to inject errors""", type=int)
3311    p.add_argument('-u', '--sct', help="""Status code type""", type=int)
3312    p.add_argument('-c', '--sc', help="""Status code""", type=int)
3313    p.set_defaults(func=bdev_nvme_add_error_injection)
3314
3315    # bdev_nvme_remove_error_injection
3316    def bdev_nvme_remove_error_injection(args):
3317        print_dict(rpc.nvme.bdev_nvme_remove_error_injection(args.client,
3318                                                             name=args.nvme_name,
3319                                                             cmd_type=args.cmd_type,
3320                                                             opc=args.opc))
3321    p = subparsers.add_parser('bdev_nvme_remove_error_injection',
3322                              help='Removes a NVMe command error injection.')
3323    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""", required=True)
3324    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""", required=True)
3325    p.add_argument('-o', '--opc', help="""Opcode of the nvme cmd.""", required=True, type=int)
3326    p.set_defaults(func=bdev_nvme_remove_error_injection)
3327
3328    def bdev_daos_create(args):
3329        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
3330        print_json(rpc.bdev.bdev_daos_create(args.client,
3331                                             num_blocks=int(num_blocks),
3332                                             block_size=args.block_size,
3333                                             name=args.name,
3334                                             uuid=args.uuid,
3335                                             pool=args.pool,
3336                                             cont=args.cont,
3337                                             oclass=args.oclass))
3338    p = subparsers.add_parser('bdev_daos_create',
3339                              help='Create a bdev with DAOS backend')
3340    p.add_argument('name', help="Name of the bdev")
3341    p.add_argument('pool', help="UUID of the DAOS pool")
3342    p.add_argument('cont', help="UUID of the DAOS container")
3343    p.add_argument(
3344        'total_size', help='Size of DAOS bdev in MB (float > 0)', type=float)
3345    p.add_argument('block_size', help='Block size for this bdev', type=int)
3346    p.add_argument('-u', '--uuid', help="UUID of the bdev")
3347    p.add_argument('-o', '--oclass', help="DAOS object class")
3348    p.set_defaults(func=bdev_daos_create)
3349
3350    def bdev_daos_delete(args):
3351        rpc.bdev.bdev_daos_delete(args.client,
3352                                  name=args.name)
3353
3354    p = subparsers.add_parser('bdev_daos_delete',
3355                              help='Delete a DAOS disk')
3356    p.add_argument('name', help='DAOS bdev name')
3357    p.set_defaults(func=bdev_daos_delete)
3358
3359    def bdev_daos_resize(args):
3360        print_json(rpc.bdev.bdev_daos_resize(args.client,
3361                                             name=args.name,
3362                                             new_size=int(args.new_size)))
3363
3364    p = subparsers.add_parser('bdev_daos_resize',
3365                              help='Resize a DAOS bdev')
3366    p.add_argument('name', help='DAOS bdev name')
3367    p.add_argument('new_size', help='new bdev size for resize operation. The unit is MiB')
3368    p.set_defaults(func=bdev_daos_resize)
3369
3370    def iobuf_set_options(args):
3371        rpc.iobuf.iobuf_set_options(args.client,
3372                                    small_pool_count=args.small_pool_count,
3373                                    large_pool_count=args.large_pool_count,
3374                                    small_bufsize=args.small_bufsize,
3375                                    large_bufsize=args.large_bufsize)
3376    p = subparsers.add_parser('iobuf_set_options', help='Set iobuf pool options')
3377    p.add_argument('--small-pool-count', help='number of small buffers in the global pool', type=int)
3378    p.add_argument('--large-pool-count', help='number of large buffers in the global pool', type=int)
3379    p.add_argument('--small-bufsize', help='size of a small buffer', type=int)
3380    p.add_argument('--large-bufsize', help='size of a large buffer', type=int)
3381    p.set_defaults(func=iobuf_set_options)
3382
3383    def bdev_nvme_start_mdns_discovery(args):
3384        rpc.bdev.bdev_nvme_start_mdns_discovery(args.client,
3385                                                name=args.name,
3386                                                svcname=args.svcname,
3387                                                hostnqn=args.hostnqn)
3388
3389    p = subparsers.add_parser('bdev_nvme_start_mdns_discovery', help='Start mdns based automatic discovery')
3390    p.add_argument('-b', '--name', help="Name of the NVMe controller prefix for each bdev name", required=True)
3391    p.add_argument('-s', '--svcname', help='Service type to discover: e.g., _nvme-disc._tcp', required=True)
3392    p.add_argument('-q', '--hostnqn', help='NVMe-oF host subnqn')
3393    p.set_defaults(func=bdev_nvme_start_mdns_discovery)
3394
3395    def bdev_nvme_stop_mdns_discovery(args):
3396        rpc.bdev.bdev_nvme_stop_mdns_discovery(args.client, name=args.name)
3397
3398    p = subparsers.add_parser('bdev_nvme_stop_mdns_discovery', help='Stop automatic mdns discovery')
3399    p.add_argument('-b', '--name', help="Name of the service to stop", required=True)
3400    p.set_defaults(func=bdev_nvme_stop_mdns_discovery)
3401
3402    def bdev_nvme_get_mdns_discovery_info(args):
3403        print_dict(rpc.bdev.bdev_nvme_get_mdns_discovery_info(args.client))
3404
3405    p = subparsers.add_parser('bdev_nvme_get_mdns_discovery_info', help='Get information about the automatic mdns discovery')
3406    p.set_defaults(func=bdev_nvme_get_mdns_discovery_info)
3407
3408    def check_called_name(name):
3409        if name in deprecated_aliases:
3410            print("{} is deprecated, use {} instead.".format(name, deprecated_aliases[name]), file=sys.stderr)
3411
3412    class dry_run_client:
3413        def call(self, method, params=None):
3414            print("Request:\n" + json.dumps({"method": method, "params": params}, indent=2))
3415
3416    def null_print(arg):
3417        pass
3418
3419    def call_rpc_func(args):
3420        args.func(args)
3421        check_called_name(args.called_rpc_name)
3422
3423    def execute_script(parser, client, fd):
3424        executed_rpc = ""
3425        for rpc_call in map(str.rstrip, fd):
3426            if not rpc_call.strip():
3427                continue
3428            executed_rpc = "\n".join([executed_rpc, rpc_call])
3429            rpc_args = shlex.split(rpc_call)
3430            if rpc_args[0][0] == '#':
3431                # Ignore lines starting with # - treat them as comments
3432                continue
3433            args = parser.parse_args(rpc_args)
3434            args.client = client
3435            try:
3436                call_rpc_func(args)
3437            except JSONRPCException as ex:
3438                print("Exception:")
3439                print(executed_rpc.strip() + " <<<")
3440                print(ex.message)
3441                exit(1)
3442
3443    def load_plugin(args):
3444        # Create temporary parser, pull out the plugin parameter, load the module, and then run the real argument parser
3445        plugin_parser = argparse.ArgumentParser(add_help=False)
3446        plugin_parser.add_argument('--plugin', dest='rpc_plugin', help='Module name of plugin with additional RPC commands')
3447
3448        rpc_module = plugin_parser.parse_known_args()[0].rpc_plugin
3449        if args is not None:
3450            rpc_module = plugin_parser.parse_known_args(args)[0].rpc_plugin
3451
3452        if rpc_module in plugins:
3453            return
3454
3455        if rpc_module is not None:
3456            try:
3457                rpc_plugin = importlib.import_module(rpc_module)
3458                try:
3459                    rpc_plugin.spdk_rpc_plugin_initialize(subparsers)
3460                    plugins.append(rpc_module)
3461                except AttributeError:
3462                    print("Module %s does not contain 'spdk_rpc_plugin_initialize' function" % rpc_module)
3463            except ModuleNotFoundError:
3464                print("Module %s not found" % rpc_module)
3465
3466    def replace_arg_underscores(args):
3467        # All option names are defined with dashes only - for example: --tgt-name
3468        # But if user used underscores, convert them to dashes (--tgt_name => --tgt-name)
3469        # SPDK was inconsistent previously and had some options with underscores, so
3470        # doing this conversion ensures backward compatibility with older scripts.
3471        for i in range(len(args)):
3472            arg = args[i]
3473            if arg.startswith('--') and "_" in arg:
3474                opt, *vals = arg.split('=')
3475                args[i] = '='.join([opt.replace('_', '-'), *vals])
3476
3477    plugins = []
3478    load_plugin(None)
3479
3480    replace_arg_underscores(sys.argv)
3481
3482    args = parser.parse_args()
3483
3484    if sys.stdin.isatty() and not hasattr(args, 'func'):
3485        # No arguments and no data piped through stdin
3486        parser.print_help()
3487        exit(1)
3488    if args.is_server:
3489        for input in sys.stdin:
3490            cmd = shlex.split(input)
3491            replace_arg_underscores(cmd)
3492            try:
3493                load_plugin(cmd)
3494                tmp_args = parser.parse_args(cmd)
3495            except SystemExit as ex:
3496                print("**STATUS=1", flush=True)
3497                continue
3498
3499            try:
3500                tmp_args.client = rpc.client.JSONRPCClient(
3501                    tmp_args.server_addr, tmp_args.port, tmp_args.timeout,
3502                    log_level=getattr(logging, tmp_args.verbose.upper()), conn_retries=tmp_args.conn_retries)
3503                call_rpc_func(tmp_args)
3504                print("**STATUS=0", flush=True)
3505            except JSONRPCException as ex:
3506                print(ex.message)
3507                print("**STATUS=1", flush=True)
3508        exit(0)
3509    elif args.dry_run:
3510        args.client = dry_run_client()
3511        print_dict = null_print
3512        print_json = null_print
3513        print_array = null_print
3514    else:
3515        try:
3516            args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.timeout,
3517                                                   log_level=getattr(logging, args.verbose.upper()),
3518                                                   conn_retries=args.conn_retries)
3519        except JSONRPCException as ex:
3520            print(ex.message)
3521            exit(1)
3522
3523    if hasattr(args, 'func'):
3524        try:
3525            call_rpc_func(args)
3526        except JSONRPCException as ex:
3527            print(ex.message)
3528            exit(1)
3529    else:
3530        execute_script(parser, args.client, sys.stdin)
3531