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