1# SPDX-License-Identifier: BSD-3-Clause 2# Copyright (C) 2018 Intel Corporation. 3# All rights reserved. 4 5from ..rpc.client import JSONRPCException 6from .ui_node import UINode 7 8 9class UINVMf(UINode): 10 def __init__(self, parent): 11 UINode.__init__(self, "nvmf", parent) 12 self.refresh() 13 14 def refresh(self): 15 self._children = set([]) 16 UINVMfSubsystems(self) 17 UINVMfTransports(self) 18 UINVMfReferrals(self) 19 20 21class UINVMfTransports(UINode): 22 def __init__(self, parent): 23 UINode.__init__(self, "transport", parent) 24 self.refresh() 25 26 def refresh(self): 27 self._children = set([]) 28 for transport in self.get_root().nvmf_get_transports(): 29 UINVMfTransport(transport, self) 30 31 def ui_command_create(self, trtype, max_queue_depth=None, max_io_qpairs_per_ctrlr=None, 32 in_capsule_data_size=None, max_io_size=None, io_unit_size=None, max_aq_depth=None): 33 """Create a transport with given parameters 34 35 Arguments: 36 trtype - Example: 'RDMA'. 37 max_queue_depth - Optional parameter. Integer, max value 65535. 38 max_io_qpairs_per_ctrlr - Optional parameter. 16 bit Integer, max value 65535. 39 in_capsule_data_size - Optional parameter. 32 bit Integer, max value 4294967295 40 max_io_size - Optional parameter. 32 bit integer, max value 4294967295 41 io_unit_size - Optional parameter. 32 bit integer, max value 4294967295 42 max_aq_depth - Optional parameter. 32 bit integer, max value 4294967295 43 """ 44 max_queue_depth = self.ui_eval_param(max_queue_depth, "number", None) 45 max_io_qpairs_per_ctrlr = self.ui_eval_param(max_io_qpairs_per_ctrlr, "number", None) 46 in_capsule_data_size = self.ui_eval_param(in_capsule_data_size, "number", None) 47 max_io_size = self.ui_eval_param(max_io_size, "number", None) 48 io_unit_size = self.ui_eval_param(io_unit_size, "number", None) 49 max_aq_depth = self.ui_eval_param(max_aq_depth, "number", None) 50 51 self.get_root().create_nvmf_transport(trtype=trtype, 52 max_queue_depth=max_queue_depth, 53 max_io_qpairs_per_ctrlr=max_io_qpairs_per_ctrlr, 54 in_capsule_data_size=in_capsule_data_size, 55 max_io_size=max_io_size, 56 io_unit_size=io_unit_size, 57 max_aq_depth=max_aq_depth) 58 59 def summary(self): 60 return "Transports: %s" % len(self.children), None 61 62 63class UINVMfTransport(UINode): 64 def __init__(self, transport, parent): 65 UINode.__init__(self, transport.trtype, parent) 66 self.transport = transport 67 68 69class UINVMfSubsystems(UINode): 70 def __init__(self, parent): 71 UINode.__init__(self, "subsystem", parent) 72 self.refresh() 73 74 def refresh(self): 75 self._children = set([]) 76 for subsystem in self.get_root().nvmf_get_subsystems(): 77 UINVMfSubsystem(subsystem, self) 78 79 def delete(self, subsystem_nqn): 80 self.get_root().nvmf_delete_subsystem(nqn=subsystem_nqn) 81 82 def ui_command_create(self, nqn, serial_number=None, 83 max_namespaces=None, allow_any_host="false"): 84 """Create subsystem with given parameters. 85 86 Arguments: 87 nqn - Target nqn(ASCII). 88 serial_number - Example: 'SPDK00000000000001'. 89 max_namespaces - Optional parameter. Maximum number of namespaces allowed to added during 90 active connection 91 allow_any_host - Optional parameter. Allow any host to connect (don't enforce allowed host NQN 92 list) 93 """ 94 allow_any_host = self.ui_eval_param(allow_any_host, "bool", False) 95 max_namespaces = self.ui_eval_param(max_namespaces, "number", 0) 96 self.get_root().create_nvmf_subsystem(nqn=nqn, serial_number=serial_number, 97 allow_any_host=allow_any_host, 98 max_namespaces=max_namespaces) 99 100 def ui_command_delete(self, subsystem_nqn): 101 """Delete subsystem with given nqn. 102 103 Arguments: 104 nqn_subsystem - Name of subsystem to delete 105 """ 106 self.delete(subsystem_nqn) 107 108 def ui_command_delete_all(self): 109 """Delete all subsystems""" 110 rpc_messages = "" 111 for child in self._children: 112 try: 113 self.delete(child.subsystem.nqn) 114 except JSONRPCException as e: 115 rpc_messages += e.message 116 if rpc_messages: 117 raise JSONRPCException(rpc_messages) 118 119 def summary(self): 120 return "Subsystems: %s" % len(self.children), None 121 122 123class UINVMfSubsystem(UINode): 124 def __init__(self, subsystem, parent): 125 UINode.__init__(self, subsystem.nqn, parent) 126 self.subsystem = subsystem 127 self.refresh() 128 129 def refresh(self): 130 self._children = set([]) 131 UINVMfSubsystemListeners(self.subsystem.listen_addresses, self) 132 UINVMfSubsystemHosts(self.subsystem.hosts, self) 133 if hasattr(self.subsystem, 'namespaces'): 134 UINVMfSubsystemNamespaces(self.subsystem.namespaces, self) 135 136 def refresh_node(self): 137 for subsystem in self.get_root().nvmf_get_subsystems(): 138 if subsystem.nqn == self.subsystem.nqn: 139 self.subsystem = subsystem 140 self.refresh() 141 142 def ui_command_show_details(self): 143 self.shell.log.info(json.dumps(vars(self.lvs), indent=2)) 144 145 def ui_command_allow_any_host(self, disable="false"): 146 """Disable or or enable allow_any_host flag. 147 148 Arguments: 149 disable - Optional parameter. If false then enable, if true disable 150 """ 151 disable = self.ui_eval_param(disable, "bool", None) 152 self.get_root().nvmf_subsystem_allow_any_host( 153 nqn=self.subsystem.nqn, disable=disable) 154 155 def summary(self): 156 sn = None 157 if hasattr(self.subsystem, 'serial_number'): 158 sn = "sn=%s" % self.subsystem.serial_number 159 st = None 160 if hasattr(self.subsystem, 'subtype'): 161 st = "st=%s" % self.subsystem.subtype 162 allow_any_host = None 163 if self.subsystem.allow_any_host: 164 allow_any_host = "Allow any host" 165 info = ", ".join(filter(None, [sn, st, allow_any_host])) 166 return info, None 167 168 169class UINVMfSubsystemListeners(UINode): 170 def __init__(self, listen_addresses, parent): 171 UINode.__init__(self, "listen_addresses", parent) 172 self.listen_addresses = listen_addresses 173 self.refresh() 174 175 def refresh(self): 176 self._children = set([]) 177 for address in self.listen_addresses: 178 UINVMfSubsystemListener(address, self) 179 180 def refresh_node(self): 181 for subsystem in self.get_root().nvmf_get_subsystems(): 182 if subsystem.nqn == self.parent.subsystem.nqn: 183 self.listen_addresses = subsystem.listen_addresses 184 self.refresh() 185 186 def delete(self, trtype, traddr, trsvcid, adrfam=None): 187 self.get_root().nvmf_subsystem_remove_listener( 188 nqn=self.parent.subsystem.nqn, trtype=trtype, 189 traddr=traddr, trsvcid=trsvcid, adrfam=adrfam) 190 191 def ui_command_create(self, trtype, traddr, trsvcid, adrfam): 192 """Create address listener for subsystem. 193 194 Arguments: 195 trtype - NVMe-oF transport type: e.g., rdma. 196 traddr - NVMe-oF transport address: e.g., an ip address. 197 trsvcid - NVMe-oF transport service id: e.g., a port number. 198 adrfam - NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc. 199 """ 200 self.get_root().nvmf_subsystem_add_listener( 201 nqn=self.parent.subsystem.nqn, trtype=trtype, traddr=traddr, 202 trsvcid=trsvcid, adrfam=adrfam) 203 204 def ui_command_delete(self, trtype, traddr, trsvcid, adrfam=None): 205 """Remove address listener for subsystem. 206 207 Arguments: 208 trtype - Transport type (RDMA) 209 traddr - NVMe-oF transport address: e.g., an ip address. 210 trsvcid - NVMe-oF transport service id: e.g., a port number. 211 adrfam - Optional argument. Address family ("IPv4", "IPv6", "IB" or "FC"). 212 """ 213 self.delete(trtype, traddr, trsvcid, adrfam) 214 215 def ui_command_delete_all(self): 216 """Remove all address listeners from subsystem.""" 217 rpc_messages = "" 218 for la in self.listen_addresses: 219 try: 220 self.delete(la['trtype'], la['traddr'], la['trsvcid'], la['adrfam']) 221 except JSONRPCException as e: 222 rpc_messages += e.message 223 if rpc_messages: 224 raise JSONRPCException(rpc_messages) 225 226 def summary(self): 227 return "Addresses: %s" % len(self.listen_addresses), None 228 229 230class UINVMfSubsystemListener(UINode): 231 def __init__(self, address, parent): 232 UINode.__init__(self, "%s:%s" % (address['traddr'], address['trsvcid']), 233 parent) 234 self.address = address 235 236 def summary(self): 237 return "%s" % self.address['trtype'], True 238 239 240class UINVMfSubsystemHosts(UINode): 241 def __init__(self, hosts, parent): 242 UINode.__init__(self, "hosts", parent) 243 self.hosts = hosts 244 self.refresh() 245 246 def refresh(self): 247 self._children = set([]) 248 for host in self.hosts: 249 UINVMfSubsystemHost(host, self) 250 251 def refresh_node(self): 252 for subsystem in self.get_root().nvmf_get_subsystems(): 253 if subsystem.nqn == self.parent.subsystem.nqn: 254 self.hosts = subsystem.hosts 255 self.refresh() 256 257 def delete(self, host): 258 self.get_root().nvmf_subsystem_remove_host( 259 nqn=self.parent.subsystem.nqn, host=host) 260 261 def ui_command_create(self, host): 262 """Add a host NQN to the list of allowed hosts. 263 264 Args: 265 host: Host NQN to add to the list of allowed host NQNs 266 """ 267 self.get_root().nvmf_subsystem_add_host( 268 nqn=self.parent.subsystem.nqn, host=host) 269 270 def ui_command_delete(self, host): 271 """Delete host from subsystem. 272 273 Arguments: 274 host - NQN of host to remove. 275 """ 276 self.delete(host) 277 278 def ui_command_delete_all(self): 279 """Delete host from subsystem""" 280 rpc_messages = "" 281 for host in self.hosts: 282 try: 283 self.delete(host['nqn']) 284 except JSONRPCException as e: 285 rpc_messages += e.message 286 if rpc_messages: 287 raise JSONRPCException(rpc_messages) 288 289 def summary(self): 290 return "Hosts: %s" % len(self.hosts), None 291 292 293class UINVMfSubsystemHost(UINode): 294 def __init__(self, host, parent): 295 UINode.__init__(self, "%s" % host['nqn'], parent) 296 self.host = host 297 298 299class UINVMfSubsystemNamespaces(UINode): 300 def __init__(self, namespaces, parent): 301 UINode.__init__(self, "namespaces", parent) 302 self.namespaces = namespaces 303 self.refresh() 304 305 def refresh(self): 306 self._children = set([]) 307 for namespace in self.namespaces: 308 UINVMfSubsystemNamespace(namespace, self) 309 310 def refresh_node(self): 311 for subsystem in self.get_root().nvmf_get_subsystems(): 312 if subsystem.nqn == self.parent.subsystem.nqn: 313 self.namespaces = subsystem.namespaces 314 self.refresh() 315 316 def delete(self, nsid): 317 self.get_root().nvmf_subsystem_remove_ns( 318 nqn=self.parent.subsystem.nqn, nsid=nsid) 319 320 def ui_command_create(self, bdev_name, nsid=None, 321 nguid=None, eui64=None, uuid=None): 322 """Add a namespace to a subsystem. 323 324 Args: 325 bdev_name: Name of bdev to expose as a namespace. 326 Optional args: 327 nsid: Namespace ID. 328 nguid: 16-byte namespace globally unique identifier in hexadecimal. 329 eui64: 8-byte namespace EUI-64 in hexadecimal (e.g. "ABCDEF0123456789"). 330 uuid: Namespace UUID. 331 """ 332 nsid = self.ui_eval_param(nsid, "number", None) 333 self.get_root().nvmf_subsystem_add_ns( 334 nqn=self.parent.subsystem.nqn, bdev_name=bdev_name, 335 nsid=nsid, nguid=nguid, eui64=eui64, uuid=uuid) 336 337 def ui_command_delete(self, nsid): 338 """Delete namespace from subsystem. 339 340 Arguments: 341 nsid - Id of namespace to remove. 342 """ 343 nsid = self.ui_eval_param(nsid, "number", None) 344 self.delete(nsid) 345 346 def ui_command_delete_all(self): 347 """Delete all namespaces from subsystem.""" 348 rpc_messages = "" 349 for namespace in self.namespaces: 350 try: 351 self.delete(namespace['nsid']) 352 except JSONRPCException as e: 353 rpc_messages += e.message 354 if rpc_messages: 355 raise JSONRPCException(rpc_messages) 356 357 def summary(self): 358 return "Namespaces: %s" % len(self.namespaces), None 359 360 361class UINVMfSubsystemNamespace(UINode): 362 def __init__(self, namespace, parent): 363 UINode.__init__(self, namespace['bdev_name'], parent) 364 self.namespace = namespace 365 366 def summary(self): 367 info = ", ".join([self.namespace['name'], str(self.namespace['nsid'])]) 368 return info, None 369 370 371class UINVMfReferral(UINode): 372 def __init__(self, address, secure_channel, parent): 373 UINode.__init__(self, "%s:%s" % (address['traddr'], address['trsvcid']), 374 parent) 375 self.address = address 376 self.secure_channel = secure_channel 377 self.refresh() 378 379 def refresh(self): 380 self._children = set([]) 381 382 def refresh_node(self): 383 self.refresh() 384 385 def summary(self): 386 info = ", ".join([self.address['trtype'], "Secure channel"]) if self.secure_channel \ 387 else self.address['trtype'] 388 return info, None 389 390 391class UINVMfReferrals(UINode): 392 def __init__(self, parent): 393 UINode.__init__(self, "referral", parent) 394 self.refresh() 395 396 def refresh(self): 397 self._children = set([]) 398 for referral in self.get_root().nvmf_discovery_get_referrals(): 399 UINVMfReferral(referral.address, referral.secure_channel, self) 400 401 def delete(self, trtype, traddr, trsvcid, adrfam=None): 402 self.get_root().nvmf_discovery_remove_referral( 403 trtype=trtype, traddr=traddr, trsvcid=trsvcid, adrfam=adrfam) 404 405 def ui_command_create(self, trtype, traddr, trsvcid, adrfam, secure_channel=False): 406 """Create a referral to a discovery subsystem. 407 408 Arguments: 409 trtype - NVMe-oF transport type: e.g., rdma. 410 traddr - NVMe-oF transport address: e.g., an ip address. 411 trsvcid - NVMe-oF transport service id: e.g., a port number. 412 adrfam - NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc. 413 secure_channel - The connection to that discovery subsystem requires a secure channel 414 Default: False 415 """ 416 self.get_root().nvmf_discovery_add_referral( 417 trtype=trtype, traddr=traddr, 418 trsvcid=trsvcid, adrfam=adrfam, secure_channel=bool(secure_channel)) 419 420 def ui_command_delete(self, trtype, traddr, trsvcid, adrfam=None): 421 """Remove a referral to a discovery subsystem. 422 423 Arguments: 424 trtype - NVMe-oF transport type: e.g., rdma. 425 traddr - NVMe-oF transport address: e.g., an ip address. 426 trsvcid - NVMe-oF transport service id: e.g., a port number. 427 adrfam - Optional argument. NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc. 428 """ 429 self.delete(trtype, traddr, trsvcid, adrfam) 430 431 def summary(self): 432 return "Referrals: %s" % len(self.children), None 433