Package rtslib :: Module fabric
[hide private]
[frames] | no frames]

Source Code for Module rtslib.fabric

  1  ''' 
  2  This file is part of RTSLib. 
  3  Copyright (c) 2011-2013 by Datera, Inc 
  4  Copyright (c) 2013 by Andy Grover 
  5   
  6  Licensed under the Apache License, Version 2.0 (the "License"); you may 
  7  not use this file except in compliance with the License. You may obtain 
  8  a copy of the License at 
  9   
 10      http://www.apache.org/licenses/LICENSE-2.0 
 11   
 12  Unless required by applicable law or agreed to in writing, software 
 13  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
 14  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
 15  License for the specific language governing permissions and limitations 
 16  under the License. 
 17   
 18   
 19  Description 
 20  ----------- 
 21   
 22  Fabrics may differ in how fabric WWNs are represented, as well as 
 23  what capabilities they support 
 24   
 25   
 26  Available parameters 
 27  -------------------- 
 28   
 29  * features 
 30  Lists the target fabric available features. Default value: 
 31  ("discovery_auth", "acls", "auth", "nps") 
 32  example: features = ("discovery_auth", "acls", "auth") 
 33  example: features = () # no features supported 
 34   
 35  Detail of features: 
 36   
 37    * tpgts 
 38    The target fabric module is using iSCSI-style target portal group tags. 
 39   
 40    * discovery_auth 
 41    The target fabric module supports a fabric-wide authentication for 
 42    discovery. 
 43   
 44    * acls 
 45    The target's TPGTs support explicit initiator ACLs. 
 46   
 47    * auth 
 48    The target's TPGT's support per-TPG authentication, and 
 49    the target's TPGT's ACLs support per-ACL initiator authentication. 
 50    Fabrics that support auth must support acls. 
 51   
 52    * nps 
 53    The TPGTs support iSCSI-like IPv4/IPv6 network portals, using IP:PORT 
 54    group names. 
 55   
 56    * nexus 
 57    The TPGTs have a 'nexus' attribute that contains the local initiator 
 58    serial unit. This attribute must be set before being able to create any 
 59    LUNs. 
 60   
 61    * wwn_types 
 62    Sets the type of WWN expected by the target fabric. Defaults to 'free'. 
 63    Usually a fabric will only support one type but iSCSI supports more. 
 64    First entry is the "native" wwn type - i.e. if a wwn can be generated, it 
 65    will be of this type. 
 66    Example: wwn_types = ("eui",) 
 67    Current valid types are: 
 68   
 69      * free 
 70      Freeform WWN. 
 71   
 72      * iqn 
 73      The fabric module targets are using iSCSI-type IQNs. 
 74   
 75      * naa 
 76      NAA FC or SAS address type WWN. 
 77   
 78      * eui 
 79      EUI-64. See http://en.wikipedia.org/wiki/MAC_address for info on this format. 
 80   
 81      * unit_serial 
 82      Disk-type unit serial. 
 83   
 84  * wwns 
 85  This property returns an iterable (either generator or list) of valid 
 86  target WWNs for the fabric, if WWNs should be chosen from existing 
 87  fabric interfaces. The most common case for this is hardware-set 
 88  WWNs. WWNs should conform to rtslib's normalized internal format: the wwn 
 89  type (see above), a period, then the wwn with interstitial dividers like 
 90  ':' removed. 
 91   
 92  * to_fabric_wwn() 
 93  Converts WWNs from normalized format (see above) to whatever the kernel code 
 94  expects when getting a wwn. Only needed if different from normalized format. 
 95   
 96  * kernel_module 
 97  Sets the name of the kernel module implementing the fabric modules. If 
 98  not specified, it will be assumed to be MODNAME_target_mod, where 
 99  MODNAME is the name of the fabric module, from the fabrics list. Note 
100  that you must not specify any .ko or such extension here. 
101  Example: self.kernel_module = "my_module" 
102   
103  * _path 
104  Sets the path of the configfs group used by the fabric module. Defaults to the 
105  name of the module from the fabrics list. 
106  Example: self._path = "%s/%s" % (self.configfs_dir, "my_cfs_dir") 
107   
108  ''' 
109   
110  import os 
111  from glob import iglob as glob 
112   
113  from node import CFSNode 
114  from utils import fread, fwrite, generate_wwn, normalize_wwn, colonize 
115  from utils import RTSLibError, modprobe, ignored 
116  from target import Target 
117  from utils import _get_auth_attr, _set_auth_attr 
118  from functools import partial 
119   
120  version_attributes = {"lio_version", "version"} 
121  discovery_auth_attributes = {"discovery_auth"} 
122  target_names_excludes = version_attributes | discovery_auth_attributes 
123 124 125 -class _BaseFabricModule(CFSNode):
126 ''' 127 Abstract Base clase for Fabric Modules. 128 It can load modules, provide information about them and 129 handle the configfs housekeeping. After instantiation, whether or 130 not the fabric module is loaded depends on if a method requiring 131 it (i.e. accessing configfs) is used. This helps limit loaded 132 kernel modules to just the fabrics in use. 133 ''' 134 135 # FabricModule ABC private stuff
136 - def __init__(self, name):
137 ''' 138 Instantiate a FabricModule object, according to the provided name. 139 @param name: the name of the FabricModule object. It must match an 140 existing target fabric module specfile (name.spec). 141 @type name: str 142 ''' 143 super(_BaseFabricModule, self).__init__() 144 self.name = str(name) 145 self.spec_file = "N/A" 146 self._path = "%s/%s" % (self.configfs_dir, self.name) 147 self.features = ('discovery_auth', 'acls', 'auth', 'nps', 'tpgts') 148 self.wwn_types = ('free',) 149 self.kernel_module = "%s_target_mod" % self.name
150 151 # FabricModule public stuff 152
153 - def _check_self(self):
154 if not self.exists: 155 modprobe(self.kernel_module) 156 self._create_in_cfs_ine('any') 157 super(_BaseFabricModule, self)._check_self()
158
159 - def has_feature(self, feature):
160 # Handle a renamed feature 161 if feature == 'acls_auth': 162 feature = 'auth' 163 return feature in self.features
164
165 - def _list_targets(self):
166 if self.exists: 167 for wwn in os.listdir(self.path): 168 if os.path.isdir("%s/%s" % (self.path, wwn)) and \ 169 wwn not in target_names_excludes: 170 yield Target(self, self.from_fabric_wwn(wwn), 'lookup')
171
172 - def _get_version(self):
173 if self.exists: 174 for attr in version_attributes: 175 path = "%s/%s" % (self.path, attr) 176 if os.path.isfile(path): 177 return fread(path) 178 else: 179 raise RTSLibError("Can't find version for fabric module %s." 180 % self.name) 181 else: 182 return None
183
184 - def to_normalized_wwn(self, wwn):
185 ''' 186 Checks whether or not the provided WWN is valid for this fabric module 187 according to the spec, and returns a tuple of our preferred string 188 representation of the wwn, and what type it turned out to be. 189 ''' 190 return normalize_wwn(self.wwn_types, wwn)
191
192 - def to_fabric_wwn(self, wwn):
193 ''' 194 Some fabrics need WWNs in a format different than rtslib's internal 195 format. These fabrics should override this method. 196 ''' 197 return wwn
198
199 - def from_fabric_wwn(self, wwn):
200 ''' 201 Converts from WWN format used in this fabric's LIO configfs to canonical 202 format. 203 Note: Do not call from wwns(). There's no guarantee fabric wwn format is 204 the same as wherever wwns() is reading from. 205 ''' 206 return wwn
207
208 - def needs_wwn(self):
209 ''' 210 This fabric requires wwn to be specified when creating a target, 211 it cannot be autogenerated. 212 ''' 213 return self.wwns != None
214
215 - def _assert_feature(self, feature):
216 if not self.has_feature(feature): 217 raise RTSLibError("This fabric module does not implement " 218 + "the %s feature." % feature)
219
221 self._check_self() 222 self._assert_feature('discovery_auth') 223 self.discovery_mutual_password = '' 224 self.discovery_mutual_userid = '' 225 self.discovery_password = '' 226 self.discovery_userid = '' 227 self.discovery_enable_auth = False
228
230 self._check_self() 231 self._assert_feature('discovery_auth') 232 path = "%s/discovery_auth/enforce_discovery_auth" % self.path 233 value = fread(path) 234 return bool(int(value))
235
236 - def _set_discovery_enable_auth(self, enable):
237 self._check_self() 238 self._assert_feature('discovery_auth') 239 path = "%s/discovery_auth/enforce_discovery_auth" % self.path 240 if int(enable): 241 enable = 1 242 else: 243 enable = 0 244 fwrite(path, "%s" % enable)
245
247 self._check_self() 248 self._assert_feature('discovery_auth') 249 path = "%s/discovery_auth/authenticate_target" % self.path 250 return bool(int(fread(path)))
251
252 - def _get_wwns(self):
253 ''' 254 Returns either iterable or None. None means fabric allows 255 arbitrary WWNs. 256 ''' 257 return None
258
259 - def _get_disc_attr(self, *args, **kwargs):
260 self._assert_feature('discovery_auth') 261 return _get_auth_attr(self, *args, **kwargs)
262
263 - def _set_disc_attr(self, *args, **kwargs):
264 self._assert_feature('discovery_auth') 265 _set_auth_attr(self, *args, **kwargs)
266 267 discovery_enable_auth = \ 268 property(_get_discovery_enable_auth, 269 _set_discovery_enable_auth, 270 doc="Set or get the discovery enable_auth flag.") 271 discovery_authenticate_target = property(_get_discovery_authenticate_target, 272 doc="Get the boolean discovery authenticate target flag.") 273 274 discovery_userid = property(partial(_get_disc_attr, attribute='discovery_auth/userid'), 275 partial(_set_disc_attr, attribute='discovery_auth/userid'), 276 doc="Set or get the initiator discovery userid.") 277 discovery_password = property(partial(_get_disc_attr, attribute='discovery_auth/password'), 278 partial(_set_disc_attr, attribute='discovery_auth/password'), 279 doc="Set or get the initiator discovery password.") 280 discovery_mutual_userid = property(partial(_get_disc_attr, attribute='discovery_auth/userid_mutual'), 281 partial(_set_disc_attr, attribute='discovery_auth/userid_mutual'), 282 doc="Set or get the mutual discovery userid.") 283 discovery_mutual_password = property(partial(_get_disc_attr, attribute='discovery_auth/password_mutual'), 284 partial(_set_disc_attr, attribute='discovery_auth/password_mutual'), 285 doc="Set or get the mutual discovery password.") 286 287 targets = property(_list_targets, 288 doc="Get the list of target objects.") 289 290 version = property(_get_version, 291 doc="Get the fabric module version string.") 292 293 wwns = property(_get_wwns, 294 doc="iterable of WWNs present for this fabric") 295
296 - def setup(self, fm, err_func):
297 ''' 298 Setup fabricmodule with settings from fm dict. 299 ''' 300 for name, value in fm.iteritems(): 301 if name != 'name': 302 try: 303 setattr(self, name, value) 304 except: 305 err_func("Could not set fabric %s attribute '%s'" % (fm['name'], name))
306
307 - def dump(self):
308 d = super(_BaseFabricModule, self).dump() 309 d['name'] = self.name 310 if self.has_feature("discovery_auth"): 311 for attr in ("userid", "password", "mutual_userid", "mutual_password"): 312 val = getattr(self, "discovery_" + attr, None) 313 if val: 314 d["discovery_" + attr] = val 315 d['discovery_enable_auth'] = self.discovery_enable_auth 316 return d
317
318 319 -class ISCSIFabricModule(_BaseFabricModule):
320
321 - def __init__(self):
322 super(ISCSIFabricModule, self).__init__('iscsi') 323 self.wwn_types = ('iqn', 'naa', 'eui')
324
325 326 -class LoopbackFabricModule(_BaseFabricModule):
327 - def __init__(self):
328 super(LoopbackFabricModule, self).__init__('loopback') 329 self.features = ("nexus",) 330 self.wwn_types = ('naa',) 331 self.kernel_module = "tcm_loop"
332
333 334 -class SBPFabricModule(_BaseFabricModule):
335 - def __init__(self):
336 super(SBPFabricModule, self).__init__('sbp') 337 self.features = () 338 self.wwn_types = ('eui',) 339 self.kernel_module = "sbp_target"
340
341 - def to_fabric_wwn(self, wwn):
342 return wwn[4:]
343
344 - def from_fabric_wwn(self, wwn):
345 return "eui." + wwn
346 347 # return 1st local guid (is unique) so our share is named uniquely 348 @property
349 - def wwns(self):
350 for fname in glob("/sys/bus/firewire/devices/fw*/is_local"): 351 if bool(int(fread(fname))): 352 guid_path = os.path.dirname(fname) + "/guid" 353 yield "eui." + fread(guid_path)[2:] 354 break
355
356 357 -class Qla2xxxFabricModule(_BaseFabricModule):
358 - def __init__(self):
359 super(Qla2xxxFabricModule, self).__init__('qla2xxx') 360 self.features = ("acls",) 361 self.wwn_types = ('naa',) 362 self.kernel_module = "tcm_qla2xxx"
363
364 - def to_fabric_wwn(self, wwn):
365 # strip 'naa.' and add colons 366 return colonize(wwn[4:])
367
368 - def from_fabric_wwn(self, wwn):
369 return "naa." + wwn.replace(":", "")
370 371 @property
372 - def wwns(self):
373 for wwn_file in glob("/sys/class/fc_host/host*/port_name"): 374 with ignored(IOError): 375 if not fread(os.path.dirname(wwn_file)+"/symbolic_name").startswith("fcoe"): 376 yield "naa." + fread(wwn_file)[2:]
377
378 379 -class SRPTFabricModule(_BaseFabricModule):
380 - def __init__(self):
381 super(SRPTFabricModule, self).__init__('srpt') 382 self.features = ("acls",) 383 self.wwn_types = ('ib',) 384 self.kernel_module = "ib_srpt"
385
386 - def to_fabric_wwn(self, wwn):
387 # strip 'ib.' and re-add '0x' 388 return "0x" + wwn[3:]
389
390 - def from_fabric_wwn(self, wwn):
391 return "ib." + wwn[2:]
392 393 @property
394 - def wwns(self):
395 for wwn_file in glob("/sys/class/infiniband/*/ports/*/gids/0"): 396 yield "ib." + fread(wwn_file).replace(":", "")
397
398 399 -class FCoEFabricModule(_BaseFabricModule):
400 - def __init__(self):
401 super(FCoEFabricModule, self).__init__('tcm_fc') 402 403 self.features = ("acls",) 404 self.kernel_module = "tcm_fc" 405 self.wwn_types=('naa',) 406 self._path = "%s/%s" % (self.configfs_dir, "fc")
407
408 - def to_fabric_wwn(self, wwn):
409 # strip 'naa.' and add colons 410 return colonize(wwn[4:])
411
412 - def from_fabric_wwn(self, wwn):
413 return "naa." + wwn.replace(":", "")
414 415 @property
416 - def wwns(self):
417 for wwn_file in glob("/sys/class/fc_host/host*/port_name"): 418 with ignored(IOError): 419 if fread(os.path.dirname(wwn_file)+"/symbolic_name").startswith("fcoe"): 420 yield "naa." + fread(wwn_file)[2:]
421
422 423 -class USBGadgetFabricModule(_BaseFabricModule):
424 - def __init__(self):
425 super(USBGadgetFabricModule, self).__init__('usb_gadget') 426 self.features = ("nexus",) 427 self.wwn_types = ('naa',) 428 self.kernel_module = "tcm_usb_gadget"
429
430 431 -class VhostFabricModule(_BaseFabricModule):
432 - def __init__(self):
433 super(VhostFabricModule, self).__init__('vhost') 434 self.features = ("nexus", "acls", "tpgts") 435 self.wwn_types = ('naa',) 436 self.kernel_module = "tcm_vhost"
437 438 439 fabric_modules = { 440 "srpt": SRPTFabricModule, 441 "iscsi": ISCSIFabricModule, 442 "loopback": LoopbackFabricModule, 443 "qla2xxx": Qla2xxxFabricModule, 444 "sbp": SBPFabricModule, 445 "tcm_fc": FCoEFabricModule, 446 # "usb_gadget": USBGadgetFabricModule, # very rare, don't show 447 "vhost": VhostFabricModule, 448 }
449 450 # 451 # Maintain compatibility with existing FabricModule(fabricname) usage 452 # e.g. FabricModule('iscsi') returns an ISCSIFabricModule 453 # 454 -class FabricModule(object):
455
456 - def __new__(cls, name):
457 return fabric_modules[name]()
458 459 @classmethod
460 - def all(cls):
461 for mod in fabric_modules.itervalues(): 462 yield mod()
463