1# 2# This file is part of pysnmp software. 3# 4# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com> 5# License: http://snmplabs.com/pysnmp/license.html 6# 7import sys 8from pysnmp.smi.indices import OrderedDict, OidOrderedDict 9from pysnmp.smi import error 10from pysnmp import debug 11 12__all__ = ['MibViewController'] 13 14if sys.version_info[0] <= 2: 15 import types 16 17 classTypes = (types.ClassType, type) 18 instanceTypes = (types.InstanceType, object) 19else: 20 classTypes = (type,) 21 instanceTypes = (object,) 22 23 24class MibViewController(object): 25 def __init__(self, mibBuilder): 26 self.mibBuilder = mibBuilder 27 self.lastBuildId = -1 28 self.__mibSymbolsIdx = OrderedDict() 29 30 # Indexing part 31 32 def indexMib(self): 33 if self.lastBuildId == self.mibBuilder.lastBuildId: 34 return 35 36 debug.logger & debug.flagMIB and debug.logger('indexMib: re-indexing MIB view') 37 38 MibScalarInstance, = self.mibBuilder.importSymbols( 39 'SNMPv2-SMI', 'MibScalarInstance' 40 ) 41 42 # 43 # Create indices 44 # 45 46 # Module name -> module-scope indices 47 self.__mibSymbolsIdx.clear() 48 49 # Oid <-> label indices 50 51 # This is potentially ambiguous mapping. Sort modules in 52 # ascending age for resolution 53 def __sortFun(x, b=self.mibBuilder): 54 if b.moduleID in b.mibSymbols[x]: 55 m = b.mibSymbols[x][b.moduleID] 56 r = m.getRevisions() 57 if r: 58 return r[0] 59 60 return "1970-01-01 00:00" 61 62 modNames = list(self.mibBuilder.mibSymbols.keys()) 63 modNames.sort(key=__sortFun) 64 65 # Index modules names 66 for modName in [''] + modNames: 67 # Modules index 68 self.__mibSymbolsIdx[modName] = mibMod = { 69 'oidToLabelIdx': OidOrderedDict(), 70 'labelToOidIdx': {}, 71 'varToNameIdx': {}, 72 'typeToModIdx': OrderedDict(), 73 'oidToModIdx': {} 74 } 75 76 if not modName: 77 globMibMod = mibMod 78 continue 79 80 # Types & MIB vars indices 81 for n, v in self.mibBuilder.mibSymbols[modName].items(): 82 if n == self.mibBuilder.moduleID: # do not index this 83 continue # special symbol 84 if isinstance(v, classTypes): 85 if n in mibMod['typeToModIdx']: 86 raise error.SmiError( 87 'Duplicate SMI type %s::%s, has %s' % (modName, n, mibMod['typeToModIdx'][n]) 88 ) 89 globMibMod['typeToModIdx'][n] = modName 90 mibMod['typeToModIdx'][n] = modName 91 elif isinstance(v, instanceTypes): 92 if isinstance(v, MibScalarInstance): 93 continue 94 if n in mibMod['varToNameIdx']: 95 raise error.SmiError( 96 'Duplicate MIB variable %s::%s has %s' % (modName, n, mibMod['varToNameIdx'][n]) 97 ) 98 globMibMod['varToNameIdx'][n] = v.name 99 mibMod['varToNameIdx'][n] = v.name 100 # Potentionally ambiguous mapping ahead 101 globMibMod['oidToModIdx'][v.name] = modName 102 mibMod['oidToModIdx'][v.name] = modName 103 globMibMod['oidToLabelIdx'][v.name] = (n,) 104 mibMod['oidToLabelIdx'][v.name] = (n,) 105 else: 106 raise error.SmiError( 107 'Unexpected object %s::%s' % (modName, n) 108 ) 109 110 # Build oid->long-label index 111 oidToLabelIdx = self.__mibSymbolsIdx['']['oidToLabelIdx'] 112 labelToOidIdx = self.__mibSymbolsIdx['']['labelToOidIdx'] 113 prevOid = () 114 baseLabel = () 115 for key in oidToLabelIdx.keys(): 116 keydiff = len(key) - len(prevOid) 117 if keydiff > 0: 118 if prevOid: 119 if keydiff == 1: 120 baseLabel = oidToLabelIdx[prevOid] 121 else: 122 baseLabel += key[-keydiff:-1] 123 else: 124 baseLabel = () 125 elif keydiff < 0: 126 baseLabel = () 127 keyLen = len(key) 128 i = keyLen - 1 129 while i: 130 k = key[:i] 131 if k in oidToLabelIdx: 132 baseLabel = oidToLabelIdx[k] 133 if i != keyLen - 1: 134 baseLabel += key[i:-1] 135 break 136 i -= 1 137 # Build oid->long-label index 138 oidToLabelIdx[key] = baseLabel + oidToLabelIdx[key] 139 # Build label->oid index 140 labelToOidIdx[oidToLabelIdx[key]] = key 141 prevOid = key 142 143 # Build module-scope oid->long-label index 144 for mibMod in self.__mibSymbolsIdx.values(): 145 for oid in mibMod['oidToLabelIdx'].keys(): 146 mibMod['oidToLabelIdx'][oid] = oidToLabelIdx[oid] 147 mibMod['labelToOidIdx'][oidToLabelIdx[oid]] = oid 148 149 self.lastBuildId = self.mibBuilder.lastBuildId 150 151 # Module management 152 153 def getOrderedModuleName(self, index): 154 self.indexMib() 155 modNames = self.__mibSymbolsIdx.keys() 156 if modNames: 157 return modNames[index] 158 raise error.SmiError('No modules loaded at %s' % self) 159 160 def getFirstModuleName(self): 161 return self.getOrderedModuleName(0) 162 163 def getLastModuleName(self): 164 return self.getOrderedModuleName(-1) 165 166 def getNextModuleName(self, modName): 167 self.indexMib() 168 try: 169 return self.__mibSymbolsIdx.nextKey(modName) 170 except KeyError: 171 raise error.SmiError( 172 'No module next to %s at %s' % (modName, self) 173 ) 174 175 # MIB tree node management 176 177 def __getOidLabel(self, nodeName, oidToLabelIdx, labelToOidIdx): 178 """getOidLabel(nodeName) -> (oid, label, suffix)""" 179 if not nodeName: 180 return nodeName, nodeName, () 181 if nodeName in labelToOidIdx: 182 return labelToOidIdx[nodeName], nodeName, () 183 if nodeName in oidToLabelIdx: 184 return nodeName, oidToLabelIdx[nodeName], () 185 if len(nodeName) < 2: 186 return nodeName, nodeName, () 187 oid, label, suffix = self.__getOidLabel( 188 nodeName[:-1], oidToLabelIdx, labelToOidIdx 189 ) 190 suffix = suffix + nodeName[-1:] 191 resLabel = label + tuple([str(x) for x in suffix]) 192 if resLabel in labelToOidIdx: 193 return labelToOidIdx[resLabel], resLabel, () 194 resOid = oid + suffix 195 if resOid in oidToLabelIdx: 196 return resOid, oidToLabelIdx[resOid], () 197 return oid, label, suffix 198 199 def getNodeNameByOid(self, nodeName, modName=''): 200 self.indexMib() 201 if modName in self.__mibSymbolsIdx: 202 mibMod = self.__mibSymbolsIdx[modName] 203 else: 204 raise error.SmiError('No module %s at %s' % (modName, self)) 205 oid, label, suffix = self.__getOidLabel( 206 nodeName, mibMod['oidToLabelIdx'], mibMod['labelToOidIdx'] 207 ) 208 if oid == label: 209 raise error.NoSuchObjectError( 210 str='Can\'t resolve node name %s::%s at %s' % 211 (modName, nodeName, self) 212 ) 213 debug.logger & debug.flagMIB and debug.logger( 214 'getNodeNameByOid: resolved %s:%s -> %s.%s' % (modName, nodeName, label, suffix)) 215 return oid, label, suffix 216 217 def getNodeNameByDesc(self, nodeName, modName=''): 218 self.indexMib() 219 if modName in self.__mibSymbolsIdx: 220 mibMod = self.__mibSymbolsIdx[modName] 221 else: 222 raise error.SmiError('No module %s at %s' % (modName, self)) 223 if nodeName in mibMod['varToNameIdx']: 224 oid = mibMod['varToNameIdx'][nodeName] 225 else: 226 raise error.NoSuchObjectError( 227 str='No such symbol %s::%s at %s' % (modName, nodeName, self) 228 ) 229 debug.logger & debug.flagMIB and debug.logger( 230 'getNodeNameByDesc: resolved %s:%s -> %s' % (modName, nodeName, oid)) 231 return self.getNodeNameByOid(oid, modName) 232 233 def getNodeName(self, nodeName, modName=''): 234 # nodeName may be either an absolute OID/label or a 235 # ( MIB-symbol, su, ff, ix) 236 try: 237 # First try nodeName as an OID/label 238 return self.getNodeNameByOid(nodeName, modName) 239 except error.NoSuchObjectError: 240 # ...on failure, try as MIB symbol 241 oid, label, suffix = self.getNodeNameByDesc(nodeName[0], modName) 242 # ...with trailing suffix 243 return self.getNodeNameByOid(oid + suffix + nodeName[1:], modName) 244 245 def getOrderedNodeName(self, index, modName=''): 246 self.indexMib() 247 if modName in self.__mibSymbolsIdx: 248 mibMod = self.__mibSymbolsIdx[modName] 249 else: 250 raise error.SmiError('No module %s at %s' % (modName, self)) 251 if not mibMod['oidToLabelIdx']: 252 raise error.NoSuchObjectError( 253 str='No variables at MIB module %s at %s' % (modName, self) 254 ) 255 try: 256 oid, label = mibMod['oidToLabelIdx'].items()[index] 257 except KeyError: 258 raise error.NoSuchObjectError( 259 str='No symbol at position %s in MIB module %s at %s' % (index, modName, self) 260 ) 261 return oid, label, () 262 263 def getFirstNodeName(self, modName=''): 264 return self.getOrderedNodeName(0, modName) 265 266 def getLastNodeName(self, modName=''): 267 return self.getOrderedNodeName(-1, modName) 268 269 def getNextNodeName(self, nodeName, modName=''): 270 oid, label, suffix = self.getNodeName(nodeName, modName) 271 try: 272 return self.getNodeName( 273 self.__mibSymbolsIdx[modName]['oidToLabelIdx'].nextKey(oid) + suffix, modName 274 ) 275 except KeyError: 276 raise error.NoSuchObjectError( 277 str='No name next to %s::%s at %s' % (modName, nodeName, self) 278 ) 279 280 def getParentNodeName(self, nodeName, modName=''): 281 oid, label, suffix = self.getNodeName(nodeName, modName) 282 if len(oid) < 2: 283 raise error.NoSuchObjectError( 284 str='No parent name for %s::%s at %s' % 285 (modName, nodeName, self) 286 ) 287 return oid[:-1], label[:-1], oid[-1:] + suffix 288 289 def getNodeLocation(self, nodeName, modName=''): 290 oid, label, suffix = self.getNodeName(nodeName, modName) 291 return self.__mibSymbolsIdx['']['oidToModIdx'][oid], label[-1], suffix 292 293 # MIB type management 294 295 def getTypeName(self, typeName, modName=''): 296 self.indexMib() 297 if modName in self.__mibSymbolsIdx: 298 mibMod = self.__mibSymbolsIdx[modName] 299 else: 300 raise error.SmiError( 301 'No module %s at %s' % (modName, self) 302 ) 303 if typeName in mibMod['typeToModIdx']: 304 m = mibMod['typeToModIdx'][typeName] 305 else: 306 raise error.NoSuchObjectError( 307 str='No such type %s::%s at %s' % (modName, typeName, self) 308 ) 309 return m, typeName 310 311 def getOrderedTypeName(self, index, modName=''): 312 self.indexMib() 313 if modName in self.__mibSymbolsIdx: 314 mibMod = self.__mibSymbolsIdx[modName] 315 else: 316 raise error.SmiError('No module %s at %s' % (modName, self)) 317 if not mibMod['typeToModIdx']: 318 raise error.NoSuchObjectError( 319 str='No types at MIB module %s at %s' % (modName, self) 320 ) 321 t = mibMod['typeToModIdx'].keys()[index] 322 return mibMod['typeToModIdx'][t], t 323 324 def getFirstTypeName(self, modName=''): 325 return self.getOrderedTypeName(0, modName) 326 327 def getLastTypeName(self, modName=''): 328 return self.getOrderedTypeName(-1, modName) 329 330 def getNextType(self, typeName, modName=''): 331 m, t = self.getTypeName(typeName, modName) 332 try: 333 return self.__mibSymbolsIdx[m]['typeToModIdx'].nextKey(t) 334 except KeyError: 335 raise error.NoSuchObjectError( 336 str='No type next to %s::%s at %s' % (modName, typeName, self) 337 ) 338