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