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