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