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