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