Commit 98775689 authored by Robert Ricci's avatar Robert Ricci

Merge in policy changes from the assing-devel branch

parent 2f63dfe6
...@@ -228,6 +228,7 @@ cout << "Physical Graph: " << parse_ptop(PG,SG,ptopfile) << endl; ...@@ -228,6 +228,7 @@ cout << "Physical Graph: " << parse_ptop(PG,SG,ptopfile) << endl;
// Calculate the minimum spanning tree for the switches - we only consider one // Calculate the minimum spanning tree for the switches - we only consider one
// potential path between each pair of switches. // potential path between each pair of switches.
// XXX: Should soon be replaced by calculate_shortest_routes()
void calculate_switch_MST() { void calculate_switch_MST() {
cout << "Calculating shortest paths on switch fabric." << endl; cout << "Calculating shortest paths on switch fabric." << endl;
...@@ -744,6 +745,20 @@ nosuchtype: ...@@ -744,6 +745,20 @@ nosuchtype:
#endif #endif
} }
// Perfrom a pre-cehck to make sure that polices that are checkable at precheck
// time are not violated. Returns 1 if everything is A-OK, 0 otherwise
// TODO - move away from using global variables
int policy_precheck() {
cout << "Policy precheck:" << endl;
if (tb_featuredesire::check_desire_policies()) {
cout << "Policy precheck succeeded" << endl;
return 1;
} else {
cout << "*** Policy precheck failed!" << endl;
return 0;
}
}
// Signal handler - add a convneint way to kill assign and make it return an // Signal handler - add a convneint way to kill assign and make it return an
// unretryable error // unretryable error
void exit_unretryable(int signal) { void exit_unretryable(int signal) {
...@@ -948,7 +963,13 @@ int main(int argc,char **argv) { ...@@ -948,7 +963,13 @@ int main(int argc,char **argv) {
} }
} }
#endif #endif
// Run the policy precheck - the idea behind running this last is that some
// policy violations might become more clear after doing pruning
if (!policy_precheck()) {
exit(EXIT_UNRETRYABLE);
}
// Bomb out early if we're only doing the prechecks // Bomb out early if we're only doing the prechecks
if (prechecks_only) { if (prechecks_only) {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
......
...@@ -25,7 +25,9 @@ tb_featuredesire::tb_featuredesire(fstring _my_name) : my_name(_my_name), ...@@ -25,7 +25,9 @@ tb_featuredesire::tb_featuredesire(fstring _my_name) : my_name(_my_name),
global(false), local(false), global(false), local(false),
l_additive(false), g_one_is_okay(false), l_additive(false), g_one_is_okay(false),
g_more_than_one(false), g_more_than_one(false),
in_use_globally(0) { in_use_globally(0), desire_policy(),
feature_policy(), desire_users(0),
desire_total_weight(0.0f) {
static int highest_id = 0; static int highest_id = 0;
// Pick a unique numeric identifier for this feature/desire // Pick a unique numeric identifier for this feature/desire
...@@ -112,6 +114,72 @@ void tb_featuredesire::remove_global_user(int howmany) { ...@@ -112,6 +114,72 @@ void tb_featuredesire::remove_global_user(int howmany) {
assert(in_use_globally >= 0); assert(in_use_globally >= 0);
} }
/*
* Functions for manipulating policies
*/
void tb_featuredesire::disallow_desire() {
desire_policy.disallow();
}
void tb_featuredesire::allow_desire() {
desire_policy.allow();
}
void tb_featuredesire::limit_desire(double limit) {
desire_policy.limit_use(limit);
}
void tb_featuredesire::unlimit_desire() {
desire_policy.unlimit_use();
}
/*
* Bookkeeping functions
*/
void tb_featuredesire::add_desire_user(double weight) {
desire_users++;
desire_total_weight += weight;
}
int tb_featuredesire::get_desire_users() {
return desire_users;
}
double tb_featuredesire::get_desire_total_weight() {
return desire_total_weight;
}
/*
* Check desire violations - true means everything was okay, false otherwise
*/
bool tb_featuredesire::check_desire_policies() {
int errors = 0;
name_featuredesire_map::const_iterator it = featuredesires_by_name.begin();
while (it != featuredesires_by_name.end()) {
tb_featuredesire *fd = it->second;
if (!fd->desire_policy.is_allowable() && fd->desire_users) {
cout << " *** Policy violation: " << endl
<< " Feature " << it->first
<< " requested, but prohibited by policy" << endl;
errors++;
} else {
if (fd->desire_policy.is_limited() &&
(fd->desire_total_weight > fd->desire_policy.get_limit())) {
cout << " *** Policy violation: " << endl
<< " Feature " << it->first
<< " requested with weight " << fd->desire_total_weight
<< " but limted to " << fd->desire_policy.get_limit()
<< " by policy" << endl;
errors++;
}
}
it++;
}
if (errors) {
return false;
} else {
return true;
}
}
/********************************************************************* /*********************************************************************
* tb_node_featuredesire * tb_node_featuredesire
*********************************************************************/ *********************************************************************/
......
...@@ -16,8 +16,44 @@ ...@@ -16,8 +16,44 @@
using namespace std; using namespace std;
/* /*
* Base class for features and desires - not intended to be used directly, only * This small class is used to describe policies in force regarding features
* to be subclassed by tb_feature and tb_desire * and desires. The idea behind putting this it its own class is that you want
* to be able to apply baiscally the same policies to features and desires, but
* treat them seperateley.
*/
class tb_featuredesire_policy {
public:
tb_featuredesire_policy(): allowable(true), limited_use(false),
min_use(0.0f), max_use(0.0f) { ; };
/*
* Functions for maintaining FD policy state. Inline, since they're
* so simple.
*/
void allow() { allowable = true; };
void disallow() { allowable = false; }
bool is_allowable() { return this->allowable; };
void limit_use(double howmuch) { limited_use = true; max_use = howmuch; };
void unlimit_use() { limited_use = false; max_use = 0.0f; }
bool is_limited() { return limited_use; }
double get_limit() { return max_use; }
friend ostream &operator<<(ostream &o, const tb_featuredesire_policy &fdp);
private:
// Indicates whether or not we are allowed to use this feature or
// desire, and if so, how much of it we are allowed to use. Note that
// while these limits are global, this is different from using a global
// FD - it is a policy knob that can be applied in the ptop file
bool allowable;
bool limited_use;
double max_use;
// Note: min_use not implemented, as it's not clear what the point
// would be
double min_use;
};
/*
* Base class for features and desires.
*/ */
class tb_featuredesire { class tb_featuredesire {
public: public:
...@@ -43,7 +79,7 @@ class tb_featuredesire { ...@@ -43,7 +79,7 @@ class tb_featuredesire {
inline bool is_g_one() const { return g_one_is_okay; } inline bool is_g_one() const { return g_one_is_okay; }
inline bool is_g_more() const { return g_more_than_one; } inline bool is_g_more() const { return g_more_than_one; }
inline int global_use_count() const { return in_use_globally; } inline int global_use_count() const { return in_use_globally; }
inline fstring name() const { return my_name; } inline fstring name() const { return my_name; }
/* /*
* Operators, primarily for use with the STL * Operators, primarily for use with the STL
...@@ -63,7 +99,34 @@ class tb_featuredesire { ...@@ -63,7 +99,34 @@ class tb_featuredesire {
*/ */
void add_global_user(int howmany = 1); void add_global_user(int howmany = 1);
void remove_global_user(int howmany = 1); void remove_global_user(int howmany = 1);
/*
* Simple bookkeeping
*/
void add_desire_user(double weight);
int get_desire_users();
double get_desire_total_weight();
/*
* Functions for manipulating the policies for features or desires with
* this name.
* NOTE: Only desire policies implement for now
*/
void disallow_desire();
void allow_desire();
void limit_desire(double limit);
void unlimit_desire();
/*
* Check to see if any desires violate policies - this is checkable at
* any time (after all desires and policies have been set up), because
* it is not dependant on the current mapping. Returns true if
* everything is okay, false if not.
* Feature policy violations, which are not yet implemented, will be
* much harder because of thise.
*/
static bool check_desire_policies();
private: private:
/* /*
* This is private, so that we can force callers to go through the * This is private, so that we can force callers to go through the
...@@ -87,11 +150,25 @@ class tb_featuredesire { ...@@ -87,11 +150,25 @@ class tb_featuredesire {
bool l_additive; // If a local FD, is additive bool l_additive; // If a local FD, is additive
// Counts how many instances of this feature are in use across all // Counts how many instances of this feature are in use across all
// nodes - for use with global nodes // nodes - for use with global features
int in_use_globally; int in_use_globally;
typedef map<fstring,tb_featuredesire*> name_featuredesire_map; typedef map<fstring,tb_featuredesire*> name_featuredesire_map;
static name_featuredesire_map featuredesires_by_name; static name_featuredesire_map featuredesires_by_name;
/*
* Policies for using features and desires with the name. NOTE: Only
* feature policies implemented yet, as they are easier to check for.
*/
tb_featuredesire_policy feature_policy;
tb_featuredesire_policy desire_policy;
/*
* Some simple bookkeeping stuff, currently only used to enforce
* policies.
*/
int desire_users;
double desire_total_weight;
}; };
/* /*
...@@ -141,6 +218,9 @@ class tb_node_featuredesire { ...@@ -141,6 +218,9 @@ class tb_node_featuredesire {
const bool is_l_additive() const { const bool is_l_additive() const {
return featuredesire_obj->is_l_additive(); return featuredesire_obj->is_l_additive();
} }
void add_desire_user(double weight) const {
featuredesire_obj->add_desire_user(weight);
}
score_and_violations add_global_user() const; score_and_violations add_global_user() const;
score_and_violations remove_global_user() const; score_and_violations remove_global_user() const;
......
...@@ -16,7 +16,7 @@ by Ricci, Alfeld, and Lepreau about assign. ...@@ -16,7 +16,7 @@ by Ricci, Alfeld, and Lepreau about assign.
##### ptop (physical topology) file ##### ptop (physical topology) file
ptop file: <line>* ptop file: <line>*
<line> ::= <node_line> | <link_line> | <type_limit_line> <line> ::= <node_line> | <link_line> | <type_limit_line> | <policy_line>
<node_line> ::= node <node_name> <node_type>+ [- <feature>* [- <flag>* ]] <node_line> ::= node <node_name> <node_type>+ [- <feature>* [- <flag>* ]]
<node_type> ::= "*"?<type_name>:<type_count> <node_type> ::= "*"?<type_name>:<type_count>
...@@ -30,6 +30,9 @@ ptop file: <line>* ...@@ -30,6 +30,9 @@ ptop file: <line>*
<type_limit_line> ::= set-type-limit <node_type> <int> <type_limit_line> ::= set-type-limit <node_type> <int>
<policy_line> ::= policy <desire_policy>
<desire_policy> ::= desire <feature_name> ( disallow | limit <float> )
Interpretation: Interpretation:
<node_line> - though a node can have several types that it can satisfy, it is <node_line> - though a node can have several types that it can satisfy, it is
...@@ -79,6 +82,10 @@ Interpretation: ...@@ -79,6 +82,10 @@ Interpretation:
file. The other two portions are mostly ignored. file. The other two portions are mostly ignored.
<type_limit_line> - used to enforce Emulab policies: ie. this experiment is <type_limit_line> - used to enforce Emulab policies: ie. this experiment is
not allowed to use more than 10 pc3000 nodes not allowed to use more than 10 pc3000 nodes
<policy_line> - used to indicate policies for mapping the experiment. The only
policies currently supported are 'desire' policies, which can be used to
disallow the top file from requesting a particular desire, or limit the
total weight that can be given to a desire
##### top (virtual topology) file ##### top (virtual topology) file
......
...@@ -321,6 +321,7 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i) ...@@ -321,6 +321,7 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
#endif #endif
} }
} }
} else if (command == "set-type-limit") { } else if (command == "set-type-limit") {
if (parsed_line.size() != 3) { if (parsed_line.size() != 3) {
ptop_error("Bad set-type-limit line, requires two arguments."); ptop_error("Bad set-type-limit line, requires two arguments.");
...@@ -337,7 +338,36 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i) ...@@ -337,7 +338,36 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
} }
ptypes[type]->set_max_users(max); ptypes[type]->set_max_users(max);
} else if (command == "policy") {
if (parsed_line.size() < 3) {
ptop_error("No policy type given.");
} else {
if (parsed_line[1] == "desire") {
fstring desire = parsed_line[2];
fstring type = parsed_line[3];
tb_featuredesire *fd_obj =
tb_featuredesire::get_featuredesire_obj(desire);
if (type == "disallow") {
fd_obj->disallow_desire();
} else if (type == "limit") {
if (parsed_line.size() != 5) {
ptop_error("Missing desire limit");
} else {
double limit;
if (sscanf(parsed_line[4].c_str(),"%lf",&limit) != 1) {
ptop_error("Malformed desire limit");
} else {
fd_obj->limit_desire(limit);
}
}
} else {
ptop_error("Unknown policy for desire");
}
} else {
ptop_error("Only desire policies are supported.");
}
}
} else { } else {
ptop_error("Unknown directive: " << command << "."); ptop_error("Unknown directive: " << command << ".");
} }
......
...@@ -152,8 +152,9 @@ int parse_top(tb_vgraph &VG, istream& i) ...@@ -152,8 +152,9 @@ int parse_top(tb_vgraph &VG, istream& i)
top_error("Bad desire, bad weight."); top_error("Bad desire, bad weight.");
gweight = 0; gweight = 0;
} }
v->desires.push_front( tb_node_featuredesire node_fd(desirename, gweight);
tb_node_featuredesire(desirename,gweight)); node_fd.add_desire_user(gweight);
v->desires.push_front(node_fd);
} }
} }
} }
......
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