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