A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
rocketfuel-topology-reader.cc
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2010 Hajime Tazaki
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Hajime Tazaki (tazaki@sfc.wide.ad.jp)
19  */
20 
21 #include <fstream>
22 #include <cstdlib>
23 #include <iostream>
24 #include <sstream>
25 #include <regex.h>
26 
27 #include "ns3/log.h"
28 #include "ns3/unused.h"
29 #include "rocketfuel-topology-reader.h"
30 
31 namespace ns3 {
32 
33 NS_LOG_COMPONENT_DEFINE ("RocketfuelTopologyReader");
34 
35 NS_OBJECT_ENSURE_REGISTERED (RocketfuelTopologyReader);
36 
37 TypeId RocketfuelTopologyReader::GetTypeId (void)
38 {
39  static TypeId tid = TypeId ("ns3::RocketfuelTopologyReader")
40  .SetParent<Object> ()
41  ;
42  return tid;
43 }
44 
45 RocketfuelTopologyReader::RocketfuelTopologyReader ()
46 {
47  NS_LOG_FUNCTION (this);
48 }
49 
50 RocketfuelTopologyReader::~RocketfuelTopologyReader ()
51 {
52  NS_LOG_FUNCTION (this);
53 }
54 
55 /* uid @loc [+] [bb] (num_neigh) [&ext] -> <nuid-1> <nuid-2> ... {-euid} ... =name[!] rn */
56 
57 #define REGMATCH_MAX 16
58 
59 #define START "^"
60 #define END "$"
61 #define SPACE "[ \t]+"
62 #define MAYSPACE "[ \t]*"
63 
64 #define ROCKETFUEL_MAPS_LINE \
65  START "(-*[0-9]+)" SPACE "(@[?A-Za-z0-9,+]+)" SPACE \
66  "(\\+)*" MAYSPACE "(bb)*" MAYSPACE \
67  "\\(([0-9]+)\\)" SPACE "(&[0-9]+)*" MAYSPACE \
68  "->" MAYSPACE "(<[0-9 \t<>]+>)*" MAYSPACE \
69  "(\\{-[0-9\\{\\} \t-]+\\})*" SPACE \
70  "=([A-Za-z0-9.!-]+)" SPACE "r([0-9])" \
71  MAYSPACE END
72 
73 #define ROCKETFUEL_WEIGHTS_LINE \
74  START "([^ \t]+)" SPACE "([^ \t]+)" SPACE "([0-9.]+)" MAYSPACE END
75 
76 int linksNumber = 0;
77 int nodesNumber = 0;
78 std::map<std::string, Ptr<Node> > nodeMap;
79 
80 static inline void
81 PrintNodeInfo (std::string & uid, std::string & loc, bool dns, bool bb,
82  std::vector <std::string>::size_type neighListSize,
83  std::string & name, int radius)
84 {
85  /* uid @loc [+] [bb] (num_neigh) [&ext] -> <nuid-1> <nuid-2> ... {-euid} ... =name[!] rn */
86  NS_LOG_INFO ("Load Node[" << uid << "]: location: " << loc << " dns: " << dns
87  << " bb: " << bb << " neighbors: " << neighListSize
88  << "(" << "%d" << ") externals: \"%s\"(%d) "
89  << "name: " << name << " radius: " << radius);
90 }
91 
92 NodeContainer
93 RocketfuelTopologyReader::GenerateFromMapsFile (int argc, char *argv[])
94 {
95  std::string uid;
96  std::string loc;
97  std::string ptr;
98  std::string name;
99  std::string nuid;
100  bool dns = false;
101  bool bb = false;
102  int num_neigh_s = 0;
103  unsigned int num_neigh = 0;
104  int radius = 0;
105  std::vector <std::string> neigh_list;
106  NodeContainer nodes;
107 
108  uid = argv[0];
109  loc = argv[1];
110 
111  if (argv[2])
112  {
113  dns = true;
114  }
115 
116  if (argv[3])
117  {
118  bb = true;
119  }
120 
121  num_neigh_s = ::atoi (argv[4]);
122  if (num_neigh_s < 0)
123  {
124  num_neigh = 0;
125  NS_LOG_WARN ("Negative number of neighbors given");
126  }
127  else
128  {
129  num_neigh = num_neigh_s;
130  }
131 
132  /* neighbors */
133  if (argv[6])
134  {
135  char *nbr;
136  char *stringp = argv[6];
137  while ((nbr = strsep (&stringp, " \t")) != NULL)
138  {
139  nbr[strlen (nbr) - 1] = '\0';
140  neigh_list.push_back (nbr + 1);
141  }
142  }
143  if (num_neigh != neigh_list.size ())
144  {
145  NS_LOG_WARN ("Given number of neighbors = " << num_neigh << " != size of neighbors list = " << neigh_list.size ());
146  }
147 
148  /* externs */
149  if (argv[7])
150  {
151  // euid = argv[7];
152  }
153 
154  /* name */
155  if (argv[8])
156  {
157  name = argv[8];
158  }
159 
160  radius = ::atoi (&argv[9][1]);
161  if (radius > 0)
162  {
163  return nodes;
164  }
165 
166  PrintNodeInfo (uid, loc, dns, bb, neigh_list.size (), name, radius);
167 
168  // Create node and link
169  if (!uid.empty ())
170  {
171  if (nodeMap[uid] == 0)
172  {
173  Ptr<Node> tmpNode = CreateObject<Node> ();
174  nodeMap[uid] = tmpNode;
175  nodes.Add (tmpNode);
176  nodesNumber++;
177  }
178 
179  for (uint32_t i = 0; i < neigh_list.size (); ++i)
180  {
181  nuid = neigh_list[i];
182 
183  if (nuid.empty ())
184  {
185  return nodes;
186  }
187 
188  if (nodeMap[nuid] == 0)
189  {
190  Ptr<Node> tmpNode = CreateObject<Node> ();
191  nodeMap[nuid] = tmpNode;
192  nodes.Add (tmpNode);
193  nodesNumber++;
194  }
195  NS_LOG_INFO (linksNumber << ":" << nodesNumber << " From: " << uid << " to: " << nuid);
196  Link link (nodeMap[uid], uid, nodeMap[nuid], nuid);
197  AddLink (link);
198  linksNumber++;
199  }
200  }
201  return nodes;
202 }
203 
204 NodeContainer
205 RocketfuelTopologyReader::GenerateFromWeightsFile (int argc, char *argv[])
206 {
207  /* uid @loc [+] [bb] (num_neigh) [&ext] -> <nuid-1> <nuid-2> ... {-euid} ... =name[!] rn */
208  std::string sname;
209  std::string tname;
210  char *endptr;
211  NodeContainer nodes;
212 
213  sname = argv[0];
214  tname = argv[1];
215  double v = strtod (argv[2], &endptr); // weight
216  NS_UNUSED (v); // suppress "set but not used" compiler warning in optimized builds
217  if (*endptr != '\0')
218  {
219  NS_LOG_WARN ("invalid weight: " << argv[2]);
220  return nodes;
221  }
222 
223  // Create node and link
224  if (!sname.empty () && !tname.empty ())
225  {
226  if (nodeMap[sname] == 0)
227  {
228  Ptr<Node> tmpNode = CreateObject<Node> ();
229  nodeMap[sname] = tmpNode;
230  nodes.Add (tmpNode);
231  nodesNumber++;
232  }
233 
234  if (nodeMap[tname] == 0)
235  {
236  Ptr<Node> tmpNode = CreateObject<Node> ();
237  nodeMap[tname] = tmpNode;
238  nodes.Add (tmpNode);
239  nodesNumber++;
240  }
241  NS_LOG_INFO (linksNumber << ":" << nodesNumber << " From: " << sname << " to: " << tname);
243  bool found = false;
244  for (iter = LinksBegin (); iter != LinksEnd (); iter++)
245  {
246  if ((iter->GetFromNode () == nodeMap[tname])
247  && (iter->GetToNode () == nodeMap[sname]))
248  {
249  found = true;
250  break;
251  }
252  }
253 
254  if (!found)
255  {
256  Link link (nodeMap[sname], sname, nodeMap[tname], tname);
257  AddLink (link);
258  linksNumber++;
259  }
260  }
261  return nodes;
262 }
263 
264 enum RocketfuelTopologyReader::RF_FileType
265 RocketfuelTopologyReader::GetFileType (const char *line)
266 {
267  int ret;
268  regmatch_t regmatch[REGMATCH_MAX];
269  regex_t regex;
270  char errbuf[512];
271 
272  // Check whether MAPS file or not
273  ret = regcomp (&regex, ROCKETFUEL_MAPS_LINE, REG_EXTENDED | REG_NEWLINE);
274  if (ret != 0)
275  {
276  regerror (ret, &regex, errbuf, sizeof (errbuf));
277  return RF_UNKNOWN;
278  }
279  ret = regexec (&regex, line, REGMATCH_MAX, regmatch, 0);
280  if (ret != REG_NOMATCH)
281  {
282  regfree (&regex);
283  return RF_MAPS;
284  }
285  regfree (&regex);
286 
287  // Check whether Weights file or not
288  ret = regcomp (&regex, ROCKETFUEL_WEIGHTS_LINE, REG_EXTENDED | REG_NEWLINE);
289  if (ret != 0)
290  {
291  regerror (ret, &regex, errbuf, sizeof (errbuf));
292  return RF_UNKNOWN;
293  }
294  ret = regexec (&regex, line, REGMATCH_MAX, regmatch, 0);
295  if (ret != REG_NOMATCH)
296  {
297  regfree (&regex);
298  return RF_WEIGHTS;
299  }
300  regfree (&regex);
301 
302  return RF_UNKNOWN;
303 }
304 
305 
306 NodeContainer
308 {
309  std::ifstream topgen;
310  topgen.open (GetFileName ().c_str ());
311  NodeContainer nodes;
312 
313  std::istringstream lineBuffer;
314  std::string line;
315  int lineNumber = 0;
316  enum RF_FileType ftype = RF_UNKNOWN;
317  char errbuf[512];
318 
319  if (!topgen.is_open ())
320  {
321  NS_LOG_WARN ("Couldn't open the file " << GetFileName ());
322  return nodes;
323  }
324 
325  while (!topgen.eof ())
326  {
327  int ret;
328  int argc;
329  char *argv[REGMATCH_MAX];
330  char *buf;
331 
332  lineNumber++;
333  line.clear ();
334  lineBuffer.clear ();
335 
336  getline (topgen, line);
337  buf = (char *)line.c_str ();
338 
339  if (lineNumber == 1)
340  {
341  ftype = GetFileType (buf);
342  if (ftype == RF_UNKNOWN)
343  {
344  NS_LOG_INFO ("Unknown File Format (" << GetFileName () << ")");
345  break;
346  }
347  }
348 
349  regmatch_t regmatch[REGMATCH_MAX];
350  regex_t regex;
351 
352  if (ftype == RF_MAPS)
353  {
354  ret = regcomp (&regex, ROCKETFUEL_MAPS_LINE, REG_EXTENDED | REG_NEWLINE);
355  if (ret != 0)
356  {
357  regerror (ret, &regex, errbuf, sizeof (errbuf));
358  regfree (&regex);
359  break;
360  }
361 
362  ret = regexec (&regex, buf, REGMATCH_MAX, regmatch, 0);
363  if (ret == REG_NOMATCH)
364  {
365  NS_LOG_WARN ("match failed (maps file): %s" << buf);
366  regfree (&regex);
367  break;
368  }
369  }
370  else if (ftype == RF_WEIGHTS)
371  {
372  ret = regcomp (&regex, ROCKETFUEL_WEIGHTS_LINE, REG_EXTENDED | REG_NEWLINE);
373  if (ret != 0)
374  {
375  regerror (ret, &regex, errbuf, sizeof (errbuf));
376  regfree (&regex);
377  break;
378  }
379 
380  ret = regexec (&regex, buf, REGMATCH_MAX, regmatch, 0);
381  if (ret == REG_NOMATCH)
382  {
383  NS_LOG_WARN ("match failed (weights file): %s" << buf);
384  regfree (&regex);
385  break;
386  }
387  }
388 
389  line = buf;
390  argc = 0;
391 
392  /* regmatch[0] is the entire strings that matched */
393  for (int i = 1; i < REGMATCH_MAX; i++)
394  {
395  if (regmatch[i].rm_so == -1)
396  {
397  argv[i - 1] = NULL;
398  }
399  else
400  {
401  line[regmatch[i].rm_eo] = '\0';
402  argv[i - 1] = &line[regmatch[i].rm_so];
403  argc = i;
404  }
405  }
406 
407  if (ftype == RF_MAPS)
408  {
409  nodes.Add (GenerateFromMapsFile (argc, argv));
410  }
411  else if (ftype == RF_WEIGHTS)
412  {
413  nodes.Add (GenerateFromWeightsFile (argc, argv));
414  }
415  else
416  {
417  NS_LOG_WARN ("Unsupported file format (only Maps/Weights are supported)");
418  }
419 
420  regfree (&regex);
421  }
422 
423 
424  topgen.close ();
425 
426  NS_LOG_INFO ("Rocketfuel topology created with " << nodesNumber << " nodes and " << linksNumber << " links");
427  return nodes;
428 }
429 
430 } /* namespace ns3 */
431 
432 
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
ConstLinksIterator LinksBegin(void) const
Returns an iterator to the the first link in this block.
std::string GetFileName(void) const
Returns the input file name.
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
#define NS_LOG_INFO(msg)
Definition: log.h:264
void AddLink(Link link)
Adds a link to the topology.
std::list< Link >::const_iterator ConstLinksIterator
Constant iterator to the list of the links.
keep track of a set of node pointers.
virtual NodeContainer Read(void)
Main topology reading function.
void Add(NodeContainer other)
Append the contents of another NodeContainer to the end of this container.
#define NS_LOG_WARN(msg)
Definition: log.h:246
ConstLinksIterator LinksEnd(void) const
Returns an iterator to the the last link in this block.