#!

/usr/bin/perl -w
#
# nicstat - print network traffic, Kbyte/s read and written.
#
Solaris 8+, Perl (Sun::Solaris::Kstat).
#
# "netstat -i" only gives a packet count, this program gives Kbytes.
#
# 30-Sep-2006, ver 1.00 (check for new versions, http://www.brendangregg.com)
#
# USAGE:
nicstat [-hsz] [-i int[,int...]] | [interval [count]]
#
#
-h
# help
#
-s
# print summary output
#
-z
# skip zero lines
#
-i int[,int...] # print these instances only
# eg,
#
nicstat
# print summary since boot
#
nicstat 1
# print continually, every 1 second
#
nicstat 1 5
# print 5 times, every 1 second
#
nicstat -i hme0 # only examine hme0
#
# This prints out the KB/s transferred for all the network cards (NICs),
# including packet counts and average sizes. The first line is the summary
# data since boot.
#
# FIELDS:
#
Int
Interface
#
rKB/s
read Kbytes/s
#
wKB/s
write Kbytes/s
#
rPk/s
read Packets/s
#
wPk/s
write Packets/s
#
rAvs
read Average size, bytes
#
wAvs
write Average size, bytes
#
%Util
%Utilisation (r+w/ifspeed)
#
Sat
Saturation (defer, nocanput, norecvbuf, noxmtbuf)
#
# NOTES:
#
# - Some unusual network cards may not provide all the details to Kstat,
# (or provide different symbols). Check for newer versions of this program,
# and the @Network array in the code below.
# - Utilisation is based on bytes transferred divided by speed of the interface
# (if the speed is known). It should be impossible to reach 100% as there
# are overheads due to bus negotiation and timing.
# - Loopback interfaces may only provide packet counts (if anything), and so
# bytes and %util will always be zero. Newer versions of Solaris (newer than
# Solaris 10 6/06) may provide loopback byte stats.
# - Saturation is determined by counting read and write errors caused by the
# interface running at saturation. This approach is not ideal, and the value
# reported is often lower than it should be (eg, 0.0). Reading the rKB/s and
# wKB/s fields may be more useful.
#
# SEE ALSO:
#
nicstat.c
# the C version, also on my website
#
kstat -n hme0 [interval [count]]
# or qfe0, ...
#
netstat -iI hme0 [interval [count]]
#
se netstat.se [interval]
# SE Toolkit
#
se nx.se [interval]
# SE Toolkit
#
# COPYRIGHT: Copyright (c) 2006 Brendan Gregg.

