Juniper-set-rsvp-metrics
From Initech Technical Wiki
#!/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']);
}
?>