xref: /spdk/scripts/rpc.py (revision 2f557958d0762ad00e068f997e2d25a205ded4b7)
1#!/usr/bin/env python3
2
3from rpc.client import print_dict, JSONRPCException
4
5import argparse
6import rpc
7import sys
8
9try:
10    from shlex import quote
11except ImportError:
12    from pipes import quote
13
14
15def print_array(a):
16    print(" ".join((quote(v) for v in a)))
17
18
19def call_cmd(func):
20    def rpc_cmd(*args, **kwargs):
21        try:
22            func(*args, **kwargs)
23        except JSONRPCException as ex:
24            print(ex.message)
25            exit(1)
26    return rpc_cmd
27
28
29if __name__ == "__main__":
30    parser = argparse.ArgumentParser(
31        description='SPDK RPC command line interface')
32    parser.add_argument('-s', dest='server_addr',
33                        help='RPC server address', default='/var/tmp/spdk.sock')
34    parser.add_argument('-p', dest='port',
35                        help='RPC port number (if server_addr is IP address)',
36                        default=5260, type=int)
37    parser.add_argument('-t', dest='timeout',
38                        help='Timout as a floating point number expressed in seconds waiting for reponse. Default: 60.0',
39                        default=60.0, type=float)
40    parser.add_argument('-v', dest='verbose',
41                        help='Verbose mode', action='store_true')
42    subparsers = parser.add_subparsers(help='RPC methods')
43
44    @call_cmd
45    def start_subsystem_init(args):
46        rpc.start_subsystem_init(args.client)
47
48    p = subparsers.add_parser('start_subsystem_init', help='Start initialization of subsystems')
49    p.set_defaults(func=start_subsystem_init)
50
51    @call_cmd
52    def wait_subsystem_init(args):
53        rpc.wait_subsystem_init(args.client)
54
55    p = subparsers.add_parser('wait_subsystem_init', help='Block until subsystems have been initialized')
56    p.set_defaults(func=wait_subsystem_init)
57
58    @call_cmd
59    def get_rpc_methods(args):
60        print_dict(rpc.get_rpc_methods(args.client,
61                                       current=args.current))
62
63    p = subparsers.add_parser('get_rpc_methods', help='Get list of supported RPC methods')
64    p.add_argument('-c', '--current', help='Get list of RPC methods only callable in the current state.', action='store_true')
65    p.set_defaults(func=get_rpc_methods)
66
67    @call_cmd
68    def save_config(args):
69        rpc.save_config(args.client,
70                        sys.stdout,
71                        indent=args.indent)
72
73    p = subparsers.add_parser('save_config', help="""Write current (live) configuration of SPDK subsystems and targets to stdout.
74    """)
75    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
76    """, type=int, default=2)
77    p.set_defaults(func=save_config)
78
79    @call_cmd
80    def load_config(args):
81        rpc.load_config(args.client, sys.stdin)
82
83    p = subparsers.add_parser('load_config', help="""Configure SPDK subsystems and targets using JSON RPC read from stdin.""")
84    p.set_defaults(func=load_config)
85
86    @call_cmd
87    def save_subsystem_config(args):
88        rpc.save_subsystem_config(args.client,
89                                  sys.stdout,
90                                  indent=args.indent,
91                                  name=args.name)
92
93    p = subparsers.add_parser('save_subsystem_config', help="""Write current (live) configuration of SPDK subsystem to stdout.
94    """)
95    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
96    """, type=int, default=2)
97    p.add_argument('-n', '--name', help='Name of subsystem', required=True)
98    p.set_defaults(func=save_subsystem_config)
99
100    @call_cmd
101    def load_subsystem_config(args):
102        rpc.load_subsystem_config(args.client,
103                                  sys.stdin)
104
105    p = subparsers.add_parser('load_subsystem_config', help="""Configure SPDK subsystem using JSON RPC read from stdin.""")
106    p.set_defaults(func=load_subsystem_config)
107
108    # app
109    @call_cmd
110    def kill_instance(args):
111        rpc.app.kill_instance(args.client,
112                              sig_name=args.sig_name)
113
114    p = subparsers.add_parser('kill_instance', help='Send signal to instance')
115    p.add_argument('sig_name', help='signal will be sent to server.')
116    p.set_defaults(func=kill_instance)
117
118    @call_cmd
119    def context_switch_monitor(args):
120        enabled = None
121        if args.enable:
122            enabled = True
123        if args.disable:
124            enabled = False
125        print_dict(rpc.app.context_switch_monitor(args.client,
126                                                  enabled=enabled))
127
128    p = subparsers.add_parser('context_switch_monitor', help='Control whether the context switch monitor is enabled')
129    p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring')
130    p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring')
131    p.set_defaults(func=context_switch_monitor)
132
133    # bdev
134    @call_cmd
135    def set_bdev_options(args):
136        rpc.bdev.set_bdev_options(args.client,
137                                  bdev_io_pool_size=args.bdev_io_pool_size,
138                                  bdev_io_cache_size=args.bdev_io_cache_size)
139
140    p = subparsers.add_parser('set_bdev_options', help="""Set options of bdev subsystem""")
141    p.add_argument('-p', '--bdev-io-pool-size', help='Number of bdev_io structures in shared buffer pool', type=int)
142    p.add_argument('-c', '--bdev-io-cache-size', help='Maximum number of bdev_io structures cached per thread', type=int)
143    p.set_defaults(func=set_bdev_options)
144
145    @call_cmd
146    def construct_crypto_bdev(args):
147        print(rpc.bdev.construct_crypto_bdev(args.client,
148                                             base_bdev_name=args.base_bdev_name,
149                                             name=args.name,
150                                             crypto_pmd=args.crypto_pmd,
151                                             key=args.key))
152    p = subparsers.add_parser('construct_crypto_bdev',
153                              help='Add a crypto vbdev')
154    p.add_argument('-b', '--base_bdev_name', help="Name of the base bdev")
155    p.add_argument('-c', '--name', help="Name of the crypto vbdev")
156    p.add_argument('-d', '--crypto_pmd', help="Name of the crypto device driver")
157    p.add_argument('-k', '--key', help="Key")
158    p.set_defaults(func=construct_crypto_bdev)
159
160    @call_cmd
161    def delete_crypto_bdev(args):
162        rpc.bdev.delete_crypto_bdev(args.client,
163                                    name=args.name)
164
165    p = subparsers.add_parser('delete_crypto_bdev', help='Delete a crypto disk')
166    p.add_argument('name', help='crypto bdev name')
167    p.set_defaults(func=delete_crypto_bdev)
168
169    @call_cmd
170    def construct_malloc_bdev(args):
171        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
172        print(rpc.bdev.construct_malloc_bdev(args.client,
173                                             num_blocks=int(num_blocks),
174                                             block_size=args.block_size,
175                                             name=args.name,
176                                             uuid=args.uuid))
177    p = subparsers.add_parser('construct_malloc_bdev',
178                              help='Add a bdev with malloc backend')
179    p.add_argument('-b', '--name', help="Name of the bdev")
180    p.add_argument('-u', '--uuid', help="UUID of the bdev")
181    p.add_argument(
182        'total_size', help='Size of malloc bdev in MB (float > 0)', type=float)
183    p.add_argument('block_size', help='Block size for this bdev', type=int)
184    p.set_defaults(func=construct_malloc_bdev)
185
186    @call_cmd
187    def delete_malloc_bdev(args):
188        rpc.bdev.delete_malloc_bdev(args.client,
189                                    name=args.name)
190
191    p = subparsers.add_parser('delete_malloc_bdev', help='Delete a malloc disk')
192    p.add_argument('name', help='malloc bdev name')
193    p.set_defaults(func=delete_malloc_bdev)
194
195    @call_cmd
196    def construct_null_bdev(args):
197        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
198        print(rpc.bdev.construct_null_bdev(args.client,
199                                           num_blocks=num_blocks,
200                                           block_size=args.block_size,
201                                           name=args.name,
202                                           uuid=args.uuid))
203
204    p = subparsers.add_parser('construct_null_bdev',
205                              help='Add a bdev with null backend')
206    p.add_argument('name', help='Block device name')
207    p.add_argument('-u', '--uuid', help='UUID of the bdev')
208    p.add_argument(
209        'total_size', help='Size of null bdev in MB (int > 0)', type=int)
210    p.add_argument('block_size', help='Block size for this bdev', type=int)
211    p.set_defaults(func=construct_null_bdev)
212
213    @call_cmd
214    def delete_null_bdev(args):
215        rpc.bdev.delete_null_bdev(args.client,
216                                  name=args.name)
217
218    p = subparsers.add_parser('delete_null_bdev', help='Delete a null bdev')
219    p.add_argument('name', help='null bdev name')
220    p.set_defaults(func=delete_null_bdev)
221
222    @call_cmd
223    def construct_aio_bdev(args):
224        print(rpc.bdev.construct_aio_bdev(args.client,
225                                          filename=args.filename,
226                                          name=args.name,
227                                          block_size=args.block_size))
228
229    p = subparsers.add_parser('construct_aio_bdev',
230                              help='Add a bdev with aio backend')
231    p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
232    p.add_argument('name', help='Block device name')
233    p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?', default=0)
234    p.set_defaults(func=construct_aio_bdev)
235
236    @call_cmd
237    def delete_aio_bdev(args):
238        rpc.bdev.delete_aio_bdev(args.client,
239                                 name=args.name)
240
241    p = subparsers.add_parser('delete_aio_bdev', help='Delete an aio disk')
242    p.add_argument('name', help='aio bdev name')
243    p.set_defaults(func=delete_aio_bdev)
244
245    @call_cmd
246    def set_bdev_nvme_options(args):
247        rpc.bdev.set_bdev_nvme_options(args.client,
248                                       action_on_timeout=args.action_on_timeout,
249                                       timeout_us=args.timeout_us,
250                                       retry_count=args.retry_count,
251                                       nvme_adminq_poll_period_us=args.nvme_adminq_poll_period_us)
252
253    p = subparsers.add_parser('set_bdev_nvme_options',
254                              help='Set options for the bdev nvme type. This is startup command.')
255    p.add_argument('-a', '--action-on-timeout',
256                   help="Action to take on command time out. Valid valies are: none, reset, abort")
257    p.add_argument('-t', '--timeout-us',
258                   help="Timeout for each command, in microseconds. If 0, don't track timeouts.", type=int)
259    p.add_argument('-n', '--retry-count',
260                   help='the number of attempts per I/O when an I/O fails', type=int)
261    p.add_argument('-p', '--nvme-adminq-poll-period-us',
262                   help='How often the admin queue is polled for asynchronous events', type=int)
263    p.set_defaults(func=set_bdev_nvme_options)
264
265    @call_cmd
266    def set_bdev_nvme_hotplug(args):
267        rpc.bdev.set_bdev_nvme_hotplug(args.client, enable=args.enable, period_us=args.period_us)
268
269    p = subparsers.add_parser('set_bdev_nvme_hotplug',
270                              help='Set hotplug options for bdev nvme type.')
271    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
272    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
273    p.add_argument('-r', '--period-us',
274                   help='How often the hotplug is processed for insert and remove events', type=int)
275    p.set_defaults(func=set_bdev_nvme_hotplug)
276
277    @call_cmd
278    def construct_nvme_bdev(args):
279        print_array(rpc.bdev.construct_nvme_bdev(args.client,
280                                                 name=args.name,
281                                                 trtype=args.trtype,
282                                                 traddr=args.traddr,
283                                                 adrfam=args.adrfam,
284                                                 trsvcid=args.trsvcid,
285                                                 subnqn=args.subnqn))
286
287    p = subparsers.add_parser('construct_nvme_bdev',
288                              help='Add bdevs with nvme backend')
289    p.add_argument('-b', '--name', help="Name of the NVMe controller, prefix for each bdev name", required=True)
290    p.add_argument('-t', '--trtype',
291                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
292    p.add_argument('-a', '--traddr',
293                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
294    p.add_argument('-f', '--adrfam',
295                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
296    p.add_argument('-s', '--trsvcid',
297                   help='NVMe-oF target trsvcid: e.g., a port number')
298    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
299    p.set_defaults(func=construct_nvme_bdev)
300
301    @call_cmd
302    def get_nvme_controllers(args):
303        print_dict(rpc.nvme.get_nvme_controllers(args.client,
304                                                 name=args.name))
305
306    p = subparsers.add_parser(
307        'get_nvme_controllers', help='Display current NVMe controllers list or required NVMe controller')
308    p.add_argument('-n', '--name', help="Name of the NVMe controller. Example: Nvme0", required=False)
309    p.set_defaults(func=get_nvme_controllers)
310
311    @call_cmd
312    def delete_nvme_controller(args):
313        rpc.bdev.delete_nvme_controller(args.client,
314                                        name=args.name)
315
316    p = subparsers.add_parser('delete_nvme_controller',
317                              help='Delete a NVMe controller using controller name')
318    p.add_argument('name', help="Name of the controller")
319    p.set_defaults(func=delete_nvme_controller)
320
321    @call_cmd
322    def construct_rbd_bdev(args):
323        print(rpc.bdev.construct_rbd_bdev(args.client,
324                                          name=args.name,
325                                          pool_name=args.pool_name,
326                                          rbd_name=args.rbd_name,
327                                          block_size=args.block_size))
328
329    p = subparsers.add_parser('construct_rbd_bdev',
330                              help='Add a bdev with ceph rbd backend')
331    p.add_argument('-b', '--name', help="Name of the bdev", required=False)
332    p.add_argument('pool_name', help='rbd pool name')
333    p.add_argument('rbd_name', help='rbd image name')
334    p.add_argument('block_size', help='rbd block size', type=int)
335    p.set_defaults(func=construct_rbd_bdev)
336
337    @call_cmd
338    def delete_rbd_bdev(args):
339        rpc.bdev.delete_rbd_bdev(args.client,
340                                 name=args.name)
341
342    p = subparsers.add_parser('delete_rbd_bdev', help='Delete a rbd bdev')
343    p.add_argument('name', help='rbd bdev name')
344    p.set_defaults(func=delete_rbd_bdev)
345
346    @call_cmd
347    def construct_error_bdev(args):
348        print(rpc.bdev.construct_error_bdev(args.client,
349                                            base_name=args.base_name))
350
351    p = subparsers.add_parser('construct_error_bdev',
352                              help='Add bdev with error injection backend')
353    p.add_argument('base_name', help='base bdev name')
354    p.set_defaults(func=construct_error_bdev)
355
356    @call_cmd
357    def delete_error_bdev(args):
358        rpc.bdev.delete_error_bdev(args.client,
359                                   name=args.name)
360
361    p = subparsers.add_parser('delete_error_bdev', help='Delete an error bdev')
362    p.add_argument('name', help='error bdev name')
363    p.set_defaults(func=delete_error_bdev)
364
365    @call_cmd
366    def construct_iscsi_bdev(args):
367        print(rpc.bdev.construct_iscsi_bdev(args.client,
368                                            name=args.name,
369                                            url=args.url,
370                                            initiator_iqn=args.initiator_iqn))
371
372    p = subparsers.add_parser('construct_iscsi_bdev',
373                              help='Add bdev with iSCSI initiator backend')
374    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
375    p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True)
376    p.add_argument('--url', help="iSCSI Lun URL", required=True)
377    p.set_defaults(func=construct_iscsi_bdev)
378
379    @call_cmd
380    def delete_iscsi_bdev(args):
381        rpc.bdev.delete_iscsi_bdev(args.client,
382                                   name=args.name)
383
384    p = subparsers.add_parser('delete_iscsi_bdev', help='Delete an iSCSI bdev')
385    p.add_argument('name', help='iSCSI bdev name')
386    p.set_defaults(func=delete_iscsi_bdev)
387
388    @call_cmd
389    def construct_pmem_bdev(args):
390        print(rpc.bdev.construct_pmem_bdev(args.client,
391                                           pmem_file=args.pmem_file,
392                                           name=args.name))
393
394    p = subparsers.add_parser('construct_pmem_bdev', help='Add a bdev with pmem backend')
395    p.add_argument('pmem_file', help='Path to pmemblk pool file')
396    p.add_argument('-n', '--name', help='Block device name', required=True)
397    p.set_defaults(func=construct_pmem_bdev)
398
399    @call_cmd
400    def delete_pmem_bdev(args):
401        rpc.bdev.delete_pmem_bdev(args.client,
402                                  name=args.name)
403
404    p = subparsers.add_parser('delete_pmem_bdev', help='Delete a pmem bdev')
405    p.add_argument('name', help='pmem bdev name')
406    p.set_defaults(func=delete_pmem_bdev)
407
408    @call_cmd
409    def construct_passthru_bdev(args):
410        print(rpc.bdev.construct_passthru_bdev(args.client,
411                                               base_bdev_name=args.base_bdev_name,
412                                               name=args.name))
413
414    p = subparsers.add_parser('construct_passthru_bdev',
415                              help='Add a pass through bdev on existing bdev')
416    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
417    p.add_argument('-p', '--name', help="Name of the pass through bdev", required=True)
418    p.set_defaults(func=construct_passthru_bdev)
419
420    @call_cmd
421    def delete_passthru_bdev(args):
422        rpc.bdev.delete_passthru_bdev(args.client,
423                                      name=args.name)
424
425    p = subparsers.add_parser('delete_passthru_bdev', help='Delete a pass through bdev')
426    p.add_argument('name', help='pass through bdev name')
427    p.set_defaults(func=delete_passthru_bdev)
428
429    @call_cmd
430    def get_bdevs(args):
431        print_dict(rpc.bdev.get_bdevs(args.client,
432                                      name=args.name))
433
434    p = subparsers.add_parser(
435        'get_bdevs', help='Display current blockdev list or required blockdev')
436    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
437    p.set_defaults(func=get_bdevs)
438
439    @call_cmd
440    def get_bdevs_iostat(args):
441        print_dict(rpc.bdev.get_bdevs_iostat(args.client,
442                                             name=args.name))
443
444    p = subparsers.add_parser(
445        'get_bdevs_iostat', help='Display current I/O statistics of all the blockdevs or required blockdev.')
446    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
447    p.set_defaults(func=get_bdevs_iostat)
448
449    @call_cmd
450    def delete_bdev(args):
451        rpc.bdev.delete_bdev(args.client,
452                             bdev_name=args.bdev_name)
453
454    p = subparsers.add_parser('delete_bdev', help='Delete a blockdev')
455    p.add_argument(
456        'bdev_name', help='Blockdev name to be deleted. Example: Malloc0.')
457    p.set_defaults(func=delete_bdev)
458
459    @call_cmd
460    def set_bdev_qd_sampling_period(args):
461        rpc.bdev.set_bdev_qd_sampling_period(args.client,
462                                             name=args.name,
463                                             period=args.period)
464
465    p = subparsers.add_parser('set_bdev_qd_sampling_period', help="Enable or disable tracking of a bdev's queue depth.")
466    p.add_argument('name', help='Blockdev name. Example: Malloc0')
467    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
468                   ' If set to 0, polling will be disabled.',
469                   type=int)
470    p.set_defaults(func=set_bdev_qd_sampling_period)
471
472    @call_cmd
473    def set_bdev_qos_limit(args):
474        rpc.bdev.set_bdev_qos_limit(args.client,
475                                    name=args.name,
476                                    rw_ios_per_sec=args.rw_ios_per_sec,
477                                    rw_mbytes_per_sec=args.rw_mbytes_per_sec)
478
479    p = subparsers.add_parser('set_bdev_qos_limit', help='Set QoS rate limit on a blockdev')
480    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
481    p.add_argument('--rw_ios_per_sec',
482                   help='R/W IOs per second limit (>=10000, example: 20000). 0 means unlimited.',
483                   type=int, required=False)
484    p.add_argument('--rw_mbytes_per_sec',
485                   help="R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.",
486                   type=int, required=False)
487    p.set_defaults(func=set_bdev_qos_limit)
488
489    @call_cmd
490    def bdev_inject_error(args):
491        rpc.bdev.bdev_inject_error(args.client,
492                                   name=args.name,
493                                   io_type=args.io_type,
494                                   error_type=args.error_type,
495                                   num=args.num)
496
497    p = subparsers.add_parser('bdev_inject_error', help='bdev inject error')
498    p.add_argument('name', help="""the name of the error injection bdev""")
499    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
500    p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
501    p.add_argument(
502        '-n', '--num', help='the number of commands you want to fail', type=int, default=1)
503    p.set_defaults(func=bdev_inject_error)
504
505    @call_cmd
506    def apply_firmware(args):
507        print_dict(rpc.bdev.apply_firmware(args.client,
508                                           bdev_name=args.bdev_name,
509                                           filename=args.filename))
510
511    p = subparsers.add_parser('apply_firmware', help='Download and commit firmware to NVMe device')
512    p.add_argument('filename', help='filename of the firmware to download')
513    p.add_argument('bdev_name', help='name of the NVMe device')
514    p.set_defaults(func=apply_firmware)
515
516    # iSCSI
517    @call_cmd
518    def set_iscsi_options(args):
519        rpc.iscsi.set_iscsi_options(
520            args.client,
521            auth_file=args.auth_file,
522            node_base=args.node_base,
523            nop_timeout=args.nop_timeout,
524            nop_in_interval=args.nop_in_interval,
525            disable_chap=args.disable_chap,
526            require_chap=args.require_chap,
527            mutual_chap=args.mutual_chap,
528            chap_group=args.chap_group,
529            max_sessions=args.max_sessions,
530            max_queue_depth=args.max_queue_depth,
531            max_connections_per_session=args.max_connections_per_session,
532            default_time2wait=args.default_time2wait,
533            default_time2retain=args.default_time2retain,
534            first_burst_length=args.first_burst_length,
535            immediate_data=args.immediate_data,
536            error_recovery_level=args.error_recovery_level,
537            allow_duplicated_isid=args.allow_duplicated_isid,
538            min_connections_per_core=args.min_connections_per_core)
539
540    p = subparsers.add_parser('set_iscsi_options', help="""Set options of iSCSI subsystem""")
541    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file')
542    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
543    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
544    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
545    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
546    *** Mutually exclusive with --require-chap""", action='store_true')
547    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
548    *** Mutually exclusive with --disable-chap""", action='store_true')
549    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
550    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
551    *** Authentication group must be precreated ***""", type=int)
552    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
553    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int)
554    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
555    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
556    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
557    p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int)
558    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
559    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
560    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
561    p.add_argument('-u', '--min-connections-per-core', help='Allocation unit of connections per core', type=int)
562    p.set_defaults(func=set_iscsi_options)
563
564    @call_cmd
565    def set_iscsi_discovery_auth(args):
566        rpc.iscsi.set_iscsi_discovery_auth(
567            args.client,
568            disable_chap=args.disable_chap,
569            require_chap=args.require_chap,
570            mutual_chap=args.mutual_chap,
571            chap_group=args.chap_group)
572
573    p = subparsers.add_parser('set_iscsi_discovery_auth', help="""Set CHAP authentication for discovery session.""")
574    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
575    *** Mutually exclusive with --require-chap""", action='store_true')
576    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
577    *** Mutually exclusive with --disable-chap""", action='store_true')
578    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
579    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
580    *** Authentication group must be precreated ***""", type=int)
581    p.set_defaults(func=set_iscsi_discovery_auth)
582
583    def add_iscsi_auth_group(args):
584        secrets = None
585        if args.secrets:
586            secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")]
587
588        rpc.iscsi.add_iscsi_auth_group(args.client, tag=args.tag, secrets=secrets)
589
590    p = subparsers.add_parser('add_iscsi_auth_group', help='Add authentication group for CHAP authentication.')
591    p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int)
592    p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets
593<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes.
594Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False)
595    p.set_defaults(func=add_iscsi_auth_group)
596
597    @call_cmd
598    def delete_iscsi_auth_group(args):
599        rpc.iscsi.delete_iscsi_auth_group(args.client, tag=args.tag)
600
601    p = subparsers.add_parser('delete_iscsi_auth_group', help='Delete an authentication group.')
602    p.add_argument('tag', help='Authentication group tag', type=int)
603    p.set_defaults(func=delete_iscsi_auth_group)
604
605    @call_cmd
606    def add_secret_to_iscsi_auth_group(args):
607        rpc.iscsi.add_secret_to_iscsi_auth_group(
608            args.client,
609            tag=args.tag,
610            user=args.user,
611            secret=args.secret,
612            muser=args.muser,
613            msecret=args.msecret)
614
615    p = subparsers.add_parser('add_secret_to_iscsi_auth_group', help='Add a secret to an authentication group.')
616    p.add_argument('tag', help='Authentication group tag', type=int)
617    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
618    p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True)
619    p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication')
620    p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication')
621    p.set_defaults(func=add_secret_to_iscsi_auth_group)
622
623    @call_cmd
624    def delete_secret_from_iscsi_auth_group(args):
625        rpc.iscsi.delete_secret_from_iscsi_auth_group(args.client, tag=args.tag, user=args.user)
626
627    p = subparsers.add_parser('delete_secret_from_iscsi_auth_group', help='Delete a secret from an authentication group.')
628    p.add_argument('tag', help='Authentication group tag', type=int)
629    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
630    p.set_defaults(func=delete_secret_from_iscsi_auth_group)
631
632    @call_cmd
633    def get_iscsi_auth_groups(args):
634        print_dict(rpc.iscsi.get_iscsi_auth_groups(args.client))
635
636    p = subparsers.add_parser('get_iscsi_auth_groups',
637                              help='Display current authentication group configuration')
638    p.set_defaults(func=get_iscsi_auth_groups)
639
640    @call_cmd
641    def get_portal_groups(args):
642        print_dict(rpc.iscsi.get_portal_groups(args.client))
643
644    p = subparsers.add_parser(
645        'get_portal_groups', help='Display current portal group configuration')
646    p.set_defaults(func=get_portal_groups)
647
648    @call_cmd
649    def get_initiator_groups(args):
650        print_dict(rpc.iscsi.get_initiator_groups(args.client))
651
652    p = subparsers.add_parser('get_initiator_groups',
653                              help='Display current initiator group configuration')
654    p.set_defaults(func=get_initiator_groups)
655
656    @call_cmd
657    def get_target_nodes(args):
658        print_dict(rpc.iscsi.get_target_nodes(args.client))
659
660    p = subparsers.add_parser('get_target_nodes', help='Display target nodes')
661    p.set_defaults(func=get_target_nodes)
662
663    @call_cmd
664    def construct_target_node(args):
665        luns = []
666        for u in args.bdev_name_id_pairs.strip().split(" "):
667            bdev_name, lun_id = u.split(":")
668            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
669
670        pg_ig_maps = []
671        for u in args.pg_ig_mappings.strip().split(" "):
672            pg, ig = u.split(":")
673            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
674
675        rpc.iscsi.construct_target_node(
676            args.client,
677            luns=luns,
678            pg_ig_maps=pg_ig_maps,
679            name=args.name,
680            alias_name=args.alias_name,
681            queue_depth=args.queue_depth,
682            chap_group=args.chap_group,
683            disable_chap=args.disable_chap,
684            require_chap=args.require_chap,
685            mutual_chap=args.mutual_chap,
686            header_digest=args.header_digest,
687            data_digest=args.data_digest)
688
689    p = subparsers.add_parser('construct_target_node',
690                              help='Add a target node')
691    p.add_argument('name', help='Target node name (ASCII)')
692    p.add_argument('alias_name', help='Target node alias name (ASCII)')
693    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
694    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
695    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
696    *** The bdevs must pre-exist ***
697    *** LUN0 (id = 0) is required ***
698    *** bdevs names cannot contain space or colon characters ***""")
699    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
700    Whitespace separated, quoted, mapping defined with colon
701    separated list of "tags" (int > 0)
702    Example: '1:1 2:2 2:1'
703    *** The Portal/Initiator Groups must be precreated ***""")
704    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
705    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
706    *** Authentication group must be precreated ***""", type=int, default=0)
707    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
708    *** Mutually exclusive with --require-chap ***""", action='store_true')
709    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
710    *** Mutually exclusive with --disable-chap ***""", action='store_true')
711    p.add_argument(
712        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
713    p.add_argument('-H', '--header-digest',
714                   help='Header Digest should be required for this target node.', action='store_true')
715    p.add_argument('-D', '--data-digest',
716                   help='Data Digest should be required for this target node.', action='store_true')
717    p.set_defaults(func=construct_target_node)
718
719    @call_cmd
720    def target_node_add_lun(args):
721        rpc.iscsi.target_node_add_lun(
722            args.client,
723            name=args.name,
724            bdev_name=args.bdev_name,
725            lun_id=args.lun_id)
726
727    p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node')
728    p.add_argument('name', help='Target node name (ASCII)')
729    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
730    *** bdev name cannot contain space or colon characters ***""")
731    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
732    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
733    p.set_defaults(func=target_node_add_lun)
734
735    @call_cmd
736    def set_iscsi_target_node_auth(args):
737        rpc.iscsi.set_iscsi_target_node_auth(
738            args.client,
739            name=args.name,
740            chap_group=args.chap_group,
741            disable_chap=args.disable_chap,
742            require_chap=args.require_chap,
743            mutual_chap=args.mutual_chap)
744
745    p = subparsers.add_parser('set_iscsi_target_node_auth', help='Set CHAP authentication for the target node')
746    p.add_argument('name', help='Target node name (ASCII)')
747    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
748    *** Authentication group must be precreated ***""", type=int, default=0)
749    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
750    *** Mutually exclusive with --require-chap ***""", action='store_true')
751    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
752    *** Mutually exclusive with --disable-chap ***""", action='store_true')
753    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
754                   action='store_true')
755    p.set_defaults(func=set_iscsi_target_node_auth)
756
757    @call_cmd
758    def add_pg_ig_maps(args):
759        pg_ig_maps = []
760        for u in args.pg_ig_mappings.strip().split(" "):
761            pg, ig = u.split(":")
762            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
763        rpc.iscsi.add_pg_ig_maps(
764            args.client,
765            pg_ig_maps=pg_ig_maps,
766            name=args.name)
767
768    p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node')
769    p.add_argument('name', help='Target node name (ASCII)')
770    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
771    Whitespace separated, quoted, mapping defined with colon
772    separated list of "tags" (int > 0)
773    Example: '1:1 2:2 2:1'
774    *** The Portal/Initiator Groups must be precreated ***""")
775    p.set_defaults(func=add_pg_ig_maps)
776
777    @call_cmd
778    def delete_pg_ig_maps(args):
779        pg_ig_maps = []
780        for u in args.pg_ig_mappings.strip().split(" "):
781            pg, ig = u.split(":")
782            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
783        rpc.iscsi.delete_pg_ig_maps(
784            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
785
786    p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node')
787    p.add_argument('name', help='Target node name (ASCII)')
788    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
789    Whitespace separated, quoted, mapping defined with colon
790    separated list of "tags" (int > 0)
791    Example: '1:1 2:2 2:1'
792    *** The Portal/Initiator Groups must be precreated ***""")
793    p.set_defaults(func=delete_pg_ig_maps)
794
795    @call_cmd
796    def add_portal_group(args):
797        portals = []
798        for p in args.portal_list:
799            ip, separator, port_cpumask = p.rpartition(':')
800            split_port_cpumask = port_cpumask.split('@')
801            if len(split_port_cpumask) == 1:
802                port = port_cpumask
803                portals.append({'host': ip, 'port': port})
804            else:
805                port = split_port_cpumask[0]
806                cpumask = split_port_cpumask[1]
807                portals.append({'host': ip, 'port': port, 'cpumask': cpumask})
808        rpc.iscsi.add_portal_group(
809            args.client,
810            portals=portals,
811            tag=args.tag)
812
813    p = subparsers.add_parser('add_portal_group', help='Add a portal group')
814    p.add_argument(
815        'tag', help='Portal group tag (unique, integer > 0)', type=int)
816    p.add_argument('portal_list', nargs=argparse.REMAINDER, help="""List of portals in 'host:port@cpumask' format, separated by whitespace
817    (cpumask is optional and can be skipped)
818    Example: '192.168.100.100:3260' '192.168.100.100:3261' '192.168.100.100:3262@0x1""")
819    p.set_defaults(func=add_portal_group)
820
821    @call_cmd
822    def add_initiator_group(args):
823        initiators = []
824        netmasks = []
825        for i in args.initiator_list.strip().split(' '):
826            initiators.append(i)
827        for n in args.netmask_list.strip().split(' '):
828            netmasks.append(n)
829        rpc.iscsi.add_initiator_group(
830            args.client,
831            tag=args.tag,
832            initiators=initiators,
833            netmasks=netmasks)
834
835    p = subparsers.add_parser('add_initiator_group',
836                              help='Add an initiator group')
837    p.add_argument(
838        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
839    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
840    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
841    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
842    Example: '255.255.0.0 255.248.0.0' etc""")
843    p.set_defaults(func=add_initiator_group)
844
845    @call_cmd
846    def add_initiators_to_initiator_group(args):
847        initiators = None
848        netmasks = None
849        if args.initiator_list:
850            initiators = []
851            for i in args.initiator_list.strip().split(' '):
852                initiators.append(i)
853        if args.netmask_list:
854            netmasks = []
855            for n in args.netmask_list.strip().split(' '):
856                netmasks.append(n)
857        rpc.iscsi.add_initiators_to_initiator_group(
858            args.client,
859            tag=args.tag,
860            initiators=initiators,
861            netmasks=netmasks)
862
863    p = subparsers.add_parser('add_initiators_to_initiator_group',
864                              help='Add initiators to an existing initiator group')
865    p.add_argument(
866        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
867    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
868    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
869    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
870    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
871    p.set_defaults(func=add_initiators_to_initiator_group)
872
873    @call_cmd
874    def delete_initiators_from_initiator_group(args):
875        initiators = None
876        netmasks = None
877        if args.initiator_list:
878            initiators = []
879            for i in args.initiator_list.strip().split(' '):
880                initiators.append(i)
881        if args.netmask_list:
882            netmasks = []
883            for n in args.netmask_list.strip().split(' '):
884                netmasks.append(n)
885        rpc.iscsi.delete_initiators_from_initiator_group(
886            args.client,
887            tag=args.tag,
888            initiators=initiators,
889            netmasks=netmasks)
890
891    p = subparsers.add_parser('delete_initiators_from_initiator_group',
892                              help='Delete initiators from an existing initiator group')
893    p.add_argument(
894        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
895    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
896    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
897    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
898    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
899    p.set_defaults(func=delete_initiators_from_initiator_group)
900
901    @call_cmd
902    def delete_target_node(args):
903        rpc.iscsi.delete_target_node(
904            args.client, target_node_name=args.target_node_name)
905
906    p = subparsers.add_parser('delete_target_node',
907                              help='Delete a target node')
908    p.add_argument('target_node_name',
909                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
910    p.set_defaults(func=delete_target_node)
911
912    @call_cmd
913    def delete_portal_group(args):
914        rpc.iscsi.delete_portal_group(args.client, tag=args.tag)
915
916    p = subparsers.add_parser('delete_portal_group',
917                              help='Delete a portal group')
918    p.add_argument(
919        'tag', help='Portal group tag (unique, integer > 0)', type=int)
920    p.set_defaults(func=delete_portal_group)
921
922    @call_cmd
923    def delete_initiator_group(args):
924        rpc.iscsi.delete_initiator_group(args.client, tag=args.tag)
925
926    p = subparsers.add_parser('delete_initiator_group',
927                              help='Delete an initiator group')
928    p.add_argument(
929        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
930    p.set_defaults(func=delete_initiator_group)
931
932    @call_cmd
933    def get_iscsi_connections(args):
934        print_dict(rpc.iscsi.get_iscsi_connections(args.client))
935
936    p = subparsers.add_parser('get_iscsi_connections',
937                              help='Display iSCSI connections')
938    p.set_defaults(func=get_iscsi_connections)
939
940    @call_cmd
941    def get_iscsi_global_params(args):
942        print_dict(rpc.iscsi.get_iscsi_global_params(args.client))
943
944    p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters')
945    p.set_defaults(func=get_iscsi_global_params)
946
947    @call_cmd
948    def get_scsi_devices(args):
949        print_dict(rpc.iscsi.get_scsi_devices(args.client))
950
951    p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices')
952    p.set_defaults(func=get_scsi_devices)
953
954    # log
955    @call_cmd
956    def set_trace_flag(args):
957        rpc.log.set_trace_flag(args.client, flag=args.flag)
958
959    p = subparsers.add_parser('set_trace_flag', help='set trace flag')
960    p.add_argument(
961        'flag', help='trace mask we want to set. (for example "nvme").')
962    p.set_defaults(func=set_trace_flag)
963
964    @call_cmd
965    def clear_trace_flag(args):
966        rpc.log.clear_trace_flag(args.client, flag=args.flag)
967
968    p = subparsers.add_parser('clear_trace_flag', help='clear trace flag')
969    p.add_argument(
970        'flag', help='trace mask we want to clear. (for example "nvme").')
971    p.set_defaults(func=clear_trace_flag)
972
973    @call_cmd
974    def get_trace_flags(args):
975        print_dict(rpc.log.get_trace_flags(args.client))
976
977    p = subparsers.add_parser('get_trace_flags', help='get trace flags')
978    p.set_defaults(func=get_trace_flags)
979
980    @call_cmd
981    def set_log_level(args):
982        rpc.log.set_log_level(args.client, level=args.level)
983
984    p = subparsers.add_parser('set_log_level', help='set log level')
985    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
986    p.set_defaults(func=set_log_level)
987
988    @call_cmd
989    def get_log_level(args):
990        print_dict(rpc.log.get_log_level(args.client))
991
992    p = subparsers.add_parser('get_log_level', help='get log level')
993    p.set_defaults(func=get_log_level)
994
995    @call_cmd
996    def set_log_print_level(args):
997        rpc.log.set_log_print_level(args.client, level=args.level)
998
999    p = subparsers.add_parser('set_log_print_level', help='set log print level')
1000    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
1001    p.set_defaults(func=set_log_print_level)
1002
1003    @call_cmd
1004    def get_log_print_level(args):
1005        print_dict(rpc.log.get_log_print_level(args.client))
1006
1007    p = subparsers.add_parser('get_log_print_level', help='get log print level')
1008    p.set_defaults(func=get_log_print_level)
1009
1010    # lvol
1011    @call_cmd
1012    def construct_lvol_store(args):
1013        print(rpc.lvol.construct_lvol_store(args.client,
1014                                            bdev_name=args.bdev_name,
1015                                            lvs_name=args.lvs_name,
1016                                            cluster_sz=args.cluster_sz))
1017
1018    p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev')
1019    p.add_argument('bdev_name', help='base bdev name')
1020    p.add_argument('lvs_name', help='name for lvol store')
1021    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
1022    p.set_defaults(func=construct_lvol_store)
1023
1024    @call_cmd
1025    def rename_lvol_store(args):
1026        rpc.lvol.rename_lvol_store(args.client,
1027                                   old_name=args.old_name,
1028                                   new_name=args.new_name)
1029
1030    p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
1031    p.add_argument('old_name', help='old name')
1032    p.add_argument('new_name', help='new name')
1033    p.set_defaults(func=rename_lvol_store)
1034
1035    @call_cmd
1036    def construct_lvol_bdev(args):
1037        print(rpc.lvol.construct_lvol_bdev(args.client,
1038                                           lvol_name=args.lvol_name,
1039                                           size=args.size * 1024 * 1024,
1040                                           thin_provision=args.thin_provision,
1041                                           uuid=args.uuid,
1042                                           lvs_name=args.lvs_name))
1043
1044    p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
1045    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1046    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1047    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
1048    p.add_argument('lvol_name', help='name for this lvol')
1049    p.add_argument('size', help='size in MiB for this bdev', type=int)
1050    p.set_defaults(func=construct_lvol_bdev)
1051
1052    @call_cmd
1053    def snapshot_lvol_bdev(args):
1054        print(rpc.lvol.snapshot_lvol_bdev(args.client,
1055                                          lvol_name=args.lvol_name,
1056                                          snapshot_name=args.snapshot_name))
1057
1058    p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
1059    p.add_argument('lvol_name', help='lvol bdev name')
1060    p.add_argument('snapshot_name', help='lvol snapshot name')
1061    p.set_defaults(func=snapshot_lvol_bdev)
1062
1063    @call_cmd
1064    def clone_lvol_bdev(args):
1065        print(rpc.lvol.clone_lvol_bdev(args.client,
1066                                       snapshot_name=args.snapshot_name,
1067                                       clone_name=args.clone_name))
1068
1069    p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
1070    p.add_argument('snapshot_name', help='lvol snapshot name')
1071    p.add_argument('clone_name', help='lvol clone name')
1072    p.set_defaults(func=clone_lvol_bdev)
1073
1074    @call_cmd
1075    def rename_lvol_bdev(args):
1076        rpc.lvol.rename_lvol_bdev(args.client,
1077                                  old_name=args.old_name,
1078                                  new_name=args.new_name)
1079
1080    p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name')
1081    p.add_argument('old_name', help='lvol bdev name')
1082    p.add_argument('new_name', help='new lvol name')
1083    p.set_defaults(func=rename_lvol_bdev)
1084
1085    @call_cmd
1086    def inflate_lvol_bdev(args):
1087        rpc.lvol.inflate_lvol_bdev(args.client,
1088                                   name=args.name)
1089
1090    p = subparsers.add_parser('inflate_lvol_bdev', help='Make thin provisioned lvol a thick provisioned lvol')
1091    p.add_argument('name', help='lvol bdev name')
1092    p.set_defaults(func=inflate_lvol_bdev)
1093
1094    @call_cmd
1095    def decouple_parent_lvol_bdev(args):
1096        rpc.lvol.decouple_parent_lvol_bdev(args.client,
1097                                           name=args.name)
1098
1099    p = subparsers.add_parser('decouple_parent_lvol_bdev', help='Decouple parent of lvol')
1100    p.add_argument('name', help='lvol bdev name')
1101    p.set_defaults(func=decouple_parent_lvol_bdev)
1102
1103    @call_cmd
1104    def resize_lvol_bdev(args):
1105        rpc.lvol.resize_lvol_bdev(args.client,
1106                                  name=args.name,
1107                                  size=args.size * 1024 * 1024)
1108
1109    p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev')
1110    p.add_argument('name', help='lvol bdev name')
1111    p.add_argument('size', help='new size in MiB for this bdev', type=int)
1112    p.set_defaults(func=resize_lvol_bdev)
1113
1114    @call_cmd
1115    def destroy_lvol_bdev(args):
1116        rpc.lvol.destroy_lvol_bdev(args.client,
1117                                   name=args.name)
1118
1119    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
1120    p.add_argument('name', help='lvol bdev name')
1121    p.set_defaults(func=destroy_lvol_bdev)
1122
1123    @call_cmd
1124    def destroy_lvol_store(args):
1125        rpc.lvol.destroy_lvol_store(args.client,
1126                                    uuid=args.uuid,
1127                                    lvs_name=args.lvs_name)
1128
1129    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
1130    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1131    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1132    p.set_defaults(func=destroy_lvol_store)
1133
1134    @call_cmd
1135    def get_lvol_stores(args):
1136        print_dict(rpc.lvol.get_lvol_stores(args.client,
1137                                            uuid=args.uuid,
1138                                            lvs_name=args.lvs_name))
1139
1140    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
1141    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1142    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1143    p.set_defaults(func=get_lvol_stores)
1144
1145    @call_cmd
1146    def get_raid_bdevs(args):
1147        print_array(rpc.bdev.get_raid_bdevs(args.client,
1148                                            category=args.category))
1149
1150    p = subparsers.add_parser('get_raid_bdevs', help="""This is used to list all the raid bdev names based on the input category
1151    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
1152    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
1153    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
1154    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
1155    p.add_argument('category', help='all or online or configuring or offline')
1156    p.set_defaults(func=get_raid_bdevs)
1157
1158    @call_cmd
1159    def construct_raid_bdev(args):
1160        base_bdevs = []
1161        for u in args.base_bdevs.strip().split(" "):
1162            base_bdevs.append(u)
1163
1164        rpc.bdev.construct_raid_bdev(args.client,
1165                                     name=args.name,
1166                                     strip_size=args.strip_size,
1167                                     raid_level=args.raid_level,
1168                                     base_bdevs=base_bdevs)
1169    p = subparsers.add_parser('construct_raid_bdev', help='Construct new raid bdev')
1170    p.add_argument('-n', '--name', help='raid bdev name', required=True)
1171    p.add_argument('-s', '--strip-size', help='strip size in KB', type=int, required=True)
1172    p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', type=int, required=True)
1173    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
1174    p.set_defaults(func=construct_raid_bdev)
1175
1176    @call_cmd
1177    def destroy_raid_bdev(args):
1178        rpc.bdev.destroy_raid_bdev(args.client,
1179                                   name=args.name)
1180    p = subparsers.add_parser('destroy_raid_bdev', help='Destroy existing raid bdev')
1181    p.add_argument('name', help='raid bdev name')
1182    p.set_defaults(func=destroy_raid_bdev)
1183
1184    # split
1185    @call_cmd
1186    def construct_split_vbdev(args):
1187        print_array(rpc.bdev.construct_split_vbdev(args.client,
1188                                                   base_bdev=args.base_bdev,
1189                                                   split_count=args.split_count,
1190                                                   split_size_mb=args.split_size_mb))
1191
1192    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
1193    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
1194    available (during examination process).""")
1195    p.add_argument('base_bdev', help='base bdev name')
1196    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
1197    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
1198    exceed the base bdev size.""", type=int)
1199    p.set_defaults(func=construct_split_vbdev)
1200
1201    @call_cmd
1202    def destruct_split_vbdev(args):
1203        rpc.bdev.destruct_split_vbdev(args.client,
1204                                      base_bdev=args.base_bdev)
1205
1206    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
1207    p.add_argument('base_bdev', help='base bdev name')
1208    p.set_defaults(func=destruct_split_vbdev)
1209
1210    # nbd
1211    @call_cmd
1212    def start_nbd_disk(args):
1213        print(rpc.nbd.start_nbd_disk(args.client,
1214                                     bdev_name=args.bdev_name,
1215                                     nbd_device=args.nbd_device))
1216
1217    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
1218    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
1219    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.')
1220    p.set_defaults(func=start_nbd_disk)
1221
1222    @call_cmd
1223    def stop_nbd_disk(args):
1224        rpc.nbd.stop_nbd_disk(args.client,
1225                              nbd_device=args.nbd_device)
1226
1227    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
1228    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
1229    p.set_defaults(func=stop_nbd_disk)
1230
1231    @call_cmd
1232    def get_nbd_disks(args):
1233        print_dict(rpc.nbd.get_nbd_disks(args.client,
1234                                         nbd_device=args.nbd_device))
1235
1236    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
1237    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
1238    p.set_defaults(func=get_nbd_disks)
1239
1240    # net
1241    @call_cmd
1242    def add_ip_address(args):
1243        rpc.net.add_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1244
1245    p = subparsers.add_parser('add_ip_address', help='Add IP address')
1246    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1247    p.add_argument('ip_addr', help='ip address will be added.')
1248    p.set_defaults(func=add_ip_address)
1249
1250    @call_cmd
1251    def delete_ip_address(args):
1252        rpc.net.delete_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1253
1254    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
1255    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1256    p.add_argument('ip_addr', help='ip address will be deleted.')
1257    p.set_defaults(func=delete_ip_address)
1258
1259    @call_cmd
1260    def get_interfaces(args):
1261        print_dict(rpc.net.get_interfaces(args.client))
1262
1263    p = subparsers.add_parser(
1264        'get_interfaces', help='Display current interface list')
1265    p.set_defaults(func=get_interfaces)
1266
1267    # NVMe-oF
1268    @call_cmd
1269    def set_nvmf_target_options(args):
1270        rpc.nvmf.set_nvmf_target_options(args.client,
1271                                         max_queue_depth=args.max_queue_depth,
1272                                         max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1273                                         in_capsule_data_size=args.in_capsule_data_size,
1274                                         max_io_size=args.max_io_size,
1275                                         max_subsystems=args.max_subsystems,
1276                                         io_unit_size=args.io_unit_size)
1277
1278    p = subparsers.add_parser('set_nvmf_target_options', help='Set NVMf target options')
1279    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1280    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1281    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1282    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1283    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int)
1284    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1285    p.set_defaults(func=set_nvmf_target_options)
1286
1287    @call_cmd
1288    def set_nvmf_target_max_subsystems(args):
1289        rpc.nvmf.set_nvmf_target_max_subsystems(args.client,
1290                                                max_subsystems=args.max_subsystems)
1291
1292    p = subparsers.add_parser('set_nvmf_target_max_subsystems', help='Set the maximum number of NVMf target subsystems')
1293    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True)
1294    p.set_defaults(func=set_nvmf_target_max_subsystems)
1295
1296    @call_cmd
1297    def set_nvmf_target_config(args):
1298        rpc.nvmf.set_nvmf_target_config(args.client,
1299                                        acceptor_poll_rate=args.acceptor_poll_rate,
1300                                        conn_sched=args.conn_sched)
1301
1302    p = subparsers.add_parser('set_nvmf_target_config', help='Set NVMf target config')
1303    p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
1304    p.add_argument('-s', '--conn-sched', help="""'roundrobin' - Schedule the incoming connections from any host
1305    on the cores in a round robin manner (Default). 'hostip' - Schedule all the incoming connections from a
1306    specific host IP on to the same core. Connections from different IP will be assigned to cores in a round
1307    robin manner""")
1308    p.set_defaults(func=set_nvmf_target_config)
1309
1310    @call_cmd
1311    def nvmf_create_transport(args):
1312        rpc.nvmf.nvmf_create_transport(args.client,
1313                                       trtype=args.trtype,
1314                                       max_queue_depth=args.max_queue_depth,
1315                                       max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1316                                       in_capsule_data_size=args.in_capsule_data_size,
1317                                       max_io_size=args.max_io_size,
1318                                       io_unit_size=args.io_unit_size,
1319                                       max_aq_depth=args.max_aq_depth)
1320
1321    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
1322    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
1323    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1324    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1325    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1326    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1327    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1328    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
1329    p.set_defaults(func=nvmf_create_transport)
1330
1331    @call_cmd
1332    def get_nvmf_transports(args):
1333        print_dict(rpc.nvmf.get_nvmf_transports(args.client))
1334
1335    p = subparsers.add_parser('get_nvmf_transports',
1336                              help='Display nvmf transports')
1337    p.set_defaults(func=get_nvmf_transports)
1338
1339    @call_cmd
1340    def get_nvmf_subsystems(args):
1341        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client))
1342
1343    p = subparsers.add_parser('get_nvmf_subsystems',
1344                              help='Display nvmf subsystems')
1345    p.set_defaults(func=get_nvmf_subsystems)
1346
1347    @call_cmd
1348    def construct_nvmf_subsystem(args):
1349        listen_addresses = None
1350        hosts = None
1351        namespaces = None
1352        if args.listen:
1353            listen_addresses = [
1354                dict(
1355                    u.split(
1356                        ":",
1357                        1) for u in a.split(" ")) for a in args.listen.split(",")]
1358
1359        if args.hosts:
1360            hosts = []
1361            for u in args.hosts.strip().split(" "):
1362                hosts.append(u)
1363
1364        if args.namespaces:
1365            namespaces = []
1366            for u in args.namespaces.strip().split(" "):
1367                bdev_name = u
1368                nsid = 0
1369                if ':' in u:
1370                    (bdev_name, nsid) = u.split(":")
1371
1372                ns_params = {'bdev_name': bdev_name}
1373
1374                nsid = int(nsid)
1375                if nsid != 0:
1376                    ns_params['nsid'] = nsid
1377
1378                namespaces.append(ns_params)
1379
1380        rpc.nvmf.construct_nvmf_subsystem(args.client,
1381                                          nqn=args.nqn,
1382                                          listen_addresses=listen_addresses,
1383                                          hosts=hosts,
1384                                          allow_any_host=args.allow_any_host,
1385                                          serial_number=args.serial_number,
1386                                          namespaces=namespaces,
1387                                          max_namespaces=args.max_namespaces)
1388
1389    p = subparsers.add_parser('construct_nvmf_subsystem', help='Add a nvmf subsystem')
1390    p.add_argument('nqn', help='Target nqn(ASCII)')
1391    p.add_argument('listen', help="""comma-separated list of Listen <trtype:transport_name traddr:address trsvcid:port_id> pairs enclosed
1392    in quotes.  Format:  'trtype:transport0 traddr:traddr0 trsvcid:trsvcid0,trtype:transport1 traddr:traddr1 trsvcid:trsvcid1' etc
1393    Example: 'trtype:RDMA traddr:192.168.100.8 trsvcid:4420,trtype:RDMA traddr:192.168.100.9 trsvcid:4420'""")
1394    p.add_argument('hosts', help="""Whitespace-separated list of host nqn list.
1395    Format:  'nqn1 nqn2' etc
1396    Example: 'nqn.2016-06.io.spdk:init nqn.2016-07.io.spdk:init'""")
1397    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1398    p.add_argument("-s", "--serial-number", help="""
1399    Format:  'sn' etc
1400    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1401    p.add_argument("-n", "--namespaces", help="""Whitespace-separated list of namespaces
1402    Format:  'bdev_name1[:nsid1] bdev_name2[:nsid2] bdev_name3[:nsid3]' etc
1403    Example: '1:Malloc0 2:Malloc1 3:Malloc2'
1404    *** The devices must pre-exist ***""")
1405    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed to added during active connection",
1406                   type=int, default=0)
1407    p.set_defaults(func=construct_nvmf_subsystem)
1408
1409    @call_cmd
1410    def nvmf_subsystem_create(args):
1411        rpc.nvmf.nvmf_subsystem_create(args.client,
1412                                       nqn=args.nqn,
1413                                       serial_number=args.serial_number,
1414                                       allow_any_host=args.allow_any_host,
1415                                       max_namespaces=args.max_namespaces)
1416
1417    p = subparsers.add_parser('nvmf_subsystem_create', help='Create an NVMe-oF subsystem')
1418    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
1419    p.add_argument("-s", "--serial-number", help="""
1420    Format:  'sn' etc
1421    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1422    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1423    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
1424                   type=int, default=0)
1425    p.set_defaults(func=nvmf_subsystem_create)
1426
1427    @call_cmd
1428    def delete_nvmf_subsystem(args):
1429        rpc.nvmf.delete_nvmf_subsystem(args.client,
1430                                       nqn=args.subsystem_nqn)
1431
1432    p = subparsers.add_parser('delete_nvmf_subsystem',
1433                              help='Delete a nvmf subsystem')
1434    p.add_argument('subsystem_nqn',
1435                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
1436    p.set_defaults(func=delete_nvmf_subsystem)
1437
1438    @call_cmd
1439    def nvmf_subsystem_add_listener(args):
1440        rpc.nvmf.nvmf_subsystem_add_listener(args.client,
1441                                             nqn=args.nqn,
1442                                             trtype=args.trtype,
1443                                             traddr=args.traddr,
1444                                             adrfam=args.adrfam,
1445                                             trsvcid=args.trsvcid)
1446
1447    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
1448    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1449    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1450    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1451    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1452    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1453    p.set_defaults(func=nvmf_subsystem_add_listener)
1454
1455    @call_cmd
1456    def nvmf_subsystem_remove_listener(args):
1457        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
1458                                                nqn=args.nqn,
1459                                                trtype=args.trtype,
1460                                                traddr=args.traddr,
1461                                                adrfam=args.adrfam,
1462                                                trsvcid=args.trsvcid)
1463
1464    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
1465    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1466    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1467    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1468    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1469    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1470    p.set_defaults(func=nvmf_subsystem_remove_listener)
1471
1472    @call_cmd
1473    def nvmf_subsystem_add_ns(args):
1474        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
1475                                       nqn=args.nqn,
1476                                       bdev_name=args.bdev_name,
1477                                       nsid=args.nsid,
1478                                       nguid=args.nguid,
1479                                       eui64=args.eui64,
1480                                       uuid=args.uuid)
1481
1482    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
1483    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1484    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
1485    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
1486    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
1487    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
1488    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
1489    p.set_defaults(func=nvmf_subsystem_add_ns)
1490
1491    @call_cmd
1492    def nvmf_subsystem_remove_ns(args):
1493        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
1494                                          nqn=args.nqn,
1495                                          nsid=args.nsid)
1496
1497    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
1498    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1499    p.add_argument('nsid', help='The requested NSID', type=int)
1500    p.set_defaults(func=nvmf_subsystem_remove_ns)
1501
1502    @call_cmd
1503    def nvmf_subsystem_add_host(args):
1504        rpc.nvmf.nvmf_subsystem_add_host(args.client,
1505                                         nqn=args.nqn,
1506                                         host=args.host)
1507
1508    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
1509    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1510    p.add_argument('host', help='Host NQN to allow')
1511    p.set_defaults(func=nvmf_subsystem_add_host)
1512
1513    @call_cmd
1514    def nvmf_subsystem_remove_host(args):
1515        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
1516                                            nqn=args.nqn,
1517                                            host=args.host)
1518
1519    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
1520    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1521    p.add_argument('host', help='Host NQN to remove')
1522    p.set_defaults(func=nvmf_subsystem_remove_host)
1523
1524    @call_cmd
1525    def nvmf_subsystem_allow_any_host(args):
1526        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
1527                                               nqn=args.nqn,
1528                                               disable=args.disable)
1529
1530    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
1531    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1532    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
1533    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
1534    p.set_defaults(func=nvmf_subsystem_allow_any_host)
1535
1536    # pmem
1537    @call_cmd
1538    def create_pmem_pool(args):
1539        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
1540        rpc.pmem.create_pmem_pool(args.client,
1541                                  pmem_file=args.pmem_file,
1542                                  num_blocks=num_blocks,
1543                                  block_size=args.block_size)
1544
1545    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
1546    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1547    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
1548    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
1549    p.set_defaults(func=create_pmem_pool)
1550
1551    @call_cmd
1552    def pmem_pool_info(args):
1553        print_dict(rpc.pmem.pmem_pool_info(args.client,
1554                                           pmem_file=args.pmem_file))
1555
1556    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
1557    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1558    p.set_defaults(func=pmem_pool_info)
1559
1560    @call_cmd
1561    def delete_pmem_pool(args):
1562        rpc.pmem.delete_pmem_pool(args.client,
1563                                  pmem_file=args.pmem_file)
1564
1565    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
1566    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1567    p.set_defaults(func=delete_pmem_pool)
1568
1569    # subsystem
1570    @call_cmd
1571    def get_subsystems(args):
1572        print_dict(rpc.subsystem.get_subsystems(args.client))
1573
1574    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
1575    entry contain (unsorted) array of subsystems it depends on.""")
1576    p.set_defaults(func=get_subsystems)
1577
1578    @call_cmd
1579    def get_subsystem_config(args):
1580        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
1581
1582    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
1583    p.add_argument('name', help='Name of subsystem to query')
1584    p.set_defaults(func=get_subsystem_config)
1585
1586    # vhost
1587    @call_cmd
1588    def set_vhost_controller_coalescing(args):
1589        rpc.vhost.set_vhost_controller_coalescing(args.client,
1590                                                  ctrlr=args.ctrlr,
1591                                                  delay_base_us=args.delay_base_us,
1592                                                  iops_threshold=args.iops_threshold)
1593
1594    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
1595    p.add_argument('ctrlr', help='controller name')
1596    p.add_argument('delay_base_us', help='Base delay time', type=int)
1597    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
1598    p.set_defaults(func=set_vhost_controller_coalescing)
1599
1600    @call_cmd
1601    def construct_vhost_scsi_controller(args):
1602        rpc.vhost.construct_vhost_scsi_controller(args.client,
1603                                                  ctrlr=args.ctrlr,
1604                                                  cpumask=args.cpumask)
1605
1606    p = subparsers.add_parser(
1607        'construct_vhost_scsi_controller', help='Add new vhost controller')
1608    p.add_argument('ctrlr', help='controller name')
1609    p.add_argument('--cpumask', help='cpu mask for this controller')
1610    p.set_defaults(func=construct_vhost_scsi_controller)
1611
1612    @call_cmd
1613    def add_vhost_scsi_lun(args):
1614        rpc.vhost.add_vhost_scsi_lun(args.client,
1615                                     ctrlr=args.ctrlr,
1616                                     scsi_target_num=args.scsi_target_num,
1617                                     bdev_name=args.bdev_name)
1618
1619    p = subparsers.add_parser('add_vhost_scsi_lun',
1620                              help='Add lun to vhost controller')
1621    p.add_argument('ctrlr', help='conntroller name where add lun')
1622    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1623    p.add_argument('bdev_name', help='bdev name')
1624    p.set_defaults(func=add_vhost_scsi_lun)
1625
1626    @call_cmd
1627    def remove_vhost_scsi_target(args):
1628        rpc.vhost.remove_vhost_scsi_target(args.client,
1629                                           ctrlr=args.ctrlr,
1630                                           scsi_target_num=args.scsi_target_num)
1631
1632    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
1633    p.add_argument('ctrlr', help='controller name to remove target from')
1634    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1635    p.set_defaults(func=remove_vhost_scsi_target)
1636
1637    @call_cmd
1638    def construct_vhost_blk_controller(args):
1639        rpc.vhost.construct_vhost_blk_controller(args.client,
1640                                                 ctrlr=args.ctrlr,
1641                                                 dev_name=args.dev_name,
1642                                                 cpumask=args.cpumask,
1643                                                 readonly=args.readonly)
1644
1645    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
1646    p.add_argument('ctrlr', help='controller name')
1647    p.add_argument('dev_name', help='device name')
1648    p.add_argument('--cpumask', help='cpu mask for this controller')
1649    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1650    p.set_defaults(func=construct_vhost_blk_controller)
1651
1652    @call_cmd
1653    def construct_vhost_nvme_controller(args):
1654        rpc.vhost.construct_vhost_nvme_controller(args.client,
1655                                                  ctrlr=args.ctrlr,
1656                                                  io_queues=args.io_queues,
1657                                                  cpumask=args.cpumask)
1658
1659    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
1660    p.add_argument('ctrlr', help='controller name')
1661    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
1662    p.add_argument('--cpumask', help='cpu mask for this controller')
1663    p.set_defaults(func=construct_vhost_nvme_controller)
1664
1665    @call_cmd
1666    def add_vhost_nvme_ns(args):
1667        rpc.vhost.add_vhost_nvme_ns(args.client,
1668                                    ctrlr=args.ctrlr,
1669                                    bdev_name=args.bdev_name)
1670
1671    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
1672    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
1673    p.add_argument('bdev_name', help='block device name for a new Namespace')
1674    p.set_defaults(func=add_vhost_nvme_ns)
1675
1676    @call_cmd
1677    def get_vhost_controllers(args):
1678        print_dict(rpc.vhost.get_vhost_controllers(args.client, args.name))
1679
1680    p = subparsers.add_parser('get_vhost_controllers', help='List all or specific vhost controller(s)')
1681    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
1682    p.set_defaults(func=get_vhost_controllers)
1683
1684    @call_cmd
1685    def remove_vhost_controller(args):
1686        rpc.vhost.remove_vhost_controller(args.client,
1687                                          ctrlr=args.ctrlr)
1688
1689    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
1690    p.add_argument('ctrlr', help='controller name')
1691    p.set_defaults(func=remove_vhost_controller)
1692
1693    @call_cmd
1694    def construct_virtio_dev(args):
1695        print_array(rpc.vhost.construct_virtio_dev(args.client,
1696                                                   name=args.name,
1697                                                   trtype=args.trtype,
1698                                                   traddr=args.traddr,
1699                                                   dev_type=args.dev_type,
1700                                                   vq_count=args.vq_count,
1701                                                   vq_size=args.vq_size))
1702
1703    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
1704    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
1705    remote side. Result is array of added bdevs.""")
1706    p.add_argument('name', help="Use this name as base for new created bdevs")
1707    p.add_argument('-t', '--trtype',
1708                   help='Virtio target transport type: pci or user', required=True)
1709    p.add_argument('-a', '--traddr',
1710                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
1711    p.add_argument('-d', '--dev-type',
1712                   help='Device type: blk or scsi', required=True)
1713    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1714    p.add_argument('--vq-size', help='Size of each queue', type=int)
1715    p.set_defaults(func=construct_virtio_dev)
1716
1717    @call_cmd
1718    def construct_virtio_user_scsi_bdev(args):
1719        print_array(rpc.vhost.construct_virtio_user_scsi_bdev(args.client,
1720                                                              path=args.path,
1721                                                              name=args.name,
1722                                                              vq_count=args.vq_count,
1723                                                              vq_size=args.vq_size))
1724
1725    p = subparsers.add_parser('construct_virtio_user_scsi_bdev', help="""Connect to virtio user scsi device.
1726    This imply scan and add bdevs offered by remote side.
1727    Result is array of added bdevs.""")
1728    p.add_argument('path', help='Path to Virtio SCSI socket')
1729    p.add_argument('name', help="""Use this name as base instead of 'VirtioScsiN'
1730    Base will be used to construct new bdev's found on target by adding 't<TARGET_ID>' sufix.""")
1731    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1732    p.add_argument('--vq-size', help='Size of each queue', type=int)
1733    p.set_defaults(func=construct_virtio_user_scsi_bdev)
1734
1735    @call_cmd
1736    def construct_virtio_pci_scsi_bdev(args):
1737        print_array(rpc.vhost.construct_virtio_pci_scsi_bdev(args.client,
1738                                                             pci_address=args.pci_address,
1739                                                             name=args.name))
1740
1741    p = subparsers.add_parser('construct_virtio_pci_scsi_bdev', help="""Create a Virtio
1742    SCSI device from a virtio-pci device.""")
1743    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1744    domain.bus.device.function format""")
1745    p.add_argument('name', help="""Name for the virtio device.
1746    It will be inhereted by all created bdevs, which are named n the following format: <name>t<target_id>""")
1747    p.set_defaults(func=construct_virtio_pci_scsi_bdev)
1748
1749    @call_cmd
1750    def get_virtio_scsi_devs(args):
1751        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client))
1752
1753    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
1754    p.set_defaults(func=get_virtio_scsi_devs)
1755
1756    @call_cmd
1757    def remove_virtio_scsi_bdev(args):
1758        rpc.vhost.remove_virtio_scsi_bdev(args.client,
1759                                          name=args.name)
1760
1761    p = subparsers.add_parser('remove_virtio_scsi_bdev', help="""Remove a Virtio-SCSI device
1762    This will delete all bdevs exposed by this device (this call is deprecated - please use remove_virtio_bdev call instead).""")
1763    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1764    p.set_defaults(func=remove_virtio_scsi_bdev)
1765
1766    @call_cmd
1767    def remove_virtio_bdev(args):
1768        rpc.vhost.remove_virtio_bdev(args.client,
1769                                     name=args.name)
1770
1771    p = subparsers.add_parser('remove_virtio_bdev', help="""Remove a Virtio device
1772    This will delete all bdevs exposed by this device""")
1773    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1774    p.set_defaults(func=remove_virtio_bdev)
1775
1776    @call_cmd
1777    def construct_virtio_user_blk_bdev(args):
1778        print(rpc.vhost.construct_virtio_user_blk_bdev(args.client,
1779                                                       path=args.path,
1780                                                       name=args.name,
1781                                                       vq_count=args.vq_count,
1782                                                       vq_size=args.vq_size))
1783
1784    p = subparsers.add_parser('construct_virtio_user_blk_bdev', help='Connect to a virtio user blk device.')
1785    p.add_argument('path', help='Path to Virtio BLK socket')
1786    p.add_argument('name', help='Name for the bdev')
1787    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1788    p.add_argument('--vq-size', help='Size of each queue', type=int)
1789    p.set_defaults(func=construct_virtio_user_blk_bdev)
1790
1791    @call_cmd
1792    def construct_virtio_pci_blk_bdev(args):
1793        print(rpc.vhost.construct_virtio_pci_blk_bdev(args.client,
1794                                                      pci_address=args.pci_address,
1795                                                      name=args.name))
1796
1797    p = subparsers.add_parser('construct_virtio_pci_blk_bdev', help='Create a Virtio Blk device from a virtio-pci device.')
1798    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1799    domain.bus.device.function format""")
1800    p.add_argument('name', help='Name for the bdev')
1801    p.set_defaults(func=construct_virtio_pci_blk_bdev)
1802
1803    # ioat
1804    @call_cmd
1805    def scan_ioat_copy_engine(args):
1806        pci_whitelist = []
1807        if args.pci_whitelist:
1808            for w in args.pci_whitelist.strip().split(" "):
1809                pci_whitelist.append(w)
1810        rpc.ioat.scan_ioat_copy_engine(args.client, pci_whitelist)
1811
1812    p = subparsers.add_parser('scan_ioat_copy_engine', help='Set scan and enable IOAT copy engine offload.')
1813    p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in
1814    domain:bus:device.function format or domain.bus.device.function format""")
1815    p.set_defaults(func=scan_ioat_copy_engine)
1816
1817    # send_nvme_cmd
1818    @call_cmd
1819    def send_nvme_cmd(args):
1820        print_dict(rpc.nvme.send_nvme_cmd(args.client,
1821                                          name=args.nvme_name,
1822                                          cmd_type=args.cmd_type,
1823                                          data_direction=args.data_direction,
1824                                          cmdbuf=args.cmdbuf,
1825                                          data=args.data,
1826                                          metadata=args.metadata,
1827                                          data_len=args.data_length,
1828                                          metadata_len=args.metadata_length,
1829                                          timeout_ms=args.timeout_ms))
1830
1831    p = subparsers.add_parser('send_nvme_cmd', help='NVMe passthrough cmd.')
1832    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
1833    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
1834    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
1835    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
1836    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
1837    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
1838    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
1839    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
1840    p.add_argument('-T', '--timeout-ms',
1841                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int, default=0)
1842    p.set_defaults(func=send_nvme_cmd)
1843
1844    args = parser.parse_args()
1845
1846    try:
1847        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.verbose, args.timeout)
1848    except JSONRPCException as ex:
1849        print(ex.message)
1850        exit(1)
1851    args.func(args)
1852