xref: /spdk/scripts/rpc.py (revision 1a526000d070b65d326b2d442fb259497b561188)
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                                              uuid=args.uuid))
1074
1075    p = subparsers.add_parser('bdev_error_create', help='Add bdev with error injection backend')
1076    p.add_argument('base_name', help='base bdev name')
1077    p.add_argument('--uuid', help='UUID for this bdev', required=False)
1078    p.set_defaults(func=bdev_error_create)
1079
1080    def bdev_error_delete(args):
1081        rpc.bdev.bdev_error_delete(args.client,
1082                                   name=args.name)
1083
1084    p = subparsers.add_parser('bdev_error_delete', help='Delete an error bdev')
1085    p.add_argument('name', help='error bdev name')
1086    p.set_defaults(func=bdev_error_delete)
1087
1088    def bdev_iscsi_set_options(args):
1089        rpc.bdev.bdev_iscsi_set_options(args.client,
1090                                        timeout_sec=args.timeout_sec)
1091
1092    p = subparsers.add_parser('bdev_iscsi_set_options', help='Set options for the bdev iscsi type.')
1093    p.add_argument('-t', '--timeout-sec', help="Timeout for command, in seconds, if 0, don't track timeout.", type=int)
1094    p.set_defaults(func=bdev_iscsi_set_options)
1095
1096    def bdev_iscsi_create(args):
1097        print_json(rpc.bdev.bdev_iscsi_create(args.client,
1098                                              name=args.name,
1099                                              url=args.url,
1100                                              initiator_iqn=args.initiator_iqn))
1101
1102    p = subparsers.add_parser('bdev_iscsi_create',
1103                              help='Add bdev with iSCSI initiator backend')
1104    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
1105    p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True)
1106    p.add_argument('--url', help="iSCSI Lun URL", required=True)
1107    p.set_defaults(func=bdev_iscsi_create)
1108
1109    def bdev_iscsi_delete(args):
1110        rpc.bdev.bdev_iscsi_delete(args.client,
1111                                   name=args.name)
1112
1113    p = subparsers.add_parser('bdev_iscsi_delete', help='Delete an iSCSI bdev')
1114    p.add_argument('name', help='iSCSI bdev name')
1115    p.set_defaults(func=bdev_iscsi_delete)
1116
1117    def bdev_passthru_create(args):
1118        print_json(rpc.bdev.bdev_passthru_create(args.client,
1119                                                 base_bdev_name=args.base_bdev_name,
1120                                                 name=args.name))
1121
1122    p = subparsers.add_parser('bdev_passthru_create', help='Add a pass through bdev on existing bdev')
1123    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
1124    p.add_argument('-p', '--name', help="Name of the pass through bdev", required=True)
1125    p.set_defaults(func=bdev_passthru_create)
1126
1127    def bdev_passthru_delete(args):
1128        rpc.bdev.bdev_passthru_delete(args.client,
1129                                      name=args.name)
1130
1131    p = subparsers.add_parser('bdev_passthru_delete', help='Delete a pass through bdev')
1132    p.add_argument('name', help='pass through bdev name')
1133    p.set_defaults(func=bdev_passthru_delete)
1134
1135    def bdev_get_bdevs(args):
1136        print_dict(rpc.bdev.bdev_get_bdevs(args.client,
1137                                           name=args.name, timeout=args.timeout_ms))
1138
1139    p = subparsers.add_parser('bdev_get_bdevs',
1140                              help='Display current blockdev list or required blockdev')
1141    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
1142    p.add_argument('-t', '--timeout-ms', help="""Time in ms to wait for the bdev to appear (only used
1143    with the -b|--name option). The default timeout is 0, meaning the RPC returns immediately
1144    whether the bdev exists or not.""",
1145                   type=int, required=False)
1146    p.set_defaults(func=bdev_get_bdevs)
1147
1148    def bdev_get_iostat(args):
1149        print_dict(rpc.bdev.bdev_get_iostat(args.client,
1150                                            name=args.name,
1151                                            per_channel=args.per_channel))
1152
1153    p = subparsers.add_parser('bdev_get_iostat',
1154                              help='Display current I/O statistics of all the blockdevs or specified blockdev.')
1155    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
1156    p.add_argument('-c', '--per-channel', default=False, dest='per_channel', help='Display per channel IO stats for specified device',
1157                   action='store_true', required=False)
1158    p.set_defaults(func=bdev_get_iostat)
1159
1160    def bdev_reset_iostat(args):
1161        rpc.bdev.bdev_reset_iostat(args.client, name=args.name, mode=args.mode)
1162
1163    p = subparsers.add_parser('bdev_reset_iostat',
1164                              help='Reset I/O statistics of all the blockdevs or specified blockdev.')
1165    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
1166    p.add_argument('-m', '--mode', help="Mode to reset I/O statistics", choices=['all', 'maxmin'], required=False)
1167    p.set_defaults(func=bdev_reset_iostat)
1168
1169    def bdev_enable_histogram(args):
1170        rpc.bdev.bdev_enable_histogram(args.client, name=args.name, enable=args.enable)
1171
1172    p = subparsers.add_parser('bdev_enable_histogram',
1173                              help='Enable or disable histogram for specified bdev')
1174    p.add_argument('-e', '--enable', default=True, dest='enable', action='store_true', help='Enable histograms on specified device')
1175    p.add_argument('-d', '--disable', dest='enable', action='store_false', help='Disable histograms on specified device')
1176    p.add_argument('name', help='bdev name')
1177    p.set_defaults(func=bdev_enable_histogram)
1178
1179    def bdev_get_histogram(args):
1180        print_dict(rpc.bdev.bdev_get_histogram(args.client, name=args.name))
1181
1182    p = subparsers.add_parser('bdev_get_histogram',
1183                              help='Get histogram for specified bdev')
1184    p.add_argument('name', help='bdev name')
1185    p.set_defaults(func=bdev_get_histogram)
1186
1187    def bdev_set_qd_sampling_period(args):
1188        rpc.bdev.bdev_set_qd_sampling_period(args.client,
1189                                             name=args.name,
1190                                             period=args.period)
1191
1192    p = subparsers.add_parser('bdev_set_qd_sampling_period',
1193                              help="Enable or disable tracking of a bdev's queue depth.")
1194    p.add_argument('name', help='Blockdev name. Example: Malloc0')
1195    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
1196                   ' If set to 0, polling will be disabled.',
1197                   type=int)
1198    p.set_defaults(func=bdev_set_qd_sampling_period)
1199
1200    def bdev_set_qos_limit(args):
1201        rpc.bdev.bdev_set_qos_limit(args.client,
1202                                    name=args.name,
1203                                    rw_ios_per_sec=args.rw_ios_per_sec,
1204                                    rw_mbytes_per_sec=args.rw_mbytes_per_sec,
1205                                    r_mbytes_per_sec=args.r_mbytes_per_sec,
1206                                    w_mbytes_per_sec=args.w_mbytes_per_sec)
1207
1208    p = subparsers.add_parser('bdev_set_qos_limit',
1209                              help='Set QoS rate limit on a blockdev')
1210    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
1211    p.add_argument('--rw-ios-per-sec',
1212                   help='R/W IOs per second limit (>=1000, example: 20000). 0 means unlimited.',
1213                   type=int, required=False)
1214    p.add_argument('--rw-mbytes-per-sec',
1215                   help="R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.",
1216                   type=int, required=False)
1217    p.add_argument('--r-mbytes-per-sec',
1218                   help="Read megabytes per second limit (>=10, example: 100). 0 means unlimited.",
1219                   type=int, required=False)
1220    p.add_argument('--w-mbytes-per-sec',
1221                   help="Write megabytes per second limit (>=10, example: 100). 0 means unlimited.",
1222                   type=int, required=False)
1223    p.set_defaults(func=bdev_set_qos_limit)
1224
1225    def bdev_error_inject_error(args):
1226        rpc.bdev.bdev_error_inject_error(args.client,
1227                                         name=args.name,
1228                                         io_type=args.io_type,
1229                                         error_type=args.error_type,
1230                                         num=args.num,
1231                                         corrupt_offset=args.corrupt_offset,
1232                                         corrupt_value=args.corrupt_value)
1233
1234    p = subparsers.add_parser('bdev_error_inject_error', help='bdev inject error')
1235    p.add_argument('name', help="""the name of the error injection bdev""")
1236    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
1237    p.add_argument('error_type', help="""error_type: 'failure' 'pending' 'corrupt_data'""")
1238    p.add_argument(
1239        '-n', '--num', help='the number of commands you want to fail', type=int)
1240    p.add_argument(
1241        '-o', '--corrupt-offset', help='the offset in bytes to xor with corrupt_value', type=int)
1242    p.add_argument(
1243        '-v', '--corrupt-value', help='the value for xor (1-255, 0 is invalid)', type=int)
1244    p.set_defaults(func=bdev_error_inject_error)
1245
1246    def bdev_nvme_apply_firmware(args):
1247        print_dict(rpc.bdev.bdev_nvme_apply_firmware(args.client,
1248                                                     bdev_name=args.bdev_name,
1249                                                     filename=args.filename))
1250
1251    p = subparsers.add_parser('bdev_nvme_apply_firmware', help='Download and commit firmware to NVMe device')
1252    p.add_argument('filename', help='filename of the firmware to download')
1253    p.add_argument('bdev_name', help='name of the NVMe device')
1254    p.set_defaults(func=bdev_nvme_apply_firmware)
1255
1256    def bdev_nvme_get_transport_statistics(args):
1257        print_dict(rpc.bdev.bdev_nvme_get_transport_statistics(args.client))
1258
1259    p = subparsers.add_parser('bdev_nvme_get_transport_statistics',
1260                              help='Get bdev_nvme poll group transport statistics')
1261    p.set_defaults(func=bdev_nvme_get_transport_statistics)
1262
1263    def bdev_nvme_get_controller_health_info(args):
1264        print_dict(rpc.bdev.bdev_nvme_get_controller_health_info(args.client,
1265                                                                 name=args.name))
1266
1267    p = subparsers.add_parser('bdev_nvme_get_controller_health_info',
1268                              help='Display health log of the required NVMe bdev controller.')
1269    p.add_argument('-c', '--name', help="Name of the NVMe bdev controller. Example: Nvme0", required=True)
1270    p.set_defaults(func=bdev_nvme_get_controller_health_info)
1271
1272    # iSCSI
1273    def iscsi_set_options(args):
1274        rpc.iscsi.iscsi_set_options(
1275            args.client,
1276            auth_file=args.auth_file,
1277            node_base=args.node_base,
1278            nop_timeout=args.nop_timeout,
1279            nop_in_interval=args.nop_in_interval,
1280            disable_chap=args.disable_chap,
1281            require_chap=args.require_chap,
1282            mutual_chap=args.mutual_chap,
1283            chap_group=args.chap_group,
1284            max_sessions=args.max_sessions,
1285            max_queue_depth=args.max_queue_depth,
1286            max_connections_per_session=args.max_connections_per_session,
1287            default_time2wait=args.default_time2wait,
1288            default_time2retain=args.default_time2retain,
1289            first_burst_length=args.first_burst_length,
1290            immediate_data=args.immediate_data,
1291            error_recovery_level=args.error_recovery_level,
1292            allow_duplicated_isid=args.allow_duplicated_isid,
1293            max_large_datain_per_connection=args.max_large_datain_per_connection,
1294            max_r2t_per_connection=args.max_r2t_per_connection,
1295            pdu_pool_size=args.pdu_pool_size,
1296            immediate_data_pool_size=args.immediate_data_pool_size,
1297            data_out_pool_size=args.data_out_pool_size)
1298
1299    p = subparsers.add_parser('iscsi_set_options',
1300                              help="""Set options of iSCSI subsystem""")
1301    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file')
1302    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
1303    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
1304    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
1305    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
1306    *** Mutually exclusive with --require-chap""", action='store_true')
1307    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
1308    *** Mutually exclusive with --disable-chap""", action='store_true')
1309    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
1310    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
1311    *** Authentication group must be precreated ***""", type=int)
1312    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
1313    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int)
1314    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
1315    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
1316    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
1317    p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int)
1318    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
1319    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
1320    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
1321    p.add_argument('-x', '--max-large-datain-per-connection', help='Max number of outstanding split read I/Os per connection', type=int)
1322    p.add_argument('-k', '--max-r2t-per-connection', help='Max number of outstanding R2Ts per connection', type=int)
1323    p.add_argument('-u', '--pdu-pool-size', help='Number of PDUs in the pool', type=int)
1324    p.add_argument('-j', '--immediate-data-pool-size', help='Number of immediate data buffers in the pool', type=int)
1325    p.add_argument('-z', '--data-out-pool-size', help='Number of data out buffers in the pool', type=int)
1326    p.set_defaults(func=iscsi_set_options)
1327
1328    def iscsi_set_discovery_auth(args):
1329        rpc.iscsi.iscsi_set_discovery_auth(
1330            args.client,
1331            disable_chap=args.disable_chap,
1332            require_chap=args.require_chap,
1333            mutual_chap=args.mutual_chap,
1334            chap_group=args.chap_group)
1335
1336    p = subparsers.add_parser('iscsi_set_discovery_auth',
1337                              help="""Set CHAP authentication for discovery session.""")
1338    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
1339    *** Mutually exclusive with --require-chap""", action='store_true')
1340    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
1341    *** Mutually exclusive with --disable-chap""", action='store_true')
1342    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
1343    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
1344    *** Authentication group must be precreated ***""", type=int)
1345    p.set_defaults(func=iscsi_set_discovery_auth)
1346
1347    def iscsi_create_auth_group(args):
1348        secrets = None
1349        if args.secrets:
1350            secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")]
1351
1352        rpc.iscsi.iscsi_create_auth_group(args.client, tag=args.tag, secrets=secrets)
1353
1354    p = subparsers.add_parser('iscsi_create_auth_group',
1355                              help='Create authentication group for CHAP authentication.')
1356    p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int)
1357    p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets
1358<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes.
1359Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False)
1360    p.set_defaults(func=iscsi_create_auth_group)
1361
1362    def iscsi_delete_auth_group(args):
1363        rpc.iscsi.iscsi_delete_auth_group(args.client, tag=args.tag)
1364
1365    p = subparsers.add_parser('iscsi_delete_auth_group',
1366                              help='Delete an authentication group.')
1367    p.add_argument('tag', help='Authentication group tag', type=int)
1368    p.set_defaults(func=iscsi_delete_auth_group)
1369
1370    def iscsi_auth_group_add_secret(args):
1371        rpc.iscsi.iscsi_auth_group_add_secret(
1372            args.client,
1373            tag=args.tag,
1374            user=args.user,
1375            secret=args.secret,
1376            muser=args.muser,
1377            msecret=args.msecret)
1378
1379    p = subparsers.add_parser('iscsi_auth_group_add_secret',
1380                              help='Add a secret to an authentication group.')
1381    p.add_argument('tag', help='Authentication group tag', type=int)
1382    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
1383    p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True)
1384    p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication')
1385    p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication')
1386    p.set_defaults(func=iscsi_auth_group_add_secret)
1387
1388    def iscsi_auth_group_remove_secret(args):
1389        rpc.iscsi.iscsi_auth_group_remove_secret(args.client, tag=args.tag, user=args.user)
1390
1391    p = subparsers.add_parser('iscsi_auth_group_remove_secret',
1392                              help='Remove a secret from an authentication group.')
1393    p.add_argument('tag', help='Authentication group tag', type=int)
1394    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
1395    p.set_defaults(func=iscsi_auth_group_remove_secret)
1396
1397    def iscsi_get_auth_groups(args):
1398        print_dict(rpc.iscsi.iscsi_get_auth_groups(args.client))
1399
1400    p = subparsers.add_parser('iscsi_get_auth_groups',
1401                              help='Display current authentication group configuration')
1402    p.set_defaults(func=iscsi_get_auth_groups)
1403
1404    def iscsi_get_portal_groups(args):
1405        print_dict(rpc.iscsi.iscsi_get_portal_groups(args.client))
1406
1407    p = subparsers.add_parser('iscsi_get_portal_groups', help='Display current portal group configuration')
1408    p.set_defaults(func=iscsi_get_portal_groups)
1409
1410    def iscsi_get_initiator_groups(args):
1411        print_dict(rpc.iscsi.iscsi_get_initiator_groups(args.client))
1412
1413    p = subparsers.add_parser('iscsi_get_initiator_groups',
1414                              help='Display current initiator group configuration')
1415    p.set_defaults(func=iscsi_get_initiator_groups)
1416
1417    def iscsi_get_target_nodes(args):
1418        print_dict(rpc.iscsi.iscsi_get_target_nodes(args.client))
1419
1420    p = subparsers.add_parser('iscsi_get_target_nodes', help='Display target nodes')
1421    p.set_defaults(func=iscsi_get_target_nodes)
1422
1423    def iscsi_create_target_node(args):
1424        luns = []
1425        for u in args.bdev_name_id_pairs.strip().split(" "):
1426            bdev_name, lun_id = u.split(":")
1427            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
1428
1429        pg_ig_maps = []
1430        for u in args.pg_ig_mappings.strip().split(" "):
1431            pg, ig = u.split(":")
1432            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1433
1434        rpc.iscsi.iscsi_create_target_node(
1435            args.client,
1436            luns=luns,
1437            pg_ig_maps=pg_ig_maps,
1438            name=args.name,
1439            alias_name=args.alias_name,
1440            queue_depth=args.queue_depth,
1441            chap_group=args.chap_group,
1442            disable_chap=args.disable_chap,
1443            require_chap=args.require_chap,
1444            mutual_chap=args.mutual_chap,
1445            header_digest=args.header_digest,
1446            data_digest=args.data_digest)
1447
1448    p = subparsers.add_parser('iscsi_create_target_node', help='Add a target node')
1449    p.add_argument('name', help='Target node name (ASCII)')
1450    p.add_argument('alias_name', help='Target node alias name (ASCII)')
1451    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
1452    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
1453    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
1454    *** The bdevs must pre-exist ***
1455    *** LUN0 (id = 0) is required ***
1456    *** bdevs names cannot contain space or colon characters ***""")
1457    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1458    Whitespace separated, quoted, mapping defined with colon
1459    separated list of "tags" (int > 0)
1460    Example: '1:1 2:2 2:1'
1461    *** The Portal/Initiator Groups must be precreated ***""")
1462    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
1463    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
1464    *** Authentication group must be precreated ***""", type=int)
1465    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
1466    *** Mutually exclusive with --require-chap ***""", action='store_true')
1467    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
1468    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1469    p.add_argument(
1470        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
1471    p.add_argument('-H', '--header-digest',
1472                   help='Header Digest should be required for this target node.', action='store_true')
1473    p.add_argument('-D', '--data-digest',
1474                   help='Data Digest should be required for this target node.', action='store_true')
1475    p.set_defaults(func=iscsi_create_target_node)
1476
1477    def iscsi_target_node_add_lun(args):
1478        rpc.iscsi.iscsi_target_node_add_lun(
1479            args.client,
1480            name=args.name,
1481            bdev_name=args.bdev_name,
1482            lun_id=args.lun_id)
1483
1484    p = subparsers.add_parser('iscsi_target_node_add_lun',
1485                              help='Add LUN to the target node')
1486    p.add_argument('name', help='Target node name (ASCII)')
1487    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
1488    *** bdev name cannot contain space or colon characters ***""")
1489    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
1490    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
1491    p.set_defaults(func=iscsi_target_node_add_lun)
1492
1493    def iscsi_target_node_set_auth(args):
1494        rpc.iscsi.iscsi_target_node_set_auth(
1495            args.client,
1496            name=args.name,
1497            chap_group=args.chap_group,
1498            disable_chap=args.disable_chap,
1499            require_chap=args.require_chap,
1500            mutual_chap=args.mutual_chap)
1501
1502    p = subparsers.add_parser('iscsi_target_node_set_auth',
1503                              help='Set CHAP authentication for the target node')
1504    p.add_argument('name', help='Target node name (ASCII)')
1505    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
1506    *** Authentication group must be precreated ***""", type=int)
1507    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
1508    *** Mutually exclusive with --require-chap ***""", action='store_true')
1509    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
1510    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1511    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
1512                   action='store_true')
1513    p.set_defaults(func=iscsi_target_node_set_auth)
1514
1515    def iscsi_target_node_add_pg_ig_maps(args):
1516        pg_ig_maps = []
1517        for u in args.pg_ig_mappings.strip().split(" "):
1518            pg, ig = u.split(":")
1519            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1520        rpc.iscsi.iscsi_target_node_add_pg_ig_maps(
1521            args.client,
1522            pg_ig_maps=pg_ig_maps,
1523            name=args.name)
1524
1525    p = subparsers.add_parser('iscsi_target_node_add_pg_ig_maps',
1526                              help='Add PG-IG maps to the target node')
1527    p.add_argument('name', help='Target node name (ASCII)')
1528    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1529    Whitespace separated, quoted, mapping defined with colon
1530    separated list of "tags" (int > 0)
1531    Example: '1:1 2:2 2:1'
1532    *** The Portal/Initiator Groups must be precreated ***""")
1533    p.set_defaults(func=iscsi_target_node_add_pg_ig_maps)
1534
1535    def iscsi_target_node_remove_pg_ig_maps(args):
1536        pg_ig_maps = []
1537        for u in args.pg_ig_mappings.strip().split(" "):
1538            pg, ig = u.split(":")
1539            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1540        rpc.iscsi.iscsi_target_node_remove_pg_ig_maps(
1541            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
1542
1543    p = subparsers.add_parser('iscsi_target_node_remove_pg_ig_maps',
1544                              help='Delete PG-IG maps from the target node')
1545    p.add_argument('name', help='Target node name (ASCII)')
1546    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1547    Whitespace separated, quoted, mapping defined with colon
1548    separated list of "tags" (int > 0)
1549    Example: '1:1 2:2 2:1'
1550    *** The Portal/Initiator Groups must be precreated ***""")
1551    p.set_defaults(func=iscsi_target_node_remove_pg_ig_maps)
1552
1553    def iscsi_target_node_set_redirect(args):
1554        rpc.iscsi.iscsi_target_node_set_redirect(
1555            args.client,
1556            name=args.name,
1557            pg_tag=args.pg_tag,
1558            redirect_host=args.redirect_host,
1559            redirect_port=args.redirect_port)
1560
1561    p = subparsers.add_parser('iscsi_target_node_set_redirect',
1562                              help="""Update redirect portal of the public portal group for the target node.
1563    Omit redirect host and port to clear previously set redirect settings.""")
1564    p.add_argument('name', help='Target node name (ASCII)')
1565    p.add_argument('pg_tag', help='Portal group tag (unique, integer > 0)', type=int)
1566    p.add_argument('-a', '--redirect-host', help='Numeric IP address for redirect portal', required=False)
1567    p.add_argument('-p', '--redirect-port', help='Numeric TCP port for redirect portal', required=False)
1568    p.set_defaults(func=iscsi_target_node_set_redirect)
1569
1570    def iscsi_target_node_request_logout(args):
1571        rpc.iscsi.iscsi_target_node_request_logout(
1572            args.client,
1573            name=args.name,
1574            pg_tag=args.pg_tag)
1575
1576    p = subparsers.add_parser('iscsi_target_node_request_logout',
1577                              help="""For the target node, request connections whose portal group tag
1578    match to logout, or request all connections if portal group tag is omitted.""")
1579    p.add_argument('name', help='Target node name (ASCII)')
1580    p.add_argument('-t', '--pg-tag', help='Portal group tag (unique, integer > 0)', type=int, required=False)
1581    p.set_defaults(func=iscsi_target_node_request_logout)
1582
1583    def iscsi_create_portal_group(args):
1584        portals = []
1585        for p in args.portal_list.strip().split(' '):
1586            ip, separator, port_cpumask = p.rpartition(':')
1587            split_port_cpumask = port_cpumask.split('@')
1588            if len(split_port_cpumask) == 1:
1589                port = port_cpumask
1590                portals.append({'host': ip, 'port': port})
1591            else:
1592                port = split_port_cpumask[0]
1593                cpumask = split_port_cpumask[1]
1594                portals.append({'host': ip, 'port': port})
1595                print("WARNING: Specifying a portal group with a CPU mask is no longer supported. Ignoring it.")
1596        rpc.iscsi.iscsi_create_portal_group(
1597            args.client,
1598            portals=portals,
1599            tag=args.tag,
1600            private=args.private,
1601            wait=args.wait)
1602
1603    p = subparsers.add_parser('iscsi_create_portal_group',
1604                              help='Add a portal group')
1605    p.add_argument(
1606        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1607    p.add_argument('portal_list', help="""List of portals in host:port format, separated by whitespace
1608    Example: '192.168.100.100:3260 192.168.100.100:3261 192.168.100.100:3262""")
1609    p.add_argument('-p', '--private', help="""Public (false) or private (true) portal group.
1610    Private portal groups do not have their portals returned by a discovery session. A public
1611    portal group may optionally specify a redirect portal for non-discovery logins. This redirect
1612    portal must be from a private portal group.""", action='store_true')
1613    p.add_argument('-w', '--wait', help="""Do not listening on portals until it is started explicitly.
1614    One major iSCSI initiator may not retry login once it failed. Hence for such initiator, listening
1615    on portals should be allowed after all associated target nodes are created.""", action='store_true')
1616    p.set_defaults(func=iscsi_create_portal_group)
1617
1618    def iscsi_start_portal_group(args):
1619        rpc.iscsi.iscsi_start_portal_group(args.client, tag=args.tag)
1620
1621    p = subparsers.add_parser('iscsi_start_portal_group',
1622                              help='Start listening on portals if it is not started yet.')
1623    p.add_argument(
1624        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1625    p.set_defaults(func=iscsi_start_portal_group)
1626
1627    def iscsi_create_initiator_group(args):
1628        initiators = []
1629        netmasks = []
1630        for i in args.initiator_list.strip().split(' '):
1631            initiators.append(i)
1632        for n in args.netmask_list.strip().split(' '):
1633            netmasks.append(n)
1634        rpc.iscsi.iscsi_create_initiator_group(
1635            args.client,
1636            tag=args.tag,
1637            initiators=initiators,
1638            netmasks=netmasks)
1639
1640    p = subparsers.add_parser('iscsi_create_initiator_group',
1641                              help='Add an initiator group')
1642    p.add_argument(
1643        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1644    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1645    enclosed in quotes.  Example: 'ANY' or 'iqn.2016-06.io.spdk:host1 iqn.2016-06.io.spdk:host2'""")
1646    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1647    Example: '255.255.0.0 255.248.0.0' etc""")
1648    p.set_defaults(func=iscsi_create_initiator_group)
1649
1650    def iscsi_initiator_group_add_initiators(args):
1651        initiators = None
1652        netmasks = None
1653        if args.initiator_list:
1654            initiators = []
1655            for i in args.initiator_list.strip().split(' '):
1656                initiators.append(i)
1657        if args.netmask_list:
1658            netmasks = []
1659            for n in args.netmask_list.strip().split(' '):
1660                netmasks.append(n)
1661        rpc.iscsi.iscsi_initiator_group_add_initiators(
1662            args.client,
1663            tag=args.tag,
1664            initiators=initiators,
1665            netmasks=netmasks)
1666
1667    p = subparsers.add_parser('iscsi_initiator_group_add_initiators',
1668                              help='Add initiators to an existing initiator group')
1669    p.add_argument(
1670        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1671    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1672    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or
1673    'iqn.2016-06.io.spdk:host1 iqn.2016-06.io.spdk:host2'""", required=False)
1674    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1675    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
1676    p.set_defaults(func=iscsi_initiator_group_add_initiators)
1677
1678    def iscsi_initiator_group_remove_initiators(args):
1679        initiators = None
1680        netmasks = None
1681        if args.initiator_list:
1682            initiators = []
1683            for i in args.initiator_list.strip().split(' '):
1684                initiators.append(i)
1685        if args.netmask_list:
1686            netmasks = []
1687            for n in args.netmask_list.strip().split(' '):
1688                netmasks.append(n)
1689        rpc.iscsi.iscsi_initiator_group_remove_initiators(
1690            args.client,
1691            tag=args.tag,
1692            initiators=initiators,
1693            netmasks=netmasks)
1694
1695    p = subparsers.add_parser('iscsi_initiator_group_remove_initiators',
1696                              help='Delete initiators from an existing initiator group')
1697    p.add_argument(
1698        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1699    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1700    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or
1701    'iqn.2016-06.io.spdk:host1 iqn.2016-06.io.spdk:host2'""", required=False)
1702    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1703    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
1704    p.set_defaults(func=iscsi_initiator_group_remove_initiators)
1705
1706    def iscsi_delete_target_node(args):
1707        rpc.iscsi.iscsi_delete_target_node(
1708            args.client, target_node_name=args.target_node_name)
1709
1710    p = subparsers.add_parser('iscsi_delete_target_node',
1711                              help='Delete a target node')
1712    p.add_argument('target_node_name',
1713                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
1714    p.set_defaults(func=iscsi_delete_target_node)
1715
1716    def iscsi_delete_portal_group(args):
1717        rpc.iscsi.iscsi_delete_portal_group(args.client, tag=args.tag)
1718
1719    p = subparsers.add_parser('iscsi_delete_portal_group',
1720                              help='Delete a portal group')
1721    p.add_argument(
1722        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1723    p.set_defaults(func=iscsi_delete_portal_group)
1724
1725    def iscsi_delete_initiator_group(args):
1726        rpc.iscsi.iscsi_delete_initiator_group(args.client, tag=args.tag)
1727
1728    p = subparsers.add_parser('iscsi_delete_initiator_group',
1729                              help='Delete an initiator group')
1730    p.add_argument(
1731        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1732    p.set_defaults(func=iscsi_delete_initiator_group)
1733
1734    def iscsi_portal_group_set_auth(args):
1735        rpc.iscsi.iscsi_portal_group_set_auth(
1736            args.client,
1737            tag=args.tag,
1738            chap_group=args.chap_group,
1739            disable_chap=args.disable_chap,
1740            require_chap=args.require_chap,
1741            mutual_chap=args.mutual_chap)
1742
1743    p = subparsers.add_parser('iscsi_portal_group_set_auth',
1744                              help='Set CHAP authentication for discovery sessions specific for the portal group')
1745    p.add_argument('tag', help='Portal group tag (unique, integer > 0)', type=int)
1746    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this portal group.
1747    *** Authentication group must be precreated ***""", type=int)
1748    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this portal group.
1749    *** Mutually exclusive with --require-chap ***""", action='store_true')
1750    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this portal group.
1751    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1752    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
1753                   action='store_true')
1754    p.set_defaults(func=iscsi_portal_group_set_auth)
1755
1756    def iscsi_get_connections(args):
1757        print_dict(rpc.iscsi.iscsi_get_connections(args.client))
1758
1759    p = subparsers.add_parser('iscsi_get_connections',
1760                              help='Display iSCSI connections')
1761    p.set_defaults(func=iscsi_get_connections)
1762
1763    def iscsi_get_options(args):
1764        print_dict(rpc.iscsi.iscsi_get_options(args.client))
1765
1766    p = subparsers.add_parser('iscsi_get_options',
1767                              help='Display iSCSI global parameters')
1768    p.set_defaults(func=iscsi_get_options)
1769
1770    def scsi_get_devices(args):
1771        print_dict(rpc.iscsi.scsi_get_devices(args.client))
1772
1773    p = subparsers.add_parser('scsi_get_devices', help='Display SCSI devices')
1774    p.set_defaults(func=scsi_get_devices)
1775
1776    # trace
1777    def trace_enable_tpoint_group(args):
1778        rpc.trace.trace_enable_tpoint_group(args.client, name=args.name)
1779
1780    p = subparsers.add_parser('trace_enable_tpoint_group',
1781                              help='enable trace on a specific tpoint group')
1782    p.add_argument(
1783        'name', help="""trace group name we want to enable in tpoint_group_mask.
1784        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1785    p.set_defaults(func=trace_enable_tpoint_group)
1786
1787    def trace_disable_tpoint_group(args):
1788        rpc.trace.trace_disable_tpoint_group(args.client, name=args.name)
1789
1790    p = subparsers.add_parser('trace_disable_tpoint_group',
1791                              help='disable trace on a specific tpoint group')
1792    p.add_argument(
1793        'name', help="""trace group name we want to disable in tpoint_group_mask.
1794        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1795    p.set_defaults(func=trace_disable_tpoint_group)
1796
1797    def trace_set_tpoint_mask(args):
1798        rpc.trace.trace_set_tpoint_mask(args.client, name=args.name, tpoint_mask=args.tpoint_mask)
1799
1800    p = subparsers.add_parser('trace_set_tpoint_mask',
1801                              help='enable tracepoint mask on a specific tpoint group')
1802    p.add_argument(
1803        'name', help="""trace group name we want to enable in tpoint_group_mask.
1804        (for example "bdev" for bdev trace group)""")
1805    p.add_argument(
1806        'tpoint_mask', help="""tracepoints to be enabled inside a given trace group.
1807        (for example value of "0x3" will enable only the first two tpoints in this group)""",
1808        type=lambda m: int(m, 16))
1809    p.set_defaults(func=trace_set_tpoint_mask)
1810
1811    def trace_clear_tpoint_mask(args):
1812        rpc.trace.trace_clear_tpoint_mask(args.client, name=args.name, tpoint_mask=args.tpoint_mask)
1813
1814    p = subparsers.add_parser('trace_clear_tpoint_mask',
1815                              help='disable tracepoint mask on a specific tpoint group')
1816    p.add_argument(
1817        'name', help="""trace group name we want to disable in tpoint_group_mask.
1818        (for example "bdev" for bdev trace group)""")
1819    p.add_argument(
1820        'tpoint_mask', help="""tracepoints to be disabled inside a given trace group.
1821        (for example value of "0x3" will disable the first two tpoints in this group)""",
1822        type=lambda m: int(m, 16))
1823    p.set_defaults(func=trace_clear_tpoint_mask)
1824
1825    def trace_get_tpoint_group_mask(args):
1826        print_dict(rpc.trace.trace_get_tpoint_group_mask(args.client))
1827
1828    p = subparsers.add_parser('trace_get_tpoint_group_mask', help='get trace point group mask')
1829    p.set_defaults(func=trace_get_tpoint_group_mask)
1830
1831    def trace_get_info(args):
1832        print_dict(rpc.trace.trace_get_info(args.client))
1833
1834    p = subparsers.add_parser('trace_get_info',
1835                              help='get name of shared memory file and list of the available trace point groups')
1836    p.set_defaults(func=trace_get_info)
1837
1838    # log
1839    def log_set_flag(args):
1840        rpc.log.log_set_flag(args.client, flag=args.flag)
1841
1842    p = subparsers.add_parser('log_set_flag', help='set log flag')
1843    p.add_argument(
1844        'flag', help='log flag we want to set. (for example "nvme").')
1845    p.set_defaults(func=log_set_flag)
1846
1847    def log_clear_flag(args):
1848        rpc.log.log_clear_flag(args.client, flag=args.flag)
1849
1850    p = subparsers.add_parser('log_clear_flag', help='clear log flag')
1851    p.add_argument(
1852        'flag', help='log flag we want to clear. (for example "nvme").')
1853    p.set_defaults(func=log_clear_flag)
1854
1855    def log_get_flags(args):
1856        print_dict(rpc.log.log_get_flags(args.client))
1857
1858    p = subparsers.add_parser('log_get_flags', help='get log flags')
1859    p.set_defaults(func=log_get_flags)
1860
1861    def log_set_level(args):
1862        rpc.log.log_set_level(args.client, level=args.level)
1863
1864    p = subparsers.add_parser('log_set_level', help='set log level')
1865    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
1866    p.set_defaults(func=log_set_level)
1867
1868    def log_get_level(args):
1869        print_dict(rpc.log.log_get_level(args.client))
1870
1871    p = subparsers.add_parser('log_get_level', help='get log level')
1872    p.set_defaults(func=log_get_level)
1873
1874    def log_set_print_level(args):
1875        rpc.log.log_set_print_level(args.client, level=args.level)
1876
1877    p = subparsers.add_parser('log_set_print_level', help='set log print level')
1878    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
1879    p.set_defaults(func=log_set_print_level)
1880
1881    def log_get_print_level(args):
1882        print_dict(rpc.log.log_get_print_level(args.client))
1883
1884    p = subparsers.add_parser('log_get_print_level', help='get log print level')
1885    p.set_defaults(func=log_get_print_level)
1886
1887    # lvol
1888    def bdev_lvol_create_lvstore(args):
1889        print_json(rpc.lvol.bdev_lvol_create_lvstore(args.client,
1890                                                     bdev_name=args.bdev_name,
1891                                                     lvs_name=args.lvs_name,
1892                                                     cluster_sz=args.cluster_sz,
1893                                                     clear_method=args.clear_method,
1894                                                     num_md_pages_per_cluster_ratio=args.md_pages_per_cluster_ratio))
1895
1896    p = subparsers.add_parser('bdev_lvol_create_lvstore', help='Add logical volume store on base bdev')
1897    p.add_argument('bdev_name', help='base bdev name')
1898    p.add_argument('lvs_name', help='name for lvol store')
1899    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
1900    p.add_argument('--clear-method', help="""Change clear method for data region.
1901        Available: none, unmap, write_zeroes""", required=False)
1902    p.add_argument('-m', '--md-pages-per-cluster-ratio', help='reserved metadata pages for each cluster', type=int, required=False)
1903    p.set_defaults(func=bdev_lvol_create_lvstore)
1904
1905    def bdev_lvol_rename_lvstore(args):
1906        rpc.lvol.bdev_lvol_rename_lvstore(args.client,
1907                                          old_name=args.old_name,
1908                                          new_name=args.new_name)
1909
1910    p = subparsers.add_parser('bdev_lvol_rename_lvstore', help='Change logical volume store name')
1911    p.add_argument('old_name', help='old name')
1912    p.add_argument('new_name', help='new name')
1913    p.set_defaults(func=bdev_lvol_rename_lvstore)
1914
1915    def bdev_lvol_grow_lvstore(args):
1916        print_dict(rpc.lvol.bdev_lvol_grow_lvstore(args.client,
1917                                                   uuid=args.uuid,
1918                                                   lvs_name=args.lvs_name))
1919
1920    p = subparsers.add_parser('bdev_lvol_grow_lvstore',
1921                              help='Grow the lvstore size to the underlying bdev size')
1922    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1923    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1924    p.set_defaults(func=bdev_lvol_grow_lvstore)
1925
1926    def bdev_lvol_create(args):
1927        print_json(rpc.lvol.bdev_lvol_create(args.client,
1928                                             lvol_name=args.lvol_name,
1929                                             size_in_mib=args.size_in_mib,
1930                                             thin_provision=args.thin_provision,
1931                                             clear_method=args.clear_method,
1932                                             uuid=args.uuid,
1933                                             lvs_name=args.lvs_name))
1934
1935    p = subparsers.add_parser('bdev_lvol_create', help='Add a bdev with an logical volume backend')
1936    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1937    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1938    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
1939    p.add_argument('-c', '--clear-method', help="""Change default data clusters clear method.
1940        Available: none, unmap, write_zeroes""", required=False)
1941    p.add_argument('lvol_name', help='name for this lvol')
1942    p.add_argument('size_in_mib', help='size in MiB for this bdev', type=int)
1943    p.set_defaults(func=bdev_lvol_create)
1944
1945    def bdev_lvol_snapshot(args):
1946        print_json(rpc.lvol.bdev_lvol_snapshot(args.client,
1947                                               lvol_name=args.lvol_name,
1948                                               snapshot_name=args.snapshot_name))
1949
1950    p = subparsers.add_parser('bdev_lvol_snapshot', help='Create a snapshot of an lvol bdev')
1951    p.add_argument('lvol_name', help='lvol bdev name')
1952    p.add_argument('snapshot_name', help='lvol snapshot name')
1953    p.set_defaults(func=bdev_lvol_snapshot)
1954
1955    def bdev_lvol_clone(args):
1956        print_json(rpc.lvol.bdev_lvol_clone(args.client,
1957                                            snapshot_name=args.snapshot_name,
1958                                            clone_name=args.clone_name))
1959
1960    p = subparsers.add_parser('bdev_lvol_clone', help='Create a clone of an lvol snapshot')
1961    p.add_argument('snapshot_name', help='lvol snapshot name')
1962    p.add_argument('clone_name', help='lvol clone name')
1963    p.set_defaults(func=bdev_lvol_clone)
1964
1965    def bdev_lvol_rename(args):
1966        rpc.lvol.bdev_lvol_rename(args.client,
1967                                  old_name=args.old_name,
1968                                  new_name=args.new_name)
1969
1970    p = subparsers.add_parser('bdev_lvol_rename', help='Change lvol bdev name')
1971    p.add_argument('old_name', help='lvol bdev name')
1972    p.add_argument('new_name', help='new lvol name')
1973    p.set_defaults(func=bdev_lvol_rename)
1974
1975    def bdev_lvol_inflate(args):
1976        rpc.lvol.bdev_lvol_inflate(args.client,
1977                                   name=args.name)
1978
1979    p = subparsers.add_parser('bdev_lvol_inflate', help='Make thin provisioned lvol a thick provisioned lvol')
1980    p.add_argument('name', help='lvol bdev name')
1981    p.set_defaults(func=bdev_lvol_inflate)
1982
1983    def bdev_lvol_decouple_parent(args):
1984        rpc.lvol.bdev_lvol_decouple_parent(args.client,
1985                                           name=args.name)
1986
1987    p = subparsers.add_parser('bdev_lvol_decouple_parent', help='Decouple parent of lvol')
1988    p.add_argument('name', help='lvol bdev name')
1989    p.set_defaults(func=bdev_lvol_decouple_parent)
1990
1991    def bdev_lvol_resize(args):
1992        rpc.lvol.bdev_lvol_resize(args.client,
1993                                  name=args.name,
1994                                  size_in_mib=args.size_in_mib)
1995
1996    p = subparsers.add_parser('bdev_lvol_resize', help='Resize existing lvol bdev')
1997    p.add_argument('name', help='lvol bdev name')
1998    p.add_argument('size_in_mib', help='new size in MiB for this bdev', type=int)
1999    p.set_defaults(func=bdev_lvol_resize)
2000
2001    def bdev_lvol_set_read_only(args):
2002        rpc.lvol.bdev_lvol_set_read_only(args.client,
2003                                         name=args.name)
2004
2005    p = subparsers.add_parser('bdev_lvol_set_read_only', help='Mark lvol bdev as read only')
2006    p.add_argument('name', help='lvol bdev name')
2007    p.set_defaults(func=bdev_lvol_set_read_only)
2008
2009    def bdev_lvol_delete(args):
2010        rpc.lvol.bdev_lvol_delete(args.client,
2011                                  name=args.name)
2012
2013    p = subparsers.add_parser('bdev_lvol_delete', help='Destroy a logical volume')
2014    p.add_argument('name', help='lvol bdev name')
2015    p.set_defaults(func=bdev_lvol_delete)
2016
2017    def bdev_lvol_delete_lvstore(args):
2018        rpc.lvol.bdev_lvol_delete_lvstore(args.client,
2019                                          uuid=args.uuid,
2020                                          lvs_name=args.lvs_name)
2021
2022    p = subparsers.add_parser('bdev_lvol_delete_lvstore', help='Destroy an logical volume store')
2023    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
2024    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
2025    p.set_defaults(func=bdev_lvol_delete_lvstore)
2026
2027    def bdev_lvol_get_lvstores(args):
2028        print_dict(rpc.lvol.bdev_lvol_get_lvstores(args.client,
2029                                                   uuid=args.uuid,
2030                                                   lvs_name=args.lvs_name))
2031
2032    p = subparsers.add_parser('bdev_lvol_get_lvstores', help='Display current logical volume store list')
2033    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
2034    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
2035    p.set_defaults(func=bdev_lvol_get_lvstores)
2036
2037    def bdev_raid_get_bdevs(args):
2038        print_json(rpc.bdev.bdev_raid_get_bdevs(args.client,
2039                                                category=args.category))
2040
2041    p = subparsers.add_parser('bdev_raid_get_bdevs',
2042                              help="""This is used to list all the raid bdev details based on the input category
2043    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
2044    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
2045    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
2046    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
2047    p.add_argument('category', help='all or online or configuring or offline')
2048    p.set_defaults(func=bdev_raid_get_bdevs)
2049
2050    def bdev_raid_create(args):
2051        base_bdevs = []
2052        for u in args.base_bdevs.strip().split(" "):
2053            base_bdevs.append(u)
2054
2055        rpc.bdev.bdev_raid_create(args.client,
2056                                  name=args.name,
2057                                  strip_size_kb=args.strip_size_kb,
2058                                  raid_level=args.raid_level,
2059                                  base_bdevs=base_bdevs,
2060                                  uuid=args.uuid)
2061    p = subparsers.add_parser('bdev_raid_create', help='Create new raid bdev')
2062    p.add_argument('-n', '--name', help='raid bdev name', required=True)
2063    p.add_argument('-z', '--strip-size-kb', help='strip size in KB', type=int)
2064    p.add_argument('-r', '--raid-level', help='raid level, raid0, raid1 and a special level concat are supported', required=True)
2065    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
2066    p.add_argument('--uuid', help='UUID for this raid bdev', required=False)
2067    p.set_defaults(func=bdev_raid_create)
2068
2069    def bdev_raid_delete(args):
2070        rpc.bdev.bdev_raid_delete(args.client,
2071                                  name=args.name)
2072    p = subparsers.add_parser('bdev_raid_delete', help='Delete existing raid bdev')
2073    p.add_argument('name', help='raid bdev name')
2074    p.set_defaults(func=bdev_raid_delete)
2075
2076    # split
2077    def bdev_split_create(args):
2078        print_array(rpc.bdev.bdev_split_create(args.client,
2079                                               base_bdev=args.base_bdev,
2080                                               split_count=args.split_count,
2081                                               split_size_mb=args.split_size_mb))
2082
2083    p = subparsers.add_parser('bdev_split_create',
2084                              help="""Add given disk name to split config. If bdev with base_name
2085    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
2086    available (during examination process).""")
2087    p.add_argument('base_bdev', help='base bdev name')
2088    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int)
2089    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
2090    exceed the base bdev size.""", type=int)
2091    p.set_defaults(func=bdev_split_create)
2092
2093    def bdev_split_delete(args):
2094        rpc.bdev.bdev_split_delete(args.client,
2095                                   base_bdev=args.base_bdev)
2096
2097    p = subparsers.add_parser('bdev_split_delete', help="""Delete split config with all created splits.""")
2098    p.add_argument('base_bdev', help='base bdev name')
2099    p.set_defaults(func=bdev_split_delete)
2100
2101    # ftl
2102    def bdev_ftl_create(args):
2103        print_dict(rpc.bdev.bdev_ftl_create(args.client,
2104                                            name=args.name,
2105                                            base_bdev=args.base_bdev,
2106                                            uuid=args.uuid,
2107                                            cache=args.cache,
2108                                            overprovisioning=args.overprovisioning,
2109                                            l2p_dram_limit=args.l2p_dram_limit,
2110                                            core_mask=args.core_mask,
2111                                            fast_shutdown=args.fast_shutdown))
2112
2113    p = subparsers.add_parser('bdev_ftl_create', help='Add FTL bdev')
2114    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2115    p.add_argument('-d', '--base-bdev', help='Name of bdev used as underlying device',
2116                   required=True)
2117    p.add_argument('-u', '--uuid', help='UUID of restored bdev (not applicable when creating new '
2118                   'instance): e.g. b286d19a-0059-4709-abcd-9f7732b1567d (optional)')
2119    p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache',
2120                   required=True)
2121    p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed'
2122                   ' to user (optional); default 20', type=int)
2123    p.add_argument('--l2p-dram-limit', help='l2p size that could reside in DRAM (optional); default 2048',
2124                   type=int)
2125    p.add_argument('--core-mask', help='CPU core mask - which cores will be used for ftl core thread, '
2126                   'by default core thread will be set to the main application core (optional)')
2127    p.add_argument('-f', '--fast-shutdown', help="Enable fast shutdown", action='store_true')
2128    p.set_defaults(func=bdev_ftl_create)
2129
2130    def bdev_ftl_load(args):
2131        print_dict(rpc.bdev.bdev_ftl_load(args.client,
2132                                          name=args.name,
2133                                          base_bdev=args.base_bdev,
2134                                          uuid=args.uuid,
2135                                          cache=args.cache,
2136                                          overprovisioning=args.overprovisioning,
2137                                          l2p_dram_limit=args.l2p_dram_limit,
2138                                          core_mask=args.core_mask,
2139                                          fast_shutdown=args.fast_shutdown))
2140
2141    p = subparsers.add_parser('bdev_ftl_load', help='Load FTL bdev')
2142    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2143    p.add_argument('-d', '--base-bdev', help='Name of bdev used as underlying device',
2144                   required=True)
2145    p.add_argument('-u', '--uuid', help='UUID of restored bdev', required=True)
2146    p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache',
2147                   required=True)
2148    p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed'
2149                   ' to user (optional); default 20', type=int)
2150    p.add_argument('--l2p-dram-limit', help='l2p size that could reside in DRAM (optional); default 2048',
2151                   type=int)
2152    p.add_argument('--core-mask', help='CPU core mask - which cores will be used for ftl core thread, '
2153                   'by default core thread will be set to the main application core (optional)')
2154    p.add_argument('-f', '--fast-shutdown', help="Enable fast shutdown", action='store_true')
2155    p.set_defaults(func=bdev_ftl_load)
2156
2157    def bdev_ftl_unload(args):
2158        print_dict(rpc.bdev.bdev_ftl_unload(args.client, name=args.name, fast_shutdown=args.fast_shutdown))
2159
2160    p = subparsers.add_parser('bdev_ftl_unload', help='Unload FTL bdev')
2161    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2162    p.add_argument('-f', '--fast-shutdown', help="Fast shutdown", action='store_true')
2163    p.set_defaults(func=bdev_ftl_unload)
2164
2165    def bdev_ftl_delete(args):
2166        print_dict(rpc.bdev.bdev_ftl_delete(args.client, name=args.name, fast_shutdown=args.fast_shutdown))
2167
2168    p = subparsers.add_parser('bdev_ftl_delete', help='Delete FTL bdev')
2169    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2170    p.add_argument('-f', '--fast-shutdown', help="Fast shutdown", action='store_true')
2171    p.set_defaults(func=bdev_ftl_delete)
2172
2173    def bdev_ftl_unmap(args):
2174        print_dict(rpc.bdev.bdev_ftl_unmap(args.client, name=args.name,
2175                                           lba=args.lba,
2176                                           num_blocks=args.num_blocks))
2177
2178    p = subparsers.add_parser('bdev_ftl_unmap', help='FTL unmap')
2179    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2180    p.add_argument('--lba', help='start LBA', required=True, type=int)
2181    p.add_argument('--num-blocks', help='num blocks', required=True, type=int)
2182    p.set_defaults(func=bdev_ftl_unmap)
2183
2184    def bdev_ftl_get_stats(args):
2185        print_dict(rpc.bdev.bdev_ftl_get_stats(args.client, name=args.name))
2186
2187    p = subparsers.add_parser('bdev_ftl_get_stats', help='print ftl stats')
2188    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
2189    p.set_defaults(func=bdev_ftl_get_stats)
2190
2191    # vmd
2192    def vmd_enable(args):
2193        print_dict(rpc.vmd.vmd_enable(args.client))
2194
2195    p = subparsers.add_parser('vmd_enable', aliases=['enable_vmd'], help='Enable VMD enumeration')
2196    p.set_defaults(func=vmd_enable)
2197
2198    def vmd_remove_device(args):
2199        print_dict(rpc.vmd.vmd_remove_device(args.client, addr=args.addr))
2200
2201    p = subparsers.add_parser('vmd_remove_device', help='Remove a device behind VMD')
2202    p.add_argument('addr', help='Address of the device to remove', type=str)
2203    p.set_defaults(func=vmd_remove_device)
2204
2205    def vmd_rescan(args):
2206        print_dict(rpc.vmd.vmd_rescan(args.client))
2207
2208    p = subparsers.add_parser('vmd_rescan', help='Force a rescan of the devices behind VMD')
2209    p.set_defaults(func=vmd_rescan)
2210
2211    # ublk
2212    def ublk_create_target(args):
2213        rpc.ublk.ublk_create_target(args.client,
2214                                    cpumask=args.cpumask)
2215    p = subparsers.add_parser('ublk_create_target',
2216                              help='Create spdk ublk target for ublk dev')
2217    p.add_argument('-m', '--cpumask', help='cpu mask for ublk dev')
2218    p.set_defaults(func=ublk_create_target)
2219
2220    def ublk_destroy_target(args):
2221        rpc.ublk.ublk_destroy_target(args.client)
2222    p = subparsers.add_parser('ublk_destroy_target',
2223                              help='Destroy spdk ublk target for ublk dev')
2224    p.set_defaults(func=ublk_destroy_target)
2225
2226    def ublk_start_disk(args):
2227        print(rpc.ublk.ublk_start_disk(args.client,
2228                                       bdev_name=args.bdev_name,
2229                                       ublk_id=args.ublk_id,
2230                                       num_queues=args.num_queues,
2231                                       queue_depth=args.queue_depth))
2232
2233    p = subparsers.add_parser('ublk_start_disk',
2234                              help='Export a bdev as a ublk device')
2235    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
2236    p.add_argument('ublk_id', help='ublk device id to be assigned. Example: 1.', type=int)
2237    p.add_argument('-q', '--num-queues', help="the total number of queues. Example: 1", type=int, required=False)
2238    p.add_argument('-d', '--queue-depth', help="queue depth. Example: 128", type=int, required=False)
2239    p.set_defaults(func=ublk_start_disk)
2240
2241    def ublk_stop_disk(args):
2242        rpc.ublk.ublk_stop_disk(args.client,
2243                                ublk_id=args.ublk_id)
2244
2245    p = subparsers.add_parser('ublk_stop_disk',
2246                              help='Stop a ublk device')
2247    p.add_argument('ublk_id', help='ublk device id to be deleted. Example: 1.', type=int)
2248    p.set_defaults(func=ublk_stop_disk)
2249
2250    def ublk_get_disks(args):
2251        print_dict(rpc.ublk.ublk_get_disks(args.client,
2252                                           ublk_id=args.ublk_id))
2253
2254    p = subparsers.add_parser('ublk_get_disks',
2255                              help='Display full or specified ublk device list')
2256    p.add_argument('-n', '--ublk-id', help="ublk device id. Example: 1", type=int, required=False)
2257    p.set_defaults(func=ublk_get_disks)
2258
2259    # nbd
2260    def nbd_start_disk(args):
2261        print(rpc.nbd.nbd_start_disk(args.client,
2262                                     bdev_name=args.bdev_name,
2263                                     nbd_device=args.nbd_device))
2264
2265    p = subparsers.add_parser('nbd_start_disk',
2266                              help='Export a bdev as an nbd disk')
2267    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
2268    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.', nargs='?')
2269    p.set_defaults(func=nbd_start_disk)
2270
2271    def nbd_stop_disk(args):
2272        rpc.nbd.nbd_stop_disk(args.client,
2273                              nbd_device=args.nbd_device)
2274
2275    p = subparsers.add_parser('nbd_stop_disk',
2276                              help='Stop an nbd disk')
2277    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
2278    p.set_defaults(func=nbd_stop_disk)
2279
2280    def nbd_get_disks(args):
2281        print_dict(rpc.nbd.nbd_get_disks(args.client,
2282                                         nbd_device=args.nbd_device))
2283
2284    p = subparsers.add_parser('nbd_get_disks',
2285                              help='Display full or specified nbd device list')
2286    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
2287    p.set_defaults(func=nbd_get_disks)
2288
2289    # NVMe-oF
2290    def nvmf_set_max_subsystems(args):
2291        rpc.nvmf.nvmf_set_max_subsystems(args.client,
2292                                         max_subsystems=args.max_subsystems)
2293
2294    p = subparsers.add_parser('nvmf_set_max_subsystems',
2295                              help='Set the maximum number of NVMf target subsystems')
2296    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True)
2297    p.set_defaults(func=nvmf_set_max_subsystems)
2298
2299    def nvmf_set_config(args):
2300        rpc.nvmf.nvmf_set_config(args.client,
2301                                 passthru_identify_ctrlr=args.passthru_identify_ctrlr,
2302                                 poll_groups_mask=args.poll_groups_mask,
2303                                 discovery_filter=args.discovery_filter)
2304
2305    p = subparsers.add_parser('nvmf_set_config', help='Set NVMf target config')
2306    p.add_argument('-i', '--passthru-identify-ctrlr', help="""Passthrough fields like serial number and model number
2307    when the controller has a single namespace that is an NVMe bdev""", action='store_true')
2308    p.add_argument('-m', '--poll-groups-mask', help='Set cpumask for NVMf poll groups (optional)', type=str)
2309    p.add_argument('-d', '--discovery-filter', help="""Set discovery filter (optional), possible values are: `match_any` (default) or
2310         comma separated values: `transport`, `address`, `svcid`""", type=str)
2311    p.set_defaults(func=nvmf_set_config)
2312
2313    def nvmf_create_transport(args):
2314        rpc.nvmf.nvmf_create_transport(**vars(args))
2315
2316    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
2317    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
2318    p.add_argument('-g', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2319    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
2320    p.add_argument('-m', '--max-io-qpairs-per-ctrlr', help='Max number of IO qpairs per controller', type=int)
2321    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
2322    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
2323    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
2324    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
2325    p.add_argument('-n', '--num-shared-buffers', help='The number of pooled data buffers available to the transport', type=int)
2326    p.add_argument('-b', '--buf-cache-size', help='The number of shared buffers to reserve for each poll group', type=int)
2327    p.add_argument('-z', '--zcopy', action='store_true', help='''Use zero-copy operations if the
2328    underlying bdev supports them''')
2329    p.add_argument('-d', '--num-cqe', help="""The number of CQ entries. Only used when no_srq=true.
2330    Relevant only for RDMA transport""", type=int)
2331    p.add_argument('-s', '--max-srq-depth', help='Max number of outstanding I/O per SRQ. Relevant only for RDMA transport', type=int)
2332    p.add_argument('-r', '--no-srq', action='store_true', help='Disable per-thread shared receive queue. Relevant only for RDMA transport')
2333    p.add_argument('-o', '--c2h-success', action='store_false', help='Disable C2H success optimization. Relevant only for TCP transport')
2334    p.add_argument('-f', '--dif-insert-or-strip', action='store_true', help='Enable DIF insert/strip. Relevant only for TCP transport')
2335    p.add_argument('-y', '--sock-priority', help='The sock priority of the tcp connection. Relevant only for TCP transport', type=int)
2336    p.add_argument('-l', '--acceptor-backlog', help='Pending connections allowed at one time. Relevant only for RDMA transport', type=int)
2337    p.add_argument('-x', '--abort-timeout-sec', help='Abort execution timeout value, in seconds', type=int)
2338    p.add_argument('-w', '--no-wr-batching', action='store_true', help='Disable work requests batching. Relevant only for RDMA transport')
2339    p.add_argument('-e', '--control-msg-num', help="""The number of control messages per poll group.
2340    Relevant only for TCP transport""", type=int)
2341    p.add_argument('-M', '--disable-mappable-bar0', action='store_true', help="""Disable mmap() of BAR0.
2342    Relevant only for VFIO-USER transport""")
2343    p.add_argument('-I', '--disable-adaptive-irq', action='store_true', help="""Disable adaptive interrupt feature.
2344    Relevant only for VFIO-USER transport""")
2345    p.add_argument('-S', '--disable-shadow-doorbells', action='store_true', help="""Disable shadow doorbell support.
2346    Relevant only for VFIO-USER transport""")
2347    p.add_argument('--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
2348    p.set_defaults(func=nvmf_create_transport)
2349
2350    def nvmf_get_transports(args):
2351        print_dict(rpc.nvmf.nvmf_get_transports(args.client, trtype=args.trtype, tgt_name=args.tgt_name))
2352
2353    p = subparsers.add_parser('nvmf_get_transports', help='Display nvmf transports or required transport')
2354    p.add_argument('--trtype', help='Transport type (optional)')
2355    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2356    p.set_defaults(func=nvmf_get_transports)
2357
2358    def nvmf_get_subsystems(args):
2359        print_dict(rpc.nvmf.nvmf_get_subsystems(args.client, nqn=args.nqn, tgt_name=args.tgt_name))
2360
2361    p = subparsers.add_parser('nvmf_get_subsystems', help='Display nvmf subsystems or required subsystem')
2362    p.add_argument('nqn', help='Subsystem NQN (optional)', nargs="?")
2363    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2364    p.set_defaults(func=nvmf_get_subsystems)
2365
2366    def nvmf_create_subsystem(args):
2367        rpc.nvmf.nvmf_create_subsystem(args.client,
2368                                       nqn=args.nqn,
2369                                       tgt_name=args.tgt_name,
2370                                       serial_number=args.serial_number,
2371                                       model_number=args.model_number,
2372                                       allow_any_host=args.allow_any_host,
2373                                       max_namespaces=args.max_namespaces,
2374                                       ana_reporting=args.ana_reporting,
2375                                       min_cntlid=args.min_cntlid,
2376                                       max_cntlid=args.max_cntlid)
2377
2378    p = subparsers.add_parser('nvmf_create_subsystem', help='Create an NVMe-oF subsystem')
2379    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
2380    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2381    p.add_argument("-s", "--serial-number", help="""
2382    Format:  'sn' etc
2383    Example: 'SPDK00000000000001'""")
2384    p.add_argument("-d", "--model-number", help="""
2385    Format:  'mn' etc
2386    Example: 'SPDK Controller'""")
2387    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce allowed host NQN list)")
2388    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
2389                   type=int)
2390    p.add_argument("-r", "--ana-reporting", action='store_true', help="Enable ANA reporting feature")
2391    p.add_argument("-i", "--min_cntlid", help="Minimum controller ID", type=int)
2392    p.add_argument("-I", "--max_cntlid", help="Maximum controller ID", type=int)
2393    p.set_defaults(func=nvmf_create_subsystem)
2394
2395    def nvmf_delete_subsystem(args):
2396        rpc.nvmf.nvmf_delete_subsystem(args.client,
2397                                       nqn=args.subsystem_nqn,
2398                                       tgt_name=args.tgt_name)
2399
2400    p = subparsers.add_parser('nvmf_delete_subsystem', help='Delete a nvmf subsystem')
2401    p.add_argument('subsystem_nqn',
2402                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
2403    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2404    p.set_defaults(func=nvmf_delete_subsystem)
2405
2406    def nvmf_subsystem_add_listener(args):
2407        rpc.nvmf.nvmf_subsystem_add_listener(**vars(args))
2408
2409    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
2410    p.add_argument('nqn', help='NVMe-oF subsystem NQN (\'discovery\' can be used as shortcut for discovery NQN)')
2411    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2412    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2413    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2414    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2415    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number (required for RDMA or TCP)')
2416    p.set_defaults(func=nvmf_subsystem_add_listener)
2417
2418    def nvmf_subsystem_remove_listener(args):
2419        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
2420                                                nqn=args.nqn,
2421                                                trtype=args.trtype,
2422                                                traddr=args.traddr,
2423                                                tgt_name=args.tgt_name,
2424                                                adrfam=args.adrfam,
2425                                                trsvcid=args.trsvcid)
2426
2427    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
2428    p.add_argument('nqn', help='NVMe-oF subsystem NQN (\'discovery\' can be used as shortcut for discovery NQN)')
2429    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2430    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2431    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2432    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2433    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number (required for TCP and RDMA transport types)')
2434    p.set_defaults(func=nvmf_subsystem_remove_listener)
2435
2436    def nvmf_subsystem_listener_set_ana_state(args):
2437        rpc.nvmf.nvmf_subsystem_listener_set_ana_state(args.client,
2438                                                       nqn=args.nqn,
2439                                                       ana_state=args.ana_state,
2440                                                       trtype=args.trtype,
2441                                                       traddr=args.traddr,
2442                                                       tgt_name=args.tgt_name,
2443                                                       adrfam=args.adrfam,
2444                                                       trsvcid=args.trsvcid,
2445                                                       anagrpid=args.anagrpid)
2446
2447    p = subparsers.add_parser('nvmf_subsystem_listener_set_ana_state', help='Set ANA state of a listener for an NVMe-oF subsystem')
2448    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2449    p.add_argument('-n', '--ana-state', help='ANA state to set: optimized, non_optimized, or inaccessible', required=True)
2450    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
2451    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
2452    p.add_argument('-p', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2453    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
2454    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
2455    p.add_argument('-g', '--anagrpid', help='ANA group ID (optional)', type=int)
2456    p.set_defaults(func=nvmf_subsystem_listener_set_ana_state)
2457
2458    def nvmf_subsystem_add_ns(args):
2459        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
2460                                       nqn=args.nqn,
2461                                       bdev_name=args.bdev_name,
2462                                       tgt_name=args.tgt_name,
2463                                       ptpl_file=args.ptpl_file,
2464                                       nsid=args.nsid,
2465                                       nguid=args.nguid,
2466                                       eui64=args.eui64,
2467                                       uuid=args.uuid,
2468                                       anagrpid=args.anagrpid)
2469
2470    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
2471    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2472    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
2473    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2474    p.add_argument('-p', '--ptpl-file', help='The persistent reservation storage location (optional)', type=str)
2475    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
2476    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
2477    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
2478    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
2479    p.add_argument('-a', '--anagrpid', help='ANA group ID (optional)', type=int)
2480    p.set_defaults(func=nvmf_subsystem_add_ns)
2481
2482    def nvmf_subsystem_remove_ns(args):
2483        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
2484                                          nqn=args.nqn,
2485                                          nsid=args.nsid,
2486                                          tgt_name=args.tgt_name)
2487
2488    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
2489    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2490    p.add_argument('nsid', help='The requested NSID', type=int)
2491    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2492    p.set_defaults(func=nvmf_subsystem_remove_ns)
2493
2494    def nvmf_subsystem_add_host(args):
2495        rpc.nvmf.nvmf_subsystem_add_host(args.client,
2496                                         nqn=args.nqn,
2497                                         host=args.host,
2498                                         tgt_name=args.tgt_name)
2499
2500    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
2501    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2502    p.add_argument('host', help='Host NQN to allow')
2503    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2504    p.set_defaults(func=nvmf_subsystem_add_host)
2505
2506    def nvmf_subsystem_remove_host(args):
2507        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
2508                                            nqn=args.nqn,
2509                                            host=args.host,
2510                                            tgt_name=args.tgt_name)
2511
2512    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
2513    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2514    p.add_argument('host', help='Host NQN to remove')
2515    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2516    p.set_defaults(func=nvmf_subsystem_remove_host)
2517
2518    def nvmf_subsystem_allow_any_host(args):
2519        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
2520                                               nqn=args.nqn,
2521                                               disable=args.disable,
2522                                               tgt_name=args.tgt_name)
2523
2524    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
2525    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2526    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
2527    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
2528    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2529    p.set_defaults(func=nvmf_subsystem_allow_any_host)
2530
2531    def nvmf_subsystem_get_controllers(args):
2532        print_dict(rpc.nvmf.nvmf_subsystem_get_controllers(args.client,
2533                                                           nqn=args.nqn,
2534                                                           tgt_name=args.tgt_name))
2535
2536    p = subparsers.add_parser('nvmf_subsystem_get_controllers',
2537                              help='Display controllers of an NVMe-oF subsystem.')
2538    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2539    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2540    p.set_defaults(func=nvmf_subsystem_get_controllers)
2541
2542    def nvmf_subsystem_get_qpairs(args):
2543        print_dict(rpc.nvmf.nvmf_subsystem_get_qpairs(args.client,
2544                                                      nqn=args.nqn,
2545                                                      tgt_name=args.tgt_name))
2546
2547    p = subparsers.add_parser('nvmf_subsystem_get_qpairs',
2548                              help='Display queue pairs of an NVMe-oF subsystem.')
2549    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2550    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2551    p.set_defaults(func=nvmf_subsystem_get_qpairs)
2552
2553    def nvmf_subsystem_get_listeners(args):
2554        print_dict(rpc.nvmf.nvmf_subsystem_get_listeners(args.client,
2555                                                         nqn=args.nqn,
2556                                                         tgt_name=args.tgt_name))
2557
2558    p = subparsers.add_parser('nvmf_subsystem_get_listeners',
2559                              help='Display listeners of an NVMe-oF subsystem.')
2560    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
2561    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2562    p.set_defaults(func=nvmf_subsystem_get_listeners)
2563
2564    def nvmf_get_stats(args):
2565        print_dict(rpc.nvmf.nvmf_get_stats(args.client, tgt_name=args.tgt_name))
2566
2567    p = subparsers.add_parser(
2568        'nvmf_get_stats', help='Display current statistics for NVMf subsystem')
2569    p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
2570    p.set_defaults(func=nvmf_get_stats)
2571
2572    def nvmf_set_crdt(args):
2573        print_dict(rpc.nvmf.nvmf_set_crdt(args.client, args.crdt1, args.crdt2, args.crdt3))
2574
2575    p = subparsers.add_parser(
2576        'nvmf_set_crdt',
2577        help="""Set the 3 crdt (Command Retry Delay Time) values for NVMf subsystem. All
2578        values are in units of 100 milliseconds (same as the NVM Express specification).""")
2579    p.add_argument('-t1', '--crdt1', help='Command Retry Delay Time 1, in units of 100 milliseconds', type=int)
2580    p.add_argument('-t2', '--crdt2', help='Command Retry Delay Time 2, in units of 100 milliseconds', type=int)
2581    p.add_argument('-t3', '--crdt3', help='Command Retry Delay Time 3, in units of 100 milliseconds', type=int)
2582    p.set_defaults(func=nvmf_set_crdt)
2583
2584    # subsystem
2585    def framework_get_subsystems(args):
2586        print_dict(rpc.subsystem.framework_get_subsystems(args.client))
2587
2588    p = subparsers.add_parser('framework_get_subsystems',
2589                              help="""Print subsystems array in initialization order. Each subsystem
2590    entry contain (unsorted) array of subsystems it depends on.""")
2591    p.set_defaults(func=framework_get_subsystems)
2592
2593    def framework_get_config(args):
2594        print_dict(rpc.subsystem.framework_get_config(args.client, args.name))
2595
2596    p = subparsers.add_parser('framework_get_config', help="""Print subsystem configuration""")
2597    p.add_argument('name', help='Name of subsystem to query')
2598    p.set_defaults(func=framework_get_config)
2599
2600    # vhost
2601    def vhost_controller_set_coalescing(args):
2602        rpc.vhost.vhost_controller_set_coalescing(args.client,
2603                                                  ctrlr=args.ctrlr,
2604                                                  delay_base_us=args.delay_base_us,
2605                                                  iops_threshold=args.iops_threshold)
2606
2607    p = subparsers.add_parser('vhost_controller_set_coalescing', help='Set vhost controller coalescing')
2608    p.add_argument('ctrlr', help='controller name')
2609    p.add_argument('delay_base_us', help='Base delay time', type=int)
2610    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
2611    p.set_defaults(func=vhost_controller_set_coalescing)
2612
2613    def virtio_blk_create_transport(args):
2614        rpc.vhost.virtio_blk_create_transport(**vars(args))
2615
2616    p = subparsers.add_parser('virtio_blk_create_transport',
2617                              help='Create virtio blk transport')
2618    p.add_argument('name', help='transport name')
2619    p.set_defaults(func=virtio_blk_create_transport)
2620
2621    def virtio_blk_get_transports(args):
2622        print_dict(rpc.vhost.virtio_blk_get_transports(args.client, name=args.name))
2623
2624    p = subparsers.add_parser('virtio_blk_get_transports', help='Display virtio-blk transports or requested transport')
2625    p.add_argument('--name', help='Transport name (optional)', type=str)
2626    p.set_defaults(func=virtio_blk_get_transports)
2627
2628    def vhost_create_scsi_controller(args):
2629        rpc.vhost.vhost_create_scsi_controller(args.client,
2630                                               ctrlr=args.ctrlr,
2631                                               cpumask=args.cpumask)
2632
2633    p = subparsers.add_parser('vhost_create_scsi_controller', help='Add new vhost controller')
2634    p.add_argument('ctrlr', help='controller name')
2635    p.add_argument('--cpumask', help='cpu mask for this controller')
2636    p.set_defaults(func=vhost_create_scsi_controller)
2637
2638    def vhost_scsi_controller_add_target(args):
2639        print_json(rpc.vhost.vhost_scsi_controller_add_target(args.client,
2640                                                              ctrlr=args.ctrlr,
2641                                                              scsi_target_num=args.scsi_target_num,
2642                                                              bdev_name=args.bdev_name))
2643
2644    p = subparsers.add_parser('vhost_scsi_controller_add_target', help='Add lun to vhost controller')
2645    p.add_argument('ctrlr', help='controller name where add lun')
2646    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
2647    p.add_argument('bdev_name', help='bdev name')
2648    p.set_defaults(func=vhost_scsi_controller_add_target)
2649
2650    def vhost_scsi_controller_remove_target(args):
2651        rpc.vhost.vhost_scsi_controller_remove_target(args.client,
2652                                                      ctrlr=args.ctrlr,
2653                                                      scsi_target_num=args.scsi_target_num)
2654
2655    p = subparsers.add_parser('vhost_scsi_controller_remove_target',
2656                              help='Remove target from vhost controller')
2657    p.add_argument('ctrlr', help='controller name to remove target from')
2658    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
2659    p.set_defaults(func=vhost_scsi_controller_remove_target)
2660
2661    def vhost_create_blk_controller(args):
2662        rpc.vhost.vhost_create_blk_controller(**vars(args))
2663
2664    p = subparsers.add_parser('vhost_create_blk_controller', help='Add a new vhost block controller')
2665    p.add_argument('ctrlr', help='controller name')
2666    p.add_argument('dev_name', help='device name')
2667    p.add_argument('--cpumask', help='cpu mask for this controller')
2668    p.add_argument('--transport', help='virtio blk transport name (default: vhost_user_blk)')
2669    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
2670    p.add_argument("-p", "--packed_ring", action='store_true', help='Set controller as packed ring supported')
2671    p.add_argument("-l", "--packed_ring_recovery", action='store_true', help='Enable packed ring live recovery')
2672    p.set_defaults(func=vhost_create_blk_controller)
2673
2674    def vhost_get_controllers(args):
2675        print_dict(rpc.vhost.vhost_get_controllers(args.client, args.name))
2676
2677    p = subparsers.add_parser('vhost_get_controllers', help='List all or specific vhost controller(s)')
2678    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
2679    p.set_defaults(func=vhost_get_controllers)
2680
2681    def vhost_delete_controller(args):
2682        rpc.vhost.vhost_delete_controller(args.client,
2683                                          ctrlr=args.ctrlr)
2684
2685    p = subparsers.add_parser('vhost_delete_controller', help='Delete a vhost controller')
2686    p.add_argument('ctrlr', help='controller name')
2687    p.set_defaults(func=vhost_delete_controller)
2688
2689    def bdev_virtio_attach_controller(args):
2690        print_array(rpc.vhost.bdev_virtio_attach_controller(args.client,
2691                                                            name=args.name,
2692                                                            trtype=args.trtype,
2693                                                            traddr=args.traddr,
2694                                                            dev_type=args.dev_type,
2695                                                            vq_count=args.vq_count,
2696                                                            vq_size=args.vq_size))
2697
2698    p = subparsers.add_parser('bdev_virtio_attach_controller',
2699                              help="""Attach virtio controller using provided
2700    transport type and device type. This will also create bdevs for any block devices connected to the
2701    controller (for example, SCSI devices for a virtio-scsi controller).
2702    Result is array of added bdevs.""")
2703    p.add_argument('name', help="Use this name as base for new created bdevs")
2704    p.add_argument('-t', '--trtype',
2705                   help='Virtio target transport type: pci or user', required=True)
2706    p.add_argument('-a', '--traddr',
2707                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
2708    p.add_argument('-d', '--dev-type',
2709                   help='Device type: blk or scsi', required=True)
2710    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
2711    p.add_argument('--vq-size', help='Size of each queue', type=int)
2712    p.set_defaults(func=bdev_virtio_attach_controller)
2713
2714    def bdev_virtio_scsi_get_devices(args):
2715        print_dict(rpc.vhost.bdev_virtio_scsi_get_devices(args.client))
2716
2717    p = subparsers.add_parser('bdev_virtio_scsi_get_devices', help='List all Virtio-SCSI devices.')
2718    p.set_defaults(func=bdev_virtio_scsi_get_devices)
2719
2720    def bdev_virtio_detach_controller(args):
2721        rpc.vhost.bdev_virtio_detach_controller(args.client,
2722                                                name=args.name)
2723
2724    p = subparsers.add_parser('bdev_virtio_detach_controller', help="""Remove a Virtio device
2725    This will delete all bdevs exposed by this device""")
2726    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
2727    p.set_defaults(func=bdev_virtio_detach_controller)
2728
2729    def bdev_virtio_blk_set_hotplug(args):
2730        rpc.vhost.bdev_virtio_blk_set_hotplug(args.client, enable=args.enable, period_us=args.period_us)
2731
2732    p = subparsers.add_parser('bdev_virtio_blk_set_hotplug', help='Set hotplug options for bdev virtio_blk type.')
2733    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
2734    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
2735    p.add_argument('-r', '--period-us',
2736                   help='How often the hotplug is processed for insert and remove events', type=int)
2737    p.set_defaults(func=bdev_virtio_blk_set_hotplug)
2738
2739    # vfio-user target
2740    def vfu_tgt_set_base_path(args):
2741        rpc.vfio_user.vfu_tgt_set_base_path(args.client, path=args.path)
2742
2743    p = subparsers.add_parser('vfu_tgt_set_base_path', help='Set socket base path.')
2744    p.add_argument('path', help='socket base path')
2745    p.set_defaults(func=vfu_tgt_set_base_path)
2746
2747    def vfu_virtio_delete_endpoint(args):
2748        rpc.vfio_user.vfu_virtio_delete_endpoint(args.client, name=args.name)
2749
2750    p = subparsers.add_parser('vfu_virtio_delete_endpoint', help='Delete the PCI device via endpoint name.')
2751    p.add_argument('name', help='Endpoint name')
2752    p.set_defaults(func=vfu_virtio_delete_endpoint)
2753
2754    def vfu_virtio_create_blk_endpoint(args):
2755        rpc.vfio_user.vfu_virtio_create_blk_endpoint(args.client,
2756                                                     name=args.name,
2757                                                     bdev_name=args.bdev_name,
2758                                                     cpumask=args.cpumask,
2759                                                     num_queues=args.num_queues,
2760                                                     qsize=args.qsize,
2761                                                     packed_ring=args.packed_ring)
2762
2763    p = subparsers.add_parser('vfu_virtio_create_blk_endpoint', help='Create virtio-blk endpoint.')
2764    p.add_argument('name', help='Name of the endpoint')
2765    p.add_argument('--bdev-name', help='block device name', type=str, required=True)
2766    p.add_argument('--cpumask', help='CPU masks')
2767    p.add_argument('--num-queues', help='number of vrings', type=int, default=0)
2768    p.add_argument('--qsize', help='number of element for each vring', type=int, default=0)
2769    p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
2770    p.set_defaults(func=vfu_virtio_create_blk_endpoint)
2771
2772    def vfu_virtio_scsi_add_target(args):
2773        rpc.vfio_user.vfu_virtio_scsi_add_target(args.client,
2774                                                 name=args.name,
2775                                                 scsi_target_num=args.scsi_target_num,
2776                                                 bdev_name=args.bdev_name)
2777
2778    p = subparsers.add_parser('vfu_virtio_scsi_add_target', help='Attach a block device to SCSI target of PCI endpoint.')
2779    p.add_argument('name', help='Name of the endpoint')
2780    p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
2781    p.add_argument('--bdev-name', help='block device name', type=str, required=True)
2782    p.set_defaults(func=vfu_virtio_scsi_add_target)
2783
2784    def vfu_virtio_scsi_remove_target(args):
2785        rpc.vfio_user.vfu_virtio_scsi_remove_target(args.client,
2786                                                    name=args.name,
2787                                                    scsi_target_num=args.scsi_target_num)
2788
2789    p = subparsers.add_parser('vfu_virtio_scsi_remove_target', help='Remove the specified SCSI target of PCI endpoint.')
2790    p.add_argument('name', help='Name of the endpoint')
2791    p.add_argument('--scsi-target-num', help='number of SCSI Target', type=int, required=True)
2792    p.set_defaults(func=vfu_virtio_scsi_remove_target)
2793
2794    def vfu_virtio_create_scsi_endpoint(args):
2795        rpc.vfio_user.vfu_virtio_create_scsi_endpoint(args.client,
2796                                                      name=args.name,
2797                                                      cpumask=args.cpumask,
2798                                                      num_io_queues=args.num_io_queues,
2799                                                      qsize=args.qsize,
2800                                                      packed_ring=args.packed_ring)
2801
2802    p = subparsers.add_parser('vfu_virtio_create_scsi_endpoint', help='Create virtio-scsi endpoint.')
2803    p.add_argument('name', help='Name of the endpoint')
2804    p.add_argument('--cpumask', help='CPU masks')
2805    p.add_argument('--num-io-queues', help='number of IO vrings', type=int, default=0)
2806    p.add_argument('--qsize', help='number of element for each vring', type=int, default=0)
2807    p.add_argument("--packed-ring", action='store_true', help='Enable packed ring')
2808    p.set_defaults(func=vfu_virtio_create_scsi_endpoint)
2809
2810    # accel_fw
2811    def accel_get_opc_assignments(args):
2812        print_dict(rpc.accel.accel_get_opc_assignments(args.client))
2813
2814    p = subparsers.add_parser('accel_get_opc_assignments', help='Get list of opcode name to module assignments.')
2815    p.set_defaults(func=accel_get_opc_assignments)
2816
2817    def accel_get_module_info(args):
2818        print_dict(rpc.accel.accel_get_module_info(args.client))
2819
2820    p = subparsers.add_parser('accel_get_module_info', help='Get list of valid module names and their operations.')
2821    p.set_defaults(func=accel_get_module_info)
2822
2823    def accel_assign_opc(args):
2824        rpc.accel.accel_assign_opc(args.client, opname=args.opname, module=args.module)
2825
2826    p = subparsers.add_parser('accel_assign_opc', help='Manually assign an operation to a module.')
2827    p.add_argument('-o', '--opname', help='opname')
2828    p.add_argument('-m', '--module', help='name of module')
2829    p.set_defaults(func=accel_assign_opc)
2830
2831    def accel_crypto_key_create(args):
2832        print_dict(rpc.accel.accel_crypto_key_create(args.client,
2833                                                     cipher=args.cipher,
2834                                                     key=args.key,
2835                                                     key2=args.key2,
2836                                                     name=args.name))
2837
2838    p = subparsers.add_parser('accel_crypto_key_create', help='Create encryption key')
2839    p.add_argument('-c', '--cipher', help='cipher', required=True, type=str)
2840    p.add_argument('-k', '--key', help='key', required=True, type=str)
2841    p.add_argument('-e', '--key2', help='key2', required=False, type=str)
2842    p.add_argument('-n', '--name', help='key name', required=True, type=str)
2843    p.set_defaults(func=accel_crypto_key_create)
2844
2845    def accel_crypto_key_destroy(args):
2846        print_dict(rpc.accel.accel_crypto_key_destroy(args.client,
2847                                                      key_name=args.name))
2848
2849    p = subparsers.add_parser('accel_crypto_key_destroy', help='Destroy encryption key')
2850    p.add_argument('-n', '--name', help='key name', required=True, type=str)
2851    p.set_defaults(func=accel_crypto_key_destroy)
2852
2853    def accel_crypto_keys_get(args):
2854        print_dict(rpc.accel.accel_crypto_keys_get(args.client,
2855                                                   key_name=args.key_name))
2856
2857    p = subparsers.add_parser('accel_crypto_keys_get', help='Get a list of the crypto keys')
2858    p.add_argument('-k', '--key-name', help='Get information about a specific key', type=str)
2859    p.set_defaults(func=accel_crypto_keys_get)
2860
2861    def accel_set_driver(args):
2862        rpc.accel.accel_set_driver(args.client, name=args.name)
2863
2864    p = subparsers.add_parser('accel_set_driver', help='Select accel platform driver to execute ' +
2865                              'operation chains')
2866    p.add_argument('name', help='name of the platform driver')
2867    p.set_defaults(func=accel_set_driver)
2868
2869    def accel_set_options(args):
2870        rpc.accel.accel_set_options(args.client, args.small_cache_size, args.large_cache_size)
2871
2872    p = subparsers.add_parser('accel_set_options', help='Set accel framework\'s options')
2873    p.add_argument('--small-cache-size', type=int, help='Size of the small iobuf cache')
2874    p.add_argument('--large-cache-size', type=int, help='Size of the large iobuf cache')
2875    p.set_defaults(func=accel_set_options)
2876
2877    def accel_get_stats(args):
2878        print_dict(rpc.accel.accel_get_stats(args.client))
2879
2880    p = subparsers.add_parser('accel_get_stats', help='Display accel framework\'s statistics')
2881    p.set_defaults(func=accel_get_stats)
2882
2883    # ioat
2884    def ioat_scan_accel_module(args):
2885        rpc.ioat.ioat_scan_accel_module(args.client)
2886
2887    p = subparsers.add_parser('ioat_scan_accel_module', help='Enable IOAT accel module offload.')
2888    p.set_defaults(func=ioat_scan_accel_module)
2889
2890    # dpdk compressdev
2891    def compressdev_scan_accel_module(args):
2892        rpc.compressdev.compressdev_scan_accel_module(args.client, pmd=args.pmd)
2893
2894    p = subparsers.add_parser('compressdev_scan_accel_module', help='Scan and enable compressdev module and set pmd option.')
2895    p.add_argument('-p', '--pmd', type=int, help='0 = auto-select, 1= QAT only, 2 = mlx5_pci only')
2896    p.set_defaults(func=compressdev_scan_accel_module)
2897
2898    # dsa
2899    def dsa_scan_accel_module(args):
2900        rpc.dsa.dsa_scan_accel_module(args.client, config_kernel_mode=args.config_kernel_mode)
2901
2902    p = subparsers.add_parser('dsa_scan_accel_module',
2903                              help='Set config and enable dsa accel module offload.')
2904    p.add_argument('-k', '--config-kernel-mode', help='Use Kernel mode dsa',
2905                   action='store_true', dest='config_kernel_mode')
2906    p.set_defaults(func=dsa_scan_accel_module, config_kernel_mode=None)
2907
2908    # iaa
2909    def iaa_scan_accel_module(args):
2910        rpc.iaa.iaa_scan_accel_module(args.client)
2911
2912    p = subparsers.add_parser('iaa_scan_accel_module',
2913                              help='Set config and enable iaa accel module offload.')
2914    p.set_defaults(func=iaa_scan_accel_module)
2915
2916    def dpdk_cryptodev_scan_accel_module(args):
2917        rpc.dpdk_cryptodev.dpdk_cryptodev_scan_accel_module(args.client)
2918
2919    p = subparsers.add_parser('dpdk_cryptodev_scan_accel_module',
2920                              help='Enable dpdk_cryptodev accel module offload.')
2921    p.set_defaults(func=dpdk_cryptodev_scan_accel_module)
2922
2923    def dpdk_cryptodev_set_driver(args):
2924        rpc.dpdk_cryptodev.dpdk_cryptodev_set_driver(args.client,
2925                                                     driver_name=args.driver_name)
2926
2927    p = subparsers.add_parser('dpdk_cryptodev_set_driver',
2928                              help='Set the DPDK cryptodev driver.')
2929    p.add_argument('-d', '--driver-name', help='The driver, can be one of crypto_aesni_mb, crypto_qat or mlx5_pci', type=str)
2930    p.set_defaults(func=dpdk_cryptodev_set_driver)
2931
2932    def dpdk_cryptodev_get_driver(args):
2933        print_dict(rpc.dpdk_cryptodev.dpdk_cryptodev_get_driver(args.client))
2934
2935    p = subparsers.add_parser('dpdk_cryptodev_get_driver', help='Get the DPDK cryptodev driver')
2936    p.set_defaults(func=dpdk_cryptodev_get_driver)
2937
2938    # mlx5
2939    def mlx5_scan_accel_module(args):
2940        rpc.mlx5.mlx5_scan_accel_module(args.client,
2941                                        qp_size=args.qp_size,
2942                                        num_requests=args.num_requests)
2943
2944    p = subparsers.add_parser('mlx5_scan_accel_module', help='Enable mlx5 accel module.')
2945    p.add_argument('-q', '--qp-size', type=int, help='QP size')
2946    p.add_argument('-r', '--num-requests', type=int, help='Size of the shared requests pool')
2947    p.set_defaults(func=mlx5_scan_accel_module)
2948
2949    # opal
2950    def bdev_nvme_opal_init(args):
2951        rpc.nvme.bdev_nvme_opal_init(args.client,
2952                                     nvme_ctrlr_name=args.nvme_ctrlr_name,
2953                                     password=args.password)
2954
2955    p = subparsers.add_parser('bdev_nvme_opal_init', help='take ownership and activate')
2956    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
2957    p.add_argument('-p', '--password', help='password for admin')
2958    p.set_defaults(func=bdev_nvme_opal_init)
2959
2960    def bdev_nvme_opal_revert(args):
2961        rpc.nvme.bdev_nvme_opal_revert(args.client,
2962                                       nvme_ctrlr_name=args.nvme_ctrlr_name,
2963                                       password=args.password)
2964    p = subparsers.add_parser('bdev_nvme_opal_revert', help='Revert to default factory settings')
2965    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
2966    p.add_argument('-p', '--password', help='password')
2967    p.set_defaults(func=bdev_nvme_opal_revert)
2968
2969    def bdev_opal_create(args):
2970        print_json(rpc.bdev.bdev_opal_create(args.client,
2971                                             nvme_ctrlr_name=args.nvme_ctrlr_name,
2972                                             nsid=args.nsid,
2973                                             locking_range_id=args.locking_range_id,
2974                                             range_start=args.range_start,
2975                                             range_length=args.range_length,
2976                                             password=args.password))
2977
2978    p = subparsers.add_parser('bdev_opal_create', help="""Create opal bdev on specified NVMe controller""")
2979    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name', required=True)
2980    p.add_argument('-n', '--nsid', help='namespace ID (only support nsid=1 for now)', type=int, required=True)
2981    p.add_argument('-i', '--locking-range-id', help='locking range id', type=int, required=True)
2982    p.add_argument('-s', '--range-start', help='locking range start LBA', type=int, required=True)
2983    p.add_argument('-l', '--range-length', help='locking range length (in blocks)', type=int, required=True)
2984    p.add_argument('-p', '--password', help='admin password', required=True)
2985    p.set_defaults(func=bdev_opal_create)
2986
2987    def bdev_opal_get_info(args):
2988        print_dict(rpc.bdev.bdev_opal_get_info(args.client,
2989                                               bdev_name=args.bdev_name,
2990                                               password=args.password))
2991
2992    p = subparsers.add_parser('bdev_opal_get_info', help='get opal locking range info for this bdev')
2993    p.add_argument('-b', '--bdev-name', help='opal bdev')
2994    p.add_argument('-p', '--password', help='password')
2995    p.set_defaults(func=bdev_opal_get_info)
2996
2997    def bdev_opal_delete(args):
2998        rpc.bdev.bdev_opal_delete(args.client,
2999                                  bdev_name=args.bdev_name,
3000                                  password=args.password)
3001
3002    p = subparsers.add_parser('bdev_opal_delete', help="""delete a virtual opal bdev""")
3003    p.add_argument('-b', '--bdev-name', help='opal virtual bdev', required=True)
3004    p.add_argument('-p', '--password', help='admin password', required=True)
3005    p.set_defaults(func=bdev_opal_delete)
3006
3007    def bdev_opal_new_user(args):
3008        rpc.bdev.bdev_opal_new_user(args.client,
3009                                    bdev_name=args.bdev_name,
3010                                    admin_password=args.admin_password,
3011                                    user_id=args.user_id,
3012                                    user_password=args.user_password)
3013
3014    p = subparsers.add_parser('bdev_opal_new_user', help="""Add a user to opal bdev who can set lock state for this bdev""")
3015    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
3016    p.add_argument('-p', '--admin-password', help='admin password', required=True)
3017    p.add_argument('-i', '--user-id', help='ID for new user', type=int, required=True)
3018    p.add_argument('-u', '--user-password', help='password set for this user', required=True)
3019    p.set_defaults(func=bdev_opal_new_user)
3020
3021    def bdev_opal_set_lock_state(args):
3022        rpc.bdev.bdev_opal_set_lock_state(args.client,
3023                                          bdev_name=args.bdev_name,
3024                                          user_id=args.user_id,
3025                                          password=args.password,
3026                                          lock_state=args.lock_state)
3027
3028    p = subparsers.add_parser('bdev_opal_set_lock_state', help="""set lock state for an opal bdev""")
3029    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
3030    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',
3031                   type=int, required=True)
3032    p.add_argument('-p', '--password', help='password of this user', required=True)
3033    p.add_argument('-l', '--lock-state', help='lock state to set, choose from {readwrite, readonly, rwlock}', required=True)
3034    p.set_defaults(func=bdev_opal_set_lock_state)
3035
3036    # bdev_nvme_send_cmd
3037    def bdev_nvme_send_cmd(args):
3038        print_dict(rpc.nvme.bdev_nvme_send_cmd(args.client,
3039                                               name=args.nvme_name,
3040                                               cmd_type=args.cmd_type,
3041                                               data_direction=args.data_direction,
3042                                               cmdbuf=args.cmdbuf,
3043                                               data=args.data,
3044                                               metadata=args.metadata,
3045                                               data_len=args.data_length,
3046                                               metadata_len=args.metadata_length,
3047                                               timeout_ms=args.timeout_ms))
3048
3049    p = subparsers.add_parser('bdev_nvme_send_cmd', help='NVMe passthrough cmd.')
3050    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
3051    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
3052    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
3053    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
3054    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
3055    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
3056    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
3057    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
3058    p.add_argument('-T', '--timeout-ms',
3059                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int)
3060    p.set_defaults(func=bdev_nvme_send_cmd)
3061
3062    # Notifications
3063    def notify_get_types(args):
3064        print_dict(rpc.notify.notify_get_types(args.client))
3065
3066    p = subparsers.add_parser('notify_get_types', help='List available notifications that user can subscribe to.')
3067    p.set_defaults(func=notify_get_types)
3068
3069    def notify_get_notifications(args):
3070        ret = rpc.notify.notify_get_notifications(args.client,
3071                                                  id=args.id,
3072                                                  max=args.max)
3073        print_dict(ret)
3074
3075    p = subparsers.add_parser('notify_get_notifications', help='Get notifications')
3076    p.add_argument('-i', '--id', help="""First ID to start fetching from""", type=int)
3077    p.add_argument('-n', '--max', help="""Maximum number of notifications to return in response""", type=int)
3078    p.set_defaults(func=notify_get_notifications)
3079
3080    def thread_get_stats(args):
3081        print_dict(rpc.app.thread_get_stats(args.client))
3082
3083    p = subparsers.add_parser(
3084        'thread_get_stats', help='Display current statistics of all the threads')
3085    p.set_defaults(func=thread_get_stats)
3086
3087    def thread_set_cpumask(args):
3088        ret = rpc.app.thread_set_cpumask(args.client,
3089                                         id=args.id,
3090                                         cpumask=args.cpumask)
3091    p = subparsers.add_parser('thread_set_cpumask',
3092                              help="""set the cpumask of the thread whose ID matches to the
3093    specified value. The thread may be migrated to one of the specified CPUs.""")
3094    p.add_argument('-i', '--id', type=int, help='thread ID')
3095    p.add_argument('-m', '--cpumask', help='cpumask for this thread')
3096    p.set_defaults(func=thread_set_cpumask)
3097
3098    def log_enable_timestamps(args):
3099        ret = rpc.app.log_enable_timestamps(args.client,
3100                                            enabled=args.enabled)
3101    p = subparsers.add_parser('log_enable_timestamps',
3102                              help='Enable or disable timestamps.')
3103    p.add_argument('-d', '--disable', dest='enabled', default=False, action='store_false', help="Disable timestamps")
3104    p.add_argument('-e', '--enable', dest='enabled', action='store_true', help="Enable timestamps")
3105    p.set_defaults(func=log_enable_timestamps)
3106
3107    def thread_get_pollers(args):
3108        print_dict(rpc.app.thread_get_pollers(args.client))
3109
3110    p = subparsers.add_parser(
3111        'thread_get_pollers', help='Display current pollers of all the threads')
3112    p.set_defaults(func=thread_get_pollers)
3113
3114    def thread_get_io_channels(args):
3115        print_dict(rpc.app.thread_get_io_channels(args.client))
3116
3117    p = subparsers.add_parser(
3118        'thread_get_io_channels', help='Display current IO channels of all the threads')
3119    p.set_defaults(func=thread_get_io_channels)
3120
3121    def env_dpdk_get_mem_stats(args):
3122        print_dict(rpc.env_dpdk.env_dpdk_get_mem_stats(args.client))
3123
3124    p = subparsers.add_parser(
3125        'env_dpdk_get_mem_stats', help='write the dpdk memory stats to a file.')
3126    p.set_defaults(func=env_dpdk_get_mem_stats)
3127
3128    # blobfs
3129    def blobfs_detect(args):
3130        print(rpc.blobfs.blobfs_detect(args.client,
3131                                       bdev_name=args.bdev_name))
3132
3133    p = subparsers.add_parser('blobfs_detect', help='Detect whether a blobfs exists on bdev')
3134    p.add_argument('bdev_name', help='Blockdev name to detect blobfs. Example: Malloc0.')
3135    p.set_defaults(func=blobfs_detect)
3136
3137    def blobfs_create(args):
3138        print(rpc.blobfs.blobfs_create(args.client,
3139                                       bdev_name=args.bdev_name,
3140                                       cluster_sz=args.cluster_sz))
3141
3142    p = subparsers.add_parser('blobfs_create', help='Build a blobfs on bdev')
3143    p.add_argument('bdev_name', help='Blockdev name to build blobfs. Example: Malloc0.')
3144    p.add_argument('-c', '--cluster-sz',
3145                   help="""Size of cluster in bytes (Optional). Must be multiple of 4KB page size. Default and minimal value is 1M.""")
3146    p.set_defaults(func=blobfs_create)
3147
3148    def blobfs_mount(args):
3149        print(rpc.blobfs.blobfs_mount(args.client,
3150                                      bdev_name=args.bdev_name,
3151                                      mountpoint=args.mountpoint))
3152
3153    p = subparsers.add_parser('blobfs_mount', help='Mount a blobfs on bdev to host path by FUSE')
3154    p.add_argument('bdev_name', help='Blockdev name where the blobfs is. Example: Malloc0.')
3155    p.add_argument('mountpoint', help='Mountpoint path in host to mount blobfs. Example: /mnt/.')
3156    p.set_defaults(func=blobfs_mount)
3157
3158    def blobfs_set_cache_size(args):
3159        print(rpc.blobfs.blobfs_set_cache_size(args.client,
3160                                               size_in_mb=args.size_in_mb))
3161
3162    p = subparsers.add_parser('blobfs_set_cache_size', help='Set cache size for blobfs')
3163    p.add_argument('size_in_mb', help='Cache size for blobfs in megabytes.', type=int)
3164    p.set_defaults(func=blobfs_set_cache_size)
3165
3166    # sock
3167    def sock_impl_get_options(args):
3168        print_json(rpc.sock.sock_impl_get_options(args.client,
3169                                                  impl_name=args.impl))
3170
3171    p = subparsers.add_parser('sock_impl_get_options', help="""Get options of socket layer implementation""")
3172    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3173    p.set_defaults(func=sock_impl_get_options)
3174
3175    def sock_impl_set_options(args):
3176        rpc.sock.sock_impl_set_options(args.client,
3177                                       impl_name=args.impl,
3178                                       recv_buf_size=args.recv_buf_size,
3179                                       send_buf_size=args.send_buf_size,
3180                                       enable_recv_pipe=args.enable_recv_pipe,
3181                                       enable_quickack=args.enable_quickack,
3182                                       enable_placement_id=args.enable_placement_id,
3183                                       enable_zerocopy_send_server=args.enable_zerocopy_send_server,
3184                                       enable_zerocopy_send_client=args.enable_zerocopy_send_client,
3185                                       zerocopy_threshold=args.zerocopy_threshold,
3186                                       tls_version=args.tls_version,
3187                                       enable_ktls=args.enable_ktls,
3188                                       psk_key=args.psk_key,
3189                                       psk_identity=args.psk_identity)
3190
3191    p = subparsers.add_parser('sock_impl_set_options', help="""Set options of socket layer implementation""")
3192    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3193    p.add_argument('-r', '--recv-buf-size', help='Size of receive buffer on socket in bytes', type=int)
3194    p.add_argument('-s', '--send-buf-size', help='Size of send buffer on socket in bytes', type=int)
3195    p.add_argument('-p', '--enable-placement-id', help='Option for placement-id. 0:disable,1:incoming_napi,2:incoming_cpu', type=int)
3196    p.add_argument('--enable-recv-pipe', help='Enable receive pipe',
3197                   action='store_true', dest='enable_recv_pipe')
3198    p.add_argument('--disable-recv-pipe', help='Disable receive pipe',
3199                   action='store_false', dest='enable_recv_pipe')
3200    p.add_argument('--enable-quickack', help='Enable quick ACK',
3201                   action='store_true', dest='enable_quickack')
3202    p.add_argument('--disable-quickack', help='Disable quick ACK',
3203                   action='store_false', dest='enable_quickack')
3204    p.add_argument('--enable-zerocopy-send-server', help='Enable zerocopy on send for server sockets',
3205                   action='store_true', dest='enable_zerocopy_send_server')
3206    p.add_argument('--disable-zerocopy-send-server', help='Disable zerocopy on send for server sockets',
3207                   action='store_false', dest='enable_zerocopy_send_server')
3208    p.add_argument('--enable-zerocopy-send-client', help='Enable zerocopy on send for client sockets',
3209                   action='store_true', dest='enable_zerocopy_send_client')
3210    p.add_argument('--disable-zerocopy-send-client', help='Disable zerocopy on send for client sockets',
3211                   action='store_false', dest='enable_zerocopy_send_client')
3212    p.add_argument('--zerocopy-threshold', help='Set zerocopy_threshold in bytes', type=int)
3213    p.add_argument('--tls-version', help='TLS protocol version', type=int)
3214    p.add_argument('--enable-ktls', help='Enable Kernel TLS',
3215                   action='store_true', dest='enable_ktls')
3216    p.add_argument('--disable-ktls', help='Disable Kernel TLS',
3217                   action='store_false', dest='enable_ktls')
3218    p.add_argument('--psk-key', help='Set default PSK KEY', dest='psk_key')
3219    p.add_argument('--psk-identity', help='Set default PSK ID', dest='psk_identity')
3220    p.set_defaults(func=sock_impl_set_options, enable_recv_pipe=None, enable_quickack=None,
3221                   enable_placement_id=None, enable_zerocopy_send_server=None, enable_zerocopy_send_client=None,
3222                   zerocopy_threshold=None, tls_version=None, enable_ktls=None, psk_key=None, psk_identity=None)
3223
3224    def sock_set_default_impl(args):
3225        print_json(rpc.sock.sock_set_default_impl(args.client,
3226                                                  impl_name=args.impl))
3227
3228    p = subparsers.add_parser('sock_set_default_impl', help="""Set the default sock implementation""")
3229    p.add_argument('-i', '--impl', help='Socket implementation name, e.g. posix', required=True)
3230    p.set_defaults(func=sock_set_default_impl)
3231
3232    def framework_get_pci_devices(args):
3233        def splitbuf(buf, step):
3234            return [buf[i:i+step] for i in range(0, len(buf), step)]
3235
3236        devices = rpc.subsystem.framework_get_pci_devices(args.client)
3237        if not args.format_lspci:
3238            print_json(devices)
3239        else:
3240            for devid, dev in enumerate(devices):
3241                print('{} device #{}'.format(dev['address'], devid))
3242                for lineid, line in enumerate(splitbuf(dev['config_space'], 32)):
3243                    print('{:02x}: {}'.format(lineid * 16, ' '.join(splitbuf(line.lower(), 2))))
3244                print()
3245
3246    p = subparsers.add_parser('framework_get_pci_devices', help='''Get a list of attached PCI devices''')
3247    p.add_argument('--format-lspci', help='Format the output in a way to be consumed by lspci -F',
3248                   action='store_true')
3249    p.set_defaults(func=framework_get_pci_devices)
3250
3251    # bdev_nvme_add_error_injection
3252    def bdev_nvme_add_error_injection(args):
3253        print_dict(rpc.nvme.bdev_nvme_add_error_injection(args.client,
3254                                                          name=args.nvme_name,
3255                                                          cmd_type=args.cmd_type,
3256                                                          opc=args.opc,
3257                                                          do_not_submit=args.do_not_submit,
3258                                                          timeout_in_us=args.timeout_in_us,
3259                                                          err_count=args.err_count,
3260                                                          sct=args.sct,
3261                                                          sc=args.sc))
3262    p = subparsers.add_parser('bdev_nvme_add_error_injection',
3263                              help='Add a NVMe command error injection.')
3264    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""", required=True)
3265    p.add_argument('-t', '--cmd-type', help="""Type of NVMe command. Valid values are: admin, io""", required=True)
3266    p.add_argument('-o', '--opc', help="""Opcode of the NVMe command.""", required=True, type=int)
3267    p.add_argument('-s', '--do-not-submit',
3268                   help="""Set to true if request should not be submitted to the controller""",
3269                   dest="do_not_submit", action='store_true')
3270    p.add_argument('-w', '--timeout-in-us', help="""Wait specified microseconds when do_not_submit is true""", type=int)
3271    p.add_argument('-e', '--err-count', help="""Number of matching NVMe commands to inject errors""", type=int)
3272    p.add_argument('-u', '--sct', help="""Status code type""", type=int)
3273    p.add_argument('-c', '--sc', help="""Status code""", type=int)
3274    p.set_defaults(func=bdev_nvme_add_error_injection)
3275
3276    # bdev_nvme_remove_error_injection
3277    def bdev_nvme_remove_error_injection(args):
3278        print_dict(rpc.nvme.bdev_nvme_remove_error_injection(args.client,
3279                                                             name=args.nvme_name,
3280                                                             cmd_type=args.cmd_type,
3281                                                             opc=args.opc))
3282    p = subparsers.add_parser('bdev_nvme_remove_error_injection',
3283                              help='Removes a NVMe command error injection.')
3284    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""", required=True)
3285    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""", required=True)
3286    p.add_argument('-o', '--opc', help="""Opcode of the nvme cmd.""", required=True, type=int)
3287    p.set_defaults(func=bdev_nvme_remove_error_injection)
3288
3289    def bdev_daos_create(args):
3290        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
3291        print_json(rpc.bdev.bdev_daos_create(args.client,
3292                                             num_blocks=int(num_blocks),
3293                                             block_size=args.block_size,
3294                                             name=args.name,
3295                                             uuid=args.uuid,
3296                                             pool=args.pool,
3297                                             cont=args.cont,
3298                                             oclass=args.oclass))
3299    p = subparsers.add_parser('bdev_daos_create',
3300                              help='Create a bdev with DAOS backend')
3301    p.add_argument('name', help="Name of the bdev")
3302    p.add_argument('pool', help="UUID of the DAOS pool")
3303    p.add_argument('cont', help="UUID of the DAOS container")
3304    p.add_argument(
3305        'total_size', help='Size of DAOS bdev in MB (float > 0)', type=float)
3306    p.add_argument('block_size', help='Block size for this bdev', type=int)
3307    p.add_argument('-u', '--uuid', help="UUID of the bdev")
3308    p.add_argument('-o', '--oclass', help="DAOS object class")
3309    p.set_defaults(func=bdev_daos_create)
3310
3311    def bdev_daos_delete(args):
3312        rpc.bdev.bdev_daos_delete(args.client,
3313                                  name=args.name)
3314
3315    p = subparsers.add_parser('bdev_daos_delete',
3316                              help='Delete a DAOS disk')
3317    p.add_argument('name', help='DAOS bdev name')
3318    p.set_defaults(func=bdev_daos_delete)
3319
3320    def bdev_daos_resize(args):
3321        print_json(rpc.bdev.bdev_daos_resize(args.client,
3322                                             name=args.name,
3323                                             new_size=int(args.new_size)))
3324
3325    p = subparsers.add_parser('bdev_daos_resize',
3326                              help='Resize a DAOS bdev')
3327    p.add_argument('name', help='DAOS bdev name')
3328    p.add_argument('new_size', help='new bdev size for resize operation. The unit is MiB')
3329    p.set_defaults(func=bdev_daos_resize)
3330
3331    def iobuf_set_options(args):
3332        rpc.iobuf.iobuf_set_options(args.client,
3333                                    small_pool_count=args.small_pool_count,
3334                                    large_pool_count=args.large_pool_count,
3335                                    small_bufsize=args.small_bufsize,
3336                                    large_bufsize=args.large_bufsize)
3337    p = subparsers.add_parser('iobuf_set_options', help='Set iobuf pool options')
3338    p.add_argument('--small-pool-count', help='number of small buffers in the global pool', type=int)
3339    p.add_argument('--large-pool-count', help='number of large buffers in the global pool', type=int)
3340    p.add_argument('--small-bufsize', help='size of a small buffer', type=int)
3341    p.add_argument('--large-bufsize', help='size of a large buffer', type=int)
3342    p.set_defaults(func=iobuf_set_options)
3343
3344    def bdev_nvme_start_mdns_discovery(args):
3345        rpc.bdev.bdev_nvme_start_mdns_discovery(args.client,
3346                                                name=args.name,
3347                                                svcname=args.svcname,
3348                                                hostnqn=args.hostnqn)
3349
3350    p = subparsers.add_parser('bdev_nvme_start_mdns_discovery', help='Start mdns based automatic discovery')
3351    p.add_argument('-b', '--name', help="Name of the NVMe controller prefix for each bdev name", required=True)
3352    p.add_argument('-s', '--svcname', help='Service type to discover: e.g., _nvme-disc._tcp', required=True)
3353    p.add_argument('-q', '--hostnqn', help='NVMe-oF host subnqn')
3354    p.set_defaults(func=bdev_nvme_start_mdns_discovery)
3355
3356    def bdev_nvme_stop_mdns_discovery(args):
3357        rpc.bdev.bdev_nvme_stop_mdns_discovery(args.client, name=args.name)
3358
3359    p = subparsers.add_parser('bdev_nvme_stop_mdns_discovery', help='Stop automatic mdns discovery')
3360    p.add_argument('-b', '--name', help="Name of the service to stop", required=True)
3361    p.set_defaults(func=bdev_nvme_stop_mdns_discovery)
3362
3363    def bdev_nvme_get_mdns_discovery_info(args):
3364        print_dict(rpc.bdev.bdev_nvme_get_mdns_discovery_info(args.client))
3365
3366    p = subparsers.add_parser('bdev_nvme_get_mdns_discovery_info', help='Get information about the automatic mdns discovery')
3367    p.set_defaults(func=bdev_nvme_get_mdns_discovery_info)
3368
3369    def check_called_name(name):
3370        if name in deprecated_aliases:
3371            print("{} is deprecated, use {} instead.".format(name, deprecated_aliases[name]), file=sys.stderr)
3372
3373    class dry_run_client:
3374        def call(self, method, params=None):
3375            print("Request:\n" + json.dumps({"method": method, "params": params}, indent=2))
3376
3377    def null_print(arg):
3378        pass
3379
3380    def call_rpc_func(args):
3381        args.func(args)
3382        check_called_name(args.called_rpc_name)
3383
3384    def execute_script(parser, client, fd):
3385        executed_rpc = ""
3386        for rpc_call in map(str.rstrip, fd):
3387            if not rpc_call.strip():
3388                continue
3389            executed_rpc = "\n".join([executed_rpc, rpc_call])
3390            rpc_args = shlex.split(rpc_call)
3391            if rpc_args[0][0] == '#':
3392                # Ignore lines starting with # - treat them as comments
3393                continue
3394            args = parser.parse_args(rpc_args)
3395            args.client = client
3396            try:
3397                call_rpc_func(args)
3398            except JSONRPCException as ex:
3399                print("Exception:")
3400                print(executed_rpc.strip() + " <<<")
3401                print(ex.message)
3402                exit(1)
3403
3404    def load_plugin(args):
3405        # Create temporary parser, pull out the plugin parameter, load the module, and then run the real argument parser
3406        plugin_parser = argparse.ArgumentParser(add_help=False)
3407        plugin_parser.add_argument('--plugin', dest='rpc_plugin', help='Module name of plugin with additional RPC commands')
3408
3409        rpc_module = plugin_parser.parse_known_args()[0].rpc_plugin
3410        if args is not None:
3411            rpc_module = plugin_parser.parse_known_args(args)[0].rpc_plugin
3412
3413        if rpc_module in plugins:
3414            return
3415
3416        if rpc_module is not None:
3417            try:
3418                rpc_plugin = importlib.import_module(rpc_module)
3419                try:
3420                    rpc_plugin.spdk_rpc_plugin_initialize(subparsers)
3421                    plugins.append(rpc_module)
3422                except AttributeError:
3423                    print("Module %s does not contain 'spdk_rpc_plugin_initialize' function" % rpc_module)
3424            except ModuleNotFoundError:
3425                print("Module %s not found" % rpc_module)
3426
3427    def replace_arg_underscores(args):
3428        # All option names are defined with dashes only - for example: --tgt-name
3429        # But if user used underscores, convert them to dashes (--tgt_name => --tgt-name)
3430        # SPDK was inconsistent previously and had some options with underscores, so
3431        # doing this conversion ensures backward compatibility with older scripts.
3432        for i in range(len(args)):
3433            arg = args[i]
3434            if arg.startswith('--') and "_" in arg:
3435                opt, *vals = arg.split('=')
3436                args[i] = '='.join([opt.replace('_', '-'), *vals])
3437
3438    plugins = []
3439    load_plugin(None)
3440
3441    replace_arg_underscores(sys.argv)
3442
3443    args = parser.parse_args()
3444
3445    if sys.stdin.isatty() and not hasattr(args, 'func'):
3446        # No arguments and no data piped through stdin
3447        parser.print_help()
3448        exit(1)
3449    if args.is_server:
3450        for input in sys.stdin:
3451            cmd = shlex.split(input)
3452            replace_arg_underscores(cmd)
3453            try:
3454                load_plugin(cmd)
3455                tmp_args = parser.parse_args(cmd)
3456            except SystemExit as ex:
3457                print("**STATUS=1", flush=True)
3458                continue
3459
3460            try:
3461                tmp_args.client = rpc.client.JSONRPCClient(
3462                    tmp_args.server_addr, tmp_args.port, tmp_args.timeout,
3463                    log_level=getattr(logging, tmp_args.verbose.upper()), conn_retries=tmp_args.conn_retries)
3464                call_rpc_func(tmp_args)
3465                print("**STATUS=0", flush=True)
3466            except JSONRPCException as ex:
3467                print(ex.message)
3468                print("**STATUS=1", flush=True)
3469        exit(0)
3470    elif args.dry_run:
3471        args.client = dry_run_client()
3472        print_dict = null_print
3473        print_json = null_print
3474        print_array = null_print
3475    else:
3476        try:
3477            args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.timeout,
3478                                                   log_level=getattr(logging, args.verbose.upper()),
3479                                                   conn_retries=args.conn_retries)
3480        except JSONRPCException as ex:
3481            print(ex.message)
3482            exit(1)
3483
3484    if hasattr(args, 'func'):
3485        try:
3486            call_rpc_func(args)
3487        except JSONRPCException as ex:
3488            print(ex.message)
3489            exit(1)
3490    else:
3491        execute_script(parser, args.client, sys.stdin)
3492