Skip to main content

Cisco IOS Discovery

The Infracast Cisco IOS plugin discovers network devices by SSHing into seed devices and walking the network using CDP (Cisco Discovery Protocol) and LLDP (Link Layer Discovery Protocol) neighbor tables. Starting from one or more known devices, Infracast recursively discovers adjacent devices until the full network topology is mapped.

How Neighbor Walking Works

Seed Device (10.0.0.1)

├─ CDP neighbor: switch-core-01 (10.0.1.1) ──► connect & enumerate
│ │
│ ├─ CDP neighbor: switch-access-01 (10.0.2.1) ──► connect & enumerate
│ ├─ CDP neighbor: switch-access-02 (10.0.2.2) ──► connect & enumerate
│ └─ LLDP neighbor: ap-floor3 (10.0.3.1) ──► connect & enumerate

└─ CDP neighbor: router-wan-01 (10.1.0.1) ──► connect & enumerate

Infracast tracks which devices it has already visited to avoid loops. The walk terminates when:

  • No new neighbors are discovered
  • The configured max_depth is reached
  • A device matches an exclude_pattern (e.g., skip WAN devices by prefix)
info

CDP and LLDP must be enabled on devices for neighbor walking to work. Most Cisco IOS devices have CDP enabled by default. LLDP is often disabled by default on IOS but enabled on IOS-XE and NX-OS.

SSH Credential Setup

Infracast connects to devices using SSH with username/password or username/SSH key authentication.

Option 1: Username + Password

infracast creds add \
--plugin cisco-ios \
--name "network-ssh-creds" \
--type ssh-password \
--username "infracast" \
--password-file /run/secrets/cisco-ssh-password

Option 2: SSH Key

# Generate a dedicated SSH key for Infracast
ssh-keygen -t ed25519 -f /run/secrets/infracast-cisco-key -C "infracast-discovery" -N ""

infracast creds add \
--plugin cisco-ios \
--name "network-ssh-key" \
--type ssh-key \
--username "infracast" \
--private-key-file /run/secrets/infracast-cisco-key

Configuring the Read-Only User on Cisco IOS

Create a dedicated read-only user for Infracast. Connect to the device and run:

! Create local user with privilege level 1 (read-only)
username infracast privilege 1 secret 0 YourSecurePassword

! Allow SSH access (if not already enabled)
ip ssh version 2
ip ssh time-out 60
ip ssh authentication-retries 3

! Restrict to VTY lines
line vty 0 4
login local
transport input ssh
exec-timeout 5 0

! Optional: restrict by source IP (highly recommended)
ip access-list standard INFRACAST-MGMT
permit 10.0.100.50 ! Infracast collector IP
deny any log
!
line vty 0 4
access-class INFRACAST-MGMT in
tip

Use privilege level 1 (unprivileged) for Infracast. All show commands used for discovery work at privilege level 1. Infracast never needs enable or configuration mode access.

Enabling CDP and LLDP

! Enable CDP globally (usually on by default)
cdp run

! Enable LLDP globally (IOS-XE, recommended)
lldp run

! Verify
show cdp neighbors detail
show lldp neighbors detail

Configuring the Discovery Job

infracast.yaml
discovery:
jobs:
- name: cisco-network
plugin: cisco-ios
credential: network-ssh-key
schedule: "0 2 * * *" # nightly at 2 AM UTC
config:
# Seed devices — discovery starts here
seed_ips:
- "10.0.0.1" # core router
- "10.0.1.1" # core switch (backup seed)

# SSH connection settings
ssh_port: 22
ssh_timeout_seconds: 30
ssh_known_hosts_check: false # set true in production with a known_hosts file

# Neighbor walk settings
walk_cdp: true
walk_lldp: true
max_depth: 10 # maximum hops from seed

# Scope control
include_subnets:
- "10.0.0.0/8" # only walk devices in these subnets
exclude_patterns:
- "^.*-WAN-.*" # skip WAN-facing devices by hostname
- "^ISP-.*"
exclude_ips:
- "192.168.1.1" # skip specific IPs

# What to collect from each device
collect:
interfaces: true
vlans: true
routes: true
acls: true
arp_table: true
mac_table: true
spanning_tree: true
ospf: true
bgp: false # set true if BGP is in use

What Gets Discovered

For each discovered device, Infracast collects:

CategoryData Collected
Device IdentityHostname, model, serial number, IOS version, uptime
InterfacesName, IP/mask, state (up/down), duplex, speed, input/output errors, description
VLANsVLAN ID, name, state, associated interfaces, trunk/access mode
RoutesDestination, next-hop, protocol (static/OSPF/BGP/connected), metric, interface
ACLsACL name, type (standard/extended), rules (source/dest/port/action), interface bindings
ARP TableIP-to-MAC mappings with interface and VLAN
MAC TableMAC-to-port mappings (CAM table)
CDP NeighborsConnected device hostname, IP, port, platform
LLDP NeighborsConnected device hostname, IP, port, system description
Spanning TreeRoot bridge, port states (forwarding/blocking), bridge priority
OSPFRouter ID, areas, neighbor adjacencies, LSA summary
BGPAS number, neighbor sessions, prefixes advertised/received (if enabled)
NTPConfigured NTP servers, sync status
SNMPCommunity strings existence (not values), contact, location

Troubleshooting

SSH connection refused

Symptom: Error: dial tcp 10.0.0.1:22: connect: connection refused

Checks:

  1. Verify SSH is enabled: show ip ssh
  2. Verify VTY lines accept SSH: show run | section line vty
  3. Check access-class restrictions — ensure the Infracast collector IP is permitted
  4. Verify no firewall is blocking TCP/22 between the collector and the device
# Test SSH manually from the collector host
ssh -o StrictHostKeyChecking=no infracast@10.0.0.1 "show version"

Authentication failure

Symptom: Error: ssh: handshake failed: ssh: unable to authenticate

Checks:

  1. Verify username and password/key are correct
  2. Check AAA configuration — if TACACS+/RADIUS is in use, verify the Infracast user exists there
  3. Try password authentication if key auth fails:
! On device: check local auth is allowed as fallback
aaa authentication login default group tacacs+ local

% Invalid input detected on show commands

Symptom: Some data is missing; logs show command parse errors

Cause: IOS version differences. Some show commands have different syntax across IOS versions.

Fix: Specify the IOS version in the job config to use compatible command syntax:

config:
ios_version_hint: "15.2" # or "16.x", "17.x", "xe-16.x"

Discovery stops too early (max_depth hit)

Symptom: Only part of the network is discovered; logs show max depth reached

Fix: Increase max_depth (default is 10):

config:
max_depth: 20

Or add additional seed IPs in different network segments to reduce traversal depth:

config:
seed_ips:
- "10.0.0.1" # DC core
- "10.1.0.1" # Branch core
- "10.2.0.1" # Campus core

Devices behind NAT not reachable

Symptom: CDP shows a neighbor but Infracast can't connect to it

Cause: CDP advertises the device's management IP, which may be a private address unreachable from the collector.

Fix: Use ip_override_map to map CDP-reported IPs to reachable addresses:

config:
ip_override_map:
"192.168.1.1": "10.100.0.1" # CDP reports 192.168.1.1, actually reach at 10.100.0.1

CDP/LLDP neighbor walking loops

Symptom: Discovery runs longer than expected; logs show the same device being visited repeatedly

Cause: This should not happen as Infracast tracks visited devices, but can occur if a device reports multiple IPs and is reached via different addresses.

Fix: Check the duplicate_detection setting:

config:
duplicate_detection: by-hostname # or 'by-ip' (default)