diff options
author | Stig Thormodsrud <stig@vyatta.com> | 2008-02-08 15:04:40 -0800 |
---|---|---|
committer | Stig Thormodsrud <stig@vyatta.com> | 2008-02-08 15:04:40 -0800 |
commit | 779df7e2f84b2750f33c073b2f310398d9f8a0fa (patch) | |
tree | 5978292710565815ff0e8308947732f61cc71650 /scripts/vyatta-show-interfaces.pl | |
parent | 4647ef1a3a84880cc7a52d2bf74163d7e470b150 (diff) | |
download | vyatta-op-779df7e2f84b2750f33c073b2f310398d9f8a0fa.tar.gz vyatta-op-779df7e2f84b2750f33c073b2f310398d9f8a0fa.zip |
- Fix bug 776: need "clear interface" command to clear counters
- Fix bug 1095: Enhancement Request: "Show interface brief" command
- Change default to "brief" if multiple interfaces can be shown
- Add "detail" for nodes defaulting to brief
- Add "brief" for nodes defaulting to detail
- Fix vif completions that wasn't working
- Remove ethtool can on vlans since it doesn't work
Diffstat (limited to 'scripts/vyatta-show-interfaces.pl')
-rw-r--r-- | scripts/vyatta-show-interfaces.pl | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/scripts/vyatta-show-interfaces.pl b/scripts/vyatta-show-interfaces.pl new file mode 100644 index 0000000..cd90104 --- /dev/null +++ b/scripts/vyatta-show-interfaces.pl @@ -0,0 +1,360 @@ +#!/usr/bin/perl +# +# Module: vyatta-show-interfaces.pl +# +# **** License **** +# Version: VPL 1.0 +# +# The contents of this file are subject to the Vyatta Public License +# Version 1.0 ("License"); you may not use this file except in +# compliance with the License. You may obtain a copy of the License at +# http://www.vyatta.com/vpl +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# This code was originally developed by Vyatta, Inc. +# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc. +# All Rights Reserved. +# +# Author: Stig Thormodsrud +# Date: February 2008 +# Description: Script to display interface information +# +# **** End License **** +# + +use lib "/opt/vyatta/share/perl5/"; +use VyattaConfig; +use Getopt::Long; +use POSIX; + +use strict; +use warnings; + +# +# valid interfaces +# +my %intf_hash = ( + ethernet => 'eth', + serial => 'wan', + tunnel => 'tun', + bridge => 'br', + loopback => 'lo', + pppoe => 'pppoe', + multilink => 'ml', + ); + +# +# valid actions +# +my %action_hash = ( + 'show' => \&run_show_intf, + 'show-brief' => \&run_show_intf_brief, + 'clear' => \&run_clear_intf, + 'reset' => \&run_reset_intf, + ); + + +my $clear_stats_dir = '/var/run/vyatta'; +my $clear_file_magic = 'XYZZYX'; + +my @rx_stat_vars = + qw/rx_bytes rx_packets rx_errors rx_dropped rx_over_errors multicast/; +my @tx_stat_vars = + qw/tx_bytes tx_packets tx_errors tx_dropped tx_carrier_errors collisions/; + +sub get_intf_type { + my $intf = shift; + + my $base; + if ($intf =~ m/([a-zA-Z]+)\d*/) { + $base = $1; + } else { + die "unknown intf type [$intf]\n"; + } + + foreach my $intf_type (keys(%intf_hash)) { + if ($intf_hash{$intf_type} eq $base) { + return $intf_type; + } + } + return undef; +} + +sub get_intf_description { + my $intf = shift; + + my $intf_type = get_intf_type($intf); + if (!defined $intf_type) { + return ""; + } + my $config = new VyattaConfig; + my $path; + if ($intf =~ m/([a-zA-Z]+\d+)\.(\d+)/) { + $path = "interfaces $intf_type $1 vif $2"; + } else { + $path = "interfaces $intf_type $intf"; + } + $config->setLevel($path); + my $description = $config->returnOrigValue("description"); + if (defined $description) { + return $description; + } else { + return ""; + } +} + +sub get_intf_stats { + my $intf = shift; + + my %stats = (); + foreach my $var (@rx_stat_vars, @tx_stat_vars) { + $stats{$var} = `cat /sys/class/net/$intf/statistics/$var`; + } + return %stats; +} + +sub get_intf_statsfile { + my $intf = shift; + + return "$clear_stats_dir/$intf.stats"; +} + +sub get_clear_stats { + my $intf = shift; + + my %stats = (); + foreach my $var (@rx_stat_vars, @tx_stat_vars) { + $stats{$var} = 0; + } + my $FILE; + my $filename = get_intf_statsfile($intf); + if (!open($FILE, "<", $filename)) { + return %stats; + } + + my $magic = <$FILE>; chomp $magic; + if ($magic ne $clear_file_magic) { + print "bad magic [$intf]\n"; + return %stats; + } + my $timestamp = <$FILE>; chomp $timestamp; + $stats{'timestamp'} = $timestamp; + my ($var, $val); + while (<$FILE>) { + chop; + ($var, $val) = split(/,/); + $stats{$var} = $val; + } + close($FILE); + return %stats; +} + +sub get_ipaddr { + my $intf = shift; + + my @addr_list = (); + my @lines = `ip addr show $intf | grep 'inet '`; + foreach my $line (@lines) { + if ($line =~ m/inet (\d+\.\d+\.\d+\.\d+)\/(\d+)/) { + push @addr_list, "$1/$2"; + } + } + chomp @addr_list; + return @addr_list; +} + +sub get_state_link { + my $intf = shift; + + my $IFF_UP = 0x1; + my ($state, $link); + my $flags = `cat /sys/class/net/$intf/flags 2> /dev/null`; + my $carrier = `cat /sys/class/net/$intf/carrier 2> /dev/null`; + chomp $flags; chomp $carrier; + my $hex_flags = hex($flags); + if ($hex_flags & $IFF_UP) { + $state = "up"; + } else { + $state = "admin down"; + } + if ($carrier eq "1") { + $link = "up"; + } else { + $link = "down"; + } + return ($state, $link); +} + +sub is_valid_intf { + my ($intf) = @_; + + if (-e "/sys/class/net/$intf") { + return 1; + } + return 0; +} + +sub is_valid_intf_type { + my $intf_type = shift; + + if (defined $intf_hash{$intf_type}) { + return 1; + } + return 0; +} + +sub get_intf_for_type { + my $intf_type = shift; + + my $intf_prefix = $intf_hash{$intf_type}; + my @list = `cd /sys/class/net; ls -d $intf_prefix\* 2> /dev/null`; + chomp @list; + return @list; +} + + +# +# The "action" routines +# + +sub run_show_intf { + my @intfs = @_; + + foreach my $intf (@intfs) { + my %clear = get_clear_stats($intf); + my $description = get_intf_description($intf); + my $timestamp = $clear{'timestamp'}; + my $line = `ip addr show $intf | sed 's/^[0-9]*: //'`; chomp $line; + print "$line\n"; + if (defined $timestamp and $timestamp ne "") { + my $time_str = strftime("%a %b %d %R:%S %Z %Y", + localtime($timestamp)); + print " Last clear: $time_str\n"; + } + if (defined $description and $description ne "") { + print " Description: $description\n"; + } + print "\n"; + my %stats = get_intf_stats($intf); + # todo: handle counter wrap + printf(" %10s %10s %10s %10s %10s %10s\n", "RX: bytes", "packets", + "errors", "dropped", "overrun", "mcast"); + printf(" %10d %10d %10d %10d %10d %10d\n", + $stats{'rx_bytes'} - $clear{'rx_bytes'}, + $stats{'rx_packets'} - $clear{'rx_packets'}, + $stats{'rx_errors'} - $clear{'rx_errors'}, , + $stats{'rx_dropped'} - $clear{'rx_dropped'}, + $stats{'rx_over_errors'} - $clear{'rx_over_errors'}, + $stats{'multicast'} - $clear{'multicast'}); + printf(" %10s %10s %10s %10s %10s %10s\n", "TX: bytes", "packets", + "errors", "dropped", "carrier", "collisions"); + printf(" %10d %10d %10d %10d %10d %10d\n\n", + $stats{'tx_bytes'} - $clear{'tx_bytes'}, + $stats{'tx_packets'} - $clear{'tx_packets'}, + $stats{'tx_errors'} - $clear{'tx_errors'}, + $stats{'tx_dropped'} - $clear{'tx_dropped'}, + $stats{'tx_carrier_errors'} - $clear{'tx_carrier_errors'}, + $stats{'collisions'} - $clear{'collisions'}); + } +} + +sub run_show_intf_brief { + my @intfs = @_; + + my $format = "%-12s %-18s %-11s %-6s %-29s\n"; + printf($format, "Interface","IP Address","State","Link","Description"); + foreach my $intf (@intfs) { + my @ip_addr = get_ipaddr($intf); + my ($state, $link) = get_state_link($intf); + my $description = get_intf_description($intf); + $description = substr($description, 0, 29); # make it fit on 1 line + if (scalar(@ip_addr) == 0) { + printf($format, $intf, "-", $state, $link, $description); + } else { + foreach my $ip (@ip_addr) { + printf($format, $intf, $ip, $state, $link, $description); + } + } + } +} + +sub run_clear_intf { + my @intfs = @_; + + foreach my $intf (@intfs) { + my %stats = get_intf_stats($intf); + my $FILE; + my $filename = get_intf_statsfile($intf); + if (!open($FILE, ">", $filename)) { + die "Couldn't open $filename [$!]\n"; + } + print "Clearing $intf\n"; + print $FILE $clear_file_magic, "\n", time(), "\n"; + my ($var, $val); + while (($var, $val) = each (%stats)) { + print $FILE $var, ",", $val; + } + close($FILE); + } +} + +sub run_reset_intf { + my @intfs = @_; + + foreach my $intf (@intfs) { + my $filename = get_intf_stats($intf); + system("rm -f $filename"); + } +} + + +# +# main +# +my @intf_list = (); +my ($intf_type, $intf, $action); +GetOptions("intf-type=s" => \$intf_type, + "intf=s" => \$intf, + "action=s" => \$action, +); + +if (defined $intf) { + if (!is_valid_intf($intf)) { + die "Invalid interface [$intf]\n"; + } + push @intf_list, $intf; +} elsif (defined $intf_type) { + if (!is_valid_intf_type($intf_type)) { + die "Invalid interface type [$intf_type]\n"; + } + @intf_list = get_intf_for_type($intf_type); +} else { + # + # get all interfaces + # + foreach my $type (sort(keys (%intf_hash))) { + push @intf_list, get_intf_for_type($type); + } +} + +if (! defined $action) { + $action = 'show'; +} + +my $func; +if (defined $action_hash{$action}) { + $func = $action_hash{$action}; +} else { + die "Invalid action [$action]\n"; +} + +# +# make it so... +# +&$func(@intf_list); + +# end of file |