Permalink
Cannot retrieve contributors at this time
executable file
299 lines (207 sloc)
7.33 KB
| #!/usr/bin/perl | |
| # | |
| # Run iperf and tcpdump for network stress testing | |
| # Copyright (C) 2016 Jon Meek | |
| # This program is free software: you can redistribute it and/or modify | |
| # it under the terms of the GNU General Public License as published by | |
| # the Free Software Foundation, either version 3 of the License, or | |
| # (at your option) any later version. | |
| # 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. | |
| # You should have received a copy of the GNU General Public License | |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| =head1 Operational Notes | |
| Run usual (for this tool set) TCP test | |
| On the receiver side: | |
| sudo run_iperf --rcv --prefix t | |
| wait for the receiver process to start (it will announce that it is | |
| listening on TCP port 3000) | |
| then on the sender (for default 10 TCP streams): | |
| sudo run_iperf --prefix t --target x.x.x.x | |
| For fewer TCP streams use -P option: | |
| sudo run_iperf --prefix t -P 5 --target x.x.x.x | |
| sudo run_iperf --prefix t -P 3 --target x.x.x.x | |
| Upon test completion the sender side command will complete, the receiver side must be terminated with a Control-C. | |
| Both the sender and receiver sides will provide the analysis command. A sample: | |
| To analyze: | |
| tcpd_read -b 1 -r t10-10.71.46.50-rcv.tcpd --tcpdump 'dst port 3000' | |
| or, the faster, task specific C++ iperfsum: | |
| iperfsum --filter 'dst port 3000' -r t10-10.71.46.50-rcv.tcpd | |
| UDP test, receiver side, the value for --udp is ignored on the receiver side: | |
| sudo run_iperf --rcv --prefix t --udp 10M | |
| Client side, 25 Mbps output rate: | |
| sudo run_iperf --prefix t --target 192.168.205.47 --udp 25M | |
| =cut | |
| # : pnlbns1:/usr2/data/pcp ; ~/lab/net/run_iperf --rcv --file pcp7 | |
| #: bns2:/usr2/data/pcp ; ~/lab/net/run_iperf --snd --target pnlbns1 --file pcp7 | |
| # tcpd_read -b 1 -r pcp18.10.221.208.38.snd.tcpd --tcpdump 'src 10.221.208.38' | |
| #$IPERF = '/usr/local/bin/iperf162'; | |
| $SUDO = 'sudo'; # Default, could be pbrun | |
| $IPERF = '/usr/local/bin/iperf'; | |
| #$IPERF = 'iperf'; # iperf needs to be in user's path | |
| $TCPDUMP = '/usr/sbin/tcpdump'; | |
| $Port = 3000; | |
| $SnapSize = 100; | |
| $Threads = 10; | |
| $Time = 30; | |
| $Interface = 'eth0'; | |
| $DumpFile = 'iperf'; | |
| $tcpdFilter = qq{port $Port or icmp}; | |
| use Getopt::Long; | |
| use Sys::Hostname; | |
| use Socket; | |
| $Debug = 1; | |
| GetOptions( | |
| "snd" => \$Sender, | |
| "rcv" => \$Receiver, | |
| "pbrun" => \$Use_pbrun, | |
| # "ns" => \$NoStartIperf, # --rcv and iperf server already running | |
| "target=s" => \$Target, # Also sets $Sender | |
| "i=s" => \$Interface, | |
| "port=i" => \$Port, | |
| "s=i" => \$SnapSize, | |
| "P=i" => \$Threads, | |
| "t=i" => \$Time, | |
| "file=s" => \$DumpFile, | |
| "f=s" => \$DumpFile, | |
| "prefix=s" => \$FilePrefix, | |
| "mss=i" => \$MaxSegmentSize, | |
| "udp=s" => \$UDPrate, # Rate is only meaningful for sender, but use one option on both sides | |
| ); | |
| $SUDO = 'pbrun' if $Use_pbrun; | |
| $Sender++ if ($Target); # To eliminate need to put --snd on command line | |
| if ($Sender && $Receiver) { | |
| die "We can't be both a Sender and a Receiver at the current time\n"; | |
| } | |
| $SIG{INT} = \&catch_int; # Cntrl-C shutdown | |
| sub catch_int { | |
| print "$0 Interrupted by Cntrl-C...\n"; | |
| close IPERF; | |
| $termCMD = qq{$SUDO kill -TERM $tcpdumpPID}; | |
| system($termCMD); | |
| # kill 'TERM', $tcpdumpPID; | |
| if ($Receiver && (defined $SourceAddressFromIperf)) { | |
| $FinalFilename = qq{$DumpFile-$SourceAddressFromIperf-rcv.tcpd}; | |
| $mvCMD = qq{$SUDO mv $tcpdFileName $FinalFilename}; | |
| print "$mvCMD\n"; | |
| system($mvCMD); | |
| print "To analyze:\ntcpd_read -b 1 -r $FinalFilename --tcpdump 'dst port $Port'\n"; | |
| } | |
| print "Exiting\n"; | |
| exit; | |
| } | |
| if ($FilePrefix) { | |
| use File::Find; | |
| $BaseDir = q{./} unless $BaseDir; # Default is current directory | |
| sub GetHighTestNumber { | |
| $rdfile = $File::Find::name; # Full path | |
| $file_name = $_; # Just the filename | |
| # print "$count File: $rdfile $file_name\n"; | |
| return if (-d $rdfile); # Skip directories | |
| return unless ($file_name =~ /\.tcpd$/); # Just take tcpdump files | |
| $file_name =~ /^$FilePrefix(\d+)/; | |
| $file_number = $1; | |
| # print " $file_number\n"; | |
| $HighTestNumber = $file_number if ($file_number > $HighTestNumber); | |
| } | |
| $HighTestNumber = 0; | |
| find(\&GetHighTestNumber, $BaseDir, $FilePrefix); | |
| $NextTestNumber = $HighTestNumber + 1; | |
| print "NextTestNumber: $NextTestNumber\n"; | |
| $DumpFile = qq{$FilePrefix$NextTestNumber}; | |
| } | |
| if (!$Sender && !$Receiver) { | |
| $usage = qq{Run iperf and tcpdump for network stress test | |
| Automatic test number incrementing: | |
| sudo run_iperf --prefix t --rcv | |
| sudo run_iperf --prefix t --target 57.72.193.35 | |
| Be sure to start the --rcv process first. | |
| Manually incrementing the file names: | |
| sudo run_iperf --rcv --file t1 | |
| sudo run_iperf --snd --target 57.72.193.35 --file t1 | |
| }; | |
| print $usage; | |
| exit; | |
| } | |
| if ($Sender) { | |
| $hostname = hostname; | |
| $ipaddr = gethostbyname($hostname); | |
| $SourceAddress = inet_ntoa($ipaddr); | |
| if ($SourceAddress eq '127.0.0.1') { | |
| print "Warning: the IP address of this system appears as 127.0.0.1\n"; | |
| print " for consistent packet file naming, adjust /etc/hosts\n"; | |
| } | |
| $tcpdFileName = qq{$DumpFile-$SourceAddress-snd.tcpd}; | |
| print "$hostname - $SourceAddress - $tcpdFileName\n"; | |
| # exit; | |
| } | |
| if ($Receiver) { | |
| $tcpdFileName = qq{$DumpFile.tcpd}; | |
| } | |
| #$tcpdFileName = qq{$DumpFile.tcpd} unless ($DumpFile =~ /\.tcpd$/); | |
| $tcpdumpCmd = qq{$SUDO $TCPDUMP -i $Interface -s $SnapSize -w $tcpdFileName $tcpdFilter}; | |
| FORK: | |
| if ($tcpdumpPID = fork) { | |
| # parent here | |
| # child process pid is available in $tcpdumpPID | |
| # waitpid($tcpdumpPID,0); | |
| # $returnstatus = ($? >> 8); | |
| } elsif (defined $tcpdumpPID) { #pid is zero here if defined | |
| # child here | |
| # Form our exec() string using our temp file. | |
| print STDERR "tcpdumpCmd: $tcpdumpCmd\n" if $Debug; | |
| exec("$tcpdumpCmd"); | |
| # parent process pid is available with getppid | |
| } elsif ($! =~ /No more process/) { | |
| # EAGAIN, supposedly recoverable fork error | |
| sleep 2; | |
| redo FORK; | |
| } else { | |
| # weirdo fork error | |
| die "fork problen\n"; | |
| } | |
| print "tcpdump started\n" if $Debug; | |
| ################################################################### | |
| # | |
| # Receiver | |
| # | |
| if ($Receiver) { | |
| $iperfCmd = qq{$IPERF -s -p $Port}; | |
| $iperfCmd .= q{ -u} if $UDPrate; | |
| print "iperf: $iperfCmd\n" if $Debug; | |
| open(IPERF, "$iperfCmd |"); | |
| while ($in = <IPERF>) { | |
| if ((!defined $SourceAddressFromIperf) && ($in =~ /connected with\s+(.*?)\s+port/)) { | |
| $SourceAddressFromIperf = $1; | |
| print "Source: $SourceAddressFromIperf\n" if $Debug; | |
| } | |
| print $in; | |
| } | |
| } | |
| ################################################################### | |
| # | |
| # Sender | |
| # | |
| if ($Sender) { | |
| $mss = ''; | |
| $mss = qq{--mss $MaxSegmentSize} if ($MaxSegmentSize); | |
| if ($UDPrate) { | |
| $iperfCmd = qq{$IPERF -p $Port $mss -t $Time -c $Target -u -b $UDPrate }; | |
| } else { | |
| $iperfCmd = qq{$IPERF -p $Port $mss -t $Time -c $Target -P $Threads }; | |
| } | |
| print "iperf: $iperfCmd\n" if $Debug; | |
| print "iperf: $iperfCmd\n"; | |
| # system($iperfCmd); | |
| open(IPERF, "$iperfCmd |"); | |
| while ($in = <IPERF>) { | |
| print $in; | |
| } | |
| close IPERF; | |
| # kill 'TERM', $tcpdumpPID; | |
| $termCMD = qq{$SUDO kill -TERM $tcpdumpPID}; | |
| system($termCMD); | |
| print "To analyze:\ntcpd_read -b 1 -r $tcpdFileName --tcpdump 'dst port $Port'\n"; | |
| } | |