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