diff options
Diffstat (limited to 'lib/Vyatta/VRRP/OPMode.pm')
-rw-r--r-- | lib/Vyatta/VRRP/OPMode.pm | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/lib/Vyatta/VRRP/OPMode.pm b/lib/Vyatta/VRRP/OPMode.pm new file mode 100644 index 0000000..32d86fc --- /dev/null +++ b/lib/Vyatta/VRRP/OPMode.pm @@ -0,0 +1,366 @@ +# +# Module: Vyatta::VRRP::OPMode +# +# **** License **** +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# This code was originally developed by Vyatta, Inc. +# Portions created by Vyatta are Copyright (C) 2007-2012 Vyatta, Inc. +# All Rights Reserved. +# +# Author: John Southworth +# Date: May 2012 +# Description: Process operational data from keepalived +# +# **** End License **** +# + +package Vyatta::VRRP::OPMode; +use strict; +use warnings; +our @EXPORT = qw(process_data process_stats print_summary print_stats print_sync print_detail check_intf); +use base qw(Exporter); + +use Sort::Versions; + +my $PIDFILE='/var/run/vrrp.pid'; +my $DATAFILE='/tmp/keepalived.data'; +my $STATSFILE='/tmp/keepalived.stats'; + +open my $PIDF, '<', $PIDFILE; +my $PID=<$PIDF>; +close $PIDF; + +sub trim { + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} + +sub conv_name { + my $name = shift; + $name = trim $name; + $name = lc $name; + $name =~ s/\s/-/g; + return $name; +} + +sub add_to_datahash { + my ($dh, $interface, $instance, $in_sync, $name, $val) = @_; + $name = conv_name $name; + if ($in_sync) { + if ($name eq 'monitor'){ + $dh->{'sync-groups'}->{$instance}->{$name} = + [ $dh->{'sync-groups'}->{$instance}->{$name} ? + @{$dh->{'sync-groups'}->{$instance}->{$name}} : (), + $val + ]; + } else { + $dh->{'sync-groups'}->{$instance}->{$name} = $val; + } + } else { + $dh->{'instances'}->{$interface}->{$instance}->{$name} = $val; + } +} + +sub process_data { + my ($dh) = @_; + my ($instance, $interface, $in_sync, $in_vip); + kill 'SIGUSR1', $PID; + open my $DATA, '<', $DATAFILE; + while (<$DATA>) + { + m/VRRP Instance = vyatta-(.*?)-(.*)/ && do { + $interface = $1; + $instance = $2; + $in_sync = undef; + $in_vip = undef; + $dh->{'instances'}->{$interface}->{$instance} = {}; + next; + }; + m/VRRP Sync Group = (.*?), (.*)/ && do { + $instance = $1; + $interface = undef; + $in_vip = undef; + my $state = $2; + $in_sync = 1; + add_to_datahash $dh, $interface, $instance, $in_sync, 'state', $state; + next; + }; + if ($in_vip){ + m/(.*?) dev (.*)/ && do { + $dh->{'instances'}->{$interface}->{$instance}->{vips} = + [ $dh->{'instances'}->{$interface}->{$instance}->{vips} ? + @{$dh->{'instances'}->{$interface}->{$instance}->{vips}} : (), + trim $1 ]; + }; + } + m/(.*?) = (.*)/ && do { + $in_vip = undef; + add_to_datahash $dh, $interface, $instance, $in_sync, $1, $2; + m/Virtual IP/ && do {$in_vip = 1}; + next; + }; + } + close $DATA; +} + +sub elapse_time { + my ($start, $stop) = @_; + + my $seconds = $stop - $start; + my $string = ''; + my $secs_min = 60; + my $secs_hour = $secs_min * 60; + my $secs_day = $secs_hour * 24; + my $secs_week = $secs_day * 7; + + my $weeks = int($seconds / $secs_week); + if ($weeks > 0 ) { + $seconds = int($seconds % $secs_week); + $string .= $weeks . "w"; + } + my $days = int($seconds / $secs_day); + if ($days > 0) { + $seconds = int($seconds % $secs_day); + $string .= $days . "d"; + } + my $hours = int($seconds / $secs_hour); + if ($hours > 0) { + $seconds = int($seconds % $secs_hour); + $string .= $hours . "h"; + } + my $mins = int($seconds / $secs_min); + if ($mins > 0) { + $seconds = int($seconds % $secs_min); + $string .= $mins . "m"; + } + $string .= $seconds . "s"; + + return $string; +} + +sub find_sync { + my ($intf, $vrid, $dh) = @_; + my $instance = "vyatta-$intf-$vrid"; + foreach my $sync (sort versioncmp keys(%{$dh->{'sync-groups'}})){ + return $sync if (grep { $instance } @{$dh->{'sync-groups'}->{$sync}->{monitor}}); + } + return; +} + +sub check_intf { + my ($hash, $intf, $vrid) = @_; + if ($intf) { + if (!exists($hash->{instances}->{$intf})){ + print "VRRP is not running on $intf\n"; + return 1; + } + if ($vrid){ + if (!exists($hash->{instances}->{$intf}->{$vrid})){ + print "No VRRP group $vrid exists on $intf\n"; + return 1; + } + } + } + return; +} + + +sub print_detail { + my ($dh,$intf,$group) = @_; + print "--------------------------------------------------\n"; + foreach my $interface (sort versioncmp keys(%{$dh->{instances}})) { + next if ($intf && $interface ne $intf); + printf "Interface: %s\n", $interface; + printf "--------------\n"; + foreach my $vrid (sort versioncmp keys(%{$dh->{instances}->{$interface}})){ + next if ($group && $vrid ne $group); + printf " Group: %s\n", $vrid; + printf " ----------\n"; + printf " State:\t\t\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{state}; + printf " Last transition:\t\t%s\n", + elapse_time($dh->{instances}->{$interface}->{$vrid}->{'last-transition'}, time); + printf "\n"; + if ( $dh->{instances}->{$interface}->{$vrid}->{state} eq 'BACKUP') { + printf " Master router:\t\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{'master-router'}; + printf " Master priority:\t\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{'master-priority'}; + printf "\n"; + } + if ($dh->{instances}->{$interface}->{$vrid}->{'transmitting-device'} ne + $dh->{instances}->{$interface}->{$vrid}->{'listening-device'}){ + printf " RFC 3768 Compliant\n"; + printf " Virtual MAC interface:\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{'transmitting-device'}; + printf " Address Owner:\t\t%s\n", + ($dh->{instances}->{$interface}->{$vrid}->{priority} == 255) ? 'yes': 'no'; + printf "\n"; + } + printf " Source Address:\t\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{'using-mcast-src_ip'}; + printf " Priority:\t\t\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{'priority'}; + printf " Advertisement interval:\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{'advert-interval'}; + printf " Authentication type:\t\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{'authentication-type'}; + printf " Preempt:\t\t\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{'preempt'}; + printf "\n"; + my $sync = find_sync($interface, $vrid, $dh); + if ($sync) { + printf " Sync-group:\t\t\t%s\n", $sync; + printf "\n"; + } + printf " VIP count:\t\t\t%s\n", + $dh->{instances}->{$interface}->{$vrid}->{'virtual-ip'}; + foreach my $vip (@{$dh->{instances}->{$interface}->{$vrid}->{vips}}){ + printf " %s\n", $vip; + } + printf "\n"; + } + } +} + +sub print_summary { + my ($dh, $intf, $group) = @_; + my $format = "%-18s%-7s%-8s%-11s%-7s%-12s%s\n"; + printf $format, '','','','RFC','Addr','Last','Sync'; + printf $format, 'Interface','Group','State','Compliant','Owner','Transition','Group'; + printf $format, '---------','-----','-----','---------','-----','----------','-----'; + foreach my $interface (sort versioncmp keys(%{$dh->{instances}})) { + next if ($intf && $interface ne $intf); + foreach my $vrid (sort versioncmp keys(%{$dh->{instances}->{$interface}})){ + next if ($group && $vrid ne $group); + my $state = $dh->{instances}->{$interface}->{$vrid}->{state}; + my $compliant = + ($dh->{instances}->{$interface}->{$vrid}->{'transmitting-device'} ne + $dh->{instances}->{$interface}->{$vrid}->{'listening-device'}) ? 'yes': 'no'; + my $addr_owner = ($dh->{instances}->{$interface}->{$vrid}->{priority} == 255) ? 'yes': 'no'; + my $lt = elapse_time($dh->{instances}->{$interface}->{$vrid}->{'last-transition'}, time); + my $sync = find_sync($interface, $vrid, $dh); + $sync = "<none>" if (!defined($sync)); + printf $format, $interface, $vrid, $state, $compliant, $addr_owner, $lt, $sync; + } + } + printf "\n"; +} + +sub process_stats { + my ($sh) = @_; + my ($instance, $interface, $section); + kill 'SIGUSR2', $PID; + open my $STATS, '<', $STATSFILE; + while (<$STATS>) + { + m/VRRP Instance: vyatta-(.*?)-(.*)/ && do { + $interface = $1; + $instance = $2; + $sh->{'instances'}->{$interface}->{$instance} = {}; + next; + }; + m/Released master: (.*)/ && do { + $sh->{'instances'}->{$interface}->{$instance}->{'released-master'} = $1; + next; + }; + m/Became master: (.*)/ && do { + $sh->{'instances'}->{$interface}->{$instance}->{'became-master'} = $1; + next; + }; + m/(.*?):$/ && do { + $section = conv_name $1; + $sh->{'instances'}->{$interface}->{$instance}->{$section} = {}; + next; + }; + m/(.*?): (.*)/ && do { + my $id = conv_name $1; + $sh->{'instances'}->{$interface}->{$instance}->{$section}->{$id} = $2; + next; + }; + print $_; + } + + close $STATS; +} + +sub print_stats { + my ($sh, $intf, $group) = @_; + print "--------------------------------------------------\n"; + foreach my $interface (sort versioncmp keys(%{$sh->{instances}})) { + next if ($intf && $interface ne $intf); + printf "Interface: %s\n", $interface; + printf "--------------\n"; + foreach my $vrid (sort versioncmp keys(%{$sh->{instances}->{$interface}})){ + next if ($group && $vrid ne $group); + printf " Group: %s\n", $vrid; + printf " ----------\n"; + printf " Advertisements:\n"; + printf " Received:\t\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{advertisements}->{received}; + printf " Sent:\t\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{advertisements}->{sent}; + printf "\n"; + printf " Became master:\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'became-master'}; + printf " Released master:\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'released-master'}; + printf "\n"; + printf " Packet errors:\n"; + printf " Length:\t\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{length}; + printf " TTL:\t\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{ttl}; + printf " Invalid type:\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{'invalid-type'}; + printf " Advertisement interval:\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{'advertisement-interval'}; + printf " Address List:\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{'address-list'}; + printf "\n"; + printf " Authentication Errors:\n"; + printf " Invalid type:\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'authentication-errors'}->{'invalid-type'}; + printf " Type mismatch:\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'authentication-errors'}->{'type-mismatch'}; + printf " Failure:\t\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'authentication-errors'}->{'failure'}; + printf "\n"; + printf " Priority Zero Advertisements:\n"; + printf " Received\t\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'priority-zero'}->{'received'}; + printf " Sent\t\t\t%d\n", + $sh->{instances}->{$interface}->{$vrid}->{'priority-zero'}->{'sent'}; + printf "\n"; + } + } +} + +sub print_sync { + my ($dh, $sync_group) = @_; + print "--------------------------------------------------\n"; + foreach my $sync (sort versioncmp keys(%{$dh->{'sync-groups'}})){ + next if ($sync_group && $sync ne $sync_group); + printf "Group: %s\n", $sync; + printf "---------\n"; + printf " State: %s\n", $dh->{'sync-groups'}->{$sync}->{state}; + printf " Monitoring:\n"; + foreach my $mon (@{$dh->{'sync-groups'}->{$sync}->{monitor}}){ + my ($intf, $vrid) = $mon =~ m/vyatta-(.*?)-(.*)/; + printf " Interface: %s, Group: %s\n", $intf, $vrid; + } + printf "\n"; + } +} + +1; |