Подскажите чем мониторить очереди шейпера.
К примеру есть у меня 5 классов
classid: 1:101
classid: 1:102
classid: 1:103
classid: 1:104
classid: 1:105
можно сделать пять вызовов
tc -s class show dev eth0 classid 1:101
tc -s class show dev eth0 classid 1:102
tc -s class show dev eth0 classid 1:103
tc -s class show dev eth0 classid 1:104
tc -s class show dev eth0 classid 1:105
но это не удобно, и слишком много лишних вызовов утилиты tc, а надо в реальном времени посмотреть статистику в очередях sent bytes, gropped, rate…
Может есть что-то top like для этих целей? Кто чем пользуется при отладке шейпера?
Или может в sysctl\proc есть счетчики с нужными мне данными?
РЕШЕНО!
Нашел скрипт на прел, tc-viewer
#!/usr/bin/perl -w
#
# script: tc-viewer 1.5
# author: Pawel 'snaj' Pawilcz
# email: pawel_pawilcz(at)yahoo.com
# www: http://snaj.ath.cx/
# licence and copyrights: GNU GPL
#
# example: tc-viewer --sort --unit=kbit --timer=5 --conf=/etc/tc-viewer.conf
#
use strict;
use Getopt::Long qw(GetOptions);
use File::Basename qw(basename);
use POSIX qw(strftime);
my ($conf, $sort, $zero, $top, $ifhelp, $unit, $iface, $counter, $timer, $hfsc, $colors ) = ( "", "0", "0", "", "0", "bit", "", "", 2, "0", "0");
my (%color_set, %names, %speedspom, %classes, %speeds) = ( ( ), ( ), ( ), ( ), ( ) );
my ($pom_line_counter, $line_counter, $class_ok, $byte_index, $pkt_index, $class, $parent, $indent, $mydiv, $count, $pomiface) = (0, 0, 0, 0, 0, "", "", " ", 1, 0, "" );
my $help = "Usage: ". basename($0) ." [--help] [--iface=<interface>] [--hfsc] [--sort] [--zero] [--timer=<seconds>] [--top=<X>] [--counter=<X>] [--colors] [--unit=<bit,B,kbit,kB>] [--conf=<tc-viewer-conf>]
--iface=<interface> interface to listen on; must be specified
--conf=<filename> path to configuration file; default none
--hfsc hfsc mode; default htb mode
--sort sort speeds; default disabled
--zero show classes with 0 speeds; default disabled
--timer=<X> refresh delay in seconds; default 2
--top=<X> show X speeds; default show all speeds
--counter=<X> after X refreshes exit; default never exit
--colors enable colored output; default disabled
--unit=<bit,B,kbit,kB> speed unit; default bit
--help prints this info
tc-viewer 1.5 by snaj
";
my %colors = (
'RST' => "\033[0m", # reset
'RED' => "\033[40;31m", # red
'GRE' => "\033[40;32m", # green
'YEL' => "\033[40;33m", # yellow
'BLU' => "\033[40;34m", # blue
'PIN' => "\033[40;35m", # pink
'LBL' => "\033[40;36m", # light blue
'BRED' => "\033[40;31;1m", # bold red
'BGRE' => "\033[40;32;1m", # bold green
'BYEL' => "\033[40;33;1m", # bold yellow
'BBLU' => "\033[40;34;1m", # bold blue
'BPIN' => "\033[40;35;1m", # bold pink
'BLBL' => "\033[40;36;1m", # bold light blue
'NONE' => "",
);
GetOptions(
'iface=s' => \$iface,
'conf=s' => \$conf,
'top=i' => \$top,
'counter=i' => \$counter,
'timer=i' => \$timer,
'sort!' => \$sort,
'zero!' => \$zero,
'colors!' => \$colors,
'hfsc!' => \$hfsc,
'help' => \$ifhelp,
'unit=s'=> \$unit,
) || die $help;
die $help if $ifhelp;
$pomiface = $iface if $iface;
eval `cat $conf` || exit 1 if $conf;
$iface = $pomiface if $pomiface;
die $help unless $iface;
$unit = "bit" if !$unit || $unit !~ /^(bit|kbit|B|kB)$/;
$mydiv =
$unit eq "bit" ? 1/8 :
$unit eq "kbit" ? 1024/8 :
$unit eq "kB" ? 1024 : 1;
if ($hfsc eq "1") {
$byte_index = $pkt_index++;
} else {
$byte_index = ($pkt_index=2)++;
}
if ($colors eq "0") {
$color_set{'Name'} = $color_set{'Speed'} = $color_set{'Range'} = $color_set{'Neutral'} = $color_set{'Reset'} = 'NONE';
} else {
$color_set{'Name'} = 'GRE' unless $color_set{'Name'};
$color_set{'Speed'} = 'RED' unless $color_set{'Speed'};
$color_set{'Range'} = 'YEL' unless $color_set{'Range'};
$color_set{'Neutral'} = 'BPIN' unless $color_set{'Neutral'};
$color_set{'Reset'} = 'RST';
}
$|=1;
sub view_speeds {
(my @TC = `tc -s class show dev $iface`) || exit 1;
for (@TC) {
if ($hfsc eq "1") {
next if(/^( period| backlog)/ || /^$/ );
if(/^class hfsc (\S+) (root|parent (\S+)) /) {
$class = $1;
($parent=$2)=~s/parent //;
$class .= "0" if ($class =~ /:$/);
$parent .= "0" if ($parent =~ /:$/);
push @{$classes{$parent}}, $class unless $class_ok;
next;
}
} else {
next if(/^( rate| lended| tokens)/ || /^$/);
if(/^class htb (\S+) (root|parent (\S+)) .*rate (\S+) ceil (\S+) /) {
my ($pom4, $pom5) = ($4, $5);
$class = $1;
($parent=$2)=~s/parent //;
$class .= "0" if ($class =~ /:$/);
$parent .= "0" if ($parent =~ /:$/);
push @{$speeds{$class}}, $pom4;
push @{$speeds{$class}}, $pom5;
push @{$classes{$parent}}, $class unless $class_ok;
next;
}
}
if(/^ Sent (\d+) bytes (\d+) pkt/) {
push @{$speeds{$class}}, $1;
push @{$speeds{$class}}, $2;
if ($zero eq "0") {
if ($class_ok && ((@{$speeds{$class}}[$byte_index] -= @{$speedspom{$class}}[$byte_index]) == 0)) {
if ( $hfsc eq "0" || !exists $classes{$class} ) {
@{$classes{$parent}}[$_] cmp $class || !(splice @{$classes{$parent}}, $_, 1) || last foreach (0..$#{$classes{$parent}});
delete $speeds{$class};
}
if ( $hfsc eq "0" ) {
delete $classes{$parent} unless @{$classes{$parent}};
}
next;
}
} else {
@{$speeds{$class}}[$byte_index] -= @{$speedspom{$class}}[$byte_index] if $class_ok;
}
@{$speeds{$class}}[$pkt_index] -= @{$speedspom{$class}}[$pkt_index] if $class_ok;
next;
}
}
$class_ok ? $class_ok-- : $class_ok++;
}
sub exit_handler {
die "\e[?25h\n\n";
}
sub sum() {
my ($class) = @_;
return unless exists $classes{$class};
return unless @{$speeds{$class}}[0] == 0;
&sum($_) foreach (@{$classes{$class}});
@{$speeds{$class}}[0] += @{$speeds{$_}}[0] foreach (@{$classes{$class}});
@{$speeds{$class}}[1] += @{$speeds{$_}}[1] foreach (@{$classes{$class}});
}
$SIG{$_} = 'exit_handler' foreach (qw/INT KILL TERM/);
print "\e[?25l\e[2J\e[1;1H\n\tCalculating ...\n";
while (1) {
&view_speeds;
%speedspom = %speeds;
%speeds = ( );
sleep $timer;
&view_speeds;
if ($hfsc eq "1") {
&sum($_) foreach (@{$classes{'root'}});
}
if ($sort eq "1") {
@{$classes{$_}} = reverse sort { @{$speeds{$a}}[$byte_index] <=> @{$speeds{$b}}[$byte_index] || substr( $a, (index $a, ':')+1) cmp substr( $b, index ($b, ':')+1) } @{$classes{$_}} foreach (keys %classes);
} else {
@{$classes{$_}} = sort { substr($a, index($a, ':')+1) cmp substr($b, index($b, ':')+1) } @{$classes{$_}} foreach (keys %classes);
}
print strftime "\e[1;1H \n$colors{$color_set{'Neutral'}} %a %b %e %H:%M:%S %Y", localtime;
print "\n\n\tMode: ", $hfsc eq "0" ? "HTB" : "HFSC" ," ^C to QUIT$colors{$color_set{'Reset'}}\n\n";
if (exists $classes{'root'}) {
my @pom_tab = (keys %speeds);
if ($top) {
if ($sort && $sort eq "1") {
@pom_tab = reverse sort { @{$speeds{$a}}[$byte_index] <=> @{$speeds{$b}}[$byte_index] || substr( $a, (index $a, ':')+1) <=> substr( $b, index ($b, ':')+1) } @pom_tab;
} else {
@pom_tab = sort { substr($a, index($a, ':')+1) <=> substr($b, index($b, ':')+1) } @pom_tab;
}
for (1..$top) {
if (defined $pom_tab[0] && exists $classes{$pom_tab[0]}) {
shift @pom_tab;
redo;
} else {
shift @pom_tab;
}
}
delete $speeds{$_} foreach (@pom_tab);
}
foreach (@{$classes{'root'}}) {
if ($hfsc eq "1") {
foreach (@{$classes{$_}}) {
&show($_, "");
last unless !$top || $count <= $top;
}
} else {
&show($_, "");
}
last unless !$top || $count <= $top;
}
} else {
print "\n\t$colors{$color_set{'Neutral'}}No transfers ...$colors{$color_set{'Reset'}}\n";
}
%classes = %speeds = %speedspom = ( );
--$counter || &exit_handler if $counter;
print "\n\e[2K" x ($pom_line_counter - $line_counter) if ($line_counter < $pom_line_counter);
$pom_line_counter = $line_counter;
$line_counter = $count = 0;
}
sub show {
my ($class, $indent_new) = @_;
my $myindent = $indent_new ? $indent_new.$indent : $indent_new." ";
return unless (exists $speeds{$class});
if( $hfsc eq "1") {
printf "\n\e[2K%s%s%-15s%s - %s%15s%s (%s%3dpps%s)", $colors{$color_set{'Name'}}, $myindent, exists $names{$class} ? $names{$class} : $class , $colors{$color_set{'Reset'}}, $colors{$color_set{'Speed'}}, sprintf("%.1f", @{$speeds{$class}}[0]/($timer*$mydiv)).' '.$unit.'/s', $colors{$color_set{'Reset'}}, $colors{$color_set{'Neutral'}}, @{$speeds{$class}}[1]/$timer, $colors{$color_set{'Reset'}} ;
} else {
printf "\n\e[2K%s%s%-20s%s < %s%10s%s - %s%10s%s > %s%15s%s (%s%3dpps%s)", $colors{$color_set{'Name'}}, $myindent, exists $names{$class} ? $names{$class} : $class , $colors{$color_set{'Reset'}}, $colors{$color_set{'Range'}}, @{$speeds{$class}}[0], $colors{$color_set{'Reset'}}, $colors{$color_set{'Range'}}, @{$speeds{$class}}[1], $colors{$color_set{'Reset'}}, $colors{$color_set{'Speed'}}, sprintf("%.1f", @{$speeds{$class}}[2]/($timer*$mydiv)).' '.$unit.'/s', $colors{$color_set{'Reset'}}, $colors{$color_set{'Neutral'}}, @{$speeds{$class}}[3]/$timer, $colors{$color_set{'Reset'}};
}
$line_counter++;
if (exists $classes{$class}) {
foreach (@{$classes{$class}}) {
&show($_, $myindent);
return unless !$top || $count <= $top;
}
} else {
$count++;
return unless !$top || $count <= $top;
}
}
&exit_handler;
tc-viewer provides the ability to watch current transfers that take place in HTB and HFSC traffic shaping classes.
tc-viewer provides the ability to watch current transfers that take place in HTB and HFSC traffic shaping classes on specified interface.
tc-viewer reads output from: tc -s class show dev iface, and analyzes (for each class) values in lines like this one :
Sent 6173259431 bytes 6300224 pkt...
Measured speeds may little vary from the real ones.
Requirements:
· Perl 5.x (latest stable for your distro because of security reasons)
Installation:
· Download script: tc-viewer · Download example configuration: tc-viewer.conf · Copy tc-viewer to some location that is in your PATH variable, for example /usr/sbin. · chmod +x /path_to_script/tc-viewer · Modify accordingly to your needs tc-viewer.conf and place somewhere, for example in /etc.
What's New in This Release:
· A problem with high values of the parameter 'top' has been fixed.
conf example
$unit = "kbit";
$iface = "eth2";
%names = (
'1:1' => 'LAN',
'1:11' => 'LAN_INET',
'1:12' => 'LAN_BE',
'1:13' => 'LAN_LAN',
'1:111' => 'LAN_INET_SERVER',
'1:112' => 'LAN_INET_USER',
'1:1121' => 'LAN_INET_USER_SHELL',
'1:1122' => 'LAN_INET_USER_PING',
'1:1123' => 'LAN_INET_USER_IM',
'1:1124' => 'LAN_INET_USER_MAIL',
'1:1125' => 'LAN_INET_USER_WEB',
'1:1126' => 'reserved',
'1:1127' => 'LAN_INET_USER_DEFAULT',
);