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