| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| /* |
| * Copyright (c) 2013 University of California, Los Angeles |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation; |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| * Author: Ilya Moiseenko <iliamo@cs.ucla.edu> |
| * Hajime Tazaki (tazaki@sfc.wide.ad.jp) |
| * Alexander Afanasyev <alexander.afanasyev@ucla.edu> |
| * |
| */ |
| |
| #include "rocketfuel-map-reader.h" |
| |
| #include "ns3/nstime.h" |
| #include "ns3/log.h" |
| #include "ns3/fatal-error.h" |
| #include "ns3/assert.h" |
| #include "ns3/names.h" |
| #include "ns3/net-device-container.h" |
| #include "ns3/point-to-point-helper.h" |
| #include "ns3/point-to-point-net-device.h" |
| #include "ns3/internet-stack-helper.h" |
| #include "ns3/ipv4-address-helper.h" |
| #include "ns3/ipv4-global-routing-helper.h" |
| #include "ns3/drop-tail-queue.h" |
| #include "ns3/ipv4-interface.h" |
| #include "ns3/ipv4.h" |
| #include "ns3/string.h" |
| #include "ns3/pointer.h" |
| #include "ns3/uinteger.h" |
| #include "ns3/ipv4-address.h" |
| #include "ns3/node-list.h" |
| #include "ns3/random-variable.h" |
| |
| #include "ns3/mobility-model.h" |
| |
| #include <regex.h> |
| |
| #include <boost/foreach.hpp> |
| #include <boost/lexical_cast.hpp> |
| |
| #include <boost/graph/graphviz.hpp> |
| #include <boost/graph/connected_components.hpp> |
| |
| #include <iomanip> |
| |
| using namespace std; |
| using namespace boost; |
| |
| NS_LOG_COMPONENT_DEFINE ("RocketfuelMapReader"); |
| |
| namespace ns3 { |
| |
| RocketfuelMapReader::RocketfuelMapReader (const std::string &path/*=""*/, double scale/*=1.0*/, const std::string &referenceOspfRate) |
| : AnnotatedTopologyReader (path, scale) |
| , m_referenceOspfRate (boost::lexical_cast<DataRate> (referenceOspfRate)) |
| { |
| } |
| |
| RocketfuelMapReader::~RocketfuelMapReader () |
| { |
| } |
| |
| NodeContainer |
| RocketfuelMapReader::Read () |
| { |
| NS_FATAL_ERROR ("Deprecated call. Use the other overloaded method instead"); |
| return NodeContainer (); |
| } |
| |
| |
| /* uid @loc [+] [bb] (num_neigh) [&ext] -> <nuid-1> <nuid-2> ... {-euid} ... =name[!] rn */ |
| |
| #define REGMATCH_MAX 16 |
| |
| #define START "^" |
| #define END "$" |
| #define SPACE "[ \t]+" |
| #define MAYSPACE "[ \t]*" |
| |
| #define ROCKETFUEL_MAPS_LINE \ |
| START "(-*[0-9]+)" SPACE "(@[?A-Za-z0-9,+]+)" SPACE \ |
| "(\\+)*" MAYSPACE "(bb)*" MAYSPACE \ |
| "\\(([0-9]+)\\)" SPACE "(&[0-9]+)*" MAYSPACE \ |
| "->" MAYSPACE "(<[0-9 \t<>]+>)*" MAYSPACE \ |
| "(\\{-[0-9\\{\\} \t-]+\\})*" SPACE \ |
| "=([A-Za-z0-9.!-]+)" SPACE "r([0-9])" \ |
| MAYSPACE END |
| |
| void |
| RocketfuelMapReader::CreateLink (string nodeName1, string nodeName2, |
| double averageRtt, |
| const string &minBw, const string &maxBw, |
| const string &minDelay, const string &maxDelay) |
| { |
| Ptr<Node> node1 = Names::Find<Node> (m_path, nodeName1); |
| Ptr<Node> node2 = Names::Find<Node> (m_path, nodeName2); |
| Link link (node1, nodeName1, node2, nodeName2); |
| |
| DataRate randBandwidth |
| (m_randVar.GetInteger (static_cast<uint32_t> (lexical_cast<DataRate> (minBw).GetBitRate ()), |
| static_cast<uint32_t> (lexical_cast<DataRate> (maxBw).GetBitRate ()))); |
| |
| int32_t metric = std::max (1, static_cast<int32_t> (1.0 * m_referenceOspfRate.GetBitRate () / randBandwidth.GetBitRate ())); |
| |
| Time randDelay = |
| Time::FromDouble ((m_randVar.GetValue (lexical_cast<Time> (minDelay).ToDouble (Time::US), |
| lexical_cast<Time> (maxDelay).ToDouble (Time::US))), |
| Time::US); |
| |
| uint32_t queue = ceil (averageRtt * (randBandwidth.GetBitRate () / 8.0 / 1100.0)); |
| |
| link.SetAttribute ("DataRate", boost::lexical_cast<string> (randBandwidth)); |
| link.SetAttribute ("OSPF", boost::lexical_cast<string> (metric)); |
| link.SetAttribute ("Delay", boost::lexical_cast<string> (ceil (randDelay.ToDouble (Time::US)))+"us"); |
| link.SetAttribute ("MaxPackets", boost::lexical_cast<string> (queue)); |
| |
| AddLink (link); |
| } |
| |
| // NodeContainer |
| void |
| RocketfuelMapReader::GenerateFromMapsFile (int argc, char *argv[]) |
| { |
| string uid; |
| string loc; |
| string ptr; |
| string name; |
| string nuid; |
| bool dns = false; |
| bool bb = false; |
| int num_neigh_s = 0; |
| unsigned int num_neigh = 0; |
| int radius = 0; |
| vector <string> neigh_list; |
| |
| uid = argv[0]; |
| loc = argv[1]; |
| |
| if (argv[2]) |
| { |
| dns = true; |
| } |
| |
| if (argv[3]) |
| { |
| bb = true; |
| } |
| |
| num_neigh_s = ::atoi (argv[4]); |
| if (num_neigh_s < 0) |
| { |
| num_neigh = 0; |
| NS_LOG_WARN ("Negative number of neighbors given"); |
| } |
| else |
| { |
| num_neigh = num_neigh_s; |
| } |
| |
| /* neighbors */ |
| if (argv[6]) |
| { |
| char *nbr; |
| char *stringp = argv[6]; |
| while ((nbr = strsep (&stringp, " \t")) != NULL) |
| { |
| nbr[strlen (nbr) - 1] = '\0'; |
| neigh_list.push_back (nbr + 1); |
| } |
| } |
| |
| if (num_neigh != neigh_list.size ()) |
| { |
| NS_LOG_WARN ("Given number of neighbors = " << num_neigh << " != size of neighbors list = " << neigh_list.size ()); |
| } |
| |
| /* externs */ |
| if (argv[7]) |
| { |
| // euid = argv[7]; |
| } |
| |
| /* name */ |
| if (argv[8]) |
| { |
| name = argv[8]; |
| } |
| |
| radius = ::atoi (&argv[9][1]); |
| if (radius > 0) |
| { |
| return; |
| } |
| |
| // Create node and link |
| if (uid.empty ()) |
| return; |
| |
| |
| node_map_t::iterator node = m_graphNodes.find (uid); |
| if (node == m_graphNodes.end ()) |
| { |
| bool ok; |
| tie (node, ok) = m_graphNodes.insert (make_pair (uid, add_vertex (nodeProperty (uid), m_graph))); |
| NS_ASSERT (ok == true); |
| |
| put (vertex_index, m_graph, node->second, m_maxNodeId); |
| m_maxNodeId ++; |
| } |
| |
| for (uint32_t i = 0; i < neigh_list.size (); ++i) |
| { |
| nuid = neigh_list[i]; |
| |
| if (nuid.empty ()) |
| { |
| continue; |
| } |
| |
| node_map_t::iterator otherNode = m_graphNodes.find (nuid); |
| if (otherNode == m_graphNodes.end ()) |
| { |
| bool ok; |
| tie (otherNode, ok) = m_graphNodes.insert (make_pair (nuid, add_vertex(nodeProperty (nuid), m_graph))); |
| NS_ASSERT (ok == true); |
| |
| put (vertex_index, m_graph, otherNode->second, m_maxNodeId); |
| m_maxNodeId ++; |
| } |
| |
| // cout << node->second << " <-> " << otherNode->second << endl; |
| // parallel edges are disabled in the graph, so no need to worry |
| add_edge (node->second, otherNode->second, m_graph); |
| } |
| } |
| |
| void RocketfuelMapReader::assignGw (Traits::vertex_descriptor vertex, uint32_t degree, node_type_t nodeType) |
| { |
| graph_traits<Graph>::adjacency_iterator u, endu; |
| for (tie (u, endu) = adjacent_vertices (vertex, m_graph); u != endu; u++) |
| { |
| if (get (vertex_rank, m_graph, *u) != UNKNOWN) |
| continue; |
| |
| put (vertex_rank, m_graph, *u, nodeType); |
| put (vertex_color, m_graph, *u, "green"); |
| |
| uint32_t u_degree = out_degree (*u, m_graph); |
| if (u_degree < degree) |
| assignGw (*u, degree, BACKBONE); |
| } |
| }; |
| |
| void |
| RocketfuelMapReader::AssignClients (uint32_t clientDegree, uint32_t gwDegree) |
| { |
| graph_traits<Graph>::vertex_iterator v, endv; |
| for (tie(v, endv) = vertices(m_graph); v != endv; v++) |
| { |
| uint32_t degree = out_degree (*v, m_graph); |
| if (degree == clientDegree) |
| { |
| put (vertex_rank, m_graph, *v, CLIENT); |
| put (vertex_color, m_graph, *v, "red"); |
| |
| assignGw (*v, gwDegree+1, GATEWAY); |
| } |
| } |
| }; |
| |
| NodeContainer |
| RocketfuelMapReader::Read (RocketfuelParams params, bool keepOneComponent/*=true*/, bool connectBackbones/*=true*/) |
| { |
| m_maxNodeId = 0; |
| |
| ifstream topgen; |
| topgen.open (GetFileName ().c_str ()); |
| //NodeContainer nodes; |
| UniformVariable var; |
| |
| istringstream lineBuffer; |
| string line; |
| int lineNumber = 0; |
| char errbuf[512]; |
| |
| if (!topgen.is_open ()) |
| { |
| NS_LOG_WARN ("Couldn't open the file " << GetFileName ()); |
| return m_nodes; |
| } |
| |
| while (!topgen.eof ()) |
| { |
| int ret; |
| int argc; |
| char *argv[REGMATCH_MAX]; |
| char *buf; |
| |
| lineNumber++; |
| line.clear (); |
| lineBuffer.clear (); |
| |
| getline (topgen, line); |
| buf = (char *)line.c_str (); |
| |
| regmatch_t regmatch[REGMATCH_MAX]; |
| regex_t regex; |
| |
| ret = regcomp (®ex, ROCKETFUEL_MAPS_LINE, REG_EXTENDED | REG_NEWLINE); |
| if (ret != 0) |
| { |
| regerror (ret, ®ex, errbuf, sizeof (errbuf)); |
| regfree (®ex); |
| continue; |
| } |
| |
| ret = regexec (®ex, buf, REGMATCH_MAX, regmatch, 0); |
| if (ret == REG_NOMATCH) |
| { |
| NS_LOG_WARN ("match failed (maps file): %s" << buf); |
| regfree (®ex); |
| continue; |
| } |
| |
| line = buf; |
| argc = 0; |
| |
| /* regmatch[0] is the entire strings that matched */ |
| for (int i = 1; i < REGMATCH_MAX; i++) |
| { |
| if (regmatch[i].rm_so == -1) |
| { |
| argv[i - 1] = NULL; |
| } |
| else |
| { |
| line[regmatch[i].rm_eo] = '\0'; |
| argv[i - 1] = &line[regmatch[i].rm_so]; |
| argc = i; |
| } |
| } |
| |
| GenerateFromMapsFile (argc, argv); |
| regfree (®ex); |
| } |
| |
| if (keepOneComponent) |
| { |
| NS_LOG_DEBUG ("Before eliminating disconnected nodes: " << num_vertices(m_graph)); |
| KeepOnlyBiggestConnectedComponent (); |
| NS_LOG_DEBUG ("After eliminating disconnected nodes: " << num_vertices(m_graph)); |
| } |
| |
| for (int clientDegree = 1; clientDegree <= params.clientNodeDegrees; clientDegree++) |
| { |
| AssignClients (clientDegree, std::min (clientDegree, 3)); |
| } |
| |
| graph_traits<Graph>::vertex_iterator v, endv; |
| for (tie(v, endv) = vertices(m_graph); v != endv; v++) |
| { |
| node_type_t type = get (vertex_rank, m_graph, *v); |
| if (type == UNKNOWN) |
| { |
| put (vertex_rank, m_graph, *v, BACKBONE); |
| put (vertex_color, m_graph, *v, "blue"); |
| } |
| } |
| |
| if (connectBackbones) |
| { |
| ConnectBackboneRouters (); |
| } |
| |
| graph_traits<Graph>::edge_iterator e, ende; |
| for (tie (e, ende) = edges (m_graph); e != ende; ) |
| { |
| Traits::vertex_descriptor |
| u = source (*e, m_graph), |
| v = target (*e, m_graph); |
| |
| node_type_t |
| u_type = get (vertex_rank, m_graph, u), |
| v_type = get (vertex_rank, m_graph, v); |
| |
| if (u_type == BACKBONE && v_type == BACKBONE) |
| { |
| // ok |
| } |
| else if ((u_type == GATEWAY && v_type == BACKBONE) || |
| (u_type == BACKBONE && v_type == GATEWAY )) |
| { |
| // ok |
| } |
| else if (u_type == GATEWAY && v_type == GATEWAY) |
| { |
| // ok |
| } |
| else if ((u_type == GATEWAY && v_type == CLIENT) || |
| (u_type == CLIENT && v_type == GATEWAY )) |
| { |
| // ok |
| } |
| else |
| { |
| // not ok |
| NS_LOG_DEBUG ("Wrong link type between nodes: " << u_type << " <-> " << v_type << " (deleting the link)"); |
| |
| graph_traits<Graph>::edge_iterator tmp = e; |
| tmp++; |
| |
| remove_edge (*e, m_graph); |
| e = tmp; |
| continue; |
| } |
| e++; |
| } |
| |
| if (keepOneComponent) |
| { |
| NS_LOG_DEBUG ("Before 2 eliminating disconnected nodes: " << num_vertices(m_graph)); |
| KeepOnlyBiggestConnectedComponent (); |
| NS_LOG_DEBUG ("After 2 eliminating disconnected nodes: " << num_vertices(m_graph)); |
| } |
| |
| for (tie(v, endv) = vertices(m_graph); v != endv; v++) |
| { |
| string nodeName = get (vertex_name, m_graph, *v); |
| Ptr<Node> node = CreateNode (nodeName, 0); |
| |
| node_type_t type = get (vertex_rank, m_graph, *v); |
| switch (type) |
| { |
| case BACKBONE: |
| Names::Rename (nodeName, "bb-" + nodeName); |
| put (vertex_name, m_graph, *v, "bb-" + nodeName); |
| m_backboneRouters.Add (node); |
| break; |
| case CLIENT: |
| Names::Rename (nodeName, "leaf-" + nodeName); |
| put (vertex_name, m_graph, *v, "leaf-" + nodeName); |
| m_customerRouters.Add (node); |
| break; |
| case GATEWAY: |
| Names::Rename (nodeName, "gw-" + nodeName); |
| put (vertex_name, m_graph, *v, "gw-" + nodeName); |
| m_gatewayRouters.Add (node); |
| break; |
| case UNKNOWN: |
| NS_FATAL_ERROR ("Should not happen"); |
| break; |
| } |
| } |
| |
| for (tie (e, ende) = edges (m_graph); e != ende; e++) |
| { |
| Traits::vertex_descriptor |
| u = source (*e, m_graph), |
| v = target (*e, m_graph); |
| |
| node_type_t |
| u_type = get (vertex_rank, m_graph, u), |
| v_type = get (vertex_rank, m_graph, v); |
| |
| string |
| u_name = get (vertex_name, m_graph, u), |
| v_name = get (vertex_name, m_graph, v); |
| |
| if (u_type == BACKBONE && v_type == BACKBONE) |
| { |
| CreateLink (u_name, v_name, |
| params.averageRtt, |
| params.minb2bBandwidth, params.maxb2bBandwidth, |
| params.minb2bDelay, params.maxb2bDelay); |
| } |
| else if ((u_type == GATEWAY && v_type == BACKBONE) || |
| (u_type == BACKBONE && v_type == GATEWAY )) |
| { |
| CreateLink (u_name, v_name, |
| params.averageRtt, |
| params.minb2gBandwidth, params.maxb2gBandwidth, |
| params.minb2gDelay, params.maxb2gDelay); |
| } |
| else if (u_type == GATEWAY && v_type == GATEWAY) |
| { |
| CreateLink (u_name, v_name, |
| params.averageRtt, |
| params.minb2gBandwidth, params.maxb2gBandwidth, |
| params.minb2gDelay, params.maxb2gDelay); |
| } |
| else if ((u_type == GATEWAY && v_type == CLIENT) || |
| (u_type == CLIENT && v_type == GATEWAY )) |
| { |
| CreateLink (u_name, v_name, |
| params.averageRtt, |
| params.ming2cBandwidth, params.maxg2cBandwidth, |
| params.ming2cDelay, params.maxg2cDelay); |
| } |
| else |
| { |
| NS_FATAL_ERROR ("Wrong link type between nodes: " << u_type << " <-> " << v_type); |
| } |
| } |
| |
| ApplySettings (); |
| |
| NS_LOG_INFO ("Clients: " << m_customerRouters.GetN ()); |
| NS_LOG_INFO ("Gateways: " << m_gatewayRouters.GetN ()); |
| NS_LOG_INFO ("Backbones: " << m_backboneRouters.GetN ()); |
| NS_LOG_INFO ("Links: " << GetLinks ().size ()); |
| |
| return m_nodes; |
| } |
| |
| const NodeContainer & |
| RocketfuelMapReader::GetBackboneRouters () const |
| { |
| return m_backboneRouters; |
| } |
| |
| const NodeContainer & |
| RocketfuelMapReader::GetGatewayRouters () const |
| { |
| return m_gatewayRouters; |
| } |
| |
| const NodeContainer & |
| RocketfuelMapReader::GetCustomerRouters () const |
| { |
| return m_customerRouters; |
| } |
| |
| void |
| RocketfuelMapReader::SaveTopology (const std::string &file) |
| { |
| ofstream os (file.c_str (), ios::trunc); |
| os << "# any empty lines and lines starting with '#' symbol is ignored\n" |
| << "\n" |
| << "# The file should contain exactly two sections: router and link, each starting with the corresponding keyword\n" |
| << "\n" |
| << "# router section defines topology nodes and their relative positions (e.g., to use in visualizer)\n" |
| << "router\n" |
| << "\n" |
| << "# each line in this section represents one router and should have the following data\n" |
| << "# node comment yPos xPos\n"; |
| |
| auto nodeWriter = [&os](NodeContainer& m) { |
| for_each (m.Begin (), m.End (), [&os](Ptr<Node> node) |
| { |
| std::string name = Names::FindName (node); |
| |
| os << name << "\t" << "NA" << "\t" << 0 << "\t" << 0 << "\n"; |
| }); |
| }; |
| |
| nodeWriter (m_backboneRouters); |
| nodeWriter (m_gatewayRouters); |
| nodeWriter (m_customerRouters); |
| |
| os << "# link section defines point-to-point links between nodes and characteristics of these links\n" |
| << "\n" |
| << "link\n" |
| << "\n" |
| << "# Each line should be in the following format (only first two are required, the rest can be omitted)\n" |
| << "# srcNode dstNode bandwidth metric delay queue\n" |
| << "# bandwidth: link bandwidth\n" |
| << "# metric: routing metric\n" |
| << "# delay: link delay\n" |
| << "# queue: MaxPackets for transmission queue on the link (both directions)\n"; |
| |
| for_each (m_linksList.begin (), m_linksList.end (), [&](const Link &link) { |
| string src = Names::FindName (link.GetFromNode ()); |
| string dst = Names::FindName (link.GetToNode ()); |
| os << src << "\t"; |
| os << dst << "\t"; |
| |
| string tmp; |
| if (link.GetAttributeFailSafe ("DataRate", tmp)) |
| os << link.GetAttribute("DataRate") << "\t"; |
| else |
| NS_FATAL_ERROR ("DataRate must be specified for the link"); |
| |
| if (link.GetAttributeFailSafe ("OSPF", tmp)) |
| os << link.GetAttribute("OSPF") << "\t"; |
| else |
| { |
| DataRate rate = boost::lexical_cast<DataRate> (link.GetAttribute("DataRate")); |
| |
| int32_t cost = std::max (1, static_cast<int32_t> (1.0 * m_referenceOspfRate.GetBitRate () / rate.GetBitRate ())); |
| |
| os << cost << "\t"; |
| } |
| |
| if (link.GetAttributeFailSafe ("Delay", tmp)) |
| { |
| os << link.GetAttribute("Delay") << "\t"; |
| |
| if (link.GetAttributeFailSafe ("MaxPackets", tmp)) |
| { |
| os << link.GetAttribute("MaxPackets") << "\t"; |
| } |
| } |
| os << "\n"; |
| }); |
| } |
| |
| |
| template <class Names, class Colors> |
| class name_color_writer { |
| public: |
| name_color_writer(Names _names, Colors _colors) : names(_names), colors(_colors) {} |
| |
| template <class VertexOrEdge> |
| void operator()(std::ostream& out, const VertexOrEdge& v) const { |
| // out << "[label=\"" << names[v] << "\",style=filled,fillcolor=\"" << colors[v] << "\"]"; |
| out << "[shape=\"circle\",width=0.1,label=\"\",style=filled,fillcolor=\"" << colors[v] << "\"]"; |
| } |
| private: |
| Names names; |
| Colors colors; |
| }; |
| |
| template <class Names, class Colors> |
| inline name_color_writer<Names, Colors> |
| make_name_color_writer(Names n, Colors c) { |
| return name_color_writer<Names, Colors>(n, c); |
| } |
| |
| |
| void |
| RocketfuelMapReader::SaveGraphviz (const std::string &file) |
| { |
| ofstream of (file.c_str ()); |
| property_map<Graph, vertex_name_t>::type names = get (vertex_name, m_graph); |
| property_map<Graph, vertex_color_t>::type colors = get (vertex_color, m_graph); |
| write_graphviz(of, m_graph, make_name_color_writer (names, colors)); |
| } |
| |
| |
| void |
| RocketfuelMapReader::KeepOnlyBiggestConnectedComponent () |
| { |
| std::map<graph_traits<Graph>::vertex_descriptor, int> temp; |
| associative_property_map< std::map<graph_traits<Graph>::vertex_descriptor, int> > components (temp); |
| |
| // //check if topology has breaks in its structure and trim it if yes |
| // property_map<Graph, vertex_index1_t>::type components = get (vertex_index1, m_graph); |
| |
| int num = connected_components (m_graph, components); |
| NS_LOG_DEBUG ("Topology has " << num << " components"); |
| |
| vector<int> sizes (num, 0); |
| |
| graph_traits<Graph>::vertex_iterator v, endv; |
| for (tie(v, endv) = vertices(m_graph); v != endv; v++) |
| { |
| sizes[ get (components, *v) ] ++; |
| } |
| int largestComponent = max_element (sizes.begin (), sizes.end ()) - sizes.begin (); |
| // cout << "Largest: " << largestComponent << endl; |
| |
| // for (int i =0 ; i < num; i++) cout << sizes[i] << " "; |
| // cout << endl; |
| |
| //////////////////////////////////////////////////// |
| // remove nodes and edges from smaller components // |
| //////////////////////////////////////////////////// |
| for (tie(v, endv) = vertices(m_graph); v != endv; v++) |
| { |
| if (get (components, *v) == largestComponent) |
| continue; |
| |
| clear_vertex (*v, m_graph); |
| } |
| |
| // this works only if vertices are organized in listS or setS (iterator is not invalidated on remove) |
| for (tie(v, endv) = vertices(m_graph); v != endv; ) |
| { |
| if (get (components, *v) == largestComponent) |
| { |
| v++; |
| continue; |
| } |
| |
| graph_traits<Graph>::vertex_iterator tmp = v; |
| tmp++; |
| |
| remove_vertex (*v, m_graph); |
| v = tmp; |
| } |
| |
| int index = 0; |
| // renumber nodes |
| for (tie(v, endv) = vertices(m_graph); v != endv; v++) |
| { |
| put (vertex_index, m_graph, *v, index++); |
| } |
| } |
| |
| void |
| RocketfuelMapReader::ConnectBackboneRouters () |
| { |
| // not the tricky part. we want backbone to be a fully connected component, |
| // so traffic doesn't bounce from backbone to gateway and back |
| |
| typedef adjacency_list< setS, setS, boost::undirectedS, |
| property<vertex_name_t, Traits::vertex_descriptor, property |
| < vertex_index_t, int, property |
| < vertex_index1_t, int > > > > BbGraph; |
| BbGraph bbGraph; |
| map<Traits::vertex_descriptor, graph_traits<BbGraph>::vertex_descriptor> nodeMap; |
| |
| int index = 0; |
| |
| graph_traits<Graph>::vertex_iterator v, endv; |
| for (tie(v, endv) = vertices(m_graph); v != endv; v++) |
| { |
| node_type_t type = get (vertex_rank, m_graph, *v); |
| if (type == BACKBONE) |
| { |
| graph_traits<BbGraph>::vertex_descriptor newv = add_vertex (*v, bbGraph); |
| put (vertex_index, bbGraph, newv, index++); |
| nodeMap[*v] = newv; |
| } |
| } |
| |
| graph_traits<BbGraph>::vertex_iterator bb, endBb; |
| for (tie (bb, endBb) = vertices (bbGraph); bb != endBb; bb++) |
| { |
| Traits::vertex_descriptor actualVertex = get (vertex_name, bbGraph, *bb); |
| |
| graph_traits<Graph>::adjacency_iterator u, endu; |
| for (tie (u, endu) = adjacent_vertices (actualVertex, m_graph); u != endu; u++) |
| { |
| if (nodeMap.find (*u) != nodeMap.end ()) |
| { |
| add_edge (nodeMap [actualVertex], nodeMap[*u], bbGraph); |
| } |
| } |
| } |
| |
| property_map<BbGraph, vertex_index1_t>::type components = get (vertex_index1, bbGraph); |
| |
| int num = connected_components (bbGraph, components); |
| NS_LOG_DEBUG ("Backbone has " << num << " components"); |
| if (num == 1) |
| return; // nothing to do |
| |
| vector< vector<graph_traits<BbGraph>::vertex_descriptor> > subgraphs (num); |
| for (tie (bb, endBb) = vertices (bbGraph); bb != endBb; bb++) |
| { |
| int component = get (vertex_index1, bbGraph, *bb); |
| subgraphs [component].push_back (*bb); |
| } |
| |
| UniformVariable randVar; |
| |
| for (int i = 1; i < num; i++) |
| { |
| int node1 = randVar.GetInteger (0, subgraphs[i-1].size ()-1); |
| int node2 = randVar.GetInteger (0, subgraphs[i].size ()-1); |
| |
| Traits::vertex_descriptor |
| v1 = get (vertex_name, bbGraph, subgraphs[i-1][node1]), |
| v2 = get (vertex_name, bbGraph, subgraphs[i ][node2]); |
| |
| NS_LOG_DEBUG ("Connecting " << get (vertex_name, m_graph, v1) << "[" << node1 << "] with " |
| << get (vertex_name, m_graph, v2) << "[" << node2 << "]"); |
| |
| add_edge (v1, v2, m_graph); |
| } |
| } |
| |
| |
| } /* namespace ns3 */ |