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