NS-3 based Named Data Networking (NDN) simulator
ndnSIM: NDN, CCN, CCNx, content centric networks
API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
annotated-topology-reader.cc
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011-2013 University of California, Los Angeles
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: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
19  * Ilya Moiseenko <iliamo@cs.ucla.edu>
20  */
21 
22 #include "annotated-topology-reader.h"
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/ndn-l3-protocol.h"
42 #include "ns3/ndn-face.h"
43 #include "ns3/random-variable.h"
44 #include "ns3/error-model.h"
45 
46 #include "ns3/constant-position-mobility-model.h"
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 
95 AnnotatedTopologyReader::~AnnotatedTopologyReader ()
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, uint32_t systemId)
116 {
117  NS_LOG_FUNCTION (this << name << posX << posY);
118  m_requiredPartitions = std::max (m_requiredPartitions, systemId + 1);
119 
120  Ptr<Node> node = CreateObject<Node> (systemId);
121  Ptr<MobilityModel> loc = DynamicCast<MobilityModel> (m_mobilityFactory.Create ());
122  node->AggregateObject (loc);
123 
124  loc->SetPosition (Vector (posX, posY, 0));
125 
126  Names::Add (m_path, name, node);
127  m_nodes.Add (node);
128 
129  return node;
130 }
131 
132 NodeContainer
134 {
135  return m_nodes;
136 }
137 
138 const std::list<TopologyReader::Link>&
140 {
141  return m_linksList;
142 }
143 
144 NodeContainer
146 {
147  ifstream topgen;
148  topgen.open (GetFileName ().c_str ());
149 
150  if ( !topgen.is_open () || !topgen.good () )
151  {
152  NS_FATAL_ERROR ("Cannot open file " << GetFileName () << " for reading");
153  return m_nodes;
154  }
155 
156  while (!topgen.eof ())
157  {
158  string line;
159  getline (topgen, line);
160 
161  if (line == "router") break;
162  }
163 
164  if (topgen.eof ())
165  {
166  NS_FATAL_ERROR ("Topology file " << GetFileName () << " does not have \"router\" section");
167  return m_nodes;
168  }
169 
170  while (!topgen.eof ())
171  {
172  string line;
173  getline (topgen,line);
174  if (line[0] == '#') continue; // comments
175  if (line=="link") 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 ()) continue;
184 
185  Ptr<Node> node;
186 
187  if (abs(latitude) > 0.001 && abs(latitude) > 0.001)
188  node = CreateNode (name, m_scale*longitude, -m_scale*latitude, systemId);
189  else
190  {
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  {
201  NS_LOG_ERROR ("Topology file " << GetFileName () << " does not have \"link\" section");
202  return m_nodes;
203  }
204 
205  // SeekToSection ("link");
206  while (!topgen.eof ())
207  {
208  string line;
209  getline (topgen,line);
210  if (line == "") continue;
211  if (line[0] == '#') 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  {
223  continue; // duplicated link
224  }
225  processedLinks[from].insert (to);
226 
227  Ptr<Node> fromNode = Names::Find<Node> (m_path, from);
228  NS_ASSERT_MSG (fromNode != 0, from << " node not found");
229  Ptr<Node> toNode = Names::Find<Node> (m_path, to);
230  NS_ASSERT_MSG (toNode != 0, to << " node not found");
231 
232  Link link (fromNode, from, toNode, to);
233 
234  link.SetAttribute ("DataRate", capacity);
235  link.SetAttribute ("OSPF", metric);
236 
237  if (!delay.empty ())
238  link.SetAttribute ("Delay", delay);
239  if (!maxPackets.empty ())
240  link.SetAttribute ("MaxPackets", maxPackets);
241 
242  // Saran Added lossRate
243  if (!lossRate.empty ())
244  link.SetAttribute ("LossRate", lossRate);
245 
246  AddLink (link);
247  NS_LOG_DEBUG ("New link " << from << " <==> " << to << " / " << capacity << " with " << metric << " metric (" << delay << ", " << maxPackets << ", " << lossRate << ")");
248  }
249 
250  NS_LOG_INFO ("Annotated topology created with " << m_nodes.GetN () << " nodes and " << LinksSize () << " links");
251  topgen.close ();
252 
253  ApplySettings ();
254 
255  return m_nodes;
256 }
257 
258 void
260 {
261  Ipv4AddressHelper address (base, Ipv4Mask ("/24"));
262 
263  BOOST_FOREACH (const Link &link, m_linksList)
264  {
265  address.Assign (NetDeviceContainer (link.GetFromNetDevice (),
266  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  {
278  NS_LOG_DEBUG ("OSPF: " << link.GetAttribute ("OSPF"));
279  uint16_t metric = boost::lexical_cast<uint16_t> (link.GetAttribute ("OSPF"));
280 
281  {
282  Ptr<Ipv4> ipv4 = link.GetFromNode ()->GetObject<Ipv4> ();
283  if (ipv4 != 0)
284  {
285  int32_t interfaceId = ipv4->GetInterfaceForDevice (link.GetFromNetDevice ());
286  NS_ASSERT (interfaceId >= 0);
287 
288  ipv4->SetMetric (interfaceId,metric);
289  }
290 
291  Ptr<ndn::L3Protocol> ndn = link.GetFromNode ()->GetObject<ndn::L3Protocol> ();
292  if (ndn != 0)
293  {
294  Ptr<ndn::Face> face = ndn->GetFaceByNetDevice (link.GetFromNetDevice ());
295  NS_ASSERT (face != 0);
296 
297  face->SetMetric (metric);
298  }
299  }
300 
301  {
302  Ptr<Ipv4> ipv4 = link.GetToNode ()->GetObject<Ipv4> ();
303  if (ipv4 != 0)
304  {
305  int32_t interfaceId = ipv4->GetInterfaceForDevice (link.GetToNetDevice ());
306  NS_ASSERT (interfaceId >= 0);
307 
308  ipv4->SetMetric (interfaceId,metric);
309  }
310 
311  Ptr<ndn::L3Protocol> ndn = link.GetToNode ()->GetObject<ndn::L3Protocol> ();
312  if (ndn != 0)
313  {
314  Ptr<ndn::Face> face = ndn->GetFaceByNetDevice (link.GetToNetDevice ());
315  NS_ASSERT (face != 0);
316 
317  face->SetMetric (metric);
318  }
319  }
320  }
321 }
322 
323 void
325 {
326 #ifdef NS3_MPI
327  if (MpiInterface::IsEnabled () &&
328  MpiInterface::GetSize () != m_requiredPartitions)
329  {
330  std::cerr << "MPI interface is enabled, but number of partitions (" << MpiInterface::GetSize ()
331  << ") is not equal to number of partitions in the topology (" << m_requiredPartitions << ")";
332  exit (-1);
333  }
334 #endif
335 
336  PointToPointHelper p2p;
337 
338  BOOST_FOREACH (Link &link, m_linksList)
339  {
340  // cout << "Link: " << Findlink.GetFromNode () << ", " << link.GetToNode () << endl;
341  string tmp;
342 
344  if (link.GetAttributeFailSafe ("MaxPackets", tmp))
345  {
346  NS_LOG_INFO ("MaxPackets = " + link.GetAttribute ("MaxPackets"));
347 
348  try
349  {
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",
354  "MaxPackets", UintegerValue (maxPackets));
355  }
356  catch (...)
357  {
358  typedef boost::tokenizer<boost::escaped_list_separator<char> > tokenizer;
359  tokenizer tok (link.GetAttribute ("MaxPackets"));
360 
361  tokenizer::iterator token = tok.begin ();
362  p2p.SetQueue (*token);
363 
364  for (token ++; token != tok.end (); token ++)
365  {
366  boost::escaped_list_separator<char> separator ('\\', '=', '\"');
367  tokenizer attributeTok (*token, separator);
368 
369  tokenizer::iterator attributeToken = attributeTok.begin ();
370 
371  string attribute = *attributeToken;
372  attributeToken++;
373 
374  if (attributeToken == attributeTok.end ())
375  {
376  NS_LOG_ERROR ("Queue attribute [" << *token << "] should be in form <Attribute>=<Value>");
377  continue;
378  }
379 
380  string value = *attributeToken;
381 
382  p2p.SetQueueAttribute (attribute, StringValue (value));
383  }
384  }
385  }
386 
387  if (link.GetAttributeFailSafe ("DataRate", tmp))
388  {
389  NS_LOG_INFO ("DataRate = " + link.GetAttribute("DataRate"));
390  p2p.SetDeviceAttribute ("DataRate", StringValue (link.GetAttribute ("DataRate")));
391  }
392 
393  if (link.GetAttributeFailSafe ("Delay", tmp))
394  {
395  NS_LOG_INFO ("Delay = " + link.GetAttribute("Delay"));
396  p2p.SetChannelAttribute ("Delay", StringValue (link.GetAttribute ("Delay")));
397  }
398 
399  NetDeviceContainer nd = p2p.Install(link.GetFromNode (), link.GetToNode ());
400  link.SetNetDevices (nd.Get (0), nd.Get (1));
401 
403  if (link.GetAttributeFailSafe ("LossRate", tmp))
404  {
405  NS_LOG_INFO ("LinkError = " + link.GetAttribute("LossRate"));
406 
407  typedef boost::tokenizer<boost::escaped_list_separator<char> > tokenizer;
408  tokenizer tok (link.GetAttribute("LossRate"));
409 
410  tokenizer::iterator token = tok.begin ();
411  ObjectFactory factory (*token);
412 
413  for (token ++; token != tok.end (); token ++)
414  {
415  boost::escaped_list_separator<char> separator ('\\', '=', '\"');
416  tokenizer attributeTok (*token, separator);
417 
418  tokenizer::iterator attributeToken = attributeTok.begin ();
419 
420  string attribute = *attributeToken;
421  attributeToken++;
422 
423  if (attributeToken == attributeTok.end ())
424  {
425  NS_LOG_ERROR ("ErrorModel attribute [" << *token << "] should be in form <Attribute>=<Value>");
426  continue;
427  }
428 
429  string value = *attributeToken;
430 
431  factory.Set (attribute, StringValue (value));
432  }
433 
434  nd.Get (0)->SetAttribute ("ReceiveErrorModel", PointerValue (factory.Create<ErrorModel> ()));
435  nd.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (factory.Create<ErrorModel> ()));
436  }
437  }
438 }
439 
440 void
441 AnnotatedTopologyReader::SaveTopology (const std::string &file)
442 {
443  ofstream os (file.c_str (), ios::trunc);
444  os << "# any empty lines and lines starting with '#' symbol is ignored\n"
445  << "\n"
446  << "# The file should contain exactly two sections: router and link, each starting with the corresponding keyword\n"
447  << "\n"
448  << "# router section defines topology nodes and their relative positions (e.g., to use in visualizer)\n"
449  << "router\n"
450  << "\n"
451  << "# each line in this section represents one router and should have the following data\n"
452  << "# node comment yPos xPos\n";
453 
454  for (NodeContainer::Iterator node = m_nodes.Begin ();
455  node != m_nodes.End ();
456  node++)
457  {
458  std::string name = Names::FindName (*node);
459  Ptr<MobilityModel> mobility = (*node)->GetObject<MobilityModel> ();
460  Vector position = mobility->GetPosition ();
461 
462  os << name << "\t" << "NA" << "\t" << -position.y << "\t" << position.x << "\n";
463  }
464 
465  os << "# link section defines point-to-point links between nodes and characteristics of these links\n"
466  << "\n"
467  << "link\n"
468  << "\n"
469  << "# Each line should be in the following format (only first two are required, the rest can be omitted)\n"
470  << "# srcNode dstNode bandwidth metric delay queue\n"
471  << "# bandwidth: link bandwidth\n"
472  << "# metric: routing metric\n"
473  << "# delay: link delay\n"
474  << "# queue: MaxPackets for transmission queue on the link (both directions)\n"
475  << "# error: comma-separated list, specifying class for ErrorModel and necessary attributes\n";
476 
477  for (std::list<Link>::const_iterator link = m_linksList.begin ();
478  link != m_linksList.end ();
479  link ++)
480  {
481  os << Names::FindName (link->GetFromNode ()) << "\t";
482  os << Names::FindName (link->GetToNode ()) << "\t";
483 
484  string tmp;
485  if (link->GetAttributeFailSafe ("DataRate", tmp))
486  os << link->GetAttribute("DataRate") << "\t";
487  else
488  NS_FATAL_ERROR ("DataRate must be specified for the link");
489 
490  if (link->GetAttributeFailSafe ("OSPF", tmp))
491  os << link->GetAttribute("OSPF") << "\t";
492  else
493  os << "1\t";
494 
495  if (link->GetAttributeFailSafe ("Delay", tmp))
496  {
497  os << link->GetAttribute("Delay") << "\t";
498 
499  if (link->GetAttributeFailSafe ("MaxPackets", tmp))
500  {
501  os << link->GetAttribute("MaxPackets") << "\t";
502 
503  if (link->GetAttributeFailSafe ("LossRate", tmp))
504  {
505  os << link->GetAttribute ("LossRate") << "\t";
506  }
507  }
508  }
509  os << "\n";
510  }
511 }
512 
513 
514 template <class Names>
515 class name_writer {
516 public:
517  name_writer(Names _names) : names(_names) {}
518 
519  template <class VertexOrEdge>
520  void operator()(std::ostream& out, const VertexOrEdge& v) const {
521  // out << "[label=\"" << names[v] << "\",style=filled,fillcolor=\"" << colors[v] << "\"]";
522  out << "[shape=\"circle\",width=0.1,label=\"\",style=filled,fillcolor=\"green\"]";
523  }
524 private:
525  Names names;
526 };
527 
528 template <class Names>
529 inline name_writer<Names>
530 make_name_writer(Names n) {
531  return name_writer<Names>(n);
532 }
533 
534 
535 void
536 AnnotatedTopologyReader::SaveGraphviz (const std::string &file)
537 {
538  typedef boost::adjacency_list_traits<boost::setS, boost::setS, boost::undirectedS> Traits;
539 
540  typedef boost::property< boost::vertex_name_t, std::string, boost::property
541  < boost::vertex_index_t, uint32_t > > nodeProperty;
542 
543  typedef boost::no_property edgeProperty;
544 
545  typedef boost::adjacency_list< boost::setS, boost::setS, boost::undirectedS,
546  nodeProperty, edgeProperty > Graph;
547 
548  typedef map<string, Traits::vertex_descriptor> node_map_t;
549  node_map_t graphNodes;
550  Graph graph;
551 
552  for (NodeContainer::Iterator node = m_nodes.Begin ();
553  node != m_nodes.End ();
554  node++)
555  {
556  std::pair<node_map_t::iterator, bool>
557  retval = graphNodes.insert (make_pair (Names::FindName (*node),
558  add_vertex (nodeProperty (Names::FindName (*node)), graph)));
559  // NS_ASSERT (ok == true);
560 
561  put (boost::vertex_index, graph, retval.first->second, (*node)->GetId ());
562  }
563 
564  for (std::list<Link>::const_iterator link = m_linksList.begin ();
565  link != m_linksList.end ();
566  link ++)
567  {
568  node_map_t::iterator from = graphNodes.find (Names::FindName (link->GetFromNode ()));
569  node_map_t::iterator to = graphNodes.find (Names::FindName (link->GetToNode ()));
570 
571  // add_edge (node->second, otherNode->second, m_graph);
572  boost::add_edge (from->second, to->second, graph);
573  }
574 
575  ofstream of (file.c_str ());
576  boost::property_map<Graph, boost::vertex_name_t>::type names = get (boost::vertex_name, graph);
577  write_graphviz (of, graph, make_name_writer (names));
578 }
579 
580 
581 }
virtual void SaveGraphviz(const std::string &file)
Save topology in graphviz format (.dot file)
virtual NodeContainer GetNodes() const
Get nodes read by the reader.
virtual void SaveTopology(const std::string &file)
Save positions (e.g., after manual modification using visualizer)
Implementation network-layer of NDN stack.
virtual const std::list< Link > & GetLinks() const
Get links read by the reader.
virtual void ApplyOspfMetric()
Apply OSPF metric on Ipv4 (if exists) and Ccnx (if exists) stacks.
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.
virtual Ptr< Face > GetFaceByNetDevice(Ptr< NetDevice > netDevice) const
Get face for NetDevice.
virtual void AssignIpv4Addresses(Ipv4Address base)
Assign IPv4 addresses to all links.
virtual void SetMobilityModel(const std::string &model)
Set mobility model to be used on nodes.