Commit 6b71417c authored by Sampo Saaristo's avatar Sampo Saaristo

Latest updates by Rui Prior (GUI ready)

parent ea78f2bf
......@@ -29,6 +29,12 @@ INTRODUCTION (very short):
for later processing. Read more from "README.crude".
* GRUDE [Graphical RUDE]
Grude is a graphical shell for RUDE (and CRUDE), written in
Perl/Tk. Read more from "README.grude".
COMPILATION AND INSTALLATION INSTRUCTIONS:
------------------------------------------
......
CRUDE - version 0.60
CRUDE - version 0.63
-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
......@@ -63,12 +63,12 @@ Commandline syntax:
default vaulue is 0, which means until
interrupted with CTRL+C.
-s #[,#...] Instead of logging results to a file
calculate some statistics on-the-fly.
-s #[,#...] Instead of logging results to a file
calculate some statistics on-the-fly.
-P <priority> Set the process real-time priority.
Only root can do that. Be carefull -
this might lock up your computer !!!
-P <priority> Set the process real-time priority.
Only root can do that. Be careful -
this might lock up your computer !!!
-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
RUDE - version 0.60
RUDE - version 0.63
-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
......@@ -22,7 +22,7 @@ From Jargon File (4.0.0/24 July 1996) [jargon]:
Commandline syntax:
rude [ -h | -v | -s <script file> ] [ -p <priority level ]
rude [ -h | -v | -s <script file> ] [ -P <priority level ]
-h Print short help.
......@@ -139,6 +139,7 @@ Configuration file:
* This command is valid only for the following flow type(s):
- CONSTANT
- TRACE
o <mtime> = { integer } - relative time from START to this action
o <id> = { integer } - flow identifier
......@@ -163,7 +164,7 @@ Available flow types:
This flow simulates stream that looks like constant bitrate traffic.
You may change the flow parameters (packet size and packet rate) with
the MODIFY command. If the generated stream is not "stable" enough, you
should try to run the rude in priviledged priority (-p option).
should try to run the rude in priviledged priority (-P option).
* TRACE
......
#!/usr/bin/perl -w
# Graphical shell for the rude/crude traffic generator and analyser
# Written by: Rui Prior <rprior@ncc.up.pt>
# Distributed under the GPLv2 license: see http://www.gnu.org/copyleft/gpl.html
# for details.
use Tk;
use Tk::FileSelect;
use Tk::Dialog;
use Tk::BrowseEntry;
use Tk::HList;
use IPC::Open3;
use IO::Select;
use File::Temp "tempdir";
use Cwd;
use File::Path;
use File::Copy;
$version = '1.0';
$end = '$'; # Damned interpolation on regexps...
# Parse command line args
if ($#ARGV >= 0) {
if ($ARGV[0] eq '-h' or $ARGV[0] eq '--help') {
print "Usage: grude [file.grd]\n\n";
exit;
}
$argfile = $ARGV[0];
# emitter() needs an existing MainWindow at $mw
$mw = MainWindow->new(-title => 'Grude');
emitter();
@ARGV = ();
} else {
# The usual
main();
}
MainLoop;
sub main {
# General cleanup
undef %tred if defined %tred;
undef %fsed if defined %fsed;
undef %fled if defined %fled;
undef %coll if defined %coll;
undef %tx if defined %tx;
if ($mw) {
foreach $widget ($mw->children) { destroy $widget }
} else {
$mw = MainWindow->new(-title => 'Grude');
}
$fchoice = $mw->Frame;
$choice = 'emitter';
$fchoice->Radiobutton(-text => 'Emitter (rude)',
-variable => \$choice,
-value => 'emitter')->grid(-sticky => 'w');
$fchoice->Radiobutton(-text => 'Collector (crude)',
-variable => \$choice,
-value => 'collector')->grid(-sticky => 'w');
$fchoice->Radiobutton(-text => 'Decode file (crude)',
-variable => \$choice,
-value => 'decoder')->grid(-sticky => 'w');
$fchoice->grid(-padx => 20, -pady => 5);
$fb = $mw->Frame;
$fb->Button(-text => 'Go',
-command => sub {eval "$choice"})->grid(-row => 0, -column => 0,
-padx => 5, -pady => 5);
$fb->Button(-text => 'Quit',
-command => sub {exit})->grid(-row => 0, -column => 1,
-padx => 5, -pady => 5);
$fb->grid();
$mw->resizable(0,0);
$mw->update;
$mw->geometry($mw->reqwidth() . 'x' . $mw->reqheight());
}
sub modsort {
if ($a eq 'initial') { return -1;}
elsif ($b eq 'initial') { return 1;}
else { return $a <=> $b}
}
sub valid_txparms {
if ($tx{'start'} ne 'NOW' and
($tx{'starth'} !~ /^(\d\d)$end/ or $1 > 23 or
$tx{'startm'} !~ /^(\d\d)$end/ or $1 > 59 or
$tx{'starts'} !~ /^(\d\d)$end/ or $1 > 59)
) {
$mw->Dialog(-title => 'Warning',
-text => 'Invalid global start time: must be HH:MM:SS',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
if ($tx{'srt'} and ($tx{'srtprio'} !~ s/^\s*(\d{1,2})\s*$end/$1/ or
$1 < 1 or $1 > 90)) {
$mw->Dialog(-title => 'Warning',
-text => 'Soft real-time priority must be in range 1..90',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
if (!defined $fled{'flows'} or ! scalar %{$fled{'flows'}}) {
$mw->Dialog(-title => 'Warning',
-text => 'Must specify at least one flow',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
return 1; # Good
}
sub valid_flow {
my $flow = $_[0];
my $oldid = $_[1];
if ($$flow{'id'} !~ s/^\s*(\d+)\s*$end/$1/) {
$mw->Dialog(-title => 'Warning',
-text => 'Invalid flow ID',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
if ($$flow{'tstart'} !~ s/^\s*(\d+)\s*$end/$1/) {
$mw->Dialog(-title => 'Warning',
-text => 'Invalid start time',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
if ($$flow{'tstop'} !~ s/^\s*(\d+)\s*$end/$1/) {
$mw->Dialog(-title => 'Warning',
-text => 'Invalid start time',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
if ($$flow{'tstop'} <= $$flow{'tstart'}) {
$mw->Dialog(-title => 'Warning',
-text => 'Stop time must be greater than start time',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
my $max = 0;
foreach $mod (keys %{$$flow{'mods'}}) {
$max = $mod if $mod ne 'initial' and $mod > $max;
}
if ($max >= $$flow{'tstop'}) {
$max++;
my $option = $mw->Dialog(-title => 'Warning',
-text => 'Start instant must precede '.
'flow stop, at '.$$flow{'tstop'}.
' msecs. Change flow stop time to '.$max.'?',
-bitmap => 'warning',
-buttons => ['Change','Cancel'])->Show;
return if ($option eq 'Cancel');
$$flow{'tstop'} = $max;
}
if ($$flow{'daddr'} !~ s/^\s*((\w|-)+(\.(\w|-)+)*)\s*$end/$1/) {
$mw->Dialog(-title => 'Warning',
-text => 'Invalid destination address',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
if ($$flow{'dport'} !~ s/^\s*(\d+)\s*$end/$1/ or $$flow{'dport'} > 65535) {
$mw->Dialog(-title => 'Warning',
-text => 'Invalid destination port',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
if ($$flow{'sport'} !~ s/^\s*(\d+)\s*$end/$1/ or $$flow{'sport'} > 65535
or $$flow{'sport'} < 1024) {
$mw->Dialog(-title => 'Warning',
-text => 'Invalid source port',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
my ($key, $val);
keys %{$fled{'flows'}}; # Reset "each"
while (($key, $val) = each %{$fled{'flows'}}) {
if ($$val{'sport'} == $$flow{'sport'} and $key != $oldid and
$key != $$flow{'id'}) {
$mw->Dialog(-title => 'Warning',
-text => "Source port $$flow{'sport'} already in use by flow $key. Please choose another one.",
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
}
if ($$flow{'settos'} and
$$flow{'tos'} !~ s/^\s*(0x(\d|[a-f]|[A-F]){2})\s*$end/$1/ and
($$flow{'tos'} !~ s/^\s*(\d{1,3})\s*$end/$1/ or $$flow{'tos'} > 255)) {
$mw->Dialog(-title => 'Warning',
-text => 'Invalid TOS value',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return 0;
}
return 1; # Congratulations!
}
sub editfspec {
my $flow = $_[0];
my $mod;
my %fmod;
if (defined $_[1]) {
$mod = ${$_[1]};
%fmod = %{${$$flow{'mods'}}{$mod}};
} else {
$mod = 'new';
}
$fsed{'window'} = $fled{'window'}->Toplevel(-title => "Flow ".$$flow{'id'}.": $mod");
my $esw = $fsed{'window'};
$esw->grab;
$esw->resizable(0,0);
$esw->protocol('WM_DELETE_WINDOW', sub { $fled{'window'}->grab;
$esw->destroy });
my $fr;
my $optlist;
if ($mod ne 'initial') {
$fr = $esw->Frame;
$fr->grid(-row => 0, -column => 0, -padx => 5, -pady => 5);
$fr->Label(-text => 'Instant')->grid(-row => 0, -column => 0);
if ($mod eq 'new') {
my $n = $$flow{'tstart'} + 1;
foreach (keys %{$$flow{'mods'}}) {
$n = $_ + 1 if (/^\d+$end/ and $_ >= $n);
}
$fsed{'inst'} = $n;
} else {
$fsed{'inst'} = $mod;
}
$fsed{'einst'} = $fr->Entry(-width => 8, -textvariable => \$fsed{'inst'});
$fsed{'einst'}->grid(-row => 0, -column => 1);
$optlist = [['Constant','CONSTANT'],['Trace','TRACE'],['Silent','SILENT']];
} else {
$optlist = [['Constant','CONSTANT'],['Trace','TRACE'],['Silent','SILENT']];
}
$fr = $esw->Frame;
$fr->grid(-row => 1, -column => 0, -padx => 5, -pady => 5);
$fr->Label(-text => 'Type')->grid(-row => 0, -column => 0);
$fmod{'type'} = 'CONSTANT' if ! defined $fmod{'type'};
undef $fsed{'bedit'};
my $dummyopt;
if ($fmod{'type'} eq 'CONSTANT') {
$dummyopt = 'Constant';
} elsif ($fmod{'type'} eq 'TRACE') {
$dummyopt = 'Trace';
} elsif ($fmod{'type'} eq 'SILENT') {
$dummyopt = 'Silent';
}
# Must use -textvariable to avoid overwriting the old variable value
$fsed{'optmen'} = $fr->Optionmenu(-variable => \$fmod{'type'},
-textvariable => \$dummyopt,
-options => $optlist,
-command => sub {
return if ! defined $fsed{'bedit'};
if ($fmod{'type'} eq 'CONSTANT') {
$fsed{'bedit'}->configure(-state => 'disabled');
$fsed{'esize'}->configure(-state => 'normal',
-textvariable => \$fmod{'size'});
$fsed{'erate'}->configure(-state => 'normal',
-textvariable => \$fmod{'rate'});
} elsif ($fmod{'type'} eq 'TRACE') {
$fsed{'bedit'}->configure(-state => 'normal');
$fsed{'esize'}->configure(-state => 'disabled', -text => '');
$fsed{'erate'}->configure(-state => 'disabled', -text => '');
} elsif ($fmod{'type'} eq 'SILENT') {
$fsed{'bedit'}->configure(-state => 'disabled');
$fsed{'esize'}->configure(-state => 'disabled', -text => '');
$fsed{'erate'}->configure(-state => 'disabled', -text => '');
}
} );
$fsed{'optmen'}->grid(-row => 0, -column => 1);
$fr->gridColumnconfigure(2, -minsize => 10);
$fsed{'bedit'} = $fr->Button(-text => 'Edit',
-command => [ \&edittrace, $$flow{'id'},
$mod, \%fmod ]);
$fsed{'bedit'}->grid(-row => 0, -column => 3);
$fr = $esw->Frame;
$fr->grid(-row => 2, -column => 0, -padx => 5, -pady => 5, -sticky => 'ew');
$fmod{'size'} = 64 if ! defined $fmod{'size'};
$fsed{'lsize'} = $fr->Label(-text => 'Size');
$fsed{'lsize'}->grid(-row => 0, -column => 0);
$fsed{'esize'} = $fr->Entry(-width => 8);
$fsed{'esize'}->grid(-row => 0, -column => 1);
$fr->gridColumnconfigure(2, -minsize => 10);
$fmod{'rate'} = 1 if ! defined $fmod{'rate'};
$fsed{'lrate'} = $fr->Label(-text => 'Rate');
$fsed{'lrate'}->grid(-row => 0, -column => 3);
$fsed{'erate'} = $fr->Entry(-width => 8);
$fsed{'erate'}->grid(-row => 0, -column => 4);
if ($fmod{'type'} eq 'CONSTANT') {
$fsed{'bedit'}->configure(-state => 'disabled');
$fsed{'esize'}->configure(-state => 'normal',
-textvariable => \$fmod{'size'});
$fsed{'erate'}->configure(-state => 'normal',
-textvariable => \$fmod{'rate'});
} elsif ($fmod{'type'} eq 'TRACE') {
$fsed{'bedit'}->configure(-state => 'normal');
$fsed{'esize'}->configure(-state => 'disabled', -text => '');
$fsed{'erate'}->configure(-state => 'disabled', -text => '');
} elsif ($fmod{'type'} eq 'SILENT') {
$fsed{'bedit'}->configure(-state => 'disabled');
$fsed{'esize'}->configure(-state => 'disabled', -text => '');
$fsed{'erate'}->configure(-state => 'disabled', -text => '');
}
$fr = $esw->Frame;
$fr->grid(-row => 3, -column => 0, -padx => 5, -pady => 5, -sticky => 'ew');
$fr->Button(-text => 'Accept',
-command => sub {
if ($fmod{'type'} eq 'CONSTANT') {
if ($fmod{'size'} !~ s/^\s*0*(\d+)\s*$end/$1/
or $fmod{'size'} < 20 or $fmod{'size'} > 32768) {
$mw->Dialog(-title => 'Warning',
-text => 'Size must be 20 <= size <= 32768',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return;
}
if ($fmod{'rate'} !~ s/^\s*0*(\d+)\s*$end/$1/) {
$mw->Dialog(-title => 'Warning',
-text => 'Rate must be a positive integer',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return;
}
if ($fmod{'rate'} == 0) {
$mw->Dialog(-title => 'Warning',
-text => 'Rate=0: changing type to Silent',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
$fmod{'type'} = 'SILENT';
}
} elsif ($fmod{'type'} eq 'TRACE') {
if ($#{$fmod{'trace'}} == -1) {
$mw->Dialog(-title => 'Warning',
-text => 'Trace list must be non-empty',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return;
}
}
if ($mod ne 'initial') {
if ($fsed{'inst'} !~ s/^\s*0*(\d+)\s*$end/$1/) {
$mw->Dialog(-title => 'Warning',
-text => 'Start instant must be a positive integer!',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return;
}
if ($fsed{'inst'} <= $$flow{'tstart'}) {
$mw->Dialog(-title => 'Warning',
-text => 'Start instant must be after '.
'flow start, at '.$$flow{'tstart'}.
' msecs',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return;
} elsif ($fsed{'inst'} >= $$flow{'tstop'}) {
my $option = $mw->Dialog(-title => 'Warning',
-text => 'Start instant must precede '.
'flow stop, at '.$$flow{'tstop'}.
' msecs. Change flow stop time?',
-bitmap => 'warning',
-buttons => ['Change','Cancel'])->Show;
return if ($option eq 'Cancel');
$$flow{'tstop'} = $fsed{'inst'} + 1;
}
if ($mod ne $fsed{'inst'}) {
if (defined ${$$flow{'mods'}}{$fsed{'inst'}}) {
my $option = $mw->Dialog(-title => 'Warning',
-text => 'Overwrite spec '.$fsed{'inst'}.'?',
-bitmap => 'warning',
-buttons => ['Confirm', 'Cancel'],
-default_button => 'Cancel')->Show;
return if ($option eq 'Cancel');
}
delete ${$$flow{'mods'}}{$mod} if ($mod ne 'new');
}
# This must be the last thing done before commitment
$mod = $fsed{'inst'};
}
${$$flow{'mods'}}{$mod} = \%fmod;
$fled{'ddmods'}->configure(
-options => [ sort modsort keys %{$$flow{'mods'}} ]
);
$fled{'window'}->grab;
$esw->destroy;
}
)->grid(-row => 0, -column => 0);
$fr->gridColumnconfigure(1, -minsize => 10);
$fr->Button(-text => 'Cancel', -command => sub {$fled{'window'}->grab;
$esw->destroy }
)->grid(-row => 0, -column => 2);
$fmod{'trace'} = [] if ! defined $fmod{'trace'};
}
sub edittrace {
my $flowid = $_[0];
my $mod = $_[1];
my $fmod = $_[2];
$tred{'n'} = 0;
my @eplist;
my @trace = @{$$fmod{'trace'}};
$tred{'window'} = $fsed{'window'}->Toplevel(-title => "Flow $flowid\: $mod - trace");
my $etw = $tred{'window'};
$etw->grab;
$etw->resizable(0,0);
$etw->protocol('WM_DELETE_WINDOW', sub { $fsed{'window'}->grab;
$etw->destroy });
my $fr = $etw->Frame;
$fr->grid(-row => 0, -column => 0, -padx => 5, -pady => 5, -sticky => 'ns');
$tred{'scrl'} = $fr->Scrolled('HList', -header => 1, -columns => 2,
-width => 22, -height => 8,
-itemtype => 'text', -selectmode => 'single',
-scrollbars => 'ose', -bg => 'white');
$tred{'scrl'}->grid(-row => 0, -column => 0, -rowspan => 4, -sticky => 'ns');
$tred{'list'} = $tred{'scrl'}->Subwidget('hlist');
$tred{'list'}->configure(-browsecmd => sub {
if (! $tred{'list'}->info('selection') eq '') {
$tred{'bdel'}->configure(-state => 'normal');
}
});
$tred{'list'}->header('create', 0, -text => 'Size',
-headerbackground => $tred{'window'}->cget('bg'));
$tred{'list'}->columnWidth(0, -char => 8);
$tred{'list'}->header('create', 1, -text => 'Wait',
-headerbackground => $tred{'window'}->cget('bg'));
$tred{'list'}->columnWidth(1, -char => 12);
$tred{'bdel'} = $fr->Button(-text => 'Del', -state => 'disabled',
-command => sub {
my $sel = $tred{'list'}->info('selection');
if (! defined $sel or $sel eq '') {
$tred{'bdel'}->configure(-state => 'disabled');
} else {
$tred{'list'}->delete('entry', $sel);
my $i;
for ($i = 0; $i <= $#eplist; $i++) {
last if ($eplist[$i] == $sel);
}
splice(@eplist, $i, 1);
splice(@trace, 2*$i, 2);
}
});
$tred{'bdel'}->grid(-column => 1, -row => 1, -padx => 3, -sticky => 'ew');
$tred{'esize'} = '';
$tred{'ewait'} = '';
$fr->Button(-text => 'Add',
-command => sub {
if ($tred{'esize'} !~ s/^\s*(\d+)\s*$end/$1/
or $tred{'esize'} < 20 or $tred{'esize'} > 32768) {
$mw->Dialog(-title => 'Warning',
-text => 'Size must be 20 <= size <= 32768',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return;
}
if ($tred{'ewait'} !~ s/^\s*(\d+|(\d*\.\d+)?)\s*$end/$1/) {
$mw->Dialog(-title => 'Warning',
-text => 'Bad wait specification',
-bitmap => 'warning',
-buttons => ['Dismiss'])->Show;
return;
}
# Add after selected entry or at the end if none selected
my $i;
my $n = $tred{'n'}++;
my $sel = $tred{'list'}->info('selection');
if (! defined $sel or $sel eq '') {
push(@eplist, $n);
push(@trace, ($tred{'esize'}, $tred{'ewait'}));
$tred{'list'}->add($n);
} else {
for ($i = 0; $i <= $#eplist; $i++) {
if ($eplist[$i] == $sel) {
$i++;
last;
}
}
splice(@eplist, $i, 0);
splice (@trace, 2*$i, 0, ($tred{'esize'}, $tred{'ewait'}));
$tred{'list'}->add($n, -after => $sel);
}
$tred{'list'}->itemCreate($n, 0, -text => $tred{'esize'});
$tred{'list'}->itemCreate($n, 1, -text => $tred{'ewait'});
$tred{'esize'} = '';
$tred{'ewait'} = '';
}
)->grid(-column => 1, -row => 2, -padx => 3, -sticky => 'ew');
$fr = $etw->Frame;
$fr->grid(-row => 1, -column => 0, -padx => 5, -pady => 5);
$fr->Label(-text => 'Size')->grid(-row => 0, -column => 0);
my $ent = $fr->Entry(-width => 6, -textvariable => \$tred{'esize'});
$ent->grid(-row => 0, -column => 1);
$fr->gridColumnconfigure(2, -minsize => 10);
$fr->Label(-text => 'Wait')->grid(-row => 0, -column => 3);
$fr->Entry(-width => 10, -textvariable => \$tred{'ewait'}
)->grid(-row => 0, -column => 4);
$tred{'list'}->configure(-selectforeground => $ent->cget('selectforeground'),
-selectbackground => $ent->cget('selectbackground'));
my $n = 0;
my $i = 0;
foreach (@trace) {
if ($i % 2) {
$tred{'list'}->itemCreate($n, 1, -text => $trace[$i]);
push(@eplist, $n);
$n++;
} else {
$tred{'list'}->add($n);
$tred{'list'}->itemCreate($n, 0, -text => $trace[$i]);
}
$i++;
}
$tred{'n'} = $n;
$fr = $etw->Frame;
$fr->grid(-row => 2, -column => 0, -padx => 5, -pady => 5);
$fr->Button(-text => 'Accept', -command => sub {
$$fmod{'trace'} = \@trace;
$fsed{'window'}->grab;
$etw->destroy;
})->grid(-column => 0, -row => 0, -padx => 3);
$fr->gridColumnconfigure(1, -minsize => 20);
$fr->Button(-text => 'Cancel', -command => sub {$fsed{'window'}->grab;
$etw->destroy }
)->grid(-column => 2, -row => 0, -padx => 3);
}
sub editflow {
$fled{'window'} = $mw->Toplevel;
my $efw = $fled{'window'};
$efw->grab;
$efw->resizable(0,0);
$fled{'flows'} = {} if !defined $fled{'flows'};
my $flows;
$flows = $fled{'flows'};
my $flowid;
if (defined $_[0]) {
$efw->configure(-title => 'Edit flow');
$flowid = $_[0];
} else {
$efw->configure(-title => 'New flow');
$flowid = 0;
foreach $id (keys %{$fled{'flows'}}) {
$flowid = $id + 1 if $id >= $flowid;
}
}
my %flow;
my $oldflow = 0;
if (defined $$flows{$flowid}) {
$oldflow = 1;
%flow = %{$$flows{$flowid}};
} else {
# New flow - defaults
$flow{'mods'} = {'initial' => {'type' => 'CONSTANT',
'rate' => '1',
'size' => '64'}};
$flow{'tstart'} = 0;
$flow{'tstop'} = $flow{'tstart'} + 1000;
$flow{'daddr'} = '';
$flow{'dport'} = 10001;
$flow{'sport'} = 1024;
$flow{'settos'} = 0;
$flow{'tos'} = 0;
}
my $fr = $efw->Frame;
$fr->grid(-row => 0, -column => 0, -padx => 5, -pady => 5);
$fr->Label(-text => 'ID')->grid(-row => 0, -column => 0);
$flow{'id'} = $flowid;
$fr->Entry(-textvariable => \$flow{'id'}, -width => 5
)->grid(-row => 0, -column => 1);
$fr->gridColumnconfigure(2, -minsize => 10);
$fr->Label(-text => 'Tstart')->grid(-row => 0, -column => 3);
$fr