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