Skip to content

Instantly share code, notes, and snippets.

@jof
Created October 12, 2011 12:37
Show Gist options
  • Save jof/1281122 to your computer and use it in GitHub Desktop.
Save jof/1281122 to your computer and use it in GitHub Desktop.
Cisco CDPviaSNMP-to-Graphviz Creator
#!/usr/bin/env ruby
require 'getoptlong'
require 'rubygems'
require 'snmp'
SNMP_COMMUNITY = 'public'
HOSTNAME_BLACKLIST = [ "that_one_switch_thats_down_but_in_dns" ]
ZONE_FILE = /path/to/dns/zone/file
HOSTNAME_REGEX = /^\s?(switch[0-9]+)/i
$QUICK_TEST = false
opts = GetoptLong.new( ['--quick-test', '-q', GetoptLong::NO_ARGUMENT ] )
opts.each do |opt,val|
case opt
when '--quick-test'
$QUICK_TEST = true
end
end
def snmp_get(oid, host)
oid = SNMP::ObjectId.new(oid)
manager = SNMP::Manager.new(:Host => host, :Community => SNMP_COMMUNITY)
vb = manager.get(oid).varbind_list.first
return vb.value
end
def snmp_get_tree(oid, host, index_distance_from_end)
index_distance_from_end += 1
oid = SNMP::ObjectId.new(oid)
manager = SNMP::Manager.new(:Host => host, :Community => SNMP_COMMUNITY)
results = []
manager.walk(oid) do |varbind|
results << [ varbind.name, varbind.value ]
end
results.map! do |tuple|
[ tuple[0].to_s.split('.')[-index_distance_from_end], tuple[1] ]
end
result_hash = {}
results.each do |name, value|
result_hash[name.to_s] = value
end
return result_hash
end
raw_lines = open(ZONE_FILE, 'r').readlines
switch_like_records = raw_lines.select { |line| line.match(HOSTNAME_REGEX) }
switch_like_hostnames = switch_like_records.map { |record| record.match(HOSTNAME_REGEX).captures.first }
if $QUICK_TEST then
switch_like_hostnames = switch_like_hostnames[0..10]
end
HOSTNAME_BLACKLIST.each { |b| switch_like_hostnames.delete(b) }
if_mib_ifdescr = '1.3.6.1.2.1.2.2.1.2'
cdpGlobalDeviceId = '1.3.6.1.4.1.9.9.23.1.3.4.0'
cdpInterfaceEntry = '1.3.6.1.4.1.9.9.23.1.1.1.1.6'
cdpCacheVersion = '1.3.6.1.4.1.9.9.23.1.2.1.1.5'
cdpCacheDeviceId = '1.3.6.1.4.1.9.9.23.1.2.1.1.6'
cdpCacheDevicePort = '1.3.6.1.4.1.9.9.23.1.2.1.1.7'
#inter_switch_links = {}
inter_switch_links = []
switch_like_hostnames.each do |switch|
STDERR.puts "Scanning #{switch}..."
cdp_host_name = snmp_get(cdpGlobalDeviceId, switch).to_s
idb_list = snmp_get_tree(if_mib_ifdescr, switch, 0)
cdp_neighbor_switches = snmp_get_tree(cdpCacheDeviceId, switch, 1)
cdp_neighbor_ports = snmp_get_tree(cdpCacheDevicePort, switch, 1)
cdp_neighbor_software = snmp_get_tree(cdpCacheVersion, switch, 1)
links = [] # e.g. [ ["switch1", "GigabitEthernet0/1"], ["switch2", "GigabitEthernet0/1"] ]
cdp_neighbor_switches.each do |ifindex, remote_hostname|
local_port_name = idb_list[ifindex]
remote_port_name = cdp_neighbor_ports[ifindex] || Unknown
links << [ [cdp_host_name, local_port_name], [remote_hostname, remote_port_name] ]
end
inter_switch_links.concat(links)
end
# Remove cycles in the graph.
inter_switch_links.each do |side_a_one, side_b_one|
inter_switch_links.reject! { |side_a_two, side_b_two| side_a_two == side_b_one }
end
# Pretty-printer.
#inter_switch_links.each do |local, remote|
# puts "#{local[0]}:#{local[1]} --> #{remote[0]}:#{remote[1]}"
#end
# Generate a dot file.
graph_host_names = inter_switch_links.map{ |link| [ link[0][0], link[1][0] ] }.flatten.sort.uniq
puts "graph hosts {"
graph_host_names.each do |node|
puts " \"#{node}\" [label=\"#{node}\"];"
end
inter_switch_links.each do |link|
puts " \"#{link[0][0]}\" -- \"#{link[1][0]}\";"
end
puts "}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment