xref: /spdk/scripts/rpc.py (revision 1fc4165fe9bf8512483356ad8e6d27f793f2e3db)
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 domain socket path or IP 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='Timeout as a floating point number expressed in seconds waiting for response. 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 enable_bdev_histogram(args):
469        rpc.bdev.enable_bdev_histogram(args.client, name=args.name, enable=args.enable)
470
471    p = subparsers.add_parser('enable_bdev_histogram', help='Enable or disable histogram for specified bdev')
472    p.add_argument('-e', '--enable', default=True, dest='enable', action='store_true', help='Enable histograms on specified device')
473    p.add_argument('-d', '--disable', dest='enable', action='store_false', help='Disable histograms on specified device')
474    p.add_argument('name', help='bdev name')
475    p.set_defaults(func=enable_bdev_histogram)
476
477    def get_bdev_histogram(args):
478        print_dict(rpc.bdev.get_bdev_histogram(args.client, name=args.name))
479
480    p = subparsers.add_parser('get_bdev_histogram', help='Get histogram for specified bdev')
481    p.add_argument('name', help='bdev name')
482    p.set_defaults(func=get_bdev_histogram)
483
484    def set_bdev_qd_sampling_period(args):
485        rpc.bdev.set_bdev_qd_sampling_period(args.client,
486                                             name=args.name,
487                                             period=args.period)
488
489    p = subparsers.add_parser('set_bdev_qd_sampling_period', help="Enable or disable tracking of a bdev's queue depth.")
490    p.add_argument('name', help='Blockdev name. Example: Malloc0')
491    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
492                   ' If set to 0, polling will be disabled.',
493                   type=int)
494    p.set_defaults(func=set_bdev_qd_sampling_period)
495
496    def set_bdev_qos_limit(args):
497        rpc.bdev.set_bdev_qos_limit(args.client,
498                                    name=args.name,
499                                    rw_ios_per_sec=args.rw_ios_per_sec,
500                                    rw_mbytes_per_sec=args.rw_mbytes_per_sec,
501                                    r_mbytes_per_sec=args.r_mbytes_per_sec,
502                                    w_mbytes_per_sec=args.w_mbytes_per_sec)
503
504    p = subparsers.add_parser('set_bdev_qos_limit', help='Set QoS rate limit on a blockdev')
505    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
506    p.add_argument('--rw_ios_per_sec',
507                   help='R/W IOs per second limit (>=10000, example: 20000). 0 means unlimited.',
508                   type=int, required=False)
509    p.add_argument('--rw_mbytes_per_sec',
510                   help="R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.",
511                   type=int, required=False)
512    p.add_argument('--r_mbytes_per_sec',
513                   help="Read megabytes per second limit (>=10, example: 100). 0 means unlimited.",
514                   type=int, required=False)
515    p.add_argument('--w_mbytes_per_sec',
516                   help="Write megabytes per second limit (>=10, example: 100). 0 means unlimited.",
517                   type=int, required=False)
518    p.set_defaults(func=set_bdev_qos_limit)
519
520    def bdev_inject_error(args):
521        rpc.bdev.bdev_inject_error(args.client,
522                                   name=args.name,
523                                   io_type=args.io_type,
524                                   error_type=args.error_type,
525                                   num=args.num)
526
527    p = subparsers.add_parser('bdev_inject_error', help='bdev inject error')
528    p.add_argument('name', help="""the name of the error injection bdev""")
529    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
530    p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
531    p.add_argument(
532        '-n', '--num', help='the number of commands you want to fail', type=int, default=1)
533    p.set_defaults(func=bdev_inject_error)
534
535    def apply_firmware(args):
536        print_dict(rpc.bdev.apply_firmware(args.client,
537                                           bdev_name=args.bdev_name,
538                                           filename=args.filename))
539
540    p = subparsers.add_parser('apply_firmware', help='Download and commit firmware to NVMe device')
541    p.add_argument('filename', help='filename of the firmware to download')
542    p.add_argument('bdev_name', help='name of the NVMe device')
543    p.set_defaults(func=apply_firmware)
544
545    # iSCSI
546    def set_iscsi_options(args):
547        rpc.iscsi.set_iscsi_options(
548            args.client,
549            auth_file=args.auth_file,
550            node_base=args.node_base,
551            nop_timeout=args.nop_timeout,
552            nop_in_interval=args.nop_in_interval,
553            disable_chap=args.disable_chap,
554            require_chap=args.require_chap,
555            mutual_chap=args.mutual_chap,
556            chap_group=args.chap_group,
557            max_sessions=args.max_sessions,
558            max_queue_depth=args.max_queue_depth,
559            max_connections_per_session=args.max_connections_per_session,
560            default_time2wait=args.default_time2wait,
561            default_time2retain=args.default_time2retain,
562            first_burst_length=args.first_burst_length,
563            immediate_data=args.immediate_data,
564            error_recovery_level=args.error_recovery_level,
565            allow_duplicated_isid=args.allow_duplicated_isid,
566            min_connections_per_core=args.min_connections_per_core)
567
568    p = subparsers.add_parser('set_iscsi_options', help="""Set options of iSCSI subsystem""")
569    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file')
570    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
571    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
572    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
573    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
574    *** Mutually exclusive with --require-chap""", action='store_true')
575    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
576    *** Mutually exclusive with --disable-chap""", action='store_true')
577    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
578    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
579    *** Authentication group must be precreated ***""", type=int)
580    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
581    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int)
582    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
583    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
584    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
585    p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int)
586    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
587    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
588    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
589    p.add_argument('-u', '--min-connections-per-core', help='Allocation unit of connections per core', type=int)
590    p.set_defaults(func=set_iscsi_options)
591
592    def set_iscsi_discovery_auth(args):
593        rpc.iscsi.set_iscsi_discovery_auth(
594            args.client,
595            disable_chap=args.disable_chap,
596            require_chap=args.require_chap,
597            mutual_chap=args.mutual_chap,
598            chap_group=args.chap_group)
599
600    p = subparsers.add_parser('set_iscsi_discovery_auth', help="""Set CHAP authentication for discovery session.""")
601    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
602    *** Mutually exclusive with --require-chap""", action='store_true')
603    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
604    *** Mutually exclusive with --disable-chap""", action='store_true')
605    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
606    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
607    *** Authentication group must be precreated ***""", type=int)
608    p.set_defaults(func=set_iscsi_discovery_auth)
609
610    def add_iscsi_auth_group(args):
611        secrets = None
612        if args.secrets:
613            secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")]
614
615        rpc.iscsi.add_iscsi_auth_group(args.client, tag=args.tag, secrets=secrets)
616
617    p = subparsers.add_parser('add_iscsi_auth_group', help='Add authentication group for CHAP authentication.')
618    p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int)
619    p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets
620<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes.
621Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False)
622    p.set_defaults(func=add_iscsi_auth_group)
623
624    def delete_iscsi_auth_group(args):
625        rpc.iscsi.delete_iscsi_auth_group(args.client, tag=args.tag)
626
627    p = subparsers.add_parser('delete_iscsi_auth_group', help='Delete an authentication group.')
628    p.add_argument('tag', help='Authentication group tag', type=int)
629    p.set_defaults(func=delete_iscsi_auth_group)
630
631    def add_secret_to_iscsi_auth_group(args):
632        rpc.iscsi.add_secret_to_iscsi_auth_group(
633            args.client,
634            tag=args.tag,
635            user=args.user,
636            secret=args.secret,
637            muser=args.muser,
638            msecret=args.msecret)
639
640    p = subparsers.add_parser('add_secret_to_iscsi_auth_group', help='Add a secret to an authentication group.')
641    p.add_argument('tag', help='Authentication group tag', type=int)
642    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
643    p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True)
644    p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication')
645    p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication')
646    p.set_defaults(func=add_secret_to_iscsi_auth_group)
647
648    def delete_secret_from_iscsi_auth_group(args):
649        rpc.iscsi.delete_secret_from_iscsi_auth_group(args.client, tag=args.tag, user=args.user)
650
651    p = subparsers.add_parser('delete_secret_from_iscsi_auth_group', help='Delete a secret from an authentication group.')
652    p.add_argument('tag', help='Authentication group tag', type=int)
653    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
654    p.set_defaults(func=delete_secret_from_iscsi_auth_group)
655
656    def get_iscsi_auth_groups(args):
657        print_dict(rpc.iscsi.get_iscsi_auth_groups(args.client))
658
659    p = subparsers.add_parser('get_iscsi_auth_groups',
660                              help='Display current authentication group configuration')
661    p.set_defaults(func=get_iscsi_auth_groups)
662
663    def get_portal_groups(args):
664        print_dict(rpc.iscsi.get_portal_groups(args.client))
665
666    p = subparsers.add_parser(
667        'get_portal_groups', help='Display current portal group configuration')
668    p.set_defaults(func=get_portal_groups)
669
670    def get_initiator_groups(args):
671        print_dict(rpc.iscsi.get_initiator_groups(args.client))
672
673    p = subparsers.add_parser('get_initiator_groups',
674                              help='Display current initiator group configuration')
675    p.set_defaults(func=get_initiator_groups)
676
677    def get_target_nodes(args):
678        print_dict(rpc.iscsi.get_target_nodes(args.client))
679
680    p = subparsers.add_parser('get_target_nodes', help='Display target nodes')
681    p.set_defaults(func=get_target_nodes)
682
683    def construct_target_node(args):
684        luns = []
685        for u in args.bdev_name_id_pairs.strip().split(" "):
686            bdev_name, lun_id = u.split(":")
687            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
688
689        pg_ig_maps = []
690        for u in args.pg_ig_mappings.strip().split(" "):
691            pg, ig = u.split(":")
692            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
693
694        rpc.iscsi.construct_target_node(
695            args.client,
696            luns=luns,
697            pg_ig_maps=pg_ig_maps,
698            name=args.name,
699            alias_name=args.alias_name,
700            queue_depth=args.queue_depth,
701            chap_group=args.chap_group,
702            disable_chap=args.disable_chap,
703            require_chap=args.require_chap,
704            mutual_chap=args.mutual_chap,
705            header_digest=args.header_digest,
706            data_digest=args.data_digest)
707
708    p = subparsers.add_parser('construct_target_node',
709                              help='Add a target node')
710    p.add_argument('name', help='Target node name (ASCII)')
711    p.add_argument('alias_name', help='Target node alias name (ASCII)')
712    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
713    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
714    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
715    *** The bdevs must pre-exist ***
716    *** LUN0 (id = 0) is required ***
717    *** bdevs names cannot contain space or colon characters ***""")
718    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
719    Whitespace separated, quoted, mapping defined with colon
720    separated list of "tags" (int > 0)
721    Example: '1:1 2:2 2:1'
722    *** The Portal/Initiator Groups must be precreated ***""")
723    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
724    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
725    *** Authentication group must be precreated ***""", type=int, default=0)
726    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
727    *** Mutually exclusive with --require-chap ***""", action='store_true')
728    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
729    *** Mutually exclusive with --disable-chap ***""", action='store_true')
730    p.add_argument(
731        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
732    p.add_argument('-H', '--header-digest',
733                   help='Header Digest should be required for this target node.', action='store_true')
734    p.add_argument('-D', '--data-digest',
735                   help='Data Digest should be required for this target node.', action='store_true')
736    p.set_defaults(func=construct_target_node)
737
738    def target_node_add_lun(args):
739        rpc.iscsi.target_node_add_lun(
740            args.client,
741            name=args.name,
742            bdev_name=args.bdev_name,
743            lun_id=args.lun_id)
744
745    p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node')
746    p.add_argument('name', help='Target node name (ASCII)')
747    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
748    *** bdev name cannot contain space or colon characters ***""")
749    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
750    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
751    p.set_defaults(func=target_node_add_lun)
752
753    def set_iscsi_target_node_auth(args):
754        rpc.iscsi.set_iscsi_target_node_auth(
755            args.client,
756            name=args.name,
757            chap_group=args.chap_group,
758            disable_chap=args.disable_chap,
759            require_chap=args.require_chap,
760            mutual_chap=args.mutual_chap)
761
762    p = subparsers.add_parser('set_iscsi_target_node_auth', help='Set CHAP authentication for the target node')
763    p.add_argument('name', help='Target node name (ASCII)')
764    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
765    *** Authentication group must be precreated ***""", type=int, default=0)
766    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
767    *** Mutually exclusive with --require-chap ***""", action='store_true')
768    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
769    *** Mutually exclusive with --disable-chap ***""", action='store_true')
770    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
771                   action='store_true')
772    p.set_defaults(func=set_iscsi_target_node_auth)
773
774    def add_pg_ig_maps(args):
775        pg_ig_maps = []
776        for u in args.pg_ig_mappings.strip().split(" "):
777            pg, ig = u.split(":")
778            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
779        rpc.iscsi.add_pg_ig_maps(
780            args.client,
781            pg_ig_maps=pg_ig_maps,
782            name=args.name)
783
784    p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node')
785    p.add_argument('name', help='Target node name (ASCII)')
786    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
787    Whitespace separated, quoted, mapping defined with colon
788    separated list of "tags" (int > 0)
789    Example: '1:1 2:2 2:1'
790    *** The Portal/Initiator Groups must be precreated ***""")
791    p.set_defaults(func=add_pg_ig_maps)
792
793    def delete_pg_ig_maps(args):
794        pg_ig_maps = []
795        for u in args.pg_ig_mappings.strip().split(" "):
796            pg, ig = u.split(":")
797            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
798        rpc.iscsi.delete_pg_ig_maps(
799            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
800
801    p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node')
802    p.add_argument('name', help='Target node name (ASCII)')
803    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
804    Whitespace separated, quoted, mapping defined with colon
805    separated list of "tags" (int > 0)
806    Example: '1:1 2:2 2:1'
807    *** The Portal/Initiator Groups must be precreated ***""")
808    p.set_defaults(func=delete_pg_ig_maps)
809
810    def add_portal_group(args):
811        portals = []
812        for p in args.portal_list:
813            ip, separator, port_cpumask = p.rpartition(':')
814            split_port_cpumask = port_cpumask.split('@')
815            if len(split_port_cpumask) == 1:
816                port = port_cpumask
817                portals.append({'host': ip, 'port': port})
818            else:
819                port = split_port_cpumask[0]
820                cpumask = split_port_cpumask[1]
821                portals.append({'host': ip, 'port': port, 'cpumask': cpumask})
822        rpc.iscsi.add_portal_group(
823            args.client,
824            portals=portals,
825            tag=args.tag)
826
827    p = subparsers.add_parser('add_portal_group', help='Add a portal group')
828    p.add_argument(
829        'tag', help='Portal group tag (unique, integer > 0)', type=int)
830    p.add_argument('portal_list', nargs=argparse.REMAINDER, help="""List of portals in 'host:port@cpumask' format, separated by whitespace
831    (cpumask is optional and can be skipped)
832    Example: '192.168.100.100:3260' '192.168.100.100:3261' '192.168.100.100:3262@0x1""")
833    p.set_defaults(func=add_portal_group)
834
835    def add_initiator_group(args):
836        initiators = []
837        netmasks = []
838        for i in args.initiator_list.strip().split(' '):
839            initiators.append(i)
840        for n in args.netmask_list.strip().split(' '):
841            netmasks.append(n)
842        rpc.iscsi.add_initiator_group(
843            args.client,
844            tag=args.tag,
845            initiators=initiators,
846            netmasks=netmasks)
847
848    p = subparsers.add_parser('add_initiator_group',
849                              help='Add an initiator group')
850    p.add_argument(
851        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
852    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
853    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
854    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
855    Example: '255.255.0.0 255.248.0.0' etc""")
856    p.set_defaults(func=add_initiator_group)
857
858    def add_initiators_to_initiator_group(args):
859        initiators = None
860        netmasks = None
861        if args.initiator_list:
862            initiators = []
863            for i in args.initiator_list.strip().split(' '):
864                initiators.append(i)
865        if args.netmask_list:
866            netmasks = []
867            for n in args.netmask_list.strip().split(' '):
868                netmasks.append(n)
869        rpc.iscsi.add_initiators_to_initiator_group(
870            args.client,
871            tag=args.tag,
872            initiators=initiators,
873            netmasks=netmasks)
874
875    p = subparsers.add_parser('add_initiators_to_initiator_group',
876                              help='Add initiators to an existing initiator group')
877    p.add_argument(
878        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
879    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
880    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
881    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
882    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
883    p.set_defaults(func=add_initiators_to_initiator_group)
884
885    def delete_initiators_from_initiator_group(args):
886        initiators = None
887        netmasks = None
888        if args.initiator_list:
889            initiators = []
890            for i in args.initiator_list.strip().split(' '):
891                initiators.append(i)
892        if args.netmask_list:
893            netmasks = []
894            for n in args.netmask_list.strip().split(' '):
895                netmasks.append(n)
896        rpc.iscsi.delete_initiators_from_initiator_group(
897            args.client,
898            tag=args.tag,
899            initiators=initiators,
900            netmasks=netmasks)
901
902    p = subparsers.add_parser('delete_initiators_from_initiator_group',
903                              help='Delete initiators from an existing initiator group')
904    p.add_argument(
905        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
906    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
907    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
908    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
909    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
910    p.set_defaults(func=delete_initiators_from_initiator_group)
911
912    def delete_target_node(args):
913        rpc.iscsi.delete_target_node(
914            args.client, target_node_name=args.target_node_name)
915
916    p = subparsers.add_parser('delete_target_node',
917                              help='Delete a target node')
918    p.add_argument('target_node_name',
919                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
920    p.set_defaults(func=delete_target_node)
921
922    def delete_portal_group(args):
923        rpc.iscsi.delete_portal_group(args.client, tag=args.tag)
924
925    p = subparsers.add_parser('delete_portal_group',
926                              help='Delete a portal group')
927    p.add_argument(
928        'tag', help='Portal group tag (unique, integer > 0)', type=int)
929    p.set_defaults(func=delete_portal_group)
930
931    def delete_initiator_group(args):
932        rpc.iscsi.delete_initiator_group(args.client, tag=args.tag)
933
934    p = subparsers.add_parser('delete_initiator_group',
935                              help='Delete an initiator group')
936    p.add_argument(
937        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
938    p.set_defaults(func=delete_initiator_group)
939
940    def get_iscsi_connections(args):
941        print_dict(rpc.iscsi.get_iscsi_connections(args.client))
942
943    p = subparsers.add_parser('get_iscsi_connections',
944                              help='Display iSCSI connections')
945    p.set_defaults(func=get_iscsi_connections)
946
947    def get_iscsi_global_params(args):
948        print_dict(rpc.iscsi.get_iscsi_global_params(args.client))
949
950    p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters')
951    p.set_defaults(func=get_iscsi_global_params)
952
953    def get_scsi_devices(args):
954        print_dict(rpc.iscsi.get_scsi_devices(args.client))
955
956    p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices')
957    p.set_defaults(func=get_scsi_devices)
958
959    # trace
960    def enable_tpoint_group(args):
961        rpc.trace.enable_tpoint_group(args.client, name=args.name)
962
963    p = subparsers.add_parser('enable_tpoint_group', help='enable trace on a specific tpoint group')
964    p.add_argument(
965        'name', help="""trace group name we want to enable in tpoint_group_mask.
966        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
967    p.set_defaults(func=enable_tpoint_group)
968
969    def disable_tpoint_group(args):
970        rpc.trace.disable_tpoint_group(args.client, name=args.name)
971
972    p = subparsers.add_parser('disable_tpoint_group', help='disable trace on a specific tpoint group')
973    p.add_argument(
974        'name', help="""trace group name we want to disable in tpoint_group_mask.
975        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
976    p.set_defaults(func=disable_tpoint_group)
977
978    def get_tpoint_group_mask(args):
979        print_dict(rpc.trace.get_tpoint_group_mask(args.client))
980
981    p = subparsers.add_parser('get_tpoint_group_mask', help='get trace point group mask')
982    p.set_defaults(func=get_tpoint_group_mask)
983
984    # log
985    def set_log_flag(args):
986        rpc.log.set_log_flag(args.client, flag=args.flag)
987
988    p = subparsers.add_parser('set_log_flag', help='set log flag')
989    p.add_argument(
990        'flag', help='log flag we want to set. (for example "nvme").')
991    p.set_defaults(func=set_log_flag)
992
993    def set_trace_flag(args):
994        print("set_trace_flag is deprecated - use set_log_flag instead")
995        rpc.log.set_trace_flag(args.client, flag=args.flag)
996
997    p = subparsers.add_parser('set_trace_flag', help='set trace flag')
998    p.add_argument(
999        'flag', help='trace mask we want to set. (for example "nvme").')
1000    p.set_defaults(func=set_trace_flag)
1001
1002    def clear_log_flag(args):
1003        rpc.log.clear_log_flag(args.client, flag=args.flag)
1004
1005    p = subparsers.add_parser('clear_log_flag', help='clear log flag')
1006    p.add_argument(
1007        'flag', help='log flag we want to clear. (for example "nvme").')
1008    p.set_defaults(func=clear_log_flag)
1009
1010    def clear_trace_flag(args):
1011        print("clear_trace_flag is deprecated - use clear_log_flag instead")
1012        rpc.log.clear_trace_flag(args.client, flag=args.flag)
1013
1014    p = subparsers.add_parser('clear_trace_flag', help='clear trace flag')
1015    p.add_argument(
1016        'flag', help='trace mask we want to clear. (for example "nvme").')
1017    p.set_defaults(func=clear_trace_flag)
1018
1019    def get_log_flags(args):
1020        print_dict(rpc.log.get_log_flags(args.client))
1021
1022    p = subparsers.add_parser('get_log_flags', help='get log flags')
1023    p.set_defaults(func=get_log_flags)
1024
1025    def get_trace_flags(args):
1026        print("get_trace_flags is deprecated - use get_log_flags instead")
1027        print_dict(rpc.log.get_trace_flags(args.client))
1028
1029    p = subparsers.add_parser('get_trace_flags', help='get trace flags')
1030    p.set_defaults(func=get_trace_flags)
1031
1032    def set_log_level(args):
1033        rpc.log.set_log_level(args.client, level=args.level)
1034
1035    p = subparsers.add_parser('set_log_level', help='set log level')
1036    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
1037    p.set_defaults(func=set_log_level)
1038
1039    def get_log_level(args):
1040        print_dict(rpc.log.get_log_level(args.client))
1041
1042    p = subparsers.add_parser('get_log_level', help='get log level')
1043    p.set_defaults(func=get_log_level)
1044
1045    def set_log_print_level(args):
1046        rpc.log.set_log_print_level(args.client, level=args.level)
1047
1048    p = subparsers.add_parser('set_log_print_level', help='set log print level')
1049    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
1050    p.set_defaults(func=set_log_print_level)
1051
1052    def get_log_print_level(args):
1053        print_dict(rpc.log.get_log_print_level(args.client))
1054
1055    p = subparsers.add_parser('get_log_print_level', help='get log print level')
1056    p.set_defaults(func=get_log_print_level)
1057
1058    # lvol
1059    def construct_lvol_store(args):
1060        print(rpc.lvol.construct_lvol_store(args.client,
1061                                            bdev_name=args.bdev_name,
1062                                            lvs_name=args.lvs_name,
1063                                            cluster_sz=args.cluster_sz,
1064                                            clear_method=args.clear_method))
1065
1066    p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev')
1067    p.add_argument('bdev_name', help='base bdev name')
1068    p.add_argument('lvs_name', help='name for lvol store')
1069    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
1070    p.add_argument('--clear-method', help="""Change clear method for data region.
1071        Available: none, unmap, write_zeroes""", required=False)
1072    p.set_defaults(func=construct_lvol_store)
1073
1074    def rename_lvol_store(args):
1075        rpc.lvol.rename_lvol_store(args.client,
1076                                   old_name=args.old_name,
1077                                   new_name=args.new_name)
1078
1079    p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
1080    p.add_argument('old_name', help='old name')
1081    p.add_argument('new_name', help='new name')
1082    p.set_defaults(func=rename_lvol_store)
1083
1084    def construct_lvol_bdev(args):
1085        print(rpc.lvol.construct_lvol_bdev(args.client,
1086                                           lvol_name=args.lvol_name,
1087                                           size=args.size * 1024 * 1024,
1088                                           thin_provision=args.thin_provision,
1089                                           clear_method=args.clear_method,
1090                                           uuid=args.uuid,
1091                                           lvs_name=args.lvs_name))
1092
1093    p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
1094    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1095    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1096    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
1097    p.add_argument('-c', '--clear-method', help="""Change default data clusters clear method.
1098        Available: none, unmap, write_zeroes""", required=False)
1099    p.add_argument('lvol_name', help='name for this lvol')
1100    p.add_argument('size', help='size in MiB for this bdev', type=int)
1101    p.set_defaults(func=construct_lvol_bdev)
1102
1103    def snapshot_lvol_bdev(args):
1104        print(rpc.lvol.snapshot_lvol_bdev(args.client,
1105                                          lvol_name=args.lvol_name,
1106                                          snapshot_name=args.snapshot_name))
1107
1108    p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
1109    p.add_argument('lvol_name', help='lvol bdev name')
1110    p.add_argument('snapshot_name', help='lvol snapshot name')
1111    p.set_defaults(func=snapshot_lvol_bdev)
1112
1113    def clone_lvol_bdev(args):
1114        print(rpc.lvol.clone_lvol_bdev(args.client,
1115                                       snapshot_name=args.snapshot_name,
1116                                       clone_name=args.clone_name))
1117
1118    p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
1119    p.add_argument('snapshot_name', help='lvol snapshot name')
1120    p.add_argument('clone_name', help='lvol clone name')
1121    p.set_defaults(func=clone_lvol_bdev)
1122
1123    def rename_lvol_bdev(args):
1124        rpc.lvol.rename_lvol_bdev(args.client,
1125                                  old_name=args.old_name,
1126                                  new_name=args.new_name)
1127
1128    p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name')
1129    p.add_argument('old_name', help='lvol bdev name')
1130    p.add_argument('new_name', help='new lvol name')
1131    p.set_defaults(func=rename_lvol_bdev)
1132
1133    def inflate_lvol_bdev(args):
1134        rpc.lvol.inflate_lvol_bdev(args.client,
1135                                   name=args.name)
1136
1137    p = subparsers.add_parser('inflate_lvol_bdev', help='Make thin provisioned lvol a thick provisioned lvol')
1138    p.add_argument('name', help='lvol bdev name')
1139    p.set_defaults(func=inflate_lvol_bdev)
1140
1141    def decouple_parent_lvol_bdev(args):
1142        rpc.lvol.decouple_parent_lvol_bdev(args.client,
1143                                           name=args.name)
1144
1145    p = subparsers.add_parser('decouple_parent_lvol_bdev', help='Decouple parent of lvol')
1146    p.add_argument('name', help='lvol bdev name')
1147    p.set_defaults(func=decouple_parent_lvol_bdev)
1148
1149    def resize_lvol_bdev(args):
1150        rpc.lvol.resize_lvol_bdev(args.client,
1151                                  name=args.name,
1152                                  size=args.size * 1024 * 1024)
1153
1154    p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev')
1155    p.add_argument('name', help='lvol bdev name')
1156    p.add_argument('size', help='new size in MiB for this bdev', type=int)
1157    p.set_defaults(func=resize_lvol_bdev)
1158
1159    def set_read_only_lvol_bdev(args):
1160        rpc.lvol.set_read_only_lvol_bdev(args.client,
1161                                         name=args.name)
1162
1163    p = subparsers.add_parser('set_read_only_lvol_bdev', help='Mark lvol bdev as read only')
1164    p.add_argument('name', help='lvol bdev name')
1165    p.set_defaults(func=set_read_only_lvol_bdev)
1166
1167    def destroy_lvol_bdev(args):
1168        rpc.lvol.destroy_lvol_bdev(args.client,
1169                                   name=args.name)
1170
1171    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
1172    p.add_argument('name', help='lvol bdev name')
1173    p.set_defaults(func=destroy_lvol_bdev)
1174
1175    def destroy_lvol_store(args):
1176        rpc.lvol.destroy_lvol_store(args.client,
1177                                    uuid=args.uuid,
1178                                    lvs_name=args.lvs_name)
1179
1180    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
1181    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1182    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1183    p.set_defaults(func=destroy_lvol_store)
1184
1185    def get_lvol_stores(args):
1186        print_dict(rpc.lvol.get_lvol_stores(args.client,
1187                                            uuid=args.uuid,
1188                                            lvs_name=args.lvs_name))
1189
1190    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
1191    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1192    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1193    p.set_defaults(func=get_lvol_stores)
1194
1195    def get_raid_bdevs(args):
1196        print_array(rpc.bdev.get_raid_bdevs(args.client,
1197                                            category=args.category))
1198
1199    p = subparsers.add_parser('get_raid_bdevs', help="""This is used to list all the raid bdev names based on the input category
1200    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
1201    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
1202    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
1203    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
1204    p.add_argument('category', help='all or online or configuring or offline')
1205    p.set_defaults(func=get_raid_bdevs)
1206
1207    def construct_raid_bdev(args):
1208        base_bdevs = []
1209        for u in args.base_bdevs.strip().split(" "):
1210            base_bdevs.append(u)
1211
1212        rpc.bdev.construct_raid_bdev(args.client,
1213                                     name=args.name,
1214                                     strip_size=args.strip_size,
1215                                     strip_size_kb=args.strip_size_kb,
1216                                     raid_level=args.raid_level,
1217                                     base_bdevs=base_bdevs)
1218    p = subparsers.add_parser('construct_raid_bdev', help='Construct new raid bdev')
1219    p.add_argument('-n', '--name', help='raid bdev name', required=True)
1220    p.add_argument('-s', '--strip-size', help='strip size in KB (deprecated)', type=int)
1221    p.add_argument('-z', '--strip-size_kb', help='strip size in KB', type=int)
1222    p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', type=int, required=True)
1223    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
1224    p.set_defaults(func=construct_raid_bdev)
1225
1226    def destroy_raid_bdev(args):
1227        rpc.bdev.destroy_raid_bdev(args.client,
1228                                   name=args.name)
1229    p = subparsers.add_parser('destroy_raid_bdev', help='Destroy existing raid bdev')
1230    p.add_argument('name', help='raid bdev name')
1231    p.set_defaults(func=destroy_raid_bdev)
1232
1233    # split
1234    def construct_split_vbdev(args):
1235        print_array(rpc.bdev.construct_split_vbdev(args.client,
1236                                                   base_bdev=args.base_bdev,
1237                                                   split_count=args.split_count,
1238                                                   split_size_mb=args.split_size_mb))
1239
1240    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
1241    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
1242    available (during examination process).""")
1243    p.add_argument('base_bdev', help='base bdev name')
1244    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
1245    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
1246    exceed the base bdev size.""", type=int)
1247    p.set_defaults(func=construct_split_vbdev)
1248
1249    def destruct_split_vbdev(args):
1250        rpc.bdev.destruct_split_vbdev(args.client,
1251                                      base_bdev=args.base_bdev)
1252
1253    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
1254    p.add_argument('base_bdev', help='base bdev name')
1255    p.set_defaults(func=destruct_split_vbdev)
1256
1257    # ftl
1258    def construct_ftl_bdev(args):
1259        print_dict(rpc.bdev.construct_ftl_bdev(args.client,
1260                                               name=args.name,
1261                                               trtype=args.trtype,
1262                                               traddr=args.traddr,
1263                                               punits=args.punits,
1264                                               uuid=args.uuid))
1265
1266    p = subparsers.add_parser('construct_ftl_bdev',
1267                              help='Add FTL bdev')
1268    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
1269    p.add_argument('-t', '--trtype',
1270                   help='NVMe target trtype: e.g., pcie', default='pcie')
1271    p.add_argument('-a', '--traddr',
1272                   help='NVMe target address: e.g., an ip address or BDF', required=True)
1273    p.add_argument('-l', '--punits', help='Parallel unit range in the form of start-end: e.g. 4-8',
1274                   required=True)
1275    p.add_argument('-u', '--uuid', help='UUID of restored bdev (not applicable when creating new '
1276                   'instance): e.g. b286d19a-0059-4709-abcd-9f7732b1567d (optional)')
1277    p.set_defaults(func=construct_ftl_bdev)
1278
1279    def delete_ftl_bdev(args):
1280        print_dict(rpc.bdev.delete_ftl_bdev(args.client, name=args.name))
1281
1282    p = subparsers.add_parser('delete_ftl_bdev', help='Delete FTL bdev')
1283    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
1284    p.set_defaults(func=delete_ftl_bdev)
1285
1286    # nbd
1287    def start_nbd_disk(args):
1288        print(rpc.nbd.start_nbd_disk(args.client,
1289                                     bdev_name=args.bdev_name,
1290                                     nbd_device=args.nbd_device))
1291
1292    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
1293    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
1294    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.')
1295    p.set_defaults(func=start_nbd_disk)
1296
1297    def stop_nbd_disk(args):
1298        rpc.nbd.stop_nbd_disk(args.client,
1299                              nbd_device=args.nbd_device)
1300
1301    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
1302    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
1303    p.set_defaults(func=stop_nbd_disk)
1304
1305    def get_nbd_disks(args):
1306        print_dict(rpc.nbd.get_nbd_disks(args.client,
1307                                         nbd_device=args.nbd_device))
1308
1309    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
1310    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
1311    p.set_defaults(func=get_nbd_disks)
1312
1313    # net
1314    def add_ip_address(args):
1315        rpc.net.add_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1316
1317    p = subparsers.add_parser('add_ip_address', help='Add IP address')
1318    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1319    p.add_argument('ip_addr', help='ip address will be added.')
1320    p.set_defaults(func=add_ip_address)
1321
1322    def delete_ip_address(args):
1323        rpc.net.delete_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1324
1325    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
1326    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1327    p.add_argument('ip_addr', help='ip address will be deleted.')
1328    p.set_defaults(func=delete_ip_address)
1329
1330    def get_interfaces(args):
1331        print_dict(rpc.net.get_interfaces(args.client))
1332
1333    p = subparsers.add_parser(
1334        'get_interfaces', help='Display current interface list')
1335    p.set_defaults(func=get_interfaces)
1336
1337    # NVMe-oF
1338    def set_nvmf_target_max_subsystems(args):
1339        rpc.nvmf.set_nvmf_target_max_subsystems(args.client,
1340                                                max_subsystems=args.max_subsystems)
1341
1342    p = subparsers.add_parser('set_nvmf_target_max_subsystems', help='Set the maximum number of NVMf target subsystems')
1343    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True)
1344    p.set_defaults(func=set_nvmf_target_max_subsystems)
1345
1346    def set_nvmf_target_config(args):
1347        rpc.nvmf.set_nvmf_target_config(args.client,
1348                                        acceptor_poll_rate=args.acceptor_poll_rate,
1349                                        conn_sched=args.conn_sched)
1350
1351    p = subparsers.add_parser('set_nvmf_target_config', help='Set NVMf target config')
1352    p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
1353    p.add_argument('-s', '--conn-sched', help="""'roundrobin' - Schedule the incoming connections from any host
1354    on the cores in a round robin manner (Default). 'hostip' - Schedule all the incoming connections from a
1355    specific host IP on to the same core. Connections from different IP will be assigned to cores in a round
1356    robin manner""")
1357    p.set_defaults(func=set_nvmf_target_config)
1358
1359    def nvmf_create_transport(args):
1360        rpc.nvmf.nvmf_create_transport(args.client,
1361                                       trtype=args.trtype,
1362                                       max_queue_depth=args.max_queue_depth,
1363                                       max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1364                                       in_capsule_data_size=args.in_capsule_data_size,
1365                                       max_io_size=args.max_io_size,
1366                                       io_unit_size=args.io_unit_size,
1367                                       max_aq_depth=args.max_aq_depth,
1368                                       num_shared_buffers=args.num_shared_buffers,
1369                                       buf_cache_size=args.buf_cache_size)
1370
1371    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
1372    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
1373    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1374    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1375    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1376    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1377    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1378    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
1379    p.add_argument('-n', '--num-shared-buffers', help='The number of pooled data buffers available to the transport', type=int)
1380    p.add_argument('-b', '--buf-cache-size', help='The number of shared buffers to reserve for each poll group', type=int)
1381    p.set_defaults(func=nvmf_create_transport)
1382
1383    def get_nvmf_transports(args):
1384        print_dict(rpc.nvmf.get_nvmf_transports(args.client))
1385
1386    p = subparsers.add_parser('get_nvmf_transports',
1387                              help='Display nvmf transports')
1388    p.set_defaults(func=get_nvmf_transports)
1389
1390    def get_nvmf_subsystems(args):
1391        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client))
1392
1393    p = subparsers.add_parser('get_nvmf_subsystems',
1394                              help='Display nvmf subsystems')
1395    p.set_defaults(func=get_nvmf_subsystems)
1396
1397    def nvmf_subsystem_create(args):
1398        rpc.nvmf.nvmf_subsystem_create(args.client,
1399                                       nqn=args.nqn,
1400                                       serial_number=args.serial_number,
1401                                       allow_any_host=args.allow_any_host,
1402                                       max_namespaces=args.max_namespaces)
1403
1404    p = subparsers.add_parser('nvmf_subsystem_create', help='Create an NVMe-oF subsystem')
1405    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
1406    p.add_argument("-s", "--serial-number", help="""
1407    Format:  'sn' etc
1408    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1409    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1410    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
1411                   type=int, default=0)
1412    p.set_defaults(func=nvmf_subsystem_create)
1413
1414    def delete_nvmf_subsystem(args):
1415        rpc.nvmf.delete_nvmf_subsystem(args.client,
1416                                       nqn=args.subsystem_nqn)
1417
1418    p = subparsers.add_parser('delete_nvmf_subsystem',
1419                              help='Delete a nvmf subsystem')
1420    p.add_argument('subsystem_nqn',
1421                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
1422    p.set_defaults(func=delete_nvmf_subsystem)
1423
1424    def nvmf_subsystem_add_listener(args):
1425        rpc.nvmf.nvmf_subsystem_add_listener(args.client,
1426                                             nqn=args.nqn,
1427                                             trtype=args.trtype,
1428                                             traddr=args.traddr,
1429                                             adrfam=args.adrfam,
1430                                             trsvcid=args.trsvcid)
1431
1432    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
1433    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1434    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1435    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1436    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1437    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1438    p.set_defaults(func=nvmf_subsystem_add_listener)
1439
1440    def nvmf_subsystem_remove_listener(args):
1441        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
1442                                                nqn=args.nqn,
1443                                                trtype=args.trtype,
1444                                                traddr=args.traddr,
1445                                                adrfam=args.adrfam,
1446                                                trsvcid=args.trsvcid)
1447
1448    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
1449    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1450    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1451    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1452    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1453    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1454    p.set_defaults(func=nvmf_subsystem_remove_listener)
1455
1456    def nvmf_subsystem_add_ns(args):
1457        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
1458                                       nqn=args.nqn,
1459                                       bdev_name=args.bdev_name,
1460                                       nsid=args.nsid,
1461                                       nguid=args.nguid,
1462                                       eui64=args.eui64,
1463                                       uuid=args.uuid)
1464
1465    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
1466    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1467    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
1468    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
1469    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
1470    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
1471    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
1472    p.set_defaults(func=nvmf_subsystem_add_ns)
1473
1474    def nvmf_subsystem_remove_ns(args):
1475        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
1476                                          nqn=args.nqn,
1477                                          nsid=args.nsid)
1478
1479    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
1480    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1481    p.add_argument('nsid', help='The requested NSID', type=int)
1482    p.set_defaults(func=nvmf_subsystem_remove_ns)
1483
1484    def nvmf_subsystem_add_host(args):
1485        rpc.nvmf.nvmf_subsystem_add_host(args.client,
1486                                         nqn=args.nqn,
1487                                         host=args.host)
1488
1489    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
1490    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1491    p.add_argument('host', help='Host NQN to allow')
1492    p.set_defaults(func=nvmf_subsystem_add_host)
1493
1494    def nvmf_subsystem_remove_host(args):
1495        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
1496                                            nqn=args.nqn,
1497                                            host=args.host)
1498
1499    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
1500    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1501    p.add_argument('host', help='Host NQN to remove')
1502    p.set_defaults(func=nvmf_subsystem_remove_host)
1503
1504    def nvmf_subsystem_allow_any_host(args):
1505        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
1506                                               nqn=args.nqn,
1507                                               disable=args.disable)
1508
1509    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
1510    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1511    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
1512    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
1513    p.set_defaults(func=nvmf_subsystem_allow_any_host)
1514
1515    # pmem
1516    def create_pmem_pool(args):
1517        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
1518        rpc.pmem.create_pmem_pool(args.client,
1519                                  pmem_file=args.pmem_file,
1520                                  num_blocks=num_blocks,
1521                                  block_size=args.block_size)
1522
1523    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
1524    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1525    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
1526    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
1527    p.set_defaults(func=create_pmem_pool)
1528
1529    def pmem_pool_info(args):
1530        print_dict(rpc.pmem.pmem_pool_info(args.client,
1531                                           pmem_file=args.pmem_file))
1532
1533    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
1534    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1535    p.set_defaults(func=pmem_pool_info)
1536
1537    def delete_pmem_pool(args):
1538        rpc.pmem.delete_pmem_pool(args.client,
1539                                  pmem_file=args.pmem_file)
1540
1541    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
1542    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1543    p.set_defaults(func=delete_pmem_pool)
1544
1545    # subsystem
1546    def get_subsystems(args):
1547        print_dict(rpc.subsystem.get_subsystems(args.client))
1548
1549    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
1550    entry contain (unsorted) array of subsystems it depends on.""")
1551    p.set_defaults(func=get_subsystems)
1552
1553    def get_subsystem_config(args):
1554        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
1555
1556    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
1557    p.add_argument('name', help='Name of subsystem to query')
1558    p.set_defaults(func=get_subsystem_config)
1559
1560    # vhost
1561    def set_vhost_controller_coalescing(args):
1562        rpc.vhost.set_vhost_controller_coalescing(args.client,
1563                                                  ctrlr=args.ctrlr,
1564                                                  delay_base_us=args.delay_base_us,
1565                                                  iops_threshold=args.iops_threshold)
1566
1567    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
1568    p.add_argument('ctrlr', help='controller name')
1569    p.add_argument('delay_base_us', help='Base delay time', type=int)
1570    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
1571    p.set_defaults(func=set_vhost_controller_coalescing)
1572
1573    def construct_vhost_scsi_controller(args):
1574        rpc.vhost.construct_vhost_scsi_controller(args.client,
1575                                                  ctrlr=args.ctrlr,
1576                                                  cpumask=args.cpumask)
1577
1578    p = subparsers.add_parser(
1579        'construct_vhost_scsi_controller', help='Add new vhost controller')
1580    p.add_argument('ctrlr', help='controller name')
1581    p.add_argument('--cpumask', help='cpu mask for this controller')
1582    p.set_defaults(func=construct_vhost_scsi_controller)
1583
1584    def add_vhost_scsi_lun(args):
1585        print(rpc.vhost.add_vhost_scsi_lun(args.client,
1586                                           ctrlr=args.ctrlr,
1587                                           scsi_target_num=args.scsi_target_num,
1588                                           bdev_name=args.bdev_name))
1589
1590    p = subparsers.add_parser('add_vhost_scsi_lun',
1591                              help='Add lun to vhost controller')
1592    p.add_argument('ctrlr', help='conntroller name where add lun')
1593    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1594    p.add_argument('bdev_name', help='bdev name')
1595    p.set_defaults(func=add_vhost_scsi_lun)
1596
1597    def remove_vhost_scsi_target(args):
1598        rpc.vhost.remove_vhost_scsi_target(args.client,
1599                                           ctrlr=args.ctrlr,
1600                                           scsi_target_num=args.scsi_target_num)
1601
1602    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
1603    p.add_argument('ctrlr', help='controller name to remove target from')
1604    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1605    p.set_defaults(func=remove_vhost_scsi_target)
1606
1607    def construct_vhost_blk_controller(args):
1608        rpc.vhost.construct_vhost_blk_controller(args.client,
1609                                                 ctrlr=args.ctrlr,
1610                                                 dev_name=args.dev_name,
1611                                                 cpumask=args.cpumask,
1612                                                 readonly=args.readonly)
1613
1614    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
1615    p.add_argument('ctrlr', help='controller name')
1616    p.add_argument('dev_name', help='device name')
1617    p.add_argument('--cpumask', help='cpu mask for this controller')
1618    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1619    p.set_defaults(func=construct_vhost_blk_controller)
1620
1621    def construct_vhost_nvme_controller(args):
1622        rpc.vhost.construct_vhost_nvme_controller(args.client,
1623                                                  ctrlr=args.ctrlr,
1624                                                  io_queues=args.io_queues,
1625                                                  cpumask=args.cpumask)
1626
1627    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
1628    p.add_argument('ctrlr', help='controller name')
1629    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
1630    p.add_argument('--cpumask', help='cpu mask for this controller')
1631    p.set_defaults(func=construct_vhost_nvme_controller)
1632
1633    def add_vhost_nvme_ns(args):
1634        rpc.vhost.add_vhost_nvme_ns(args.client,
1635                                    ctrlr=args.ctrlr,
1636                                    bdev_name=args.bdev_name)
1637
1638    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
1639    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
1640    p.add_argument('bdev_name', help='block device name for a new Namespace')
1641    p.set_defaults(func=add_vhost_nvme_ns)
1642
1643    def get_vhost_controllers(args):
1644        print_dict(rpc.vhost.get_vhost_controllers(args.client, args.name))
1645
1646    p = subparsers.add_parser('get_vhost_controllers', help='List all or specific vhost controller(s)')
1647    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
1648    p.set_defaults(func=get_vhost_controllers)
1649
1650    def remove_vhost_controller(args):
1651        rpc.vhost.remove_vhost_controller(args.client,
1652                                          ctrlr=args.ctrlr)
1653
1654    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
1655    p.add_argument('ctrlr', help='controller name')
1656    p.set_defaults(func=remove_vhost_controller)
1657
1658    def construct_virtio_dev(args):
1659        print_array(rpc.vhost.construct_virtio_dev(args.client,
1660                                                   name=args.name,
1661                                                   trtype=args.trtype,
1662                                                   traddr=args.traddr,
1663                                                   dev_type=args.dev_type,
1664                                                   vq_count=args.vq_count,
1665                                                   vq_size=args.vq_size))
1666
1667    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
1668    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
1669    remote side. Result is array of added bdevs.""")
1670    p.add_argument('name', help="Use this name as base for new created bdevs")
1671    p.add_argument('-t', '--trtype',
1672                   help='Virtio target transport type: pci or user', required=True)
1673    p.add_argument('-a', '--traddr',
1674                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
1675    p.add_argument('-d', '--dev-type',
1676                   help='Device type: blk or scsi', required=True)
1677    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1678    p.add_argument('--vq-size', help='Size of each queue', type=int)
1679    p.set_defaults(func=construct_virtio_dev)
1680
1681    def get_virtio_scsi_devs(args):
1682        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client))
1683
1684    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
1685    p.set_defaults(func=get_virtio_scsi_devs)
1686
1687    def remove_virtio_bdev(args):
1688        rpc.vhost.remove_virtio_bdev(args.client,
1689                                     name=args.name)
1690
1691    p = subparsers.add_parser('remove_virtio_bdev', help="""Remove a Virtio device
1692    This will delete all bdevs exposed by this device""")
1693    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1694    p.set_defaults(func=remove_virtio_bdev)
1695
1696    # ioat
1697    def scan_ioat_copy_engine(args):
1698        pci_whitelist = []
1699        if args.pci_whitelist:
1700            for w in args.pci_whitelist.strip().split(" "):
1701                pci_whitelist.append(w)
1702        rpc.ioat.scan_ioat_copy_engine(args.client, pci_whitelist)
1703
1704    p = subparsers.add_parser('scan_ioat_copy_engine', help='Set scan and enable IOAT copy engine offload.')
1705    p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in
1706    domain:bus:device.function format or domain.bus.device.function format""")
1707    p.set_defaults(func=scan_ioat_copy_engine)
1708
1709    # send_nvme_cmd
1710    def send_nvme_cmd(args):
1711        print_dict(rpc.nvme.send_nvme_cmd(args.client,
1712                                          name=args.nvme_name,
1713                                          cmd_type=args.cmd_type,
1714                                          data_direction=args.data_direction,
1715                                          cmdbuf=args.cmdbuf,
1716                                          data=args.data,
1717                                          metadata=args.metadata,
1718                                          data_len=args.data_length,
1719                                          metadata_len=args.metadata_length,
1720                                          timeout_ms=args.timeout_ms))
1721
1722    p = subparsers.add_parser('send_nvme_cmd', help='NVMe passthrough cmd.')
1723    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
1724    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
1725    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
1726    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
1727    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
1728    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
1729    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
1730    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
1731    p.add_argument('-T', '--timeout-ms',
1732                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int, default=0)
1733    p.set_defaults(func=send_nvme_cmd)
1734
1735    args = parser.parse_args()
1736
1737    try:
1738        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.verbose, args.timeout)
1739        args.func(args)
1740    except JSONRPCException as ex:
1741        print("Exception:")
1742        print(ex.message)
1743        exit(1)
1744