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