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