Juniper-set-rsvp-metrics

From Initech Technical Wiki
Jump to: navigation, search
#!/usr/bin/php
<?php

function usage () {

	echo "\n";
	echo "Juniper RSVP Metric Analysis and Reset tool";
	echo "\n";
	echo "Usage: juniper-set-rsvp-metrics [--size=<ping_size>] [--count=<ping_count>] [-r] [--routers=<router1>,<router2>] [-q]\n";
	echo "\n";
	echo "  --routers=<router1>,<router2>  Optionally provide a list of routers to run this script against, if ommitted it will\n";
	echo "                                 attempt to discover the list of routers from stored rancid configurations\n";
	echo "  --size=<ping_size>             What size ICMP packets to test against each OSPF neighbor - the default is 8,900 bytes";
	echo "  --count=<ping_count>           How many ICMP packets to send to each OSPF neighbor - the default is 10,000";
	echo "  -r                             Use rapid ICMP mode, the default is non-rapid";
	echo "  -q                             Run this script without prompting to continue, useful to run automatically from cron\n";
	echo "  -d                             Print a LOT of debug output about what exactly it's doing\n";
	echo "  -h|--help                      Display this help text\n";
	echo "\n";
	exit;
}

function arguments($argv) {
    $_ARG = array();
    foreach ($argv as $arg) {
      if (ereg('--([^=]+)=(.*)',$arg,$reg)) {
        $_ARG[$reg[1]] = $reg[2];
      } elseif(ereg('-([a-zA-Z0-9])',$arg,$reg)) {
            $_ARG[$reg[1]] = 'true';
        }
   
    }
  return $_ARG;
}

// Parse command-line aguments into an array calles $arguments
$arguments=arguments($argv);

// Output usage information if the user has involked the -h or --help arguments
if((isset($arguments['h']))&&($arguments['h']==true)) { usage(); }

if(!isset($arguments['size'])) {
	$arguments['size']=8900;
}
if(!isset($arguments['count'])) {
        $arguments['count']=10000;
}
$arguments['timeout']=$arguments['count']+($arguments['count']/2);
if(!isset($arguments['r'])) {
        $arguments['r']="NON-RAPID";
} else {
	$arguments['r']="RAPID";
}

// Verify that the user is rancid, this script can only effectively be run by the rancid user
if(trim(`whoami`) !== 'rancid') {
	echo "You must be the rancid user to run this script, exiting\n";
	exit(1);
}

// Echo welcome message if -q wasn't involked at the command line or if -d was
if((!isset($arguments['q']))||(isset($arguments['d']))) {
echo "\n";
echo "Welcome to the Juniper RSVP Metric Analysis and Reset tool.\n";
}

if(isset($arguments['d'])) {
	echo "DEBUG: Begin dump of command-line arguments\n";
	var_dump($arguments);
	echo "DEBUG: End dump of command-line arguments\n";
}

// Make the user confirm their actions if -q wasn't issued at the command line
if(!isset($arguments['q'])) {
echo "Type 'yes' to continue or just press enter to quit: ";

$handle = fopen ("php://stdin","r");
$line = fgets($handle);
if(trim($line) != 'yes'){
    echo "Quiting\n";
    exit;
}
fclose($handle);
echo "\n"; 
echo "Thank you, continuing...\n";

}


// Get list of routers, either from command-line or by detecting traffic-engineering in rancid stored configs
if(isset($arguments['routers'])) {
	if(isset($arguments['d'])) {
		echo "DEBUG: Router list was provided at command-line, exploding it into an array\n";
	}
	$candidate_list_of_routers=explode(',',$arguments['routers']);
} else {
        if(isset($arguments['d'])) {
                echo "DEBUG: Router list was provided at command-line, exploding it into an array\n";
        }
	exec("grep 'traffic-engineering' ~rancid/managed_devices/configs/* 2>&1 | grep -v 'grep' |grep -v '.new:'| awk '{print $1}' | awk -F\: '{print $1}' | sort | uniq | xargs -I arg1 basename arg1", $candidate_list_of_routers);
}

