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