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