if(isset($arguments['d'])) {
	echo "DEBUG: Begin router array dump\n";
	var_dump($candidate_list_of_routers);
	echo "DEBUG: End router array dump\n";
}

// Make sure that each router is a juniper
if(isset($arguments['d'])) {
	echo "DEBUG: Processing each router to make sure it's a juniper\n";
}
foreach ($candidate_list_of_routers as $router) {
	if(trim(`grep '#RANCID-CONTENT-TYPE: juniper' ~rancid/managed_devices/configs/$router 2>&1`) == '#RANCID-CONTENT-TYPE: juniper') {
		if(isset($arguments['d'])) {
			echo "DEBUG: OK - $router detected as juniper\n";
		}
		$list_of_routers[$router]=array();
	} else {
		if(isset($arguments['d'])) {
			echo "DEBUG: PROBLEM - $router is not a juniper, ignoring it\n";
		}
	}
}

// For each router create a temp file and dump the config out to that file in set format
if(isset($arguments['d'])) {
        echo "\n";
        echo "------------------------section break----------------------------\n";
        echo "\n";
        echo "DEBUG: Logging into each router and grabbing its current config\n";
}

foreach ($list_of_routers as $router_name => &$router_ref) {
	$tempfile=trim(`mktemp`);
	if(isset($arguments['d'])) {
		echo "DEBUG: Create $tempfile for $router_name config\n";
	}
	$router_ref['config_file']=$tempfile;
	`jlogin -c 'show configuration | display inheritance | display set | no-more' $router_name | grep '^set' > $tempfile`;
}

// For each router login and grab the OSPF neighbors, Remote end IP and interface name
if(isset($arguments['d'])) {
	echo "\n";
        echo "DEBUG: Processing each router to grab its OSPF neighbors\n";
}

foreach ($list_of_routers as $router_name => &$router_ref) {
	if(isset($arguments['d'])) {
		echo "DEBUG: Logging into $router_name with jlogin and issuing command 'show ospf neighbor'\n";
	}
	exec("jlogin -c 'show ospf neighbor' $router_name | grep 'Full' | awk '{print $1\",\"$2}'",$ospf_neighbor_list);

	if(isset($arguments['d'])) {
        	echo "DEBUG: begin dump of OSPF output\n";
		var_dump($ospf_neighbor_list);
		echo "DEBUG: end dump of OSPF output\n";
	}
	
	// Parse output, split ip address and interface name and grab some more details about each interface

	if(isset($arguments['d'])) {
		echo "DEBUG: For each OSPF neighbor split the neighbor IP and the interface and parse more information for each interface from the saved configs\n";
	}

	foreach ($ospf_neighbor_list as $neighbor) {
		list($ip,$interface)=explode(",",$neighbor);

		if(isset($arguments['d'])) {
			"DEBUG: Parsing interface $interface and neighbor $ip\n";
		}
		
		// Setup a sub-array within the router variable
		$router_ref['neighbors'][$ip]['interface']['name']=$interface;

		// Split the interface into its component parts;
		list($unit,$subunit)=explode(".",$interface);
		$router_ref['neighbors'][$ip]['interface']['unit']=$unit;
		$router_ref['neighbors'][$ip]['interface']['subunit']=$subunit;

		// Grab the interface description from the saved config
		$router_ref['neighbors'][$ip]['interface']['description']=trim(`grep '^set interfaces $unit unit $subunit description ' {$router_ref['config_file']} | awk -F\" '{print $2}'`);

		// Grab current TE metric from saved config
		$router_ref['neighbors'][$ip]['interface']['current_metric']=trim(`grep '^set protocols ospf area 0.0.0.0 interface {$unit}.{$subunit} te-metric ' {$router_ref['config_file']} | awk '{print $9}'`);
		if($router_ref['neighbors'][$ip]['interface']['current_metric']=="") {
			$router_ref['neighbors'][$ip]['interface']['current_metric']="unset";
		}

		if(isset($arguments['d'])) {
			echo "DEBUG: Begin var_dump of neighbor $ip\n";
			var_dump($router_ref['neighbors'][$ip]);
			echo "DEBUG: End var_dump of neighbor $ip\n";
		}
	}

	// Destroy the ospf neighbor list array for reuse next time
	unset($ospf_neighbor_list);
}

