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