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