Skip to content

Switch based discovery fails to find any nodes on Cisco switches due to (by default) per-VLAN SNMP contexts #224

Description

@LHurst-OCF

In _snmp_map_switch (confluent_server/confluent/networking/macmap.py), the mac walk is only done on the initial connection. On CISCO switches, mac information is returned per-context so the initial list will only see the default context.

There seems to be some comments about this problem in the code:

 # 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

Specifically, these loops are done once with the original connection (default context), which finds nothing on a Cisco switch where nodes are not visible in the default context (typically VLAN 1):

    async 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:
        async 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)

Moving this inside the VLAN loop (which is run through at least once on all switches, by virtue of adding None to the VLANS and only Cisco switches with VLANs loop and get new connections created per VLAN context should correct this problem (note that the new connections are created without privacy_policy passed through, which I think is also an oversight?).

As there are some CISCO configurations where the macs may be returned by the default context too (I'm not sure if ONLY by the default context or as well as VLAN), I also propose changing if not vlanstocheck: vlanstocheck.add(None) to for vlan in (None, *vlanstocheck): so the initial (default) context is looped over unconditionally (on CISCO and non-CISCO) which will retain current code path in all cases but also add the per-VLAN MAC walking required for (at least some) CISCO switch configurations.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions