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
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
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
152
158
160
161 if feature == 'acls_auth':
162 feature = 'auth'
163 return feature in self.features
164
171
183
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
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
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
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
216 if not self.has_feature(feature):
217 raise RTSLibError("This fabric module does not implement "
218 + "the %s feature." % feature)
219
228
235
245
251
253 '''
254 Returns either iterable or None. None means fabric allows
255 arbitrary WWNs.
256 '''
257 return None
258
262
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
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
324
328 super(LoopbackFabricModule, self).__init__('loopback')
329 self.features = ("nexus",)
330 self.wwn_types = ('naa',)
331 self.kernel_module = "tcm_loop"
332
336 super(SBPFabricModule, self).__init__('sbp')
337 self.features = ()
338 self.wwn_types = ('eui',)
339 self.kernel_module = "sbp_target"
340
343
346
347
348 @property
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
359 super(Qla2xxxFabricModule, self).__init__('qla2xxx')
360 self.features = ("acls",)
361 self.wwn_types = ('naa',)
362 self.kernel_module = "tcm_qla2xxx"
363
367
369 return "naa." + wwn.replace(":", "")
370
371 @property
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
381 super(SRPTFabricModule, self).__init__('srpt')
382 self.features = ("acls",)
383 self.wwn_types = ('ib',)
384 self.kernel_module = "ib_srpt"
385
387
388 return "0x" + wwn[3:]
389
391 return "ib." + wwn[2:]
392
393 @property
395 for wwn_file in glob("/sys/class/infiniband/*/ports/*/gids/0"):
396 yield "ib." + fread(wwn_file).replace(":", "")
397
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
411
413 return "naa." + wwn.replace(":", "")
414
415 @property
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
425 super(USBGadgetFabricModule, self).__init__('usb_gadget')
426 self.features = ("nexus",)
427 self.wwn_types = ('naa',)
428 self.kernel_module = "tcm_usb_gadget"
429
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
447 "vhost": VhostFabricModule,
448 }
463