#! /usr/local/bin/perl # # copyright 2010 The Regents of the University of California All Rights # Reserved # # Permission to copy, modify and distribute any part of this AS ASSIGNMENT # SUPPLEMENTAL MATERIAL for educational, research and non-profit purposes, # without fee, and without a written agreement is hereby granted, provided # that the above copyright notice, this paragraph and the following three # paragraphs appear in all copies. # # Those desiring to incorporate this AS ASSIGNMENT SUPPLEMENTAL PATERIAL # into commercial products or use for commercial purposes should contact # the Technology Transfer Office, University of California, San Diego, 9500 # Gilman Drive, Mail Code 0910, La Jolla, CA 92093-0910, Ph: (858) # 534-5815, FAX: (858) 534-7345, E-MAIL:invent@ucsd.edu. # # IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, # INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS AS ASSIGNMENT # PAPER SUPPLEMENTAL MATERIAL, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS # BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # THE AS ASSIGNMENT SUPPLEMENTAL MATERIAL PROVIDED HEREIN IS ON AN "AS IS" # BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE # MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. THE # UNIVERSITY OF CALIFORNIA MAKES NO REPRESENTATIONS AND EXTENDS NO # WARRANTIES OF ANY KIND, EITHER IMPLIED OR EXPRESS, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A # PARTICULAR PURPOSE, OR THAT THE USE OF THE AS ASSIGNMENT SUPPLEMENTAL # MATERIAL WILL NOT INFRINGE ANY PATENT, TRADEMARK OR OTHER RIGHTS. # use strict; # This needs to be the path to ASFinder # http://www.caida.org/tools/measurement/coralreef/status.xml use lib '/usr/local/pkg/caida_coral-3.8.4/Coral/lib/'; use CAIDA::ASFinder; my %valid_options = %{{ "prefix2as" => ["p", "ASFinder friendly \"prefix\\tlength\\tAS\" (prefix2as.2010.04.19.txt)"], "routers" => ["r","kapar router file (midar-iffinder-kapar.nodes)"], "links" => ["l","kapar links file (midar-iffinder-kapar.links)"] }}; use Getopt::Std; use FindBin qw($Bin); use Socket; my ($exe) = ($0 =~ /([^\/]+)$/); my $usage = "usage:$exe [-p prefix2as] [-r routers] [-l link] [config]\n". " $exe -c > sample-config-file"; sub Help() { print <= 0) { $error_message = "no file for :".join(",",@missing)."\n"; } if ($#permission >= 0) { $error_message = "no read permission for :".join(",",@permission)."\n"; } my $asfinder = new CAIDA::ASFinder(); my %total; my @routers; my %file2linenum; foreach my $keyword (@keyword_order) { my ($key, $description) = @{$valid_options{$keyword}}; my $file = $opts{$key}; if (-r $file) { PrintStatus("$keyword Loading"); if ($keyword eq "prefix2as") { $asfinder->load_file_text($file); } elsif ($keyword eq "routers") { LoadRoutersLinks($file); } elsif ($keyword eq "links") { LoadRoutersLinks($file); } else { die("Unknown keyword:$keyword"); } } else { die "missing $keyword"; } } my %as2degree; CountAsDegree(); my @rids = (0..$#routers); my $rids_second = AssignAs("election", \@rids); my ($key, $description) = @{$valid_options{"links"}}; my $link_file = $opts{$key}; LoadRoutersLinks($link_file,"second pass"); AssignAs("election+degree", $rids_second); ResolveSets(\@rids); PrintAsAssignment(); ################################################################## sub LoadRoutersLinks { my ($file, $second_pass) = @_; my $linenum_total = CountFileSize($file); $file2linenum{$file} = $linenum_total; if ($file =~ /gz$/) { open (IN, "gunzip -c $file|") || die("Unable to open $file:$!"); } else { open(IN, "<$file") || die("Unable to open $file:$!"); } my $linenum = 0; while() { CheckStatus("$file $second_pass",$linenum++,$linenum_total); s/#.*//; next unless (/[^\s]/); if (/^node N(\d+):\s+(.*)/) { my ($rid, $ips) = ($1, $2); my @ips = split /\s+/, $ips; my $placeholder_counted; $total{routers}{seen}++; foreach my $ip (@ips) { if ($ip =~ /\d/) { unless ($ip =~ /^0\./) { my ($as, $prefix, $len) = GetAs($ip); if ($len > 7) { $routers[$rid]{ases}{$as}++; } } elsif (!defined $placeholder_counted) { $placeholder_counted = 1; } } } unless (defined $routers[$rid]{has_ip}){ $total{routers}{"no ip"}++; } } elsif (/^link L(\d+):\s+(.*)/) { my ($lid, $rid_ips) = ($1, $2); my %as; my @rid; my $num_routers; my $link_has_ip; unless (defined $second_pass) { $total{links}{seen}++; } foreach my $rid_ip (split /\s+/ , $rid_ips) { my ($rid, $ip) = ($rid_ip =~ /^N([^\:]+):?(.*)/); push @rid, $rid; unless (defined $second_pass) { if ($ip =~ /\d/ && !$ip =~ /^0\./) { $link_has_ip = 1; my ($as, $prefix, $len) = GetAs($ip); if ($len > 7) { $as{$as} = 1; } } } else { my $as = $routers[$rid]{as}; if (defined $as) { $as{$as} = 1; } } } my @as = keys %as; if ($#as >= 0) { foreach my $rid (@rid) { foreach my $as (@as) { $routers[$rid]{ases}{$as}++; } } } elsif (!defined $second_pass) { $total{links}{skipped}++; } } else { print STDERR "$file\[$linenum\] failed to parse:$_"; } } close IN; } sub GetAs { my ($ip) = @_; # my ($as, $prefix, $len) = GetAs($ip); return $asfinder->get_as($ip); } ################################################################## sub CountAsDegree { my %as_as; foreach my $rid (0..$#routers) { next unless (defined $routers[$rid]); my @as = keys %{$routers[$rid]{ases}}; next if ($#as < 1); foreach my $i (0..($#as-1)) { foreach my $j (($i+1)..$#as) { $as_as{$as[$i]}{$as[$j]} = 1; $as_as{$as[$j]}{$as[$i]} = 1; } } } foreach my $as (keys %as_as) { my $degree = keys %{$as_as{$as}}; $as2degree{$as} = $degree; } } ################################################################## sub AssignAs { my ($method_label, $rids) = @_; PrintStatus("Assigning AS $method_label"); my ($method) = ($method_label =~ /([^\+]+)$/); my @as_second_pass; my $total_routers = @$rids; my $num_routers = 0; foreach my $rid (@$rids) { CheckStatus("Assigning AS $method", $num_routers++, $total_routers); my @as; my $as2value; if ($method eq "degree") { @as = keys %{$routers[$rid]{ases}}; $as2value = \%as2degree; } elsif ($method eq "election") { $as2value = $routers[$rid]{ases}; @as = keys %$as2value; } else { die("Unknown method:$method"); } @as = sort {$as2value->{$a}<=>$as2value->{$b}} @as; delete $routers[$rid]{ases}; if ($#as == 0) { $routers[$rid]{as} = $as[0]; $routers[$rid]{method} = "single"; undef $routers[$rid]{ases}; } elsif ($#as > 0) { if ($as2value->{$as[0]} != $as2value->{$as[1]}) { $routers[$rid]{as} = $as[0]; $routers[$rid]{method} = $method_label; } else { push @as_second_pass, $rid; } } else { push @as_second_pass, $rid; } } return \@as_second_pass; } ################################################################## sub ResolveSets { my ($rids) = @_; PrintStatus("Resolve Sets"); my @as_second_pass; my $total_routers = @$rids; my $num_routers = 0; foreach my $rid (@$rids) { CheckStatus("Resolving Sets", $num_routers++, $total_routers); my $as_set = $routers[$rid]{as}; next if (!defined $as_set || ($as_set =~ /^\d+$/)); my $as; my @as = split /[^\d]/, $as_set; if ($#as == 0) { $as = $as[0]; } else { if (defined $routers[$rid]{ases}) { my $as2value = $routers[$rid]{ases}; @as = sort {$as2value->{$a}<=>$as2value->{$b}} @as; if ($as2value->{$as[0]} != $as2value->{$as[1]}) { $as = $as[0]; } } unless (defined $as) { @as = sort {$as2degree{$a}<=>$as2degree{$b}} @as; if ($as2degree{$as[0]} != $as2degree{$as[1]}) { $as = $as[0]; } } } unless (defined $as) { @as = reverse sort {$a<=>$b} @as; $as = $as[0]; } if (defined $as) { $routers[$rid]{as} = $as; } } } ################################################################## sub PrintAsAssignment { PrintStatus("Printing AS"); my $total_routers = @routers; my $num_routers = 0; print "#node.AS rid AS method\n"; foreach my $rid (0..$#routers) { CheckStatus("Assigning AS (pass one)", $num_routers++, $total_routers); next unless (defined $routers[$rid]); next unless (defined $routers[$rid]{as}); my $as = $routers[$rid]{as}; my $method = $routers[$rid]{method}; print "node.AS N$rid $as $method\n"; } } ################################################################## sub PrintStatus { my ($message) = @_; my ($sec, $min, $hour, $day, $mon, $year) = localtime(time); $mon++; foreach my $value ($sec, $min, $hour, $day, $mon) { $value = "0".$value if ($value < 10); } $year += 1900; print STDERR " $year/$mon/$day $hour:$min:$sec $message\n"; } { my %file2start; my $check_last_time; sub CheckStatus { my ($file, $linenum, $linenum_total) = @_; my $check_window = 5; my $time = time; unless (defined $file2start{$file}) { $file2start{$file} = $time; $check_last_time = $time; } elsif ($time-$check_last_time >= $check_window) { my $prec = sprintf("%.2f", 100*($linenum/$linenum_total)); my $start_time = $file2start{$file}; my $estimate_time = ($linenum_total-$linenum) *(($time-$start_time)/$linenum); $estimate_time = sprintf("%.3f",$estimate_time/(60*60)); PrintStatus("$file $prec\% $estimate_time hours"); $check_last_time = $time; } } } sub CountFileSize { my ($file) = @_; if ($file =~ /gz$/) { open (COUNT, "gunzip -c $file |") || die("Unable to open $file:$!"); } else { open (COUNT, "<$file") || die("Unable to open $file:$!"); } my $linenum = 0; while () { $linenum++; } close COUNT; return $linenum; } ################################################################## sub PrintSampleConfig { print "# This file tells $exe where the following data files are\n"; foreach my $keyword (sort keys %valid_options) { my ($key, $description) = @{$valid_options{$keyword}}; print "# $description\n"; print "$keyword:\n"; } } sub ParseConfig { my ($filename, $opts) = @_; my $dir = $filename; $dir =~ s/\/?[^\/]+$//; open (IN,"<$filename") || die ("Unable to open config file $filename:$!"); my $linenum = 0; my ($continue_next, $key); while () { $linenum++; s/#.*//; next unless (/[^\s]/); chop; my $continue; if (defined $continue_next) { $continue = 1; } undef $continue_next; if (/\\$/) { chop; $continue_next = 1; } if (defined $continue) { $opts->{$key} .= " ".AddPath($key, $dir, $_); } elsif (/([^\:]+)\:\s*(.*)/) { my ($keyword , $value) = ($1, $2); my $key_description = $valid_options{$keyword}; if (defined $key_description) { my ($key, $description) = @$key_description; unless (defined $opts->{$key}) { $opts->{$key} = AddPath($key, $dir,$value); } } } else { print STDERR "$filename\[$linenum\] failed to parse $_"; } } close IN; } sub AddPath { my ($key, $dir, $file) = @_; if (($dir =~ /[^\s]/) && ($key ne "D")) { $file =~ s/^\s*//; unless ($file =~ /^\//) { return "$dir/$file"; } } return $file; } 1;