xref: /spdk/scripts/rpc.py (revision 42dba6047b054d9db99f2a78f1b7100a9b3162a1)
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 set_read_only_lvol_bdev(args):
1096        rpc.lvol.set_read_only_lvol_bdev(args.client,
1097                                         name=args.name)
1098
1099    p = subparsers.add_parser('set_read_only_lvol_bdev', help='Mark lvol bdev as read only')
1100    p.add_argument('name', help='lvol bdev name')
1101    p.set_defaults(func=set_read_only_lvol_bdev)
1102
1103    def destroy_lvol_bdev(args):
1104        rpc.lvol.destroy_lvol_bdev(args.client,
1105                                   name=args.name)
1106
1107    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
1108    p.add_argument('name', help='lvol bdev name')
1109    p.set_defaults(func=destroy_lvol_bdev)
1110
1111    def destroy_lvol_store(args):
1112        rpc.lvol.destroy_lvol_store(args.client,
1113                                    uuid=args.uuid,
1114                                    lvs_name=args.lvs_name)
1115
1116    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
1117    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1118    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1119    p.set_defaults(func=destroy_lvol_store)
1120
1121    def get_lvol_stores(args):
1122        print_dict(rpc.lvol.get_lvol_stores(args.client,
1123                                            uuid=args.uuid,
1124                                            lvs_name=args.lvs_name))
1125
1126    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
1127    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1128    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1129    p.set_defaults(func=get_lvol_stores)
1130
1131    def get_raid_bdevs(args):
1132        print_array(rpc.bdev.get_raid_bdevs(args.client,
1133                                            category=args.category))
1134
1135    p = subparsers.add_parser('get_raid_bdevs', help="""This is used to list all the raid bdev names based on the input category
1136    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
1137    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
1138    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
1139    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
1140    p.add_argument('category', help='all or online or configuring or offline')
1141    p.set_defaults(func=get_raid_bdevs)
1142
1143    def construct_raid_bdev(args):
1144        base_bdevs = []
1145        for u in args.base_bdevs.strip().split(" "):
1146            base_bdevs.append(u)
1147
1148        rpc.bdev.construct_raid_bdev(args.client,
1149                                     name=args.name,
1150                                     strip_size=args.strip_size,
1151                                     raid_level=args.raid_level,
1152                                     base_bdevs=base_bdevs)
1153    p = subparsers.add_parser('construct_raid_bdev', help='Construct new raid bdev')
1154    p.add_argument('-n', '--name', help='raid bdev name', required=True)
1155    p.add_argument('-s', '--strip-size', help='strip size in KB', type=int, required=True)
1156    p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', type=int, required=True)
1157    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
1158    p.set_defaults(func=construct_raid_bdev)
1159
1160    def destroy_raid_bdev(args):
1161        rpc.bdev.destroy_raid_bdev(args.client,
1162                                   name=args.name)
1163    p = subparsers.add_parser('destroy_raid_bdev', help='Destroy existing raid bdev')
1164    p.add_argument('name', help='raid bdev name')
1165    p.set_defaults(func=destroy_raid_bdev)
1166
1167    # split
1168    def construct_split_vbdev(args):
1169        print_array(rpc.bdev.construct_split_vbdev(args.client,
1170                                                   base_bdev=args.base_bdev,
1171                                                   split_count=args.split_count,
1172                                                   split_size_mb=args.split_size_mb))
1173
1174    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
1175    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
1176    available (during examination process).""")
1177    p.add_argument('base_bdev', help='base bdev name')
1178    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
1179    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
1180    exceed the base bdev size.""", type=int)
1181    p.set_defaults(func=construct_split_vbdev)
1182
1183    def destruct_split_vbdev(args):
1184        rpc.bdev.destruct_split_vbdev(args.client,
1185                                      base_bdev=args.base_bdev)
1186
1187    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
1188    p.add_argument('base_bdev', help='base bdev name')
1189    p.set_defaults(func=destruct_split_vbdev)
1190
1191    # nbd
1192    def start_nbd_disk(args):
1193        print(rpc.nbd.start_nbd_disk(args.client,
1194                                     bdev_name=args.bdev_name,
1195                                     nbd_device=args.nbd_device))
1196
1197    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
1198    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
1199    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.')
1200    p.set_defaults(func=start_nbd_disk)
1201
1202    def stop_nbd_disk(args):
1203        rpc.nbd.stop_nbd_disk(args.client,
1204                              nbd_device=args.nbd_device)
1205
1206    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
1207    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
1208    p.set_defaults(func=stop_nbd_disk)
1209
1210    def get_nbd_disks(args):
1211        print_dict(rpc.nbd.get_nbd_disks(args.client,
1212                                         nbd_device=args.nbd_device))
1213
1214    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
1215    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
1216    p.set_defaults(func=get_nbd_disks)
1217
1218    # net
1219    def add_ip_address(args):
1220        rpc.net.add_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1221
1222    p = subparsers.add_parser('add_ip_address', help='Add 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 added.')
1225    p.set_defaults(func=add_ip_address)
1226
1227    def delete_ip_address(args):
1228        rpc.net.delete_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1229
1230    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
1231    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1232    p.add_argument('ip_addr', help='ip address will be deleted.')
1233    p.set_defaults(func=delete_ip_address)
1234
1235    def get_interfaces(args):
1236        print_dict(rpc.net.get_interfaces(args.client))
1237
1238    p = subparsers.add_parser(
1239        'get_interfaces', help='Display current interface list')
1240    p.set_defaults(func=get_interfaces)
1241
1242    # NVMe-oF
1243    def set_nvmf_target_options(args):
1244        rpc.nvmf.set_nvmf_target_options(args.client,
1245                                         max_queue_depth=args.max_queue_depth,
1246                                         max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1247                                         in_capsule_data_size=args.in_capsule_data_size,
1248                                         max_io_size=args.max_io_size,
1249                                         max_subsystems=args.max_subsystems,
1250                                         io_unit_size=args.io_unit_size)
1251
1252    p = subparsers.add_parser('set_nvmf_target_options', help='Set NVMf target options')
1253    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1254    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1255    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1256    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1257    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int)
1258    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1259    p.set_defaults(func=set_nvmf_target_options)
1260
1261    def set_nvmf_target_max_subsystems(args):
1262        rpc.nvmf.set_nvmf_target_max_subsystems(args.client,
1263                                                max_subsystems=args.max_subsystems)
1264
1265    p = subparsers.add_parser('set_nvmf_target_max_subsystems', help='Set the maximum number of NVMf target subsystems')
1266    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True)
1267    p.set_defaults(func=set_nvmf_target_max_subsystems)
1268
1269    def set_nvmf_target_config(args):
1270        rpc.nvmf.set_nvmf_target_config(args.client,
1271                                        acceptor_poll_rate=args.acceptor_poll_rate,
1272                                        conn_sched=args.conn_sched)
1273
1274    p = subparsers.add_parser('set_nvmf_target_config', help='Set NVMf target config')
1275    p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
1276    p.add_argument('-s', '--conn-sched', help="""'roundrobin' - Schedule the incoming connections from any host
1277    on the cores in a round robin manner (Default). 'hostip' - Schedule all the incoming connections from a
1278    specific host IP on to the same core. Connections from different IP will be assigned to cores in a round
1279    robin manner""")
1280    p.set_defaults(func=set_nvmf_target_config)
1281
1282    def nvmf_create_transport(args):
1283        rpc.nvmf.nvmf_create_transport(args.client,
1284                                       trtype=args.trtype,
1285                                       max_queue_depth=args.max_queue_depth,
1286                                       max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1287                                       in_capsule_data_size=args.in_capsule_data_size,
1288                                       max_io_size=args.max_io_size,
1289                                       io_unit_size=args.io_unit_size,
1290                                       max_aq_depth=args.max_aq_depth,
1291                                       num_shared_buffers=args.num_shared_buffers,
1292                                       buf_cache_size=args.buf_cache_size)
1293
1294    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
1295    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
1296    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1297    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1298    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1299    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1300    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1301    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
1302    p.add_argument('-n', '--num-shared-buffers', help='The number of pooled data buffers available to the transport', type=int)
1303    p.add_argument('-b', '--buf-cache-size', help='The number of shared buffers to cache per poll group', type=int)
1304    p.set_defaults(func=nvmf_create_transport)
1305
1306    def get_nvmf_transports(args):
1307        print_dict(rpc.nvmf.get_nvmf_transports(args.client))
1308
1309    p = subparsers.add_parser('get_nvmf_transports',
1310                              help='Display nvmf transports')
1311    p.set_defaults(func=get_nvmf_transports)
1312
1313    def get_nvmf_subsystems(args):
1314        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client))
1315
1316    p = subparsers.add_parser('get_nvmf_subsystems',
1317                              help='Display nvmf subsystems')
1318    p.set_defaults(func=get_nvmf_subsystems)
1319
1320    def construct_nvmf_subsystem(args):
1321        listen_addresses = None
1322        hosts = None
1323        namespaces = None
1324        if args.listen:
1325            listen_addresses = [
1326                dict(
1327                    u.split(
1328                        ":",
1329                        1) for u in a.split(" ")) for a in args.listen.split(",")]
1330
1331        if args.hosts:
1332            hosts = []
1333            for u in args.hosts.strip().split(" "):
1334                hosts.append(u)
1335
1336        if args.namespaces:
1337            namespaces = []
1338            for u in args.namespaces.strip().split(" "):
1339                bdev_name = u
1340                nsid = 0
1341                if ':' in u:
1342                    (bdev_name, nsid) = u.split(":")
1343
1344                ns_params = {'bdev_name': bdev_name}
1345
1346                nsid = int(nsid)
1347                if nsid != 0:
1348                    ns_params['nsid'] = nsid
1349
1350                namespaces.append(ns_params)
1351
1352        rpc.nvmf.construct_nvmf_subsystem(args.client,
1353                                          nqn=args.nqn,
1354                                          listen_addresses=listen_addresses,
1355                                          hosts=hosts,
1356                                          allow_any_host=args.allow_any_host,
1357                                          serial_number=args.serial_number,
1358                                          namespaces=namespaces,
1359                                          max_namespaces=args.max_namespaces)
1360
1361    p = subparsers.add_parser('construct_nvmf_subsystem', help='Add a nvmf subsystem')
1362    p.add_argument('nqn', help='Target nqn(ASCII)')
1363    p.add_argument('listen', help="""comma-separated list of Listen <trtype:transport_name traddr:address trsvcid:port_id> pairs enclosed
1364    in quotes.  Format:  'trtype:transport0 traddr:traddr0 trsvcid:trsvcid0,trtype:transport1 traddr:traddr1 trsvcid:trsvcid1' etc
1365    Example: 'trtype:RDMA traddr:192.168.100.8 trsvcid:4420,trtype:RDMA traddr:192.168.100.9 trsvcid:4420'""")
1366    p.add_argument('hosts', help="""Whitespace-separated list of host nqn list.
1367    Format:  'nqn1 nqn2' etc
1368    Example: 'nqn.2016-06.io.spdk:init nqn.2016-07.io.spdk:init'""")
1369    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1370    p.add_argument("-s", "--serial-number", help="""
1371    Format:  'sn' etc
1372    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1373    p.add_argument("-n", "--namespaces", help="""Whitespace-separated list of namespaces
1374    Format:  'bdev_name1[:nsid1] bdev_name2[:nsid2] bdev_name3[:nsid3]' etc
1375    Example: '1:Malloc0 2:Malloc1 3:Malloc2'
1376    *** The devices must pre-exist ***""")
1377    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed to added during active connection",
1378                   type=int, default=0)
1379    p.set_defaults(func=construct_nvmf_subsystem)
1380
1381    def nvmf_subsystem_create(args):
1382        rpc.nvmf.nvmf_subsystem_create(args.client,
1383                                       nqn=args.nqn,
1384                                       serial_number=args.serial_number,
1385                                       allow_any_host=args.allow_any_host,
1386                                       max_namespaces=args.max_namespaces)
1387
1388    p = subparsers.add_parser('nvmf_subsystem_create', help='Create an NVMe-oF subsystem')
1389    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
1390    p.add_argument("-s", "--serial-number", help="""
1391    Format:  'sn' etc
1392    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1393    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1394    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
1395                   type=int, default=0)
1396    p.set_defaults(func=nvmf_subsystem_create)
1397
1398    def delete_nvmf_subsystem(args):
1399        rpc.nvmf.delete_nvmf_subsystem(args.client,
1400                                       nqn=args.subsystem_nqn)
1401
1402    p = subparsers.add_parser('delete_nvmf_subsystem',
1403                              help='Delete a nvmf subsystem')
1404    p.add_argument('subsystem_nqn',
1405                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
1406    p.set_defaults(func=delete_nvmf_subsystem)
1407
1408    def nvmf_subsystem_add_listener(args):
1409        rpc.nvmf.nvmf_subsystem_add_listener(args.client,
1410                                             nqn=args.nqn,
1411                                             trtype=args.trtype,
1412                                             traddr=args.traddr,
1413                                             adrfam=args.adrfam,
1414                                             trsvcid=args.trsvcid)
1415
1416    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
1417    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1418    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1419    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1420    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1421    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1422    p.set_defaults(func=nvmf_subsystem_add_listener)
1423
1424    def nvmf_subsystem_remove_listener(args):
1425        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
1426                                                nqn=args.nqn,
1427                                                trtype=args.trtype,
1428                                                traddr=args.traddr,
1429                                                adrfam=args.adrfam,
1430                                                trsvcid=args.trsvcid)
1431
1432    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
1433    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1434    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1435    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1436    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1437    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1438    p.set_defaults(func=nvmf_subsystem_remove_listener)
1439
1440    def nvmf_subsystem_add_ns(args):
1441        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
1442                                       nqn=args.nqn,
1443                                       bdev_name=args.bdev_name,
1444                                       nsid=args.nsid,
1445                                       nguid=args.nguid,
1446                                       eui64=args.eui64,
1447                                       uuid=args.uuid)
1448
1449    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
1450    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1451    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
1452    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
1453    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
1454    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
1455    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
1456    p.set_defaults(func=nvmf_subsystem_add_ns)
1457
1458    def nvmf_subsystem_remove_ns(args):
1459        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
1460                                          nqn=args.nqn,
1461                                          nsid=args.nsid)
1462
1463    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
1464    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1465    p.add_argument('nsid', help='The requested NSID', type=int)
1466    p.set_defaults(func=nvmf_subsystem_remove_ns)
1467
1468    def nvmf_subsystem_add_host(args):
1469        rpc.nvmf.nvmf_subsystem_add_host(args.client,
1470                                         nqn=args.nqn,
1471                                         host=args.host)
1472
1473    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
1474    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1475    p.add_argument('host', help='Host NQN to allow')
1476    p.set_defaults(func=nvmf_subsystem_add_host)
1477
1478    def nvmf_subsystem_remove_host(args):
1479        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
1480                                            nqn=args.nqn,
1481                                            host=args.host)
1482
1483    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
1484    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1485    p.add_argument('host', help='Host NQN to remove')
1486    p.set_defaults(func=nvmf_subsystem_remove_host)
1487
1488    def nvmf_subsystem_allow_any_host(args):
1489        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
1490                                               nqn=args.nqn,
1491                                               disable=args.disable)
1492
1493    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
1494    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1495    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
1496    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
1497    p.set_defaults(func=nvmf_subsystem_allow_any_host)
1498
1499    # pmem
1500    def create_pmem_pool(args):
1501        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
1502        rpc.pmem.create_pmem_pool(args.client,
1503                                  pmem_file=args.pmem_file,
1504                                  num_blocks=num_blocks,
1505                                  block_size=args.block_size)
1506
1507    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
1508    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1509    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
1510    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
1511    p.set_defaults(func=create_pmem_pool)
1512
1513    def pmem_pool_info(args):
1514        print_dict(rpc.pmem.pmem_pool_info(args.client,
1515                                           pmem_file=args.pmem_file))
1516
1517    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
1518    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1519    p.set_defaults(func=pmem_pool_info)
1520
1521    def delete_pmem_pool(args):
1522        rpc.pmem.delete_pmem_pool(args.client,
1523                                  pmem_file=args.pmem_file)
1524
1525    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
1526    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1527    p.set_defaults(func=delete_pmem_pool)
1528
1529    # subsystem
1530    def get_subsystems(args):
1531        print_dict(rpc.subsystem.get_subsystems(args.client))
1532
1533    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
1534    entry contain (unsorted) array of subsystems it depends on.""")
1535    p.set_defaults(func=get_subsystems)
1536
1537    def get_subsystem_config(args):
1538        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
1539
1540    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
1541    p.add_argument('name', help='Name of subsystem to query')
1542    p.set_defaults(func=get_subsystem_config)
1543
1544    # vhost
1545    def set_vhost_controller_coalescing(args):
1546        rpc.vhost.set_vhost_controller_coalescing(args.client,
1547                                                  ctrlr=args.ctrlr,
1548                                                  delay_base_us=args.delay_base_us,
1549                                                  iops_threshold=args.iops_threshold)
1550
1551    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
1552    p.add_argument('ctrlr', help='controller name')
1553    p.add_argument('delay_base_us', help='Base delay time', type=int)
1554    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
1555    p.set_defaults(func=set_vhost_controller_coalescing)
1556
1557    def construct_vhost_scsi_controller(args):
1558        rpc.vhost.construct_vhost_scsi_controller(args.client,
1559                                                  ctrlr=args.ctrlr,
1560                                                  cpumask=args.cpumask)
1561
1562    p = subparsers.add_parser(
1563        'construct_vhost_scsi_controller', help='Add new vhost controller')
1564    p.add_argument('ctrlr', help='controller name')
1565    p.add_argument('--cpumask', help='cpu mask for this controller')
1566    p.set_defaults(func=construct_vhost_scsi_controller)
1567
1568    def add_vhost_scsi_lun(args):
1569        rpc.vhost.add_vhost_scsi_lun(args.client,
1570                                     ctrlr=args.ctrlr,
1571                                     scsi_target_num=args.scsi_target_num,
1572                                     bdev_name=args.bdev_name)
1573
1574    p = subparsers.add_parser('add_vhost_scsi_lun',
1575                              help='Add lun to vhost controller')
1576    p.add_argument('ctrlr', help='conntroller name where add lun')
1577    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1578    p.add_argument('bdev_name', help='bdev name')
1579    p.set_defaults(func=add_vhost_scsi_lun)
1580
1581    def remove_vhost_scsi_target(args):
1582        rpc.vhost.remove_vhost_scsi_target(args.client,
1583                                           ctrlr=args.ctrlr,
1584                                           scsi_target_num=args.scsi_target_num)
1585
1586    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
1587    p.add_argument('ctrlr', help='controller name to remove target from')
1588    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1589    p.set_defaults(func=remove_vhost_scsi_target)
1590
1591    def construct_vhost_blk_controller(args):
1592        rpc.vhost.construct_vhost_blk_controller(args.client,
1593                                                 ctrlr=args.ctrlr,
1594                                                 dev_name=args.dev_name,
1595                                                 cpumask=args.cpumask,
1596                                                 readonly=args.readonly)
1597
1598    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
1599    p.add_argument('ctrlr', help='controller name')
1600    p.add_argument('dev_name', help='device name')
1601    p.add_argument('--cpumask', help='cpu mask for this controller')
1602    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1603    p.set_defaults(func=construct_vhost_blk_controller)
1604
1605    def construct_vhost_nvme_controller(args):
1606        rpc.vhost.construct_vhost_nvme_controller(args.client,
1607                                                  ctrlr=args.ctrlr,
1608                                                  io_queues=args.io_queues,
1609                                                  cpumask=args.cpumask)
1610
1611    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
1612    p.add_argument('ctrlr', help='controller name')
1613    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
1614    p.add_argument('--cpumask', help='cpu mask for this controller')
1615    p.set_defaults(func=construct_vhost_nvme_controller)
1616
1617    def add_vhost_nvme_ns(args):
1618        rpc.vhost.add_vhost_nvme_ns(args.client,
1619                                    ctrlr=args.ctrlr,
1620                                    bdev_name=args.bdev_name)
1621
1622    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
1623    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
1624    p.add_argument('bdev_name', help='block device name for a new Namespace')
1625    p.set_defaults(func=add_vhost_nvme_ns)
1626
1627    def get_vhost_controllers(args):
1628        print_dict(rpc.vhost.get_vhost_controllers(args.client, args.name))
1629
1630    p = subparsers.add_parser('get_vhost_controllers', help='List all or specific vhost controller(s)')
1631    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
1632    p.set_defaults(func=get_vhost_controllers)
1633
1634    def remove_vhost_controller(args):
1635        rpc.vhost.remove_vhost_controller(args.client,
1636                                          ctrlr=args.ctrlr)
1637
1638    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
1639    p.add_argument('ctrlr', help='controller name')
1640    p.set_defaults(func=remove_vhost_controller)
1641
1642    def construct_virtio_dev(args):
1643        print_array(rpc.vhost.construct_virtio_dev(args.client,
1644                                                   name=args.name,
1645                                                   trtype=args.trtype,
1646                                                   traddr=args.traddr,
1647                                                   dev_type=args.dev_type,
1648                                                   vq_count=args.vq_count,
1649                                                   vq_size=args.vq_size))
1650
1651    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
1652    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
1653    remote side. Result is array of added bdevs.""")
1654    p.add_argument('name', help="Use this name as base for new created bdevs")
1655    p.add_argument('-t', '--trtype',
1656                   help='Virtio target transport type: pci or user', required=True)
1657    p.add_argument('-a', '--traddr',
1658                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
1659    p.add_argument('-d', '--dev-type',
1660                   help='Device type: blk or scsi', required=True)
1661    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1662    p.add_argument('--vq-size', help='Size of each queue', type=int)
1663    p.set_defaults(func=construct_virtio_dev)
1664
1665    def construct_virtio_user_scsi_bdev(args):
1666        print_array(rpc.vhost.construct_virtio_user_scsi_bdev(args.client,
1667                                                              path=args.path,
1668                                                              name=args.name,
1669                                                              vq_count=args.vq_count,
1670                                                              vq_size=args.vq_size))
1671
1672    p = subparsers.add_parser('construct_virtio_user_scsi_bdev', help="""Connect to virtio user scsi device.
1673    This imply scan and add bdevs offered by remote side.
1674    Result is array of added bdevs.""")
1675    p.add_argument('path', help='Path to Virtio SCSI socket')
1676    p.add_argument('name', help="""Use this name as base instead of 'VirtioScsiN'
1677    Base will be used to construct new bdev's found on target by adding 't<TARGET_ID>' sufix.""")
1678    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1679    p.add_argument('--vq-size', help='Size of each queue', type=int)
1680    p.set_defaults(func=construct_virtio_user_scsi_bdev)
1681
1682    def construct_virtio_pci_scsi_bdev(args):
1683        print_array(rpc.vhost.construct_virtio_pci_scsi_bdev(args.client,
1684                                                             pci_address=args.pci_address,
1685                                                             name=args.name))
1686
1687    p = subparsers.add_parser('construct_virtio_pci_scsi_bdev', help="""Create a Virtio
1688    SCSI device from a virtio-pci device.""")
1689    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1690    domain.bus.device.function format""")
1691    p.add_argument('name', help="""Name for the virtio device.
1692    It will be inhereted by all created bdevs, which are named n the following format: <name>t<target_id>""")
1693    p.set_defaults(func=construct_virtio_pci_scsi_bdev)
1694
1695    def get_virtio_scsi_devs(args):
1696        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client))
1697
1698    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
1699    p.set_defaults(func=get_virtio_scsi_devs)
1700
1701    def remove_virtio_scsi_bdev(args):
1702        rpc.vhost.remove_virtio_scsi_bdev(args.client,
1703                                          name=args.name)
1704
1705    p = subparsers.add_parser('remove_virtio_scsi_bdev', help="""Remove a Virtio-SCSI device
1706    This will delete all bdevs exposed by this device (this call is deprecated - please use remove_virtio_bdev call instead).""")
1707    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1708    p.set_defaults(func=remove_virtio_scsi_bdev)
1709
1710    def remove_virtio_bdev(args):
1711        rpc.vhost.remove_virtio_bdev(args.client,
1712                                     name=args.name)
1713
1714    p = subparsers.add_parser('remove_virtio_bdev', help="""Remove a Virtio device
1715    This will delete all bdevs exposed by this device""")
1716    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1717    p.set_defaults(func=remove_virtio_bdev)
1718
1719    def construct_virtio_user_blk_bdev(args):
1720        print(rpc.vhost.construct_virtio_user_blk_bdev(args.client,
1721                                                       path=args.path,
1722                                                       name=args.name,
1723                                                       vq_count=args.vq_count,
1724                                                       vq_size=args.vq_size))
1725
1726    p = subparsers.add_parser('construct_virtio_user_blk_bdev', help='Connect to a virtio user blk device.')
1727    p.add_argument('path', help='Path to Virtio BLK socket')
1728    p.add_argument('name', help='Name for the bdev')
1729    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1730    p.add_argument('--vq-size', help='Size of each queue', type=int)
1731    p.set_defaults(func=construct_virtio_user_blk_bdev)
1732
1733    def construct_virtio_pci_blk_bdev(args):
1734        print(rpc.vhost.construct_virtio_pci_blk_bdev(args.client,
1735                                                      pci_address=args.pci_address,
1736                                                      name=args.name))
1737
1738    p = subparsers.add_parser('construct_virtio_pci_blk_bdev', help='Create a Virtio Blk device from a virtio-pci device.')
1739    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1740    domain.bus.device.function format""")
1741    p.add_argument('name', help='Name for the bdev')
1742    p.set_defaults(func=construct_virtio_pci_blk_bdev)
1743
1744    # ioat
1745    def scan_ioat_copy_engine(args):
1746        pci_whitelist = []
1747        if args.pci_whitelist:
1748            for w in args.pci_whitelist.strip().split(" "):
1749                pci_whitelist.append(w)
1750        rpc.ioat.scan_ioat_copy_engine(args.client, pci_whitelist)
1751
1752    p = subparsers.add_parser('scan_ioat_copy_engine', help='Set scan and enable IOAT copy engine offload.')
1753    p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in
1754    domain:bus:device.function format or domain.bus.device.function format""")
1755    p.set_defaults(func=scan_ioat_copy_engine)
1756
1757    # send_nvme_cmd
1758    def send_nvme_cmd(args):
1759        print_dict(rpc.nvme.send_nvme_cmd(args.client,
1760                                          name=args.nvme_name,
1761                                          cmd_type=args.cmd_type,
1762                                          data_direction=args.data_direction,
1763                                          cmdbuf=args.cmdbuf,
1764                                          data=args.data,
1765                                          metadata=args.metadata,
1766                                          data_len=args.data_length,
1767                                          metadata_len=args.metadata_length,
1768                                          timeout_ms=args.timeout_ms))
1769
1770    p = subparsers.add_parser('send_nvme_cmd', help='NVMe passthrough cmd.')
1771    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
1772    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
1773    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
1774    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
1775    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
1776    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
1777    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
1778    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
1779    p.add_argument('-T', '--timeout-ms',
1780                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int, default=0)
1781    p.set_defaults(func=send_nvme_cmd)
1782
1783    args = parser.parse_args()
1784
1785    try:
1786        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.verbose, args.timeout)
1787        args.func(args)
1788    except JSONRPCException as ex:
1789        print("Exception:")
1790        print(ex.message)
1791        exit(1)
1792