xref: /spdk/scripts/rpc.py (revision 0f842e860eb333e86781d5034536fd58163e8780)
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            no_discovery_auth=args.no_discovery_auth,
497            req_discovery_auth=args.req_discovery_auth,
498            req_discovery_auth_mutual=args.req_discovery_auth_mutual,
499            discovery_auth_group=args.discovery_auth_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', '--no-discovery-auth', help="""CHAP for discovery session should be disabled.
516    *** Mutually exclusive with --req-discovery-auth""", action='store_true')
517    p.add_argument('-r', '--req-discovery-auth', help="""CHAP for discovery session should be required.
518    *** Mutually exclusive with --no-discovery-auth""", action='store_true')
519    p.add_argument('-m', '--req-discovery-auth-mutual', help='CHAP for discovery session should be mutual', action='store_true')
520    p.add_argument('-g', '--discovery-auth-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 get_portal_groups(args):
535        print_dict(rpc.iscsi.get_portal_groups(args.client))
536
537    p = subparsers.add_parser(
538        'get_portal_groups', help='Display current portal group configuration')
539    p.set_defaults(func=get_portal_groups)
540
541    @call_cmd
542    def get_initiator_groups(args):
543        print_dict(rpc.iscsi.get_initiator_groups(args.client))
544
545    p = subparsers.add_parser('get_initiator_groups',
546                              help='Display current initiator group configuration')
547    p.set_defaults(func=get_initiator_groups)
548
549    @call_cmd
550    def get_target_nodes(args):
551        print_dict(rpc.iscsi.get_target_nodes(args.client))
552
553    p = subparsers.add_parser('get_target_nodes', help='Display target nodes')
554    p.set_defaults(func=get_target_nodes)
555
556    @call_cmd
557    def construct_target_node(args):
558        luns = []
559        for u in args.bdev_name_id_pairs.strip().split(" "):
560            bdev_name, lun_id = u.split(":")
561            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
562
563        pg_ig_maps = []
564        for u in args.pg_ig_mappings.strip().split(" "):
565            pg, ig = u.split(":")
566            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
567
568        rpc.iscsi.construct_target_node(
569            args.client,
570            luns=luns,
571            pg_ig_maps=pg_ig_maps,
572            name=args.name,
573            alias_name=args.alias_name,
574            queue_depth=args.queue_depth,
575            chap_group=args.chap_group,
576            disable_chap=args.disable_chap,
577            require_chap=args.require_chap,
578            mutual_chap=args.mutual_chap,
579            header_digest=args.header_digest,
580            data_digest=args.data_digest)
581
582    p = subparsers.add_parser('construct_target_node',
583                              help='Add a target node')
584    p.add_argument('name', help='Target node name (ASCII)')
585    p.add_argument('alias_name', help='Target node alias name (ASCII)')
586    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
587    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
588    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
589    *** The bdevs must pre-exist ***
590    *** LUN0 (id = 0) is required ***
591    *** bdevs names cannot contain space or colon characters ***""")
592    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
593    Whitespace separated, quoted, mapping defined with colon
594    separated list of "tags" (int > 0)
595    Example: '1:1 2:2 2:1'
596    *** The Portal/Initiator Groups must be precreated ***""")
597    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
598    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
599    *** Authentication group must be precreated ***""", type=int, default=0)
600    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
601    *** Mutually exclusive with --require-chap ***""", action='store_true')
602    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
603    *** Mutually exclusive with --disable-chap ***""", action='store_true')
604    p.add_argument(
605        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
606    p.add_argument('-H', '--header-digest',
607                   help='Header Digest should be required for this target node.', action='store_true')
608    p.add_argument('-D', '--data-digest',
609                   help='Data Digest should be required for this target node.', action='store_true')
610    p.set_defaults(func=construct_target_node)
611
612    @call_cmd
613    def target_node_add_lun(args):
614        rpc.iscsi.target_node_add_lun(
615            args.client,
616            name=args.name,
617            bdev_name=args.bdev_name,
618            lun_id=args.lun_id)
619
620    p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node')
621    p.add_argument('name', help='Target node name (ASCII)')
622    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
623    *** bdev name cannot contain space or colon characters ***""")
624    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
625    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
626    p.set_defaults(func=target_node_add_lun)
627
628    @call_cmd
629    def add_pg_ig_maps(args):
630        pg_ig_maps = []
631        for u in args.pg_ig_mappings.strip().split(" "):
632            pg, ig = u.split(":")
633            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
634        rpc.iscsi.add_pg_ig_maps(
635            args.client,
636            pg_ig_maps=pg_ig_maps,
637            name=args.name)
638
639    p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node')
640    p.add_argument('name', help='Target node name (ASCII)')
641    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
642    Whitespace separated, quoted, mapping defined with colon
643    separated list of "tags" (int > 0)
644    Example: '1:1 2:2 2:1'
645    *** The Portal/Initiator Groups must be precreated ***""")
646    p.set_defaults(func=add_pg_ig_maps)
647
648    @call_cmd
649    def delete_pg_ig_maps(args):
650        pg_ig_maps = []
651        for u in args.pg_ig_mappings.strip().split(" "):
652            pg, ig = u.split(":")
653            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
654        rpc.iscsi.delete_pg_ig_maps(
655            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
656
657    p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node')
658    p.add_argument('name', help='Target node name (ASCII)')
659    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
660    Whitespace separated, quoted, mapping defined with colon
661    separated list of "tags" (int > 0)
662    Example: '1:1 2:2 2:1'
663    *** The Portal/Initiator Groups must be precreated ***""")
664    p.set_defaults(func=delete_pg_ig_maps)
665
666    @call_cmd
667    def add_portal_group(args):
668        portals = []
669        for p in args.portal_list:
670            ip, separator, port_cpumask = p.rpartition(':')
671            split_port_cpumask = port_cpumask.split('@')
672            if len(split_port_cpumask) == 1:
673                port = port_cpumask
674                portals.append({'host': ip, 'port': port})
675            else:
676                port = split_port_cpumask[0]
677                cpumask = split_port_cpumask[1]
678                portals.append({'host': ip, 'port': port, 'cpumask': cpumask})
679        rpc.iscsi.add_portal_group(
680            args.client,
681            portals=portals,
682            tag=args.tag)
683
684    p = subparsers.add_parser('add_portal_group', help='Add a portal group')
685    p.add_argument(
686        'tag', help='Portal group tag (unique, integer > 0)', type=int)
687    p.add_argument('portal_list', nargs=argparse.REMAINDER, help="""List of portals in 'host:port@cpumask' format, separated by whitespace
688    (cpumask is optional and can be skipped)
689    Example: '192.168.100.100:3260' '192.168.100.100:3261' '192.168.100.100:3262@0x1""")
690    p.set_defaults(func=add_portal_group)
691
692    @call_cmd
693    def add_initiator_group(args):
694        initiators = []
695        netmasks = []
696        for i in args.initiator_list.strip().split(' '):
697            initiators.append(i)
698        for n in args.netmask_list.strip().split(' '):
699            netmasks.append(n)
700        rpc.iscsi.add_initiator_group(
701            args.client,
702            tag=args.tag,
703            initiators=initiators,
704            netmasks=netmasks)
705
706    p = subparsers.add_parser('add_initiator_group',
707                              help='Add an initiator group')
708    p.add_argument(
709        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
710    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
711    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
712    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
713    Example: '255.255.0.0 255.248.0.0' etc""")
714    p.set_defaults(func=add_initiator_group)
715
716    @call_cmd
717    def add_initiators_to_initiator_group(args):
718        initiators = None
719        netmasks = None
720        if args.initiator_list:
721            initiators = []
722            for i in args.initiator_list.strip().split(' '):
723                initiators.append(i)
724        if args.netmask_list:
725            netmasks = []
726            for n in args.netmask_list.strip().split(' '):
727                netmasks.append(n)
728        rpc.iscsi.add_initiators_to_initiator_group(
729            args.client,
730            tag=args.tag,
731            initiators=initiators,
732            netmasks=netmasks)
733
734    p = subparsers.add_parser('add_initiators_to_initiator_group',
735                              help='Add initiators to an existing initiator group')
736    p.add_argument(
737        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
738    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
739    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
740    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
741    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
742    p.set_defaults(func=add_initiators_to_initiator_group)
743
744    @call_cmd
745    def delete_initiators_from_initiator_group(args):
746        initiators = None
747        netmasks = None
748        if args.initiator_list:
749            initiators = []
750            for i in args.initiator_list.strip().split(' '):
751                initiators.append(i)
752        if args.netmask_list:
753            netmasks = []
754            for n in args.netmask_list.strip().split(' '):
755                netmasks.append(n)
756        rpc.iscsi.delete_initiators_from_initiator_group(
757            args.client,
758            tag=args.tag,
759            initiators=initiators,
760            netmasks=netmasks)
761
762    p = subparsers.add_parser('delete_initiators_from_initiator_group',
763                              help='Delete initiators from an existing initiator group')
764    p.add_argument(
765        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
766    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
767    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
768    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
769    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
770    p.set_defaults(func=delete_initiators_from_initiator_group)
771
772    @call_cmd
773    def delete_target_node(args):
774        rpc.iscsi.delete_target_node(
775            args.client, target_node_name=args.target_node_name)
776
777    p = subparsers.add_parser('delete_target_node',
778                              help='Delete a target node')
779    p.add_argument('target_node_name',
780                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
781    p.set_defaults(func=delete_target_node)
782
783    @call_cmd
784    def delete_portal_group(args):
785        rpc.iscsi.delete_portal_group(args.client, tag=args.tag)
786
787    p = subparsers.add_parser('delete_portal_group',
788                              help='Delete a portal group')
789    p.add_argument(
790        'tag', help='Portal group tag (unique, integer > 0)', type=int)
791    p.set_defaults(func=delete_portal_group)
792
793    @call_cmd
794    def delete_initiator_group(args):
795        rpc.iscsi.delete_initiator_group(args.client, tag=args.tag)
796
797    p = subparsers.add_parser('delete_initiator_group',
798                              help='Delete an initiator group')
799    p.add_argument(
800        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
801    p.set_defaults(func=delete_initiator_group)
802
803    @call_cmd
804    def get_iscsi_connections(args):
805        print_dict(rpc.iscsi.get_iscsi_connections(args.client))
806
807    p = subparsers.add_parser('get_iscsi_connections',
808                              help='Display iSCSI connections')
809    p.set_defaults(func=get_iscsi_connections)
810
811    @call_cmd
812    def get_iscsi_global_params(args):
813        print_dict(rpc.iscsi.get_iscsi_global_params(args.client))
814
815    p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters')
816    p.set_defaults(func=get_iscsi_global_params)
817
818    @call_cmd
819    def get_scsi_devices(args):
820        print_dict(rpc.iscsi.get_scsi_devices(args.client))
821
822    p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices')
823    p.set_defaults(func=get_scsi_devices)
824
825    # log
826    @call_cmd
827    def set_trace_flag(args):
828        rpc.log.set_trace_flag(args.client, flag=args.flag)
829
830    p = subparsers.add_parser('set_trace_flag', help='set trace flag')
831    p.add_argument(
832        'flag', help='trace mask we want to set. (for example "nvme").')
833    p.set_defaults(func=set_trace_flag)
834
835    @call_cmd
836    def clear_trace_flag(args):
837        rpc.log.clear_trace_flag(args.client, flag=args.flag)
838
839    p = subparsers.add_parser('clear_trace_flag', help='clear trace flag')
840    p.add_argument(
841        'flag', help='trace mask we want to clear. (for example "nvme").')
842    p.set_defaults(func=clear_trace_flag)
843
844    @call_cmd
845    def get_trace_flags(args):
846        print_dict(rpc.log.get_trace_flags(args.client))
847
848    p = subparsers.add_parser('get_trace_flags', help='get trace flags')
849    p.set_defaults(func=get_trace_flags)
850
851    @call_cmd
852    def set_log_level(args):
853        rpc.log.set_log_level(args.client, level=args.level)
854
855    p = subparsers.add_parser('set_log_level', help='set log level')
856    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
857    p.set_defaults(func=set_log_level)
858
859    @call_cmd
860    def get_log_level(args):
861        print_dict(rpc.log.get_log_level(args.client))
862
863    p = subparsers.add_parser('get_log_level', help='get log level')
864    p.set_defaults(func=get_log_level)
865
866    @call_cmd
867    def set_log_print_level(args):
868        rpc.log.set_log_print_level(args.client, level=args.level)
869
870    p = subparsers.add_parser('set_log_print_level', help='set log print level')
871    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
872    p.set_defaults(func=set_log_print_level)
873
874    @call_cmd
875    def get_log_print_level(args):
876        print_dict(rpc.log.get_log_print_level(args.client))
877
878    p = subparsers.add_parser('get_log_print_level', help='get log print level')
879    p.set_defaults(func=get_log_print_level)
880
881    # lvol
882    @call_cmd
883    def construct_lvol_store(args):
884        print(rpc.lvol.construct_lvol_store(args.client,
885                                            bdev_name=args.bdev_name,
886                                            lvs_name=args.lvs_name,
887                                            cluster_sz=args.cluster_sz))
888
889    p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev')
890    p.add_argument('bdev_name', help='base bdev name')
891    p.add_argument('lvs_name', help='name for lvol store')
892    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
893    p.set_defaults(func=construct_lvol_store)
894
895    @call_cmd
896    def rename_lvol_store(args):
897        rpc.lvol.rename_lvol_store(args.client,
898                                   old_name=args.old_name,
899                                   new_name=args.new_name)
900
901    p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
902    p.add_argument('old_name', help='old name')
903    p.add_argument('new_name', help='new name')
904    p.set_defaults(func=rename_lvol_store)
905
906    @call_cmd
907    def construct_lvol_bdev(args):
908        print(rpc.lvol.construct_lvol_bdev(args.client,
909                                           lvol_name=args.lvol_name,
910                                           size=args.size * 1024 * 1024,
911                                           thin_provision=args.thin_provision,
912                                           uuid=args.uuid,
913                                           lvs_name=args.lvs_name))
914
915    p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
916    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
917    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
918    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
919    p.add_argument('lvol_name', help='name for this lvol')
920    p.add_argument('size', help='size in MiB for this bdev', type=int)
921    p.set_defaults(func=construct_lvol_bdev)
922
923    @call_cmd
924    def snapshot_lvol_bdev(args):
925        print(rpc.lvol.snapshot_lvol_bdev(args.client,
926                                          lvol_name=args.lvol_name,
927                                          snapshot_name=args.snapshot_name))
928
929    p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
930    p.add_argument('lvol_name', help='lvol bdev name')
931    p.add_argument('snapshot_name', help='lvol snapshot name')
932    p.set_defaults(func=snapshot_lvol_bdev)
933
934    @call_cmd
935    def clone_lvol_bdev(args):
936        print(rpc.lvol.clone_lvol_bdev(args.client,
937                                       snapshot_name=args.snapshot_name,
938                                       clone_name=args.clone_name))
939
940    p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
941    p.add_argument('snapshot_name', help='lvol snapshot name')
942    p.add_argument('clone_name', help='lvol clone name')
943    p.set_defaults(func=clone_lvol_bdev)
944
945    @call_cmd
946    def rename_lvol_bdev(args):
947        rpc.lvol.rename_lvol_bdev(args.client,
948                                  old_name=args.old_name,
949                                  new_name=args.new_name)
950
951    p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name')
952    p.add_argument('old_name', help='lvol bdev name')
953    p.add_argument('new_name', help='new lvol name')
954    p.set_defaults(func=rename_lvol_bdev)
955
956    @call_cmd
957    def inflate_lvol_bdev(args):
958        rpc.lvol.inflate_lvol_bdev(args.client,
959                                   name=args.name)
960
961    p = subparsers.add_parser('inflate_lvol_bdev', help='Make thin provisioned lvol a thick provisioned lvol')
962    p.add_argument('name', help='lvol bdev name')
963    p.set_defaults(func=inflate_lvol_bdev)
964
965    @call_cmd
966    def decouple_parent_lvol_bdev(args):
967        rpc.lvol.decouple_parent_lvol_bdev(args.client,
968                                           name=args.name)
969
970    p = subparsers.add_parser('decouple_parent_lvol_bdev', help='Decouple parent of lvol')
971    p.add_argument('name', help='lvol bdev name')
972    p.set_defaults(func=decouple_parent_lvol_bdev)
973
974    @call_cmd
975    def resize_lvol_bdev(args):
976        rpc.lvol.resize_lvol_bdev(args.client,
977                                  name=args.name,
978                                  size=args.size * 1024 * 1024)
979
980    p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev')
981    p.add_argument('name', help='lvol bdev name')
982    p.add_argument('size', help='new size in MiB for this bdev', type=int)
983    p.set_defaults(func=resize_lvol_bdev)
984
985    @call_cmd
986    def destroy_lvol_bdev(args):
987        rpc.lvol.destroy_lvol_bdev(args.client,
988                                   name=args.name)
989
990    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
991    p.add_argument('name', help='lvol bdev name')
992    p.set_defaults(func=destroy_lvol_bdev)
993
994    @call_cmd
995    def destroy_lvol_store(args):
996        rpc.lvol.destroy_lvol_store(args.client,
997                                    uuid=args.uuid,
998                                    lvs_name=args.lvs_name)
999
1000    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
1001    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1002    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1003    p.set_defaults(func=destroy_lvol_store)
1004
1005    @call_cmd
1006    def get_lvol_stores(args):
1007        print_dict(rpc.lvol.get_lvol_stores(args.client,
1008                                            uuid=args.uuid,
1009                                            lvs_name=args.lvs_name))
1010
1011    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
1012    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1013    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1014    p.set_defaults(func=get_lvol_stores)
1015
1016    @call_cmd
1017    def get_raid_bdevs(args):
1018        print_array(rpc.bdev.get_raid_bdevs(args.client,
1019                                            category=args.category))
1020
1021    p = subparsers.add_parser('get_raid_bdevs', help="""This is used to list all the raid bdev names based on the input category
1022    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
1023    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
1024    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
1025    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
1026    p.add_argument('category', help='all or online or configuring or offline')
1027    p.set_defaults(func=get_raid_bdevs)
1028
1029    @call_cmd
1030    def construct_raid_bdev(args):
1031        base_bdevs = []
1032        for u in args.base_bdevs.strip().split(" "):
1033            base_bdevs.append(u)
1034
1035        rpc.bdev.construct_raid_bdev(args.client,
1036                                     name=args.name,
1037                                     strip_size=args.strip_size,
1038                                     raid_level=args.raid_level,
1039                                     base_bdevs=base_bdevs)
1040    p = subparsers.add_parser('construct_raid_bdev', help='Construct new raid bdev')
1041    p.add_argument('-n', '--name', help='raid bdev name', required=True)
1042    p.add_argument('-s', '--strip-size', help='strip size in KB', type=int, required=True)
1043    p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', type=int, required=True)
1044    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
1045    p.set_defaults(func=construct_raid_bdev)
1046
1047    @call_cmd
1048    def destroy_raid_bdev(args):
1049        rpc.bdev.destroy_raid_bdev(args.client,
1050                                   name=args.name)
1051    p = subparsers.add_parser('destroy_raid_bdev', help='Destroy existing raid bdev')
1052    p.add_argument('name', help='raid bdev name')
1053    p.set_defaults(func=destroy_raid_bdev)
1054
1055    # split
1056    @call_cmd
1057    def construct_split_vbdev(args):
1058        print_array(rpc.bdev.construct_split_vbdev(args.client,
1059                                                   base_bdev=args.base_bdev,
1060                                                   split_count=args.split_count,
1061                                                   split_size_mb=args.split_size_mb))
1062
1063    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
1064    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
1065    available (during examination process).""")
1066    p.add_argument('base_bdev', help='base bdev name')
1067    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
1068    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
1069    exceed the base bdev size.""", type=int)
1070    p.set_defaults(func=construct_split_vbdev)
1071
1072    @call_cmd
1073    def destruct_split_vbdev(args):
1074        rpc.bdev.destruct_split_vbdev(args.client,
1075                                      base_bdev=args.base_bdev)
1076
1077    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
1078    p.add_argument('base_bdev', help='base bdev name')
1079    p.set_defaults(func=destruct_split_vbdev)
1080
1081    # nbd
1082    @call_cmd
1083    def start_nbd_disk(args):
1084        print(rpc.nbd.start_nbd_disk(args.client,
1085                                     bdev_name=args.bdev_name,
1086                                     nbd_device=args.nbd_device))
1087
1088    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
1089    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
1090    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.')
1091    p.set_defaults(func=start_nbd_disk)
1092
1093    @call_cmd
1094    def stop_nbd_disk(args):
1095        rpc.nbd.stop_nbd_disk(args.client,
1096                              nbd_device=args.nbd_device)
1097
1098    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
1099    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
1100    p.set_defaults(func=stop_nbd_disk)
1101
1102    @call_cmd
1103    def get_nbd_disks(args):
1104        print_dict(rpc.nbd.get_nbd_disks(args.client,
1105                                         nbd_device=args.nbd_device))
1106
1107    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
1108    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
1109    p.set_defaults(func=get_nbd_disks)
1110
1111    # net
1112    @call_cmd
1113    def add_ip_address(args):
1114        rpc.net.add_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1115
1116    p = subparsers.add_parser('add_ip_address', help='Add IP address')
1117    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1118    p.add_argument('ip_addr', help='ip address will be added.')
1119    p.set_defaults(func=add_ip_address)
1120
1121    @call_cmd
1122    def delete_ip_address(args):
1123        rpc.net.delete_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1124
1125    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
1126    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1127    p.add_argument('ip_addr', help='ip address will be deleted.')
1128    p.set_defaults(func=delete_ip_address)
1129
1130    @call_cmd
1131    def get_interfaces(args):
1132        print_dict(rpc.net.get_interfaces(args.client))
1133
1134    p = subparsers.add_parser(
1135        'get_interfaces', help='Display current interface list')
1136    p.set_defaults(func=get_interfaces)
1137
1138    # NVMe-oF
1139    @call_cmd
1140    def set_nvmf_target_options(args):
1141        rpc.nvmf.set_nvmf_target_options(args.client,
1142                                         max_queue_depth=args.max_queue_depth,
1143                                         max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1144                                         in_capsule_data_size=args.in_capsule_data_size,
1145                                         max_io_size=args.max_io_size,
1146                                         max_subsystems=args.max_subsystems,
1147                                         io_unit_size=args.io_unit_size)
1148
1149    p = subparsers.add_parser('set_nvmf_target_options', help='Set NVMf target options')
1150    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1151    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1152    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1153    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1154    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int)
1155    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1156    p.set_defaults(func=set_nvmf_target_options)
1157
1158    @call_cmd
1159    def set_nvmf_target_config(args):
1160        rpc.nvmf.set_nvmf_target_config(args.client,
1161                                        acceptor_poll_rate=args.acceptor_poll_rate)
1162
1163    p = subparsers.add_parser('set_nvmf_target_config', help='Set NVMf target config')
1164    p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
1165    p.set_defaults(func=set_nvmf_target_config)
1166
1167    @call_cmd
1168    def get_nvmf_subsystems(args):
1169        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client))
1170
1171    p = subparsers.add_parser('get_nvmf_subsystems',
1172                              help='Display nvmf subsystems')
1173    p.set_defaults(func=get_nvmf_subsystems)
1174
1175    @call_cmd
1176    def construct_nvmf_subsystem(args):
1177        listen_addresses = None
1178        hosts = None
1179        namespaces = None
1180        if args.listen:
1181            listen_addresses = [
1182                dict(
1183                    u.split(
1184                        ":",
1185                        1) for u in a.split(" ")) for a in args.listen.split(",")]
1186
1187        if args.hosts:
1188            hosts = []
1189            for u in args.hosts.strip().split(" "):
1190                hosts.append(u)
1191
1192        if args.namespaces:
1193            namespaces = []
1194            for u in args.namespaces.strip().split(" "):
1195                bdev_name = u
1196                nsid = 0
1197                if ':' in u:
1198                    (bdev_name, nsid) = u.split(":")
1199
1200                ns_params = {'bdev_name': bdev_name}
1201
1202                nsid = int(nsid)
1203                if nsid != 0:
1204                    ns_params['nsid'] = nsid
1205
1206                namespaces.append(ns_params)
1207
1208        rpc.nvmf.construct_nvmf_subsystem(args.client,
1209                                          nqn=args.nqn,
1210                                          listen_addresses=listen_addresses,
1211                                          hosts=hosts,
1212                                          allow_any_host=args.allow_any_host,
1213                                          serial_number=args.serial_number,
1214                                          namespaces=namespaces,
1215                                          max_namespaces=args.max_namespaces)
1216
1217    p = subparsers.add_parser('construct_nvmf_subsystem', help='Add a nvmf subsystem')
1218    p.add_argument('nqn', help='Target nqn(ASCII)')
1219    p.add_argument('listen', help="""comma-separated list of Listen <trtype:transport_name traddr:address trsvcid:port_id> pairs enclosed
1220    in quotes.  Format:  'trtype:transport0 traddr:traddr0 trsvcid:trsvcid0,trtype:transport1 traddr:traddr1 trsvcid:trsvcid1' etc
1221    Example: 'trtype:RDMA traddr:192.168.100.8 trsvcid:4420,trtype:RDMA traddr:192.168.100.9 trsvcid:4420'""")
1222    p.add_argument('hosts', help="""Whitespace-separated list of host nqn list.
1223    Format:  'nqn1 nqn2' etc
1224    Example: 'nqn.2016-06.io.spdk:init nqn.2016-07.io.spdk:init'""")
1225    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1226    p.add_argument("-s", "--serial-number", help="""
1227    Format:  'sn' etc
1228    Example: 'SPDK00000000000001'""", default='0000:00:01.0')
1229    p.add_argument("-n", "--namespaces", help="""Whitespace-separated list of namespaces
1230    Format:  'bdev_name1[:nsid1] bdev_name2[:nsid2] bdev_name3[:nsid3]' etc
1231    Example: '1:Malloc0 2:Malloc1 3:Malloc2'
1232    *** The devices must pre-exist ***""")
1233    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed to added during active connection",
1234                   type=int, default=0)
1235    p.set_defaults(func=construct_nvmf_subsystem)
1236
1237    @call_cmd
1238    def delete_nvmf_subsystem(args):
1239        rpc.nvmf.delete_nvmf_subsystem(args.client,
1240                                       nqn=args.subsystem_nqn)
1241
1242    p = subparsers.add_parser('delete_nvmf_subsystem',
1243                              help='Delete a nvmf subsystem')
1244    p.add_argument('subsystem_nqn',
1245                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
1246    p.set_defaults(func=delete_nvmf_subsystem)
1247
1248    @call_cmd
1249    def nvmf_subsystem_add_listener(args):
1250        rpc.nvmf.nvmf_subsystem_add_listener(args.client,
1251                                             nqn=args.nqn,
1252                                             trtype=args.trtype,
1253                                             traddr=args.traddr,
1254                                             adrfam=args.adrfam,
1255                                             trsvcid=args.trsvcid)
1256
1257    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
1258    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1259    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1260    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1261    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1262    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1263    p.set_defaults(func=nvmf_subsystem_add_listener)
1264
1265    @call_cmd
1266    def nvmf_subsystem_remove_listener(args):
1267        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
1268                                                nqn=args.nqn,
1269                                                trtype=args.trtype,
1270                                                traddr=args.traddr,
1271                                                adrfam=args.adrfam,
1272                                                trsvcid=args.trsvcid)
1273
1274    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
1275    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1276    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1277    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1278    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1279    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1280    p.set_defaults(func=nvmf_subsystem_remove_listener)
1281
1282    @call_cmd
1283    def nvmf_subsystem_add_ns(args):
1284        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
1285                                       nqn=args.nqn,
1286                                       bdev_name=args.bdev_name,
1287                                       nsid=args.nsid,
1288                                       nguid=args.nguid,
1289                                       eui64=args.eui64,
1290                                       uuid=args.uuid)
1291
1292    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
1293    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1294    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
1295    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
1296    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
1297    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
1298    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
1299    p.set_defaults(func=nvmf_subsystem_add_ns)
1300
1301    @call_cmd
1302    def nvmf_subsystem_remove_ns(args):
1303        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
1304                                          nqn=args.nqn,
1305                                          nsid=args.nsid)
1306
1307    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
1308    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1309    p.add_argument('nsid', help='The requested NSID', type=int)
1310    p.set_defaults(func=nvmf_subsystem_remove_ns)
1311
1312    @call_cmd
1313    def nvmf_subsystem_add_host(args):
1314        rpc.nvmf.nvmf_subsystem_add_host(args.client,
1315                                         nqn=args.nqn,
1316                                         host=args.host)
1317
1318    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
1319    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1320    p.add_argument('host', help='Host NQN to allow')
1321    p.set_defaults(func=nvmf_subsystem_add_host)
1322
1323    @call_cmd
1324    def nvmf_subsystem_remove_host(args):
1325        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
1326                                            nqn=args.nqn,
1327                                            host=args.host)
1328
1329    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
1330    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1331    p.add_argument('host', help='Host NQN to remove')
1332    p.set_defaults(func=nvmf_subsystem_remove_host)
1333
1334    @call_cmd
1335    def nvmf_subsystem_allow_any_host(args):
1336        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
1337                                               nqn=args.nqn,
1338                                               disable=args.disable)
1339
1340    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
1341    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1342    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
1343    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
1344    p.set_defaults(func=nvmf_subsystem_allow_any_host)
1345
1346    # pmem
1347    @call_cmd
1348    def create_pmem_pool(args):
1349        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
1350        rpc.pmem.create_pmem_pool(args.client,
1351                                  pmem_file=args.pmem_file,
1352                                  num_blocks=num_blocks,
1353                                  block_size=args.block_size)
1354
1355    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
1356    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1357    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
1358    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
1359    p.set_defaults(func=create_pmem_pool)
1360
1361    @call_cmd
1362    def pmem_pool_info(args):
1363        print_dict(rpc.pmem.pmem_pool_info(args.client,
1364                                           pmem_file=args.pmem_file))
1365
1366    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
1367    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1368    p.set_defaults(func=pmem_pool_info)
1369
1370    @call_cmd
1371    def delete_pmem_pool(args):
1372        rpc.pmem.delete_pmem_pool(args.client,
1373                                  pmem_file=args.pmem_file)
1374
1375    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
1376    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1377    p.set_defaults(func=delete_pmem_pool)
1378
1379    # subsystem
1380    @call_cmd
1381    def get_subsystems(args):
1382        print_dict(rpc.subsystem.get_subsystems(args.client))
1383
1384    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
1385    entry contain (unsorted) array of subsystems it depends on.""")
1386    p.set_defaults(func=get_subsystems)
1387
1388    @call_cmd
1389    def get_subsystem_config(args):
1390        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
1391
1392    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
1393    p.add_argument('name', help='Name of subsystem to query')
1394    p.set_defaults(func=get_subsystem_config)
1395
1396    # vhost
1397    @call_cmd
1398    def set_vhost_controller_coalescing(args):
1399        rpc.vhost.set_vhost_controller_coalescing(args.client,
1400                                                  ctrlr=args.ctrlr,
1401                                                  delay_base_us=args.delay_base_us,
1402                                                  iops_threshold=args.iops_threshold)
1403
1404    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
1405    p.add_argument('ctrlr', help='controller name')
1406    p.add_argument('delay_base_us', help='Base delay time', type=int)
1407    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
1408    p.set_defaults(func=set_vhost_controller_coalescing)
1409
1410    @call_cmd
1411    def construct_vhost_scsi_controller(args):
1412        rpc.vhost.construct_vhost_scsi_controller(args.client,
1413                                                  ctrlr=args.ctrlr,
1414                                                  cpumask=args.cpumask)
1415
1416    p = subparsers.add_parser(
1417        'construct_vhost_scsi_controller', help='Add new vhost controller')
1418    p.add_argument('ctrlr', help='controller name')
1419    p.add_argument('--cpumask', help='cpu mask for this controller')
1420    p.set_defaults(func=construct_vhost_scsi_controller)
1421
1422    @call_cmd
1423    def add_vhost_scsi_lun(args):
1424        rpc.vhost.add_vhost_scsi_lun(args.client,
1425                                     ctrlr=args.ctrlr,
1426                                     scsi_target_num=args.scsi_target_num,
1427                                     bdev_name=args.bdev_name)
1428
1429    p = subparsers.add_parser('add_vhost_scsi_lun',
1430                              help='Add lun to vhost controller')
1431    p.add_argument('ctrlr', help='conntroller name where add lun')
1432    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1433    p.add_argument('bdev_name', help='bdev name')
1434    p.set_defaults(func=add_vhost_scsi_lun)
1435
1436    @call_cmd
1437    def remove_vhost_scsi_target(args):
1438        rpc.vhost.remove_vhost_scsi_target(args.client,
1439                                           ctrlr=args.ctrlr,
1440                                           scsi_target_num=args.scsi_target_num)
1441
1442    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
1443    p.add_argument('ctrlr', help='controller name to remove target from')
1444    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1445    p.set_defaults(func=remove_vhost_scsi_target)
1446
1447    @call_cmd
1448    def construct_vhost_blk_controller(args):
1449        rpc.vhost.construct_vhost_blk_controller(args.client,
1450                                                 ctrlr=args.ctrlr,
1451                                                 dev_name=args.dev_name,
1452                                                 cpumask=args.cpumask,
1453                                                 readonly=args.readonly)
1454
1455    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
1456    p.add_argument('ctrlr', help='controller name')
1457    p.add_argument('dev_name', help='device name')
1458    p.add_argument('--cpumask', help='cpu mask for this controller')
1459    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1460    p.set_defaults(func=construct_vhost_blk_controller)
1461
1462    @call_cmd
1463    def construct_vhost_nvme_controller(args):
1464        rpc.vhost.construct_vhost_nvme_controller(args.client,
1465                                                  ctrlr=args.ctrlr,
1466                                                  io_queues=args.io_queues,
1467                                                  cpumask=args.cpumask)
1468
1469    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
1470    p.add_argument('ctrlr', help='controller name')
1471    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
1472    p.add_argument('--cpumask', help='cpu mask for this controller')
1473    p.set_defaults(func=construct_vhost_nvme_controller)
1474
1475    @call_cmd
1476    def add_vhost_nvme_ns(args):
1477        rpc.vhost.add_vhost_nvme_ns(args.client,
1478                                    ctrlr=args.ctrlr,
1479                                    bdev_name=args.bdev_name)
1480
1481    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
1482    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
1483    p.add_argument('bdev_name', help='block device name for a new Namespace')
1484    p.set_defaults(func=add_vhost_nvme_ns)
1485
1486    @call_cmd
1487    def get_vhost_controllers(args):
1488        print_dict(rpc.vhost.get_vhost_controllers(args.client))
1489
1490    p = subparsers.add_parser('get_vhost_controllers', help='List vhost controllers')
1491    p.set_defaults(func=get_vhost_controllers)
1492
1493    @call_cmd
1494    def remove_vhost_controller(args):
1495        rpc.vhost.remove_vhost_controller(args.client,
1496                                          ctrlr=args.ctrlr)
1497
1498    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
1499    p.add_argument('ctrlr', help='controller name')
1500    p.set_defaults(func=remove_vhost_controller)
1501
1502    @call_cmd
1503    def construct_virtio_dev(args):
1504        print_array(rpc.vhost.construct_virtio_dev(args.client,
1505                                                   name=args.name,
1506                                                   trtype=args.trtype,
1507                                                   traddr=args.traddr,
1508                                                   dev_type=args.dev_type,
1509                                                   vq_count=args.vq_count,
1510                                                   vq_size=args.vq_size))
1511
1512    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
1513    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
1514    remote side. Result is array of added bdevs.""")
1515    p.add_argument('name', help="Use this name as base for new created bdevs")
1516    p.add_argument('-t', '--trtype',
1517                   help='Virtio target transport type: pci or user', required=True)
1518    p.add_argument('-a', '--traddr',
1519                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
1520    p.add_argument('-d', '--dev-type',
1521                   help='Device type: blk or scsi', required=True)
1522    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1523    p.add_argument('--vq-size', help='Size of each queue', type=int)
1524    p.set_defaults(func=construct_virtio_dev)
1525
1526    @call_cmd
1527    def construct_virtio_user_scsi_bdev(args):
1528        print_array(rpc.vhost.construct_virtio_user_scsi_bdev(args.client,
1529                                                              path=args.path,
1530                                                              name=args.name,
1531                                                              vq_count=args.vq_count,
1532                                                              vq_size=args.vq_size))
1533
1534    p = subparsers.add_parser('construct_virtio_user_scsi_bdev', help="""Connect to virtio user scsi device.
1535    This imply scan and add bdevs offered by remote side.
1536    Result is array of added bdevs.""")
1537    p.add_argument('path', help='Path to Virtio SCSI socket')
1538    p.add_argument('name', help="""Use this name as base instead of 'VirtioScsiN'
1539    Base will be used to construct new bdev's found on target by adding 't<TARGET_ID>' sufix.""")
1540    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1541    p.add_argument('--vq-size', help='Size of each queue', type=int)
1542    p.set_defaults(func=construct_virtio_user_scsi_bdev)
1543
1544    @call_cmd
1545    def construct_virtio_pci_scsi_bdev(args):
1546        print_array(rpc.vhost.construct_virtio_pci_scsi_bdev(args.client,
1547                                                             pci_address=args.pci_address,
1548                                                             name=args.name))
1549
1550    p = subparsers.add_parser('construct_virtio_pci_scsi_bdev', help="""Create a Virtio
1551    SCSI device from a virtio-pci device.""")
1552    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1553    domain.bus.device.function format""")
1554    p.add_argument('name', help="""Name for the virtio device.
1555    It will be inhereted by all created bdevs, which are named n the following format: <name>t<target_id>""")
1556    p.set_defaults(func=construct_virtio_pci_scsi_bdev)
1557
1558    @call_cmd
1559    def get_virtio_scsi_devs(args):
1560        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client))
1561
1562    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
1563    p.set_defaults(func=get_virtio_scsi_devs)
1564
1565    @call_cmd
1566    def remove_virtio_scsi_bdev(args):
1567        rpc.vhost.remove_virtio_scsi_bdev(args.client,
1568                                          name=args.name)
1569
1570    p = subparsers.add_parser('remove_virtio_scsi_bdev', help="""Remove a Virtio-SCSI device
1571    This will delete all bdevs exposed by this device (this call is deprecated - please use remove_virtio_bdev call instead).""")
1572    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1573    p.set_defaults(func=remove_virtio_scsi_bdev)
1574
1575    @call_cmd
1576    def remove_virtio_bdev(args):
1577        rpc.vhost.remove_virtio_bdev(args.client,
1578                                     name=args.name)
1579
1580    p = subparsers.add_parser('remove_virtio_bdev', help="""Remove a Virtio device
1581    This will delete all bdevs exposed by this device""")
1582    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1583    p.set_defaults(func=remove_virtio_bdev)
1584
1585    @call_cmd
1586    def construct_virtio_user_blk_bdev(args):
1587        print(rpc.vhost.construct_virtio_user_blk_bdev(args.client,
1588                                                       path=args.path,
1589                                                       name=args.name,
1590                                                       vq_count=args.vq_count,
1591                                                       vq_size=args.vq_size))
1592
1593    p = subparsers.add_parser('construct_virtio_user_blk_bdev', help='Connect to a virtio user blk device.')
1594    p.add_argument('path', help='Path to Virtio BLK socket')
1595    p.add_argument('name', help='Name for the bdev')
1596    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1597    p.add_argument('--vq-size', help='Size of each queue', type=int)
1598    p.set_defaults(func=construct_virtio_user_blk_bdev)
1599
1600    @call_cmd
1601    def construct_virtio_pci_blk_bdev(args):
1602        print(rpc.vhost.construct_virtio_pci_blk_bdev(args.client,
1603                                                      pci_address=args.pci_address,
1604                                                      name=args.name))
1605
1606    p = subparsers.add_parser('construct_virtio_pci_blk_bdev', help='Create a Virtio Blk device from a virtio-pci device.')
1607    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1608    domain.bus.device.function format""")
1609    p.add_argument('name', help='Name for the bdev')
1610    p.set_defaults(func=construct_virtio_pci_blk_bdev)
1611
1612    # ioat
1613    @call_cmd
1614    def scan_ioat_copy_engine(args):
1615        pci_whitelist = []
1616        if args.pci_whitelist:
1617            for w in args.pci_whitelist.strip().split(" "):
1618                pci_whitelist.append(w)
1619        rpc.ioat.scan_ioat_copy_engine(args.client, pci_whitelist)
1620
1621    p = subparsers.add_parser('scan_ioat_copy_engine', help='Set scan and enable IOAT copy engine offload.')
1622    p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in
1623    domain:bus:device.function format or domain.bus.device.function format""")
1624    p.set_defaults(func=scan_ioat_copy_engine)
1625
1626    args = parser.parse_args()
1627
1628    try:
1629        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.verbose, args.timeout)
1630    except JSONRPCException as ex:
1631        print(ex.message)
1632        exit(1)
1633    args.func(args)
1634