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