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