xref: /spdk/scripts/rpc.py (revision f6c5e40aed498e983c84a75122315a35a74c8ac1)
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 construct_nvme_bdev(args):
223        print_array(rpc.bdev.construct_nvme_bdev(args.client,
224                                                 name=args.name,
225                                                 trtype=args.trtype,
226                                                 traddr=args.traddr,
227                                                 adrfam=args.adrfam,
228                                                 trsvcid=args.trsvcid,
229                                                 subnqn=args.subnqn))
230
231    p = subparsers.add_parser('construct_nvme_bdev',
232                              help='Add bdev with nvme backend')
233    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
234    p.add_argument('-t', '--trtype',
235                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
236    p.add_argument('-a', '--traddr',
237                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
238    p.add_argument('-f', '--adrfam',
239                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
240    p.add_argument('-s', '--trsvcid',
241                   help='NVMe-oF target trsvcid: e.g., a port number')
242    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
243    p.set_defaults(func=construct_nvme_bdev)
244
245    @call_cmd
246    def construct_rbd_bdev(args):
247        print(rpc.bdev.construct_rbd_bdev(args.client,
248                                          name=args.name,
249                                          pool_name=args.pool_name,
250                                          rbd_name=args.rbd_name,
251                                          block_size=args.block_size))
252
253    p = subparsers.add_parser('construct_rbd_bdev',
254                              help='Add a bdev with ceph rbd backend')
255    p.add_argument('-b', '--name', help="Name of the bdev", required=False)
256    p.add_argument('pool_name', help='rbd pool name')
257    p.add_argument('rbd_name', help='rbd image name')
258    p.add_argument('block_size', help='rbd block size', type=int)
259    p.set_defaults(func=construct_rbd_bdev)
260
261    @call_cmd
262    def delete_rbd_bdev(args):
263        rpc.bdev.delete_rbd_bdev(args.client,
264                                 name=args.name)
265
266    p = subparsers.add_parser('delete_rbd_bdev', help='Delete a rbd bdev')
267    p.add_argument('name', help='rbd bdev name')
268    p.set_defaults(func=delete_rbd_bdev)
269
270    @call_cmd
271    def construct_error_bdev(args):
272        print(rpc.bdev.construct_error_bdev(args.client,
273                                            base_name=args.base_name))
274
275    p = subparsers.add_parser('construct_error_bdev',
276                              help='Add bdev with error injection backend')
277    p.add_argument('base_name', help='base bdev name')
278    p.set_defaults(func=construct_error_bdev)
279
280    @call_cmd
281    def delete_error_bdev(args):
282        rpc.bdev.delete_error_bdev(args.client,
283                                   name=args.name)
284
285    p = subparsers.add_parser('delete_error_bdev', help='Delete an error bdev')
286    p.add_argument('name', help='error bdev name')
287    p.set_defaults(func=delete_error_bdev)
288
289    @call_cmd
290    def construct_iscsi_bdev(args):
291        print(rpc.bdev.construct_iscsi_bdev(args.client,
292                                            name=args.name,
293                                            url=args.url,
294                                            initiator_iqn=args.initiator_iqn))
295
296    p = subparsers.add_parser('construct_iscsi_bdev',
297                              help='Add bdev with iSCSI initiator backend')
298    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
299    p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True)
300    p.add_argument('--url', help="iSCSI Lun URL", required=True)
301    p.set_defaults(func=construct_iscsi_bdev)
302
303    @call_cmd
304    def delete_iscsi_bdev(args):
305        rpc.bdev.delete_iscsi_bdev(args.client,
306                                   name=args.name)
307
308    p = subparsers.add_parser('delete_iscsi_bdev', help='Delete an iSCSI bdev')
309    p.add_argument('name', help='iSCSI bdev name')
310    p.set_defaults(func=delete_iscsi_bdev)
311
312    @call_cmd
313    def construct_pmem_bdev(args):
314        print(rpc.bdev.construct_pmem_bdev(args.client,
315                                           pmem_file=args.pmem_file,
316                                           name=args.name))
317
318    p = subparsers.add_parser('construct_pmem_bdev', help='Add a bdev with pmem backend')
319    p.add_argument('pmem_file', help='Path to pmemblk pool file')
320    p.add_argument('-n', '--name', help='Block device name', required=True)
321    p.set_defaults(func=construct_pmem_bdev)
322
323    @call_cmd
324    def delete_pmem_bdev(args):
325        rpc.bdev.delete_pmem_bdev(args.client,
326                                  name=args.name)
327
328    p = subparsers.add_parser('delete_pmem_bdev', help='Delete a pmem bdev')
329    p.add_argument('name', help='pmem bdev name')
330    p.set_defaults(func=delete_pmem_bdev)
331
332    @call_cmd
333    def construct_passthru_bdev(args):
334        print(rpc.bdev.construct_passthru_bdev(args.client,
335                                               base_bdev_name=args.base_bdev_name,
336                                               passthru_bdev_name=args.passthru_bdev_name))
337
338    p = subparsers.add_parser('construct_passthru_bdev',
339                              help='Add a pass through bdev on existing bdev')
340    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
341    p.add_argument('-p', '--passthru-bdev-name', help="Name of the pass through bdev", required=True)
342    p.set_defaults(func=construct_passthru_bdev)
343
344    @call_cmd
345    def delete_passthru_bdev(args):
346        rpc.bdev.delete_passthru_bdev(args.client,
347                                      name=args.name)
348
349    p = subparsers.add_parser('delete_passthru_bdev', help='Delete a pass through bdev')
350    p.add_argument('name', help='pass through bdev name')
351    p.set_defaults(func=delete_passthru_bdev)
352
353    @call_cmd
354    def get_bdevs(args):
355        print_dict(rpc.bdev.get_bdevs(args.client,
356                                      name=args.name))
357
358    p = subparsers.add_parser(
359        'get_bdevs', help='Display current blockdev list or required blockdev')
360    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
361    p.set_defaults(func=get_bdevs)
362
363    @call_cmd
364    def get_bdevs_config(args):
365        print_dict(rpc.bdev.get_bdevs_config(args.client,
366                                             name=args.name))
367
368    p = subparsers.add_parser(
369        'get_bdevs_config', help='Display current (live) blockdev configuration list or required blockdev')
370    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
371    p.set_defaults(func=get_bdevs_config)
372
373    @call_cmd
374    def get_bdevs_iostat(args):
375        print_dict(rpc.bdev.get_bdevs_iostat(args.client,
376                                             name=args.name))
377
378    p = subparsers.add_parser(
379        'get_bdevs_iostat', help='Display current I/O statistics of all the blockdevs or required blockdev.')
380    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
381    p.set_defaults(func=get_bdevs_iostat)
382
383    @call_cmd
384    def delete_bdev(args):
385        rpc.bdev.delete_bdev(args.client,
386                             bdev_name=args.bdev_name)
387
388    p = subparsers.add_parser('delete_bdev', help='Delete a blockdev')
389    p.add_argument(
390        'bdev_name', help='Blockdev name to be deleted. Example: Malloc0.')
391    p.set_defaults(func=delete_bdev)
392
393    @call_cmd
394    def set_bdev_qd_sampling_period(args):
395        rpc.bdev.set_bdev_qd_sampling_period(args.client,
396                                             name=args.name,
397                                             period=args.period)
398
399    p = subparsers.add_parser('set_bdev_qd_sampling_period', help="Enable or disable tracking of a bdev's queue depth.")
400    p.add_argument('name', help='Blockdev name. Example: Malloc0')
401    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
402                   ' If set to 0, polling will be disabled.',
403                   type=int)
404    p.set_defaults(func=set_bdev_qd_sampling_period)
405
406    @call_cmd
407    def set_bdev_qos_limit_iops(args):
408        rpc.bdev.set_bdev_qos_limit_iops(args.client,
409                                         name=args.name,
410                                         ios_per_sec=args.ios_per_sec)
411
412    p = subparsers.add_parser('set_bdev_qos_limit_iops', help='Set QoS IOPS limit on a blockdev')
413    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
414    p.add_argument('ios_per_sec',
415                   help='IOs per second limit (>=10000, example: 20000). 0 means unlimited.', type=int)
416    p.set_defaults(func=set_bdev_qos_limit_iops)
417
418    @call_cmd
419    def bdev_inject_error(args):
420        rpc.bdev.bdev_inject_error(args.client,
421                                   name=args.name,
422                                   io_type=args.io_type,
423                                   error_type=args.error_type,
424                                   num=args.num)
425
426    p = subparsers.add_parser('bdev_inject_error', help='bdev inject error')
427    p.add_argument('name', help="""the name of the error injection bdev""")
428    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
429    p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
430    p.add_argument(
431        '-n', '--num', help='the number of commands you want to fail', type=int, default=1)
432    p.set_defaults(func=bdev_inject_error)
433
434    @call_cmd
435    def apply_firmware(args):
436        print_dict(rpc.bdev.apply_firmware(args.client,
437                                           bdev_name=args.bdev_name,
438                                           filename=args.filename))
439
440    p = subparsers.add_parser('apply_firmware', help='Download and commit firmware to NVMe device')
441    p.add_argument('filename', help='filename of the firmware to download')
442    p.add_argument('bdev_name', help='name of the NVMe device')
443    p.set_defaults(func=apply_firmware)
444
445    # iSCSI
446    def set_iscsi_options(args):
447        rpc.iscsi.set_iscsi_options(
448            args.client,
449            auth_file=args.auth_file,
450            node_base=args.node_base,
451            nop_timeout=args.nop_timeout,
452            nop_in_interval=args.nop_in_interval,
453            no_discovery_auth=args.no_discovery_auth,
454            req_discovery_auth=args.req_discovery_auth,
455            req_discovery_auth_mutual=args.req_discovery_auth_mutual,
456            discovery_auth_group=args.discovery_auth_group,
457            max_sessions=args.max_sessions,
458            max_connections_per_session=args.max_connections_per_session,
459            default_time2wait=args.default_time2wait,
460            default_time2retain=args.default_time2retain,
461            immediate_data=args.immediate_data,
462            error_recovery_level=args.error_recovery_level,
463            allow_duplicated_isid=args.allow_duplicated_isid,
464            min_connections_per_session=args.min_connections_per_session)
465
466    p = subparsers.add_parser('set_iscsi_options', help="""Set options of iSCSI subsystem""")
467    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file for discovery session')
468    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
469    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
470    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
471    p.add_argument('-d', '--no-discovery-auth', help="""CHAP for discovery session should be disabled.
472    *** Mutually exclusive with --req-discovery-auth""", action='store_true')
473    p.add_argument('-r', '--req-discovery-auth', help="""CHAP for discovery session should be required.
474    *** Mutually exclusive with --no-discovery-auth""", action='store_true')
475    p.add_argument('-m', '--req-discovery-auth-mutual', help='CHAP for discovery session should be mutual', action='store_true')
476    p.add_argument('-g', '--discovery-auth-group', help="""Authentication group ID for discovery session.
477    *** Authentication group must be precreated ***""", type=int)
478    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
479    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
480    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
481    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
482    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
483    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
484    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
485    p.add_argument('-u', '--min-connections-per-session', help='Allocation unit of connections per core', type=int)
486    p.set_defaults(func=set_iscsi_options)
487
488    @call_cmd
489    def get_portal_groups(args):
490        print_dict(rpc.iscsi.get_portal_groups(args.client))
491
492    p = subparsers.add_parser(
493        'get_portal_groups', help='Display current portal group configuration')
494    p.set_defaults(func=get_portal_groups)
495
496    @call_cmd
497    def get_initiator_groups(args):
498        print_dict(rpc.iscsi.get_initiator_groups(args.client))
499
500    p = subparsers.add_parser('get_initiator_groups',
501                              help='Display current initiator group configuration')
502    p.set_defaults(func=get_initiator_groups)
503
504    @call_cmd
505    def get_target_nodes(args):
506        print_dict(rpc.iscsi.get_target_nodes(args.client))
507
508    p = subparsers.add_parser('get_target_nodes', help='Display target nodes')
509    p.set_defaults(func=get_target_nodes)
510
511    @call_cmd
512    def construct_target_node(args):
513        luns = []
514        for u in args.bdev_name_id_pairs.strip().split(" "):
515            bdev_name, lun_id = u.split(":")
516            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
517
518        pg_ig_maps = []
519        for u in args.pg_ig_mappings.strip().split(" "):
520            pg, ig = u.split(":")
521            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
522
523        rpc.iscsi.construct_target_node(
524            args.client,
525            luns=luns,
526            pg_ig_maps=pg_ig_maps,
527            name=args.name,
528            alias_name=args.alias_name,
529            queue_depth=args.queue_depth,
530            chap_group=args.chap_group,
531            disable_chap=args.disable_chap,
532            require_chap=args.require_chap,
533            mutual_chap=args.mutual_chap,
534            header_digest=args.header_digest,
535            data_digest=args.data_digest)
536
537    p = subparsers.add_parser('construct_target_node',
538                              help='Add a target node')
539    p.add_argument('name', help='Target node name (ASCII)')
540    p.add_argument('alias_name', help='Target node alias name (ASCII)')
541    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
542    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
543    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
544    *** The bdevs must pre-exist ***
545    *** LUN0 (id = 0) is required ***
546    *** bdevs names cannot contain space or colon characters ***""")
547    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
548    Whitespace separated, quoted, mapping defined with colon
549    separated list of "tags" (int > 0)
550    Example: '1:1 2:2 2:1'
551    *** The Portal/Initiator Groups must be precreated ***""")
552    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
553    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
554    *** Authentication group must be precreated ***""", type=int, default=0)
555    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
556    *** Mutually exclusive with --require-chap ***""", action='store_true')
557    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
558    *** Mutually exclusive with --disable-chap ***""", action='store_true')
559    p.add_argument(
560        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
561    p.add_argument('-H', '--header-digest',
562                   help='Header Digest should be required for this target node.', action='store_true')
563    p.add_argument('-D', '--data-digest',
564                   help='Data Digest should be required for this target node.', action='store_true')
565    p.set_defaults(func=construct_target_node)
566
567    @call_cmd
568    def target_node_add_lun(args):
569        rpc.iscsi.target_node_add_lun(
570            args.client,
571            name=args.name,
572            bdev_name=args.bdev_name,
573            lun_id=args.lun_id)
574
575    p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node')
576    p.add_argument('name', help='Target node name (ASCII)')
577    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
578    *** bdev name cannot contain space or colon characters ***""")
579    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
580    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
581    p.set_defaults(func=target_node_add_lun)
582
583    @call_cmd
584    def add_pg_ig_maps(args):
585        pg_ig_maps = []
586        for u in args.pg_ig_mappings.strip().split(" "):
587            pg, ig = u.split(":")
588            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
589        rpc.iscsi.add_pg_ig_maps(
590            args.client,
591            pg_ig_maps=pg_ig_maps,
592            name=args.name)
593
594    p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node')
595    p.add_argument('name', help='Target node name (ASCII)')
596    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
597    Whitespace separated, quoted, mapping defined with colon
598    separated list of "tags" (int > 0)
599    Example: '1:1 2:2 2:1'
600    *** The Portal/Initiator Groups must be precreated ***""")
601    p.set_defaults(func=add_pg_ig_maps)
602
603    @call_cmd
604    def delete_pg_ig_maps(args):
605        pg_ig_maps = []
606        for u in args.pg_ig_mappings.strip().split(" "):
607            pg, ig = u.split(":")
608            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
609        rpc.iscsi.delete_pg_ig_maps(
610            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
611
612    p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node')
613    p.add_argument('name', help='Target node name (ASCII)')
614    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
615    Whitespace separated, quoted, mapping defined with colon
616    separated list of "tags" (int > 0)
617    Example: '1:1 2:2 2:1'
618    *** The Portal/Initiator Groups must be precreated ***""")
619    p.set_defaults(func=delete_pg_ig_maps)
620
621    @call_cmd
622    def add_portal_group(args):
623        portals = []
624        for p in args.portal_list:
625            ip, separator, port_cpumask = p.rpartition(':')
626            split_port_cpumask = port_cpumask.split('@')
627            if len(split_port_cpumask) == 1:
628                port = port_cpumask
629                portals.append({'host': ip, 'port': port})
630            else:
631                port = split_port_cpumask[0]
632                cpumask = split_port_cpumask[1]
633                portals.append({'host': ip, 'port': port, 'cpumask': cpumask})
634        rpc.iscsi.add_portal_group(
635            args.client,
636            portals=portals,
637            tag=args.tag)
638
639    p = subparsers.add_parser('add_portal_group', help='Add a portal group')
640    p.add_argument(
641        'tag', help='Portal group tag (unique, integer > 0)', type=int)
642    p.add_argument('portal_list', nargs=argparse.REMAINDER, help="""List of portals in 'host:port@cpumask' format, separated by whitespace
643    (cpumask is optional and can be skipped)
644    Example: '192.168.100.100:3260' '192.168.100.100:3261' '192.168.100.100:3262@0x1""")
645    p.set_defaults(func=add_portal_group)
646
647    @call_cmd
648    def add_initiator_group(args):
649        initiators = []
650        netmasks = []
651        for i in args.initiator_list.strip().split(' '):
652            initiators.append(i)
653        for n in args.netmask_list.strip().split(' '):
654            netmasks.append(n)
655        rpc.iscsi.add_initiator_group(
656            args.client,
657            tag=args.tag,
658            initiators=initiators,
659            netmasks=netmasks)
660
661    p = subparsers.add_parser('add_initiator_group',
662                              help='Add an initiator group')
663    p.add_argument(
664        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
665    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
666    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
667    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
668    Example: '255.255.0.0 255.248.0.0' etc""")
669    p.set_defaults(func=add_initiator_group)
670
671    @call_cmd
672    def add_initiators_to_initiator_group(args):
673        initiators = None
674        netmasks = None
675        if args.initiator_list:
676            initiators = []
677            for i in args.initiator_list.strip().split(' '):
678                initiators.append(i)
679        if args.netmask_list:
680            netmasks = []
681            for n in args.netmask_list.strip().split(' '):
682                netmasks.append(n)
683        rpc.iscsi.add_initiators_to_initiator_group(
684            args.client,
685            tag=args.tag,
686            initiators=initiators,
687            netmasks=netmasks)
688
689    p = subparsers.add_parser('add_initiators_to_initiator_group',
690                              help='Add initiators to an existing initiator group')
691    p.add_argument(
692        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
693    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
694    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
695    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
696    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
697    p.set_defaults(func=add_initiators_to_initiator_group)
698
699    @call_cmd
700    def delete_initiators_from_initiator_group(args):
701        initiators = None
702        netmasks = None
703        if args.initiator_list:
704            initiators = []
705            for i in args.initiator_list.strip().split(' '):
706                initiators.append(i)
707        if args.netmask_list:
708            netmasks = []
709            for n in args.netmask_list.strip().split(' '):
710                netmasks.append(n)
711        rpc.iscsi.delete_initiators_from_initiator_group(
712            args.client,
713            tag=args.tag,
714            initiators=initiators,
715            netmasks=netmasks)
716
717    p = subparsers.add_parser('delete_initiators_from_initiator_group',
718                              help='Delete initiators from an existing initiator group')
719    p.add_argument(
720        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
721    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
722    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
723    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
724    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
725    p.set_defaults(func=delete_initiators_from_initiator_group)
726
727    @call_cmd
728    def delete_target_node(args):
729        rpc.iscsi.delete_target_node(
730            args.client, target_node_name=args.target_node_name)
731
732    p = subparsers.add_parser('delete_target_node',
733                              help='Delete a target node')
734    p.add_argument('target_node_name',
735                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
736    p.set_defaults(func=delete_target_node)
737
738    @call_cmd
739    def delete_portal_group(args):
740        rpc.iscsi.delete_portal_group(args.client, tag=args.tag)
741
742    p = subparsers.add_parser('delete_portal_group',
743                              help='Delete a portal group')
744    p.add_argument(
745        'tag', help='Portal group tag (unique, integer > 0)', type=int)
746    p.set_defaults(func=delete_portal_group)
747
748    @call_cmd
749    def delete_initiator_group(args):
750        rpc.iscsi.delete_initiator_group(args.client, tag=args.tag)
751
752    p = subparsers.add_parser('delete_initiator_group',
753                              help='Delete an initiator group')
754    p.add_argument(
755        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
756    p.set_defaults(func=delete_initiator_group)
757
758    @call_cmd
759    def get_iscsi_connections(args):
760        print_dict(rpc.iscsi.get_iscsi_connections(args.client))
761
762    p = subparsers.add_parser('get_iscsi_connections',
763                              help='Display iSCSI connections')
764    p.set_defaults(func=get_iscsi_connections)
765
766    @call_cmd
767    def get_iscsi_global_params(args):
768        print_dict(rpc.iscsi.get_iscsi_global_params(args.client))
769
770    p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters')
771    p.set_defaults(func=get_iscsi_global_params)
772
773    @call_cmd
774    def get_scsi_devices(args):
775        print_dict(rpc.iscsi.get_scsi_devices(args.client))
776
777    p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices')
778    p.set_defaults(func=get_scsi_devices)
779
780    # log
781    @call_cmd
782    def set_trace_flag(args):
783        rpc.log.set_trace_flag(args.client, args)
784
785    p = subparsers.add_parser('set_trace_flag', help='set trace flag')
786    p.add_argument(
787        'flag', help='trace mask we want to set. (for example "nvme").')
788    p.set_defaults(func=set_trace_flag)
789
790    @call_cmd
791    def clear_trace_flag(args):
792        rpc.log.clear_trace_flag(args.client, args)
793
794    p = subparsers.add_parser('clear_trace_flag', help='clear trace flag')
795    p.add_argument(
796        'flag', help='trace mask we want to clear. (for example "nvme").')
797    p.set_defaults(func=clear_trace_flag)
798
799    @call_cmd
800    def get_trace_flags(args):
801        print_dict(rpc.log.get_trace_flags(args.client, args))
802
803    p = subparsers.add_parser('get_trace_flags', help='get trace flags')
804    p.set_defaults(func=get_trace_flags)
805
806    @call_cmd
807    def set_log_level(args):
808        rpc.log.set_log_level(args.client, args)
809
810    p = subparsers.add_parser('set_log_level', help='set log level')
811    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
812    p.set_defaults(func=set_log_level)
813
814    @call_cmd
815    def get_log_level(args):
816        print_dict(rpc.log.get_log_level(args.client, args))
817
818    p = subparsers.add_parser('get_log_level', help='get log level')
819    p.set_defaults(func=get_log_level)
820
821    @call_cmd
822    def set_log_print_level(args):
823        rpc.log.set_log_print_level(args.client, args)
824
825    p = subparsers.add_parser('set_log_print_level', help='set log print level')
826    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
827    p.set_defaults(func=set_log_print_level)
828
829    @call_cmd
830    def get_log_print_level(args):
831        print_dict(rpc.log.get_log_print_level(args.client, args))
832
833    p = subparsers.add_parser('get_log_print_level', help='get log print level')
834    p.set_defaults(func=get_log_print_level)
835
836    # lvol
837    @call_cmd
838    def construct_lvol_store(args):
839        print(rpc.lvol.construct_lvol_store(args.client,
840                                            bdev_name=args.bdev_name,
841                                            lvs_name=args.lvs_name,
842                                            cluster_sz=args.cluster_sz))
843
844    p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev')
845    p.add_argument('bdev_name', help='base bdev name')
846    p.add_argument('lvs_name', help='name for lvol store')
847    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
848    p.set_defaults(func=construct_lvol_store)
849
850    @call_cmd
851    def rename_lvol_store(args):
852        rpc.lvol.rename_lvol_store(args.client,
853                                   old_name=args.old_name,
854                                   new_name=args.new_name)
855
856    p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
857    p.add_argument('old_name', help='old name')
858    p.add_argument('new_name', help='new name')
859    p.set_defaults(func=rename_lvol_store)
860
861    @call_cmd
862    def construct_lvol_bdev(args):
863        print(rpc.lvol.construct_lvol_bdev(args.client,
864                                           lvol_name=args.lvol_name,
865                                           size=args.size * 1024 * 1024,
866                                           thin_provision=args.thin_provision,
867                                           uuid=args.uuid,
868                                           lvs_name=args.lvs_name))
869
870    p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
871    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
872    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
873    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
874    p.add_argument('lvol_name', help='name for this lvol')
875    p.add_argument('size', help='size in MiB for this bdev', type=int)
876    p.set_defaults(func=construct_lvol_bdev)
877
878    @call_cmd
879    def snapshot_lvol_bdev(args):
880        print(rpc.lvol.snapshot_lvol_bdev(args.client,
881                                          lvol_name=args.lvol_name,
882                                          snapshot_name=args.snapshot_name))
883
884    p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
885    p.add_argument('lvol_name', help='lvol bdev name')
886    p.add_argument('snapshot_name', help='lvol snapshot name')
887    p.set_defaults(func=snapshot_lvol_bdev)
888
889    @call_cmd
890    def clone_lvol_bdev(args):
891        print(rpc.lvol.clone_lvol_bdev(args.client,
892                                       snapshot_name=args.snapshot_name,
893                                       clone_name=args.clone_name))
894
895    p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
896    p.add_argument('snapshot_name', help='lvol snapshot name')
897    p.add_argument('clone_name', help='lvol clone name')
898    p.set_defaults(func=clone_lvol_bdev)
899
900    @call_cmd
901    def rename_lvol_bdev(args):
902        rpc.lvol.rename_lvol_bdev(args.client,
903                                  old_name=args.old_name,
904                                  new_name=args.new_name)
905
906    p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name')
907    p.add_argument('old_name', help='lvol bdev name')
908    p.add_argument('new_name', help='new lvol name')
909    p.set_defaults(func=rename_lvol_bdev)
910
911    @call_cmd
912    def inflate_lvol_bdev(args):
913        rpc.lvol.inflate_lvol_bdev(args.client,
914                                   name=args.name)
915
916    p = subparsers.add_parser('inflate_lvol_bdev', help='Make thin provisioned lvol a thick provisioned lvol')
917    p.add_argument('name', help='lvol bdev name')
918    p.set_defaults(func=inflate_lvol_bdev)
919
920    @call_cmd
921    def decouple_parent_lvol_bdev(args):
922        rpc.lvol.decouple_parent_lvol_bdev(args.client,
923                                           name=args.name)
924
925    p = subparsers.add_parser('decouple_parent_lvol_bdev', help='Decouple parent of lvol')
926    p.add_argument('name', help='lvol bdev name')
927    p.set_defaults(func=decouple_parent_lvol_bdev)
928
929    @call_cmd
930    def resize_lvol_bdev(args):
931        rpc.lvol.resize_lvol_bdev(args.client,
932                                  name=args.name,
933                                  size=args.size * 1024 * 1024)
934
935    p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev')
936    p.add_argument('name', help='lvol bdev name')
937    p.add_argument('size', help='new size in MiB for this bdev', type=int)
938    p.set_defaults(func=resize_lvol_bdev)
939
940    @call_cmd
941    def destroy_lvol_bdev(args):
942        rpc.lvol.destroy_lvol_bdev(args.client,
943                                   name=args.name)
944
945    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
946    p.add_argument('name', help='lvol bdev name')
947    p.set_defaults(func=destroy_lvol_bdev)
948
949    @call_cmd
950    def destroy_lvol_store(args):
951        rpc.lvol.destroy_lvol_store(args.client,
952                                    uuid=args.uuid,
953                                    lvs_name=args.lvs_name)
954
955    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
956    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
957    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
958    p.set_defaults(func=destroy_lvol_store)
959
960    @call_cmd
961    def get_lvol_stores(args):
962        print_dict(rpc.lvol.get_lvol_stores(args.client,
963                                            uuid=args.uuid,
964                                            lvs_name=args.lvs_name))
965
966    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
967    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
968    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
969    p.set_defaults(func=get_lvol_stores)
970
971    @call_cmd
972    def get_raid_bdevs(args):
973        print_array(rpc.bdev.get_raid_bdevs(args.client,
974                                            category=args.category))
975
976    p = subparsers.add_parser('get_raid_bdevs', help="""This is used to list all the raid bdev names based on the input category
977    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
978    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
979    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
980    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
981    p.add_argument('category', help='all or online or configuring or offline')
982    p.set_defaults(func=get_raid_bdevs)
983
984    @call_cmd
985    def construct_raid_bdev(args):
986        base_bdevs = []
987        for u in args.base_bdevs.strip().split(" "):
988            base_bdevs.append(u)
989
990        rpc.bdev.construct_raid_bdev(args.client,
991                                     name=args.name,
992                                     strip_size=args.strip_size,
993                                     raid_level=args.raid_level,
994                                     base_bdevs=base_bdevs)
995    p = subparsers.add_parser('construct_raid_bdev', help='Construct new raid bdev')
996    p.add_argument('-n', '--name', help='raid bdev name', required=True)
997    p.add_argument('-s', '--strip-size', help='strip size in KB', type=int, required=True)
998    p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', type=int, required=True)
999    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
1000    p.set_defaults(func=construct_raid_bdev)
1001
1002    @call_cmd
1003    def destroy_raid_bdev(args):
1004        rpc.bdev.destroy_raid_bdev(args.client,
1005                                   name=args.name)
1006    p = subparsers.add_parser('destroy_raid_bdev', help='Destroy existing raid bdev')
1007    p.add_argument('name', help='raid bdev name')
1008    p.set_defaults(func=destroy_raid_bdev)
1009
1010    # split
1011    @call_cmd
1012    def construct_split_vbdev(args):
1013        print_array(rpc.bdev.construct_split_vbdev(args.client,
1014                                                   base_bdev=args.base_bdev,
1015                                                   split_count=args.split_count,
1016                                                   split_size_mb=args.split_size_mb))
1017
1018    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
1019    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
1020    available (during examination process).""")
1021    p.add_argument('base_bdev', help='base bdev name')
1022    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
1023    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
1024    exceed the base bdev size.""", type=int)
1025    p.set_defaults(func=construct_split_vbdev)
1026
1027    @call_cmd
1028    def destruct_split_vbdev(args):
1029        rpc.bdev.destruct_split_vbdev(args.client,
1030                                      base_bdev=args.base_bdev)
1031
1032    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
1033    p.add_argument('base_bdev', help='base bdev name')
1034    p.set_defaults(func=destruct_split_vbdev)
1035
1036    # nbd
1037    @call_cmd
1038    def start_nbd_disk(args):
1039        print(rpc.nbd.start_nbd_disk(args.client,
1040                                     bdev_name=args.bdev_name,
1041                                     nbd_device=args.nbd_device))
1042
1043    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
1044    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
1045    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.')
1046    p.set_defaults(func=start_nbd_disk)
1047
1048    @call_cmd
1049    def stop_nbd_disk(args):
1050        rpc.nbd.stop_nbd_disk(args.client,
1051                              nbd_device=args.nbd_device)
1052
1053    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
1054    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
1055    p.set_defaults(func=stop_nbd_disk)
1056
1057    @call_cmd
1058    def get_nbd_disks(args):
1059        print_dict(rpc.nbd.get_nbd_disks(args.client,
1060                                         nbd_device=args.nbd_device))
1061
1062    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
1063    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
1064    p.set_defaults(func=get_nbd_disks)
1065
1066    # net
1067    @call_cmd
1068    def add_ip_address(args):
1069        rpc.net.add_ip_address(args.client, args)
1070
1071    p = subparsers.add_parser('add_ip_address', help='Add IP address')
1072    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1073    p.add_argument('ip_addr', help='ip address will be added.')
1074    p.set_defaults(func=add_ip_address)
1075
1076    @call_cmd
1077    def delete_ip_address(args):
1078        rpc.net.delete_ip_address(args.client, args)
1079
1080    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
1081    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1082    p.add_argument('ip_addr', help='ip address will be deleted.')
1083    p.set_defaults(func=delete_ip_address)
1084
1085    @call_cmd
1086    def get_interfaces(args):
1087        print_dict(rpc.net.get_interfaces(args.client, args))
1088
1089    p = subparsers.add_parser(
1090        'get_interfaces', help='Display current interface list')
1091    p.set_defaults(func=get_interfaces)
1092
1093    # NVMe-oF
1094    @call_cmd
1095    def set_nvmf_target_options(args):
1096        rpc.nvmf.set_nvmf_target_options(args.client,
1097                                         max_queue_depth=args.max_queue_depth,
1098                                         max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1099                                         in_capsule_data_size=args.in_capsule_data_size,
1100                                         max_io_size=args.max_io_size,
1101                                         max_subsystems=args.max_subsystems,
1102                                         io_unit_size=args.io_unit_size)
1103
1104    p = subparsers.add_parser('set_nvmf_target_options', help='Set NVMf target options')
1105    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1106    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1107    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1108    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1109    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int)
1110    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1111    p.set_defaults(func=set_nvmf_target_options)
1112
1113    @call_cmd
1114    def set_nvmf_target_config(args):
1115        rpc.nvmf.set_nvmf_target_config(args.client,
1116                                        acceptor_poll_rate=args.acceptor_poll_rate)
1117
1118    p = subparsers.add_parser('set_nvmf_target_config', help='Set NVMf target config')
1119    p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
1120    p.set_defaults(func=set_nvmf_target_config)
1121
1122    @call_cmd
1123    def get_nvmf_subsystems(args):
1124        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client))
1125
1126    p = subparsers.add_parser('get_nvmf_subsystems',
1127                              help='Display nvmf subsystems')
1128    p.set_defaults(func=get_nvmf_subsystems)
1129
1130    @call_cmd
1131    def construct_nvmf_subsystem(args):
1132        listen_addresses = None
1133        hosts = None
1134        namespaces = None
1135        if args.listen:
1136            listen_addresses = [
1137                dict(
1138                    u.split(
1139                        ":",
1140                        1) for u in a.split(" ")) for a in args.listen.split(",")]
1141
1142        if args.hosts:
1143            hosts = []
1144            for u in args.hosts.strip().split(" "):
1145                hosts.append(u)
1146
1147        if args.namespaces:
1148            namespaces = []
1149            for u in args.namespaces.strip().split(" "):
1150                bdev_name = u
1151                nsid = 0
1152                if ':' in u:
1153                    (bdev_name, nsid) = u.split(":")
1154
1155                ns_params = {'bdev_name': bdev_name}
1156
1157                nsid = int(nsid)
1158                if nsid != 0:
1159                    ns_params['nsid'] = nsid
1160
1161                namespaces.append(ns_params)
1162
1163        rpc.nvmf.construct_nvmf_subsystem(args.client,
1164                                          nqn=args.nqn,
1165                                          listen_addresses=listen_addresses,
1166                                          hosts=hosts,
1167                                          allow_any_host=args.allow_any_host,
1168                                          serial_number=args.serial_number,
1169                                          namespaces=namespaces,
1170                                          max_namespaces=args.max_namespaces)
1171
1172    p = subparsers.add_parser('construct_nvmf_subsystem', help='Add a nvmf subsystem')
1173    p.add_argument('nqn', help='Target nqn(ASCII)')
1174    p.add_argument('listen', help="""comma-separated list of Listen <trtype:transport_name traddr:address trsvcid:port_id> pairs enclosed
1175    in quotes.  Format:  'trtype:transport0 traddr:traddr0 trsvcid:trsvcid0,trtype:transport1 traddr:traddr1 trsvcid:trsvcid1' etc
1176    Example: 'trtype:RDMA traddr:192.168.100.8 trsvcid:4420,trtype:RDMA traddr:192.168.100.9 trsvcid:4420'""")
1177    p.add_argument('hosts', help="""Whitespace-separated list of host nqn list.
1178    Format:  'nqn1 nqn2' etc
1179    Example: 'nqn.2016-06.io.spdk:init nqn.2016-07.io.spdk:init'""")
1180    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1181    p.add_argument("-s", "--serial-number", help="""
1182    Format:  'sn' etc
1183    Example: 'SPDK00000000000001'""", default='0000:00:01.0')
1184    p.add_argument("-n", "--namespaces", help="""Whitespace-separated list of namespaces
1185    Format:  'bdev_name1[:nsid1] bdev_name2[:nsid2] bdev_name3[:nsid3]' etc
1186    Example: '1:Malloc0 2:Malloc1 3:Malloc2'
1187    *** The devices must pre-exist ***""")
1188    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed to added during active connection",
1189                   type=int, default=0)
1190    p.set_defaults(func=construct_nvmf_subsystem)
1191
1192    @call_cmd
1193    def delete_nvmf_subsystem(args):
1194        rpc.nvmf.delete_nvmf_subsystem(args.client,
1195                                       nqn=args.subsystem_nqn)
1196
1197    p = subparsers.add_parser('delete_nvmf_subsystem',
1198                              help='Delete a nvmf subsystem')
1199    p.add_argument('subsystem_nqn',
1200                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
1201    p.set_defaults(func=delete_nvmf_subsystem)
1202
1203    @call_cmd
1204    def nvmf_subsystem_add_listener(args):
1205        rpc.nvmf.nvmf_subsystem_add_listener(args.client,
1206                                             nqn=args.nqn,
1207                                             trtype=args.trtype,
1208                                             traddr=args.traddr,
1209                                             adrfam=args.adrfam,
1210                                             trsvcid=args.trsvcid)
1211
1212    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
1213    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1214    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1215    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1216    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1217    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1218    p.set_defaults(func=nvmf_subsystem_add_listener)
1219
1220    @call_cmd
1221    def nvmf_subsystem_remove_listener(args):
1222        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
1223                                                nqn=args.nqn,
1224                                                trtype=args.trtype,
1225                                                traddr=args.traddr,
1226                                                adrfam=args.adrfam,
1227                                                trsvcid=args.trsvcid)
1228
1229    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
1230    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1231    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1232    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1233    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1234    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1235    p.set_defaults(func=nvmf_subsystem_remove_listener)
1236
1237    @call_cmd
1238    def nvmf_subsystem_add_ns(args):
1239        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
1240                                       nqn=args.nqn,
1241                                       bdev_name=args.bdev_name,
1242                                       nsid=args.nsid,
1243                                       nguid=args.nguid,
1244                                       eui64=args.eui64,
1245                                       uuid=args.uuid)
1246
1247    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
1248    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1249    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
1250    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
1251    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
1252    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
1253    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
1254    p.set_defaults(func=nvmf_subsystem_add_ns)
1255
1256    @call_cmd
1257    def nvmf_subsystem_remove_ns(args):
1258        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
1259                                          nqn=args.nqn,
1260                                          nsid=args.nsid)
1261
1262    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
1263    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1264    p.add_argument('nsid', help='The requested NSID', type=int)
1265    p.set_defaults(func=nvmf_subsystem_remove_ns)
1266
1267    @call_cmd
1268    def nvmf_subsystem_add_host(args):
1269        rpc.nvmf.nvmf_subsystem_add_host(args.client,
1270                                         nqn=args.nqn,
1271                                         host=args.host)
1272
1273    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
1274    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1275    p.add_argument('host', help='Host NQN to allow')
1276    p.set_defaults(func=nvmf_subsystem_add_host)
1277
1278    @call_cmd
1279    def nvmf_subsystem_remove_host(args):
1280        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
1281                                            nqn=args.nqn,
1282                                            host=args.host)
1283
1284    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
1285    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1286    p.add_argument('host', help='Host NQN to remove')
1287    p.set_defaults(func=nvmf_subsystem_remove_host)
1288
1289    @call_cmd
1290    def nvmf_subsystem_allow_any_host(args):
1291        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
1292                                               nqn=args.nqn,
1293                                               disable=args.disable)
1294
1295    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
1296    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1297    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
1298    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
1299    p.set_defaults(func=nvmf_subsystem_allow_any_host)
1300
1301    # pmem
1302    @call_cmd
1303    def create_pmem_pool(args):
1304        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
1305        rpc.pmem.create_pmem_pool(args.client,
1306                                  pmem_file=args.pmem_file,
1307                                  num_blocks=num_blocks,
1308                                  block_size=args.block_size)
1309
1310    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
1311    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1312    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
1313    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
1314    p.set_defaults(func=create_pmem_pool)
1315
1316    @call_cmd
1317    def pmem_pool_info(args):
1318        print_dict(rpc.pmem.pmem_pool_info(args.client,
1319                                           pmem_file=args.pmem_file))
1320
1321    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
1322    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1323    p.set_defaults(func=pmem_pool_info)
1324
1325    @call_cmd
1326    def delete_pmem_pool(args):
1327        rpc.pmem.delete_pmem_pool(args.client,
1328                                  pmem_file=args.pmem_file)
1329
1330    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
1331    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1332    p.set_defaults(func=delete_pmem_pool)
1333
1334    # subsystem
1335    @call_cmd
1336    def get_subsystems(args):
1337        print_dict(rpc.subsystem.get_subsystems(args.client))
1338
1339    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
1340    entry contain (unsorted) array of subsystems it depends on.""")
1341    p.set_defaults(func=get_subsystems)
1342
1343    @call_cmd
1344    def get_subsystem_config(args):
1345        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
1346
1347    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
1348    p.add_argument('name', help='Name of subsystem to query')
1349    p.set_defaults(func=get_subsystem_config)
1350
1351    # vhost
1352    @call_cmd
1353    def set_vhost_controller_coalescing(args):
1354        rpc.vhost.set_vhost_controller_coalescing(args.client,
1355                                                  ctrlr=args.ctrlr,
1356                                                  delay_base_us=args.delay_base_us,
1357                                                  iops_threshold=args.iops_threshold)
1358
1359    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
1360    p.add_argument('ctrlr', help='controller name')
1361    p.add_argument('delay_base_us', help='Base delay time', type=int)
1362    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
1363    p.set_defaults(func=set_vhost_controller_coalescing)
1364
1365    @call_cmd
1366    def construct_vhost_scsi_controller(args):
1367        rpc.vhost.construct_vhost_scsi_controller(args.client,
1368                                                  ctrlr=args.ctrlr,
1369                                                  cpumask=args.cpumask)
1370
1371    p = subparsers.add_parser(
1372        'construct_vhost_scsi_controller', help='Add new vhost controller')
1373    p.add_argument('ctrlr', help='controller name')
1374    p.add_argument('--cpumask', help='cpu mask for this controller')
1375    p.set_defaults(func=construct_vhost_scsi_controller)
1376
1377    @call_cmd
1378    def add_vhost_scsi_lun(args):
1379        rpc.vhost.add_vhost_scsi_lun(args.client,
1380                                     ctrlr=args.ctrlr,
1381                                     scsi_target_num=args.scsi_target_num,
1382                                     bdev_name=args.bdev_name)
1383
1384    p = subparsers.add_parser('add_vhost_scsi_lun',
1385                              help='Add lun to vhost controller')
1386    p.add_argument('ctrlr', help='conntroller name where add lun')
1387    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1388    p.add_argument('bdev_name', help='bdev name')
1389    p.set_defaults(func=add_vhost_scsi_lun)
1390
1391    @call_cmd
1392    def remove_vhost_scsi_target(args):
1393        rpc.vhost.remove_vhost_scsi_target(args.client,
1394                                           ctrlr=args.ctrlr,
1395                                           scsi_target_num=args.scsi_target_num)
1396
1397    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
1398    p.add_argument('ctrlr', help='controller name to remove target from')
1399    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1400    p.set_defaults(func=remove_vhost_scsi_target)
1401
1402    @call_cmd
1403    def construct_vhost_blk_controller(args):
1404        rpc.vhost.construct_vhost_blk_controller(args.client,
1405                                                 ctrlr=args.ctrlr,
1406                                                 dev_name=args.dev_name,
1407                                                 cpumask=args.cpumask,
1408                                                 readonly=args.readonly)
1409
1410    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
1411    p.add_argument('ctrlr', help='controller name')
1412    p.add_argument('dev_name', help='device name')
1413    p.add_argument('--cpumask', help='cpu mask for this controller')
1414    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1415    p.set_defaults(func=construct_vhost_blk_controller)
1416
1417    @call_cmd
1418    def construct_vhost_nvme_controller(args):
1419        rpc.vhost.construct_vhost_nvme_controller(args.client,
1420                                                  ctrlr=args.ctrlr,
1421                                                  io_queues=args.io_queues,
1422                                                  cpumask=args.cpumask)
1423
1424    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
1425    p.add_argument('ctrlr', help='controller name')
1426    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
1427    p.add_argument('--cpumask', help='cpu mask for this controller')
1428    p.set_defaults(func=construct_vhost_nvme_controller)
1429
1430    @call_cmd
1431    def add_vhost_nvme_ns(args):
1432        rpc.vhost.add_vhost_nvme_ns(args.client,
1433                                    ctrlr=args.ctrlr,
1434                                    bdev_name=args.bdev_name)
1435
1436    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
1437    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
1438    p.add_argument('bdev_name', help='block device name for a new Namespace')
1439    p.set_defaults(func=add_vhost_nvme_ns)
1440
1441    @call_cmd
1442    def get_vhost_controllers(args):
1443        print_dict(rpc.vhost.get_vhost_controllers(args.client))
1444
1445    p = subparsers.add_parser('get_vhost_controllers', help='List vhost controllers')
1446    p.set_defaults(func=get_vhost_controllers)
1447
1448    @call_cmd
1449    def remove_vhost_controller(args):
1450        rpc.vhost.remove_vhost_controller(args.client,
1451                                          ctrlr=args.ctrlr)
1452
1453    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
1454    p.add_argument('ctrlr', help='controller name')
1455    p.set_defaults(func=remove_vhost_controller)
1456
1457    @call_cmd
1458    def construct_virtio_dev(args):
1459        print_array(rpc.vhost.construct_virtio_dev(args.client,
1460                                                   name=args.name,
1461                                                   trtype=args.trtype,
1462                                                   traddr=args.traddr,
1463                                                   dev_type=args.dev_type,
1464                                                   vq_count=args.vq_count,
1465                                                   vq_size=args.vq_size))
1466
1467    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
1468    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
1469    remote side. Result is array of added bdevs.""")
1470    p.add_argument('name', help="Use this name as base for new created bdevs")
1471    p.add_argument('-t', '--trtype',
1472                   help='Virtio target transport type: pci or user', required=True)
1473    p.add_argument('-a', '--traddr',
1474                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
1475    p.add_argument('-d', '--dev-type',
1476                   help='Device type: blk or scsi', required=True)
1477    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1478    p.add_argument('--vq-size', help='Size of each queue', type=int)
1479    p.set_defaults(func=construct_virtio_dev)
1480
1481    @call_cmd
1482    def construct_virtio_user_scsi_bdev(args):
1483        print_array(rpc.vhost.construct_virtio_user_scsi_bdev(args.client,
1484                                                              path=args.path,
1485                                                              name=args.name,
1486                                                              vq_count=args.vq_count,
1487                                                              vq_size=args.vq_size))
1488
1489    p = subparsers.add_parser('construct_virtio_user_scsi_bdev', help="""Connect to virtio user scsi device.
1490    This imply scan and add bdevs offered by remote side.
1491    Result is array of added bdevs.""")
1492    p.add_argument('path', help='Path to Virtio SCSI socket')
1493    p.add_argument('name', help="""Use this name as base instead of 'VirtioScsiN'
1494    Base will be used to construct new bdev's found on target by adding 't<TARGET_ID>' sufix.""")
1495    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1496    p.add_argument('--vq-size', help='Size of each queue', type=int)
1497    p.set_defaults(func=construct_virtio_user_scsi_bdev)
1498
1499    @call_cmd
1500    def construct_virtio_pci_scsi_bdev(args):
1501        print_array(rpc.vhost.construct_virtio_pci_scsi_bdev(args.client,
1502                                                             pci_address=args.pci_address,
1503                                                             name=args.name))
1504
1505    p = subparsers.add_parser('construct_virtio_pci_scsi_bdev', help="""Create a Virtio
1506    SCSI device from a virtio-pci device.""")
1507    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1508    domain.bus.device.function format""")
1509    p.add_argument('name', help="""Name for the virtio device.
1510    It will be inhereted by all created bdevs, which are named n the following format: <name>t<target_id>""")
1511    p.set_defaults(func=construct_virtio_pci_scsi_bdev)
1512
1513    @call_cmd
1514    def get_virtio_scsi_devs(args):
1515        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client))
1516
1517    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
1518    p.set_defaults(func=get_virtio_scsi_devs)
1519
1520    @call_cmd
1521    def remove_virtio_scsi_bdev(args):
1522        rpc.vhost.remove_virtio_scsi_bdev(args.client,
1523                                          name=args.name)
1524
1525    p = subparsers.add_parser('remove_virtio_scsi_bdev', help="""Remove a Virtio-SCSI device
1526    This will delete all bdevs exposed by this device""")
1527    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1528    p.set_defaults(func=remove_virtio_scsi_bdev)
1529
1530    @call_cmd
1531    def construct_virtio_user_blk_bdev(args):
1532        print(rpc.vhost.construct_virtio_user_blk_bdev(args.client,
1533                                                       path=args.path,
1534                                                       name=args.name,
1535                                                       vq_count=args.vq_count,
1536                                                       vq_size=args.vq_size))
1537
1538    p = subparsers.add_parser('construct_virtio_user_blk_bdev', help='Connect to a virtio user blk device.')
1539    p.add_argument('path', help='Path to Virtio BLK socket')
1540    p.add_argument('name', help='Name for the bdev')
1541    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1542    p.add_argument('--vq-size', help='Size of each queue', type=int)
1543    p.set_defaults(func=construct_virtio_user_blk_bdev)
1544
1545    @call_cmd
1546    def construct_virtio_pci_blk_bdev(args):
1547        print(rpc.vhost.construct_virtio_pci_blk_bdev(args.client,
1548                                                      pci_address=args.pci_address,
1549                                                      name=args.name))
1550
1551    p = subparsers.add_parser('construct_virtio_pci_blk_bdev', help='Create a Virtio Blk device from a virtio-pci device.')
1552    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1553    domain.bus.device.function format""")
1554    p.add_argument('name', help='Name for the bdev')
1555    p.set_defaults(func=construct_virtio_pci_blk_bdev)
1556
1557    # ioat
1558    @call_cmd
1559    def scan_ioat_copy_engine(args):
1560        pci_whitelist = []
1561        if args.pci_whitelist:
1562            for w in args.pci_whitelist.strip().split(" "):
1563                pci_whitelist.append(w)
1564        rpc.ioat.scan_ioat_copy_engine(args.client, pci_whitelist)
1565
1566    p = subparsers.add_parser('scan_ioat_copy_engine', help='Set scan and enable IOAT copy engine offload.')
1567    p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in
1568    domain:bus:device.function format or domain.bus.device.function format""")
1569    p.set_defaults(func=scan_ioat_copy_engine)
1570
1571    args = parser.parse_args()
1572
1573    try:
1574        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.verbose, args.timeout)
1575    except JSONRPCException as ex:
1576        print(ex.message)
1577        exit(1)
1578    args.func(args)
1579