#!/usr/bin/perl

use strict;
use Socket;
use Data::Dumper;

my $REMOVE_DOMAIN = '.hkfree.org';
my $EXPORT = 1;
my $EXPORT_DIR = '/opt/ospf-map/data';

my %router_name_cache;

sub router_id2name {
	my $ar = shift;
	# lookup cache
	return $router_name_cache{$ar} if ($router_name_cache{$ar});
        # reverse lookup
        my $ipaddr = inet_aton($ar);
        my $host = gethostbyaddr($ipaddr, AF_INET);
        if ($host =~ /^(.+)$REMOVE_DOMAIN$/) { $host = $1 } # trim trailing ".hkfree.org"
	$host = $ar if (!$host); # failed lookup, use ip address
	$router_name_cache{$ar} = $host; # store to cache
	return $host;
}

sub ospf_database_network {
	my $dat = `echo "sh ip os da ne"|vtysh`;
	if ($EXPORT) {
	    open OO,">$EXPORT_DIR/ospf_database_network";
	    print OO $dat;
	    close OO;
	}
	my @dats = split(/\n/,$dat);
	my $links_by_id = {};

	my @link;
	my $link_id;
	while ($#dats > 0) {
		my $line = shift @dats;
        	if ($line =~ /Attached Router: (.+?)$/) {   # collect routers on the link
	        	my $ar = $1;
			# push router to link's list of connected routers
			push @link, $ar;
		}
		if ($line =~ /Link State ID: (.+?) \(address of Designated Router\)/) {
			$link_id = $1;
		}
		if ($line eq '') {  # end of "link" section
			$links_by_id->{$link_id} = [ @link ];
			@link = ();
		}
	}
	return $links_by_id;
}

sub ospf_database_router_links {	# pozor, v principu ma kazdy link na KAZDEM konci extra cost, coz se tu zanedbava (mely by byt obvykle stejne)
	my $router_id = shift;
	#print "ro: $router_id\n";
	my $dat = `echo "sh ip os da ro $router_id"|vtysh`;
	if ($EXPORT) {
	    open OO,">$EXPORT_DIR/$router_id";
	    print OO $dat;
	    close OO;
	}
	#print $dat;
	my @dats = split(/\n/,$dat);
	my $costs_by_link_id = {};
	
	my $link_id;
	my $cost;
        while ($#dats > 0) {
		my $line = shift @dats;
		if ($line =~ /\(Link ID\) .+: (.+?)$/) {	# net or designated router
			$link_id = $1;
		}
		if ($line =~ /TOS 0 Metric: (.+?)$/) {
			$cost = $1;
			$costs_by_link_id->{$link_id} = $cost;
		}
	}
	return $costs_by_link_id;
}

sub link_attrs {
	my $cost = shift;
	my $cost2 = shift;
	my $s;
	if ($cost <= 10) {
		$s .= " style=bold weight=4 label=\"$cost,$cost2\"";
	}
	my @costs = ($cost);
	push @costs, $cost2 if ($cost2);
	my $costlab = join(",",@costs);
	$s .= " label=\"$costlab\"";
	return $s;
}

if ($EXPORT) {
    `rm $EXPORT_DIR/*`;
}

open F,'database-network';
my $bones = 0;
my $links = 0;

my $time = localtime();
print qq|graph ospfmap {
graph [
	overlap=scale,
	splines=true,
	root="10.107.99.1",
        size="40,40",
        fontname="Arial,Helvetica",
	fontsize=16,
	label="\\n\\nhkfree.org - autogenerated OSPF map ($time)"
];
node [ 
	style=filled,
	fillcolor=lightblue1,
        fontname="Helvetica",
        fontsize=20,
];
edge [
        fontname="Helvetica",
]
|;

my $links_by_id = ospf_database_network();
foreach my $link_id (keys %$links_by_id) {
	my @link = @{$links_by_id->{$link_id}};
	if ($#link >= 2) {	# multipoint
	    $bones++;
	    my $bone_name = "Seg. $bones";
	    print "\"$bone_name\" [shape=diamond, style=\"rounded\"];\n";
	    foreach my $router (@link) {
	    	$links++;
		my $router_links_costs = ospf_database_router_links($router);
		#print "linkid: $link_id\n";
		#print Dumper($router_links_costs);
		my $cost = $router_links_costs->{$link_id};
		#print "cost: $cost\n";
                $router = router_id2name($router);
		my $attrs = link_attrs($cost);
	        print "\"$router\" -- \"$bone_name\" [ id=$links $attrs ];\n";
	    }
	} else {		# point-to-point
	    if ($link[0]) {	# workaround on dummy parsing, some records are empty
	    	$links++;
                my $router_links_costs = ospf_database_router_links($link[0]);
		my $cost = $router_links_costs->{$link_id};
		my $router_links_costs = ospf_database_router_links($link[1]);
		my $cost2 = $router_links_costs->{$link_id};
		my $attrs = link_attrs($cost,$cost2);
		$link[0] = router_id2name($link[0]);
                $link[1] = router_id2name($link[1]);
		print "\"$link[0]\" -- \"$link[1]\" [ id=$links $attrs ];\n";
	    }
	}
	@link = ();
}
print "}\n";
close F;

open RN,">$EXPORT_DIR/router_names";
foreach my $router (keys %router_name_cache) {
    print RN $router."\t".$router_name_cache{$router}."\n";
}
close RN;