getopts('hi:sz') or usage(). my %NetworkOnly. $loop_max). write to the Free Software Foundation. Tweaked style. added saturation value. you can redistribute it and/or the terms of the GNU General Public License the Free Software Foundation. if (defined $ARGV[0]) { $interval = $ARGV[0].Suite 330. my ($interval./. } . $loop_max = 1. use strict. $loop_max = defined $ARGV[1] ? $ARGV[1] : 2**32. added summary style (from Peter Tribble). # match on network interfaces if (defined $main::opt_i) { foreach my $net (split /.html) Author: Brendan Gregg [Sydney. Boston. (http://www.gnu. Australia] 18-Jul-2004 07-Jan-2005 07-Jan-2005 23-Jan-2006 11-Aug-2006 30-Sep-2006 Brendan Gregg " " " " " " " " " " Created this.# # # # # # # # # # # # # # # # # # # # # # # # # This program is modify it under as published by of the License.org/copyleft/gpl. You should have received a copy of the GNU General Public License along with this program. if not. See the GNU General Public License for more details. } else { $interval = 1. free software. 59 Temple Place . Inc. # network interfaces to print my $NETWORKONLY = 0. This program is distributed in the hope that it will be useful.. tweaked output. Improved output neatness. my $Kstat = Sun::Solaris::Kstat->new(). USA. $main::opt_i) { $NetworkOnly{$net} = 1. but WITHOUT ANY WARRANTY. # # Process command line args # usage() if defined $ARGV[0] and $ARGV[0] eq "--help". Added loopback. use Sun::Solaris::Kstat. either version 2 or (at your option) any later version. my $SKIPZERO = defined $main::opt_z ? $main::opt_z : 0. MA 02111-1307. my $STYLE = defined $main::opt_s ? $main::opt_s : 0. without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. } # check for -i. usage() if $interval == 0. # process [interval [count]]. use Getopt::Std. usage() if defined $main::opt_h.

# # # # # # current loop number max lines per header counter for lines printed Kstat network interfaces network interface data network interface data # autoflush ### Determine network interfaces unless (find_nets()) { if ($NETWORKONLY) { print STDERR "ERROR1: $main::opt_i matched no network interfaces. } ### Get new data my (@NetworkData) = fetch_net_data(). $rpackets. $wbytes. "Time". $old_sat. $old_wbytes. "Time". $old_time). foreach my $network_data (@NetworkData) { ### Extract values my ($int. "rKB/s". } . $time) = split /:/. "Int". $old_wpackets. $old_rpackets. $wpackets. } else { print STDERR "ERROR1: No network interfaces found!\n". my $loop = 0. $old_time) = split /:/. "wPk/s". "%Util". } # globals. "Int". } exit 1. "wKB/s". my $line = $PAGESIZE. $old_wpackets. "wAvs". "wKB/s". $network_data. $old_rpackets. } # # Main # while (1) { ### Print Header if ($line >= $PAGESIZE) { if ($STYLE == 0) { printf "%8s %7s %7s %7s %7s %7s %7s %7s %7s %6s\n". if (defined $NetworkDataOld{$int}) { ($old_rbytes. "rKB/s".$NETWORKONLY = 1. my $PAGESIZE = 20. my %NetworkData. } elsif ($STYLE == 1) { printf "%8s %8s %14s %14s\n". $old_wbytes. $old_sat. "Sat".\n". ### Retrieve old values my ($old_rbytes. $rbytes. my %NetworkDataOld. $| = 1. $NetworkDataOld{$int}. $speed. my %NetworkNames. $sat. } $line = 0. $main::opt_h = 0. "rPk/s". "rAvs".

} # saturation per sec my $sats = ($sat .$old_wpackets) / $tdiff. $Time[0]. # per second values my $rbps = ($rbytes . $Time[2]. print_neat($rkps). my $ravs = $rpps > 0 ? $rbps / $rpps : 0. $Time[1].$old_sat) / $tdiff. my $wpps = ($wpackets . my $wkps = $wbps / 1024. } else { $util = 0. $Time[1].2f %6. print_neat($rpps). my $rkps = $rbps / 1024.$old_time. my $wbps = ($wbytes . if ($speed > 0) { # the following has a mysterious "800". printf "%7. # skip zero lines if asked next if $SKIPZERO and ($rbps + $wbps) == 0. print_neat($wpps). my $wavs = $wpps > 0 ? $wbps / $wpps : 0. $sats. $util = 100 if $util > 100. $Time[2].3f\n". $util. # # Print statistics # if ($rbps ne "") { my @Time = localtime(). my $rpps = ($rpackets . } elsif ($STYLE == 1) { printf "%02d:%02d:%02d %8s %14. print_neat($wavs). $util = ($rbps + $wbps) * 800 / $speed. .$old_wbytes) / $tdiff.else { $old_rbytes = $old_wbytes = $old_rpackets = $old_wpackets = $old_sat = $old_time = 0. $rkps.3f %14. and 8 for bytes2bits. it is 100 # for the % conversion.$old_rpackets) / $tdiff. if ($STYLE == 0) { printf "%02d:%02d:%02d %7s ".$old_rbytes) / $tdiff. $wkps. } # # Calculate statistics # # delta time my $tdiff = $time . $Time[0]. $int. print_neat($wkps).2f\n". # % utilisation my $util. print_neat($ravs). $int.

# Check this is a network device.walk Kstat to discover network interfaces. # Matching on ifspeed has been more reliable than "class" # we also match loopback interfaces. foreach my $name (keys %$Instances) { ### Skip interface if asked if ($NETWORKONLY) { next unless $NetworkOnly{$name}. } } } } . # for multiple interfaces. } ### Store old values $NetworkDataOld{$int} = "$rbytes:$wbytes:$rpackets:$wpackets:$sat:$time". ### Interval sleep $interval. } # find_nets . } ### Skip if not the regular statistic set next unless $name =~ /^$module/. $found++. my $Names = $Instances->{$name}. foreach my $instance (keys %$Modules) { my $Instances = $Modules->{$instance}.} $line++. if (defined $$Names{ifspeed} || $module eq "lo") { ### Save network interface $NetworkNames{$name} = $Names. # # This walks %Kstat and populates a %NetworkNames with discovered # network interfaces. } ### Check for end last if ++$loop == $loop_max. # sub find_nets { my $found = 0. always print the header $line += $PAGESIZE if @NetworkData > 1. ### Loop over all Kstat modules foreach my $module (keys %$Kstat) { my $Modules = $Kstat->{$module}.

$wbytes. $speed = 2 ** 48. $wpackets = $$Names{opackets64}. } else { $rpackets = $$Names{ipackets}. } # fetch . # # This uses the interfaces in %NetworkNames and returns useful Kstat data. $rpackets. To do this we. $wbytes = $$Names{obytes}. . $sat += defined $$Names{nocanput} ? $$Names{nocanput} : 0. $time). } ### Determine saturation value my $sat = 0. $wbytes = $$Names{obytes64}.0 . opackets64 # (or the 32 bit versions if the 64 bit values are not there). print the # %Util as 0. } ### Fetch interface speed if (defined $$Names{ifspeed}) { $speed = $$Names{ifspeed}.return $found. } elsif (defined $$Names{obytes}) { $rbytes = $$Names{rbytes}. # sub fetch_net_data { my ($rbytes. ipackets64. } ### Fetch read bytes if (defined $$Names{opackets64}) { $rpackets = $$Names{ipackets64}. my @NetworkData = (). ### Loop over previously found network interfaces foreach my $name (keys %NetworkNames) { my $Names = $NetworkNames{$name}. $sat += defined $$Names{norcvbuf} ? $$Names{norcvbuf} : 0. $Kstat->update().fetch Kstat data for the network interfaces. # The Kstat values used are rbytes64. } else { # if we can't fetch the speed. } else { $rbytes = $wbytes = 0. $wpackets. obytes64. if (defined $$Names{nocanput} or defined $$Names{norcvbuf}) { $sat += defined $$Names{defer} ? $$Names{defer} : 0. $wpackets = $$Names{opackets}. $speed. if (defined $$Names{opackets}) { ### Fetch write bytes if (defined $$Names{obytes64}) { $rbytes = $$Names{rbytes64}.

if ($num >= 100000) { printf "%7d ". $num.. plus # a trailing space..print a float with decimal places if appropriate. nicstat # print summary since boot nicstat 1 # print continually every 1 second nicstat 1 5 # print 5 times. # # This specifically keeps the width to 7 characters. if possible. $num.int.2f ". # sub print_neat { my $num = shift. } elsif ($num >= 100) { printf "%7.]] | [interval [count]] eg. } } # usage .print usage and exit. } ### use the last snaptime value. every 1 second nicstat -s # summary output nicstat -i hme0 # print hme0 only END exit 1. } else { printf "%7. "$rpackets:$wpackets:$speed:$sat:$time". } } return @NetworkData. "$name:$rbytes:$wbytes:" . ### store data push @NetworkData. } .1f ".$sat += defined $$Names{noxmtbuf} ? $$Names{noxmtbuf} : 0. # sub usage { print STDERR <<END. $time = $$Names{snaptime}. $num. USAGE: nicstat [-hsz] [-i int[. } # print_neat .