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