Commit ba73e37b authored by Robert Ricci's avatar Robert Ricci
Browse files

Merge branch 'assign-select-link-speed'

parents 06be27d0 63a4dfd9
......@@ -36,9 +36,21 @@ inline double loss_distance(double a,double b) {
class tb_delay_info {
public:
// TODO: Make a real constructor!
tb_delay_info() : bandwidth(0), delay(0), loss(0.0),
adjust_to_native_bandwidth(false) { ; } ;
// Note the adjust_to_native_bandwidth flag below
int bandwidth;
int delay;
double loss;
// If true, we just use the native bandwidth of the interface that gets
// picked; the bandwidth member gets updated on every assignment. This only
// makes sense on virtual links.
bool adjust_to_native_bandwidth;
// TODO: We don't actually use any of these; we should get 'em out of here.
int bw_under,bw_over;
int delay_under,delay_over;
double loss_under,loss_over;
......@@ -62,12 +74,14 @@ public:
friend ostream &operator<<(ostream &o, const tb_delay_info& delay)
{
o << "tb_delay_info: bw=" << delay.bandwidth << "+" <<
delay.bw_over << "-" << delay.bw_under << "/" << delay.bw_weight;
o << " delay=" << delay.delay << "+" << delay.delay_over <<
"-" << delay.delay_under << "/" << delay.delay_weight;
o << " loss=" << delay.loss << "+" << delay.loss_over << "-" <<
delay.loss_under << "/" << delay.loss_weight;
// Only print out the stuff that matters, not all of the pieces we don't
// use
o << "tb_delay_info: bw=" << delay.bandwidth;
if (delay.adjust_to_native_bandwidth) {
o << "(adjusted)";
}
o << " delay=" << delay.delay;
o << " loss=" << delay.loss;
o << endl;
return o;
}
......
......@@ -98,8 +98,8 @@ top file: <line>*
<desire> ::= <desire_type><desire_name>:<float>
<desire_type> ::= | "?+" | "&*" | "*!"
<link_line1> ::= link <link_name> <interface> <interface> <int> <float> <float>
<link_flag>*
<link_line1> ::= link <link_name> <interface> <interface> <int|'*'> <float>
<float> <link_flag>*
<link_line2> ::= link <link_name> <interface> <interface> <int> <float> <float>
<link_type> <link_flag*>
<link_flag> ::= nodelay | emulated | trivial_ok | fixsrciface:<string> |
......@@ -124,7 +124,9 @@ Interpretation:
<desire> - see <feature> in the ptop file
<desire_type> - see <feature_type> in the ptop file
<link_line1> and <link_line2> - see notes below for the difference between the
two line types. See <link_line> in the ptop file.
two line types. See <link_line> in the ptop file. The integer gives the
bandwidth for the link, but if the special value '*' is given, assign
simply uses the native bandwidth of the interfaces selected.
<link_type> - when present, a valid mapping must put this virtual link on a
physical link of the same type. For multi-hop link mappings (ie. those
that traverse multiple switches), *all* links used must be of this type. I
......
......@@ -18,6 +18,7 @@ static const char rcsid[] = "$Id: parse_request_rspec.cc,v 1.16 2009-10-21 20:49
#include <fstream>
#include <sstream>
#include <sys/time.h>
#include "anneal.h"
#include "vclass.h"
......
......@@ -242,8 +242,18 @@ int parse_top(tb_vgraph &vg, istream& input)
l->type = link_type;
put(vedge_pmap,e,l);
if ((sscanf(bw.c_str(),"%d",&(l->delay_info.bandwidth)) != 1) ||
(sscanf(bwunder.c_str(),"%d",&(l->delay_info.bw_under)) != 1) ||
// Special flag: treat a bandwidth of '*' specially
if (!strcmp(bw.c_str(),"*")) {
l->delay_info.bandwidth = -2; // Special flag
l->delay_info.adjust_to_native_bandwidth = true;
} else {
if (sscanf(bw.c_str(),"%d",&(l->delay_info.bandwidth)) != 1) {
top_error("Bad line line, bad bandwidth characteristics.");
}
}
// Scan in the rest of the delay_info structure
if ((sscanf(bwunder.c_str(),"%d",&(l->delay_info.bw_under)) != 1) ||
(sscanf(bwover.c_str(),"%d",&(l->delay_info.bw_over)) != 1) ||
(sscanf(bwweight.c_str(),"%lg",&(l->delay_info.bw_weight)) != 1) ||
(sscanf(delay.c_str(),"%d",&(l->delay_info.delay)) != 1) ||
......@@ -288,10 +298,10 @@ int parse_top(tb_vgraph &vg, istream& input)
parsed_line[i] << ".");
}
}
#ifdef PER_VNODE_TT
tb_vnode *vnode1 = get(vvertex_pmap,node1);
tb_vnode *vnode2 = get(vvertex_pmap,node2);
#ifdef PER_VNODE_TT
if (l->emulated) {
if (!l->allow_trivial) {
vnode1->total_bandwidth += l->delay_info.bandwidth;
......@@ -304,6 +314,14 @@ int parse_top(tb_vgraph &vg, istream& input)
vnode2->link_counts[link_type]++;
}
#endif
// Some sanity checks: this combination is illegal for now
if (l->delay_info.adjust_to_native_bandwidth && (l->allow_trivial ||
l->emulated)) {
top_error("Auto-assigning bandwidth on trivial or emulated links"
" not allowed!");
}
}
} else if (command == string("make-vclass")) {
if (parsed_line.size() < 4) {
......
......@@ -336,47 +336,95 @@ float find_link_resolutions(resolution_vector &resolutions, pvertex pv,
++dest_switch_it) {
if (*source_switch_it == *dest_switch_it) continue;
tb_link_info info(tb_link_info::LINK_INTERSWITCH);
if (find_interswitch_path(*source_switch_it,*dest_switch_it,vlink->delay_info.bandwidth,
info.plinks, info.switches) != 0) {
bool first_link, second_link;
/*
* Check to see if either, or both, pnodes are actually the
* switches we are looking for
*/
if ((pv == *source_switch_it) || (pv ==
*dest_switch_it)) {
first_link = false;
} else {
first_link = true;
}
if ((dest_pv == *source_switch_it) ||
(dest_pv == *dest_switch_it)) {
second_link = false;
} else {
second_link = true;
}
if (first_link) {
// Check only whether the source interface is fixed - this is the
// first link in a multi-hop path
if (!find_best_link(pv,*source_switch_it,vlink,first,true,false)) {
// No link to this switch
SDEBUG(cerr << " interswitch failed - no first link"
<< endl;)
continue;
}
}
/*
* Check to see if either, or both, pnodes are actually the
* switches we are looking for
*/
bool first_link, second_link;
if ((pv == *source_switch_it) || (pv ==
*dest_switch_it)) {
first_link = false;
} else {
first_link = true;
}
if ((dest_pv == *source_switch_it) ||
(dest_pv == *dest_switch_it)) {
second_link = false;
} else {
second_link = true;
}
if (second_link) {
// Check only whether the dest interface is fixed - this is the
// last link in a multi-hop path
if (!find_best_link(dest_pv,*dest_switch_it,vlink,second,false,true)) {
// No link to tshis switch
SDEBUG(cerr << " interswitch failed - no second link" << endl;)
// Get link objects
if (first_link) {
// Check only whether the source interface is fixed - this is the
// first link in a multi-hop path
if (!find_best_link(pv,*source_switch_it,vlink,first,true,false)) {
// No link to this switch
SDEBUG(cerr << " interswitch failed - no first link"
<< endl;)
continue;
}
}
if (second_link) {
// Check only whether the dest interface is fixed - this is the
// last link in a multi-hop path
if (!find_best_link(dest_pv,*dest_switch_it,vlink,second,false,true)) {
// No link to tshis switch
SDEBUG(cerr << " interswitch failed - no second link" << endl;)
continue;
}
}
// For regular links, we just grab the vlink's bandwidth; for links
// where we're matching the link speed to the 'native' one for the
// interface, we have to look up interface speeds on both ends.
int bandwidth;
if (vlink->delay_info.adjust_to_native_bandwidth) {
// Grab the actual plink objects for both pedges - it's possible for
// one or both to be missing if we're linking directly to a switch
// (as with a LAN)
tb_plink *first_plink = NULL;
tb_plink *second_plink = NULL;
if (first_link) {
first_plink = get(pedge_pmap,first);
}
if (second_link) {
second_plink = get(pedge_pmap,second);
}
if (first_plink != NULL && second_plink != NULL) {
// If both endpoints are not switches, we use the minimum
// bandwidth
bandwidth = min(first_plink->delay_info.bandwidth,
second_plink->delay_info.bandwidth);
} else if (first_plink == NULL) {
// If one end is a switch, use the bandwidth from the other
// end
bandwidth = second_plink->delay_info.bandwidth;
} else if (second_plink == NULL) {
bandwidth = first_plink->delay_info.bandwidth;
} else {
// Both endpoints are switches! (eg. this might be a link between
// two LANs): It is not at all clear what the right semantics
// for this would be, and unfortunately, we can't catch this
// earlier. So, exiting with an error is crappy, but it's
// unlikely to happen in our regular use, and it's the best we
// can do.
cerr << "*** Using bandwidth adjustment on virutal links " <<
"between switches not allowed " << endl;
exit(EXIT_FATAL);
}
} else {
// If not auto-adjusting, just use the specified bandwidth
bandwidth = vlink->delay_info.bandwidth;
}
// Find a path on the switch fabric between these two switches
if (find_interswitch_path(*source_switch_it,*dest_switch_it,bandwidth,
info.plinks, info.switches) != 0) {
// Okay, we found a real resolution!
if (flipped) { // Order these need to go in depends on flipped bit
if (second_link) {
info.plinks.push_front(second);
......@@ -491,6 +539,8 @@ void resolve_link(vvertex vv, pvertex pv, tb_vnode *vnode, tb_pnode *pnode,
* doesn't usually get called for trivial links, and
* letting them fall through into the 'normal' link code
* below is disatrous!
* Note: We can't get here when doing adjust_to_native_bandwidth,
* since it's illegal to allow trivial links when it's in use.
*/
score_link_info(edge,pnode,dest_pnode,vnode,dest_vnode);
} else {
......@@ -784,6 +834,12 @@ void unscore_link_info(vedge ve,tb_pnode *src_pnode,tb_pnode *dst_pnode, tb_vnod
}
#endif
// If auto-adjusting the vlink bandwidth, we set it to a sentinel value
// so that we can detect any problems next time we do a score_link_info()
if (vlink->delay_info.adjust_to_native_bandwidth) {
vlink->delay_info.bandwidth = -2;
}
}
/*
......@@ -1019,6 +1075,22 @@ void score_link_info(vedge ve, tb_pnode *src_pnode, tb_pnode *dst_pnode, tb_vnod
{
tb_vlink *vlink = get(vedge_pmap,ve);
tb_pnode *the_switch;
// If this link is to be adjusted to the native speed of the interface, go
// ahead and do that now - we use the minimum of the two endpoint interfaces
// Note! Not currently supported on trivial links! (it's illegal for
// adjust_to_native_bandwidth and trivial_ok to both be true)
if (vlink->delay_info.adjust_to_native_bandwidth &&
vlink->link_info.type_used != tb_link_info::LINK_TRIVIAL) {
// Check for special sentinel value to make sure we remembered to re-set
// the value before
assert(vlink->delay_info.bandwidth == -2);
tb_plink *front_plink = get(pedge_pmap, vlink->link_info.plinks.front());
tb_plink *back_plink = get(pedge_pmap, vlink->link_info.plinks.back());
vlink->delay_info.bandwidth =
min(front_plink->delay_info.bandwidth, back_plink->delay_info.bandwidth);
}
switch (vlink->link_info.type_used) {
case tb_link_info::LINK_DIRECT:
SADD(SCORE_DIRECT_LINK);
......@@ -1479,9 +1551,13 @@ bool find_best_link(pvertex pv,pvertex switch_pv,tb_vlink *vlink,
}
} else {
// For non-emulated links, we're just looking for links with few (0,
// actually) users, and enough bandwidth
// actually) users, and enough bandwidth (if we're adjusting the bw
// on the vlink to match what's on the interfaces selected, we don't
// even need to check bandwidth)
if ((users < best_users) &&
(plink->delay_info.bandwidth >= vlink->delay_info.bandwidth)) {
(vlink->delay_info.adjust_to_native_bandwidth ||
(plink->delay_info.bandwidth >= vlink->delay_info.bandwidth)
)) {
best_pedge = *pedge_it;
best_distance = distance;
found_best = true;
......
......@@ -1928,6 +1928,13 @@ sub GenVirtLans($)
my ($traced,$trace_endnode) = @{$member0->_traceinfo()};
my ($rtraced,$rtrace_endnode) = @{$member1->_traceinfo()};
# Rob says not supported
if (($trivial_ok || $emulated) &&
($bandwidth == 0 || $rbandwidth == 0)) {
tberror("Cannot mix trivial_ok|emulated with * bw\n");
$errors++;
}
#
# Geni links and lans are dead simple right now.
#
......@@ -2073,7 +2080,9 @@ sub GenVirtLans($)
my $plink = "linksimple/$vname/$member0,$member1";
$self->addlink("$plink $vname0 $vname1 ".
max($top_bw,$top_rbw) . " 0 0 $protocol" .
($top_bw == 0 ? "*" :
max($top_bw,$top_rbw)).
" 0 0 $protocol" .
($emulated ? " emulated" : "") .
($trivial_ok ? " trivial_ok" : "") .
" $fixall");
......@@ -2098,11 +2107,13 @@ sub GenVirtLans($)
$self->addnode("$delayname delay $delaydesire");
$self->addlink("linksdelaysrc/$vname/$member0,$member1 ".
"$vname0 $delayname $top_bw 0 0 ".
"$protocol $fixsrc0");
"$vname0 $delayname ".
($top_bw == 0 ? "*" : $top_bw) .
" 0 0 $protocol $fixsrc0");
$self->addlink("linksdelaydst/$vname/$member1,$member0 ".
"$vname1 $delayname $top_bw 0 0 ".
"$protocol $fixdst1");
"$vname1 $delayname ".
($top_bw == 0 ? "*" : $top_bw) .
" 0 0 $protocol $fixdst1");
$self->printdb("Delay node $plink ($delayname) = " .
join(" ", @delayinfo) . "\n");
......@@ -2124,16 +2135,18 @@ sub GenVirtLans($)
}
else {
my $plink = "linksimple/$vname/$member0,$member1";
my $spec = "$plink $vname0 $vname1";
my $spec = "$plink $vname0 $vname1 ";
if ($emulated) {
$spec .= " " . max($top_bw,$top_rbw) .
" 0 0 $protocol emulated";
$spec .= max($top_bw,$top_rbw);
}
else {
$spec .= " $top_bw 0 0 $protocol";
# Let assign choose bw if top_bw is zero.
$spec .= ($top_bw == 0 ? "*" : $top_bw);
}
$spec .= " 0 0 $protocol";
$spec .= " emulated" if ($emulated);
if ($trivial_ok) {
$spec .= " trivial_ok";
#
......@@ -2338,7 +2351,8 @@ sub GenVirtLans($)
$rdelay,$rbw,$rbackfill,$rloss,0);
$self->addlink("$plink $vnodevname lan/$vname " .
max($top_bw,$top_rbw) .
($top_bw == 0 ? "*" :
max($top_bw,$top_rbw)).
" 0 0 $protocol" .
($emulated ? " emulated" : "") .
($trivial_ok ? " trivial_ok" : "") .
......@@ -2360,11 +2374,13 @@ sub GenVirtLans($)
$self->addnode("$delayname delay $delaydesire");
$self->addlink("linkdelaysrc/$vname/$member " .
"$vnodevname $delayname $top_bw 0 0 ".
"$protocol $fixsrc0");
"$vnodevname $delayname ".
($top_bw == 0 ? "*" : $top_bw) .
" 0 0 $protocol $fixsrc0");
$self->addlink("linkdelaydst/$vname/$member " .
"lan/$vname $delayname $top_bw 0 0 ".
"$protocol");
"lan/$vname $delayname ".
($top_bw == 0 ? "*" : $top_bw) .
" 0 0 $protocol");
$self->printdb("Delay node $plink ($delayname) = " .
join(" ", @delayinfo) . "\n");
......@@ -2388,12 +2404,13 @@ sub GenVirtLans($)
}
else {
my $plink = "linklan/$vname/$member";
my $spec = "$plink $vnodevname lan/$vname ";
# Let assign choose bw if top_bw is zero.
$spec .= ($top_bw == 0 ? "*" : $top_bw);
$spec .= " 0 0 $protocol";
$spec .= " emulated" if ($emulated);
my $spec = "$plink $vnodevname lan/$vname $top_bw " .
"0 0 $protocol";
if ($emulated) {
$spec .= " emulated";
}
if ($trivial_ok) {
$spec .= " trivial_ok";
......@@ -2692,6 +2709,12 @@ sub getbandwidth($$$$)
my $node_type = $virtnode->type();
my $protocol = protocolbasetype($virtlan->_protocol());
my $linkbws = $self->{'TYPELINKBW'};
#
# A target bandwidth of zero indicates that we want assign to choose.
#
return 0
if ($targetbw == 0);
foreach my $bw (keys(%{ $linkbws->{$node_type}{$protocol} })) {
if (($bw >= $targetbw) && ($bw < $best)) {
......@@ -2738,6 +2761,13 @@ sub requires_delay($$$$)
my $linkbws = $self->{'TYPELINKBW'};
my $node_class;
#
# A target bandwidth of zero indicates that we want assign to choose.
# Therefore, no delay is needed since assign picks the native bw.
#
return 0
if ($targetbw == 0);
if (!exists($linkbws->{$node_type}{$protocol})) {
warn("requires_delay(): $virtnode - invalid type $node_type!\n");
return 0;
......@@ -4200,7 +4230,7 @@ sub InterpLinks($)
my ($nodeB,$portB) = undef;
my $protolink;
my $virtnodeB = $self->vnodes()->{$vnodeB};
#
# If the link is delayed, its with endpoint delays, not a
# delay node.
......@@ -4211,7 +4241,7 @@ sub InterpLinks($)
if (! $trivial) {
$nodeB = $member1->_pnode();
$portB = $member1->_pport();
$self->printdb("LINK simple: $virtA,$virtB - ".
"$nodeA:$portA,$nodeB:$portB\n");
......@@ -4687,6 +4717,51 @@ sub InterpLinks($)
}
}
#
# Check the portbw to make sure they are all set; if the user is
# letting assign pick the interfaces (zero bandwidth), then portbw
# is still zero, and it needs to be set to the default speed for
# that interface.
#
foreach my $virtlan (values(%{ $self->vlans() })) {
foreach my $member ($virtlan->memberlist()) {
# Will this happen?
next
if (!exists($self->solution_portmap()->{$member}));
# XXX NSE checks I do not understand.
next
if (! (exists($self->portbw()->{$member}) &&
exists($self->solution_v2p()->{$member->vnode()})));
# Skip anything that was turned into a vinterface; the
# port speed will get set elsewhere.
next
if (exists($self->solution_vifacemap()->{$member}));
my $iface = $self->solution_portmap()->{$member};
my $pnodename = $self->solution_v2p()->{$member->vnode()};
my $speed = $self->portbw()->{$member};
# Already set.
next
if ($speed);
my $interface = Interface->LookupByIface($pnodename, $iface);
if (!defined($interface)) {
tberror("Could not lookup interface $pnodename:$iface\n");
return -1;
}
$speed =
$self->interfacespeedmbps($interface->type(), "ethernet");
# portbw() is in bps.
$self->portbw()->{$member} = $speed * 1000;
$self->printdb("Setting portbw: $pnodename:$iface $speed\n");
}
}
# Write the vlans to the DB.
$self->UploadVlans() == 0
or return -1;
......
......@@ -2,7 +2,7 @@
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2006 University of Utah and the Flux Group.
# Copyright (c) 2000-2006, 2010 University of Utah and the Flux Group.
# All rights reserved.
#
......@@ -537,6 +537,13 @@ proc new {class args} {
# unit is given then bytes (b) is assumed. It returns the bandwidth
# in Kbps.
proc parse_bw {bspec {islink 1}} {
#
# Special case; "*" means let assign pick the bandwidth. Make it zero.
#
if {"$bspec" == "*"} {
return 0
}
# Default to bytes
if {[scan $bspec "%f%s" bw unit] == 1} {
set unit b
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment