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

7 8 9 10
#include "port.h"

#include <boost/graph/adjacency_list.hpp>

11 12 13
#include <iostream>

#include <stdio.h>
14 15 16 17

using namespace boost;

#include "delay.h"
18
#include "physical.h"
19
#include "parser.h"
20

21 22 23
#include <string>
using namespace std;

24 25
extern name_pvertex_map pname2vertex;

26
#define ptop_error(s) errors++;cout << "PTOP:" << line << ": " << s << endl; exit(EXIT_FATAL)
27
#define ptop_error_noline(s) errors++;cout << "PTOP: " << s << endl
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

// Used to do late binding of subnode names to pnodes, so that we're no
// dependant on their ordering in the ptop file, which can be annoying to get
// right.
// Returns the number of errors found
int bind_ptop_subnodes() {
    int errors = 0;

    // Iterate through all pnodes looking for ones that are subnodes
    pvertex_iterator vit,vendit;
    tie(vit,vendit) = vertices(PG);
    for (;vit != vendit;++vit) {
	tb_pnode *pnode = get(pvertex_pmap,*vit);
	if (!pnode->subnode_of_name.empty()) {
	    if (pname2vertex.find(pnode->subnode_of_name) ==
		    pname2vertex.end()) {
		ptop_error_noline(pnode->name << " is a subnode of a " <<
			"non-existent node, " << pnode->subnode_of_name << ".");
			continue;
		}
		pvertex parent_pv = pname2vertex[pnode->subnode_of_name];
		pnode->subnode_of = get(pvertex_pmap,parent_pv);
		pnode->subnode_of->has_subnode = true;
	}
    }

    return errors;
}
56

