NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
annotated-topology-reader.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
20 // Based on the code by Hajime Tazaki <tazaki@sfc.wide.ad.jp>
21 
23 
24 #include "ns3/nstime.h"
25 #include "ns3/log.h"
26 #include "ns3/assert.h"
27 #include "ns3/names.h"
28 #include "ns3/net-device-container.h"
29 #include "ns3/point-to-point-helper.h"
30 #include "ns3/point-to-point-net-device.h"
31 #include "ns3/internet-stack-helper.h"
32 #include "ns3/ipv4-address-helper.h"
33 #include "ns3/ipv4-global-routing-helper.h"
34 #include "ns3/drop-tail-queue.h"
35 #include "ns3/ipv4-interface.h"
36 #include "ns3/ipv4.h"
37 #include "ns3/string.h"
38 #include "ns3/pointer.h"
39 #include "ns3/uinteger.h"
40 #include "ns3/ipv4-address.h"
41 #include "ns3/error-model.h"
42 #include "ns3/constant-position-mobility-model.h"
43 #include "ns3/double.h"
44 
47 
48 #include <boost/foreach.hpp>
49 #include <boost/lexical_cast.hpp>
50 #include <boost/tokenizer.hpp>
51 
52 #include <boost/graph/adjacency_list.hpp>
53 #include <boost/graph/graphviz.hpp>
54 
55 #include <set>
56 
57 #ifdef NS3_MPI
58 #include <ns3/mpi-interface.h>
59 #endif
60 
61 using namespace std;
62 
63 namespace ns3 {
64 
65 NS_LOG_COMPONENT_DEFINE("AnnotatedTopologyReader");
66 
67 AnnotatedTopologyReader::AnnotatedTopologyReader(const std::string& path, double scale /*=1.0*/)
68  : m_path(path)
69  , m_randX(CreateObject<UniformRandomVariable>())
70  , m_randY(CreateObject<UniformRandomVariable>())
71  , m_scale(scale)
72  , m_requiredPartitions(1)
73 {
74  NS_LOG_FUNCTION(this);
75 
76  m_randX->SetAttribute("Min", DoubleValue(0));
77  m_randX->SetAttribute("Max", DoubleValue(100.0));
78 
79  m_randY->SetAttribute("Min", DoubleValue(0));
80  m_randY->SetAttribute("Max", DoubleValue(100.0));
81 
82  SetMobilityModel("ns3::ConstantPositionMobilityModel");
83 }
84 
85 void
86 AnnotatedTopologyReader::SetBoundingBox(double ulx, double uly, double lrx, double lry)
87 {
88  NS_LOG_FUNCTION(this << ulx << uly << lrx << lry);
89 
90  m_randX->SetAttribute("Min", DoubleValue(ulx));
91  m_randX->SetAttribute("Max", DoubleValue(lrx));
92 
93  m_randY->SetAttribute("Min", DoubleValue(uly));
94  m_randY->SetAttribute("Max", DoubleValue(lry));
95 }
96 
97 void
99 {
100  NS_LOG_FUNCTION(this << model);
101  m_mobilityFactory.SetTypeId(model);
102 }
103 
105 {
106  NS_LOG_FUNCTION(this);
107 }
108 
109 Ptr<Node>
110 AnnotatedTopologyReader::CreateNode(const std::string name, uint32_t systemId)
111 {
112  NS_LOG_FUNCTION(this << name);
113  m_requiredPartitions = std::max(m_requiredPartitions, systemId + 1);
114 
115  Ptr<Node> node = CreateObject<Node>(systemId);
116 
117  Names::Add(m_path, name, node);
118  m_nodes.Add(node);
119 
120  return node;
121 }
122 
123 Ptr<Node>
124 AnnotatedTopologyReader::CreateNode(const std::string name, double posX, double posY,
125  uint32_t systemId)
126 {
127  NS_LOG_FUNCTION(this << name << posX << posY);
128  m_requiredPartitions = std::max(m_requiredPartitions, systemId + 1);
129 
130  Ptr<Node> node = CreateObject<Node>(systemId);
131  Ptr<MobilityModel> loc = DynamicCast<MobilityModel>(m_mobilityFactory.Create());
132  node->AggregateObject(loc);
133 
134  loc->SetPosition(Vector(posX, posY, 0));
135 
136  Names::Add(m_path, name, node);
137  m_nodes.Add(node);
138 
139  return node;
140 }
141 
142 NodeContainer
144 {
145  return m_nodes;
146 }
147 
148 const std::list<TopologyReader::Link>&
150 {
151  return m_linksList;
152 }
153 
154 NodeContainer
156 {
157  ifstream topgen;
158  topgen.open(GetFileName().c_str());
159 
160  if (!topgen.is_open() || !topgen.good()) {
161  NS_FATAL_ERROR("Cannot open file " << GetFileName() << " for reading");
162  return m_nodes;
163  }
164 
165  while (!topgen.eof()) {
166  string line;
167  getline(topgen, line);
168 
169  if (line == "router")
170  break;
171  }
172 
173  if (topgen.eof()) {
174  NS_FATAL_ERROR("Topology file " << GetFileName() << " does not have \"router\" section");
175  return m_nodes;
176  }
177 
178  while (!topgen.eof()) {
179  string line;
180  getline(topgen, line);
181  if (line[0] == '#')
182  continue; // comments
183  if (line == "link")
184  break; // stop reading nodes
185 
186  istringstream lineBuffer(line);
187  string name, city;
188  double latitude = 0, longitude = 0;
189  uint32_t systemId = 0;
190 
191  lineBuffer >> name >> city >> latitude >> longitude >> systemId;
192  if (name.empty())
193  continue;
194 
195  Ptr<Node> node;
196 
197  if (abs(latitude) > 0.001 && abs(latitude) > 0.001)
198  node = CreateNode(name, m_scale * longitude, -m_scale * latitude, systemId);
199  else {
200  Ptr<UniformRandomVariable> var = CreateObject<UniformRandomVariable>();
201  node = CreateNode(name, var->GetValue(0, 200), var->GetValue(0, 200), systemId);
202  // node = CreateNode (name, systemId);
203  }
204  }
205 
206  map<string, set<string>> processedLinks; // to eliminate duplications
207 
208  if (topgen.eof()) {
209  NS_LOG_ERROR("Topology file " << GetFileName() << " does not have \"link\" section");
210  return m_nodes;
211  }
212 
213  // SeekToSection ("link");
214  while (!topgen.eof()) {
215  string line;
216  getline(topgen, line);
217  if (line == "")
218  continue;
219  if (line[0] == '#')
220  continue; // comments
221 
222  // NS_LOG_DEBUG ("Input: [" << line << "]");
223 
224  istringstream lineBuffer(line);
225  string from, to, capacity, metric, delay, maxPackets, lossRate;
226 
227  lineBuffer >> from >> to >> capacity >> metric >> delay >> maxPackets >> lossRate;
228 
229  if (processedLinks[to].size() != 0
230  && processedLinks[to].find(from) != processedLinks[to].end()) {
231  continue; // duplicated link
232  }
233  processedLinks[from].insert(to);
234 
235  Ptr<Node> fromNode = Names::Find<Node>(m_path, from);
236  NS_ASSERT_MSG(fromNode != 0, from << " node not found");
237  Ptr<Node> toNode = Names::Find<Node>(m_path, to);
238  NS_ASSERT_MSG(toNode != 0, to << " node not found");
239 
240  Link link(fromNode, from, toNode, to);
241 
242  link.SetAttribute("DataRate", capacity);
243  link.SetAttribute("OSPF", metric);
244 
245  if (!delay.empty())
246  link.SetAttribute("Delay", delay);
247  if (!maxPackets.empty())
248  link.SetAttribute("MaxPackets", maxPackets);
249 
250  // Saran Added lossRate
251  if (!lossRate.empty())
252  link.SetAttribute("LossRate", lossRate);
253 
254  AddLink(link);
255  NS_LOG_DEBUG("New link " << from << " <==> " << to << " / " << capacity << " with " << metric
256  << " metric (" << delay << ", " << maxPackets << ", " << lossRate
257  << ")");
258  }
259 
260  NS_LOG_INFO("Annotated topology created with " << m_nodes.GetN() << " nodes and " << LinksSize()
261  << " links");
262  topgen.close();
263 
264  ApplySettings();
265 
266  return m_nodes;
267 }
268 
269 void
271 {
272  Ipv4AddressHelper address(base, Ipv4Mask("/24"));
273 
274  BOOST_FOREACH (const Link& link, m_linksList) {
275  address.Assign(NetDeviceContainer(link.GetFromNetDevice(), link.GetToNetDevice()));
276 
277  base = Ipv4Address(base.Get() + 256);
278  address.SetBase(base, Ipv4Mask("/24"));
279  }
280 }
281 
282 void
284 {
285  BOOST_FOREACH (const Link& link, m_linksList) {
286  NS_LOG_DEBUG("OSPF: " << link.GetAttribute("OSPF"));
287  uint16_t metric = boost::lexical_cast<uint16_t>(link.GetAttribute("OSPF"));
288 
289  {
290  Ptr<Ipv4> ipv4 = link.GetFromNode()->GetObject<Ipv4>();
291  if (ipv4 != 0) {
292  int32_t interfaceId = ipv4->GetInterfaceForDevice(link.GetFromNetDevice());
293  NS_ASSERT(interfaceId >= 0);
294 
295  ipv4->SetMetric(interfaceId, metric);
296  }
297 
298  Ptr<ndn::L3Protocol> ndn = link.GetFromNode()->GetObject<ndn::L3Protocol>();
299  if (ndn != 0) {
300  shared_ptr<ndn::Face> face = ndn->getFaceByNetDevice(link.GetFromNetDevice());
301  NS_ASSERT(face != 0);
302 
303  face->setMetric(metric);
304  }
305  }
306 
307  {
308  Ptr<Ipv4> ipv4 = link.GetToNode()->GetObject<Ipv4>();
309  if (ipv4 != 0) {
310  int32_t interfaceId = ipv4->GetInterfaceForDevice(link.GetToNetDevice());
311  NS_ASSERT(interfaceId >= 0);
312 
313  ipv4->SetMetric(interfaceId, metric);
314  }
315 
316  Ptr<ndn::L3Protocol> ndn = link.GetToNode()->GetObject<ndn::L3Protocol>();
317  if (ndn != 0) {
318  shared_ptr<ndn::Face> face = ndn->getFaceByNetDevice(link.GetToNetDevice());
319  NS_ASSERT(face != 0);
320 
321  face->setMetric(metric);
322  }
323  }
324  }
325 }
326 
327 void
329 {
330 #ifdef NS3_MPI
331  if (MpiInterface::IsEnabled() && MpiInterface::GetSize() != m_requiredPartitions) {
332  std::cerr << "MPI interface is enabled, but number of partitions (" << MpiInterface::GetSize()
333  << ") is not equal to number of partitions in the topology (" << m_requiredPartitions
334  << ")";
335  exit(-1);
336  }
337 #endif
338 
339  PointToPointHelper p2p;
340 
341  BOOST_FOREACH (Link& link, m_linksList) {
342  // cout << "Link: " << Findlink.GetFromNode () << ", " << link.GetToNode () << endl;
343  string tmp;
344 
346  if (link.GetAttributeFailSafe("MaxPackets", tmp)) {
347  NS_LOG_INFO("MaxPackets = " + link.GetAttribute("MaxPackets"));
348 
349  try {
350  uint32_t maxPackets = boost::lexical_cast<uint32_t>(link.GetAttribute("MaxPackets"));
351 
352  // compatibility mode. Only DropTailQueue is supported
353  p2p.SetQueue("ns3::DropTailQueue", "MaxPackets", UintegerValue(maxPackets));
354  }
355  catch (...) {
356  typedef boost::tokenizer<boost::escaped_list_separator<char>> tokenizer;
357  std::string value = link.GetAttribute("MaxPackets");
358  tokenizer tok(value);
359 
360  tokenizer::iterator token = tok.begin();
361  p2p.SetQueue(*token);
362 
363  for (token++; token != tok.end(); token++) {
364  boost::escaped_list_separator<char> separator('\\', '=', '\"');
365  tokenizer attributeTok(*token, separator);
366 
367  tokenizer::iterator attributeToken = attributeTok.begin();
368 
369  string attribute = *attributeToken;
370  attributeToken++;
371 
372  if (attributeToken == attributeTok.end()) {
373  NS_LOG_ERROR("Queue attribute [" << *token
374  << "] should be in form <Attribute>=<Value>");
375  continue;
376  }
377 
378  string value = *attributeToken;
379 
380  p2p.SetQueueAttribute(attribute, StringValue(value));
381  }
382  }
383  }
384 
385  if (link.GetAttributeFailSafe("DataRate", tmp)) {
386  NS_LOG_INFO("DataRate = " + link.GetAttribute("DataRate"));
387  p2p.SetDeviceAttribute("DataRate", StringValue(link.GetAttribute("DataRate")));
388  }
389 
390  if (link.GetAttributeFailSafe("Delay", tmp)) {
391  NS_LOG_INFO("Delay = " + link.GetAttribute("Delay"));
392  p2p.SetChannelAttribute("Delay", StringValue(link.GetAttribute("Delay")));
393  }
394 
395  NetDeviceContainer nd = p2p.Install(link.GetFromNode(), link.GetToNode());
396  link.SetNetDevices(nd.Get(0), nd.Get(1));
397 
399  if (link.GetAttributeFailSafe("LossRate", tmp)) {
400  NS_LOG_INFO("LinkError = " + link.GetAttribute("LossRate"));
401 
402  typedef boost::tokenizer<boost::escaped_list_separator<char>> tokenizer;
403  std::string value = link.GetAttribute("LossRate");
404  tokenizer tok(value);
405 
406  tokenizer::iterator token = tok.begin();
407  ObjectFactory factory(*token);
408 
409  for (token++; token != tok.end(); token++) {
410  boost::escaped_list_separator<char> separator('\\', '=', '\"');
411  tokenizer attributeTok(*token, separator);
412 
413  tokenizer::iterator attributeToken = attributeTok.begin();
414 
415  string attribute = *attributeToken;
416  attributeToken++;
417 
418  if (attributeToken == attributeTok.end()) {
419  NS_LOG_ERROR("ErrorModel attribute [" << *token
420  << "] should be in form <Attribute>=<Value>");
421  continue;
422  }
423 
424  string value = *attributeToken;
425 
426  factory.Set(attribute, StringValue(value));
427  }
428 
429  nd.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue(factory.Create<ErrorModel>()));
430  nd.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue(factory.Create<ErrorModel>()));
431  }
432  }
433 }
434 
435 void
437 {
438  ofstream os(file.c_str(), ios::trunc);
439  os << "# any empty lines and lines starting with '#' symbol is ignored\n"
440  << "\n"
441  << "# The file should contain exactly two sections: router and link, each starting with the "
442  "corresponding keyword\n"
443  << "\n"
444  << "# router section defines topology nodes and their relative positions (e.g., to use in "
445  "visualizer)\n"
446  << "router\n"
447  << "\n"
448  << "# each line in this section represents one router and should have the following data\n"
449  << "# node comment yPos xPos\n";
450 
451  for (NodeContainer::Iterator node = m_nodes.Begin(); node != m_nodes.End(); node++) {
452  std::string name = Names::FindName(*node);
453  Ptr<MobilityModel> mobility = (*node)->GetObject<MobilityModel>();
454  Vector position = mobility->GetPosition();
455 
456  os << name << "\t"
457  << "NA"
458  << "\t" << -position.y << "\t" << position.x << "\n";
459  }
460 
461  os
462  << "# link section defines point-to-point links between nodes and characteristics of these "
463  "links\n"
464  << "\n"
465  << "link\n"
466  << "\n"
467  << "# Each line should be in the following format (only first two are required, the rest can "
468  "be omitted)\n"
469  << "# srcNode dstNode bandwidth metric delay queue\n"
470  << "# bandwidth: link bandwidth\n"
471  << "# metric: routing metric\n"
472  << "# delay: link delay\n"
473  << "# queue: MaxPackets for transmission queue on the link (both directions)\n"
474  << "# error: comma-separated list, specifying class for ErrorModel and necessary attributes\n";
475 
476  for (std::list<Link>::const_iterator link = m_linksList.begin(); link != m_linksList.end();
477  link++) {
478  os << Names::FindName(link->GetFromNode()) << "\t";
479  os << Names::FindName(link->GetToNode()) << "\t";
480 
481  string tmp;
482  if (link->GetAttributeFailSafe("DataRate", tmp))
483  os << link->GetAttribute("DataRate") << "\t";
484  else
485  NS_FATAL_ERROR("DataRate must be specified for the link");
486 
487  if (link->GetAttributeFailSafe("OSPF", tmp))
488  os << link->GetAttribute("OSPF") << "\t";
489  else
490  os << "1\t";
491 
492  if (link->GetAttributeFailSafe("Delay", tmp)) {
493  os << link->GetAttribute("Delay") << "\t";
494 
495  if (link->GetAttributeFailSafe("MaxPackets", tmp)) {
496  os << link->GetAttribute("MaxPackets") << "\t";
497 
498  if (link->GetAttributeFailSafe("LossRate", tmp)) {
499  os << link->GetAttribute("LossRate") << "\t";
500  }
501  }
502  }
503  os << "\n";
504  }
505 }
506 
508 
509 template<class Names>
510 class name_writer {
511 public:
512  name_writer(Names _names)
513  : names(_names)
514  {
515  }
516 
517  template<class VertexOrEdge>
518  void
519  operator()(std::ostream& out, const VertexOrEdge& v) const
520  {
521  // out << "[label=\"" << names[v] << "\",style=filled,fillcolor=\"" << colors[v] << "\"]";
522  out << "[shape=\"circle\",width=0.1,label=\"\",style=filled,fillcolor=\"green\"]";
523  }
524 
525 private:
526  Names names;
527 };
528 
529 template<class Names>
530 inline name_writer<Names>
531 make_name_writer(Names n)
532 {
533  return name_writer<Names>(n);
534 }
535 
537 
538 void
540 {
541  typedef boost::adjacency_list_traits<boost::setS, boost::setS, boost::undirectedS> Traits;
542 
543  typedef boost::property<boost::vertex_name_t, std::string,
544  boost::property<boost::vertex_index_t, uint32_t>> nodeProperty;
545 
546  typedef boost::no_property edgeProperty;
547 
548  typedef boost::adjacency_list<boost::setS, boost::setS, boost::undirectedS, nodeProperty,
549  edgeProperty> Graph;
550 
551  typedef map<string, Traits::vertex_descriptor> node_map_t;
552  node_map_t graphNodes;
553  Graph graph;
554 
555  for (NodeContainer::Iterator node = m_nodes.Begin(); node != m_nodes.End(); node++) {
556  std::pair<node_map_t::iterator, bool> retval = graphNodes.insert(
557  make_pair(Names::FindName(*node), add_vertex(nodeProperty(Names::FindName(*node)), graph)));
558  // NS_ASSERT (ok == true);
559 
560  put(boost::vertex_index, graph, retval.first->second, (*node)->GetId());
561  }
562 
563  for (std::list<Link>::const_iterator link = m_linksList.begin(); link != m_linksList.end();
564  link++) {
565  node_map_t::iterator from = graphNodes.find(Names::FindName(link->GetFromNode()));
566  node_map_t::iterator to = graphNodes.find(Names::FindName(link->GetToNode()));
567 
568  // add_edge (node->second, otherNode->second, m_graph);
569  boost::add_edge(from->second, to->second, graph);
570  }
571 
572  ofstream of(file.c_str());
573  boost::property_map<Graph, boost::vertex_name_t>::type names = get(boost::vertex_name, graph);
574  write_graphviz(of, graph, make_name_writer(names));
575 }
576 
577 }
shared_ptr< Face > getFaceByNetDevice(Ptr< NetDevice > netDevice) const
Remove face from ndn stack (remove callbacks)
Copyright (c) 2011-2015 Regents of the University of California.
STL namespace.
virtual void ApplyOspfMetric()
Apply OSPF metric on Ipv4 (if exists) and Ccnx (if exists) stacks.
Table::const_iterator iterator
Definition: cs-internal.hpp:41
virtual void SetMobilityModel(const std::string &model)
Set mobility model to be used on nodes.
virtual const std::list< Link > & GetLinks() const
Get links read by the reader.
virtual void AssignIpv4Addresses(Ipv4Address base)
Assign IPv4 addresses to all links.
virtual void SaveTopology(const std::string &file)
Save positions (e.g., after manual modification using visualizer)
void ApplySettings()
This method applies setting to corresponding nodes and links NetDeviceContainer must be allocated Nod...
Copyright (c) 2011-2015 Regents of the University of California.
virtual void SetBoundingBox(double ulx, double uly, double lrx, double lry)
Set bounding box where nodes will be randomly places (if positions are unspecified) ...
virtual NodeContainer Read()
Main annotated topology reading function.
Implementation network-layer of NDN stack.
virtual NodeContainer GetNodes() const
Get nodes read by the reader.
virtual void SaveGraphviz(const std::string &file)
Save topology in graphviz format (.dot file)
Ptr< Node > CreateNode(const std::string name, uint32_t systemId)