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