445 lines
15 KiB
C++
445 lines
15 KiB
C++
/*
|
|
* Copyright (c) 2010 Egemen K. Cetinkaya, Justin P. Rohrer, and Amit Dandekar
|
|
*
|
|
* 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: Egemen K. Cetinkaya <ekc@ittc.ku.edu>
|
|
* Author: Justin P. Rohrer <rohrej@ittc.ku.edu>
|
|
* Author: Amit Dandekar <dandekar@ittc.ku.edu>
|
|
*
|
|
* James P.G. Sterbenz <jpgs@ittc.ku.edu>, director
|
|
* ResiliNets Research Group https://resilinets.org/
|
|
* Information and Telecommunication Technology Center
|
|
* and
|
|
* Department of Electrical Engineering and Computer Science
|
|
* The University of Kansas
|
|
* Lawrence, KS USA
|
|
*
|
|
* Work supported in part by NSF FIND (Future Internet Design) Program
|
|
* under grant CNS-0626918 (Postmodern Internet Architecture) and
|
|
* by NSF grant CNS-1050226 (Multilayer Network Resilience Analysis and Experimentation on GENI)
|
|
*
|
|
* This program reads an upper triangular adjacency matrix (e.g. adjacency_matrix.txt) and
|
|
* node coordinates file (e.g. node_coordinates.txt). The program also set-ups a
|
|
* wired network topology with P2P links according to the adjacency matrix with
|
|
* nx(n-1) CBR traffic flows, in which n is the number of nodes in the adjacency matrix.
|
|
*/
|
|
|
|
// ---------- Header Includes -------------------------------------------------
|
|
#include "ns3/applications-module.h"
|
|
#include "ns3/assert.h"
|
|
#include "ns3/core-module.h"
|
|
#include "ns3/global-route-manager.h"
|
|
#include "ns3/internet-module.h"
|
|
#include "ns3/ipv4-global-routing-helper.h"
|
|
#include "ns3/mobility-module.h"
|
|
#include "ns3/netanim-module.h"
|
|
#include "ns3/network-module.h"
|
|
#include "ns3/point-to-point-module.h"
|
|
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace ns3;
|
|
|
|
// ---------- Prototypes ------------------------------------------------------
|
|
|
|
std::vector<std::vector<bool>> readNxNMatrix(std::string adj_mat_file_name);
|
|
std::vector<std::vector<double>> readCoordinatesFile(std::string node_coordinates_file_name);
|
|
void printCoordinateArray(const char* description, std::vector<std::vector<double>> coord_array);
|
|
void printMatrix(const char* description, std::vector<std::vector<bool>> array);
|
|
|
|
NS_LOG_COMPONENT_DEFINE("GenericTopologyCreation");
|
|
|
|
int
|
|
main(int argc, char* argv[])
|
|
{
|
|
// ---------- Simulation Variables ------------------------------------------
|
|
|
|
// Change the variables and file names only in this block!
|
|
|
|
double SimTime = 3.00;
|
|
double SinkStartTime = 1.0001;
|
|
double SinkStopTime = 2.90001;
|
|
double AppStartTime = 2.0001;
|
|
double AppStopTime = 2.80001;
|
|
|
|
std::string AppPacketRate("40Kbps");
|
|
Config::SetDefault("ns3::OnOffApplication::PacketSize", StringValue("1000"));
|
|
Config::SetDefault("ns3::OnOffApplication::DataRate", StringValue(AppPacketRate));
|
|
std::string LinkRate("10Mbps");
|
|
std::string LinkDelay("2ms");
|
|
// DropTailQueue::MaxPackets affects the # of dropped packets, default value:100
|
|
// Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (1000));
|
|
|
|
srand((unsigned)time(nullptr)); // generate different seed each time
|
|
|
|
std::string tr_name("n-node-ppp.tr");
|
|
std::string pcap_name("n-node-ppp");
|
|
std::string flow_name("n-node-ppp.xml");
|
|
std::string anim_name("n-node-ppp.anim.xml");
|
|
|
|
std::string adj_mat_file_name("examples/matrix-topology/adjacency_matrix.txt");
|
|
std::string node_coordinates_file_name("examples/matrix-topology/node_coordinates.txt");
|
|
|
|
CommandLine cmd(__FILE__);
|
|
cmd.Parse(argc, argv);
|
|
|
|
// ---------- End of Simulation Variables ----------------------------------
|
|
|
|
// ---------- Read Adjacency Matrix ----------------------------------------
|
|
|
|
std::vector<std::vector<bool>> Adj_Matrix;
|
|
Adj_Matrix = readNxNMatrix(adj_mat_file_name);
|
|
|
|
// Optionally display 2-dimensional adjacency matrix (Adj_Matrix) array
|
|
// printMatrix (adj_mat_file_name.c_str (),Adj_Matrix);
|
|
|
|
// ---------- End of Read Adjacency Matrix ---------------------------------
|
|
|
|
// ---------- Read Node Coordinates File -----------------------------------
|
|
|
|
std::vector<std::vector<double>> coord_array;
|
|
coord_array = readCoordinatesFile(node_coordinates_file_name);
|
|
|
|
// Optionally display node coordinates file
|
|
// printCoordinateArray (node_coordinates_file_name.c_str (),coord_array);
|
|
|
|
int n_nodes = coord_array.size();
|
|
int matrixDimension = Adj_Matrix.size();
|
|
|
|
if (matrixDimension != n_nodes)
|
|
{
|
|
NS_FATAL_ERROR("The number of lines in coordinate file is: "
|
|
<< n_nodes << " not equal to the number of nodes in adjacency matrix size "
|
|
<< matrixDimension);
|
|
}
|
|
|
|
// ---------- End of Read Node Coordinates File ----------------------------
|
|
|
|
// ---------- Network Setup ------------------------------------------------
|
|
|
|
NS_LOG_INFO("Create Nodes.");
|
|
|
|
NodeContainer nodes; // Declare nodes objects
|
|
nodes.Create(n_nodes);
|
|
|
|
NS_LOG_INFO("Create P2P Link Attributes.");
|
|
|
|
PointToPointHelper p2p;
|
|
p2p.SetDeviceAttribute("DataRate", StringValue(LinkRate));
|
|
p2p.SetChannelAttribute("Delay", StringValue(LinkDelay));
|
|
|
|
NS_LOG_INFO("Install Internet Stack to Nodes.");
|
|
|
|
InternetStackHelper internet;
|
|
internet.Install(NodeContainer::GetGlobal());
|
|
|
|
NS_LOG_INFO("Assign Addresses to Nodes.");
|
|
|
|
Ipv4AddressHelper ipv4_n;
|
|
ipv4_n.SetBase("10.0.0.0", "255.255.255.252");
|
|
|
|
NS_LOG_INFO("Create Links Between Nodes.");
|
|
|
|
uint32_t linkCount = 0;
|
|
|
|
for (size_t i = 0; i < Adj_Matrix.size(); i++)
|
|
{
|
|
for (size_t j = 0; j < Adj_Matrix[i].size(); j++)
|
|
{
|
|
if (Adj_Matrix[i][j])
|
|
{
|
|
NodeContainer n_links = NodeContainer(nodes.Get(i), nodes.Get(j));
|
|
NetDeviceContainer n_devs = p2p.Install(n_links);
|
|
ipv4_n.Assign(n_devs);
|
|
ipv4_n.NewNetwork();
|
|
linkCount++;
|
|
NS_LOG_INFO("matrix element [" << i << "][" << j << "] is 1");
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_INFO("matrix element [" << i << "][" << j << "] is 0");
|
|
}
|
|
}
|
|
}
|
|
NS_LOG_INFO("Number of links in the adjacency matrix is: " << linkCount);
|
|
NS_LOG_INFO("Number of all nodes is: " << nodes.GetN());
|
|
|
|
NS_LOG_INFO("Initialize Global Routing.");
|
|
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
|
|
|
|
// ---------- End of Network Set-up ----------------------------------------
|
|
|
|
// ---------- Allocate Node Positions --------------------------------------
|
|
|
|
NS_LOG_INFO("Allocate Positions to Nodes.");
|
|
|
|
MobilityHelper mobility_n;
|
|
Ptr<ListPositionAllocator> positionAlloc_n = CreateObject<ListPositionAllocator>();
|
|
|
|
for (size_t m = 0; m < coord_array.size(); m++)
|
|
{
|
|
positionAlloc_n->Add(Vector(coord_array[m][0], coord_array[m][1], 0));
|
|
Ptr<Node> n0 = nodes.Get(m);
|
|
Ptr<ConstantPositionMobilityModel> nLoc = n0->GetObject<ConstantPositionMobilityModel>();
|
|
if (!nLoc)
|
|
{
|
|
nLoc = CreateObject<ConstantPositionMobilityModel>();
|
|
n0->AggregateObject(nLoc);
|
|
}
|
|
// y-coordinates are negated for correct display in NetAnim
|
|
// NetAnim's (0,0) reference coordinates are located on upper left corner
|
|
// by negating the y coordinates, we declare the reference (0,0) coordinate
|
|
// to the bottom left corner
|
|
Vector nVec(coord_array[m][0], -coord_array[m][1], 0);
|
|
nLoc->SetPosition(nVec);
|
|
}
|
|
mobility_n.SetPositionAllocator(positionAlloc_n);
|
|
mobility_n.Install(nodes);
|
|
|
|
// ---------- End of Allocate Node Positions -------------------------------
|
|
|
|
// ---------- Create n*(n-1) CBR Flows -------------------------------------
|
|
|
|
NS_LOG_INFO("Setup Packet Sinks.");
|
|
|
|
uint16_t port = 9;
|
|
|
|
for (int i = 0; i < n_nodes; i++)
|
|
{
|
|
PacketSinkHelper sink("ns3::UdpSocketFactory",
|
|
InetSocketAddress(Ipv4Address::GetAny(), port));
|
|
ApplicationContainer apps_sink =
|
|
sink.Install(nodes.Get(i)); // sink is installed on all nodes
|
|
apps_sink.Start(Seconds(SinkStartTime));
|
|
apps_sink.Stop(Seconds(SinkStopTime));
|
|
}
|
|
|
|
NS_LOG_INFO("Setup CBR Traffic Sources.");
|
|
|
|
for (int i = 0; i < n_nodes; i++)
|
|
{
|
|
for (int j = 0; j < n_nodes; j++)
|
|
{
|
|
if (i != j)
|
|
{
|
|
// We needed to generate a random number (rn) to be used to eliminate
|
|
// the artificial congestion caused by sending the packets at the
|
|
// same time. This rn is added to AppStartTime to have the sources
|
|
// start at different time, however they will still send at the same rate.
|
|
|
|
Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
|
|
x->SetAttribute("Min", DoubleValue(0));
|
|
x->SetAttribute("Max", DoubleValue(1));
|
|
double rn = x->GetValue();
|
|
Ptr<Node> n = nodes.Get(j);
|
|
Ptr<Ipv4> ipv4 = n->GetObject<Ipv4>();
|
|
Ipv4InterfaceAddress ipv4_int_addr = ipv4->GetAddress(1, 0);
|
|
Ipv4Address ip_addr = ipv4_int_addr.GetLocal();
|
|
OnOffHelper onoff(
|
|
"ns3::UdpSocketFactory",
|
|
InetSocketAddress(ip_addr, port)); // traffic flows from node[i] to node[j]
|
|
onoff.SetConstantRate(DataRate(AppPacketRate));
|
|
ApplicationContainer apps =
|
|
onoff.Install(nodes.Get(i)); // traffic sources are installed on all nodes
|
|
apps.Start(Seconds(AppStartTime + rn));
|
|
apps.Stop(Seconds(AppStopTime));
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------- End of Create n*(n-1) CBR Flows ------------------------------
|
|
|
|
// ---------- Simulation Monitoring ----------------------------------------
|
|
|
|
NS_LOG_INFO("Configure Tracing.");
|
|
|
|
AsciiTraceHelper ascii;
|
|
p2p.EnableAsciiAll(ascii.CreateFileStream(tr_name));
|
|
// p2p.EnablePcapAll(pcap_name);
|
|
|
|
// Ptr<FlowMonitor> flowmon;
|
|
// FlowMonitorHelper flowmonHelper;
|
|
// flowmon = flowmonHelper.InstallAll();
|
|
|
|
// Configure animator with default settings
|
|
|
|
AnimationInterface anim(anim_name);
|
|
NS_LOG_INFO("Run Simulation.");
|
|
|
|
Simulator::Stop(Seconds(SimTime));
|
|
Simulator::Run();
|
|
// flowmon->SerializeToXmlFile(flow_name, true, true);
|
|
Simulator::Destroy();
|
|
|
|
// ---------- End of Simulation Monitoring ---------------------------------
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ---------- Function Definitions -------------------------------------------
|
|
|
|
std::vector<std::vector<bool>>
|
|
readNxNMatrix(std::string adj_mat_file_name)
|
|
{
|
|
std::ifstream adj_mat_file;
|
|
adj_mat_file.open(adj_mat_file_name, std::ios::in);
|
|
if (adj_mat_file.fail())
|
|
{
|
|
NS_FATAL_ERROR("File " << adj_mat_file_name << " not found");
|
|
}
|
|
std::vector<std::vector<bool>> array;
|
|
int i = 0;
|
|
int n_nodes = 0;
|
|
|
|
while (!adj_mat_file.eof())
|
|
{
|
|
std::string line;
|
|
getline(adj_mat_file, line);
|
|
if (line.empty())
|
|
{
|
|
NS_LOG_WARN("WARNING: Ignoring blank row in the array: " << i);
|
|
break;
|
|
}
|
|
|
|
std::istringstream iss(line);
|
|
bool element;
|
|
std::vector<bool> row;
|
|
int j = 0;
|
|
|
|
while (iss >> element)
|
|
{
|
|
row.push_back(element);
|
|
j++;
|
|
}
|
|
|
|
if (i == 0)
|
|
{
|
|
n_nodes = j;
|
|
}
|
|
|
|
if (j != n_nodes)
|
|
{
|
|
NS_LOG_ERROR("ERROR: Number of elements in line "
|
|
<< i << ": " << j
|
|
<< " not equal to number of elements in line 0: " << n_nodes);
|
|
NS_FATAL_ERROR("ERROR: The number of rows is not equal to the number of columns! in "
|
|
"the adjacency matrix");
|
|
}
|
|
else
|
|
{
|
|
array.push_back(row);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (i != n_nodes)
|
|
{
|
|
NS_LOG_ERROR("There are " << i << " rows and " << n_nodes << " columns.");
|
|
NS_FATAL_ERROR("ERROR: The number of rows is not equal to the number of columns! in the "
|
|
"adjacency matrix");
|
|
}
|
|
|
|
adj_mat_file.close();
|
|
return array;
|
|
}
|
|
|
|
std::vector<std::vector<double>>
|
|
readCoordinatesFile(std::string node_coordinates_file_name)
|
|
{
|
|
std::ifstream node_coordinates_file;
|
|
node_coordinates_file.open(node_coordinates_file_name, std::ios::in);
|
|
if (node_coordinates_file.fail())
|
|
{
|
|
NS_FATAL_ERROR("File " << node_coordinates_file_name << " not found");
|
|
}
|
|
std::vector<std::vector<double>> coord_array;
|
|
int m = 0;
|
|
|
|
while (!node_coordinates_file.eof())
|
|
{
|
|
std::string line;
|
|
getline(node_coordinates_file, line);
|
|
|
|
if (line.empty())
|
|
{
|
|
NS_LOG_WARN("WARNING: Ignoring blank row: " << m);
|
|
break;
|
|
}
|
|
|
|
std::istringstream iss(line);
|
|
double coordinate;
|
|
std::vector<double> row;
|
|
int n = 0;
|
|
while (iss >> coordinate)
|
|
{
|
|
row.push_back(coordinate);
|
|
n++;
|
|
}
|
|
|
|
if (n != 2)
|
|
{
|
|
NS_LOG_ERROR("ERROR: Number of elements at line#"
|
|
<< m << " is " << n
|
|
<< " which is not equal to 2 for node coordinates file");
|
|
exit(1);
|
|
}
|
|
|
|
else
|
|
{
|
|
coord_array.push_back(row);
|
|
}
|
|
m++;
|
|
}
|
|
node_coordinates_file.close();
|
|
return coord_array;
|
|
}
|
|
|
|
void
|
|
printMatrix(const char* description, std::vector<std::vector<bool>> array)
|
|
{
|
|
std::cout << "**** Start " << description << "********" << std::endl;
|
|
for (size_t m = 0; m < array.size(); m++)
|
|
{
|
|
for (size_t n = 0; n < array[m].size(); n++)
|
|
{
|
|
std::cout << array[m][n] << ' ';
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
std::cout << "**** End " << description << "********" << std::endl;
|
|
}
|
|
|
|
void
|
|
printCoordinateArray(const char* description, std::vector<std::vector<double>> coord_array)
|
|
{
|
|
std::cout << "**** Start " << description << "********" << std::endl;
|
|
for (size_t m = 0; m < coord_array.size(); m++)
|
|
{
|
|
for (size_t n = 0; n < coord_array[m].size(); n++)
|
|
{
|
|
std::cout << coord_array[m][n] << ' ';
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
std::cout << "**** End " << description << "********" << std::endl;
|
|
}
|
|
|
|
// ---------- End of Function Definitions ------------------------------------
|