parse_top.cc 10.8 KB
Newer Older
Robert Ricci's avatar
Robert Ricci committed
1 2
/*
 * EMULAB-COPYRIGHT
Robert Ricci's avatar
Robert Ricci committed
3
 * Copyright (c) 2000-2010 University of Utah and the Flux Group.
Robert Ricci's avatar
Robert Ricci committed
4 5 6
 * All rights reserved.
 */

7 8
static const char rcsid[] = "$Id: parse_top.cc,v 1.42 2009-05-20 18:06:08 tarunp Exp $";

9
#include "port.h"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
10

11 12
#include <boost/config.hpp>
#include <boost/utility.hpp>
13
#include BOOST_PMAP_HEADER
14 15
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
Mac Newbold's avatar
Mac Newbold committed
16

17 18 19
#include <iostream>

#include <stdio.h>
20 21

using namespace boost;
Mac Newbold's avatar
Mac Newbold committed
22 23

#include "common.h"
24
#include "vclass.h"
25 26
#include "delay.h"
#include "physical.h"
Mac Newbold's avatar
Mac Newbold committed
27
#include "virtual.h"
28
#include "parser.h"
29
#include "anneal.h"
30
#include "string.h"
Mac Newbold's avatar
Mac Newbold committed
31

32 33
extern name_vvertex_map vname2vertex;
extern name_name_map fixed_nodes;
Robert Ricci's avatar
Robert Ricci committed
34
extern name_name_map node_hints;
35
extern name_count_map vtypes;
36
extern name_list_map vclasses;
37
extern vvertex_vector virtual_nodes;
Mac Newbold's avatar
Mac Newbold committed
38

39 40
#define top_error(s) errors++;cout << "TOP:" << line << ": " << s << endl
#define top_error_noline(s) errors++;cout << "TOP: " << s << endl
41 42 43 44 45

// Used to do late binding of subnode names to vnodes, so that we're no
// dependant on their ordering in the top file, which can be annoying to get
// right.
// Returns the number of errors found
46
int bind_top_subnodes(tb_vgraph &vg) {
47 48 49 50
    int errors = 0;

    // Iterate through all vnodes looking for ones that are subnodes
    vvertex_iterator vit,vendit;
51
    tie(vit,vendit) = vertices(vg);
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
    for (;vit != vendit;++vit) {
	tb_vnode *vnode = get(vvertex_pmap, *vit);
	if (!vnode->subnode_of_name.empty()) {
	    if (vname2vertex.find(vnode->subnode_of_name)
		    == vname2vertex.end()) {
		top_error_noline(vnode->name << " is a subnode of a " <<
			"non-existent node, " << vnode->subnode_of_name << ".");
		continue;
	    }
	    vvertex parent_vv = vname2vertex[vnode->subnode_of_name];
	    vnode->subnode_of = get(vvertex_pmap,parent_vv);
	    vnode->subnode_of->subnodes.push_back(vnode);
	}
    }

    return errors;
}
Mac Newbold's avatar
Mac Newbold committed
69

70 71
extern name_vclass_map vclass_map;

