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