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