xref: /spdk/scripts/rpc.py (revision 7d38f16674f1bc7071d08f4d4dad68fc3ffad965)
1#!/usr/bin/env python3
2
3from rpc.client import print_dict, JSONRPCException
4
5import argparse
6import rpc
7import sys
8
9try:
10    from shlex import quote
11except ImportError:
12    from pipes import quote
13
14
15def print_array(a):
16    print(" ".join((quote(v) for v in a)))
17
18
19if __name__ == "__main__":
20    parser = argparse.ArgumentParser(
21        description='SPDK RPC command line interface')
22    parser.add_argument('-s', dest='server_addr',
23                        help='RPC server address', default='/var/tmp/spdk.sock')
24    parser.add_argument('-p', dest='port',
25                        help='RPC port number (if server_addr is IP address)',
26                        default=5260, type=int)
27    parser.add_argument('-t', dest='timeout',
28                        help='Timout as a floating point number expressed in seconds waiting for reponse. Default: 60.0',
29                        default=60.0, type=float)
30    parser.add_argument('-v', dest='verbose',
31                        help='Verbose mode', action='store_true')
32    subparsers = parser.add_subparsers(help='RPC methods')
33
34    def start_subsystem_init(args):
35        rpc.start_subsystem_init(args.client)
36
37    p = subparsers.add_parser('start_subsystem_init', help='Start initialization of subsystems')
38    p.set_defaults(func=start_subsystem_init)
39
40    def wait_subsystem_init(args):
41        rpc.wait_subsystem_init(args.client)
42
43    p = subparsers.add_parser('wait_subsystem_init', help='Block until subsystems have been initialized')
44    p.set_defaults(func=wait_subsystem_init)
45
46    def get_rpc_methods(args):
47        print_dict(rpc.get_rpc_methods(args.client,
48                                       current=args.current))
49
50    p = subparsers.add_parser('get_rpc_methods', help='Get list of supported RPC methods')
51    p.add_argument('-c', '--current', help='Get list of RPC methods only callable in the current state.', action='store_true')
52    p.set_defaults(func=get_rpc_methods)
53
54    def save_config(args):
55        rpc.save_config(args.client,
56                        sys.stdout,
57                        indent=args.indent)
58
59    p = subparsers.add_parser('save_config', help="""Write current (live) configuration of SPDK subsystems and targets to stdout.
60    """)
61    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
62    """, type=int, default=2)
63    p.set_defaults(func=save_config)
64
65    def load_config(args):
66        rpc.load_config(args.client, sys.stdin)
67
68    p = subparsers.add_parser('load_config', help="""Configure SPDK subsystems and targets using JSON RPC read from stdin.""")
69    p.set_defaults(func=load_config)
70
71    def save_subsystem_config(args):
72        rpc.save_subsystem_config(args.client,
73                                  sys.stdout,
74                                  indent=args.indent,
75                                  name=args.name)
76
77    p = subparsers.add_parser('save_subsystem_config', help="""Write current (live) configuration of SPDK subsystem to stdout.
78    """)
79    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
80    """, type=int, default=2)
81    p.add_argument('-n', '--name', help='Name of subsystem', required=True)
82    p.set_defaults(func=save_subsystem_config)
83
84    def load_subsystem_config(args):
85        rpc.load_subsystem_config(args.client,
86                                  sys.stdin)
87
88    p = subparsers.add_parser('load_subsystem_config', help="""Configure SPDK subsystem using JSON RPC read from stdin.""")
89    p.set_defaults(func=load_subsystem_config)
90
91    # app
92    def kill_instance(args):
93        rpc.app.kill_instance(args.client,
94                              sig_name=args.sig_name)
95
96    p = subparsers.add_parser('kill_instance', help='Send signal to instance')
97    p.add_argument('sig_name', help='signal will be sent to server.')
98    p.set_defaults(func=kill_instance)
99
100    def context_switch_monitor(args):
101        enabled = None
102        if args.enable:
103            enabled = True
104        if args.disable:
105            enabled = False
106        print_dict(rpc.app.context_switch_monitor(args.client,
107                                                  enabled=enabled))
108
109    p = subparsers.add_parser('context_switch_monitor', help='Control whether the context switch monitor is enabled')
110    p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring')
111    p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring')
112    p.set_defaults(func=context_switch_monitor)
113
114    # bdev
115    def set_bdev_options(args):
116        rpc.bdev.set_bdev_options(args.client,
117                                  bdev_io_pool_size=args.bdev_io_pool_size,
118                                  bdev_io_cache_size=args.bdev_io_cache_size)
119
120    p = subparsers.add_parser('set_bdev_options', help="""Set options of bdev subsystem""")
121    p.add_argument('-p', '--bdev-io-pool-size', help='Number of bdev_io structures in shared buffer pool', type=int)
122    p.add_argument('-c', '--bdev-io-cache-size', help='Maximum number of bdev_io structures cached per thread', type=int)
123    p.set_defaults(func=set_bdev_options)
124
125    def construct_crypto_bdev(args):
126        print(rpc.bdev.construct_crypto_bdev(args.client,
127                                             base_bdev_name=args.base_bdev_name,
128                                             name=args.name,
129                                             crypto_pmd=args.crypto_pmd,
130                                             key=args.key))
131    p = subparsers.add_parser('construct_crypto_bdev',
132                              help='Add a crypto vbdev')
133    p.add_argument('-b', '--base_bdev_name', help="Name of the base bdev")
134    p.add_argument('-c', '--name', help="Name of the crypto vbdev")
135    p.add_argument('-d', '--crypto_pmd', help="Name of the crypto device driver")
136    p.add_argument('-k', '--key', help="Key")
137    p.set_defaults(func=construct_crypto_bdev)
138
139    def delete_crypto_bdev(args):
140        rpc.bdev.delete_crypto_bdev(args.client,
141                                    name=args.name)
142
143    p = subparsers.add_parser('delete_crypto_bdev', help='Delete a crypto disk')
144    p.add_argument('name', help='crypto bdev name')
145    p.set_defaults(func=delete_crypto_bdev)
146
147    def construct_malloc_bdev(args):
148        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
149        print(rpc.bdev.construct_malloc_bdev(args.client,
150                                             num_blocks=int(num_blocks),
151                                             block_size=args.block_size,
152                                             name=args.name,
153                                             uuid=args.uuid))
154    p = subparsers.add_parser('construct_malloc_bdev',
155                              help='Add a bdev with malloc backend')
156    p.add_argument('-b', '--name', help="Name of the bdev")
157    p.add_argument('-u', '--uuid', help="UUID of the bdev")
158    p.add_argument(
159        'total_size', help='Size of malloc bdev in MB (float > 0)', type=float)
160    p.add_argument('block_size', help='Block size for this bdev', type=int)
161    p.set_defaults(func=construct_malloc_bdev)
162
163    def delete_malloc_bdev(args):
164        rpc.bdev.delete_malloc_bdev(args.client,
165                                    name=args.name)
166
167    p = subparsers.add_parser('delete_malloc_bdev', help='Delete a malloc disk')
168    p.add_argument('name', help='malloc bdev name')
169    p.set_defaults(func=delete_malloc_bdev)
170
171    def construct_null_bdev(args):
172        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
173        print(rpc.bdev.construct_null_bdev(args.client,
174                                           num_blocks=num_blocks,
175                                           block_size=args.block_size,
176                                           name=args.name,
177                                           uuid=args.uuid))
178
179    p = subparsers.add_parser('construct_null_bdev',
180                              help='Add a bdev with null backend')
181    p.add_argument('name', help='Block device name')
182    p.add_argument('-u', '--uuid', help='UUID of the bdev')
183    p.add_argument(
184        'total_size', help='Size of null bdev in MB (int > 0)', type=int)
185    p.add_argument('block_size', help='Block size for this bdev', type=int)
186    p.set_defaults(func=construct_null_bdev)
187
188    def delete_null_bdev(args):
189        rpc.bdev.delete_null_bdev(args.client,
190                                  name=args.name)
191
192    p = subparsers.add_parser('delete_null_bdev', help='Delete a null bdev')
193    p.add_argument('name', help='null bdev name')
194    p.set_defaults(func=delete_null_bdev)
195
196    def construct_aio_bdev(args):
197        print(rpc.bdev.construct_aio_bdev(args.client,
198                                          filename=args.filename,
199                                          name=args.name,
200                                          block_size=args.block_size))
201
202    p = subparsers.add_parser('construct_aio_bdev',
203                              help='Add a bdev with aio backend')
204    p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
205    p.add_argument('name', help='Block device name')
206    p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?', default=0)
207    p.set_defaults(func=construct_aio_bdev)
208
209    def delete_aio_bdev(args):
210        rpc.bdev.delete_aio_bdev(args.client,
211                                 name=args.name)
212
213    p = subparsers.add_parser('delete_aio_bdev', help='Delete an aio disk')
214    p.add_argument('name', help='aio bdev name')
215    p.set_defaults(func=delete_aio_bdev)
216
217    def set_bdev_nvme_options(args):
218        rpc.bdev.set_bdev_nvme_options(args.client,
219                                       action_on_timeout=args.action_on_timeout,
220                                       timeout_us=args.timeout_us,
221                                       retry_count=args.retry_count,
222                                       nvme_adminq_poll_period_us=args.nvme_adminq_poll_period_us)
223
224    p = subparsers.add_parser('set_bdev_nvme_options',
225                              help='Set options for the bdev nvme type. This is startup command.')
226    p.add_argument('-a', '--action-on-timeout',
227                   help="Action to take on command time out. Valid valies are: none, reset, abort")
228    p.add_argument('-t', '--timeout-us',
229                   help="Timeout for each command, in microseconds. If 0, don't track timeouts.", type=int)
230    p.add_argument('-n', '--retry-count',
231                   help='the number of attempts per I/O when an I/O fails', type=int)
232    p.add_argument('-p', '--nvme-adminq-poll-period-us',
233                   help='How often the admin queue is polled for asynchronous events', type=int)
234    p.set_defaults(func=set_bdev_nvme_options)
235
236    def set_bdev_nvme_hotplug(args):
237        rpc.bdev.set_bdev_nvme_hotplug(args.client, enable=args.enable, period_us=args.period_us)
238
239    p = subparsers.add_parser('set_bdev_nvme_hotplug',
240                              help='Set hotplug options for bdev nvme type.')
241    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
242    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
243    p.add_argument('-r', '--period-us',
244                   help='How often the hotplug is processed for insert and remove events', type=int)
245    p.set_defaults(func=set_bdev_nvme_hotplug)
246
247    def construct_nvme_bdev(args):
248        print_array(rpc.bdev.construct_nvme_bdev(args.client,
249                                                 name=args.name,
250                                                 trtype=args.trtype,
251                                                 traddr=args.traddr,
252                                                 adrfam=args.adrfam,
253                                                 trsvcid=args.trsvcid,
254                                                 subnqn=args.subnqn))
255
256    p = subparsers.add_parser('construct_nvme_bdev',
257                              help='Add bdevs with nvme backend')
258    p.add_argument('-b', '--name', help="Name of the NVMe controller, prefix for each bdev name", required=True)
259    p.add_argument('-t', '--trtype',
260                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
261    p.add_argument('-a', '--traddr',
262                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
263    p.add_argument('-f', '--adrfam',
264                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
265    p.add_argument('-s', '--trsvcid',
266                   help='NVMe-oF target trsvcid: e.g., a port number')
267    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
268    p.set_defaults(func=construct_nvme_bdev)
269
270    def get_nvme_controllers(args):
271        print_dict(rpc.nvme.get_nvme_controllers(args.client,
272                                                 name=args.name))
273
274    p = subparsers.add_parser(
275        'get_nvme_controllers', help='Display current NVMe controllers list or required NVMe controller')
276    p.add_argument('-n', '--name', help="Name of the NVMe controller. Example: Nvme0", required=False)
277    p.set_defaults(func=get_nvme_controllers)
278
279    def delete_nvme_controller(args):
280        rpc.bdev.delete_nvme_controller(args.client,
281                                        name=args.name)
282
283    p = subparsers.add_parser('delete_nvme_controller',
284                              help='Delete a NVMe controller using controller name')
285    p.add_argument('name', help="Name of the controller")
286    p.set_defaults(func=delete_nvme_controller)
287
288    def construct_rbd_bdev(args):
289        config = None
290        if args.config:
291            config = {}
292            for entry in args.config:
293                parts = entry.split('=', 1)
294                if len(parts) != 2:
295                    raise Exception('--config %s not in key=value form' % entry)
296                config[parts[0]] = parts[1]
297        print(rpc.bdev.construct_rbd_bdev(args.client,
298                                          name=args.name,
299                                          user=args.user,
300                                          config=config,
301                                          pool_name=args.pool_name,
302                                          rbd_name=args.rbd_name,
303                                          block_size=args.block_size))
304
305    p = subparsers.add_parser('construct_rbd_bdev',
306                              help='Add a bdev with ceph rbd backend')
307    p.add_argument('-b', '--name', help="Name of the bdev", required=False)
308    p.add_argument('--user', help="Ceph user name (i.e. admin, not client.admin)", required=False)
309    p.add_argument('--config', action='append', metavar='key=value',
310                   help="adds a key=value configuration option for rados_conf_set (default: rely on config file)")
311    p.add_argument('pool_name', help='rbd pool name')
312    p.add_argument('rbd_name', help='rbd image name')
313    p.add_argument('block_size', help='rbd block size', type=int)
314    p.set_defaults(func=construct_rbd_bdev)
315
316    def delete_rbd_bdev(args):
317        rpc.bdev.delete_rbd_bdev(args.client,
318                                 name=args.name)
319
320    p = subparsers.add_parser('delete_rbd_bdev', help='Delete a rbd bdev')
321    p.add_argument('name', help='rbd bdev name')
322    p.set_defaults(func=delete_rbd_bdev)
323
324    def construct_error_bdev(args):
325        print(rpc.bdev.construct_error_bdev(args.client,
326                                            base_name=args.base_name))
327
328    p = subparsers.add_parser('construct_error_bdev',
329                              help='Add bdev with error injection backend')
330    p.add_argument('base_name', help='base bdev name')
331    p.set_defaults(func=construct_error_bdev)
332
333    def delete_error_bdev(args):
334        rpc.bdev.delete_error_bdev(args.client,
335                                   name=args.name)
336
337    p = subparsers.add_parser('delete_error_bdev', help='Delete an error bdev')
338    p.add_argument('name', help='error bdev name')
339    p.set_defaults(func=delete_error_bdev)
340
341    def construct_iscsi_bdev(args):
342        print(rpc.bdev.construct_iscsi_bdev(args.client,
343                                            name=args.name,
344                                            url=args.url,
345                                            initiator_iqn=args.initiator_iqn))
346
347    p = subparsers.add_parser('construct_iscsi_bdev',
348                              help='Add bdev with iSCSI initiator backend')
349    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
350    p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True)
351    p.add_argument('--url', help="iSCSI Lun URL", required=True)
352    p.set_defaults(func=construct_iscsi_bdev)
353
354    def delete_iscsi_bdev(args):
355        rpc.bdev.delete_iscsi_bdev(args.client,
356                                   name=args.name)
357
358    p = subparsers.add_parser('delete_iscsi_bdev', help='Delete an iSCSI bdev')
359    p.add_argument('name', help='iSCSI bdev name')
360    p.set_defaults(func=delete_iscsi_bdev)
361
362    def construct_pmem_bdev(args):
363        print(rpc.bdev.construct_pmem_bdev(args.client,
364                                           pmem_file=args.pmem_file,
365                                           name=args.name))
366
367    p = subparsers.add_parser('construct_pmem_bdev', help='Add a bdev with pmem backend')
368    p.add_argument('pmem_file', help='Path to pmemblk pool file')
369    p.add_argument('-n', '--name', help='Block device name', required=True)
370    p.set_defaults(func=construct_pmem_bdev)
371
372    def delete_pmem_bdev(args):
373        rpc.bdev.delete_pmem_bdev(args.client,
374                                  name=args.name)
375
376    p = subparsers.add_parser('delete_pmem_bdev', help='Delete a pmem bdev')
377    p.add_argument('name', help='pmem bdev name')
378    p.set_defaults(func=delete_pmem_bdev)
379
380    def construct_passthru_bdev(args):
381        print(rpc.bdev.construct_passthru_bdev(args.client,
382                                               base_bdev_name=args.base_bdev_name,
383                                               name=args.name))
384
385    p = subparsers.add_parser('construct_passthru_bdev',
386                              help='Add a pass through bdev on existing bdev')
387    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
388    p.add_argument('-p', '--name', help="Name of the pass through bdev", required=True)
389    p.set_defaults(func=construct_passthru_bdev)
390
391    def delete_passthru_bdev(args):
392        rpc.bdev.delete_passthru_bdev(args.client,
393                                      name=args.name)
394
395    p = subparsers.add_parser('delete_passthru_bdev', help='Delete a pass through bdev')
396    p.add_argument('name', help='pass through bdev name')
397    p.set_defaults(func=delete_passthru_bdev)
398
399    def get_bdevs(args):
400        print_dict(rpc.bdev.get_bdevs(args.client,
401                                      name=args.name))
402
403    p = subparsers.add_parser(
404        'get_bdevs', help='Display current blockdev list or required blockdev')
405    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
406    p.set_defaults(func=get_bdevs)
407
408    def get_bdevs_iostat(args):
409        print_dict(rpc.bdev.get_bdevs_iostat(args.client,
410                                             name=args.name))
411
412    p = subparsers.add_parser(
413        'get_bdevs_iostat', help='Display current I/O statistics of all the blockdevs or required blockdev.')
414    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
415    p.set_defaults(func=get_bdevs_iostat)
416
417    def delete_bdev(args):
418        rpc.bdev.delete_bdev(args.client,
419                             bdev_name=args.bdev_name)
420
421    p = subparsers.add_parser('delete_bdev', help='Delete a blockdev')
422    p.add_argument(
423        'bdev_name', help='Blockdev name to be deleted. Example: Malloc0.')
424    p.set_defaults(func=delete_bdev)
425
426    def set_bdev_qd_sampling_period(args):
427        rpc.bdev.set_bdev_qd_sampling_period(args.client,
428                                             name=args.name,
429                                             period=args.period)
430
431    p = subparsers.add_parser('set_bdev_qd_sampling_period', help="Enable or disable tracking of a bdev's queue depth.")
432    p.add_argument('name', help='Blockdev name. Example: Malloc0')
433    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
434                   ' If set to 0, polling will be disabled.',
435                   type=int)
436    p.set_defaults(func=set_bdev_qd_sampling_period)
437
438    def set_bdev_qos_limit(args):
439        rpc.bdev.set_bdev_qos_limit(args.client,
440                                    name=args.name,
441                                    rw_ios_per_sec=args.rw_ios_per_sec,
442                                    rw_mbytes_per_sec=args.rw_mbytes_per_sec)
443
444    p = subparsers.add_parser('set_bdev_qos_limit', help='Set QoS rate limit on a blockdev')
445    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
446    p.add_argument('--rw_ios_per_sec',
447                   help='R/W IOs per second limit (>=10000, example: 20000). 0 means unlimited.',
448                   type=int, required=False)
449    p.add_argument('--rw_mbytes_per_sec',
450                   help="R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.",
451                   type=int, required=False)
452    p.set_defaults(func=set_bdev_qos_limit)
453
454    def bdev_inject_error(args):
455        rpc.bdev.bdev_inject_error(args.client,
456                                   name=args.name,
457                                   io_type=args.io_type,
458                                   error_type=args.error_type,
459                                   num=args.num)
460
461    p = subparsers.add_parser('bdev_inject_error', help='bdev inject error')
462    p.add_argument('name', help="""the name of the error injection bdev""")
463    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
464    p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
465    p.add_argument(
466        '-n', '--num', help='the number of commands you want to fail', type=int, default=1)
467    p.set_defaults(func=bdev_inject_error)
468
469    def apply_firmware(args):
470        print_dict(rpc.bdev.apply_firmware(args.client,
471                                           bdev_name=args.bdev_name,
472                                           filename=args.filename))
473
474    p = subparsers.add_parser('apply_firmware', help='Download and commit firmware to NVMe device')
475    p.add_argument('filename', help='filename of the firmware to download')
476    p.add_argument('bdev_name', help='name of the NVMe device')
477    p.set_defaults(func=apply_firmware)
478
479    # iSCSI
480    def set_iscsi_options(args):
481        rpc.iscsi.set_iscsi_options(
482            args.client,
483            auth_file=args.auth_file,
484            node_base=args.node_base,
485            nop_timeout=args.nop_timeout,
486            nop_in_interval=args.nop_in_interval,
487            disable_chap=args.disable_chap,
488            require_chap=args.require_chap,
489            mutual_chap=args.mutual_chap,
490            chap_group=args.chap_group,
491            max_sessions=args.max_sessions,
492            max_queue_depth=args.max_queue_depth,
493            max_connections_per_session=args.max_connections_per_session,
494            default_time2wait=args.default_time2wait,
495            default_time2retain=args.default_time2retain,
496            first_burst_length=args.first_burst_length,
497            immediate_data=args.immediate_data,
498            error_recovery_level=args.error_recovery_level,
499            allow_duplicated_isid=args.allow_duplicated_isid,
500            min_connections_per_core=args.min_connections_per_core)
501
502    p = subparsers.add_parser('set_iscsi_options', help="""Set options of iSCSI subsystem""")
503    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file')
504    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
505    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
506    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
507    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
508    *** Mutually exclusive with --require-chap""", action='store_true')
509    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
510    *** Mutually exclusive with --disable-chap""", action='store_true')
511    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
512    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
513    *** Authentication group must be precreated ***""", type=int)
514    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
515    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int)
516    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
517    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
518    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
519    p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int)
520    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
521    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
522    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
523    p.add_argument('-u', '--min-connections-per-core', help='Allocation unit of connections per core', type=int)
524    p.set_defaults(func=set_iscsi_options)
525
526    def set_iscsi_discovery_auth(args):
527        rpc.iscsi.set_iscsi_discovery_auth(
528            args.client,
529            disable_chap=args.disable_chap,
530            require_chap=args.require_chap,
531            mutual_chap=args.mutual_chap,
532            chap_group=args.chap_group)
533
534    p = subparsers.add_parser('set_iscsi_discovery_auth', help="""Set CHAP authentication for discovery session.""")
535    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
536    *** Mutually exclusive with --require-chap""", action='store_true')
537    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
538    *** Mutually exclusive with --disable-chap""", action='store_true')
539    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
540    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
541    *** Authentication group must be precreated ***""", type=int)
542    p.set_defaults(func=set_iscsi_discovery_auth)
543
544    def add_iscsi_auth_group(args):
545        secrets = None
546        if args.secrets:
547            secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")]
548
549        rpc.iscsi.add_iscsi_auth_group(args.client, tag=args.tag, secrets=secrets)
550
551    p = subparsers.add_parser('add_iscsi_auth_group', help='Add authentication group for CHAP authentication.')
552    p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int)
553    p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets
554<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes.
555Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False)
556    p.set_defaults(func=add_iscsi_auth_group)
557
558    def delete_iscsi_auth_group(args):
559        rpc.iscsi.delete_iscsi_auth_group(args.client, tag=args.tag)
560
561    p = subparsers.add_parser('delete_iscsi_auth_group', help='Delete an authentication group.')
562    p.add_argument('tag', help='Authentication group tag', type=int)
563    p.set_defaults(func=delete_iscsi_auth_group)
564
565    def add_secret_to_iscsi_auth_group(args):
566        rpc.iscsi.add_secret_to_iscsi_auth_group(
567            args.client,
568            tag=args.tag,
569            user=args.user,
570            secret=args.secret,
571            muser=args.muser,
572            msecret=args.msecret)
573
574    p = subparsers.add_parser('add_secret_to_iscsi_auth_group', help='Add a secret to an authentication group.')
575    p.add_argument('tag', help='Authentication group tag', type=int)
576    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
577    p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True)
578    p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication')
579    p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication')
580    p.set_defaults(func=add_secret_to_iscsi_auth_group)
581
582    def delete_secret_from_iscsi_auth_group(args):
583        rpc.iscsi.delete_secret_from_iscsi_auth_group(args.client, tag=args.tag, user=args.user)
584
585    p = subparsers.add_parser('delete_secret_from_iscsi_auth_group', help='Delete a secret from an authentication group.')
586    p.add_argument('tag', help='Authentication group tag', type=int)
587    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
588    p.set_defaults(func=delete_secret_from_iscsi_auth_group)
589
590    def get_iscsi_auth_groups(args):
591        print_dict(rpc.iscsi.get_iscsi_auth_groups(args.client))
592
593    p = subparsers.add_parser('get_iscsi_auth_groups',
594                              help='Display current authentication group configuration')
595    p.set_defaults(func=get_iscsi_auth_groups)
596
597    def get_portal_groups(args):
598        print_dict(rpc.iscsi.get_portal_groups(args.client))
599
600    p = subparsers.add_parser(
601        'get_portal_groups', help='Display current portal group configuration')
602    p.set_defaults(func=get_portal_groups)
603
604    def get_initiator_groups(args):
605        print_dict(rpc.iscsi.get_initiator_groups(args.client))
606
607    p = subparsers.add_parser('get_initiator_groups',
608                              help='Display current initiator group configuration')
609    p.set_defaults(func=get_initiator_groups)
610
611    def get_target_nodes(args):
612        print_dict(rpc.iscsi.get_target_nodes(args.client))
613
614    p = subparsers.add_parser('get_target_nodes', help='Display target nodes')
615    p.set_defaults(func=get_target_nodes)
616
617    def construct_target_node(args):
618        luns = []
619        for u in args.bdev_name_id_pairs.strip().split(" "):
620            bdev_name, lun_id = u.split(":")
621            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
622
623        pg_ig_maps = []
624        for u in args.pg_ig_mappings.strip().split(" "):
625            pg, ig = u.split(":")
626            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
627
628        rpc.iscsi.construct_target_node(
629            args.client,
630            luns=luns,
631            pg_ig_maps=pg_ig_maps,
632            name=args.name,
633            alias_name=args.alias_name,
634            queue_depth=args.queue_depth,
635            chap_group=args.chap_group,
636            disable_chap=args.disable_chap,
637            require_chap=args.require_chap,
638            mutual_chap=args.mutual_chap,
639            header_digest=args.header_digest,
640            data_digest=args.data_digest)
641
642    p = subparsers.add_parser('construct_target_node',
643                              help='Add a target node')
644    p.add_argument('name', help='Target node name (ASCII)')
645    p.add_argument('alias_name', help='Target node alias name (ASCII)')
646    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
647    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
648    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
649    *** The bdevs must pre-exist ***
650    *** LUN0 (id = 0) is required ***
651    *** bdevs names cannot contain space or colon characters ***""")
652    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
653    Whitespace separated, quoted, mapping defined with colon
654    separated list of "tags" (int > 0)
655    Example: '1:1 2:2 2:1'
656    *** The Portal/Initiator Groups must be precreated ***""")
657    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
658    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
659    *** Authentication group must be precreated ***""", type=int, default=0)
660    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
661    *** Mutually exclusive with --require-chap ***""", action='store_true')
662    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
663    *** Mutually exclusive with --disable-chap ***""", action='store_true')
664    p.add_argument(
665        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
666    p.add_argument('-H', '--header-digest',
667                   help='Header Digest should be required for this target node.', action='store_true')
668    p.add_argument('-D', '--data-digest',
669                   help='Data Digest should be required for this target node.', action='store_true')
670    p.set_defaults(func=construct_target_node)
671
672    def target_node_add_lun(args):
673        rpc.iscsi.target_node_add_lun(
674            args.client,
675            name=args.name,
676            bdev_name=args.bdev_name,
677            lun_id=args.lun_id)
678
679    p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node')
680    p.add_argument('name', help='Target node name (ASCII)')
681    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
682    *** bdev name cannot contain space or colon characters ***""")
683    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
684    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
685    p.set_defaults(func=target_node_add_lun)
686
687    def set_iscsi_target_node_auth(args):
688        rpc.iscsi.set_iscsi_target_node_auth(
689            args.client,
690            name=args.name,
691            chap_group=args.chap_group,
692            disable_chap=args.disable_chap,
693            require_chap=args.require_chap,
694            mutual_chap=args.mutual_chap)
695
696    p = subparsers.add_parser('set_iscsi_target_node_auth', help='Set CHAP authentication for the target node')
697    p.add_argument('name', help='Target node name (ASCII)')
698    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
699    *** Authentication group must be precreated ***""", type=int, default=0)
700    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
701    *** Mutually exclusive with --require-chap ***""", action='store_true')
702    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
703    *** Mutually exclusive with --disable-chap ***""", action='store_true')
704    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
705                   action='store_true')
706    p.set_defaults(func=set_iscsi_target_node_auth)
707
708    def add_pg_ig_maps(args):
709        pg_ig_maps = []
710        for u in args.pg_ig_mappings.strip().split(" "):
711            pg, ig = u.split(":")
712            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
713        rpc.iscsi.add_pg_ig_maps(
714            args.client,
715            pg_ig_maps=pg_ig_maps,
716            name=args.name)
717
718    p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node')
719    p.add_argument('name', help='Target node name (ASCII)')
720    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
721    Whitespace separated, quoted, mapping defined with colon
722    separated list of "tags" (int > 0)
723    Example: '1:1 2:2 2:1'
724    *** The Portal/Initiator Groups must be precreated ***""")
725    p.set_defaults(func=add_pg_ig_maps)
726
727    def delete_pg_ig_maps(args):
728        pg_ig_maps = []
729        for u in args.pg_ig_mappings.strip().split(" "):
730            pg, ig = u.split(":")
731            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
732        rpc.iscsi.delete_pg_ig_maps(
733            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
734
735    p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node')
736    p.add_argument('name', help='Target node name (ASCII)')
737    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
738    Whitespace separated, quoted, mapping defined with colon
739    separated list of "tags" (int > 0)
740    Example: '1:1 2:2 2:1'
741    *** The Portal/Initiator Groups must be precreated ***""")
742    p.set_defaults(func=delete_pg_ig_maps)
743
744    def add_portal_group(args):
745        portals = []
746        for p in args.portal_list:
747            ip, separator, port_cpumask = p.rpartition(':')
748            split_port_cpumask = port_cpumask.split('@')
749            if len(split_port_cpumask) == 1:
750                port = port_cpumask
751                portals.append({'host': ip, 'port': port})
752            else:
753                port = split_port_cpumask[0]
754                cpumask = split_port_cpumask[1]
755                portals.append({'host': ip, 'port': port, 'cpumask': cpumask})
756        rpc.iscsi.add_portal_group(
757            args.client,
758            portals=portals,
759            tag=args.tag)
760
761    p = subparsers.add_parser('add_portal_group', help='Add a portal group')
762    p.add_argument(
763        'tag', help='Portal group tag (unique, integer > 0)', type=int)
764    p.add_argument('portal_list', nargs=argparse.REMAINDER, help="""List of portals in 'host:port@cpumask' format, separated by whitespace
765    (cpumask is optional and can be skipped)
766    Example: '192.168.100.100:3260' '192.168.100.100:3261' '192.168.100.100:3262@0x1""")
767    p.set_defaults(func=add_portal_group)
768
769    def add_initiator_group(args):
770        initiators = []
771        netmasks = []
772        for i in args.initiator_list.strip().split(' '):
773            initiators.append(i)
774        for n in args.netmask_list.strip().split(' '):
775            netmasks.append(n)
776        rpc.iscsi.add_initiator_group(
777            args.client,
778            tag=args.tag,
779            initiators=initiators,
780            netmasks=netmasks)
781
782    p = subparsers.add_parser('add_initiator_group',
783                              help='Add an initiator group')
784    p.add_argument(
785        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
786    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
787    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
788    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
789    Example: '255.255.0.0 255.248.0.0' etc""")
790    p.set_defaults(func=add_initiator_group)
791
792    def add_initiators_to_initiator_group(args):
793        initiators = None
794        netmasks = None
795        if args.initiator_list:
796            initiators = []
797            for i in args.initiator_list.strip().split(' '):
798                initiators.append(i)
799        if args.netmask_list:
800            netmasks = []
801            for n in args.netmask_list.strip().split(' '):
802                netmasks.append(n)
803        rpc.iscsi.add_initiators_to_initiator_group(
804            args.client,
805            tag=args.tag,
806            initiators=initiators,
807            netmasks=netmasks)
808
809    p = subparsers.add_parser('add_initiators_to_initiator_group',
810                              help='Add initiators to an existing initiator group')
811    p.add_argument(
812        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
813    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
814    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
815    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
816    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
817    p.set_defaults(func=add_initiators_to_initiator_group)
818
819    def delete_initiators_from_initiator_group(args):
820        initiators = None
821        netmasks = None
822        if args.initiator_list:
823            initiators = []
824            for i in args.initiator_list.strip().split(' '):
825                initiators.append(i)
826        if args.netmask_list:
827            netmasks = []
828            for n in args.netmask_list.strip().split(' '):
829                netmasks.append(n)
830        rpc.iscsi.delete_initiators_from_initiator_group(
831            args.client,
832            tag=args.tag,
833            initiators=initiators,
834            netmasks=netmasks)
835
836    p = subparsers.add_parser('delete_initiators_from_initiator_group',
837                              help='Delete initiators from an existing initiator group')
838    p.add_argument(
839        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
840    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
841    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
842    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
843    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
844    p.set_defaults(func=delete_initiators_from_initiator_group)
845
846    def delete_target_node(args):
847        rpc.iscsi.delete_target_node(
848            args.client, target_node_name=args.target_node_name)
849
850    p = subparsers.add_parser('delete_target_node',
851                              help='Delete a target node')
852    p.add_argument('target_node_name',
853                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
854    p.set_defaults(func=delete_target_node)
855
856    def delete_portal_group(args):
857        rpc.iscsi.delete_portal_group(args.client, tag=args.tag)
858
859    p = subparsers.add_parser('delete_portal_group',
860                              help='Delete a portal group')
861    p.add_argument(
862        'tag', help='Portal group tag (unique, integer > 0)', type=int)
863    p.set_defaults(func=delete_portal_group)
864
865    def delete_initiator_group(args):
866        rpc.iscsi.delete_initiator_group(args.client, tag=args.tag)
867
868    p = subparsers.add_parser('delete_initiator_group',
869                              help='Delete an initiator group')
870    p.add_argument(
871        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
872    p.set_defaults(func=delete_initiator_group)
873
874    def get_iscsi_connections(args):
875        print_dict(rpc.iscsi.get_iscsi_connections(args.client))
876
877    p = subparsers.add_parser('get_iscsi_connections',
878                              help='Display iSCSI connections')
879    p.set_defaults(func=get_iscsi_connections)
880
881    def get_iscsi_global_params(args):
882        print_dict(rpc.iscsi.get_iscsi_global_params(args.client))
883
884    p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters')
885    p.set_defaults(func=get_iscsi_global_params)
886
887    def get_scsi_devices(args):
888        print_dict(rpc.iscsi.get_scsi_devices(args.client))
889
890    p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices')
891    p.set_defaults(func=get_scsi_devices)
892
893    # log
894    def set_log_flag(args):
895        rpc.log.set_log_flag(args.client, flag=args.flag)
896
897    p = subparsers.add_parser('set_log_flag', help='set log flag')
898    p.add_argument(
899        'flag', help='log flag we want to set. (for example "nvme").')
900    p.set_defaults(func=set_log_flag)
901
902    def set_trace_flag(args):
903        print("set_trace_flag is deprecated - use set_log_flag instead")
904        rpc.log.set_trace_flag(args.client, flag=args.flag)
905
906    p = subparsers.add_parser('set_trace_flag', help='set trace flag')
907    p.add_argument(
908        'flag', help='trace mask we want to set. (for example "nvme").')
909    p.set_defaults(func=set_trace_flag)
910
911    def clear_log_flag(args):
912        rpc.log.clear_log_flag(args.client, flag=args.flag)
913
914    p = subparsers.add_parser('clear_log_flag', help='clear log flag')
915    p.add_argument(
916        'flag', help='log flag we want to clear. (for example "nvme").')
917    p.set_defaults(func=clear_log_flag)
918
919    def clear_trace_flag(args):
920        print("clear_trace_flag is deprecated - use clear_log_flag instead")
921        rpc.log.clear_trace_flag(args.client, flag=args.flag)
922
923    p = subparsers.add_parser('clear_trace_flag', help='clear trace flag')
924    p.add_argument(
925        'flag', help='trace mask we want to clear. (for example "nvme").')
926    p.set_defaults(func=clear_trace_flag)
927
928    def get_log_flags(args):
929        print_dict(rpc.log.get_log_flags(args.client))
930
931    p = subparsers.add_parser('get_log_flags', help='get log flags')
932    p.set_defaults(func=get_log_flags)
933
934    def get_trace_flags(args):
935        print("get_trace_flags is deprecated - use get_log_flags instead")
936        print_dict(rpc.log.get_trace_flags(args.client))
937
938    p = subparsers.add_parser('get_trace_flags', help='get trace flags')
939    p.set_defaults(func=get_trace_flags)
940
941    def set_log_level(args):
942        rpc.log.set_log_level(args.client, level=args.level)
943
944    p = subparsers.add_parser('set_log_level', help='set log level')
945    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
946    p.set_defaults(func=set_log_level)
947
948    def get_log_level(args):
949        print_dict(rpc.log.get_log_level(args.client))
950
951    p = subparsers.add_parser('get_log_level', help='get log level')
952    p.set_defaults(func=get_log_level)
953
954    def set_log_print_level(args):
955        rpc.log.set_log_print_level(args.client, level=args.level)
956
957    p = subparsers.add_parser('set_log_print_level', help='set log print level')
958    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
959    p.set_defaults(func=set_log_print_level)
960
961    def get_log_print_level(args):
962        print_dict(rpc.log.get_log_print_level(args.client))
963
964    p = subparsers.add_parser('get_log_print_level', help='get log print level')
965    p.set_defaults(func=get_log_print_level)
966
967    # lvol
968    def construct_lvol_store(args):
969        print(rpc.lvol.construct_lvol_store(args.client,
970                                            bdev_name=args.bdev_name,
971                                            lvs_name=args.lvs_name,
972                                            cluster_sz=args.cluster_sz))
973
974    p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev')
975    p.add_argument('bdev_name', help='base bdev name')
976    p.add_argument('lvs_name', help='name for lvol store')
977    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
978    p.set_defaults(func=construct_lvol_store)
979
980    def rename_lvol_store(args):
981        rpc.lvol.rename_lvol_store(args.client,
982                                   old_name=args.old_name,
983                                   new_name=args.new_name)
984
985    p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
986    p.add_argument('old_name', help='old name')
987    p.add_argument('new_name', help='new name')
988    p.set_defaults(func=rename_lvol_store)
989
990    def construct_lvol_bdev(args):
991        print(rpc.lvol.construct_lvol_bdev(args.client,
992                                           lvol_name=args.lvol_name,
993                                           size=args.size * 1024 * 1024,
994                                           thin_provision=args.thin_provision,
995                                           uuid=args.uuid,
996                                           lvs_name=args.lvs_name))
997
998    p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
999    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1000    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1001    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
1002    p.add_argument('lvol_name', help='name for this lvol')
1003    p.add_argument('size', help='size in MiB for this bdev', type=int)
1004    p.set_defaults(func=construct_lvol_bdev)
1005
1006    def snapshot_lvol_bdev(args):
1007        print(rpc.lvol.snapshot_lvol_bdev(args.client,
1008                                          lvol_name=args.lvol_name,
1009                                          snapshot_name=args.snapshot_name))
1010
1011    p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
1012    p.add_argument('lvol_name', help='lvol bdev name')
1013    p.add_argument('snapshot_name', help='lvol snapshot name')
1014    p.set_defaults(func=snapshot_lvol_bdev)
1015
1016    def clone_lvol_bdev(args):
1017        print(rpc.lvol.clone_lvol_bdev(args.client,
1018                                       snapshot_name=args.snapshot_name,
1019                                       clone_name=args.clone_name))
1020
1021    p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
1022    p.add_argument('snapshot_name', help='lvol snapshot name')
1023    p.add_argument('clone_name', help='lvol clone name')
1024    p.set_defaults(func=clone_lvol_bdev)
1025
1026    def rename_lvol_bdev(args):
1027        rpc.lvol.rename_lvol_bdev(args.client,
1028                                  old_name=args.old_name,
1029                                  new_name=args.new_name)
1030
1031    p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name')
1032    p.add_argument('old_name', help='lvol bdev name')
1033    p.add_argument('new_name', help='new lvol name')
1034    p.set_defaults(func=rename_lvol_bdev)
1035
1036    def inflate_lvol_bdev(args):
1037        rpc.lvol.inflate_lvol_bdev(args.client,
1038                                   name=args.name)
1039
1040    p = subparsers.add_parser('inflate_lvol_bdev', help='Make thin provisioned lvol a thick provisioned lvol')
1041    p.add_argument('name', help='lvol bdev name')
1042    p.set_defaults(func=inflate_lvol_bdev)
1043
1044    def decouple_parent_lvol_bdev(args):
1045        rpc.lvol.decouple_parent_lvol_bdev(args.client,
1046                                           name=args.name)
1047
1048    p = subparsers.add_parser('decouple_parent_lvol_bdev', help='Decouple parent of lvol')
1049    p.add_argument('name', help='lvol bdev name')
1050    p.set_defaults(func=decouple_parent_lvol_bdev)
1051
1052    def resize_lvol_bdev(args):
1053        rpc.lvol.resize_lvol_bdev(args.client,
1054                                  name=args.name,
1055                                  size=args.size * 1024 * 1024)
1056
1057    p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev')
1058    p.add_argument('name', help='lvol bdev name')
1059    p.add_argument('size', help='new size in MiB for this bdev', type=int)
1060    p.set_defaults(func=resize_lvol_bdev)
1061
1062    def destroy_lvol_bdev(args):
1063        rpc.lvol.destroy_lvol_bdev(args.client,
1064                                   name=args.name)
1065
1066    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
1067    p.add_argument('name', help='lvol bdev name')
1068    p.set_defaults(func=destroy_lvol_bdev)
1069
1070    def destroy_lvol_store(args):
1071        rpc.lvol.destroy_lvol_store(args.client,
1072                                    uuid=args.uuid,
1073                                    lvs_name=args.lvs_name)
1074
1075    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
1076    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1077    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1078    p.set_defaults(func=destroy_lvol_store)
1079
1080    def get_lvol_stores(args):
1081        print_dict(rpc.lvol.get_lvol_stores(args.client,
1082                                            uuid=args.uuid,
1083                                            lvs_name=args.lvs_name))
1084
1085    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
1086    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1087    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1088    p.set_defaults(func=get_lvol_stores)
1089
1090    def get_raid_bdevs(args):
1091        print_array(rpc.bdev.get_raid_bdevs(args.client,
1092                                            category=args.category))
1093
1094    p = subparsers.add_parser('get_raid_bdevs', help="""This is used to list all the raid bdev names based on the input category
1095    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
1096    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
1097    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
1098    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
1099    p.add_argument('category', help='all or online or configuring or offline')
1100    p.set_defaults(func=get_raid_bdevs)
1101
1102    def construct_raid_bdev(args):
1103        base_bdevs = []
1104        for u in args.base_bdevs.strip().split(" "):
1105            base_bdevs.append(u)
1106
1107        rpc.bdev.construct_raid_bdev(args.client,
1108                                     name=args.name,
1109                                     strip_size=args.strip_size,
1110                                     raid_level=args.raid_level,
1111                                     base_bdevs=base_bdevs)
1112    p = subparsers.add_parser('construct_raid_bdev', help='Construct new raid bdev')
1113    p.add_argument('-n', '--name', help='raid bdev name', required=True)
1114    p.add_argument('-s', '--strip-size', help='strip size in KB', type=int, required=True)
1115    p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', type=int, required=True)
1116    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
1117    p.set_defaults(func=construct_raid_bdev)
1118
1119    def destroy_raid_bdev(args):
1120        rpc.bdev.destroy_raid_bdev(args.client,
1121                                   name=args.name)
1122    p = subparsers.add_parser('destroy_raid_bdev', help='Destroy existing raid bdev')
1123    p.add_argument('name', help='raid bdev name')
1124    p.set_defaults(func=destroy_raid_bdev)
1125
1126    # split
1127    def construct_split_vbdev(args):
1128        print_array(rpc.bdev.construct_split_vbdev(args.client,
1129                                                   base_bdev=args.base_bdev,
1130                                                   split_count=args.split_count,
1131                                                   split_size_mb=args.split_size_mb))
1132
1133    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
1134    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
1135    available (during examination process).""")
1136    p.add_argument('base_bdev', help='base bdev name')
1137    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
1138    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
1139    exceed the base bdev size.""", type=int)
1140    p.set_defaults(func=construct_split_vbdev)
1141
1142    def destruct_split_vbdev(args):
1143        rpc.bdev.destruct_split_vbdev(args.client,
1144                                      base_bdev=args.base_bdev)
1145
1146    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
1147    p.add_argument('base_bdev', help='base bdev name')
1148    p.set_defaults(func=destruct_split_vbdev)
1149
1150    # nbd
1151    def start_nbd_disk(args):
1152        print(rpc.nbd.start_nbd_disk(args.client,
1153                                     bdev_name=args.bdev_name,
1154                                     nbd_device=args.nbd_device))
1155
1156    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
1157    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
1158    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.')
1159    p.set_defaults(func=start_nbd_disk)
1160
1161    def stop_nbd_disk(args):
1162        rpc.nbd.stop_nbd_disk(args.client,
1163                              nbd_device=args.nbd_device)
1164
1165    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
1166    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
1167    p.set_defaults(func=stop_nbd_disk)
1168
1169    def get_nbd_disks(args):
1170        print_dict(rpc.nbd.get_nbd_disks(args.client,
1171                                         nbd_device=args.nbd_device))
1172
1173    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
1174    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
1175    p.set_defaults(func=get_nbd_disks)
1176
1177    # net
1178    def add_ip_address(args):
1179        rpc.net.add_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1180
1181    p = subparsers.add_parser('add_ip_address', help='Add IP address')
1182    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1183    p.add_argument('ip_addr', help='ip address will be added.')
1184    p.set_defaults(func=add_ip_address)
1185
1186    def delete_ip_address(args):
1187        rpc.net.delete_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1188
1189    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
1190    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1191    p.add_argument('ip_addr', help='ip address will be deleted.')
1192    p.set_defaults(func=delete_ip_address)
1193
1194    def get_interfaces(args):
1195        print_dict(rpc.net.get_interfaces(args.client))
1196
1197    p = subparsers.add_parser(
1198        'get_interfaces', help='Display current interface list')
1199    p.set_defaults(func=get_interfaces)
1200
1201    # NVMe-oF
1202    def set_nvmf_target_options(args):
1203        rpc.nvmf.set_nvmf_target_options(args.client,
1204                                         max_queue_depth=args.max_queue_depth,
1205                                         max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1206                                         in_capsule_data_size=args.in_capsule_data_size,
1207                                         max_io_size=args.max_io_size,
1208                                         max_subsystems=args.max_subsystems,
1209                                         io_unit_size=args.io_unit_size)
1210
1211    p = subparsers.add_parser('set_nvmf_target_options', help='Set NVMf target options')
1212    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1213    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1214    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1215    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1216    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int)
1217    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1218    p.set_defaults(func=set_nvmf_target_options)
1219
1220    def set_nvmf_target_max_subsystems(args):
1221        rpc.nvmf.set_nvmf_target_max_subsystems(args.client,
1222                                                max_subsystems=args.max_subsystems)
1223
1224    p = subparsers.add_parser('set_nvmf_target_max_subsystems', help='Set the maximum number of NVMf target subsystems')
1225    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True)
1226    p.set_defaults(func=set_nvmf_target_max_subsystems)
1227
1228    def set_nvmf_target_config(args):
1229        rpc.nvmf.set_nvmf_target_config(args.client,
1230                                        acceptor_poll_rate=args.acceptor_poll_rate,
1231                                        conn_sched=args.conn_sched)
1232
1233    p = subparsers.add_parser('set_nvmf_target_config', help='Set NVMf target config')
1234    p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
1235    p.add_argument('-s', '--conn-sched', help="""'roundrobin' - Schedule the incoming connections from any host
1236    on the cores in a round robin manner (Default). 'hostip' - Schedule all the incoming connections from a
1237    specific host IP on to the same core. Connections from different IP will be assigned to cores in a round
1238    robin manner""")
1239    p.set_defaults(func=set_nvmf_target_config)
1240
1241    def nvmf_create_transport(args):
1242        rpc.nvmf.nvmf_create_transport(args.client,
1243                                       trtype=args.trtype,
1244                                       max_queue_depth=args.max_queue_depth,
1245                                       max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1246                                       in_capsule_data_size=args.in_capsule_data_size,
1247                                       max_io_size=args.max_io_size,
1248                                       io_unit_size=args.io_unit_size,
1249                                       max_aq_depth=args.max_aq_depth)
1250
1251    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
1252    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
1253    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1254    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1255    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1256    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1257    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1258    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
1259    p.set_defaults(func=nvmf_create_transport)
1260
1261    def get_nvmf_transports(args):
1262        print_dict(rpc.nvmf.get_nvmf_transports(args.client))
1263
1264    p = subparsers.add_parser('get_nvmf_transports',
1265                              help='Display nvmf transports')
1266    p.set_defaults(func=get_nvmf_transports)
1267
1268    def get_nvmf_subsystems(args):
1269        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client))
1270
1271    p = subparsers.add_parser('get_nvmf_subsystems',
1272                              help='Display nvmf subsystems')
1273    p.set_defaults(func=get_nvmf_subsystems)
1274
1275    def construct_nvmf_subsystem(args):
1276        listen_addresses = None
1277        hosts = None
1278        namespaces = None
1279        if args.listen:
1280            listen_addresses = [
1281                dict(
1282                    u.split(
1283                        ":",
1284                        1) for u in a.split(" ")) for a in args.listen.split(",")]
1285
1286        if args.hosts:
1287            hosts = []
1288            for u in args.hosts.strip().split(" "):
1289                hosts.append(u)
1290
1291        if args.namespaces:
1292            namespaces = []
1293            for u in args.namespaces.strip().split(" "):
1294                bdev_name = u
1295                nsid = 0
1296                if ':' in u:
1297                    (bdev_name, nsid) = u.split(":")
1298
1299                ns_params = {'bdev_name': bdev_name}
1300
1301                nsid = int(nsid)
1302                if nsid != 0:
1303                    ns_params['nsid'] = nsid
1304
1305                namespaces.append(ns_params)
1306
1307        rpc.nvmf.construct_nvmf_subsystem(args.client,
1308                                          nqn=args.nqn,
1309                                          listen_addresses=listen_addresses,
1310                                          hosts=hosts,
1311                                          allow_any_host=args.allow_any_host,
1312                                          serial_number=args.serial_number,
1313                                          namespaces=namespaces,
1314                                          max_namespaces=args.max_namespaces)
1315
1316    p = subparsers.add_parser('construct_nvmf_subsystem', help='Add a nvmf subsystem')
1317    p.add_argument('nqn', help='Target nqn(ASCII)')
1318    p.add_argument('listen', help="""comma-separated list of Listen <trtype:transport_name traddr:address trsvcid:port_id> pairs enclosed
1319    in quotes.  Format:  'trtype:transport0 traddr:traddr0 trsvcid:trsvcid0,trtype:transport1 traddr:traddr1 trsvcid:trsvcid1' etc
1320    Example: 'trtype:RDMA traddr:192.168.100.8 trsvcid:4420,trtype:RDMA traddr:192.168.100.9 trsvcid:4420'""")
1321    p.add_argument('hosts', help="""Whitespace-separated list of host nqn list.
1322    Format:  'nqn1 nqn2' etc
1323    Example: 'nqn.2016-06.io.spdk:init nqn.2016-07.io.spdk:init'""")
1324    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1325    p.add_argument("-s", "--serial-number", help="""
1326    Format:  'sn' etc
1327    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1328    p.add_argument("-n", "--namespaces", help="""Whitespace-separated list of namespaces
1329    Format:  'bdev_name1[:nsid1] bdev_name2[:nsid2] bdev_name3[:nsid3]' etc
1330    Example: '1:Malloc0 2:Malloc1 3:Malloc2'
1331    *** The devices must pre-exist ***""")
1332    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed to added during active connection",
1333                   type=int, default=0)
1334    p.set_defaults(func=construct_nvmf_subsystem)
1335
1336    def nvmf_subsystem_create(args):
1337        rpc.nvmf.nvmf_subsystem_create(args.client,
1338                                       nqn=args.nqn,
1339                                       serial_number=args.serial_number,
1340                                       allow_any_host=args.allow_any_host,
1341                                       max_namespaces=args.max_namespaces)
1342
1343    p = subparsers.add_parser('nvmf_subsystem_create', help='Create an NVMe-oF subsystem')
1344    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
1345    p.add_argument("-s", "--serial-number", help="""
1346    Format:  'sn' etc
1347    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1348    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1349    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
1350                   type=int, default=0)
1351    p.set_defaults(func=nvmf_subsystem_create)
1352
1353    def delete_nvmf_subsystem(args):
1354        rpc.nvmf.delete_nvmf_subsystem(args.client,
1355                                       nqn=args.subsystem_nqn)
1356
1357    p = subparsers.add_parser('delete_nvmf_subsystem',
1358                              help='Delete a nvmf subsystem')
1359    p.add_argument('subsystem_nqn',
1360                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
1361    p.set_defaults(func=delete_nvmf_subsystem)
1362
1363    def nvmf_subsystem_add_listener(args):
1364        rpc.nvmf.nvmf_subsystem_add_listener(args.client,
1365                                             nqn=args.nqn,
1366                                             trtype=args.trtype,
1367                                             traddr=args.traddr,
1368                                             adrfam=args.adrfam,
1369                                             trsvcid=args.trsvcid)
1370
1371    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
1372    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1373    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1374    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1375    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1376    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1377    p.set_defaults(func=nvmf_subsystem_add_listener)
1378
1379    def nvmf_subsystem_remove_listener(args):
1380        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
1381                                                nqn=args.nqn,
1382                                                trtype=args.trtype,
1383                                                traddr=args.traddr,
1384                                                adrfam=args.adrfam,
1385                                                trsvcid=args.trsvcid)
1386
1387    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
1388    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1389    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1390    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1391    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1392    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1393    p.set_defaults(func=nvmf_subsystem_remove_listener)
1394
1395    def nvmf_subsystem_add_ns(args):
1396        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
1397                                       nqn=args.nqn,
1398                                       bdev_name=args.bdev_name,
1399                                       nsid=args.nsid,
1400                                       nguid=args.nguid,
1401                                       eui64=args.eui64,
1402                                       uuid=args.uuid)
1403
1404    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
1405    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1406    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
1407    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
1408    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
1409    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
1410    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
1411    p.set_defaults(func=nvmf_subsystem_add_ns)
1412
1413    def nvmf_subsystem_remove_ns(args):
1414        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
1415                                          nqn=args.nqn,
1416                                          nsid=args.nsid)
1417
1418    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
1419    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1420    p.add_argument('nsid', help='The requested NSID', type=int)
1421    p.set_defaults(func=nvmf_subsystem_remove_ns)
1422
1423    def nvmf_subsystem_add_host(args):
1424        rpc.nvmf.nvmf_subsystem_add_host(args.client,
1425                                         nqn=args.nqn,
1426                                         host=args.host)
1427
1428    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
1429    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1430    p.add_argument('host', help='Host NQN to allow')
1431    p.set_defaults(func=nvmf_subsystem_add_host)
1432
1433    def nvmf_subsystem_remove_host(args):
1434        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
1435                                            nqn=args.nqn,
1436                                            host=args.host)
1437
1438    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
1439    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1440    p.add_argument('host', help='Host NQN to remove')
1441    p.set_defaults(func=nvmf_subsystem_remove_host)
1442
1443    def nvmf_subsystem_allow_any_host(args):
1444        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
1445                                               nqn=args.nqn,
1446                                               disable=args.disable)
1447
1448    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
1449    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1450    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
1451    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
1452    p.set_defaults(func=nvmf_subsystem_allow_any_host)
1453
1454    # pmem
1455    def create_pmem_pool(args):
1456        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
1457        rpc.pmem.create_pmem_pool(args.client,
1458                                  pmem_file=args.pmem_file,
1459                                  num_blocks=num_blocks,
1460                                  block_size=args.block_size)
1461
1462    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
1463    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1464    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
1465    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
1466    p.set_defaults(func=create_pmem_pool)
1467
1468    def pmem_pool_info(args):
1469        print_dict(rpc.pmem.pmem_pool_info(args.client,
1470                                           pmem_file=args.pmem_file))
1471
1472    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
1473    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1474    p.set_defaults(func=pmem_pool_info)
1475
1476    def delete_pmem_pool(args):
1477        rpc.pmem.delete_pmem_pool(args.client,
1478                                  pmem_file=args.pmem_file)
1479
1480    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
1481    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1482    p.set_defaults(func=delete_pmem_pool)
1483
1484    # subsystem
1485    def get_subsystems(args):
1486        print_dict(rpc.subsystem.get_subsystems(args.client))
1487
1488    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
1489    entry contain (unsorted) array of subsystems it depends on.""")
1490    p.set_defaults(func=get_subsystems)
1491
1492    def get_subsystem_config(args):
1493        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
1494
1495    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
1496    p.add_argument('name', help='Name of subsystem to query')
1497    p.set_defaults(func=get_subsystem_config)
1498
1499    # vhost
1500    def set_vhost_controller_coalescing(args):
1501        rpc.vhost.set_vhost_controller_coalescing(args.client,
1502                                                  ctrlr=args.ctrlr,
1503                                                  delay_base_us=args.delay_base_us,
1504                                                  iops_threshold=args.iops_threshold)
1505
1506    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
1507    p.add_argument('ctrlr', help='controller name')
1508    p.add_argument('delay_base_us', help='Base delay time', type=int)
1509    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
1510    p.set_defaults(func=set_vhost_controller_coalescing)
1511
1512    def construct_vhost_scsi_controller(args):
1513        rpc.vhost.construct_vhost_scsi_controller(args.client,
1514                                                  ctrlr=args.ctrlr,
1515                                                  cpumask=args.cpumask)
1516
1517    p = subparsers.add_parser(
1518        'construct_vhost_scsi_controller', help='Add new vhost controller')
1519    p.add_argument('ctrlr', help='controller name')
1520    p.add_argument('--cpumask', help='cpu mask for this controller')
1521    p.set_defaults(func=construct_vhost_scsi_controller)
1522
1523    def add_vhost_scsi_lun(args):
1524        rpc.vhost.add_vhost_scsi_lun(args.client,
1525                                     ctrlr=args.ctrlr,
1526                                     scsi_target_num=args.scsi_target_num,
1527                                     bdev_name=args.bdev_name)
1528
1529    p = subparsers.add_parser('add_vhost_scsi_lun',
1530                              help='Add lun to vhost controller')
1531    p.add_argument('ctrlr', help='conntroller name where add lun')
1532    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1533    p.add_argument('bdev_name', help='bdev name')
1534    p.set_defaults(func=add_vhost_scsi_lun)
1535
1536    def remove_vhost_scsi_target(args):
1537        rpc.vhost.remove_vhost_scsi_target(args.client,
1538                                           ctrlr=args.ctrlr,
1539                                           scsi_target_num=args.scsi_target_num)
1540
1541    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
1542    p.add_argument('ctrlr', help='controller name to remove target from')
1543    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1544    p.set_defaults(func=remove_vhost_scsi_target)
1545
1546    def construct_vhost_blk_controller(args):
1547        rpc.vhost.construct_vhost_blk_controller(args.client,
1548                                                 ctrlr=args.ctrlr,
1549                                                 dev_name=args.dev_name,
1550                                                 cpumask=args.cpumask,
1551                                                 readonly=args.readonly)
1552
1553    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
1554    p.add_argument('ctrlr', help='controller name')
1555    p.add_argument('dev_name', help='device name')
1556    p.add_argument('--cpumask', help='cpu mask for this controller')
1557    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1558    p.set_defaults(func=construct_vhost_blk_controller)
1559
1560    def construct_vhost_nvme_controller(args):
1561        rpc.vhost.construct_vhost_nvme_controller(args.client,
1562                                                  ctrlr=args.ctrlr,
1563                                                  io_queues=args.io_queues,
1564                                                  cpumask=args.cpumask)
1565
1566    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
1567    p.add_argument('ctrlr', help='controller name')
1568    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
1569    p.add_argument('--cpumask', help='cpu mask for this controller')
1570    p.set_defaults(func=construct_vhost_nvme_controller)
1571
1572    def add_vhost_nvme_ns(args):
1573        rpc.vhost.add_vhost_nvme_ns(args.client,
1574                                    ctrlr=args.ctrlr,
1575                                    bdev_name=args.bdev_name)
1576
1577    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
1578    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
1579    p.add_argument('bdev_name', help='block device name for a new Namespace')
1580    p.set_defaults(func=add_vhost_nvme_ns)
1581
1582    def get_vhost_controllers(args):
1583        print_dict(rpc.vhost.get_vhost_controllers(args.client, args.name))
1584
1585    p = subparsers.add_parser('get_vhost_controllers', help='List all or specific vhost controller(s)')
1586    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
1587    p.set_defaults(func=get_vhost_controllers)
1588
1589    def remove_vhost_controller(args):
1590        rpc.vhost.remove_vhost_controller(args.client,
1591                                          ctrlr=args.ctrlr)
1592
1593    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
1594    p.add_argument('ctrlr', help='controller name')
1595    p.set_defaults(func=remove_vhost_controller)
1596
1597    def construct_virtio_dev(args):
1598        print_array(rpc.vhost.construct_virtio_dev(args.client,
1599                                                   name=args.name,
1600                                                   trtype=args.trtype,
1601                                                   traddr=args.traddr,
1602                                                   dev_type=args.dev_type,
1603                                                   vq_count=args.vq_count,
1604                                                   vq_size=args.vq_size))
1605
1606    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
1607    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
1608    remote side. Result is array of added bdevs.""")
1609    p.add_argument('name', help="Use this name as base for new created bdevs")
1610    p.add_argument('-t', '--trtype',
1611                   help='Virtio target transport type: pci or user', required=True)
1612    p.add_argument('-a', '--traddr',
1613                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
1614    p.add_argument('-d', '--dev-type',
1615                   help='Device type: blk or scsi', required=True)
1616    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1617    p.add_argument('--vq-size', help='Size of each queue', type=int)
1618    p.set_defaults(func=construct_virtio_dev)
1619
1620    def construct_virtio_user_scsi_bdev(args):
1621        print_array(rpc.vhost.construct_virtio_user_scsi_bdev(args.client,
1622                                                              path=args.path,
1623                                                              name=args.name,
1624                                                              vq_count=args.vq_count,
1625                                                              vq_size=args.vq_size))
1626
1627    p = subparsers.add_parser('construct_virtio_user_scsi_bdev', help="""Connect to virtio user scsi device.
1628    This imply scan and add bdevs offered by remote side.
1629    Result is array of added bdevs.""")
1630    p.add_argument('path', help='Path to Virtio SCSI socket')
1631    p.add_argument('name', help="""Use this name as base instead of 'VirtioScsiN'
1632    Base will be used to construct new bdev's found on target by adding 't<TARGET_ID>' sufix.""")
1633    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1634    p.add_argument('--vq-size', help='Size of each queue', type=int)
1635    p.set_defaults(func=construct_virtio_user_scsi_bdev)
1636
1637    def construct_virtio_pci_scsi_bdev(args):
1638        print_array(rpc.vhost.construct_virtio_pci_scsi_bdev(args.client,
1639                                                             pci_address=args.pci_address,
1640                                                             name=args.name))
1641
1642    p = subparsers.add_parser('construct_virtio_pci_scsi_bdev', help="""Create a Virtio
1643    SCSI device from a virtio-pci device.""")
1644    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1645    domain.bus.device.function format""")
1646    p.add_argument('name', help="""Name for the virtio device.
1647    It will be inhereted by all created bdevs, which are named n the following format: <name>t<target_id>""")
1648    p.set_defaults(func=construct_virtio_pci_scsi_bdev)
1649
1650    def get_virtio_scsi_devs(args):
1651        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client))
1652
1653    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
1654    p.set_defaults(func=get_virtio_scsi_devs)
1655
1656    def remove_virtio_scsi_bdev(args):
1657        rpc.vhost.remove_virtio_scsi_bdev(args.client,
1658                                          name=args.name)
1659
1660    p = subparsers.add_parser('remove_virtio_scsi_bdev', help="""Remove a Virtio-SCSI device
1661    This will delete all bdevs exposed by this device (this call is deprecated - please use remove_virtio_bdev call instead).""")
1662    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1663    p.set_defaults(func=remove_virtio_scsi_bdev)
1664
1665    def remove_virtio_bdev(args):
1666        rpc.vhost.remove_virtio_bdev(args.client,
1667                                     name=args.name)
1668
1669    p = subparsers.add_parser('remove_virtio_bdev', help="""Remove a Virtio device
1670    This will delete all bdevs exposed by this device""")
1671    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1672    p.set_defaults(func=remove_virtio_bdev)
1673
1674    def construct_virtio_user_blk_bdev(args):
1675        print(rpc.vhost.construct_virtio_user_blk_bdev(args.client,
1676                                                       path=args.path,
1677                                                       name=args.name,
1678                                                       vq_count=args.vq_count,
1679                                                       vq_size=args.vq_size))
1680
1681    p = subparsers.add_parser('construct_virtio_user_blk_bdev', help='Connect to a virtio user blk device.')
1682    p.add_argument('path', help='Path to Virtio BLK socket')
1683    p.add_argument('name', help='Name for the bdev')
1684    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1685    p.add_argument('--vq-size', help='Size of each queue', type=int)
1686    p.set_defaults(func=construct_virtio_user_blk_bdev)
1687
1688    def construct_virtio_pci_blk_bdev(args):
1689        print(rpc.vhost.construct_virtio_pci_blk_bdev(args.client,
1690                                                      pci_address=args.pci_address,
1691                                                      name=args.name))
1692
1693    p = subparsers.add_parser('construct_virtio_pci_blk_bdev', help='Create a Virtio Blk device from a virtio-pci device.')
1694    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1695    domain.bus.device.function format""")
1696    p.add_argument('name', help='Name for the bdev')
1697    p.set_defaults(func=construct_virtio_pci_blk_bdev)
1698
1699    # ioat
1700    def scan_ioat_copy_engine(args):
1701        pci_whitelist = []
1702        if args.pci_whitelist:
1703            for w in args.pci_whitelist.strip().split(" "):
1704                pci_whitelist.append(w)
1705        rpc.ioat.scan_ioat_copy_engine(args.client, pci_whitelist)
1706
1707    p = subparsers.add_parser('scan_ioat_copy_engine', help='Set scan and enable IOAT copy engine offload.')
1708    p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in
1709    domain:bus:device.function format or domain.bus.device.function format""")
1710    p.set_defaults(func=scan_ioat_copy_engine)
1711
1712    # send_nvme_cmd
1713    def send_nvme_cmd(args):
1714        print_dict(rpc.nvme.send_nvme_cmd(args.client,
1715                                          name=args.nvme_name,
1716                                          cmd_type=args.cmd_type,
1717                                          data_direction=args.data_direction,
1718                                          cmdbuf=args.cmdbuf,
1719                                          data=args.data,
1720                                          metadata=args.metadata,
1721                                          data_len=args.data_length,
1722                                          metadata_len=args.metadata_length,
1723                                          timeout_ms=args.timeout_ms))
1724
1725    p = subparsers.add_parser('send_nvme_cmd', help='NVMe passthrough cmd.')
1726    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
1727    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
1728    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
1729    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
1730    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
1731    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
1732    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
1733    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
1734    p.add_argument('-T', '--timeout-ms',
1735                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int, default=0)
1736    p.set_defaults(func=send_nvme_cmd)
1737
1738    args = parser.parse_args()
1739
1740    try:
1741        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.verbose, args.timeout)
1742        args.func(args)
1743    except JSONRPCException as ex:
1744        print("Exception:")
1745        print(ex.message)
1746        exit(1)
1747