pvl/snmp/bridge.py
author Tero Marttila <terom@paivola.fi>
Tue, 18 Mar 2014 21:24:35 +0200
changeset 397 8455f42d8926
parent 395 9de553b50128
permissions -rw-r--r--
pvl.snmp.bridge: dot1q support for per-vlan fdb's
"""
    Requirements:
        memoized-property

    Setup:
        ./opt/bin/build-pysnmp-mib -o usr/mibs/BRIDGE-MIB.py etc/mibs/rfc1493.mib

    Run:
        PYSNMP_MIB_DIRS=usr/mibs/ ./opt/bin/python ...

    SNMP:
        BRIDGE-MIB::dot1dTpFdbTable
        Q-BRIDGE-MIB::dot1qTpFdbTable
        Q-BRIDGE-MIB::dot1qVlanCurrentTable

"""

from pvl.snmp import snmp
from pvl.snmp.snmp import pysnmp

from memoized_property import memoized_property

import logging; log = logging.getLogger('pvl.snmp.vlan')

DOT1D_TP_AGING_TIME = pysnmp.MibVariable('BRIDGE-MIB', 'dot1dTpAgingTime', 0)
DOT1D_TP_FDB_PORT = pysnmp.MibVariable('BRIDGE-MIB', 'dot1dTpFdbPort')

DOT1Q_VLAN_FDB_ID = pysnmp.MibVariable('Q-BRIDGE-MIB', 'dot1qVlanFdbId') # [dot1qVlanIndex]

DOT1Q_TP_FDB_PORT = pysnmp.MibVariable('Q-BRIDGE-MIB', 'dot1qTpFdbPort') # [dot1qFdbId, dot1qTpFdbAddress]

def macaddr (value) :
    """
        Excepts a MAC address from an SNMP OctetString.
    """

    return ':'.join('{octet:02x}'.format(octet=c) for c in value.asNumbers())

class BridgeAgent (snmp.SNMPAgent) :
    """
        Query Bridge configuration.

        XXX: this is not VLAN-aware!
    """

    def ping (self) :
        for name, value in self.get(DOT1D_TP_AGING_TIME) :
            # XXX: ????
            if value.tagSet == pysnmp.rfc1905.NoSuchInstance.tagSet :
                continue

            return True

    def fdb_ports (self) :
        """
            Map hosts in the brige FDB to specific ports.
        """

        for idx, data in self.table(DOT1D_TP_FDB_PORT) :
            addr, = idx
            port = data[DOT1D_TP_FDB_PORT]
            
            yield macaddr(addr), int(port)

    def vlan_fdb (self) :
        """
            Get FDB id -> vlan mappings.

                (fdb, vlan)
        """

        for idx, data in self.table(DOT1Q_VLAN_FDB_ID) :
            time, vlan = idx
            fdb = int(data[DOT1Q_VLAN_FDB_ID])

            yield fdb, vlan

    def vlan_fdb_ports (self) :
        """
            Get per-vlan host -> port mappings.

                (macaddr, port, vlan)
        """

        fdb_to_vlan = dict(self.vlan_fdb())

        for idx, data in self.table(DOT1Q_TP_FDB_PORT) :
            fdb, addr = idx
            port = data[DOT1Q_TP_FDB_PORT]

            vlan = fdb_to_vlan.get(fdb)

            yield macaddr(addr), int(port), vlan


if __name__ == '__main__':
    import doctest
    doctest.testmod()