Below is the file 'plugins/cisco_ios.py' from this revision. You can also download the file.


from goatpy.snmpwrapper import snmpwalk
import basic_snmp
import csv
import os
import re

# http://tools.cisco.com/Support/SNMP/do/BrowseMIB.do?local=en&step=2&mibName=CISCO-TC-V1SMI
network_protocol = { '1' : 'ip', '2' : 'decnet', '3' : 'pup', '4' : 'chaos', '5' : 'xna', '6' : 'x121', '7' : 'appletalk', '8' : 'clns', '9' : 'lat', '10' : 'vines', '11' : 'cons', '12' : 'apollo', '13' : 'stun', '14' : 'novell', '15' : 'qllc', '16' : 'snapshot', '17' : 'atmIlmi', '18' : 'bstun', '19' : 'x25pvc', '20' : 'ipv6', '21' : 'cdm', '22' : 'nbf', '23' : 'bpxIgx', '24' : 'clnsPfx', '25' : 'http' }

# http://tools.cisco.com/Support/SNMP/do/BrowseMIB.do?local=en&mibName=CISCO-CDP-MIB
def adjacency(table_name, table_io, device):
    def to_ipaddr(s):
        if not s:
            return s
        return '.'.join([str(t) for t in map(lambda h: int(h, 16), s.split(' '))])
    def to_ascii(s):
        if not s:
            return s
        asdigits = [int(t, 16) for t in s.split(' ')]
        asdigits = filter(lambda x: x >= 32 and x <= 122, asdigits)
        return ''.join([chr(t) for t in asdigits])
    row_to_field =  { 1 : ('INTEGER', 'cdpCacheIfIndex'),
                      3 : ('INTEGER', 'cdpCacheAddressType'),
                      4 : ('Hex-STRING', 'cdpCacheAddress'),
                      6 : ('STRING', 'cdpCacheDeviceId'),
                      7 : ('STRING', 'cdpCacheDevicePort')  }
    table = {}
    for oid, type, value in snmpwalk(device.device_name, device.config['community'], "2c", "SNMPv2-SMI::enterprises.9.9.23.1.2.1.1", ssh_dest=device.config.get('ssh')):
        id, row = tuple(oid[-2:]), int(oid[-3])
        if not table.has_key(id): table[id] = {}
        match_type, match_name = row_to_field.get(row, (None, None))
        if match_name and match_type and match_type == type:
            table[id][match_name] = value

    for row in table:
        vals = table[row]
        yield (device.config['zone'],
               vals.get('cdpCacheDeviceId', '')[1:-1],
               vals.get('cdpCacheIfIndex', ''),
               vals.get('cdpCacheDevicePort', '')[1:-1],
               network_protocol.get(vals.get('cdpCacheAddressType'), 'unknown'),
               to_ipaddr(vals.get('cdpCacheAddress', '')))

# see: http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a0080094a9b.shtml
def ethernet_forwarding(table_name, table_io, device):
    vlans_file = device.get_filename('ethernet_vlans')
    vlans = []
    if os.access(vlans_file, os.R_OK):
        rows = csv.reader(open(vlans_file))
        header = rows.next()
        vlan_column = header.index('vlan')
        for row in rows:
            vlans.append(row[vlan_column])
	# build the bridgeport -> ifindex table
	bridgeport_to_ifindex = {}
	for oid, type, value in snmpwalk(device.device_name, device.config['community'], "2c", "1.3.6.1.2.1.2.2.1.1", ssh_dest=device.config.get('ssh')): # dot1dBasePortIfIndex
		bridgeport = int(oid[-1])
		ifindex = int(value)
		bridgeport_to_ifindex[bridgeport] = ifindex

    def get_uid_to_mac(vlan):
    	rv = {}
    	for oid, type, value in  snmpwalk(device.device_name, device.config['community'] + '@' + vlan, "2c", ".1.3.6.1.2.1.17.4.3.1.1", ssh_dest=device.config.get('ssh')): # dot1dTpFdbAddress
    		uid = tuple(oid[-6:])
    		mac = value
    		rv[uid] = mac
    	return rv

    def get_uid_to_bridgeport(vlan):
    	rv = {}
    	for oid, type, value in  snmpwalk(device.device_name, device.config['community'] + '@' + vlan, "2c", ".1.3.6.1.2.1.17.4.3.1.2", ssh_dest=device.config.get('ssh')): # dot1dTpFdbAddress
    		uid = tuple(oid[-6:])
    		bridgeport = int(value)
    		rv[uid] = bridgeport
    	return rv

    for vlan in vlans:
        log("retrieving vlan forwarding table for : %s" % (vlan))
        uid_to_mac = get_uid_to_mac(vlan)
        uid_to_bridgeport = get_uid_to_bridgeport(vlan)
        for uid in uid_to_mac:
            mac, bridgeport = uid_to_mac.get(uid), uid_to_bridgeport.get(uid)
            if bridgeport and mac:
                ifindex = bridgeport_to_ifindex.get(bridgeport)
                yield device.config['zone'], vlan, mac, ifindex

def ethernet_vlans(table_name, table_io, device):
    # walk vtpVlanName
    for oid, type, value in snmpwalk(device.device_name, device.config['community'], "2c", ".1.3.6.1.4.1.9.9.46.1.3.1.1.4", ssh_dest=device.config.get('ssh')):
        value = value[1:-1]
        yield device.config['zone'], int(oid[-1]), value

tables = {
    'adjacency' : adjacency,
    'ethernet_forwarding' : ethernet_forwarding,
    'ethernet_vlans' : ethernet_vlans,
    'ip_addresses' : basic_snmp.ip_addresses,
    'ip_arp' : basic_snmp.ip_arp,
    'ip_routing' : basic_snmp.ip_routing
}

def init():
    export['has_table'] = simple_has_table(tables)
    export['get_table'] = simple_get_table(tables)
    log("Cisco IOS initialised")