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