add missing pvl.snmp.* files
authorTero Marttila <terom@paivola.fi>
Mon, 17 Mar 2014 23:54:00 +0200
changeset 389 93e3b199cbe6
parent 388 5a034dbd641c
child 390 e72f78b8bce4
add missing pvl.snmp.* files
pvl/snmp/__init__.py
pvl/snmp/lldp.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pvl/snmp/lldp.py	Mon Mar 17 23:54:00 2014 +0200
@@ -0,0 +1,139 @@
+"""
+    Requirements:
+        memoized-property
+
+    Setup:
+        ./opt/bin/build-pysnmp-mib -o usr/mibs/LLDP-MIB.py etc/mibs/LLDP-MIB
+
+    Run:
+        PYSNMP_MIB_DIRS=usr/mibs/ ./opt/bin/python ...
+
+"""
+
+from pvl.snmp import snmp
+from pvl.snmp.snmp import pysnmp
+
+from memoized_property import memoized_property
+
+import logging; log = logging.getLogger('pvl.snmp.lldp')
+
+def macaddr (value) :
+    """
+        Excepts a MAC address from an SNMP OctetString.
+    """
+
+    return ':'.join('{octet:02x}'.format(octet=c) for c in value.asNumbers())
+
+class LLDPAgent (snmp.SNMPAgent) :
+    """
+        Query LLDP info from a remote agent.
+    """
+
+    @classmethod
+    def _chassis_id (cls, chassis_id, subtype) :
+        log.debug("%s: %r", subtype, chassis_id)
+        
+        # XXX: reference names from LLDP-MIB.py
+        if subtype == 4:
+            return macaddr(chassis_id)
+        else :
+            return chassis_id
+ 
+    @classmethod
+    def _port_id (cls, port_id, subtype, desc) :
+        log.debug("%s: %r (%s)", subtype, port_id, desc)
+        
+        # XXX: reference names from LLDP-MIB.py
+        if subtype == 5: # interfaceName -> IF-MIB::ifName ?
+            return str(port_id)
+        elif subtype == 3 : # macAddress
+            if desc :
+                # prefer desc in this case
+                return desc
+            else :
+                return macaddr(port_id)
+        elif subtype == 7 : # local
+            return str(port_id) # XXX: integer?
+        else :
+            log.warn("unknown subtype=%d: %r", subtype, port_id)
+
+            return port_id
+       
+    LLDP_LOC_CHASSIS_ID = pysnmp.MibVariable('LLDP-MIB', 'lldpLocChassisId')
+    LLDP_LOC_CHASSIS_ID_SUBTYPE = pysnmp.MibVariable('LLDP-MIB', 'lldpLocChassisIdSubtype')
+    LLDP_LOC_SYS_NAME = pysnmp.MibVariable('LLDP-MIB', 'lldpLocSysName')
+
+    @memoized_property
+    def local (self) :
+        """
+            Describe the local system.
+        """
+
+        for idx, data in self.table(
+                self.LLDP_LOC_CHASSIS_ID,
+                self.LLDP_LOC_CHASSIS_ID_SUBTYPE,
+                self.LLDP_LOC_SYS_NAME,
+        ) :
+            return {
+                    'chassis':  self._chassis_id(data[self.LLDP_LOC_CHASSIS_ID], data[self.LLDP_LOC_CHASSIS_ID_SUBTYPE]),
+                    'sys_name': str(data[self.LLDP_LOC_SYS_NAME]),
+            }
+
+    LLDP_LOC_PORT_DESC = pysnmp.MibVariable('LLDP-MIB', 'lldpLocPortDesc')
+    LLDP_LOC_PORT_ID = pysnmp.MibVariable('LLDP-MIB', 'lldpLocPortId')
+    LLDP_LOC_PORT_ID_SUBTYPE = pysnmp.MibVariable('LLDP-MIB', 'lldpLocPortIdSubtype')
+
+    @memoized_property
+    def ports (self) :
+        """
+            Describe the local ports.
+        """
+
+        ports = { }
+
+        for idx, data in self.table(
+                self.LLDP_LOC_PORT_DESC,
+                self.LLDP_LOC_PORT_ID,
+                self.LLDP_LOC_PORT_ID_SUBTYPE,
+        ) :
+            port, = idx
+            
+            ports[int(port)] = {
+                    'port_id': int(port),
+                    'port': self._port_id(data[self.LLDP_LOC_PORT_ID], data[self.LLDP_LOC_PORT_ID_SUBTYPE], data[self.LLDP_LOC_PORT_DESC]),
+            }
+
+        return ports
+
+    def port (self, port) :
+        return self.ports[int(port)]
+
+    LLDP_REM_CHASSIS_ID = pysnmp.MibVariable('LLDP-MIB', 'lldpRemChassisId')
+    LLDP_REM_CHASSIS_ID_SUBTYPE = pysnmp.MibVariable('LLDP-MIB', 'lldpRemChassisIdSubtype')
+    LLDP_REM_SYS_NAME = pysnmp.MibVariable('LLDP-MIB', 'lldpRemSysName')
+    LLDP_REM_PORT_ID = pysnmp.MibVariable('LLDP-MIB', 'lldpRemPortId')
+    LLDP_REM_PORT_ID_SUBTYPE = pysnmp.MibVariable('LLDP-MIB', 'lldpRemPortIdSubtype')
+    LLDP_REM_PORT_DESC = pysnmp.MibVariable('LLDP-MIB', 'lldpRemPortDesc')
+
+    def remotes (self) :
+        """
+            Describe remote systems, indexed by local port.
+        """
+
+        for idx, data in self.table(
+                self.LLDP_REM_CHASSIS_ID,
+                self.LLDP_REM_CHASSIS_ID_SUBTYPE,
+                self.LLDP_REM_SYS_NAME,
+                self.LLDP_REM_PORT_ID,
+                self.LLDP_REM_PORT_ID_SUBTYPE,
+                self.LLDP_REM_PORT_DESC,
+        ) :
+            time, port, idx = idx
+
+            yield int(port), {
+                'chassis':  self._chassis_id(data[self.LLDP_REM_CHASSIS_ID], data[self.LLDP_REM_CHASSIS_ID_SUBTYPE]),
+                'sys_name': str(data[self.LLDP_REM_SYS_NAME]),
+                'port':     self._port_id(data[self.LLDP_REM_PORT_ID], data[self.LLDP_REM_PORT_ID_SUBTYPE], data[self.LLDP_REM_PORT_DESC]),
+            }
+
+