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