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