def _snmp_map_switch(switch, password, user): haveqbridge = False mactobridge = {} conn = snmp.Session(switch, password, user) ifnamemap = get_portnamemap(conn) for vb in conn.walk('1.3.6.1.2.1.17.7.1.2.2.1.2'): haveqbridge = True oid, bridgeport = vb if not bridgeport: continue oid = str(oid).rsplit('.', 6) # if 7, then oid[1] would be vlan id macaddr = '{0:02x}:{1:02x}:{2:02x}:{3:02x}:{4:02x}:{5:02x}'.format( *([int(x) for x in oid[-6:]])) mactobridge[macaddr] = int(bridgeport) if not haveqbridge: for vb in conn.walk('1.3.6.1.2.1.17.4.3.1.2'): oid, bridgeport = vb if not bridgeport: continue oid = str(oid).rsplit('.', 6) macaddr = '{0:02x}:{1:02x}:{2:02x}:{3:02x}:{4:02x}:{5:02x}'.format( *([int(x) for x in oid[-6:]])) mactobridge[macaddr] = int(bridgeport) vlanstocheck = set([]) try: #ciscoiftovlanmap = {} for vb in conn.walk('.1.3.6.1.4.1.9.9.68.1.2.2.1.2'): vlanstocheck.add(vb[1]) #ciscotrunktovlanmap = {} for vb in conn.walk('.1.3.6.1.4.1.9.9.46.1.6.1.1.5'): vlanstocheck.add(vb[1]) except Exception: # We might have crashed snmp on a non-cisco switch # in such a case, delay 8 seconds to allow recovery to complete eventlet.sleep(8) if not vlanstocheck: vlanstocheck.add(None) bridgetoifmap = {} for vlan in vlanstocheck: if vlan: if user: conn = snmp.Session(switch, password, user, 'vlan-{}'.format(vlan)) else: if not isinstance(password, str): password = password.decode('utf8') conn = snmp.Session(switch, '{}@{}'.format(password, vlan)) for vb in conn.walk('1.3.6.1.2.1.17.1.4.1.2'): bridgeport, ifidx = vb bridgeport = int(str(bridgeport).rsplit('.', 1)[1]) try: bridgetoifmap[bridgeport] = int(ifidx) except ValueError: # ifidx might be '', skip in such a case continue #OFFLOAD: end of need to offload? return mactobridge, ifnamemap, bridgetoifmap
def _map_switch_backend(args): """Manipulate portions of mac address map relevant to a given switch """ # 1.3.6.1.2.1.17.7.1.2.2.1.2 - mactoindex (qbridge - preferred) # if not, check for cisco and if cisco, build list of all relevant vlans: # .1.3.6.1.4.1.9.9.46.1.6.1.1.5 - trunk port vlan map (cisco only) # .1.3.6.1.4.1.9.9.68.1.2.2.1.2 - access port vlan map (cisco only) # if cisco, vlan community string indexed or snmpv3 contest for: # 1.3.6.1.2.1.17.4.3.1.2 - mactoindx (bridge - low-end switches and cisco) # .1.3.6.1.2.1.17.1.4.1.2 - bridge index to if index map # no vlan index or context for: # .1.3.6.1.2.1.31.1.1.1.1 - ifName... but some switches don't do it # .1.3.6.1.2.1.2.2.1.2 - ifDescr, usually useless, but a # fallback if ifName is empty # global _macmap if len(args) == 3: switch, password, user = args if not user: user = None else: switch, password = args user = None haveqbridge = False mactobridge = {} conn = snmp.Session(switch, password, user) for vb in conn.walk('1.3.6.1.2.1.17.7.1.2.2.1.2'): haveqbridge = True oid, bridgeport = vb if not bridgeport: continue oid = str(oid).rsplit('.', 6) # if 7, then oid[1] would be vlan id macaddr = '{0:02x}:{1:02x}:{2:02x}:{3:02x}:{4:02x}:{5:02x}'.format( *([int(x) for x in oid[-6:]])) mactobridge[macaddr] = int(bridgeport) if not haveqbridge: for vb in conn.walk('1.3.6.1.2.1.17.4.3.1.2'): oid, bridgeport = vb if not bridgeport: continue oid = str(oid).rsplit('.', 6) macaddr = '{0:02x}:{1:02x}:{2:02x}:{3:02x}:{4:02x}:{5:02x}'.format( *([int(x) for x in oid[-6:]])) mactobridge[macaddr] = int(bridgeport) bridgetoifmap = {} for vb in conn.walk('1.3.6.1.2.1.17.1.4.1.2'): bridgeport, ifidx = vb bridgeport = int(str(bridgeport).rsplit('.', 1)[1]) try: bridgetoifmap[bridgeport] = int(ifidx) except ValueError: # ifidx might be '', skip in such a case continue ifnamemap = get_portnamemap(conn) maccounts = {} bridgetoifvalid = False for mac in mactobridge: try: ifname = ifnamemap[bridgetoifmap[mactobridge[mac]]] bridgetoifvalid = True except KeyError: continue if ifname not in maccounts: maccounts[ifname] = 1 else: maccounts[ifname] += 1 if not bridgetoifvalid: bridgetoifmap = {} # Not a single mac address resolved to an interface index, chances are # that the switch is broken, and the mactobridge is reporting ifidx # instead of bridge port index # try again, skipping the bridgetoifmap lookup for mac in mactobridge: try: ifname = ifnamemap[mactobridge[mac]] bridgetoifmap[mactobridge[mac]] = mactobridge[mac] except KeyError: continue if ifname not in maccounts: maccounts[ifname] = 1 else: maccounts[ifname] += 1 _macsbyswitch[switch] = {} for mac in mactobridge: # We want to merge it so that when a mac appears in multiple # places, it is captured. try: ifname = ifnamemap[bridgetoifmap[mactobridge[mac]]] except KeyError: continue if mac in _macmap: _macmap[mac].append((switch, ifname, maccounts[ifname])) else: _macmap[mac] = [(switch, ifname, maccounts[ifname])] if ifname in _macsbyswitch[switch]: _macsbyswitch[switch][ifname].append(mac) else: _macsbyswitch[switch][ifname] = [mac] nodename = _nodelookup(switch, ifname) if nodename is not None: if mac in _nodesbymac and _nodesbymac[mac][0] != nodename: # For example, listed on both a real edge port # and by accident a trunk port log.log({ 'error': '{0} and {1} described by ambiguous' ' switch topology values'.format(nodename, _nodesbymac[mac][0]) }) _nodesbymac[mac] = (None, None) else: _nodesbymac[mac] = (nodename, maccounts[ifname])
def _list_interfaces(switchname, configmanager): switchcreds = get_switchcreds(configmanager, (switchname,)) switchcreds = switchcreds[0] conn = snmp.Session(*switchcreds) ifnames = netutil.get_portnamemap(conn) return util.natural_sort(ifnames.values())