"""
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 ...
SNMP:
LLDP-MIB::lldpLocalSystemData
LLDP-MIB::lldpRemTable
"""
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]),
}