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