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