57
int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
58
{
59 60
  int num_nodes = 0;
  int line=0,errors=0;
61
  char inbuf[16384];
62 63
  string_vector parsed_line;

64
  while (!i.eof()) {
65
    line++;
66
    i.getline(inbuf,16384);
67 68 69
    parsed_line = split_line(inbuf,' ');
    if (parsed_line.size() == 0) {continue;}

70
    string command = parsed_line[0];
71

72
    if (command == "node") {
73 74
      if (parsed_line.size() < 3) {
	ptop_error("Bad node line, too few arguments.");
75
      } else {
76
	num_nodes++;
77
	fstring name = parsed_line[1];
78 79
	bool isswitch = false;
	pvertex pv = add_vertex(PG);
80
	tb_pnode *p = new tb_pnode(name);
81 82 83 84 85
	put(pvertex_pmap,pv,p);
	
	unsigned int i;
	for (i = 2;
	     (i < parsed_line.size()) &&
86 87 88 89
	       (parsed_line[i] != "-");++i) {
	  string stype,load;
	  if (split_two(parsed_line[i],':',stype,load,"1") != 0) {
	    ptop_error("Bad node line, no load for type: " << stype << ".");
90
	  }
91
          fstring type(stype);
92 93 94 95 96 97
	  // Check to see if this is a static type
	  bool is_static = false;
	  if (type[0] == '*') {
	    is_static = true;
	    type.pop_front();
	  }
98
	  int iload;
99 100
	  if (load == "*") { // Allow * to mean unlimited
            // (okay, a really big number)
101
	    iload = 10000;
102
	  } else if (sscanf(load.c_str(),"%d",&iload) != 1) {
103 104
	    ptop_error("Bad node line, bad load: " << load << ".");
	    iload = 1;
105
	  }
106 107 108 109 110

	  /*
	   * Make a tb_ptype structure for this guy - or just add this node to
	   * it if it already exists
	   */
111
	  if (ptypes.find(type) == ptypes.end()) {
112
	      ptypes[type] = new tb_ptype(type);
113
	  }
114 115 116
	  ptypes[type]->add_slots(iload);
	  tb_ptype *ptype = ptypes[type];

117
	  if (type == "switch") {
118
	    isswitch = true;
119
	    p->is_switch = true;
120
	    p->types["switch"] = new tb_pnode::type_record(1,false,ptype);
121 122 123 124 125
	    svertex sv = add_vertex(SG);
	    tb_switch *s = new tb_switch();
	    put(svertex_pmap,sv,s);
	    s->mate = pv;
	    p->sgraph_switch = sv;
126
	    p->switches.insert(pv);
127
	  } else {
128
	    p->types[type] = new tb_pnode::type_record(iload,is_static,ptype);
129
	  }
130
	  p->type_list.push_back(p->types[type]);
131
	}
132 133 134
	for (i=i+1;(i<parsed_line.size()) && (parsed_line[i] != "-") ;++i) {
	  string sfeature,cost;
	  if (split_two(parsed_line[i],':',sfeature,cost,"0") != 0) {
135
	    ptop_error("Bad node line, no cost for feature: " <<
136
		       sfeature << ".");
137
	  }
138 139
      fstring feature(sfeature);

140 141 142 143
	  double gcost;
	  if (sscanf(cost.c_str(),"%lg",&gcost) != 1) {
	    ptop_error("Bad node line, bad cost: " << gcost << ".");
	    gcost = 0;
144
	  }
145 146 147

	  p->features.push_front(tb_node_featuredesire(feature,gcost));

148
	}
149
	/*
150
	 * Parse any other node options or flags
151 152
	 */
	for (i=i+1; i < parsed_line.size(); ++i) {
153
	    string flag,value;
154
	    split_two(parsed_line[i],':',flag,value,"(null)");
155
	    if (flag == "trivial_bw") {
156
		// Handle trivial bandwidth spec
157 158 159 160 161 162 163
		int trivial_bw;
		if (sscanf(value.c_str(),"%i",&trivial_bw) != 1) {
		    ptop_error("Bad bandwidth given for trivial_bw: " << value
			    << endl);
		    trivial_bw = 0;
		}
		p->trivial_bw = trivial_bw;
164
	    } else if (flag == "subnode_of") {
165 166 167 168 169 170 171 172 173
		// Handle subnode relationships
		if (!p->subnode_of_name.empty()) {
		    ptop_error("Can't be a subnode of two nodes");
		    continue;
		} else {
		    // Just store the name for now, we'll do late binding to
		    // an actual pnode later
		    p->subnode_of_name = value;
		}
174
	    } else if (flag == "unique") {
175 176 177
		// Means that we should never put this pnode into a ptype with
		// other pnodes
		p->unique = true;
178 179 180 181
	    } else {
		ptop_error("Bad flag given: " << flag << ".");
	    }
	}
182
	p->features.sort();
183
	pname2vertex[name] = pv;
184
      }
185
    } else if (command == "link") {
186
      if (parsed_line.size() < 8) {
187 188 189 190 191
	ptop_error("Bad link line, too few arguments.");
      }
      int num = 1;
#ifdef PENALIZE_BANDWIDTH
      float penalty;
192 193 194
      if (parsed_line.size() == 9) {
	if (sscanf(parsed_line[8].c_str(),"%f",&penalty) != 1) {
	  ptop_error("Bad number argument: " << parsed_line[8] << ".");
195
	  penalty=1.0;
196
	}
197 198 199
      }
#endif

200
#if 0
201
#ifdef FIX_PLINK_ENDPOINTS
Robert Ricci's avatar
Robert Ricci committed
202 203 204 205 206 207
      bool fixends;
#ifdef FIX_PLINKS_DEFAULT
      fixends = true;
#else
      fixends = false;
#endif
208
      if (parsed_line.size() == 10) {
209
	  if (parsed_line[9] == "fixends") {
210 211 212 213
	      fixends = true;
	  }
      }
#else
214
      if (parsed_line.size() > 9) {
215 216 217
	ptop_error("Bad link line, too many arguments.");
      }
#endif
218 219
#endif

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
      fstring name = parsed_line[1];
      string ssrc,ssrcmac;
      split_two(parsed_line[2],':',ssrc,ssrcmac,"(null)");
      string ssrcn, ssrciface;
      split_two(ssrcmac,'/',ssrcn,ssrciface,"(null)");
      fstring src = ssrc;
      fstring srcmac = ssrcmac;
      fstring srciface = ssrciface;
      string sdst,sdstmac;
      split_two(parsed_line[3],':',sdst,sdstmac,"(null)");
      string sdstn, sdstiface;
      split_two(sdstmac,'/',sdstn,sdstiface,"(null)");
      fstring dst(sdst), dstmac(sdstmac), dstiface(sdstiface);
      string bw = parsed_line[4];
      string delay = parsed_line[5];
      string loss = parsed_line[6];
      fstring link_type = parsed_line[7];
237 238 239 240 241 242 243 244 245 246
      int ibw,idelay;
      double gloss;

      
      if ((sscanf(bw.c_str(),"%d",&ibw) != 1) ||
	  (sscanf(delay.c_str(),"%d",&idelay) != 1) ||
	  (sscanf(loss.c_str(),"%lg",&gloss) != 1)) {
	ptop_error("Bad link line, bad delay characteristics.");
      }

247 248 249 250
      if (ibw <= 0) {
          ptop_error("Bad link line - negative or zero bandwidth.");
      }

251
#define ISSWITCH(n) (n->types.find("switch") != n->types.end())
252 253
      // Check to make sure the nodes in the link actually exist
      if (pname2vertex.find(src) == pname2vertex.end()) {
254
	  ptop_error("Bad link line, non-existent src node " << src);
255 256 257
	  continue;
      }
      if (pname2vertex.find(dst) == pname2vertex.end()) {
258
	  ptop_error("Bad link line, non-existent dst node " << dst);
259 260 261
	  continue;
      }

262 263 264 265 266 267 268
      pvertex srcv = pname2vertex[src];
      pvertex dstv = pname2vertex[dst];
      tb_pnode *srcnode = get(pvertex_pmap,srcv);
      tb_pnode *dstnode = get(pvertex_pmap,dstv);
      
      for (int cur = 0;cur<num;++cur) {
	pedge pe = (add_edge(srcv,dstv,PG)).first;
269
	tb_plink *pl = new
270 271
	    tb_plink(name,tb_plink::PLINK_NORMAL,link_type,src,dst,
                    srcmac,dstmac, srciface,dstiface);
272 273 274 275
	put(pedge_pmap,pe,pl);
	pl->delay_info.bandwidth = ibw;
	pl->delay_info.delay = idelay;
	pl->delay_info.loss = gloss;
276
#if 0
277 278 279
#ifdef FIX_PLINK_ENDPOINTS
	pl->fixends = fixends;
#endif
280
#endif
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
#ifdef PENALIZE_BANDWIDTH
	pl->penalty = penalty;
#endif
	if (ISSWITCH(srcnode) && ISSWITCH(dstnode)) {
	  if (cur != 0) {
	    cout <<
	      "Warning: Extra links between switches will be ignored. (" <<
	      name << ")" << endl;
	  } else {
	    svertex src_switch = get(pvertex_pmap,srcv)->sgraph_switch;
	    svertex dst_switch = get(pvertex_pmap,dstv)->sgraph_switch;
	    sedge swedge = add_edge(src_switch,dst_switch,SG).first;
	    tb_slink *sl = new tb_slink();
	    put(sedge_pmap,swedge,sl);
	    sl->mate = pe;
296
	    pl->is_type = tb_plink::PLINK_INTERSWITCH;
297
	  }
298
	}
299 300
	srcnode->total_interfaces++;
	dstnode->total_interfaces++;
301 302 303
	srcnode->link_counts[link_type]++;
	dstnode->link_counts[link_type]++;
	for (int i = 8; i < parsed_line.size(); i++) {
304
	  fstring link_type = parsed_line[i];
305 306 307 308
	  pl->types.insert(link_type);
	  srcnode->link_counts[link_type]++;
	  dstnode->link_counts[link_type]++;
	}
309 310 311
	if (ISSWITCH(srcnode) &&
	    ! ISSWITCH(dstnode)) {
	  dstnode->switches.insert(srcv);
312 313 314
#ifdef PER_VNODE_TT
	  dstnode->total_bandwidth += ibw;
#endif
315 316 317 318
	}
	else if (ISSWITCH(dstnode) &&
		 ! ISSWITCH(srcnode)) {
	  srcnode->switches.insert(dstv);
319 320 321
#ifdef PER_VNODE_TT
	  srcnode->total_bandwidth += ibw;
#endif
322
	}
323
      }
324

325
    } else if (command == "set-type-limit") {
326 327 328
      if (parsed_line.size() != 3) {
	ptop_error("Bad set-type-limit line, requires two arguments.");
      }
329
      fstring type = parsed_line[1];
330 331 332 333 334 335 336 337 338 339 340
      int max;
      if (sscanf(parsed_line[2].c_str(),"%u",&max) != 1) {
	  ptop_error("Bad number argument: " << parsed_line[2] << ".");
      }

      // Look for a record for this ptype - create it if it doesn't exist
      if (ptypes.find(type) == ptypes.end()) {
	  ptypes[type] = new tb_ptype(type);
      }

      ptypes[type]->set_max_users(max);
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
     } 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."); 
 	    }
 	}
 	
371
    } else {
372
      ptop_error("Unknown directive: " << command << ".");
373 374
    }
  }
375

376 377
  errors += bind_ptop_subnodes();

378
  if (errors > 0) {exit(EXIT_FATAL);}
379 380
  
  return num_nodes;
381 382
}