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