// Login to each router and ping each OSPF neighbor with large packets to figure out the lowest RTT, this will be the new interface metric

if(isset($arguments['d'])) {
        echo "\n";
        echo "------------------------section break----------------------------\n";
        echo "\n";
        echo "DEBUG: Login to each router and ping each OSPF neighbor with large packets to figure out the lowest RTT, this will be the new interface metric\n";
	echo "\n";
}

foreach ($list_of_routers as $router_name => &$router_ref) {
	if(isset($arguments['d'])) {
		echo "-------------------------------\n";
		echo "DEBUG: Begin router {$router_name}\n\n";
	}
	foreach ($router_ref['neighbors'] as $neighbor_ip => &$neighbor_ref) {

		if(isset($arguments['d'])) {
			echo "DEBUG: Logging into $router_name and {$arguments['r']} pinging neighbor ip $neighbor_ip on interface {$neighbor_ref['interface']['name']} ({$neighbor_ref['interface']['description']})\n";
			echo "DEBUG: We will send {$arguments['count']} ICMP packets at {$arguments['size']} bytes each\n";
		}
		if($arguments['r']=="RAPID") {
			$rtt=trim(`jlogin -t {$arguments['timeout']} -c 'ping no-resolve do-not-fragment size {$arguments['size']} rapid count {$arguments['count']} $neighbor_ip' $router_name |grep 'round-trip min' | awk '{print $4}' | awk -F/ '{print $1}'`);
		} else {
			$rtt=trim(`jlogin -t {$arguments['timeout']} -c 'ping no-resolve do-not-fragment size {$arguments['size']} count {$arguments['count']} $neighbor_ip' $router_name |grep 'round-trip min' | awk '{print $4}' | awk -F/ '{print $1}'`);
		}
		$neighbor_ref['interface']['rtt']=$rtt;
		if($rtt<1) {
			$neighbor_ref['interface']['new_metric']=1;
		} else {
			$neighbor_ref['interface']['new_metric']=floor($rtt);
		}
		if(isset($arguments['d'])) {
			echo "DEBUG: Finished, minimum round trip time on this interface was {$neighbor_ref['interface']['rtt']}ms, new metric recommendation is {$neighbor_ref['interface']['new_metric']}\n\n";
		}
	}
	if(isset($arguments['d'])) {
        	echo "DEBUG: End router {$router_name}\n";
        	echo "-------------------------------\n";
	}

}

// Output recommendations if not implementing them ourselves

if(isset($arguments['d'])) {
        echo "\n";
        echo "------------------------section break----------------------------\n";
        echo "\n";
        echo "DEBUG: Output of configuration change recommendations\n";
}
foreach ($list_of_routers as $router_name => &$router_ref) {
	$header_printed=false;
	
	foreach ($router_ref['neighbors'] as $neighbor_ip => &$neighbor_ref) {
		if($neighbor_ref['interface']['new_metric'] !== $neighbor_ref['interface']['current_metric']) {
			if($header_printed==false) {
				echo "\n";
				echo "**************************************************************\n";
				echo "* {$router_name}\n";
				echo "**************************************************************\n";
				$header_printed=true;
			}
			echo "set protocols ospf area 0.0.0.0 interface {$neighbor_ref['interface']['unit']}.{$neighbor_ref['interface']['subunit']} te-metric {$neighbor_ref['interface']['new_metric']}\n";
		}

	}
}



// Clean up temp files before exit

if(isset($arguments['d'])) {
        echo "\n";
	echo "------------------------section break----------------------------\n";
	echo "\n";
        echo "DEBUG: Delete all temporary config files before process exit\n";
}
foreach ($list_of_routers as $router_name => &$router_ref) {
	if(isset($arguments['d'])) {
		echo "DEBUG: Deleting ". $router_ref['config_file'] ." for $router_name\n";
	}
	unlink ($router_ref['config_file']);
}
?>