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