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