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