72
int parse_top(tb_vgraph &vg, istream& input)
Mac Newbold's avatar
Mac Newbold committed
73
{
74 75
  string_vector parsed_line;
  int errors=0,line=0;
Mac Newbold's avatar
Mac Newbold committed
76
  int num_nodes = 0;
77
  char inbuf[1024];
Mac Newbold's avatar
Mac Newbold committed
78
  
79
  while (!input.eof()) {
80
    line++;
81
    input.getline(inbuf,1024);
82 83 84
    parsed_line = split_line(inbuf,' ');
    if (parsed_line.size() == 0) {continue;}

85
    string command = parsed_line[0];
86

87
    if (command == string("node")) {
88 89
      if (parsed_line.size() < 3) {
	top_error("Bad node line, too few arguments.");
Mac Newbold's avatar
Mac Newbold committed
90
      } else {
91 92
	string name = parsed_line[1];
	string unparsed_type = parsed_line[2];
93 94

	// Type might now a have a 'number of slots' assoicated with it
95 96
	string type;
	string typecount_str;
97 98 99 100 101 102 103 104
	split_two(unparsed_type,':',type,typecount_str,"1");

	int typecount;
	if (sscanf(typecount_str.c_str(),"%i",&typecount) != 1) {
	    top_error("Bad type slot count.");
	    typecount = 1;
	}

Mac Newbold's avatar
Mac Newbold committed
105
	num_nodes++;
106 107
        tb_vclass *vclass;
	
108 109
	name_vclass_map::iterator dit = vclass_map.find(type);
	if (dit != vclass_map.end()) {
110 111
	  type = "";
	  vclass = (*dit).second;
112
	} else {
113 114 115
	  vclass = NULL;
	  if (vtypes.find(type) == vtypes.end()) {
	      vtypes[type] = typecount;
116
	  } else {
117
	      vtypes[type] += typecount;
118
	  }
119
	}
120 121 122 123 124 125 126

	tb_vnode *v = new tb_vnode(name,type,typecount);
	v->vclass = vclass;
	vvertex vv = add_vertex(vg);
	vname2vertex[name] = vv;
	virtual_nodes.push_back(vv);
	put(vvertex_pmap,vv,v);
127
	
128
	for (unsigned int i = 3;i < parsed_line.size();++i) {
129
	  string desirename,desireweight;
130
	  if (split_two(parsed_line[i],':',desirename,desireweight,"0") == 1) {
131
	      // It must be a flag?
132
	      if (parsed_line[i] == string("disallow_trivial_mix")) {
133 134 135 136 137
		  v->disallow_trivial_mix = true;
	      } else {
		  top_error("Unknown flag or bad desire (missing weight)");
	      }
	  } else {
138
	      if (desirename == string("subnode_of")) {
139
		  // Okay, it's not a desire, it's a subnode declaration
140
		  if (!v->subnode_of_name.empty()) {
141 142 143
		      top_error("Can only be a subnode of one node");
		      continue;
		  }
144
		  v->subnode_of_name = desireweight;
145 146 147 148 149 150 151

	      } else {
		  double gweight;
		  if (sscanf(desireweight.c_str(),"%lg",&gweight) != 1) {
		      top_error("Bad desire, bad weight.");
		      gweight = 0;
		  }
152 153 154
		  tb_node_featuredesire node_fd(desirename, gweight);
		  node_fd.add_desire_user(gweight);
		  v->desires.push_front(node_fd);
155
	      }
156 157
	  }
	}
158
	v->desires.sort();
Mac Newbold's avatar
Mac Newbold committed
159
      }
160
    } else if (command == string("link")) {
161
      if (parsed_line.size() < 8) {
162
	top_error("Bad link line, too few arguments.");
Mac Newbold's avatar
Mac Newbold committed
163
      } else {
164 165 166 167 168 169 170 171
	string name = parsed_line[1];
	string src = parsed_line[2];
	string dst = parsed_line[3];
	string link_type = parsed_line[7];
	string bw,bwunder,bwover;
	string delay,delayunder,delayover;
	string loss,lossunder,lossover;
	string bwweight,delayweight,lossweight;
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
	string_vector parsed_delay,parsed_bw,parsed_loss;
	parsed_bw = split_line(parsed_line[4],':');
	bw = parsed_bw[0];
	if (parsed_bw.size() == 1) {
	  bwunder = "0";
	  bwover = "0";
	  bwweight = "1";
	} else if (parsed_bw.size() == 3) {
	  bwunder = parsed_bw[1];
	  bwover = parsed_bw[2];
	  bwweight = "1";
	} else if (parsed_bw.size() == 4) {
	  bwunder = parsed_bw[1];
	  bwover = parsed_bw[2];
	  bwweight = parsed_bw[3];
187
	} else {
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
	  top_error("Bad link line, bad bandwidth specifier.");
	}
	parsed_delay = split_line(parsed_line[5],':');
	delay = parsed_delay[0];
	if (parsed_delay.size() == 1) {
	  delayunder = "0";
	  delayover = "0";
	  delayweight = "1";
	} else if (parsed_delay.size() == 3) {
	  delayunder = parsed_delay[1];
	  delayover = parsed_delay[2];
	  delayweight = "1";
	} else if (parsed_delay.size() == 4) {
	  delayunder = parsed_delay[1];
	  delayover = parsed_delay[2];
	  delayweight = parsed_delay[3];
	} else {
	  top_error("Bad link line, bad delay specifier.");
	}
	parsed_loss = split_line(parsed_line[6],':');
	loss = parsed_loss[0];
	if (parsed_loss.size() == 1) {
	  lossunder = "0";
	  lossover = "0";
	  lossweight = "1";
	} else if (parsed_loss.size() == 3) {
	  lossunder = parsed_loss[1];
	  lossover = parsed_loss[2];
	  lossweight = "1";
	} else if (parsed_loss.size() == 4) {
	  lossunder = parsed_loss[1];
	  lossover = parsed_loss[2];
	  lossweight = parsed_loss[4];
	} else {
	  top_error("Bad link line, bad loss specifier.");
	}

	vedge e;
226 227 228 229 230 231 232 233 234 235
	// Check to make sure the nodes in the link actually exist
	if (vname2vertex.find(src) == vname2vertex.end()) {
	  top_error("Bad link line, non-existent node.");
	  continue;
	}
	if (vname2vertex.find(dst) == vname2vertex.end()) {
	  top_error("Bad link line, non-existent node.");
	  continue;
	}

236 237
	vvertex node1 = vname2vertex[src];
	vvertex node2 = vname2vertex[dst];
238
	e = add_edge(node1,node2,vg).first;
239 240 241
	tb_vlink *l = new tb_vlink();
	l->src = node1;
	l->dst = node2;
242
	l->type = link_type;
243 244
	put(vedge_pmap,e,l);

245 246
        // Special flag: treat a bandwidth of '*' specially
        if (!strcmp(bw.c_str(),"*")) {
247
            l->delay_info.bandwidth = -2; // Special flag
248 249 250 251 252 253 254 255 256
            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) ||
257 258 259 260 261 262 263 264 265 266 267 268
	    (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) ||
	    (sscanf(delayunder.c_str(),"%d",&(l->delay_info.delay_under)) != 1) ||
	    (sscanf(delayover.c_str(),"%d",&(l->delay_info.delay_over)) != 1) ||
	    (sscanf(delayweight.c_str(),"%lg",&(l->delay_info.delay_weight)) != 1) ||
	    (sscanf(loss.c_str(),"%lg",&(l->delay_info.loss)) != 1) ||
	    (sscanf(lossunder.c_str(),"%lg",&(l->delay_info.loss_under)) != 1) ||
	    (sscanf(lossover.c_str(),"%lg",&(l->delay_info.loss_over)) != 1) ||
	    (sscanf(lossweight.c_str(),"%lg",&(l->delay_info.loss_weight)) != 1)) {
	  top_error("Bad line line, bad delay characteristics.");
	}
Robert Ricci's avatar
Robert Ricci committed
269
	l->no_connection = true;
270 271
	l->name = name;
	l->allow_delayed = true;
272 273 274 275 276
#ifdef ALLOW_TRIVIAL_DEFAULT
	l->allow_trivial = true;
#else
	l->allow_trivial = false;
#endif
277
	l->emulated = false;
278 279 280
	l->fix_src_iface = false;
	l->fix_dst_iface = false;
		
281
	for (unsigned int i = 8;i < parsed_line.size();++i) {
282 283 284
	  string stag, svalue;
	  split_two(parsed_line[i],':',stag,svalue,"");
	  if (parsed_line[i] == string("nodelay")) {
285
	    l->allow_delayed = false;
286
	  } else if (parsed_line[i] == string("emulated")) {
287
	    l->emulated = true;
288
	  } else if (parsed_line[i] == string("trivial_ok")) {
289
	    l->allow_trivial = true;
290 291 292 293 294 295
	  } else if (stag == string("fixsrciface")) {
            l->fix_src_iface = true;
	    l->src_iface = svalue;
    	  } else if (stag == string("fixdstiface")) {
            l->fix_dst_iface = true;
	    l->dst_iface = svalue;
296 297 298 299
	  } else {
	    top_error("bad link line, unknown tag: " <<
		      parsed_line[i] << ".");
	  }
300
	}
301

302 303
	tb_vnode *vnode1 = get(vvertex_pmap,node1);
	tb_vnode *vnode2 = get(vvertex_pmap,node2);
304
#ifdef PER_VNODE_TT
305
	if (l->emulated) {
306 307 308 309
	    if (!l->allow_trivial) {
		vnode1->total_bandwidth += l->delay_info.bandwidth;
		vnode2->total_bandwidth += l->delay_info.bandwidth;
	    }
310 311 312
	} else {
	    vnode1->num_links++;
	    vnode2->num_links++;
313 314
	    vnode1->link_counts[link_type]++;
	    vnode2->link_counts[link_type]++;
315 316
	}
#endif
317 318 319 320 321 322 323 324
        
        // 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!");
        }
	
325
      }
326
    } else if (command == string("make-vclass")) {
327 328
      if (parsed_line.size() < 4) {
	top_error("Bad vclass line, too few arguments.");
329
      } else {
330 331
	string name = parsed_line[1];
	string weight = parsed_line[2];
332 333 334 335
	double gweight;
	if (sscanf(weight.c_str(),"%lg",&gweight) != 1) {
	  top_error("Bad vclass line, invalid weight.");
	  gweight = 0;
336
	}
337 338 339 340 341
	
	tb_vclass *v = new tb_vclass(name,gweight);
	vclass_map[name] = v;
	for (unsigned int i = 3;i<parsed_line.size();++i) {
	  v->add_type(parsed_line[i]);
342
	  vclasses[name].push_back(parsed_line[i]);
343
	}
344
      }
345
    } else if (command == string("fix-node")) {
346 347 348
      if (parsed_line.size() != 3) {
	top_error("Bad fix-node line, wrong number of arguments.");
      } else {
349 350
	string virtualnode = parsed_line[1];
	string physicalnode = parsed_line[2];
351 352
	fixed_nodes[virtualnode] = physicalnode;
      }
353
    } else if (command == string("node-hint")) {
Robert Ricci's avatar
Robert Ricci committed
354 355 356
      if (parsed_line.size() != 3) {
	top_error("Bad node-hint line, wrong number of arguments.");
      } else {
357 358
	string virtualnode = parsed_line[1];
	string physicalnode = parsed_line[2];
Robert Ricci's avatar
Robert Ricci committed
359 360
	node_hints[virtualnode] = physicalnode;
      }
361
    } else {
362
      top_error("Unknown directive: " << command << ".");
Mac Newbold's avatar
Mac Newbold committed
363 364
    }
  }
365

366
  errors += bind_top_subnodes(vg);
367

368
  if (errors > 0) {exit(EXIT_FATAL);}
369
  
Mac Newbold's avatar
Mac Newbold committed
370 371
  return num_nodes;
}