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