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