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