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