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