Skip to content

Instantly share code, notes, and snippets.

@jeremyschulman
Last active December 11, 2015 05:08
Show Gist options
  • Save jeremyschulman/4549891 to your computer and use it in GitHub Desktop.
Save jeremyschulman/4549891 to your computer and use it in GitHub Desktop.
A simple example tracking down a routing path through a BGP/MPLS/LDP Junos network.
require 'highline/import'
require 'net/netconf/jnpr'
target = ARGV[0] || begin
puts "You must specify a starting target device"
exit 1
end
dst_route = ARGV[1] || begin
puts "You need to specify a destination route"
exit 1
end
my_username = ENV["USER"]
puts "login: #{my_username}"
my_password = ask("password: "){|a| a.echo = false}
module ScannerLDP
def get_lldp_nei( ifd_name )
ifd_name.gsub!(/\.\d+/, '') # drop the IFL
rsp = @rpc.command "show lldp neighbors interface #{ifd_name}"
if_nei = rsp.xpath('lldp-neighbor-information')
rmt_sysname = if_nei.xpath('lldp-remote-system-name').text
rmt_ip = if_nei.xpath('lldp-remote-management-address').text
{ :rmtsys => rmt_sysname, :rmtip => rmt_ip }
end
def get_lacp_ifds( ae_name )
ae_name.gsub!(/\.\d+/, '') # drop the IFL
rsp = @rpc.get_lacp_interface_information( :interface_name => ae_name )
rsp.xpath('//lag-lacp-protocol/name').collect{|i| i.text}
end
def nh_proc( nh )
nh_table = nh.xpath('nh-table').text
nh_mpls = nh.xpath('mpls-label').text
rdat = {}
rdat[:protocol] = nh.xpath('../protocol-name').text
rdat[:nh] = nh.xpath('to').text
rdat[:via] = nh.xpath('via').text
rdat[:table] = nh_table unless nh_table.empty?
rdat[:mpls] = nh_mpls unless nh_mpls.empty?
rdat
end
def get_active_route( opts )
rpc_args = {}
rpc_args[:destination] = opts[:dest]
rpc_args[:active_path] = true
rpc_args[:table] = opts[:table] if opts[:table]
as_txt = (opts[:as_txt]) ? { :format => 'text' } : nil
rsp = @rpc.get_route_information( rpc_args, as_txt )
if as_txt
rsp.text
else
nh = rsp.xpath('//nh[selected-next-hop]')[0] || rsp.xpath('//nh')[0]
nh_proc( nh )
end
end
def get_mpls_route( label )
rsp = @rpc.get_route_information( :table => 'mpls', :label => label )
nh = rsp.xpath('//nh')[0]
nh_proc( nh )
end
def get_next_rtr( nhop )
ifd_name = nhop[:via]
if ifd_name.match /ae\d/
ifd_name = get_lacp_ifds( ifd_name )[0]
end
lldp_nei = get_lldp_nei( ifd_name )
end
end
def mpls_stack_proc( mpls_stack, mpls_txt_acts )
mpls_txt_acts.scan(/(\w+)\s?(\d+)?,?/).each do |action|
case action[0]
when "Push"
mpls_stack.unshift action[1]
when "Pop"
mpls_stack.shift
when "Swap"
mpls_stack[0] = action[1]
end
end
mpls_stack
end
login = { :username => my_username, :password => my_password }
login[:target] = target
mpls_stack = []
done = false
until done
puts "\nLOGGING INTO: #{target} ..."
dev = Netconf::SSH.new( login )
dev.extend ScannerLDP
dev.open
if mpls_stack.empty?
nhop = dev.get_active_route( :table => 'wireless', :dest => dst_route )
else
nhop = dev.get_mpls_route( mpls_stack[0] )
end
if nhop[:mpls]
mpls_stack_proc( mpls_stack, nhop[:mpls] )
end
if mpls_stack.empty?
puts "MPLS stack is empty, we're at the end ..."
nhop = dev.get_active_route( :table => nhop[:table], :dest => dst_route, :as_txt => true )
puts nhop
puts "\nDONE!"
done = true
else
puts "MPLS stack is now: " + mpls_stack.join(",")
next_rtr = dev.get_next_rtr( nhop )
login[:target] = next_rtr[:rmtip]
target = next_rtr[:rmtsys]
end
dev.close
end
$ ruby trace-route-ldp.rb mx240-176 192.168.199.0
login: jschulman
password:
LOGGING INTO: mx240-176 ...
MPLS stack is now: 300896,18
LOGGING INTO: MX480-R244 ...
MPLS stack is now: 301088,18
LOGGING INTO: MX240-R178 ...
MPLS stack is now: 18
LOGGING INTO: MX240-R130-re0 ...
MPLS stack is empty, we're at the end ...
wireless.inet.0: 13 destinations, 26 routes (13 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.199.0/24 *[OSPF/10] 20:38:57, metric 2
> to 10.0.0.33 via xe-2/1/2.110
DONE!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment