mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
Quagga: add some ospfv3 diagnostics calls to quagga.rb (#149)
* quagga: add some ospfv3 diagnostics * Quagga (OSPFv3): Add database support * Quagga: add more backend calls for OSPFv3 * Quagga: integrate into controller and configd
This commit is contained in:
+28
@@ -64,6 +64,12 @@ class DiagnosticsController extends ApiControllerBase
|
||||
$backend = new Backend();
|
||||
return array("response" => json_decode(trim($backend->configdRun("quagga ospf-$name"))));
|
||||
}
|
||||
private function get_ospf3_information($name)
|
||||
{
|
||||
$backend = new Backend();
|
||||
return array("response" => json_decode(trim($backend->configdRun("quagga ospfv3-$name"))));
|
||||
}
|
||||
// OSPFv2
|
||||
public function ospfoverviewAction()
|
||||
{
|
||||
return $this->get_ospf_information('overview');
|
||||
@@ -84,6 +90,28 @@ class DiagnosticsController extends ApiControllerBase
|
||||
{
|
||||
return $this->get_ospf_information('interface');
|
||||
}
|
||||
// OSPFv3
|
||||
public function ospfv3overviewAction()
|
||||
{
|
||||
return $this->get_ospf3_information('overview');
|
||||
}
|
||||
public function ospfv3neighborAction()
|
||||
{
|
||||
return $this->get_ospf3_information('neighbor');
|
||||
}
|
||||
public function ospfv3routeAction()
|
||||
{
|
||||
return $this->get_ospf3_information('route');
|
||||
}
|
||||
public function ospfv3databaseAction()
|
||||
{
|
||||
return $this->get_ospf3_information('database');
|
||||
}
|
||||
public function ospfv3interfaceAction()
|
||||
{
|
||||
return $this->get_ospf3_information('interface');
|
||||
}
|
||||
// General
|
||||
private function get_general_information($name)
|
||||
{
|
||||
$backend = new Backend();
|
||||
|
||||
@@ -21,9 +21,13 @@ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
=end
|
||||
|
||||
require 'json'
|
||||
require 'shellwords'
|
||||
require 'pp'
|
||||
|
||||
$QUAGGA_DEBUG = false
|
||||
|
||||
class VTYSH
|
||||
def initialize(path = '/usr/local/bin/vtysh')
|
||||
@path = path
|
||||
@@ -189,6 +193,7 @@ class OSPF
|
||||
# make sure there is an array to write in
|
||||
current_if[:unparsed] ||= []
|
||||
current_if[:unparsed] << line
|
||||
puts line if $QUAGGA_DEBUG
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -229,7 +234,7 @@ class OSPF
|
||||
db[router]['external_states'] ||= []
|
||||
qta = nil
|
||||
else
|
||||
$stderr.puts "unknown heading"
|
||||
puts "unknown heading" if $QUAGGA_DEBUG
|
||||
end
|
||||
else
|
||||
if qta == nil
|
||||
@@ -286,7 +291,7 @@ class OSPF
|
||||
last_line = {ip: $1, cost: $2.to_i, area: $3, asbr: (", ASBR" == $4), type: 'R'}
|
||||
route[heading] << last_line
|
||||
else
|
||||
#puts line
|
||||
puts line if $QUAGGA_DEBUG
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -328,8 +333,7 @@ class OSPF
|
||||
when ""
|
||||
break
|
||||
else
|
||||
# debug
|
||||
#puts line
|
||||
puts line if $QUAGGA_DEBUG
|
||||
end
|
||||
end
|
||||
# general overview has ended - now the area overviews come
|
||||
@@ -358,7 +362,7 @@ class OSPF
|
||||
when "Area has no authentication"
|
||||
current_area[:auth] = "none"
|
||||
else
|
||||
#puts line
|
||||
puts line if $QUAGGA_DEBUG
|
||||
end
|
||||
end
|
||||
overview
|
||||
@@ -420,12 +424,230 @@ class BGP
|
||||
end
|
||||
end
|
||||
|
||||
class OSPFv3
|
||||
def initialize(sh)
|
||||
@vtysh = sh
|
||||
end
|
||||
|
||||
def overview
|
||||
lines = @vtysh.execute("show ipv6 ospf6").lines
|
||||
overview = {}
|
||||
while line = lines.shift&.strip
|
||||
case line
|
||||
when /OSPFv3 Routing Process \((\d+)\) with Router-ID ([\d\.]+)/
|
||||
overview[:router_id] = $2
|
||||
overview[:routing_process] = $1.to_i
|
||||
when /Initial SPF scheduling delay (\d+) millisec\(s\)/
|
||||
overview[:initial_spf_scheduling_delay] = $1.to_i
|
||||
# this line contains a typo in the output - I made it to work with and without
|
||||
# this typo
|
||||
when /(Min|Max)imum hold time between consecutive SPFs (\d+) milli?second\(s\)/
|
||||
overview[:hold_time] ||= {}
|
||||
overview[:hold_time][$1.downcase] = $2.to_i
|
||||
when "This router is an ASBR (injecting external routing information)"
|
||||
overview[:asbr] = true
|
||||
when /SPF timer is (.*)/
|
||||
overview[:spf_timer] = $1
|
||||
when /Running (.*)/
|
||||
overview[:running_time] = $1
|
||||
when /Number of AS scoped LSAs is (\d+)/
|
||||
overview[:number_as_scoped] = $1.to_i
|
||||
when /Hold time multiplier is currently (\d+)/
|
||||
overview[:current_hold_time_multipier] = $1.to_i
|
||||
when /Number of areas in this router is (\d+)/
|
||||
overview[:number_of_areas] = $1.to_i
|
||||
when ""
|
||||
break
|
||||
else
|
||||
# debug
|
||||
puts line if $QUAGGA_DEBUG
|
||||
end
|
||||
end
|
||||
# general overview has ended - now the area overviews come
|
||||
overview[:areas] = {}
|
||||
current_area = {}
|
||||
while line = lines.shift&.strip
|
||||
case line
|
||||
when /^Area ([\d\.]*)/
|
||||
current_area = {}
|
||||
overview[:areas][$1] = current_area
|
||||
when /Interface attached to this area: (.*)/
|
||||
current_area[:interfaces] = $1.split(" ")
|
||||
when /Number of Area scoped LSAs is (.*)/
|
||||
current_area[:number_lsas] = $1.to_i
|
||||
else
|
||||
puts line if $QUAGGA_DEBUG
|
||||
end
|
||||
end
|
||||
overview
|
||||
end
|
||||
|
||||
def linkstate
|
||||
lines = @vtysh.execute("show ipv6 ospf6 linkstate").lines
|
||||
linkstate = {}
|
||||
|
||||
qta = nil
|
||||
current_area = []
|
||||
while line = lines.shift&.strip
|
||||
case line
|
||||
when /SPF Result in Area (.*)/
|
||||
linkstate[$1] = current_area = []
|
||||
qta = QuaggaTableReader.new(["Type","Router-ID", "Net-ID", "Rtr-Bits", "Options", "Cost"])
|
||||
lines.shift
|
||||
qta.read_headline(lines.shift)
|
||||
else
|
||||
if line.length > 10
|
||||
current_area << qta.read_entry(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
linkstate
|
||||
end
|
||||
|
||||
def route
|
||||
route = []
|
||||
lines = @vtysh.execute("show ipv6 ospf6 route").lines
|
||||
|
||||
lines.each do |line|
|
||||
f1, f2, network, gateway, interface, time = line.strip.split(/\s+/)
|
||||
route << { f1: f1,
|
||||
f2: f2,
|
||||
network: network,
|
||||
gateway: gateway,
|
||||
interface: interface,
|
||||
time: time }
|
||||
end
|
||||
route
|
||||
end
|
||||
|
||||
def neighbor
|
||||
qta = QuaggaTableReader.new(["Neighbor ID","Pri", "DeadTime", "State/IfState", "Duration I/F[State]"])
|
||||
neighbor = []
|
||||
nb = @vtysh.execute("show ipv6 ospf6 neighbor").lines
|
||||
qta.read_headline(nb.shift.strip)
|
||||
while line = nb.shift&.strip
|
||||
puts line
|
||||
if line.length > 10
|
||||
tmp = qta.read_entry(line)
|
||||
tmp['Pri'] = tmp['Pri'].to_i
|
||||
neighbor << tmp
|
||||
end
|
||||
end
|
||||
neighbor
|
||||
end
|
||||
def database
|
||||
lines = @vtysh.execute("show ipv6 ospf6 database").lines
|
||||
database = {}
|
||||
mode = :none
|
||||
area = ''
|
||||
qta = :none
|
||||
while line = lines.shift&.strip
|
||||
case line
|
||||
when /Area Scoped Link State Database \(Area (.*)\)/
|
||||
mode = :scoped_link_db
|
||||
database[:scoped_link_db] ||= {}
|
||||
database[:scoped_link_db][$1] = area = []
|
||||
qta = database_qta(lines)
|
||||
when /I\/F Scoped Link State Database \(I\/F (\S+) in Area (.*)\)/
|
||||
mode = :if_scoped_link_state
|
||||
database[:if_scoped_link_state] ||= {}
|
||||
database[:if_scoped_link_state][$1] ||= {}
|
||||
area = database[:if_scoped_link_state][$1][$2] ||= []
|
||||
qta= database_qta(lines)
|
||||
when "AS Scoped Link State Database"
|
||||
mode = :as_scoped
|
||||
area = database[:as_scoped] ||= []
|
||||
qta=database_qta(lines)
|
||||
# note: i have no data for this but i think it looks like the others
|
||||
else
|
||||
if line.length > 10
|
||||
area << qta.read_entry(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
database
|
||||
end
|
||||
|
||||
def interface
|
||||
lines = @vtysh.execute("show ipv6 ospf6 interface").lines
|
||||
int = {}
|
||||
current_if = {}
|
||||
while line = lines.shift
|
||||
if line.length > 5
|
||||
case line.strip
|
||||
when /(\S+) is (down|up), type ([A-Z]+)/
|
||||
current_if = int[$1] = {up: ($2 == "up" ? true : false),
|
||||
type: $3,
|
||||
enabled: true}
|
||||
when /Interface ID: (\d+)/
|
||||
current_if[:id] = $1.to_i
|
||||
when /OSPF not enabled on this interface/
|
||||
current_if[:enabled] = false
|
||||
when /Instance ID (\d+), Interface MTU (\d+) \(autodetect: (\d+)\)/
|
||||
current_if[:instance_id] = $1.to_i
|
||||
current_if[:interface_mtu] = $2.to_i
|
||||
current_if[:interface_mtu_autodetect] = $3.to_i
|
||||
when "Internet Address:"
|
||||
# ignore
|
||||
when /(inet |inet6): (\S+)/
|
||||
current_if[:IPv6] ||= []
|
||||
current_if[:IPv4] ||= []
|
||||
family = $1 == 'inet6' ? :IPv6 : :IPv4
|
||||
address = $2
|
||||
current_if[family] << address
|
||||
when /MTU mismatch detection: (en|dis)abled/
|
||||
current_if[:mtu_mismatch_detection] = $1 == 'en'
|
||||
when /DR: (\S+) BDR: (\S+)/
|
||||
current_if[:designated_router] = $1
|
||||
current_if[:backup_designated_router] = $2
|
||||
when /State (\S+), Transmit Delay (\d+) sec, Priority (\d+)/
|
||||
current_if[:state] = $1
|
||||
current_if[:transmit_delay] = $2.to_i
|
||||
current_if[:priority] = $3.to_i
|
||||
when /Number of I\/F scoped LSAs is (\d+)/
|
||||
current_if[:number_if_scoped_lsas] = $1.to_i
|
||||
when /(\d+) Pending LSAs for (\S+) in Time ([\d:]+)(?: (.*))/
|
||||
current_if[:pending_lsas] ||= {}
|
||||
current_if[:pending_lsas][$2] = {time: $3,
|
||||
count: $1,
|
||||
flags: $4}
|
||||
when "Timer intervals configured:"
|
||||
# ignore
|
||||
when /Hello (\d+), Dead (\d+), Retransmit (\d+)/
|
||||
current_if[:timers] = {hello: $1.to_i,
|
||||
dead: $2.to_i,
|
||||
retransmit: $3.to_i }
|
||||
when /Area ID (\S+), Cost (\d+)/
|
||||
current_if[:area_cost] ||= []
|
||||
current_if[:area_cost] << {area: $1, cost: $2.to_i }
|
||||
else
|
||||
puts line if $QUAGGA_DEBUG
|
||||
end
|
||||
end
|
||||
end
|
||||
int
|
||||
end
|
||||
|
||||
private
|
||||
def database_qta(lines)
|
||||
# DON'T REMOVE THE SPACES!!!
|
||||
# For some reasons the fields are right aligned with the fields which makes it hard
|
||||
# to parse. I don't know a better way to get the correct offset except automatically.
|
||||
# (Detection of semantic of the fields)
|
||||
qta = QuaggaTableReader.new(["Type", "LSId", "AdvRouter", " Age", " SeqNum"," Payload"])
|
||||
lines.shift
|
||||
qta.read_headline(lines.shift)
|
||||
qta
|
||||
end
|
||||
end
|
||||
|
||||
require 'optparse'
|
||||
options = {}
|
||||
supported_sections = %w{general ospf}
|
||||
OptionParser.new do |opts|
|
||||
opts.banner = "Usage: #{__FILE__} -s section [section specific params]"
|
||||
opts.on("-d", "--ospf-database") do |od|
|
||||
#### OSPFv2
|
||||
opts.on("-d", "--ospf-database", "Prints the OSPF Database") do |od|
|
||||
options[:ospf_database] = od
|
||||
end
|
||||
opts.on("-r", "--ospf-route", 'print OSPF routing table') do |od|
|
||||
@@ -440,15 +662,37 @@ OptionParser.new do |opts|
|
||||
opts.on("-o", "--ospf-overview", "Print OSPF summary") do |od|
|
||||
options[:ospf_overview] = od
|
||||
end
|
||||
#### OSPFv3
|
||||
opts.on("-D", "--ospfv3-database", "Prints the OSPFv3 Database") do |od|
|
||||
options[:ospfv3_database] = od
|
||||
end
|
||||
opts.on("-t", "--ospfv3-route", 'print OSPFv3 routing table') do |od|
|
||||
options[:ospfv3_route] = od
|
||||
end
|
||||
opts.on("-I", "--ospfv3-interface", 'print OSPFv3 interface information') do |od|
|
||||
options[:ospfv3_interface] = od
|
||||
end
|
||||
opts.on("-N", "--ospfv3-neighbor", 'Print OSPFv3 neighbors') do |od|
|
||||
options[:ospfv3_neighbors] = od
|
||||
end
|
||||
opts.on("-O", "--ospfv3-overview", "Print OSPFv3 summary") do |od|
|
||||
options[:ospfv3_overview] = od
|
||||
end
|
||||
#### general things about routing
|
||||
opts.on("-R", "--general-routes", "Print Routing Table") do |od|
|
||||
options[:general_routes] = od
|
||||
end
|
||||
### BGP
|
||||
opts.on("-B", "--bgp-overview", "Print an overview of BGP") do |od|
|
||||
options[:bgp_overview] = od
|
||||
end
|
||||
### program opts
|
||||
opts.on("-H", "--human-readable", "Print the output human readable (not json)") do |od|
|
||||
options[:human_readable] = od
|
||||
end
|
||||
opts.on("-X", "--debug", "Prints debug output") do |od|
|
||||
$QUAGGA_DEBUG = true
|
||||
end
|
||||
opts.on("-h", "--help", "Prints this help") do
|
||||
puts opts
|
||||
exit
|
||||
@@ -457,6 +701,7 @@ end.parse!
|
||||
# use the lib
|
||||
sh = VTYSH.new
|
||||
ospf = OSPF.new sh
|
||||
ospfv3 = OSPFv3.new sh
|
||||
bgp = BGP.new sh
|
||||
general = General.new sh
|
||||
|
||||
@@ -465,9 +710,12 @@ options.keys.each do |k|
|
||||
# if it is true
|
||||
if options[k]
|
||||
begin
|
||||
if k.to_s.include? 'ospf'
|
||||
if k.to_s.include? 'ospf_'
|
||||
cmd = k.to_s.split('_').last
|
||||
result[k] = ospf.send(cmd)
|
||||
elsif k.to_s.include? 'ospfv3'
|
||||
cmd = k.to_s.split('_').last
|
||||
result[k] = ospfv3.send(cmd)
|
||||
elsif k.to_s.include? 'general'
|
||||
cmd = k.to_s.split('_').last
|
||||
result[k] = general.send(cmd)
|
||||
@@ -477,7 +725,7 @@ options.keys.each do |k|
|
||||
end
|
||||
rescue # do nothing on an error
|
||||
result[k] = "error"
|
||||
#puts $!
|
||||
puts $! if $QUAGGA_DEBUG
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -70,6 +70,36 @@ parameters:
|
||||
type:script_output
|
||||
message: Print OSPF summary
|
||||
|
||||
[ospfv3-database]
|
||||
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-database
|
||||
parameters:
|
||||
type:script_output
|
||||
message: Shows the OSPF database
|
||||
|
||||
[ospfv3-route]
|
||||
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-route
|
||||
parameters:
|
||||
type:script_output
|
||||
message: print OSPF routing table
|
||||
|
||||
[ospfv3-interface]
|
||||
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-interface
|
||||
parameters:
|
||||
type:script_output
|
||||
message: print OSPF interface information
|
||||
|
||||
[ospfv3-neighbor]
|
||||
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-neighbor
|
||||
parameters:
|
||||
type:script_output
|
||||
message: Print OSPF neighbors
|
||||
|
||||
[ospfv3-overview]
|
||||
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-overview
|
||||
parameters:
|
||||
type:script_output
|
||||
message: Print OSPF summary
|
||||
|
||||
[general-routes]
|
||||
command:/usr/local/opnsense/scripts/quagga/quagga.rb --general-routes
|
||||
parameters:
|
||||
|
||||
Reference in New Issue
Block a user