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