#### ASpath-tree v.4.2 - Released on Thu APR 17 2003, h.16:58:12 #### File: lib/getbgptable.pl Last modified on Tue DEC 10 2002, h.10:00:33 # Routines to collect IPv6 BGP AS path information from the supported # router platforms. Currently these include: cisco (IOS>12), zebra and juniper. # The information coming from the router (via RSH or local command) is parsed to # produce a normalized BGP table and to count route entries and ASs. # Lines of the normalized table are in the format "flags prefix ASpath". # Flags is a 5 character field given by: # 1st char: status code (* valid, s suppressed) # 2nd char: status code (> best, d damped, h history, r RIB failure, - nothing noted) # 3rd char: status code (i internal, - nothing noted) # 4th char: network directly connected (0 no, 1 yes) # 5th char: origin code (i IGP, e EGP, ? incomplete) # ASpaths are AS numbers separated by a blanck space. # Numbers of route entries and ASs are stored in a hash array with possible keys: # valid # suppressed # best # damped # history # RIBfailure # internal # ASs (all the ASs in the router BGP table) # Finally this routine produces a text file containing the raw version of the router table # and if required log files of both the raw router table and the normalized table. sub get_bgp_table { my ($parser, $command, $line) = ('', '', ''); my (@lines) = (); use Socket; use Net::Telnet; if (defined($ROUTERUSERPASS)) { # TELNET module to get BGP4+ AS Path table if ($ROUTER =~ /^JUNIPER$/i) { $parser = "juniper"; $STATUSCODES = "*> active"; my $telnet_session = new Net::Telnet( prompt => '/[\w().-]*[\$#]\s*$/' ); $telnet_session->open($ROUTERADDR); $telnet_session->login($ROUTERUSER, $ROUTERUSERPASS); $telnet_session->cmd(String => "set cli screen-length 0", Timeout => 1800); @lines = $telnet_session->cmd(String => "show route table inet6.0 all terse", Timeout => 1800); $telnet_session->close; } else { $ROUTER = "CISCO"; $parser = "cisco"; $STATUSCODES = "s suppressed, d damped, h history, * valid, > best, r RIB-failure"; my $telnet_session = new Net::Telnet( prompt => '/[\w().-]*[\$#]\s*$/' ); $telnet_session->open($ROUTERADDR); $telnet_session->login($ROUTERUSER, $ROUTERUSERPASS); $telnet_session->cmd(String => "terminal length 0", Timeout => 1800); @lines = $telnet_session->cmd(String => "show bgp ipv6", Timeout => 1800); $telnet_session->close; } # end TELNET module } else { # RSH module to get BGP4+ AS Path table if ($ROUTER =~ /^JUNIPER$/i) { $parser = "juniper"; $STATUSCODES = "*> active"; $command = "show route table inet6.0 all terse"; if ($ROUTERUSER eq 'root') {$command = 'cli '.$command} $command = "$RSHDIR/rsh $ROUTERADDR -l $ROUTERUSER \"$command\""; } elsif ($ROUTER =~ /^ZEBRA$/i) { $parser = "zebra"; $STATUSCODES = "s suppressed, d damped, h history, * valid, > best"; $command = "vtysh -e \'show ipv6 bgp\'"; unless ($LOCAL) {$command = "$RSHDIR/rsh $ROUTERADDR -l $ROUTERUSER \"$command\""} } elsif ($ROUTER =~ /^ZEBRA93$/i) { $parser = "cisco"; $STATUSCODES = "s suppressed, d damped, h history, * valid, > best"; $command = "vtysh -e \'show bgp ipv6\'"; unless ($LOCAL) {$command = "$RSHDIR/rsh $ROUTERADDR -l $ROUTERUSER \"$command\""} } elsif ($ROUTER =~ /^CISCO$/i || !$ROUTER) { $ROUTER = "CISCO"; $parser = "cisco"; $STATUSCODES = "s suppressed, d damped, h history, * valid, > best, r RIB-failure"; $command = "$RSHDIR/rsh $ROUTERADDR -l $ROUTERUSER \"show bgp ipv6\""; } else {&log_it_and_die("ERROR in configuration file: bad value for parameter ROUTER = $ROUTER!")} # execute command to get the IPv6 BGP table open(OUTPUT,"$command |"); for () { s/\x0d//g; push(@lines, $_); } close(OUTPUT); } chomp(@lines); # Write log and for web files (raw table) open(TXTFILE,"> $BGPTABLEFILE"); foreach $line (@lines) {unless(grep(/$ROUTERADDR/,$line)) {print TXTFILE "$line\n"}} close(TXTFILE); if($DEBUG) { open(LOGFILE1,"> $LOGDIR/router-table.txt"); foreach $line (@lines) {unless(grep(/$ROUTERADDR/,$line)) {print LOGFILE1 "$line\n"}} close(LOGFILE1); } # Create array of route entries and hash of summary figures my ($irtable, $inum) = &$parser(@lines); # Write log file (normalized table) if($DEBUG) { open(LOGFILE1,"> $LOGDIR/normalized-table.txt"); foreach (@rtable) {print LOGFILE1 "$_\n"} close(LOGFILE1); } return($irtable, $inum); } # parser for the IPv6 BGP table on a Cisco router (zebra >= 0.93) sub cisco { my (@lines) = @_; my ($prefix, $line, $ASNs, $element, $aspath) = ('', '', '', '', '', ''); my ($flag1, $flag2, $flag3) = (' ', ' ', ' '); my $flags = ' '; my $status_code = ' '; my $onlink = 0; my ($iass, $irtable); my $nexthop_col_start = 20; my $path_col_start = 61; my $state = 9; my ($iass, $irtable); my %num = (); foreach $line (@lines) { if ($state == 9 && $line =~ /.*LocPrf.*/) {$state = 0} elsif ($state == 0 && $line =~ /^[\ssdhr\*]{1}[sdhr\s\>]{1}[i\s]{1}.*/) { if ($line =~ /^.{3}(\S+).*/) {$prefix = $1} $flag1 = substr($line, 0, 1); $flag2 = substr($line, 1, 1); $flag3 = substr($line, 2, 1); $status_code = $flag1.$flag2.flag3; $num{total}++; if ($status_code =~ /\*/) {$num{valid}++} if ($status_code =~ /s/) {$num{suppressed}++} if ($status_code =~ /\>/) {$num{best}++} if ($status_code =~ /d/) {$num{damped}++} if ($status_code =~ /h/) {$num{history}++} if ($status_code =~ /r/) {$num{RIBfailure}++} if ($status_code =~ /i/) {$num{internal}++} if ($flag2 eq '>') { if (substr($line, $nexthop_col_start-1, 2) =~ /\s\S/) { if (substr($line, $nexthop_col_start-1, 3) eq ' ::') {$onlink = 1} if (substr($line, ($path_col_start -1), 2) =~ /\s\S/) { $aspath = substr($line, $path_col_start); } else {$state = 1} } else {$state = 2} } } elsif ($state == 1 && substr($line, ($path_col_start -1), 2) =~ /\s\S/) { $aspath = substr($line, $path_col_start); } elsif ($state == 2 && substr($line, ($nexthop_col_start -1), 2) =~ /\s\S/) { if (substr($line, $nexthop_col_start-1, 3) eq ' ::') {$onlink = 1} if (substr($line, ($path_col_start -1), 2) =~ /\s\S/) { $aspath = substr($line, $path_col_start); } else {$state = 1} } if ($prefix && $aspath) { ($iass, $irtable) = &format_normaltable_entry($prefix, $aspath, $flag1, $flag2, $flag3, $onlink, $iass, $irtable); $prefix = ''; $aspath = ''; $onlink = 0; $state = 0; } } $num{ASs} = @$iass; return($irtable,\%num); } # parser for the IPv6 BGP table on a ZEBRA router (zebra < 0.93x) sub zebra { my (@lines) = @_; my ($prefix, $line, $ASNs, $element, $aspath) = ('', '', '', '', '', ''); my ($flag1, $flag2, $flag3) = (' ', ' ', ' '); my $flags = ' '; my $status_code = ' '; my $onlink = 0; my ($iass, $irtable); my $nexthop_col_start = 5; my $path_col_start = 65; my $state = 9; my ($iass, $irtable); my %num = (); foreach $line (@lines) { if ($state == 9 && $line =~ /.*LocPrf.*/) {$state = 0} elsif ($state == 0 && $line =~ /^[\ssdh\*]{1}[sdh\s\>]{1}[i\s]{1}.*/) { if ($line =~ /^.{3}(\S+).*/) {$prefix = $1} $flag1 = substr($line, 0, 1); $flag2 = substr($line, 1, 1); $flag3 = substr($line, 2, 1); $status_code = $flag1.$flag2.flag3; $num{total}++; if ($status_code =~ /\*/) {$num{valid}++} if ($status_code =~ /s/) {$num{suppressed}++} if ($status_code =~ /\>/) {$num{best}++} if ($status_code =~ /d/) {$num{damped}++} if ($status_code =~ /h/) {$num{history}++} if ($status_code =~ /r/) {$num{RIBfailure}++} if ($status_code =~ /i/) {$num{internal}++} if ($flag2 eq '>') { if (substr($line, ($path_col_start -1), 2) =~ /\s\S/) { $aspath = substr($line, $path_col_start); $state = 1; } else {&log_it("ZEBRA Parser: next hop not found where expected in line:\n $line\n")} } } elsif ($state == 1 && substr($line, ($nexthop_col_start -1), 2) =~ /\s\S/) { if (substr($line, $nexthop_col_start-1, 3) eq ' ::') {$onlink = 1} $state = 0; } if ($prefix && $aspath) { ($iass, $irtable) = &format_normaltable_entry($prefix, $aspath, $flag1, $flag2, $flag3, $onlink, $iass, $irtable); $prefix = ''; $aspath = ''; $onlink = 0; $state = 0; } } $num{ASs} = @$iass; return($irtable,\%num); } # parser for the IPv6 BGP table on a JUNIPER router sub juniper { my (@lines) = @_; my ($prefix, $line, $ASNs, $element, $aspath) = ('', '', '', '', '', ''); my ($flag1, $flag2, $flag3) = (' ', ' ', ' '); my $flags = ' '; my $status_code = ' '; my $onlink = 0; my ($iass, $irtable); my ($iass, $irtable); my %num = (); foreach $line (@lines) { if ($line =~ /^[\s\*]{1}\s{1}(.*)/) { @elements = grep(/\S/, split(/\s+/, $1)); $flag2 = substr($line, 0, 1); if ($elements[0] =~ /\//) { $prefix = $elements[0]; if ($flag2 eq '*') { $num{total}++; $num{best}++; $flag1 = '*'; $flag2 = '>'; $flag3 = '-'; if ($elements[1] eq 'D' && $prefix !~ /^fe80/i) {#to be checked $onlink = 1; $aspath = '?'; } elsif ($elements[1] eq 'B') { $line =~ /\>{1}\S+\s+(.*)$/; $aspath = $1; } } } elsif ($flag2 eq '*') { $num{total}++; $num{best}++; $flag1 = '*'; $flag2 = '>'; $flag3 = '-'; if ($elements[0] eq 'D' && $prefix !~ /^fe80/i) {#to be checked $onlink = 1; $aspath = '?'; } elsif ($elements[0] eq 'B') { $line =~ /\>{1}\S+\s+(.*)$/; $aspath = $1; } } else { $num{total}++; } } if ($prefix && $aspath) { ($iass, $irtable) = &format_normaltable_entry($prefix, $aspath, $flag1, $flag2, $flag3, $onlink, $iass, $irtable); $prefix = ''; $aspath = ''; $onlink = 0; } } $num{valid} = $num{total}; $num{ASs} = @$iass; return($irtable,\%num); } # format entry for normalized table, deals with AS confederations and AS sets (all routers) sub format_normaltable_entry { my ($prefix, $aspath, $flag1, $flag2, $flag3, $onlink, $iass, $irtable) = @_; my ($elemet, $ASNs, $origincode, $flags); my (@elements); if ($aspath =~ /\([\d\s]+\)\s*(\S+.*)/) {$aspath = $1} # hide AS confederation info @elements = grep(/\S/, split(/\s+/, $aspath)); foreach $element (@elements) { if ($element =~ /^\d+$/) { unless (grep(/^$element$/, @$iass)) {push(@$iass, $element)} $ASNs .= " $element"; } elsif ($element =~ /^\{/) { my @tmp = split(/\,/, substr($element, 1, length($element)-2)); my $newelement = ''; foreach my $el (@tmp) { $newelement .= "$el\#"; unless (grep(/$el/, @$iass)) {push(@$iass, $el)} } chop($newelement); $ASNs .= " $newelement"; } elsif ($element =~ /[\?ie]{1}/) {$origincode = $element} } if ($flag3 eq ' ') {$flag3 = '-'} $flags = $flag1.$flag2.$flag3.$onlink.$origincode; push (@$irtable, "$flags $prefix $ASNs"); return($iass, $irtable); } (1); #### ASpath-tree v.4.2 - Released on Thu APR 17 2003, h.16:58:12 #### File: lib/getbgptable.pl Last modified on Tue DEC 10 2002, h.10:00:33