#71 LLDP fixes

Brian Candler

(1) Fix the logic which maps local port (lldpLocPortId/lldpLocPortDesc) to interface index.

Currently it matches only lldpLocPortDesc against ifDescr and ifAlias. However in many switches (e.g. Netgear, Dell) the PortDesc is a user-supplied comment or empty string if no comment has been set. Because SNMP::Info doesn't test for the empty-string case, and because many interfaces will have empty string for ifAlias, it returns an arbitrary interface.

The new logic looks at lldpLocPortId (if non-blank) and then lldpLocPortDesc (ditto). It matches them in turn again ifName, ifDescr and then ifAlias.

Typically ifName is the short port name like "Gi1/0/1" (Cisco) or "1/0/1" (Netgear), and for both those vendors it's the same as the value in lldpLocPortId, at least with the firmware versions I tested.

(2) Fix the logic of the returned remote port name (lldp_port)

Currently it returns lldpRemPortDesc unless the PortIdType is "interfaceName" in which case it returns lldpRemPortId.

However there are switches which set PortIdType to "local" and return the correct port name in lldpRemPortId, but lldpRemPortDesc is either a user-supplied comment or empty string.

The new logic returns lldpRemPortId if PortIdType is either "local" or "interfaceName" but is otherwise unchanged.

More details at https://sourceforge.net/p/snmp-info/mailman/snmp-info-users/thread/53ABF242.30703%40pobox.com/#msg32507476

1 Attachments


Code: 53ad88d281b24b45b0886c1d


  • Eric A. Miller
    Eric A. Miller

    Thanks for the patch and detailed troubleshooting.

    One reason for the issue you're experiencing is that the Netgear class uses i_name() for interfaces() where most other classes use i_descr(). For this reason, I'm hesitant to apply this patch to LLDP globally.

    However, you identified a bug that I believe will be fixed in the next release via this commit. This should resolve the local port mapping.

    The remote port mapping will need to be handled in the application code because there is so much variation in implementation of the LLDP standard. Your application should try and match the remote port on ifDescr, ifName, and ifAlias.

    Please let us know if the above commit resolves the local port mapping.

  • Eric A. Miller
    Eric A. Miller

    • assigned_to: Eric A. Miller
  • Brian Candler
    Brian Candler

    Thank you. Your commit will avoid the blank string lldpLocPortDesc matching an arbitrary ifAlias, so AFAICS it will default to returning the lldpRemLocalPortNum (extracted from the INDEX) as the local port number. This is not guaranteed to be the same as the OID index to the ifTable, although for Netgear it looks like it probably is.

    The problem with the remote port name remains, the one that this patch was intended to fix:

    @@ -171,7 +182,7 @@
          foreach my $key ( sort keys %$pid ) {
              my $port = $pdesc->{$key};
              my $type = $ptype->{$key};
    -        if ( $type and $type eq 'interfaceName' ) {
    +        if ( $type and ($type eq 'interfaceName' or $type eq 'local') ) {
                  # If the pid claims to be an interface name,
                  # believe it.
                  $port = $pid->{$key};

    That is: when the remote device is a Netgear, the lldpRemPortDesc contains the user-defined ifAlias (which could be either empty string or arbitrary content), so you really want to see the lldpRemPortId instead.

    Unfortunately the class of the local SNMP::Info is irrelevant here, because for example you could be querying a Dell switch which has a connection to a Netgear.


    (a) Probably the reason the Netgear class uses ifName as the interface name is because the ifDescr is far too verbose:

    IF-MIB::ifDescr.1 = STRING: Unit: 1 Slot: 0 Port: 1 10G - Level
    IF-MIB::ifName.1 = STRING: 1/0/1

    (b) Digging through the LLDP-MIB, it does seem that Netgear is wrong according to the spec:

    lldpLocPortDesc OBJECT-TYPE
        SYNTAX          SnmpAdminString (SIZE  (0..255))
        MAX-ACCESS      read-only
        STATUS          current
            "The string value used to identify the 802 LAN station's port
            description associated with the local system.  If the local
            agent supports IETF RFC 2863, lldpLocPortDesc object should
            have the same value of ifDescr object."

    (c) For Cisco and Dell the lldpLocPortDesc does match the ifDescr; the Netgear doesn't.

    [Cisco 1901]
    iso.0.8802. = STRING: "GigabitEthernet0/0/0"
    IF-MIB::ifDescr.1 = STRING: GigabitEthernet0/0/0
    [Netgear XSM7224S]
    iso.0.8802. = ""
    IF-MIB::ifDescr.1 = STRING: Unit: 1 Slot: 0 Port: 1 Gigabit - Level
    [Dell 5524]
    iso.0.8802. = STRING: "gigabitethernet1/0/1"
    IF-MIB::ifDescr.1 = STRING: gigabitethernet1/0/1

    (d) However in all the devices I've tried, the lldpLocPortId does match the ifName:

    [Cisco 1901]
    iso.0.8802. = STRING: "Gi0/0/0"
    IF-MIB::ifName.1 = STRING: Gi0/0/0
    [Netgear XSM7224S]
    iso.0.8802. = STRING: "1/0/1"
    IF-MIB::ifName.1 = STRING: 1/0/1
    [Dell 5524]
    iso.0.8802. = STRING: "gi1/0/1"
    IF-MIB::ifName.1 = STRING: gi1/0/1

    So it seems to me reasonable to try matching lldpLocPortId against ifName. Given point (b) above then arguably this should only be a fallback if the lldpLocPortDesc doesn't match ifDescr.

    (e) Aside: the way RFC 2863 defines ifDescr is stupid and rightly ignored by everyone.

    ifDescr OBJECT-TYPE
        SYNTAX      DisplayString (SIZE (0..255))
        MAX-ACCESS  read-only
        STATUS      current
                "A textual string containing information about the
                interface.  This string should include the name of the
                manufacturer, the product name and the version of the
                interface hardware/software."