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