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