#! /bin/perl
# File: bgp2fvl.pl     
# Goal: Parse a Cisco "show IP bgp" dump file to create 
# 	a Otter Data file that contains the AS connection 
#	network.
#
# Input: reads in a BGP file from 	STDIN
# Output: prints a Otter file to 	STDOUT 
# 	All AS that start a path are labeled as roots
# Wants: Perl 5
#
# Written: Bradley Huffaker             (1/24/14)
#
# For:Cooperative Association for Internet Data Analysis
###########################################################################
###########################################################################
#By accessing this software, BGP2ODF, you are duly informed of and
#agree to be bound by the conditions described below in this notice:
# 
#This software product, BGP2ODF, is developed by Duane Wessels, and
#copyrighted(C) 1998 by the University of California, San Diego (UCSD),
#with all rights reserved.  UCSD administers the NSF grant to CAIDA,
#number NCR-9711092, under which this code was developed. 
# 
#There is no charge for BGP2ODF software. You can redistribute it and/or
#modify it under the terms of the GNU General Public License, v. 2 dated
#June 1991 which is incorporated by reference herein.  BGP2ODF is
#distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF
#MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use of
#it will not infringe on any third party's intellectual property
#rights.
# 
#You should have received a copy of the GNU GPL along with the BGP2ODF
#program.  Copies can also be obtained from
#http://www.gnu.org/copyleft/gpl.html or by writing to
# 
#                        University of California, San Diego
#                        SDSC/CAIDA
#                        9500 Gilman Dr., MS-0505
#                        La Jolla, CA 92093 - 0505  USA
# 
#  Or contact INFO@CAIDA.ORG
###########################################################################

# Input file format  
#****************************************************************************
# The BGP Source file
#BGP table version is 253386, local router ID is 198.32.162.100
#Status codes: s suppressed, d damped, h history, * valid, > best, i - internal
#Origin codes: i - IGP, e - EGP, ? - incomplete
# 
#   Network          Next Hop          Metric LocPrf Weight Path
#*  3.0.0.0          206.157.77.11        165             0 1673 701 80 ?
#*                   144.228.240.93         4             0 1239 701 80 ?
#*                   205.238.48.3                         0 2914 1280 701 80 ?

# AS 2 netname file format
# This changes over time.  Since this data changes.  You should try to get
# data as close the the orginal data file as possible
# AS 	 	  AS Data
#****************************************************************************
#  1              BBNPLANET           
#  2              DCN-AS              
#  3              MIT-GATEWAYS        
#  4              ISI-AS              
#  5              SYMBOLICS           
#  6              HIS-MULTICS         
#  306 - 371      NGNET-AS            

requires 'header.pl';

$as2org_file = "/home/kc/Caida/as2asname";

# The oufput file
$final_file = "/home/web/Tools/Otter/Working/as_data/bgp.fvl";

&GetAS2Org($as2org_file);
&GetFile();
&ProcessFiles();

sub GetFile
{
	#print STDERR "Prasing input\n";
	while(<STDIN>)
	{
		if (/\{([^\,]+).*\}/)
		{
			s/\{.*\}/$1/g;
		}
		$pathnum++;
		if (0)
		{
		if (/^[^\d]+([\d|\.|\/]+)\s+\d+\./)
		{
			$ip_mask = $1;
			if ($ip_mask=~/\/(\d+)/)
			{
				$size = $1;
			}
			else
			{
				@parts = split /\./,$ip_mask;
				$netnum =$parts[0]*0x01000000+$parts[1]*0x00010000
					+$parts[2]*0x00000100+$parts[3]*0x00000001;
         			if ( ! ( $netnum & 0x80000000 ) ) 
				{
            				$size= 8;
         			} 
				elsif ( ! ( $netnum & 0x40000000 ) ) 
				{
            				$size = 16;
         			}
				elsif ( ! ( $netnum & 0x20000000 ) )
				{
            				$size = 24;
         			}
				else
				{
         				printf STDERR "Whoa!  $ip_mask is not a ".
						"valid unicast IP address...\n";
         				$size = -1;
         			}
			}
			$prefixes{$size}++;
		}
		}
		if (/\s0 (\d+) ([\s|\d]*)[^\d]+$/)
		{
			$roots{$1}++;
			$path = "$1 $2";
			foreach $as (split /\s+/,$path)
			{
				$as{$as}++;
			}
			$paths{$path} = 1;
		}
		else
		{
			print STDERR "NO MATCH:", $_;
		}
	}
}

sub GetAS2Org
{
	my ($filename) = @_;
	#print STDERR "Getting AS2Org:$filename\n";
	open (IN, "<$filename") || die ("Unable to open $filename:$!");
	while (<IN>)
	{
		# removes comments
		s/\#.*//g;
		if (/\s*(\d+)\s+\-\s+(\d+)\s+([^\n]+[^\s])/)
		{
			foreach $num ($1..$2)
			{
				$as2org{$num} = $3;
			}
		}
		elsif (/\s*(\d+)\s+([^\n]+[^\s])/)
		{
			$as2org{$1} = $2;
		}
	}
	close IN;
}
	
sub ProcessFiles
{
	#print STDERR "Processing output\n";
	print STDOUT &Header();

	@as = sort keys %as;
	@paths = keys %paths;
	print STDOUT "t ",$#as+1,"\n";
	print STDOUT "# not needed but the number of paths is ",$#paths+1,"\n";
	print STDOUT "g 0 d 1 Node\n";
	print STDOUT "f 0 degree\n";
	print STDOUT "g 1 d 1 Path\n";
	print STDOUT "f 1 length\n";
	
	$as_index = 0;
	foreach $as (@as)
	{
		$name = $as2org{$as};
		$name = "unknown"
			if (!$name);
		$root = "";
		$root = " r"
			if ($roots{$as});
		print STDOUT "? $as_index $name($as)$root\n";
		print STDOUT "v $as_index 0 $as{$as}\n";
		$as2index{$as} = $as_index++;
	}

	$path_index = 0;
	foreach $path (keys %paths)
	{
		@as = split /\s+/,$path;
		print STDOUT "p $path_index ",$#as+1;
		foreach $as (@as)
		{
			$index = $as2index{$as};
			print STDOUT " $index";
		}
		print STDOUT "\n";
		print STDOUT "u $path_index 1 ",$#as+1,"\n";
		$path_index++;
	}
}

