Skip to main content

File this under “ya I’ll never do that again”.  We’ve all had at least one “oops” that sticks with us.

How does one find Cisco Switches or Routers that just happen to have the same Hostname or the same Management IP Address reported in LLDP and / or CDP?  What if those alleged Cisco device just happen to have the same configuration except for the out of band management address?  Accidentally of course.  

Well, this happened during a rapid stand up of two new Cisco routers.  (Not me, of course.  I learned this lesson many moons ago).   To speed up the deployment, a copy / paste of config from one Router to two others occurred.  Oh, yes, some nasty stuff happened after this.  But that’s not pertinent to the resolution.

NQE to the rescue.  Since the Management IP addresses were “forgotten” or unknown to those troubleshooting the issue, how does one find these near identical twins?  Remember that CDP announces Serial Numbers.  LLDP typically does not advertise the device’s Serial Number.  Thus, let’s find as quickly as possible all of the CDP neighbors as known by every device in the network that Forward Networks knows about.  Then stare and compare (in this version) to see if there are any duplicate Hostnames and / or IP addresses.

CDP typically advertises the device Serial Number.  LLDP typically does not. 
 

There are notes for future development in case you’re up to the task.  

As anticipated, the CDP advertisements are not consistent across models.  Thus, let’s use the lowest common denominator in the pattern match.  
 

/**
* @intent List the Serial Number / Processor Board ID for all Cisco Operating Systems and determine if the SN is in the Inventory.
*/

/* ********* FOLLOW UP *********
- Parse the various Cisco versions with unique pattern matches to find the links and management IP address.
- Determine if there are CDP Neighbors with different SNs but the same management IP address and / or hostname.
- Combine with Uncollected CDP and LLDP neighbor NQE to show interfaces in a group.
*/
//
/* EXAMPLE - "show cdp neighbor detail" output.
----------------------------------------
Device ID:CISCOROUTER1(FOX9999999)
System Name: USTXALLPN0300

Interface address(es): 1
IPv4 Address: 10.10.10.10
Platform: N9K-C9504, Capabilities: Router Switch IGMP Filtering Supports-STP-Dispute
Interface: Ethernet1/1, Port ID (outgoing port): Ethernet1/1
*/

// The "Device" pattern is consistent across Cisco operating systems. However the remaining output is not.
// Note that in some cases the Serial number is not enumerated.
pattern_CDP =
```
----------------------------------------
Device {deviceID1:string}
```;

deviceNames =
foreach device in network.devices
select device.name;

ciscoInventory =
foreach device in network.devices
where device.platform.vendor == Vendor.CISCO
let outputs = device.outputs
foreach command in outputs.commands
select { deviceName: device.name, commandType: command.commandType }
;

inventory =
foreach device in network.devices
let platform = device.platform
foreach component in platform.components
select component.serialNumber
/* {
// deviceName: device.name,
// componentName: component.name,
// partId: component.partId,
// serialNumber: component.serialNumber,
// partType: component.partType
} */
;

foreach device in network.devices
foreach command in device.outputs.commands
where device.platform.vendor == Vendor.CISCO
let outputs = device.outputs
// Only Cisco is authorized CDP. Therefore the platform.vendor type of Vendor.CISCO is not required to be filtered upon.
where command.commandType == CommandType.CDP
// OS type check is a placeholder for future IOS, NXOS, IOS_XR, IOS_XE, ASA, and FXOS individual blockMatches() that will enumerate the CDP Neighbor's output.
let os = device.platform.os
let configurations = parseConfigBlocks(os, command.response)
foreach cdp_output in blockMatches(configurations, pattern_CDP)
// Parse out the CDP Neighbors hostname. Account for when the Serial Number is not present in the list.
let cdpNeighborID = replace(cdp_output.data.deviceID1, "ID:", "")
let cdpNeighborID = replace(cdpNeighborID, "(", " ")
let cdpNeighborID = replace(cdpNeighborID, ")", "")
let cdpNeighborIDName = patternMatch(cdpNeighborID, `{first:string}`)
let cdpNeighborIDSN = patternMatch(cdpNeighborID, `{first:string} {second:string}`)
let cdpNeighborSN = if !isPresent(cdpNeighborIDSN) then cdpNeighborIDName.first + " - SN Empty" else cdpNeighborIDSN.second

select distinct {
// Note that the violation checks only whether the CDP Neighbor's Hostname is in the list of Modeled Device / Sources and not whether the Serial Number matches.
"Device Name Not Modeled": cdpNeighborIDName.first not in deviceNames,
"Local Device Name": device.name,
Location: device.locationName,
"CDP Neighbor Name":cdpNeighborIDName.first,
"CDP Neighbor SN": cdpNeighborSN,
check: cdpNeighborSN not in inventory
}


CDP can sometimes be your friend.  In this case, it saved the day along with a little ingenuity in an NQE script.  

After the duplicates were found, triangulated by filtering on the offending device’s unique serial number, the connection of the out of band management interface was identified.  

Be the first to reply!

Reply