xref: /spdk/scripts/rpc.py (revision 784b9d48746955f210926648a0131f84f58de76f)
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 specified 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_reset_iostat(args):
1145        rpc.bdev.bdev_reset_iostat(args.client, name=args.name, mode=args.mode)
1146
1147    p = subparsers.add_parser('bdev_reset_iostat',
1148                              help='Reset I/O statistics of all the blockdevs or specified blockdev.')
1149    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
1150    p.add_argument('-m', '--mode', help="Mode to reset I/O statistics", choices=['all', 'maxmin'], required=False)
1151    p.set_defaults(func=bdev_reset_iostat)
1152
1153    def bdev_enable_histogram(args):
1154        rpc.bdev.bdev_enable_histogram(args.client, name=args.name, enable=args.enable)
1155
1156    p = subparsers.add_parser('bdev_enable_histogram',
1157                              help='Enable or disable histogram for specified bdev')
1158    p.add_argument('-e', '--enable', default=True, dest='enable', action='store_true', help='Enable histograms on specified device')
1159    p.add_argument('-d', '--disable', dest='enable', action='store_false', help='Disable histograms on specified device')
1160    p.add_argument('name', help='bdev name')
1161    p.set_defaults(func=bdev_enable_histogram)
1162
1163    def bdev_get_histogram(args):
1164        print_dict(rpc.bdev.bdev_get_histogram(args.client, name=args.name))
1165
1166    p = subparsers.add_parser('bdev_get_histogram',
1167                              help='Get histogram for specified bdev')
1168    p.add_argument('name', help='bdev name')
1169    p.set_defaults(func=bdev_get_histogram)
1170
1171    def bdev_set_qd_sampling_period(args):
1172        rpc.bdev.bdev_set_qd_sampling_period(args.client,
1173                                             name=args.name,
1174                                             period=args.period)
1175
1176    p = subparsers.add_parser('bdev_set_qd_sampling_period',
1177                              help="Enable or disable tracking of a bdev's queue depth.")
1178    p.add_argument('name', help='Blockdev name. Example: Malloc0')
1179    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
1180                   ' If set to 0, polling will be disabled.',
1181                   type=int)
1182    p.set_defaults(func=bdev_set_qd_sampling_period)
1183
1184    def bdev_set_qos_limit(args):
1185        rpc.bdev.bdev_set_qos_limit(args.client,
1186                                    name=args.name,
1187                                    rw_ios_per_sec=args.rw_ios_per_sec,
1188                                    rw_mbytes_per_sec=args.rw_mbytes_per_sec,
1189                                    r_mbytes_per_sec=args.r_mbytes_per_sec,
1190                                    w_mbytes_per_sec=args.w_mbytes_per_sec)
1191
1192    p = subparsers.add_parser('bdev_set_qos_limit',
1193                              help='Set QoS rate limit on a blockdev')
1194    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
1195    p.add_argument('--rw-ios-per-sec',
1196                   help='R/W IOs per second limit (>=1000, example: 20000). 0 means unlimited.',
1197                   type=int, required=False)
1198    p.add_argument('--rw-mbytes-per-sec',
1199                   help="R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.",
1200                   type=int, required=False)
1201    p.add_argument('--r-mbytes-per-sec',
1202                   help="Read megabytes per second limit (>=10, example: 100). 0 means unlimited.",
1203                   type=int, required=False)
1204    p.add_argument('--w-mbytes-per-sec',
1205                   help="Write megabytes per second limit (>=10, example: 100). 0 means unlimited.",
1206                   type=int, required=False)
1207    p.set_defaults(func=bdev_set_qos_limit)
1208
1209    def bdev_error_inject_error(args):
1210        rpc.bdev.bdev_error_inject_error(args.client,
1211                                         name=args.name,
1212                                         io_type=args.io_type,
1213                                         error_type=args.error_type,
1214                                         num=args.num,
1215                                         corrupt_offset=args.corrupt_offset,
1216                                         corrupt_value=args.corrupt_value)
1217
1218    p = subparsers.add_parser('bdev_error_inject_error', help='bdev inject error')
1219    p.add_argument('name', help="""the name of the error injection bdev""")
1220    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
1221    p.add_argument('error_type', help="""error_type: 'failure' 'pending' 'corrupt_data'""")
1222    p.add_argument(
1223        '-n', '--num', help='the number of commands you want to fail', type=int)
1224    p.add_argument(
1225        '-o', '--corrupt-offset', help='the offset in bytes to xor with corrupt_value', type=int)
1226    p.add_argument(
1227        '-v', '--corrupt-value', help='the value for xor (1-255, 0 is invalid)', type=int)
1228    p.set_defaults(func=bdev_error_inject_error)
1229
1230    def bdev_nvme_apply_firmware(args):
1231        print_dict(rpc.bdev.bdev_nvme_apply_firmware(args.client,
1232                                                     bdev_name=args.bdev_name,
1233                                                     filename=args.filename))
1234
1235    p = subparsers.add_parser('bdev_nvme_apply_firmware', help='Download and commit firmware to NVMe device')
1236    p.add_argument('filename', help='filename of the firmware to download')
1237    p.add_argument('bdev_name', help='name of the NVMe device')
1238    p.set_defaults(func=bdev_nvme_apply_firmware)
1239
1240    def bdev_nvme_get_transport_statistics(args):
1241        print_dict(rpc.bdev.bdev_nvme_get_transport_statistics(args.client))
1242
1243    p = subparsers.add_parser('bdev_nvme_get_transport_statistics',
1244                              help='Get bdev_nvme poll group transport statistics')
1245    p.set_defaults(func=bdev_nvme_get_transport_statistics)
1246
1247    def bdev_nvme_get_controller_health_info(args):
1248        print_dict(rpc.bdev.bdev_nvme_get_controller_health_info(args.client,
1249                                                                 name=args.name))
1250
1251    p = subparsers.add_parser('bdev_nvme_get_controller_health_info',
1252                              help='Display health log of the required NVMe bdev controller.')
1253    p.add_argument('-c', '--name', help="Name of the NVMe bdev controller. Example: Nvme0", required=True)
1254    p.set_defaults(func=bdev_nvme_get_controller_health_info)
1255
1256    # iSCSI
1257    def iscsi_set_options(args):
1258        rpc.iscsi.iscsi_set_options(
1259            args.client,
1260            auth_file=args.auth_file,
1261            node_base=args.node_base,
1262            nop_timeout=args.nop_timeout,
1263            nop_in_interval=args.nop_in_interval,
1264            disable_chap=args.disable_chap,
1265            require_chap=args.require_chap,
1266            mutual_chap=args.mutual_chap,
1267            chap_group=args.chap_group,
1268            max_sessions=args.max_sessions,
1269            max_queue_depth=args.max_queue_depth,
1270            max_connections_per_session=args.max_connections_per_session,
1271            default_time2wait=args.default_time2wait,
1272            default_time2retain=args.default_time2retain,
1273            first_burst_length=args.first_burst_length,
1274            immediate_data=args.immediate_data,
1275            error_recovery_level=args.error_recovery_level,
1276            allow_duplicated_isid=args.allow_duplicated_isid,
1277            max_large_datain_per_connection=args.max_large_datain_per_connection,
1278            max_r2t_per_connection=args.max_r2t_per_connection,
1279            pdu_pool_size=args.pdu_pool_size,
1280            immediate_data_pool_size=args.immediate_data_pool_size,
1281            data_out_pool_size=args.data_out_pool_size)
1282
1283    p = subparsers.add_parser('iscsi_set_options',
1284                              help="""Set options of iSCSI subsystem""")
1285    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file')
1286    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
1287    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
1288    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
1289    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
1290    *** Mutually exclusive with --require-chap""", action='store_true')
1291    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
1292    *** Mutually exclusive with --disable-chap""", action='store_true')
1293    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
1294    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
1295    *** Authentication group must be precreated ***""", type=int)
1296    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
1297    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int)
1298    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
1299    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
1300    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
1301    p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int)
1302    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
1303    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
1304    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
1305    p.add_argument('-x', '--max-large-datain-per-connection', help='Max number of outstanding split read I/Os per connection', type=int)
1306    p.add_argument('-k', '--max-r2t-per-connection', help='Max number of outstanding R2Ts per connection', type=int)
1307    p.add_argument('-u', '--pdu-pool-size', help='Number of PDUs in the pool', type=int)
1308    p.add_argument('-j', '--immediate-data-pool-size', help='Number of immediate data buffers in the pool', type=int)
1309    p.add_argument('-z', '--data-out-pool-size', help='Number of data out buffers in the pool', type=int)
1310    p.set_defaults(func=iscsi_set_options)
1311
1312    def iscsi_set_discovery_auth(args):
1313        rpc.iscsi.iscsi_set_discovery_auth(
1314            args.client,
1315            disable_chap=args.disable_chap,
1316            require_chap=args.require_chap,
1317            mutual_chap=args.mutual_chap,
1318            chap_group=args.chap_group)
1319
1320    p = subparsers.add_parser('iscsi_set_discovery_auth',
1321                              help="""Set CHAP authentication for discovery session.""")
1322    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
1323    *** Mutually exclusive with --require-chap""", action='store_true')
1324    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
1325    *** Mutually exclusive with --disable-chap""", action='store_true')
1326    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
1327    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
1328    *** Authentication group must be precreated ***""", type=int)
1329    p.set_defaults(func=iscsi_set_discovery_auth)
1330
1331    def iscsi_create_auth_group(args):
1332        secrets = None
1333        if args.secrets:
1334            secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")]
1335
1336        rpc.iscsi.iscsi_create_auth_group(args.client, tag=args.tag, secrets=secrets)
1337
1338    p = subparsers.add_parser('iscsi_create_auth_group',
1339                              help='Create authentication group for CHAP authentication.')
1340    p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int)
1341    p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets
1342<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes.
1343Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False)
1344    p.set_defaults(func=iscsi_create_auth_group)
1345
1346    def iscsi_delete_auth_group(args):
1347        rpc.iscsi.iscsi_delete_auth_group(args.client, tag=args.tag)
1348
1349    p = subparsers.add_parser('iscsi_delete_auth_group',
1350                              help='Delete an authentication group.')
1351    p.add_argument('tag', help='Authentication group tag', type=int)
1352    p.set_defaults(func=iscsi_delete_auth_group)
1353
1354    def iscsi_auth_group_add_secret(args):
1355        rpc.iscsi.iscsi_auth_group_add_secret(
1356            args.client,
1357            tag=args.tag,
1358            user=args.user,
1359            secret=args.secret,
1360            muser=args.muser,
1361            msecret=args.msecret)
1362
1363    p = subparsers.add_parser('iscsi_auth_group_add_secret',
1364                              help='Add a secret to an authentication group.')
1365    p.add_argument('tag', help='Authentication group tag', type=int)
1366    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
1367    p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True)
1368    p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication')
1369    p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication')
1370    p.set_defaults(func=iscsi_auth_group_add_secret)
1371
1372    def iscsi_auth_group_remove_secret(args):
1373        rpc.iscsi.iscsi_auth_group_remove_secret(args.client, tag=args.tag, user=args.user)
1374
1375    p = subparsers.add_parser('iscsi_auth_group_remove_secret',
1376                              help='Remove a secret from an authentication group.')
1377    p.add_argument('tag', help='Authentication group tag', type=int)
1378    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
1379    p.set_defaults(func=iscsi_auth_group_remove_secret)
1380
1381    def iscsi_get_auth_groups(args):
1382        print_dict(rpc.iscsi.iscsi_get_auth_groups(args.client))
1383
1384    p = subparsers.add_parser('iscsi_get_auth_groups',
1385                              help='Display current authentication group configuration')
1386    p.set_defaults(func=iscsi_get_auth_groups)
1387
1388    def iscsi_get_portal_groups(args):
1389        print_dict(rpc.iscsi.iscsi_get_portal_groups(args.client))
1390
1391    p = subparsers.add_parser('iscsi_get_portal_groups', help='Display current portal group configuration')
1392    p.set_defaults(func=iscsi_get_portal_groups)
1393
1394    def iscsi_get_initiator_groups(args):
1395        print_dict(rpc.iscsi.iscsi_get_initiator_groups(args.client))
1396
1397    p = subparsers.add_parser('iscsi_get_initiator_groups',
1398                              help='Display current initiator group configuration')
1399    p.set_defaults(func=iscsi_get_initiator_groups)
1400
1401    def iscsi_get_target_nodes(args):
1402        print_dict(rpc.iscsi.iscsi_get_target_nodes(args.client))
1403
1404    p = subparsers.add_parser('iscsi_get_target_nodes', help='Display target nodes')
1405    p.set_defaults(func=iscsi_get_target_nodes)
1406
1407    def iscsi_create_target_node(args):
1408        luns = []
1409        for u in args.bdev_name_id_pairs.strip().split(" "):
1410            bdev_name, lun_id = u.split(":")
1411            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
1412
1413        pg_ig_maps = []
1414        for u in args.pg_ig_mappings.strip().split(" "):
1415            pg, ig = u.split(":")
1416            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1417
1418        rpc.iscsi.iscsi_create_target_node(
1419            args.client,
1420            luns=luns,
1421            pg_ig_maps=pg_ig_maps,
1422            name=args.name,
1423            alias_name=args.alias_name,
1424            queue_depth=args.queue_depth,
1425            chap_group=args.chap_group,
1426            disable_chap=args.disable_chap,
1427            require_chap=args.require_chap,
1428            mutual_chap=args.mutual_chap,
1429            header_digest=args.header_digest,
1430            data_digest=args.data_digest)
1431
1432    p = subparsers.add_parser('iscsi_create_target_node', help='Add a target node')
1433    p.add_argument('name', help='Target node name (ASCII)')
1434    p.add_argument('alias_name', help='Target node alias name (ASCII)')
1435    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
1436    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
1437    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
1438    *** The bdevs must pre-exist ***
1439    *** LUN0 (id = 0) is required ***
1440    *** bdevs names cannot contain space or colon characters ***""")
1441    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1442    Whitespace separated, quoted, mapping defined with colon
1443    separated list of "tags" (int > 0)
1444    Example: '1:1 2:2 2:1'
1445    *** The Portal/Initiator Groups must be precreated ***""")
1446    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
1447    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
1448    *** Authentication group must be precreated ***""", type=int)
1449    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
1450    *** Mutually exclusive with --require-chap ***""", action='store_true')
1451    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
1452    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1453    p.add_argument(
1454        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
1455    p.add_argument('-H', '--header-digest',
1456                   help='Header Digest should be required for this target node.', action='store_true')
1457    p.add_argument('-D', '--data-digest',
1458                   help='Data Digest should be required for this target node.', action='store_true')
1459    p.set_defaults(func=iscsi_create_target_node)
1460
1461    def iscsi_target_node_add_lun(args):
1462        rpc.iscsi.iscsi_target_node_add_lun(
1463            args.client,
1464            name=args.name,
1465            bdev_name=args.bdev_name,
1466            lun_id=args.lun_id)
1467
1468    p = subparsers.add_parser('iscsi_target_node_add_lun',
1469                              help='Add LUN to the target node')
1470    p.add_argument('name', help='Target node name (ASCII)')
1471    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
1472    *** bdev name cannot contain space or colon characters ***""")
1473    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
1474    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
1475    p.set_defaults(func=iscsi_target_node_add_lun)
1476
1477    def iscsi_target_node_set_auth(args):
1478        rpc.iscsi.iscsi_target_node_set_auth(
1479            args.client,
1480            name=args.name,
1481            chap_group=args.chap_group,
1482            disable_chap=args.disable_chap,
1483            require_chap=args.require_chap,
1484            mutual_chap=args.mutual_chap)
1485
1486    p = subparsers.add_parser('iscsi_target_node_set_auth',
1487                              help='Set CHAP authentication for the target node')
1488    p.add_argument('name', help='Target node name (ASCII)')
1489    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
1490    *** Authentication group must be precreated ***""", type=int)
1491    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
1492    *** Mutually exclusive with --require-chap ***""", action='store_true')
1493    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
1494    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1495    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
1496                   action='store_true')
1497    p.set_defaults(func=iscsi_target_node_set_auth)
1498
1499    def iscsi_target_node_add_pg_ig_maps(args):
1500        pg_ig_maps = []
1501        for u in args.pg_ig_mappings.strip().split(" "):
1502            pg, ig = u.split(":")
1503            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1504        rpc.iscsi.iscsi_target_node_add_pg_ig_maps(
1505            args.client,
1506            pg_ig_maps=pg_ig_maps,
1507            name=args.name)
1508
1509    p = subparsers.add_parser('iscsi_target_node_add_pg_ig_maps',
1510                              help='Add PG-IG maps to the target node')
1511    p.add_argument('name', help='Target node name (ASCII)')
1512    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1513    Whitespace separated, quoted, mapping defined with colon
1514    separated list of "tags" (int > 0)
1515    Example: '1:1 2:2 2:1'
1516    *** The Portal/Initiator Groups must be precreated ***""")
1517    p.set_defaults(func=iscsi_target_node_add_pg_ig_maps)
1518
1519    def iscsi_target_node_remove_pg_ig_maps(args):
1520        pg_ig_maps = []
1521        for u in args.pg_ig_mappings.strip().split(" "):
1522            pg, ig = u.split(":")
1523            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1524        rpc.iscsi.iscsi_target_node_remove_pg_ig_maps(
1525            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
1526
1527    p = subparsers.add_parser('iscsi_target_node_remove_pg_ig_maps',
1528                              help='Delete PG-IG maps from the target node')
1529    p.add_argument('name', help='Target node name (ASCII)')
1530    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1531    Whitespace separated, quoted, mapping defined with colon
1532    separated list of "tags" (int > 0)
1533    Example: '1:1 2:2 2:1'
1534    *** The Portal/Initiator Groups must be precreated ***""")
1535    p.set_defaults(func=iscsi_target_node_remove_pg_ig_maps)
1536
1537    def iscsi_target_node_set_redirect(args):
1538        rpc.iscsi.iscsi_target_node_set_redirect(
1539            args.client,
1540            name=args.name,
1541            pg_tag=args.pg_tag,
1542            redirect_host=args.redirect_host,
1543            redirect_port=args.redirect_port)
1544
1545    p = subparsers.add_parser('iscsi_target_node_set_redirect',
1546                              help="""Update redirect portal of the public portal group for the target node.
1547    Omit redirect host and port to clear previously set redirect settings.""")
1548    p.add_argument('name', help='Target node name (ASCII)')
1549    p.add_argument('pg_tag', help='Portal group tag (unique, integer > 0)', type=int)
1550    p.add_argument('-a', '--redirect-host', help='Numeric IP address for redirect portal', required=False)
1551    p.add_argument('-p', '--redirect-port', help='Numeric TCP port for redirect portal', required=False)
1552    p.set_defaults(func=iscsi_target_node_set_redirect)
1553
1554    def iscsi_target_node_request_logout(args):
1555        rpc.iscsi.iscsi_target_node_request_logout(
1556            args.client,
1557            name=args.name,
1558            pg_tag=args.pg_tag)
1559
1560    p = subparsers.add_parser('iscsi_target_node_request_logout',
1561                              help="""For the target node, request connections whose portal group tag
1562    match to logout, or request all connections if portal group tag is omitted.""")
1563    p.add_argument('name', help='Target node name (ASCII)')
1564    p.add_argument('-t', '--pg-tag', help='Portal group tag (unique, integer > 0)', type=int, required=False)
1565    p.set_defaults(func=iscsi_target_node_request_logout)
1566
1567    def iscsi_create_portal_group(args):
1568        portals = []
1569        for p in args.portal_list.strip().split(' '):
1570            ip, separator, port_cpumask = p.rpartition(':')
1571            split_port_cpumask = port_cpumask.split('@')
1572            if len(split_port_cpumask) == 1:
1573                port = port_cpumask
1574                portals.append({'host': ip, 'port': port})
1575            else:
1576                port = split_port_cpumask[0]
1577                cpumask = split_port_cpumask[1]
1578                portals.append({'host': ip, 'port': port})
1579                print("WARNING: Specifying a portal group with a CPU mask is no longer supported. Ignoring it.")
1580        rpc.iscsi.iscsi_create_portal_group(
1581            args.client,
1582            portals=portals,
1583            tag=args.tag,
1584            private=args.private,
1585            wait=args.wait)
1586
1587    p = subparsers.add_parser('iscsi_create_portal_group',
1588                              help='Add a portal group')
1589    p.add_argument(
1590        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1591    p.add_argument('portal_list', help="""List of portals in host:port format, separated by whitespace
1592    Example: '192.168.100.100:3260 192.168.100.100:3261 192.168.100.100:3262""")
1593    p.add_argument('-p', '--private', help="""Public (false) or private (true) portal group.
1594    Private portal groups do not have their portals returned by a discovery session. A public
1595    portal group may optionally specify a redirect portal for non-discovery logins. This redirect
1596    portal must be from a private portal group.""", action='store_true')
1597    p.add_argument('-w', '--wait', help="""Do not listening on portals until it is started explicitly.
1598    One major iSCSI initiator may not retry login once it failed. Hence for such initiator, listening
1599    on portals should be allowed after all associated target nodes are created.""", action='store_true')
1600    p.set_defaults(func=iscsi_create_portal_group)
1601
1602    def iscsi_start_portal_group(args):
1603        rpc.iscsi.iscsi_start_portal_group(args.client, tag=args.tag)
1604
1605    p = subparsers.add_parser('iscsi_start_portal_group',
1606                              help='Start listening on portals if it is not started yet.')
1607    p.add_argument(
1608        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1609    p.set_defaults(func=iscsi_start_portal_group)
1610
1611    def iscsi_create_initiator_group(args):
1612        initiators = []
1613        netmasks = []
1614        for i in args.initiator_list.strip().split(' '):
1615            initiators.append(i)
1616        for n in args.netmask_list.strip().split(' '):
1617            netmasks.append(n)
1618        rpc.iscsi.iscsi_create_initiator_group(
1619            args.client,
1620            tag=args.tag,
1621            initiators=initiators,
1622            netmasks=netmasks)
1623
1624    p = subparsers.add_parser('iscsi_create_initiator_group',
1625                              help='Add an initiator group')
1626    p.add_argument(
1627        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1628    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1629    enclosed in quotes.  Example: 'ANY' or 'iqn.2016-06.io.spdk:host1 iqn.2016-06.io.spdk:host2'""")
1630    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1631    Example: '255.255.0.0 255.248.0.0' etc""")
1632    p.set_defaults(func=iscsi_create_initiator_group)
1633
1634    def iscsi_initiator_group_add_initiators(args):
1635        initiators = None
1636        netmasks = None
1637        if args.initiator_list:
1638            initiators = []
1639            for i in args.initiator_list.strip().split(' '):
1640                initiators.append(i)
1641        if args.netmask_list:
1642            netmasks = []
1643            for n in args.netmask_list.strip().split(' '):
1644                netmasks.append(n)
1645        rpc.iscsi.iscsi_initiator_group_add_initiators(
1646            args.client,
1647            tag=args.tag,
1648            initiators=initiators,
1649            netmasks=netmasks)
1650
1651    p = subparsers.add_parser('iscsi_initiator_group_add_initiators',
1652                              help='Add initiators to an existing initiator group')
1653    p.add_argument(
1654        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1655    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1656    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or
1657    'iqn.2016-06.io.spdk:host1 iqn.2016-06.io.spdk:host2'""", required=False)
1658    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1659    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
1660    p.set_defaults(func=iscsi_initiator_group_add_initiators)
1661
1662    def iscsi_initiator_group_remove_initiators(args):
1663        initiators = None
1664        netmasks = None
1665        if args.initiator_list:
1666            initiators = []
1667            for i in args.initiator_list.strip().split(' '):
1668                initiators.append(i)
1669        if args.netmask_list:
1670            netmasks = []
1671            for n in args.netmask_list.strip().split(' '):
1672                netmasks.append(n)
1673        rpc.iscsi.iscsi_initiator_group_remove_initiators(
1674            args.client,
1675            tag=args.tag,
1676            initiators=initiators,
1677            netmasks=netmasks)
1678
1679    p = subparsers.add_parser('iscsi_initiator_group_remove_initiators',
1680                              help='Delete initiators from an existing initiator group')
1681    p.add_argument(
1682        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1683    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1684    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or
1685    'iqn.2016-06.io.spdk:host1 iqn.2016-06.io.spdk:host2'""", required=False)
1686    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1687    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
1688    p.set_defaults(func=iscsi_initiator_group_remove_initiators)
1689
1690    def iscsi_delete_target_node(args):
1691        rpc.iscsi.iscsi_delete_target_node(
1692            args.client, target_node_name=args.target_node_name)
1693
1694    p = subparsers.add_parser('iscsi_delete_target_node',
1695                              help='Delete a target node')
1696    p.add_argument('target_node_name',
1697                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
1698    p.set_defaults(func=iscsi_delete_target_node)
1699
1700    def iscsi_delete_portal_group(args):
1701        rpc.iscsi.iscsi_delete_portal_group(args.client, tag=args.tag)
1702
1703    p = subparsers.add_parser('iscsi_delete_portal_group',
1704                              help='Delete a portal group')
1705    p.add_argument(
1706        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1707    p.set_defaults(func=iscsi_delete_portal_group)
1708
1709    def iscsi_delete_initiator_group(args):
1710        rpc.iscsi.iscsi_delete_initiator_group(args.client, tag=args.tag)
1711
1712    p = subparsers.add_parser('iscsi_delete_initiator_group',
1713                              help='Delete an initiator group')
1714    p.add_argument(
1715        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1716    p.set_defaults(func=iscsi_delete_initiator_group)
1717
1718    def iscsi_portal_group_set_auth(args):
1719        rpc.iscsi.iscsi_portal_group_set_auth(
1720            args.client,
1721            tag=args.tag,
1722            chap_group=args.chap_group,
1723            disable_chap=args.disable_chap,
1724            require_chap=args.require_chap,
1725            mutual_chap=args.mutual_chap)
1726
1727    p = subparsers.add_parser('iscsi_portal_group_set_auth',
1728                              help='Set CHAP authentication for discovery sessions specific for the portal group')
1729    p.add_argument('tag', help='Portal group tag (unique, integer > 0)', type=int)
1730    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this portal group.
1731    *** Authentication group must be precreated ***""", type=int)
1732    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this portal group.
1733    *** Mutually exclusive with --require-chap ***""", action='store_true')
1734    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this portal group.
1735    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1736    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
1737                   action='store_true')
1738    p.set_defaults(func=iscsi_portal_group_set_auth)
1739
1740    def iscsi_get_connections(args):
1741        print_dict(rpc.iscsi.iscsi_get_connections(args.client))
1742
1743    p = subparsers.add_parser('iscsi_get_connections',
1744                              help='Display iSCSI connections')
1745    p.set_defaults(func=iscsi_get_connections)
1746
1747    def iscsi_get_options(args):
1748        print_dict(rpc.iscsi.iscsi_get_options(args.client))
1749
1750    p = subparsers.add_parser('iscsi_get_options',
1751                              help='Display iSCSI global parameters')
1752    p.set_defaults(func=iscsi_get_options)
1753
1754    def scsi_get_devices(args):
1755        print_dict(rpc.iscsi.scsi_get_devices(args.client))
1756
1757    p = subparsers.add_parser('scsi_get_devices', help='Display SCSI devices')
1758    p.set_defaults(func=scsi_get_devices)
1759
1760    # trace
1761    def trace_enable_tpoint_group(args):
1762        rpc.trace.trace_enable_tpoint_group(args.client, name=args.name)
1763
1764    p = subparsers.add_parser('trace_enable_tpoint_group',
1765                              help='enable trace on a specific tpoint group')
1766    p.add_argument(
1767        'name', help="""trace group name we want to enable in tpoint_group_mask.
1768        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1769    p.set_defaults(func=trace_enable_tpoint_group)
1770
1771    def trace_disable_tpoint_group(args):
1772        rpc.trace.trace_disable_tpoint_group(args.client, name=args.name)
1773
1774    p = subparsers.add_parser('trace_disable_tpoint_group',
1775                              help='disable trace on a specific tpoint group')
1776    p.add_argument(
1777        'name', help="""trace group name we want to disable in tpoint_group_mask.
1778        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1779    p.set_defaults(func=trace_disable_tpoint_group)
1780
1781    def trace_set_tpoint_mask(args):
1782        rpc.trace.trace_set_tpoint_mask(args.client, name=args.name, tpoint_mask=args.tpoint_mask)
1783
1784    p = subparsers.add_parser('trace_set_tpoint_mask',
1785                              help='enable tracepoint mask on a specific tpoint group')
1786    p.add_argument(
1787        'name', help="""trace group name we want to enable in tpoint_group_mask.
1788        (for example "bdev" for bdev trace group)""")
1789    p.add_argument(
1790        'tpoint_mask', help="""tracepoints to be enabled inside a given trace group.
1791        (for example value of "0x3" will enable only the first two tpoints in this group)""",
1792        type=lambda m: int(m, 16))
1793    p.set_defaults(func=trace_set_tpoint_mask)
1794
1795    def trace_clear_tpoint_mask(args):
1796        rpc.trace.trace_clear_tpoint_mask(args.client, name=args.name, tpoint_mask=args.tpoint_mask)
1797
1798    p = subparsers.add_parser('trace_clear_tpoint_mask',
1799                              help='disable tracepoint mask on a specific tpoint group')
1800    p.add_argument(
1801        'name', help="""trace group name we want to disable in tpoint_group_mask.
1802        (for example "bdev" for bdev trace group)""")
1803    p.add_argument(
1804        'tpoint_mask', help="""tracepoints to be disabled inside a given trace group.
1805        (for example value of "0x3" will disable the first two tpoints in this group)""",
1806        type=lambda m: int(m, 16))
1807    p.set_defaults(func=trace_clear_tpoint_mask)
1808
1809    def trace_get_tpoint_group_mask(args):
1810        print_dict(rpc.trace.trace_get_tpoint_group_mask(args.client))
1811
1812    p = subparsers.add_parser('trace_get_tpoint_group_mask', help='get trace point group mask')
1813    p.set_defaults(func=trace_get_tpoint_group_mask)
1814
1815    def trace_get_info(args):
1816        print_dict(rpc.trace.trace_get_info(args.client))
1817
1818    p = subparsers.add_parser('trace_get_info',
1819                              help='get name of shared memory file and list of the available trace point groups')
1820    p.set_defaults(func=trace_get_info)
1821
1822    # log
1823    def log_set_flag(args):
1824        rpc.log.log_set_flag(args.client, flag=args.flag)
1825
1826    p = subparsers.add_parser('log_set_flag', help='set log flag')
1827    p.add_argument(
1828        'flag', help='log flag we want to set. (for example "nvme").')
1829    p.set_defaults(func=log_set_flag)
1830
1831    def log_clear_flag(args):
1832        rpc.log.log_clear_flag(args.client, flag=args.flag)
1833
1834    p = subparsers.add_parser('log_clear_flag', help='clear log flag')
1835    p.add_argument(
1836        'flag', help='log flag we want to clear. (for example "nvme").')
1837    p.set_defaults(func=log_clear_flag)
1838
1839    def log_get_flags(args):
1840        print_dict(rpc.log.log_get_flags(args.client))
1841
1842    p = subparsers.add_parser('log_get_flags', help='get log flags')
1843    p.set_defaults(func=log_get_flags)
1844
1845    def log_set_level(args):
1846        rpc.log.log_set_level(args.client, level=args.level)
1847
1848    p = subparsers.add_parser('log_set_level', help='set log level')
1849    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
1850    p.set_defaults(func=log_set_level)
1851
1852    def log_get_level(args):
1853        print_dict(rpc.log.log_get_level(args.client))
1854
1855    p = subparsers.add_parser('log_get_level', help='get log level')
1856    p.set_defaults(func=log_get_level)
1857
1858    def log_set_print_level(args):
1859        rpc.log.log_set_print_level(args.client, level=args.level)
1860
1861    p = subparsers.add_parser('log_set_print_level', help='set log print level')
1862    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
1863    p.set_defaults(func=log_set_print_level)
1864
1865    def log_get_print_level(args):
1866        print_dict(rpc.log.log_get_print_level(args.client))
1867
1868    p = subparsers.add_parser('log_get_print_level', help='get log print level')
1869    p.set_defaults(func=log_get_print_level)
1870
1871    # lvol
1872    def bdev_lvol_create_lvstore(args):
1873        print_json(rpc.lvol.bdev_lvol_create_lvstore(args.client,
1874                                                     bdev_name=args.bdev_name,
1875                                                     lvs_name=args.lvs_name,
1876                                                     cluster_sz=args.cluster_sz,
1877                                                     clear_method=args.clear_method,
1878                                                     num_md_pages_per_cluster_ratio=args.md_pages_per_cluster_ratio))
1879
1880    p = subparsers.add_parser('bdev_lvol_create_lvstore', help='Add logical volume store on base bdev')
1881    p.add_argument('bdev_name', help='base bdev name')
1882    p.add_argument('lvs_name', help='name for lvol store')
1883    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
1884    p.add_argument('--clear-method', help="""Change clear method for data region.
1885        Available: none, unmap, write_zeroes""", required=False)
1886    p.add_argument('-m', '--md-pages-per-cluster-ratio', help='reserved metadata pages for each cluster', type=int, required=False)
1887    p.set_defaults(func=bdev_lvol_create_lvstore)
1888
1889    def bdev_lvol_rename_lvstore(args):
1890        rpc.lvol.bdev_lvol_rename_lvstore(args.client,
1891                                          old_name=args.old_name,
1892                                          new_name=args.new_name)
1893
1894    p = subparsers.add_parser('bdev_lvol_rename_lvstore', help='Change logical volume store name')
1895    p.add_argument('old_name', help='old name')
1896    p.add_argument('new_name', help='new name')
1897    p.set_defaults(func=bdev_lvol_rename_lvstore)
1898
1899    def bdev_lvol_grow_lvstore(args):
1900        print_dict(rpc.lvol.bdev_lvol_grow_lvstore(args.client,
1901                                                   uuid=args.uuid,
1902                                                   lvs_name=args.lvs_name))
1903
1904    p = subparsers.add_parser('bdev_lvol_grow_lvstore',
1905                              help='Grow the lvstore size to the underlying bdev size')
1906    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1907    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1908    p.set_defaults(func=bdev_lvol_grow_lvstore)
1909
1910    def bdev_lvol_create(args):
1911        print_json(rpc.lvol.bdev_lvol_create(args.client,
1912                                             lvol_name=args.lvol_name,
1913                                             size=args.size * 1024 * 1024,
1914                                             thin_provision=args.thin_provision,
1915                                             clear_method=args.clear_method,
1916                                             uuid=args.uuid,
1917                                             lvs_name=args.lvs_name))
1918
1919    p = subparsers.add_parser('bdev_lvol_create', help='Add a bdev with an logical volume backend')
1920    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1921    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1922    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
1923    p.add_argument('-c', '--clear-method', help="""Change default data clusters clear method.
1924        Available: none, unmap, write_zeroes""", required=False)
1925    p.add_argument('lvol_name', help='name for this lvol')
1926    p.add_argument('size', help='size in MiB for this bdev', type=int)
1927    p.set_defaults(func=bdev_lvol_create)
1928
1929    def bdev_lvol_snapshot(args):
1930        print_json(rpc.lvol.bdev_lvol_snapshot(args.client,
1931                                               lvol_name=args.lvol_name,
1932                                               snapshot_name=args.snapshot_name))
1933
1934    p = subparsers.add_parser('bdev_lvol_snapshot', help='Create a snapshot of an lvol bdev')
1935    p.add_argument('lvol_name', help='lvol bdev name')
1936    p.add_argument('snapshot_name', help='lvol snapshot name')
1937    p.set_defaults(func=bdev_lvol_snapshot)
1938
1939    def bdev_lvol_clone(args):
1940        print_json(rpc.lvol.bdev_lvol_clone(args.client,
1941                                            snapshot_name=args.snapshot_name,
1942                                            clone_name=args.clone_name))
1943
1944    p = subparsers.add_parser('bdev_lvol_clone', help='Create a clone of an lvol snapshot')
1945    p.add_argument('snapshot_name', help='lvol snapshot name')
1946    p.add_argument('clone_name', help='lvol clone name')
1947    p.set_defaults(func=bdev_lvol_clone)
1948
1949    def bdev_lvol_rename(args):
1950        rpc.lvol.bdev_lvol_rename(args.client,
1951                                  old_name=args.old_name,
1952                                  new_name=args.new_name)
1953
1954    p = subparsers.add_parser('bdev_lvol_rename', help='Change lvol bdev name')
1955    p.add_argument('old_name', help='lvol bdev name')
1956    p.add_argument('new_name', help='new lvol name')
1957    p.set_defaults(func=bdev_lvol_rename)
1958
1959    def bdev_lvol_inflate(args):
1960        rpc.lvol.bdev_lvol_inflate(args.client,
1961                                   name=args.name)
1962
1963    p = subparsers.add_parser('bdev_lvol_inflate', help='Make thin provisioned lvol a thick provisioned lvol')
1964    p.add_argument('name', help='lvol bdev name')
1965    p.set_defaults(func=bdev_lvol_inflate)
1966
1967    def bdev_lvol_decouple_parent(args):
1968        rpc.lvol.bdev_lvol_decouple_parent(args.client,
1969                                           name=args.name)
1970
1971    p = subparsers.add_parser('bdev_lvol_decouple_parent', help='Decouple parent of lvol')
1972    p.add_argument('name', help='lvol bdev name')
1973    p.set_defaults(func=bdev_lvol_decouple_parent)
1974
1975    def bdev_lvol_resize(args):
1976        rpc.lvol.bdev_lvol_resize(args.client,
1977                                  name=args.name,
1978                                  size=args.size * 1024 * 1024)
1979
1980    p = subparsers.add_parser('bdev_lvol_resize', help='Resize existing lvol bdev')
1981    p.add_argument('name', help='lvol bdev name')
1982    p.add_argument('size', help='new size in MiB for this bdev', type=int)
1983    p.set_defaults(func=bdev_lvol_resize)
1984
1985    def bdev_lvol_set_read_only(args):
1986        rpc.lvol.bdev_lvol_set_read_only(args.client,
1987                                         name=args.name)
1988
1989    p = subparsers.add_parser('bdev_lvol_set_read_only', help='Mark lvol bdev as read only')
1990    p.add_argument('name', help='lvol bdev name')
1991    p.set_defaults(func=bdev_lvol_set_read_only)
1992
1993    def bdev_lvol_delete(args):
1994        rpc.lvol.bdev_lvol_delete(args.client,
1995                                  name=args.name)
1996
1997    p = subparsers.add_parser('bdev_lvol_delete', help='Destroy a logical volume')
1998    p.add_argument('name', help='lvol bdev name')
1999    p.set_defaults(func=bdev_lvol_delete)
2000
2001    def bdev_lvol_delete_lvstore(args):
2002        rpc.lvol.bdev_lvol_delete_lvstore(args.client,
2003                                          uuid=args.uuid,
2004                                          lvs_name=args.lvs_name)
2005
2006    p = subparsers.add_parser('bdev_lvol_delete_lvstore', help='Destroy an logical volume store')
2007    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
2008    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
2009    p.set_defaults(func=bdev_lvol_delete_lvstore)
2010
2011    def bdev_lvol_get_lvstores(args):
2012        print_dict(rpc.lvol.bdev_lvol_get_lvstores(args.client,
2013                                                   uuid=args.uuid,
2014                                                   lvs_name=args.lvs_name))
2015
2016    p = subparsers.add_parser('bdev_lvol_get_lvstores', help='Display current logical volume store list')
2017    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
2018    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
2019    p.set_defaults(func=bdev_lvol_get_lvstores)
2020
2021    def bdev_raid_get_bdevs(args):
2022        print_json(rpc.bdev.bdev_raid_get_bdevs(args.client,
2023                                                category=args.category))
2024
2025    p = subparsers.add_parser('bdev_raid_get_bdevs',
2026                              help="""This is used to list all the raid bdev details based on the input category
2027    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
2028    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
2029    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
2030    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
2031    p.add_argument('category', help='all or online or configuring or offline')
2032    p.set_defaults(func=bdev_raid_get_bdevs)
2033
2034    def bdev_raid_create(args):
2035        base_bdevs = []
2036        for u in args.base_bdevs.strip().split(" "):
2037            base_bdevs.append(u)
2038
2039        rpc.bdev.bdev_raid_create(args.client,
2040                                  name=args.name,
2041                                  strip_size_kb=args.strip_size_kb,
2042                                  raid_level=args.raid_level,
2043                                  base_bdevs=base_bdevs)
2044    p = subparsers.add_parser('bdev_raid_create', help='Create new raid bdev')
2045    p.add_argument('-n', '--name', help='raid bdev name', required=True)
2046    p.add_argument('-z', '--strip-size-kb', help='strip size in KB', type=int)
2047    p.add_argument('-r', '--raid-level', help='raid level, raid0 and a special level concat are supported', required=True)
2048    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
2049    p.set_defaults(func=bdev_raid_create)
2050
2051    def bdev_raid_delete(args):
2052        rpc.bdev.bdev_raid_delete(args.client,
2053                                  name=args.name)
2054    p = subparsers.add_parser('bdev_raid_delete', help='Delete existing raid bdev')
2055    p.add_argument('name', help='raid bdev name')
2056    p.set_defaults(func=bdev_raid_delete)
2057
2058    # split
2059    def bdev_split_create(args):
2060        print_array(rpc.bdev.bdev_split_create(args.client,
2061                                               base_bdev=args.base_bdev,
2062                                               split_count=args.split_count,
2063                                               split_size_mb=args.split_size_mb))
2064
2065    p = subparsers.add_parser('bdev_split_create',
2066                              help="""Add given disk name to split config. If bdev with base_name
2067    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
2068    available (during examination process).""")
2069    p.add_argument('base_bdev', help='base bdev name')
2070    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int)
2071    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
2072    exceed the base bdev size.""", type=int)
2073    p.set_defaults(func=bdev_split_create)
2074
2075    def bdev_split_delete(args):
2076        rpc.bdev.bdev_split_delete(args.client,
2077                                   base_bdev=args.base_bdev)
2078
2079    p = subparsers.add_parser('bdev_split_delete', help="""Delete split config with all created splits.""")
2080    p.add_argument('base_bdev', help='base bdev name')
2081    p.set_defaults(func=bdev_split_delete)
2082
2083    # ftl
2084    def bdev_ftl_create(args):
2085        print_dict(rpc.bdev.bdev_ftl_create(args.client,
2086                                            name=args.name,
2087                                            base_bdev=args.base_bdev,
2088                                            uuid=args.uuid,
2089                                            cache=args.cache,
2090                                            overprovisioning=args.overprovisioning,
2091                                            l2p_dram_limit=args.l2p_dram_limit,
2092                                            core_mask=args.core_mask,
2093                                            fast_shutdown=args.fast_shutdown))
2094
2095    p = subparsers.add_parser('bdev_ftl_create', help='Add FTL bdev')
2096    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2097    p.add_argument('-d', '--base-bdev', help='Name of bdev used as underlying device',
2098                   required=True)
2099    p.add_argument('-u', '--uuid', help='UUID of restored bdev (not applicable when creating new '
2100                   'instance): e.g. b286d19a-0059-4709-abcd-9f7732b1567d (optional)')
2101    p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache',
2102                   required=True)
2103    p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed'
2104                   ' to user (optional); default 20', type=int)
2105    p.add_argument('--l2p-dram-limit', help='l2p size that could reside in DRAM (optional); default 2048',
2106                   type=int)
2107    p.add_argument('--core-mask', help='CPU core mask - which cores will be used for ftl core thread, '
2108                   'by default core thread will be set to the main application core (optional)')
2109    p.add_argument('-f', '--fast-shutdown', help="Enable fast shutdown", action='store_true')
2110    p.set_defaults(func=bdev_ftl_create)
2111
2112    def bdev_ftl_load(args):
2113        print_dict(rpc.bdev.bdev_ftl_load(args.client,
2114                                          name=args.name,
2115                                          base_bdev=args.base_bdev,
2116                                          uuid=args.uuid,
2117                                          cache=args.cache,
2118                                          overprovisioning=args.overprovisioning,
2119                                          l2p_dram_limit=args.l2p_dram_limit,
2120                                          core_mask=args.core_mask,
2121                                          fast_shutdown=args.fast_shutdown))
2122
2123    p = subparsers.add_parser('bdev_ftl_load', help='Load FTL bdev')
2124    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2125    p.add_argument('-d', '--base-bdev', help='Name of bdev used as underlying device',
2126                   required=True)
2127    p.add_argument('-u', '--uuid', help='UUID of restored bdev', required=True)
2128    p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache',
2129                   required=True)
2130    p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed'
2131                   ' to user (optional); default 20', type=int)
2132    p.add_argument('--l2p-dram-limit', help='l2p size that could reside in DRAM (optional); default 2048',
2133                   type=int)
2134    p.add_argument('--core-mask', help='CPU core mask - which cores will be used for ftl core thread, '
2135                   'by default core thread will be set to the main application core (optional)')
2136    p.add_argument('-f', '--fast-shutdown', help="Enable fast shutdown", action='store_true')
2137    p.set_defaults(func=bdev_ftl_load)
2138
2139    def bdev_ftl_unload(args):
2140        print_dict(rpc.bdev.bdev_ftl_unload(args.client, name=args.name))
2141
2142    p = subparsers.add_parser('bdev_ftl_unload', help='Unload FTL bdev')
2143    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2144    p.add_argument('-f', '--fast-shutdown', help="Fast shutdown", action='store_true')
2145    p.set_defaults(func=bdev_ftl_unload)
2146
2147    def bdev_ftl_delete(args):
2148        print_dict(rpc.bdev.bdev_ftl_delete(args.client, name=args.name, fast_shutdown=args.fast_shutdown))
2149
2150    p = subparsers.add_parser('bdev_ftl_delete', help='Delete FTL bdev')
2151    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2152    p.add_argument('-f', '--fast-shutdown', help="Fast shutdown", action='store_true')
2153    p.set_defaults(func=bdev_ftl_delete)
2154
2155    def bdev_ftl_unmap(args):
2156        print_dict(rpc.bdev.bdev_ftl_unmap(args.client, name=args.name,
2157                                           lba=args.lba,
2158                                           num_blocks=args.num_blocks))
2159
2160    p = subparsers.add_parser('bdev_ftl_unmap', help='FTL unmap')
2161    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2162    p.add_argument('--lba', help='start LBA', required=True, type=int)
2163    p.add_argument('--num-blocks', help='num blocks', required=True, type=int)
2164    p.set_defaults(func=bdev_ftl_unmap)
2165
2166    def bdev_ftl_get_stats(args):
2167        print_dict(rpc.bdev.bdev_ftl_get_stats(args.client, name=args.name))
2168
2169    p = subparsers.add_parser('bdev_ftl_get_stats', help='print ftl stats')
2170    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2171    p.set_defaults(func=bdev_ftl_get_stats)
2172
2173    # vmd
2174    def vmd_enable(args):
2175        print_dict(rpc.vmd.vmd_enable(args.client))
2176
2177    p = subparsers.add_parser('vmd_enable', aliases=['enable_vmd'], help='Enable VMD enumeration')
2178    p.set_defaults(func=vmd_enable)
2179
2180    def vmd_remove_device(args):
2181        print_dict(rpc.vmd.vmd_remove_device(args.client, addr=args.addr))
2182
2183    p = subparsers.add_parser('vmd_remove_device', help='Remove a device behind VMD')
2184    p.add_argument('addr', help='Address of the device to remove', type=str)
2185    p.set_defaults(func=vmd_remove_device)
2186
2187    def vmd_rescan(args):
2188        print_dict(rpc.vmd.vmd_rescan(args.client))
2189
2190    p = subparsers.add_parser('vmd_rescan', help='Force a rescan of the devices behind VMD')
2191    p.set_defaults(func=vmd_rescan)
2192
2193    # nbd
2194    def nbd_start_disk(args):
2195        print(rpc.nbd.nbd_start_disk(args.client,
2196                                     bdev_name=args.bdev_name,
2197                                     nbd_device=args.nbd_device))
2198
2199    p = subparsers.add_parser('nbd_start_disk',
2200                              help='Export a bdev as an nbd disk')
2201    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
2202    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.', nargs='?')
2203    p.set_defaults(func=nbd_start_disk)
2204
2205    def nbd_stop_disk(args):
2206        rpc.nbd.nbd_stop_disk(args.client,
2207                              nbd_device=args.nbd_device)
2208
2209    p = subparsers.add_parser('nbd_stop_disk',
2210                              help='Stop an nbd disk')
2211    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
2212    p.set_defaults(func=nbd_stop_disk)
2213
2214    def nbd_get_disks(args):
2215        print_dict(rpc.nbd.nbd_get_disks(args.client,
2216                                         nbd_device=args.nbd_device))
2217
2218    p = subparsers.add_parser('nbd_get_disks',
2219                              help='Display full or specified nbd device list')
2220    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
2221    p.set_defaults(func=nbd_get_disks)
2222
2223    # NVMe-oF
2224    def nvmf_set_max_subsystems(args):
2225        rpc.nvmf.nvmf_set_max_subsystems(args.client,
2226                                         max_subsystems=args.max_subsystems)
2227
2228    p = subparsers.add_parser('nvmf_set_max_subsystems',
2229                              help='Set the maximum number of NVMf target subsystems')
2230    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True)
2231    p.set_defaults(func=nvmf_set_max_subsystems)
2232
2233    def nvmf_set_config(args):
2234        rpc.nvmf.nvmf_set_config(args.client,
2235                                 passthru_identify_ctrlr=args.passthru_identify_ctrlr,
2236                                 poll_groups_mask=args.poll_groups_mask,
2237                                 discovery_filter=args.discovery_filter)
2238
2239    p = subparsers.add_parser('nvmf_set_config', help='Set NVMf target config')
2240    p.add_argument('-i', '--passthru-identify-ctrlr', help="""Passthrough fields like serial number and model number
2241    when the controller has a single namespace that is an NVMe bdev""", action='store_true')
2242    p.add_argument('-m', '--poll-groups-mask', help='Set cpumask for NVMf poll groups (optional)', type=str)
2243    p.add_argument('-d', '--discovery-filter', help="""Set discovery filter (optional), possible values are: `match_any` (default) or
2244         comma separated values: `transport`, `address`, `svcid`""", type=str)
2245    p.set_defaults(func=nvmf_set_config)
2246
2247    def nvmf_create_transport(args):
2248        rpc.nvmf.nvmf_create_transport(**vars(args))
2249
2250    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
2251    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
2252    p.add_argument('-g', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2253    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
2254    p.add_argument('-m', '--max-io-qpairs-per-ctrlr', help='Max number of IO qpairs per controller', type=int)
2255    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
2256    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
2257    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
2258    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
2259    p.add_argument('-n', '--num-shared-buffers', help='The number of pooled data buffers available to the transport', type=int)
2260    p.add_argument('-b', '--buf-cache-size', help='The number of shared buffers to reserve for each poll group', type=int)
2261    p.add_argument('-z', '--zcopy', action='store_true', help='''Use zero-copy operations if the
2262    underlying bdev supports them''')
2263    p.add_argument('-d', '--num-cqe', help="""The number of CQ entries. Only used when no_srq=true.
2264    Relevant only for RDMA transport""", type=int)
2265    p.add_argument('-s', '--max-srq-depth', help='Max number of outstanding I/O per SRQ. Relevant only for RDMA transport', type=int)
2266    p.add_argument('-r', '--no-srq', action='store_true', help='Disable per-thread shared receive queue. Relevant only for RDMA transport')
2267    p.add_argument('-o', '--c2h-success', action='store_false', help='Disable C2H success optimization. Relevant only for TCP transport')
2268    p.add_argument('-f', '--dif-insert-or-strip', action='store_true', help='Enable DIF insert/strip. Relevant only for TCP transport')
2269    p.add_argument('-y', '--sock-priority', help='The sock priority of the tcp connection. Relevant only for TCP transport', type=int)
2270    p.add_argument('-l', '--acceptor-backlog', help='Pending connections allowed at one time. Relevant only for RDMA transport', type=int)
2271    p.add_argument('-x', '--abort-timeout-sec', help='Abort execution timeout value, in seconds', type=int)
2272    p.add_argument('-w', '--no-wr-batching', action='store_true', help='Disable work requests batching. Relevant only for RDMA transport')
2273    p.add_argument('-e', '--control-msg-num', help="""The number of control messages per poll group.
2274    Relevant only for TCP transport""", type=int)
2275    p.add_argument('-M', '--disable-mappable-bar0', action='store_true', help="""Disable mmap() of BAR0.
2276    Relevant only for VFIO-USER transport""")
2277    p.add_argument('-I', '--disable-adaptive-irq', action='store_true', help="""Disable adaptive interrupt feature.
2278    Relevant only for VFIO-USER transport""")
2279    p.add_argument('-S', '--disable-shadow-doorbells', action='store_true', help="""Disable shadow doorbell support.
2280    Relevant only for VFIO-USER transport""")
2281    p.add_argument('--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
2282    p.set_defaults(func=nvmf_create_transport)
2283
2284    def nvmf_get_transports(args):
2285        print_dict(rpc.nvmf.nvmf_get_transports(args.client, trtype=args.trtype, tgt_name=args.tgt_name))
2286
2287    p = subparsers.add_parser('nvmf_get_transports', help='Display nvmf transports or required transport')
2288    p.add_argument('--trtype', help='Transport type (optional)')
2289    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2290    p.set_defaults(func=nvmf_get_transports)
2291
2292    def nvmf_get_subsystems(args):
2293        print_dict(rpc.nvmf.nvmf_get_subsystems(args.client, nqn=args.nqn, tgt_name=args.tgt_name))
2294
2295    p = subparsers.add_parser('nvmf_get_subsystems', help='Display nvmf subsystems or required subsystem')
2296    p.add_argument('nqn', help='Subsystem NQN (optional)', nargs="?")
2297    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2298    p.set_defaults(func=nvmf_get_subsystems)
2299
2300    def nvmf_create_subsystem(args):
2301        rpc.nvmf.nvmf_create_subsystem(args.client,
2302                                       nqn=args.nqn,
2303                                       tgt_name=args.tgt_name,
2304                                       serial_number=args.serial_number,
2305                                       model_number=args.model_number,
2306                                       allow_any_host=args.allow_any_host,
2307                                       max_namespaces=args.max_namespaces,
2308                                       ana_reporting=args.ana_reporting,
2309                                       min_cntlid=args.min_cntlid,
2310                                       max_cntlid=args.max_cntlid)
2311
2312    p = subparsers.add_parser('nvmf_create_subsystem', help='Create an NVMe-oF subsystem')
2313    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
2314    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2315    p.add_argument("-s", "--serial-number", help="""
2316    Format:  'sn' etc
2317    Example: 'SPDK00000000000001'""")
2318    p.add_argument("-d", "--model-number", help="""
2319    Format:  'mn' etc
2320    Example: 'SPDK Controller'""")
2321    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce allowed host NQN list)")
2322    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
2323                   type=int)
2324    p.add_argument("-r", "--ana-reporting", action='store_true', help="Enable ANA reporting feature")
2325    p.add_argument("-i", "--min_cntlid", help="Minimum controller ID", type=int)
2326    p.add_argument("-I", "--max_cntlid", help="Maximum controller ID", type=int)
2327    p.set_defaults(func=nvmf_create_subsystem)
2328
2329    def nvmf_delete_subsystem(args):
2330        rpc.nvmf.nvmf_delete_subsystem(args.client,
2331                                       nqn=args.subsystem_nqn,
2332                                       tgt_name=args.tgt_name)
2333
2334    p = subparsers.add_parser('nvmf_delete_subsystem', help='Delete a nvmf subsystem')
2335    p.add_argument('subsystem_nqn',
2336                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
2337    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2338    p.set_defaults(func=nvmf_delete_subsystem)
2339
2340    def nvmf_subsystem_add_listener(args):
2341        rpc.nvmf.nvmf_subsystem_add_listener(**vars(args))
2342
2343    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
2344    p.add_argument('nqn', help='NVMe-oF subsystem NQN (\'discovery\' can be used as shortcut for discovery NQN)')
2345    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2346    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2347    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2348    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2349    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number (required for RDMA or TCP)')
2350    p.set_defaults(func=nvmf_subsystem_add_listener)
2351
2352    def nvmf_subsystem_remove_listener(args):
2353        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
2354                                                nqn=args.nqn,
2355                                                trtype=args.trtype,
2356                                                traddr=args.traddr,
2357                                                tgt_name=args.tgt_name,
2358                                                adrfam=args.adrfam,
2359                                                trsvcid=args.trsvcid)
2360
2361    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
2362    p.add_argument('nqn', help='NVMe-oF subsystem NQN (\'discovery\' can be used as shortcut for discovery NQN)')
2363    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2364    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2365    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2366    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2367    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number (required for TCP and RDMA transport types)')
2368    p.set_defaults(func=nvmf_subsystem_remove_listener)
2369
2370    def nvmf_subsystem_listener_set_ana_state(args):
2371        rpc.nvmf.nvmf_subsystem_listener_set_ana_state(args.client,
2372                                                       nqn=args.nqn,
2373                                                       ana_state=args.ana_state,
2374                                                       trtype=args.trtype,
2375                                                       traddr=args.traddr,
2376                                                       tgt_name=args.tgt_name,
2377                                                       adrfam=args.adrfam,
2378                                                       trsvcid=args.trsvcid,
2379                                                       anagrpid=args.anagrpid)
2380
2381    p = subparsers.add_parser('nvmf_subsystem_listener_set_ana_state', help='Set ANA state of a listener for an NVMe-oF subsystem')
2382    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2383    p.add_argument('-n', '--ana-state', help='ANA state to set: optimized, non_optimized, or inaccessible', required=True)
2384    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2385    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2386    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2387    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2388    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
2389    p.add_argument('-g', '--anagrpid', help='ANA group ID (optional)', type=int)
2390    p.set_defaults(func=nvmf_subsystem_listener_set_ana_state)
2391
2392    def nvmf_subsystem_add_ns(args):
2393        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
2394                                       nqn=args.nqn,
2395                                       bdev_name=args.bdev_name,
2396                                       tgt_name=args.tgt_name,
2397                                       ptpl_file=args.ptpl_file,
2398                                       nsid=args.nsid,
2399                                       nguid=args.nguid,
2400                                       eui64=args.eui64,
2401                                       uuid=args.uuid,
2402                                       anagrpid=args.anagrpid)
2403
2404    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
2405    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2406    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
2407    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2408    p.add_argument('-p', '--ptpl-file', help='The persistent reservation storage location (optional)', type=str)
2409    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
2410    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
2411    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
2412    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
2413    p.add_argument('-a', '--anagrpid', help='ANA group ID (optional)', type=int)
2414    p.set_defaults(func=nvmf_subsystem_add_ns)
2415
2416    def nvmf_subsystem_remove_ns(args):
2417        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
2418                                          nqn=args.nqn,
2419                                          nsid=args.nsid,
2420                                          tgt_name=args.tgt_name)
2421
2422    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
2423    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2424    p.add_argument('nsid', help='The requested NSID', type=int)
2425    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2426    p.set_defaults(func=nvmf_subsystem_remove_ns)
2427
2428    def nvmf_subsystem_add_host(args):
2429        rpc.nvmf.nvmf_subsystem_add_host(args.client,
2430                                         nqn=args.nqn,
2431                                         host=args.host,
2432                                         tgt_name=args.tgt_name)
2433
2434    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
2435    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2436    p.add_argument('host', help='Host NQN to allow')
2437    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2438    p.set_defaults(func=nvmf_subsystem_add_host)
2439
2440    def nvmf_subsystem_remove_host(args):
2441        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
2442                                            nqn=args.nqn,
2443                                            host=args.host,
2444                                            tgt_name=args.tgt_name)
2445
2446    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
2447    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2448    p.add_argument('host', help='Host NQN to remove')
2449    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2450    p.set_defaults(func=nvmf_subsystem_remove_host)
2451
2452    def nvmf_subsystem_allow_any_host(args):
2453        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
2454                                               nqn=args.nqn,
2455                                               disable=args.disable,
2456                                               tgt_name=args.tgt_name)
2457
2458    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
2459    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2460    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
2461    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
2462    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2463    p.set_defaults(func=nvmf_subsystem_allow_any_host)
2464
2465    def nvmf_subsystem_get_controllers(args):
2466        print_dict(rpc.nvmf.nvmf_subsystem_get_controllers(args.client,
2467                                                           nqn=args.nqn,
2468                                                           tgt_name=args.tgt_name))
2469
2470    p = subparsers.add_parser('nvmf_subsystem_get_controllers',
2471                              help='Display controllers of an NVMe-oF subsystem.')
2472    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2473    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2474    p.set_defaults(func=nvmf_subsystem_get_controllers)
2475
2476    def nvmf_subsystem_get_qpairs(args):
2477        print_dict(rpc.nvmf.nvmf_subsystem_get_qpairs(args.client,
2478                                                      nqn=args.nqn,
2479                                                      tgt_name=args.tgt_name))
2480
2481    p = subparsers.add_parser('nvmf_subsystem_get_qpairs',
2482                              help='Display queue pairs of an NVMe-oF subsystem.')
2483    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2484    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2485    p.set_defaults(func=nvmf_subsystem_get_qpairs)
2486
2487    def nvmf_subsystem_get_listeners(args):
2488        print_dict(rpc.nvmf.nvmf_subsystem_get_listeners(args.client,
2489                                                         nqn=args.nqn,
2490                                                         tgt_name=args.tgt_name))
2491
2492    p = subparsers.add_parser('nvmf_subsystem_get_listeners',
2493                              help='Display listeners of an NVMe-oF subsystem.')
2494    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2495    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2496    p.set_defaults(func=nvmf_subsystem_get_listeners)
2497
2498    def nvmf_get_stats(args):
2499        print_dict(rpc.nvmf.nvmf_get_stats(args.client, tgt_name=args.tgt_name))
2500
2501    p = subparsers.add_parser(
2502        'nvmf_get_stats', help='Display current statistics for NVMf subsystem')
2503    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2504    p.set_defaults(func=nvmf_get_stats)
2505
2506    def nvmf_set_crdt(args):
2507        print_dict(rpc.nvmf.nvmf_set_crdt(args.client, args.crdt1, args.crdt2, args.crdt3))
2508
2509    p = subparsers.add_parser(
2510        'nvmf_set_crdt',
2511        help="""Set the 3 crdt (Command Retry Delay Time) values for NVMf subsystem. All
2512        values are in units of 100 milliseconds (same as the NVM Express specification).""")
2513    p.add_argument('-t1', '--crdt1', help='Command Retry Delay Time 1, in units of 100 milliseconds', type=int)
2514    p.add_argument('-t2', '--crdt2', help='Command Retry Delay Time 2, in units of 100 milliseconds', type=int)
2515    p.add_argument('-t3', '--crdt3', help='Command Retry Delay Time 3, in units of 100 milliseconds', type=int)
2516    p.set_defaults(func=nvmf_set_crdt)
2517
2518    # pmem
2519    def bdev_pmem_create_pool(args):
2520        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
2521        rpc.pmem.bdev_pmem_create_pool(args.client,
2522                                       pmem_file=args.pmem_file,
2523                                       num_blocks=num_blocks,
2524                                       block_size=args.block_size)
2525
2526    p = subparsers.add_parser('bdev_pmem_create_pool', help='Create pmem pool')
2527    p.add_argument('pmem_file', help='Path to pmemblk pool file')
2528    p.add_argument('total_size', help='Size of pmem bdev in MB (int > 0)', type=int)
2529    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
2530    p.set_defaults(func=bdev_pmem_create_pool)
2531
2532    def bdev_pmem_get_pool_info(args):
2533        print_dict(rpc.pmem.bdev_pmem_get_pool_info(args.client,
2534                                                    pmem_file=args.pmem_file))
2535
2536    p = subparsers.add_parser('bdev_pmem_get_pool_info', help='Display pmem pool info and check consistency')
2537    p.add_argument('pmem_file', help='Path to pmemblk pool file')
2538    p.set_defaults(func=bdev_pmem_get_pool_info)
2539
2540    def bdev_pmem_delete_pool(args):
2541        rpc.pmem.bdev_pmem_delete_pool(args.client,
2542                                       pmem_file=args.pmem_file)
2543
2544    p = subparsers.add_parser('bdev_pmem_delete_pool', help='Delete pmem pool')
2545    p.add_argument('pmem_file', help='Path to pmemblk pool file')
2546    p.set_defaults(func=bdev_pmem_delete_pool)
2547
2548    # subsystem
2549    def framework_get_subsystems(args):
2550        print_dict(rpc.subsystem.framework_get_subsystems(args.client))
2551
2552    p = subparsers.add_parser('framework_get_subsystems',
2553                              help="""Print subsystems array in initialization order. Each subsystem
2554    entry contain (unsorted) array of subsystems it depends on.""")
2555    p.set_defaults(func=framework_get_subsystems)
2556
2557    def framework_get_config(args):
2558        print_dict(rpc.subsystem.framework_get_config(args.client, args.name))
2559
2560    p = subparsers.add_parser('framework_get_config', help="""Print subsystem configuration""")
2561    p.add_argument('name', help='Name of subsystem to query')
2562    p.set_defaults(func=framework_get_config)
2563
2564    # vhost
2565    def vhost_controller_set_coalescing(args):
2566        rpc.vhost.vhost_controller_set_coalescing(args.client,
2567                                                  ctrlr=args.ctrlr,
2568                                                  delay_base_us=args.delay_base_us,
2569                                                  iops_threshold=args.iops_threshold)
2570
2571    p = subparsers.add_parser('vhost_controller_set_coalescing', help='Set vhost controller coalescing')
2572    p.add_argument('ctrlr', help='controller name')
2573    p.add_argument('delay_base_us', help='Base delay time', type=int)
2574    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
2575    p.set_defaults(func=vhost_controller_set_coalescing)
2576
2577    def virtio_blk_create_transport(args):
2578        rpc.vhost.virtio_blk_create_transport(**vars(args))
2579
2580    p = subparsers.add_parser('virtio_blk_create_transport',
2581                              help='Create virtio blk transport')
2582    p.add_argument('name', help='transport name')
2583    p.set_defaults(func=virtio_blk_create_transport)
2584
2585    def vhost_create_scsi_controller(args):
2586        rpc.vhost.vhost_create_scsi_controller(args.client,
2587                                               ctrlr=args.ctrlr,
2588                                               cpumask=args.cpumask)
2589
2590    p = subparsers.add_parser('vhost_create_scsi_controller', help='Add new vhost controller')
2591    p.add_argument('ctrlr', help='controller name')
2592    p.add_argument('--cpumask', help='cpu mask for this controller')
2593    p.set_defaults(func=vhost_create_scsi_controller)
2594
2595    def vhost_scsi_controller_add_target(args):
2596        print_json(rpc.vhost.vhost_scsi_controller_add_target(args.client,
2597                                                              ctrlr=args.ctrlr,
2598                                                              scsi_target_num=args.scsi_target_num,
2599                                                              bdev_name=args.bdev_name))
2600
2601    p = subparsers.add_parser('vhost_scsi_controller_add_target', help='Add lun to vhost controller')
2602    p.add_argument('ctrlr', help='controller name where add lun')
2603    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
2604    p.add_argument('bdev_name', help='bdev name')
2605    p.set_defaults(func=vhost_scsi_controller_add_target)
2606
2607    def vhost_scsi_controller_remove_target(args):
2608        rpc.vhost.vhost_scsi_controller_remove_target(args.client,
2609                                                      ctrlr=args.ctrlr,
2610                                                      scsi_target_num=args.scsi_target_num)
2611
2612    p = subparsers.add_parser('vhost_scsi_controller_remove_target',
2613                              help='Remove target from vhost controller')
2614    p.add_argument('ctrlr', help='controller name to remove target from')
2615    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
2616    p.set_defaults(func=vhost_scsi_controller_remove_target)
2617
2618    def vhost_create_blk_controller(args):
2619        rpc.vhost.vhost_create_blk_controller(**vars(args))
2620
2621    p = subparsers.add_parser('vhost_create_blk_controller', help='Add a new vhost block controller')
2622    p.add_argument('ctrlr', help='controller name')
2623    p.add_argument('dev_name', help='device name')
2624    p.add_argument('--cpumask', help='cpu mask for this controller')
2625    p.add_argument('--transport', help='virtio blk transport name (default: vhost_user_blk)')
2626    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
2627    p.add_argument("-p", "--packed_ring", action='store_true', help='Set controller as packed ring supported')
2628    p.add_argument("-l", "--packed_ring_recovery", action='store_true', help='Enable packed ring live recovery')
2629    p.set_defaults(func=vhost_create_blk_controller)
2630
2631    def vhost_get_controllers(args):
2632        print_dict(rpc.vhost.vhost_get_controllers(args.client, args.name))
2633
2634    p = subparsers.add_parser('vhost_get_controllers', help='List all or specific vhost controller(s)')
2635    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
2636    p.set_defaults(func=vhost_get_controllers)
2637
2638    def vhost_delete_controller(args):
2639        rpc.vhost.vhost_delete_controller(args.client,
2640                                          ctrlr=args.ctrlr)
2641
2642    p = subparsers.add_parser('vhost_delete_controller', help='Delete a vhost controller')
2643    p.add_argument('ctrlr', help='controller name')
2644    p.set_defaults(func=vhost_delete_controller)
2645
2646    def bdev_virtio_attach_controller(args):
2647        print_array(rpc.vhost.bdev_virtio_attach_controller(args.client,
2648                                                            name=args.name,
2649                                                            trtype=args.trtype,
2650                                                            traddr=args.traddr,
2651                                                            dev_type=args.dev_type,
2652                                                            vq_count=args.vq_count,
2653                                                            vq_size=args.vq_size))
2654
2655    p = subparsers.add_parser('bdev_virtio_attach_controller',
2656                              help="""Attach virtio controller using provided
2657    transport type and device type. This will also create bdevs for any block devices connected to the
2658    controller (for example, SCSI devices for a virtio-scsi controller).
2659    Result is array of added bdevs.""")
2660    p.add_argument('name', help="Use this name as base for new created bdevs")
2661    p.add_argument('-t', '--trtype',
2662                   help='Virtio target transport type: pci or user', required=True)
2663    p.add_argument('-a', '--traddr',
2664                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
2665    p.add_argument('-d', '--dev-type',
2666                   help='Device type: blk or scsi', required=True)
2667    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
2668    p.add_argument('--vq-size', help='Size of each queue', type=int)
2669    p.set_defaults(func=bdev_virtio_attach_controller)
2670
2671    def bdev_virtio_scsi_get_devices(args):
2672        print_dict(rpc.vhost.bdev_virtio_scsi_get_devices(args.client))
2673
2674    p = subparsers.add_parser('bdev_virtio_scsi_get_devices', help='List all Virtio-SCSI devices.')
2675    p.set_defaults(func=bdev_virtio_scsi_get_devices)
2676
2677    def bdev_virtio_detach_controller(args):
2678        rpc.vhost.bdev_virtio_detach_controller(args.client,
2679                                                name=args.name)
2680
2681    p = subparsers.add_parser('bdev_virtio_detach_controller', help="""Remove a Virtio device
2682    This will delete all bdevs exposed by this device""")
2683    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
2684    p.set_defaults(func=bdev_virtio_detach_controller)
2685
2686    def bdev_virtio_blk_set_hotplug(args):
2687        rpc.vhost.bdev_virtio_blk_set_hotplug(args.client, enable=args.enable, period_us=args.period_us)
2688
2689    p = subparsers.add_parser('bdev_virtio_blk_set_hotplug', help='Set hotplug options for bdev virtio_blk type.')
2690    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
2691    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
2692    p.add_argument('-r', '--period-us',
2693                   help='How often the hotplug is processed for insert and remove events', type=int)
2694    p.set_defaults(func=bdev_virtio_blk_set_hotplug)
2695
2696    # vfio-user target
2697    def vfu_tgt_set_base_path(args):
2698        rpc.vfio_user.vfu_tgt_set_base_path(args.client, path=args.path)
2699
2700    p = subparsers.add_parser('vfu_tgt_set_base_path', help='Set socket base path.')
2701    p.add_argument('path', help='socket base path')
2702    p.set_defaults(func=vfu_tgt_set_base_path)
2703
2704    def vfu_virtio_delete_endpoint(args):
2705        rpc.vfio_user.vfu_virtio_delete_endpoint(args.client, name=args.name)
2706
2707    p = subparsers.add_parser('vfu_virtio_delete_endpoint', help='Delete the PCI device via endpoint name.')
2708    p.add_argument('name', help='Endpoint name')
2709    p.set_defaults(func=vfu_virtio_delete_endpoint)
2710
2711    def vfu_virtio_create_blk_endpoint(args):
2712        rpc.vfio_user.vfu_virtio_create_blk_endpoint(args.client,
2713                                                     name=args.name,
2714                                                     bdev_name=args.bdev_name,
2715                                                     cpumask=args.cpumask,
2716                                                     num_queues=args.num_queues,
2717                                                     qsize=args.qsize,
2718                                                     packed_ring=args.packed_ring)
2719
2720    p = subparsers.add_parser('vfu_virtio_create_blk_endpoint', help='Create virtio-blk endpoint.')
2721    p.add_argument('name', help='Name of the endpoint')
2722    p.add_argument('--bdev-name', help='block device name', type=str, required=True)
2723    p.add_argument('--cpumask', help='CPU masks')
2724    p.add_argument('--num-queues', help='number of vrings', type=int, default=0)
2725    p.add_argument('--qsize', help='number of element for each vring', type=int, default=0)
2726    p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
2727    p.set_defaults(func=vfu_virtio_create_blk_endpoint)
2728
2729    def vfu_virtio_scsi_add_target(args):
2730        rpc.vfio_user.vfu_virtio_scsi_add_target(args.client,
2731                                                 name=args.name,
2732                                                 scsi_target_num=args.scsi_target_num,
2733                                                 bdev_name=args.bdev_name)
2734
2735    p = subparsers.add_parser('vfu_virtio_scsi_add_target', help='Attach a block device to SCSI target of PCI endpoint.')
2736    p.add_argument('name', help='Name of the endpoint')
2737    p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
2738    p.add_argument('--bdev-name', help='block device name', type=str, required=True)
2739    p.set_defaults(func=vfu_virtio_scsi_add_target)
2740
2741    def vfu_virtio_scsi_remove_target(args):
2742        rpc.vfio_user.vfu_virtio_scsi_remove_target(args.client,
2743                                                    name=args.name,
2744                                                    scsi_target_num=args.scsi_target_num)
2745
2746    p = subparsers.add_parser('vfu_virtio_scsi_remove_target', help='Remove the specified SCSI target of PCI endpoint.')
2747    p.add_argument('name', help='Name of the endpoint')
2748    p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
2749    p.set_defaults(func=vfu_virtio_scsi_remove_target)
2750
2751    def vfu_virtio_create_scsi_endpoint(args):
2752        rpc.vfio_user.vfu_virtio_create_scsi_endpoint(args.client,
2753                                                      name=args.name,
2754                                                      cpumask=args.cpumask,
2755                                                      num_io_queues=args.num_io_queues,
2756                                                      qsize=args.qsize,
2757                                                      packed_ring=args.packed_ring)
2758
2759    p = subparsers.add_parser('vfu_virtio_create_scsi_endpoint', help='Create virtio-scsi endpoint.')
2760    p.add_argument('name', help='Name of the endpoint')
2761    p.add_argument('--cpumask', help='CPU masks')
2762    p.add_argument('--num-io-queues', help='number of IO vrings', type=int, default=0)
2763    p.add_argument('--qsize', help='number of element for each vring', type=int, default=0)
2764    p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
2765    p.set_defaults(func=vfu_virtio_create_scsi_endpoint)
2766
2767    # accel_fw
2768    def accel_get_opc_assignments(args):
2769        print_dict(rpc.accel.accel_get_opc_assignments(args.client))
2770
2771    p = subparsers.add_parser('accel_get_opc_assignments', help='Get list of opcode name to module assignments.')
2772    p.set_defaults(func=accel_get_opc_assignments)
2773
2774    def accel_get_module_info(args):
2775        print_dict(rpc.accel.accel_get_module_info(args.client))
2776
2777    p = subparsers.add_parser('accel_get_module_info', help='Get list of valid module names and their operations.')
2778    p.set_defaults(func=accel_get_module_info)
2779
2780    def accel_assign_opc(args):
2781        rpc.accel.accel_assign_opc(args.client, opname=args.opname, module=args.module)
2782
2783    p = subparsers.add_parser('accel_assign_opc', help='Manually assign an operation to a module.')
2784    p.add_argument('-o', '--opname', help='opname')
2785    p.add_argument('-m', '--module', help='name of module')
2786    p.set_defaults(func=accel_assign_opc)
2787
2788    # ioat
2789    def ioat_scan_accel_module(args):
2790        rpc.ioat.ioat_scan_accel_module(args.client)
2791
2792    p = subparsers.add_parser('ioat_scan_accel_module', help='Enable IOAT accel module offload.')
2793    p.set_defaults(func=ioat_scan_accel_module)
2794
2795    # dsa
2796    def dsa_scan_accel_module(args):
2797        rpc.dsa.dsa_scan_accel_module(args.client, config_kernel_mode=args.config_kernel_mode)
2798
2799    p = subparsers.add_parser('dsa_scan_accel_module',
2800                              help='Set config and enable dsa accel module offload.')
2801    p.add_argument('-k', '--config-kernel-mode', help='Use Kernel mode dsa',
2802                   action='store_true', dest='config_kernel_mode')
2803    p.set_defaults(func=dsa_scan_accel_module, config_kernel_mode=None)
2804
2805    # iaa
2806    def iaa_scan_accel_module(args):
2807        rpc.iaa.iaa_scan_accel_module(args.client)
2808
2809    p = subparsers.add_parser('iaa_scan_accel_module',
2810                              help='Set config and enable iaa accel module offload.')
2811    p.set_defaults(func=iaa_scan_accel_module)
2812
2813    # opal
2814    def bdev_nvme_opal_init(args):
2815        rpc.nvme.bdev_nvme_opal_init(args.client,
2816                                     nvme_ctrlr_name=args.nvme_ctrlr_name,
2817                                     password=args.password)
2818
2819    p = subparsers.add_parser('bdev_nvme_opal_init', help='take ownership and activate')
2820    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
2821    p.add_argument('-p', '--password', help='password for admin')
2822    p.set_defaults(func=bdev_nvme_opal_init)
2823
2824    def bdev_nvme_opal_revert(args):
2825        rpc.nvme.bdev_nvme_opal_revert(args.client,
2826                                       nvme_ctrlr_name=args.nvme_ctrlr_name,
2827                                       password=args.password)
2828    p = subparsers.add_parser('bdev_nvme_opal_revert', help='Revert to default factory settings')
2829    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
2830    p.add_argument('-p', '--password', help='password')
2831    p.set_defaults(func=bdev_nvme_opal_revert)
2832
2833    def bdev_opal_create(args):
2834        print_json(rpc.bdev.bdev_opal_create(args.client,
2835                                             nvme_ctrlr_name=args.nvme_ctrlr_name,
2836                                             nsid=args.nsid,
2837                                             locking_range_id=args.locking_range_id,
2838                                             range_start=args.range_start,
2839                                             range_length=args.range_length,
2840                                             password=args.password))
2841
2842    p = subparsers.add_parser('bdev_opal_create', help="""Create opal bdev on specified NVMe controller""")
2843    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name', required=True)
2844    p.add_argument('-n', '--nsid', help='namespace ID (only support nsid=1 for now)', type=int, required=True)
2845    p.add_argument('-i', '--locking-range-id', help='locking range id', type=int, required=True)
2846    p.add_argument('-s', '--range-start', help='locking range start LBA', type=int, required=True)
2847    p.add_argument('-l', '--range-length', help='locking range length (in blocks)', type=int, required=True)
2848    p.add_argument('-p', '--password', help='admin password', required=True)
2849    p.set_defaults(func=bdev_opal_create)
2850
2851    def bdev_opal_get_info(args):
2852        print_dict(rpc.bdev.bdev_opal_get_info(args.client,
2853                                               bdev_name=args.bdev_name,
2854                                               password=args.password))
2855
2856    p = subparsers.add_parser('bdev_opal_get_info', help='get opal locking range info for this bdev')
2857    p.add_argument('-b', '--bdev-name', help='opal bdev')
2858    p.add_argument('-p', '--password', help='password')
2859    p.set_defaults(func=bdev_opal_get_info)
2860
2861    def bdev_opal_delete(args):
2862        rpc.bdev.bdev_opal_delete(args.client,
2863                                  bdev_name=args.bdev_name,
2864                                  password=args.password)
2865
2866    p = subparsers.add_parser('bdev_opal_delete', help="""delete a virtual opal bdev""")
2867    p.add_argument('-b', '--bdev-name', help='opal virtual bdev', required=True)
2868    p.add_argument('-p', '--password', help='admin password', required=True)
2869    p.set_defaults(func=bdev_opal_delete)
2870
2871    def bdev_opal_new_user(args):
2872        rpc.bdev.bdev_opal_new_user(args.client,
2873                                    bdev_name=args.bdev_name,
2874                                    admin_password=args.admin_password,
2875                                    user_id=args.user_id,
2876                                    user_password=args.user_password)
2877
2878    p = subparsers.add_parser('bdev_opal_new_user', help="""Add a user to opal bdev who can set lock state for this bdev""")
2879    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
2880    p.add_argument('-p', '--admin-password', help='admin password', required=True)
2881    p.add_argument('-i', '--user-id', help='ID for new user', type=int, required=True)
2882    p.add_argument('-u', '--user-password', help='password set for this user', required=True)
2883    p.set_defaults(func=bdev_opal_new_user)
2884
2885    def bdev_opal_set_lock_state(args):
2886        rpc.bdev.bdev_opal_set_lock_state(args.client,
2887                                          bdev_name=args.bdev_name,
2888                                          user_id=args.user_id,
2889                                          password=args.password,
2890                                          lock_state=args.lock_state)
2891
2892    p = subparsers.add_parser('bdev_opal_set_lock_state', help="""set lock state for an opal bdev""")
2893    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
2894    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',
2895                   type=int, required=True)
2896    p.add_argument('-p', '--password', help='password of this user', required=True)
2897    p.add_argument('-l', '--lock-state', help='lock state to set, choose from {readwrite, readonly, rwlock}', required=True)
2898    p.set_defaults(func=bdev_opal_set_lock_state)
2899
2900    # bdev_nvme_send_cmd
2901    def bdev_nvme_send_cmd(args):
2902        print_dict(rpc.nvme.bdev_nvme_send_cmd(args.client,
2903                                               name=args.nvme_name,
2904                                               cmd_type=args.cmd_type,
2905                                               data_direction=args.data_direction,
2906                                               cmdbuf=args.cmdbuf,
2907                                               data=args.data,
2908                                               metadata=args.metadata,
2909                                               data_len=args.data_length,
2910                                               metadata_len=args.metadata_length,
2911                                               timeout_ms=args.timeout_ms))
2912
2913    p = subparsers.add_parser('bdev_nvme_send_cmd', help='NVMe passthrough cmd.')
2914    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
2915    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
2916    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
2917    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
2918    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
2919    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
2920    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
2921    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
2922    p.add_argument('-T', '--timeout-ms',
2923                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int)
2924    p.set_defaults(func=bdev_nvme_send_cmd)
2925
2926    # Notifications
2927    def notify_get_types(args):
2928        print_dict(rpc.notify.notify_get_types(args.client))
2929
2930    p = subparsers.add_parser('notify_get_types', help='List available notifications that user can subscribe to.')
2931    p.set_defaults(func=notify_get_types)
2932
2933    def notify_get_notifications(args):
2934        ret = rpc.notify.notify_get_notifications(args.client,
2935                                                  id=args.id,
2936                                                  max=args.max)
2937        print_dict(ret)
2938
2939    p = subparsers.add_parser('notify_get_notifications', help='Get notifications')
2940    p.add_argument('-i', '--id', help="""First ID to start fetching from""", type=int)
2941    p.add_argument('-n', '--max', help="""Maximum number of notifications to return in response""", type=int)
2942    p.set_defaults(func=notify_get_notifications)
2943
2944    def thread_get_stats(args):
2945        print_dict(rpc.app.thread_get_stats(args.client))
2946
2947    p = subparsers.add_parser(
2948        'thread_get_stats', help='Display current statistics of all the threads')
2949    p.set_defaults(func=thread_get_stats)
2950
2951    def thread_set_cpumask(args):
2952        ret = rpc.app.thread_set_cpumask(args.client,
2953                                         id=args.id,
2954                                         cpumask=args.cpumask)
2955    p = subparsers.add_parser('thread_set_cpumask',
2956                              help="""set the cpumask of the thread whose ID matches to the
2957    specified value. The thread may be migrated to one of the specified CPUs.""")
2958    p.add_argument('-i', '--id', type=int, help='thread ID')
2959    p.add_argument('-m', '--cpumask', help='cpumask for this thread')
2960    p.set_defaults(func=thread_set_cpumask)
2961
2962    def log_enable_timestamps(args):
2963        ret = rpc.app.log_enable_timestamps(args.client,
2964                                            enabled=args.enabled)
2965    p = subparsers.add_parser('log_enable_timestamps',
2966                              help='Enable or disable timestamps.')
2967    p.add_argument('-d', '--disable', dest='enabled', default=False, action='store_false', help="Disable timestamps")
2968    p.add_argument('-e', '--enable', dest='enabled', action='store_true', help="Enable timestamps")
2969    p.set_defaults(func=log_enable_timestamps)
2970
2971    def thread_get_pollers(args):
2972        print_dict(rpc.app.thread_get_pollers(args.client))
2973
2974    p = subparsers.add_parser(
2975        'thread_get_pollers', help='Display current pollers of all the threads')
2976    p.set_defaults(func=thread_get_pollers)
2977
2978    def thread_get_io_channels(args):
2979        print_dict(rpc.app.thread_get_io_channels(args.client))
2980
2981    p = subparsers.add_parser(
2982        'thread_get_io_channels', help='Display current IO channels of all the threads')
2983    p.set_defaults(func=thread_get_io_channels)
2984
2985    def env_dpdk_get_mem_stats(args):
2986        print_dict(rpc.env_dpdk.env_dpdk_get_mem_stats(args.client))
2987
2988    p = subparsers.add_parser(
2989        'env_dpdk_get_mem_stats', help='write the dpdk memory stats to a file.')
2990    p.set_defaults(func=env_dpdk_get_mem_stats)
2991
2992    # blobfs
2993    def blobfs_detect(args):
2994        print(rpc.blobfs.blobfs_detect(args.client,
2995                                       bdev_name=args.bdev_name))
2996
2997    p = subparsers.add_parser('blobfs_detect', help='Detect whether a blobfs exists on bdev')
2998    p.add_argument('bdev_name', help='Blockdev name to detect blobfs. Example: Malloc0.')
2999    p.set_defaults(func=blobfs_detect)
3000
3001    def blobfs_create(args):
3002        print(rpc.blobfs.blobfs_create(args.client,
3003                                       bdev_name=args.bdev_name,
3004                                       cluster_sz=args.cluster_sz))
3005
3006    p = subparsers.add_parser('blobfs_create', help='Build a blobfs on bdev')
3007    p.add_argument('bdev_name', help='Blockdev name to build blobfs. Example: Malloc0.')
3008    p.add_argument('-c', '--cluster-sz',
3009                   help="""Size of cluster in bytes (Optional). Must be multiple of 4KB page size. Default and minimal value is 1M.""")
3010    p.set_defaults(func=blobfs_create)
3011
3012    def blobfs_mount(args):
3013        print(rpc.blobfs.blobfs_mount(args.client,
3014                                      bdev_name=args.bdev_name,
3015                                      mountpoint=args.mountpoint))
3016
3017    p = subparsers.add_parser('blobfs_mount', help='Mount a blobfs on bdev to host path by FUSE')
3018    p.add_argument('bdev_name', help='Blockdev name where the blobfs is. Example: Malloc0.')
3019    p.add_argument('mountpoint', help='Mountpoint path in host to mount blobfs. Example: /mnt/.')
3020    p.set_defaults(func=blobfs_mount)
3021
3022    def blobfs_set_cache_size(args):
3023        print(rpc.blobfs.blobfs_set_cache_size(args.client,
3024                                               size_in_mb=args.size_in_mb))
3025
3026    p = subparsers.add_parser('blobfs_set_cache_size', help='Set cache size for blobfs')
3027    p.add_argument('size_in_mb', help='Cache size for blobfs in megabytes.', type=int)
3028    p.set_defaults(func=blobfs_set_cache_size)
3029
3030    # sock
3031    def sock_impl_get_options(args):
3032        print_json(rpc.sock.sock_impl_get_options(args.client,
3033                                                  impl_name=args.impl))
3034
3035    p = subparsers.add_parser('sock_impl_get_options', help="""Get options of socket layer implementation""")
3036    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3037    p.set_defaults(func=sock_impl_get_options)
3038
3039    def sock_impl_set_options(args):
3040        rpc.sock.sock_impl_set_options(args.client,
3041                                       impl_name=args.impl,
3042                                       recv_buf_size=args.recv_buf_size,
3043                                       send_buf_size=args.send_buf_size,
3044                                       enable_recv_pipe=args.enable_recv_pipe,
3045                                       enable_quickack=args.enable_quickack,
3046                                       enable_placement_id=args.enable_placement_id,
3047                                       enable_zerocopy_send_server=args.enable_zerocopy_send_server,
3048                                       enable_zerocopy_send_client=args.enable_zerocopy_send_client,
3049                                       zerocopy_threshold=args.zerocopy_threshold,
3050                                       tls_version=args.tls_version,
3051                                       enable_ktls=args.enable_ktls,
3052                                       psk_key=args.psk_key,
3053                                       psk_identity=args.psk_identity)
3054
3055    p = subparsers.add_parser('sock_impl_set_options', help="""Set options of socket layer implementation""")
3056    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3057    p.add_argument('-r', '--recv-buf-size', help='Size of receive buffer on socket in bytes', type=int)
3058    p.add_argument('-s', '--send-buf-size', help='Size of send buffer on socket in bytes', type=int)
3059    p.add_argument('-p', '--enable-placement-id', help='Option for placement-id. 0:disable,1:incoming_napi,2:incoming_cpu', type=int)
3060    p.add_argument('--enable-recv-pipe', help='Enable receive pipe',
3061                   action='store_true', dest='enable_recv_pipe')
3062    p.add_argument('--disable-recv-pipe', help='Disable receive pipe',
3063                   action='store_false', dest='enable_recv_pipe')
3064    p.add_argument('--enable-quickack', help='Enable quick ACK',
3065                   action='store_true', dest='enable_quickack')
3066    p.add_argument('--disable-quickack', help='Disable quick ACK',
3067                   action='store_false', dest='enable_quickack')
3068    p.add_argument('--enable-zerocopy-send-server', help='Enable zerocopy on send for server sockets',
3069                   action='store_true', dest='enable_zerocopy_send_server')
3070    p.add_argument('--disable-zerocopy-send-server', help='Disable zerocopy on send for server sockets',
3071                   action='store_false', dest='enable_zerocopy_send_server')
3072    p.add_argument('--enable-zerocopy-send-client', help='Enable zerocopy on send for client sockets',
3073                   action='store_true', dest='enable_zerocopy_send_client')
3074    p.add_argument('--disable-zerocopy-send-client', help='Disable zerocopy on send for client sockets',
3075                   action='store_false', dest='enable_zerocopy_send_client')
3076    p.add_argument('--zerocopy-threshold', help='Set zerocopy_threshold in bytes', type=int)
3077    p.add_argument('--tls-version', help='TLS protocol version', type=int)
3078    p.add_argument('--enable-ktls', help='Enable Kernel TLS',
3079                   action='store_true', dest='enable_ktls')
3080    p.add_argument('--disable-ktls', help='Disable Kernel TLS',
3081                   action='store_false', dest='enable_ktls')
3082    p.add_argument('--psk-key', help='Set default PSK KEY', dest='psk_key')
3083    p.add_argument('--psk-identity', help='Set default PSK ID', dest='psk_identity')
3084    p.set_defaults(func=sock_impl_set_options, enable_recv_pipe=None, enable_quickack=None,
3085                   enable_placement_id=None, enable_zerocopy_send_server=None, enable_zerocopy_send_client=None,
3086                   zerocopy_threshold=None, tls_version=None, enable_ktls=None, psk_key=None, psk_identity=None)
3087
3088    def sock_set_default_impl(args):
3089        print_json(rpc.sock.sock_set_default_impl(args.client,
3090                                                  impl_name=args.impl))
3091
3092    p = subparsers.add_parser('sock_set_default_impl', help="""Set the default sock implementation""")
3093    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3094    p.set_defaults(func=sock_set_default_impl)
3095
3096    def framework_get_pci_devices(args):
3097        def splitbuf(buf, step):
3098            return [buf[i:i+step] for i in range(0, len(buf), step)]
3099
3100        devices = rpc.subsystem.framework_get_pci_devices(args.client)
3101        if not args.format_lspci:
3102            print_json(devices)
3103        else:
3104            for devid, dev in enumerate(devices):
3105                print('{} device #{}'.format(dev['address'], devid))
3106                for lineid, line in enumerate(splitbuf(dev['config_space'], 32)):
3107                    print('{:02x}: {}'.format(lineid * 16, ' '.join(splitbuf(line.lower(), 2))))
3108                print()
3109
3110    p = subparsers.add_parser('framework_get_pci_devices', help='''Get a list of attached PCI devices''')
3111    p.add_argument('--format-lspci', help='Format the output in a way to be consumed by lspci -F',
3112                   action='store_true')
3113    p.set_defaults(func=framework_get_pci_devices)
3114
3115    # bdev_nvme_add_error_injection
3116    def bdev_nvme_add_error_injection(args):
3117        print_dict(rpc.nvme.bdev_nvme_add_error_injection(args.client,
3118                                                          name=args.nvme_name,
3119                                                          cmd_type=args.cmd_type,
3120                                                          opc=args.opc,
3121                                                          do_not_submit=args.do_not_submit,
3122                                                          timeout_in_us=args.timeout_in_us,
3123                                                          err_count=args.err_count,
3124                                                          sct=args.sct,
3125                                                          sc=args.sc))
3126    p = subparsers.add_parser('bdev_nvme_add_error_injection',
3127                              help='Add a NVMe command error injection.')
3128    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""", required=True)
3129    p.add_argument('-t', '--cmd-type', help="""Type of NVMe command. Valid values are: admin, io""", required=True)
3130    p.add_argument('-o', '--opc', help="""Opcode of the NVMe command.""", required=True, type=int)
3131    p.add_argument('-s', '--do-not-submit',
3132                   help="""Set to true if request should not be submitted to the controller""",
3133                   dest="do_not_submit", action='store_true')
3134    p.add_argument('-w', '--timeout-in-us', help="""Wait specified microseconds when do_not_submit is true""", type=int)
3135    p.add_argument('-e', '--err-count', help="""Number of matching NVMe commands to inject errors""", type=int)
3136    p.add_argument('-u', '--sct', help="""Status code type""", type=int)
3137    p.add_argument('-c', '--sc', help="""Status code""", type=int)
3138    p.set_defaults(func=bdev_nvme_add_error_injection)
3139
3140    # bdev_nvme_remove_error_injection
3141    def bdev_nvme_remove_error_injection(args):
3142        print_dict(rpc.nvme.bdev_nvme_remove_error_injection(args.client,
3143                                                             name=args.nvme_name,
3144                                                             cmd_type=args.cmd_type,
3145                                                             opc=args.opc))
3146    p = subparsers.add_parser('bdev_nvme_remove_error_injection',
3147                              help='Removes a NVMe command error injection.')
3148    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""", required=True)
3149    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""", required=True)
3150    p.add_argument('-o', '--opc', help="""Opcode of the nvme cmd.""", required=True, type=int)
3151    p.set_defaults(func=bdev_nvme_remove_error_injection)
3152
3153    def bdev_daos_create(args):
3154        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
3155        print_json(rpc.bdev.bdev_daos_create(args.client,
3156                                             num_blocks=int(num_blocks),
3157                                             block_size=args.block_size,
3158                                             name=args.name,
3159                                             uuid=args.uuid,
3160                                             pool=args.pool,
3161                                             cont=args.cont,
3162                                             oclass=args.oclass))
3163    p = subparsers.add_parser('bdev_daos_create',
3164                              help='Create a bdev with DAOS backend')
3165    p.add_argument('name', help="Name of the bdev")
3166    p.add_argument('pool', help="UUID of the DAOS pool")
3167    p.add_argument('cont', help="UUID of the DAOS container")
3168    p.add_argument(
3169        'total_size', help='Size of DAOS bdev in MB (float > 0)', type=float)
3170    p.add_argument('block_size', help='Block size for this bdev', type=int)
3171    p.add_argument('-u', '--uuid', help="UUID of the bdev")
3172    p.add_argument('-o', '--oclass', help="DAOS object class")
3173    p.set_defaults(func=bdev_daos_create)
3174
3175    def bdev_daos_delete(args):
3176        rpc.bdev.bdev_daos_delete(args.client,
3177                                  name=args.name)
3178
3179    p = subparsers.add_parser('bdev_daos_delete',
3180                              help='Delete a DAOS disk')
3181    p.add_argument('name', help='DAOS bdev name')
3182    p.set_defaults(func=bdev_daos_delete)
3183
3184    def bdev_daos_resize(args):
3185        print_json(rpc.bdev.bdev_daos_resize(args.client,
3186                                             name=args.name,
3187                                             new_size=int(args.new_size)))
3188
3189    p = subparsers.add_parser('bdev_daos_resize',
3190                              help='Resize a DAOS bdev')
3191    p.add_argument('name', help='DAOS bdev name')
3192    p.add_argument('new_size', help='new bdev size for resize operation. The unit is MiB')
3193    p.set_defaults(func=bdev_daos_resize)
3194
3195    def check_called_name(name):
3196        if name in deprecated_aliases:
3197            print("{} is deprecated, use {} instead.".format(name, deprecated_aliases[name]), file=sys.stderr)
3198
3199    class dry_run_client:
3200        def call(self, method, params=None):
3201            print("Request:\n" + json.dumps({"method": method, "params": params}, indent=2))
3202
3203    def null_print(arg):
3204        pass
3205
3206    def call_rpc_func(args):
3207        args.func(args)
3208        check_called_name(args.called_rpc_name)
3209
3210    def execute_script(parser, client, fd):
3211        executed_rpc = ""
3212        for rpc_call in map(str.rstrip, fd):
3213            if not rpc_call.strip():
3214                continue
3215            executed_rpc = "\n".join([executed_rpc, rpc_call])
3216            rpc_args = shlex.split(rpc_call)
3217            if rpc_args[0][0] == '#':
3218                # Ignore lines starting with # - treat them as comments
3219                continue
3220            args = parser.parse_args(rpc_args)
3221            args.client = client
3222            try:
3223                call_rpc_func(args)
3224            except JSONRPCException as ex:
3225                print("Exception:")
3226                print(executed_rpc.strip() + " <<<")
3227                print(ex.message)
3228                exit(1)
3229
3230    def load_plugin(args):
3231        # Create temporary parser, pull out the plugin parameter, load the module, and then run the real argument parser
3232        plugin_parser = argparse.ArgumentParser(add_help=False)
3233        plugin_parser.add_argument('--plugin', dest='rpc_plugin', help='Module name of plugin with additional RPC commands')
3234
3235        rpc_module = plugin_parser.parse_known_args()[0].rpc_plugin
3236        if args is not None:
3237            rpc_module = plugin_parser.parse_known_args(args)[0].rpc_plugin
3238
3239        if rpc_module is not None:
3240            try:
3241                rpc_plugin = importlib.import_module(rpc_module)
3242                try:
3243                    rpc_plugin.spdk_rpc_plugin_initialize(subparsers)
3244                except AttributeError:
3245                    print("Module %s does not contain 'spdk_rpc_plugin_initialize' function" % rpc_module)
3246            except ModuleNotFoundError:
3247                print("Module %s not found" % rpc_module)
3248
3249    def replace_arg_underscores(args):
3250        # All option names are defined with dashes only - for example: --tgt-name
3251        # But if user used underscores, convert them to dashes (--tgt_name => --tgt-name)
3252        # SPDK was inconsistent previously and had some options with underscores, so
3253        # doing this conversion ensures backward compatibility with older scripts.
3254        for i in range(len(args)):
3255            arg = args[i]
3256            if arg.startswith('--') and "_" in arg:
3257                args[i] = arg.replace('_', '-')
3258
3259    load_plugin(None)
3260
3261    replace_arg_underscores(sys.argv)
3262
3263    args = parser.parse_args()
3264
3265    if sys.stdin.isatty() and not hasattr(args, 'func'):
3266        # No arguments and no data piped through stdin
3267        parser.print_help()
3268        exit(1)
3269    if args.is_server:
3270        for input in sys.stdin:
3271            cmd = shlex.split(input)
3272            replace_arg_underscores(cmd)
3273            try:
3274                load_plugin(cmd)
3275                tmp_args = parser.parse_args(cmd)
3276            except SystemExit as ex:
3277                print("**STATUS=1", flush=True)
3278                continue
3279
3280            try:
3281                tmp_args.client = rpc.client.JSONRPCClient(
3282                    tmp_args.server_addr, tmp_args.port, tmp_args.timeout,
3283                    log_level=getattr(logging, tmp_args.verbose.upper()), conn_retries=tmp_args.conn_retries)
3284                call_rpc_func(tmp_args)
3285                print("**STATUS=0", flush=True)
3286            except JSONRPCException as ex:
3287                print(ex.message)
3288                print("**STATUS=1", flush=True)
3289        exit(0)
3290    elif args.dry_run:
3291        args.client = dry_run_client()
3292        print_dict = null_print
3293        print_json = null_print
3294        print_array = null_print
3295    else:
3296        try:
3297            args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.timeout,
3298                                                   log_level=getattr(logging, args.verbose.upper()),
3299                                                   conn_retries=args.conn_retries)
3300        except JSONRPCException as ex:
3301            print(ex.message)
3302            exit(1)
3303
3304    if hasattr(args, 'func'):
3305        try:
3306            call_rpc_func(args)
3307        except JSONRPCException as ex:
3308            print(ex.message)
3309            exit(1)
3310    else:
3311        execute_script(parser, args.client, sys.stdin)
3312