From 4273c4d1ba37e1c2acd85ceb27552f40cc4e4341 Mon Sep 17 00:00:00 2001 From: Josh Pelkey Date: Fri, 18 Sep 2009 10:32:07 -0400 Subject: [PATCH] Merge NixVector Routing code --- AUTHORS | 1 + CHANGES.html | 11 + RELEASE_NOTES | 4 + examples/nix-simple.cc | 114 +++ examples/nms-p2p-nix.cc | 458 ++++++++++ examples/wscript | 8 + src/common/nix-vector.cc | 419 +++++++++ src/common/nix-vector.h | 166 ++++ src/common/packet.cc | 24 +- src/common/packet.h | 14 + src/common/wscript | 2 + src/helper/ipv4-nix-vector-helper.cc | 39 + src/helper/ipv4-nix-vector-helper.h | 55 ++ src/helper/wscript | 4 +- .../ipv4-nix-vector-routing.cc | 840 ++++++++++++++++++ .../ipv4-nix-vector-routing.h | 157 ++++ .../nix-vector-routing/nix-vector-routing.h | 71 ++ src/routing/nix-vector-routing/waf | 1 + src/routing/nix-vector-routing/wscript | 15 + src/wscript | 1 + 20 files changed, 2401 insertions(+), 3 deletions(-) create mode 100644 examples/nix-simple.cc create mode 100644 examples/nms-p2p-nix.cc create mode 100644 src/common/nix-vector.cc create mode 100644 src/common/nix-vector.h create mode 100644 src/helper/ipv4-nix-vector-helper.cc create mode 100644 src/helper/ipv4-nix-vector-helper.h create mode 100644 src/routing/nix-vector-routing/ipv4-nix-vector-routing.cc create mode 100644 src/routing/nix-vector-routing/ipv4-nix-vector-routing.h create mode 100644 src/routing/nix-vector-routing/nix-vector-routing.h create mode 100644 src/routing/nix-vector-routing/waf create mode 100644 src/routing/nix-vector-routing/wscript diff --git a/AUTHORS b/AUTHORS index 3353e7652..93e5c0225 100644 --- a/AUTHORS +++ b/AUTHORS @@ -31,3 +31,4 @@ Mauro Tortonesi (mauro.tortonesi@unife.it) Sebastien Vincent (vincent@clarinet.u-strasbg.fr) Guillaume Vu-Brugier (gvubrugier@gmail.com) Florian Westphal (fw@strlen.de) +Josh Pelkey (jpelkey@gatech.edu) diff --git a/CHANGES.html b/CHANGES.html index d4350ab7d..c8ae3b493 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -113,6 +113,17 @@ router solicitation, DAD

+
  • Nix-vector Routing +

    Add nix-vector routing protocol +

    + +

    +
  • +

    Changes to existing API:

    diff --git a/RELEASE_NOTES b/RELEASE_NOTES index bf1181f79..bf7d4bb52 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -59,6 +59,10 @@ New user-visible features - IEEE 802.11s (Draft 3.0) model including Peering Management Protocol and HWMP. - Forwarding Layer for Meshing (FLAME) protocol. + d) Nix-vector routing: + - Ipv4NixVectorHelper + - Examples (nix-simple, nms-p2p-nix) + API changes from ns-3.5 ----------------------- API changes for this release are documented in the file CHANGES.html. diff --git a/examples/nix-simple.cc b/examples/nix-simple.cc new file mode 100644 index 000000000..e22aca983 --- /dev/null +++ b/examples/nix-simple.cc @@ -0,0 +1,114 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * 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 + */ + +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" + +/* + * Simple point to point links: + * + * n0 -- n1 -- n2 -- n3 + * + * n0 has UdpEchoClient + * n3 has UdpEchoServer + * + * n0 IP: 10.1.1.1 + * n1 IP: 10.1.1.2, 10.1.2.1 + * n2 IP: 10.1.2.2, 10.1.3.1 + * n3 IP: 10.1.3.2 + * + */ + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("FirstScriptExample"); + + int +main (int argc, char *argv[]) +{ + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); + + NodeContainer nodes12; + nodes12.Create (2); + + NodeContainer nodes23; + nodes23.Add (nodes12.Get (1)); + nodes23.Create (1); + + NodeContainer nodes34; + nodes34.Add(nodes23.Get (1)); + nodes34.Create (1); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NodeContainer allNodes = NodeContainer (nodes12, nodes23.Get (1), nodes34.Get (1)); + + // NixHelper to install nix-vector routing + // on all nodes + Ipv4NixVectorHelper nixRouting; + Ipv4StaticRoutingHelper staticRouting; + + Ipv4ListRoutingHelper list; + list.Add (staticRouting, 0); + list.Add (nixRouting, 10); + + InternetStackHelper stack; + stack.SetRoutingHelper (list); + stack.Install (allNodes); + + NetDeviceContainer devices12; + NetDeviceContainer devices23; + NetDeviceContainer devices34; + devices12 = pointToPoint.Install (nodes12); + devices23 = pointToPoint.Install (nodes23); + devices34 = pointToPoint.Install (nodes34); + + Ipv4AddressHelper address1; + address1.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4AddressHelper address2; + address2.SetBase ("10.1.2.0", "255.255.255.0"); + Ipv4AddressHelper address3; + address3.SetBase ("10.1.3.0", "255.255.255.0"); + + address1.Assign (devices12); + address2.Assign (devices23); + Ipv4InterfaceContainer interfaces = address3.Assign (devices34); + + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (nodes34.Get (1)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + + UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = echoClient.Install (nodes12.Get (0)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); + + + Simulator::Run (); + Simulator::Destroy (); + return 0; +} diff --git a/examples/nms-p2p-nix.cc b/examples/nms-p2p-nix.cc new file mode 100644 index 000000000..6bf8fb137 --- /dev/null +++ b/examples/nms-p2p-nix.cc @@ -0,0 +1,458 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// DARPA NMS Campus Network Model +// +// - This topology replicates the original NMS Campus Network model +// with the exception of chord links (which were never utilized in the +// original model) +// - Link Bandwidths and Delays may not be the same as the original +// specifications +// +// (c)2009, GTech Systems, Inc. - Alfred Park + +// for timing functions +#include +#include +#include + +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/global-routing-module.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/simulator.h" + +using namespace std; +using namespace ns3; + +typedef struct timeval TIMER_TYPE; +#define TIMER_NOW(_t) gettimeofday(&_t,NULL); +#define TIMER_SECONDS(_t) ((double)(_t).tv_sec + (_t).tv_usec*1e-6) +#define TIMER_DIFF(_t1, _t2) (TIMER_SECONDS(_t1)-TIMER_SECONDS(_t2)) + +NS_LOG_COMPONENT_DEFINE ("CampusNetworkModel"); + +void Progress () +{ + Time now = Simulator::Now (); + Simulator::Schedule (Seconds (0.1), Progress); +} + +int +main (int argc, char *argv[]) +{ + //Config::SetDefault ("ns3::Simulator::SchedulerType", StringValue ("ns3::CalendarScheduler")); + TIMER_TYPE t0, t1, t2; + TIMER_NOW(t0); + cout << " ==== DARPA NMS CAMPUS NETWORK SIMULATION ====" << endl; + LogComponentEnable ("OnOffApplication", LOG_LEVEL_INFO); + + //RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + int nCN = 2, nLANClients = 42; + bool nix = true; + + CommandLine cmd; + cmd.AddValue ("CN", "Number of total CNs [2]", nCN); + cmd.AddValue ("LAN", "Number of nodes per LAN [42]", nLANClients); + cmd.AddValue ("NIX", "Toggle nix-vector routing", nix); + cmd.Parse (argc,argv); + + if (nCN < 2) + { + cout << "Number of total CNs (" << nCN << ") lower than minimum of 2" + << endl; + return 1; + } + + cout << "Number of CNs: " << nCN << ", LAN nodes: " << nLANClients << endl; + + NodeContainer nodes_net0[nCN][3], nodes_net1[nCN][6], nodes_netLR[nCN], + nodes_net2[nCN][14], nodes_net2LAN[nCN][7][nLANClients], + nodes_net3[nCN][9], nodes_net3LAN[nCN][5][nLANClients]; + PointToPointHelper p2p_2gb200ms, p2p_1gb5ms, p2p_100mb1ms; + InternetStackHelper stack; + Ipv4InterfaceContainer ifs, ifs0[nCN][3], ifs1[nCN][6], ifs2[nCN][14], + ifs3[nCN][9], ifs2LAN[nCN][7][nLANClients], + ifs3LAN[nCN][5][nLANClients]; + Ipv4AddressHelper address; + std::ostringstream oss; + p2p_1gb5ms.SetDeviceAttribute ("DataRate", StringValue ("1Gbps")); + p2p_1gb5ms.SetChannelAttribute ("Delay", StringValue ("5ms")); + p2p_2gb200ms.SetDeviceAttribute ("DataRate", StringValue ("2Gbps")); + p2p_2gb200ms.SetChannelAttribute ("Delay", StringValue ("200ms")); + p2p_100mb1ms.SetDeviceAttribute ("DataRate", StringValue ("100Mbps")); + p2p_100mb1ms.SetChannelAttribute ("Delay", StringValue ("1ms")); + + // Setup NixVector Routing + Ipv4NixVectorHelper nixRouting; + Ipv4StaticRoutingHelper staticRouting; + + Ipv4ListRoutingHelper list; + list.Add (staticRouting, 0); + list.Add (nixRouting, 10); + + if (nix) + { + stack.SetRoutingHelper (list); + } + + // Create Campus Networks + for (int z = 0; z < nCN; ++z) + { + cout << "Creating Campus Network " << z << ":" << endl; + // Create Net0 + cout << " SubNet [ 0"; + for (int i = 0; i < 3; ++i) + { + nodes_net0[z][i].Create (1); + stack.Install (nodes_net0[z][i]); + } + nodes_net0[z][0].Add (nodes_net0[z][1].Get (0)); + nodes_net0[z][1].Add (nodes_net0[z][2].Get (0)); + nodes_net0[z][2].Add (nodes_net0[z][0].Get (0)); + NetDeviceContainer ndc0[3]; + for (int i = 0; i < 3; ++i) + { + ndc0[i] = p2p_1gb5ms.Install (nodes_net0[z][i]); + } + // Create Net1 + cout << " 1"; + for (int i = 0; i < 6; ++i) + { + nodes_net1[z][i].Create (1); + stack.Install (nodes_net1[z][i]); + } + nodes_net1[z][0].Add (nodes_net1[z][1].Get (0)); + nodes_net1[z][2].Add (nodes_net1[z][0].Get (0)); + nodes_net1[z][3].Add (nodes_net1[z][0].Get (0)); + nodes_net1[z][4].Add (nodes_net1[z][1].Get (0)); + nodes_net1[z][5].Add (nodes_net1[z][1].Get (0)); + NetDeviceContainer ndc1[6]; + for (int i = 0; i < 6; ++i) + { + if (i == 1) + { + continue; + } + ndc1[i] = p2p_1gb5ms.Install (nodes_net1[z][i]); + } + // Connect Net0 <-> Net1 + NodeContainer net0_1; + net0_1.Add (nodes_net0[z][2].Get (0)); + net0_1.Add (nodes_net1[z][0].Get (0)); + NetDeviceContainer ndc0_1; + ndc0_1 = p2p_1gb5ms.Install (net0_1); + oss.str(""); + oss << 10 + z << ".1.252.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc0_1); + // Create Net2 + cout << " 2"; + for (int i = 0; i < 14; ++i) + { + nodes_net2[z][i].Create (1); + stack.Install (nodes_net2[z][i]); + } + nodes_net2[z][0].Add (nodes_net2[z][1].Get (0)); + nodes_net2[z][2].Add (nodes_net2[z][0].Get (0)); + nodes_net2[z][1].Add (nodes_net2[z][3].Get (0)); + nodes_net2[z][3].Add (nodes_net2[z][2].Get (0)); + nodes_net2[z][4].Add (nodes_net2[z][2].Get (0)); + nodes_net2[z][5].Add (nodes_net2[z][3].Get (0)); + nodes_net2[z][6].Add (nodes_net2[z][5].Get (0)); + nodes_net2[z][7].Add (nodes_net2[z][2].Get (0)); + nodes_net2[z][8].Add (nodes_net2[z][3].Get (0)); + nodes_net2[z][9].Add (nodes_net2[z][4].Get (0)); + nodes_net2[z][10].Add (nodes_net2[z][5].Get (0)); + nodes_net2[z][11].Add (nodes_net2[z][6].Get (0)); + nodes_net2[z][12].Add (nodes_net2[z][6].Get (0)); + nodes_net2[z][13].Add (nodes_net2[z][6].Get (0)); + NetDeviceContainer ndc2[14]; + for (int i = 0; i < 14; ++i) + { + ndc2[i] = p2p_1gb5ms.Install (nodes_net2[z][i]); + } + NetDeviceContainer ndc2LAN[7][nLANClients]; + for (int i = 0; i < 7; ++i) + { + oss.str (""); + oss << 10 + z << ".4." << 15 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + for (int j = 0; j < nLANClients; ++j) + { + nodes_net2LAN[z][i][j].Create (1); + stack.Install (nodes_net2LAN[z][i][j]); + nodes_net2LAN[z][i][j].Add (nodes_net2[z][i+7].Get (0)); + ndc2LAN[i][j] = p2p_100mb1ms.Install (nodes_net2LAN[z][i][j]); + ifs2LAN[z][i][j] = address.Assign (ndc2LAN[i][j]); + } + } + // Create Net3 + cout << " 3 ]" << endl; + for (int i = 0; i < 9; ++i) + { + nodes_net3[z][i].Create (1); + stack.Install(nodes_net3[z][i]); + } + nodes_net3[z][0].Add (nodes_net3[z][1].Get (0)); + nodes_net3[z][1].Add (nodes_net3[z][2].Get (0)); + nodes_net3[z][2].Add (nodes_net3[z][3].Get (0)); + nodes_net3[z][3].Add (nodes_net3[z][1].Get (0)); + nodes_net3[z][4].Add (nodes_net3[z][0].Get (0)); + nodes_net3[z][5].Add (nodes_net3[z][0].Get (0)); + nodes_net3[z][6].Add (nodes_net3[z][2].Get (0)); + nodes_net3[z][7].Add (nodes_net3[z][3].Get (0)); + nodes_net3[z][8].Add (nodes_net3[z][3].Get (0)); + NetDeviceContainer ndc3[9]; + for (int i = 0; i < 9; ++i) + { + ndc3[i] = p2p_1gb5ms.Install (nodes_net3[z][i]); + } + NetDeviceContainer ndc3LAN[5][nLANClients]; + for (int i = 0; i < 5; ++i) + { + oss.str (""); + oss << 10 + z << ".5." << 10 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.255"); + for (int j = 0; j < nLANClients; ++j) + { + nodes_net3LAN[z][i][j].Create (1); + stack.Install (nodes_net3LAN[z][i][j]); + nodes_net3LAN[z][i][j].Add (nodes_net3[z][i+4].Get (0)); + ndc3LAN[i][j] = p2p_100mb1ms.Install (nodes_net3LAN[z][i][j]); + ifs3LAN[z][i][j] = address.Assign (ndc3LAN[i][j]); + } + } + cout << " Connecting Subnets..." << endl; + // Create Lone Routers (Node 4 & 5) + nodes_netLR[z].Create (2); + stack.Install (nodes_netLR[z]); + NetDeviceContainer ndcLR; + ndcLR = p2p_1gb5ms.Install (nodes_netLR[z]); + // Connect Net2/Net3 through Lone Routers to Net0 + NodeContainer net0_4, net0_5, net2_4a, net2_4b, net3_5a, net3_5b; + net0_4.Add (nodes_netLR[z].Get (0)); + net0_4.Add (nodes_net0[z][0].Get (0)); + net0_5.Add (nodes_netLR[z].Get (1)); + net0_5.Add (nodes_net0[z][1].Get (0)); + net2_4a.Add (nodes_netLR[z].Get (0)); + net2_4a.Add (nodes_net2[z][0].Get (0)); + net2_4b.Add (nodes_netLR[z].Get (1)); + net2_4b.Add (nodes_net2[z][1].Get (0)); + net3_5a.Add (nodes_netLR[z].Get (1)); + net3_5a.Add (nodes_net3[z][0].Get (0)); + net3_5b.Add (nodes_netLR[z].Get (1)); + net3_5b.Add (nodes_net3[z][1].Get (0)); + NetDeviceContainer ndc0_4, ndc0_5, ndc2_4a, ndc2_4b, ndc3_5a, ndc3_5b; + ndc0_4 = p2p_1gb5ms.Install (net0_4); + oss.str (""); + oss << 10 + z << ".1.253.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc0_4); + ndc0_5 = p2p_1gb5ms.Install (net0_5); + oss.str (""); + oss << 10 + z << ".1.254.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc0_5); + ndc2_4a = p2p_1gb5ms.Install (net2_4a); + oss.str (""); + oss << 10 + z << ".4.253.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc2_4a); + ndc2_4b = p2p_1gb5ms.Install (net2_4b); + oss.str (""); + oss << 10 + z << ".4.254.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc2_4b); + ndc3_5a = p2p_1gb5ms.Install (net3_5a); + oss.str (""); + oss << 10 + z << ".5.253.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc3_5a); + ndc3_5b = p2p_1gb5ms.Install (net3_5b); + oss.str (""); + oss << 10 + z << ".5.254.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc3_5b); + // Assign IP addresses + cout << " Assigning IP addresses..." << endl; + for (int i = 0; i < 3; ++i) + { + oss.str (""); + oss << 10 + z << ".1." << 1 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs0[z][i] = address.Assign (ndc0[i]); + } + for (int i = 0; i < 6; ++i) + { + if (i == 1) + { + continue; + } + oss.str (""); + oss << 10 + z << ".2." << 1 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs1[z][i] = address.Assign (ndc1[i]); + } + oss.str (""); + oss << 10 + z << ".3.1.0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndcLR); + for (int i = 0; i < 14; ++i) + { + oss.str (""); + oss << 10 + z << ".4." << 1 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs2[z][i] = address.Assign (ndc2[i]); + } + for (int i = 0; i < 9; ++i) + { + oss.str (""); + oss << 10 + z << ".5." << 1 + i << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs3[z][i] = address.Assign (ndc3[i]); + } + } + // Create Ring Links + if (nCN > 1) + { + cout << "Forming Ring Topology..." << endl; + NodeContainer nodes_ring[nCN]; + for (int z = 0; z < nCN-1; ++z) + { + nodes_ring[z].Add (nodes_net0[z][0].Get (0)); + nodes_ring[z].Add (nodes_net0[z+1][0].Get (0)); + } + nodes_ring[nCN-1].Add (nodes_net0[nCN-1][0].Get (0)); + nodes_ring[nCN-1].Add (nodes_net0[0][0].Get (0)); + NetDeviceContainer ndc_ring[nCN]; + for (int z = 0; z < nCN; ++z) + { + ndc_ring[z] = p2p_2gb200ms.Install (nodes_ring[z]); + oss.str (""); + oss << "254.1." << z + 1 << ".0"; + address.SetBase (oss.str ().c_str (), "255.255.255.0"); + ifs = address.Assign (ndc_ring[z]); + } + } + + // Create Traffic Flows + cout << "Creating TCP Traffic Flows:" << endl; + Config::SetDefault ("ns3::OnOffApplication::MaxBytes", UintegerValue (500000)); + Config::SetDefault ("ns3::OnOffApplication::OnTime", + RandomVariableValue (ConstantVariable (1))); + Config::SetDefault ("ns3::OnOffApplication::OffTime", + RandomVariableValue (ConstantVariable (0))); + Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (512)); + + UniformVariable urng; + int r1; + double r2; + for (int z = 0; z < nCN; ++z) + { + int x = z + 1; + if (z == nCN - 1) + { + x = 0; + } + // Subnet 2 LANs + cout << " Campus Network " << z << " Flows [ Net2 "; + for (int i = 0; i < 7; ++i) + { + for (int j = 0; j < nLANClients; ++j) + { + // Sinks + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), 9999)); + ApplicationContainer sinkApp = sinkHelper.Install ( + nodes_net2LAN[z][i][j].Get (0)); + sinkApp.Start (Seconds (100.0)); + // Sources + r1 = 2 + (int)(4 * urng.GetValue ()); + r2 = 100 + (10 * urng.GetValue ());; + OnOffHelper client ("ns3::TcpSocketFactory", Address ()); + AddressValue remoteAddress(InetSocketAddress ( + ifs2LAN[z][i][j].GetAddress (0), 9999)); + client.SetAttribute ("Remote", remoteAddress); + ApplicationContainer clientApp; + clientApp.Add (client.Install (nodes_net1[x][r1].Get (0))); + clientApp.Start (Seconds (r2)); + } + } + // Subnet 3 LANs + cout << "Net3 ]" << endl; + for (int i = 0; i < 5; ++i) + { + for (int j = 0; j < nLANClients; ++j) + { + // Sinks + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), 9999)); + ApplicationContainer sinkApp = sinkHelper.Install ( + nodes_net3LAN[z][i][j].Get (0)); + sinkApp.Start (Seconds (100.0)); + // Sources + r1 = 2 + (int)(4 * urng.GetValue ()); + r2 = 100 + (10 * urng.GetValue ());; + OnOffHelper client ("ns3::TcpSocketFactory", Address ()); + AddressValue remoteAddress (InetSocketAddress ( + ifs2LAN[z][i][j].GetAddress (0), 9999)); + client.SetAttribute ("Remote", remoteAddress); + ApplicationContainer clientApp; + clientApp.Add (client.Install (nodes_net1[x][r1].Get (0))); + clientApp.Start (Seconds (r2)); + } + } + } + + cout << "Created " << NodeList::GetNNodes () << " nodes." << endl; + TIMER_TYPE routingStart; + TIMER_NOW (routingStart); + + if (nix) + { + // Calculate routing tables + cout << "Using Nix-vectors..." << endl; + } + else + { + // Calculate routing tables + cout << "Populating Global Static Routing Tables..." << endl; + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + } + + TIMER_TYPE routingEnd; + TIMER_NOW (routingEnd); + cout << "Routing tables population took " + << TIMER_DIFF (routingEnd, routingStart) << endl; +#if 0 + std::ofstream ascii; + ascii.open("nms_p2p_nix.tr"); + PointToPointHelper::EnableAsciiAll(ascii); + CsmaHelper::EnableAsciiAll(ascii); +#endif + +#if 0 + PointToPointHelper::EnablePcapAll("nms_p2p"); + CsmaHelper::EnablePcapAll("nms_csma"); +#endif + + Simulator::ScheduleNow (Progress); + cout << "Running simulator..." << endl; + TIMER_NOW (t1); + Simulator::Stop (Seconds (200.0)); + Simulator::Run (); + TIMER_NOW (t2); + cout << "Simulator finished." << endl; + Simulator::Destroy (); + + double d1 = TIMER_DIFF (t1, t0), d2 = TIMER_DIFF (t2, t1); + cout << "-----" << endl << "Runtime Stats:" << endl; + cout << "Simulator init time: " << d1 << endl; + cout << "Simulator run time: " << d2 << endl; + cout << "Total elapsed time: " << d1+d2 << endl; + return 0; +} diff --git a/examples/wscript b/examples/wscript index d88436b50..5bdca27db 100644 --- a/examples/wscript +++ b/examples/wscript @@ -96,6 +96,14 @@ def build(bld): ['point-to-point', 'internet-stack', 'olsr']) obj.source = 'simple-point-to-point-olsr.cc' + obj = bld.create_ns3_program('nix-simple', + ['point-to-point', 'internet-stack', 'nix-vector-routing']) + obj.source = 'nix-simple.cc' + + obj = bld.create_ns3_program('nms-p2p-nix', + ['point-to-point', 'internet-stack', 'nix-vector-routing']) + obj.source = 'nms-p2p-nix.cc' + obj = bld.create_ns3_program('tcp-large-transfer', ['point-to-point', 'internet-stack']) obj.source = 'tcp-large-transfer.cc' diff --git a/src/common/nix-vector.cc b/src/common/nix-vector.cc new file mode 100644 index 000000000..9997901e1 --- /dev/null +++ b/src/common/nix-vector.cc @@ -0,0 +1,419 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2009 The Georgia Institute of Technology + * + * 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 + * + * Authors: Josh Pelkey + */ + +#include "ns3/log.h" + +#include "nix-vector.h" + +NS_LOG_COMPONENT_DEFINE ("NixVector"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (NixVector); + +typedef std::vector NixBits_t; + +NixVector::NixVector () + : m_nixVector (0), + m_used (0), + m_currentVectorBitSize (0), + m_totalBitSize (0) +{ + NS_LOG_FUNCTION_NOARGS (); + + m_nixVector.push_back (0); +} + +NixVector::~NixVector () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +Ptr +NixVector::Copy (void) const +{ + // we need to invoke the copy constructor directly + // rather than calling Create because the copy constructor + // is private. + return Ptr (new NixVector (*this), false); +} + +NixVector::NixVector (const NixVector &o) + : m_nixVector (o.m_nixVector), + m_used (o.m_used), + m_currentVectorBitSize (o.m_currentVectorBitSize), + m_totalBitSize (o.m_totalBitSize) +{} + +NixVector & +NixVector::operator = (const NixVector &o) +{ + if (this == &o) + { + return *this; + } + m_nixVector = o.m_nixVector; + m_used = o.m_used; + m_currentVectorBitSize = o.m_currentVectorBitSize; + m_totalBitSize = o.m_totalBitSize; + return *this; +} + +TypeId +NixVector::GetTypeId(void) +{ + static TypeId tid = TypeId ("ns3::NixVector") + .SetParent () + .AddConstructor () + ; + + return tid; +} + +std::ostream & operator << (std::ostream &os, const NixVector &nix) +{ + nix.DumpNixVector (os); + return os; +} + +void +NixVector::AddNeighborIndex (uint32_t newBits, uint32_t numberOfBits) +{ + NS_LOG_FUNCTION_NOARGS (); + + if (numberOfBits > 32) + { + NS_FATAL_ERROR ("Can't add more than 32 bits to a nix-vector at one time"); + } + + // Check to see if the number + // of new bits forces the creation of + // a new entry into the NixVector vector + // i.e., we will overflow int o.w. + if (m_currentVectorBitSize + numberOfBits > 32) + { + if (m_currentVectorBitSize == 32) + { + // can't add any more to this vector, so + // start a new one + m_nixVector.push_back(newBits); + + // also reset number of bits in + // m_currentVectorBitSize + // because we are working with a new + // entry in the vector + m_currentVectorBitSize = numberOfBits; + m_totalBitSize += numberOfBits; + } + else + { + // Put what we can in the remaining portion of the + // vector entry + uint32_t tempBits = newBits; + tempBits = newBits << m_currentVectorBitSize; + tempBits |= m_nixVector.back (); + m_nixVector.back () = tempBits; + + // Now start a new vector entry + // and push the remaining bits + // there + newBits = newBits >> (32 - m_currentVectorBitSize); + m_nixVector.push_back (newBits); + + // also reset number of bits in + // m_currentVectorBitSize + // because we are working with a new + // entry in the vector + m_currentVectorBitSize = (numberOfBits - (32 - m_currentVectorBitSize)); + m_totalBitSize += numberOfBits; + } + } + else + { + // Shift over the newbits by the + // number of current bits. This allows + // us to logically OR with the present + // NixVector, resulting in the new + // NixVector + newBits = newBits << m_currentVectorBitSize; + newBits |= m_nixVector.back (); + + // Now insert the new NixVector and + // increment number of bits for + // m_currentVectorBitSize and m_totalBitSize + // accordingly + m_nixVector.back () = newBits; + m_currentVectorBitSize += numberOfBits; + m_totalBitSize += numberOfBits; + } +} + +uint32_t +NixVector::ExtractNeighborIndex (uint32_t numberOfBits) +{ + NS_LOG_FUNCTION_NOARGS (); + + if (numberOfBits > 32) + { + NS_FATAL_ERROR ("Can't extract more than 32 bits to a nix-vector at one time"); + } + + uint32_t vectorIndex = 0; + uint32_t extractedBits = 0; + uint32_t totalRemainingBits = GetRemainingBits (); + + if (numberOfBits > totalRemainingBits) + { + NS_FATAL_ERROR ("You've tried to extract too many bits of the Nix-vector, " << this << ". NumberBits: " + << numberOfBits << " Remaining: " << totalRemainingBits); + } + + if (numberOfBits <= 0) + { + NS_FATAL_ERROR ("You've specified a number of bits for Nix-vector <= 0!"); + } + + // First determine where in the NixVector + // vector we need to extract which depends + // on the number of used bits and the total + // number of bits + vectorIndex = ((totalRemainingBits-1) / 32); + + // Next, determine if this extraction will + // span multiple vector entries + if (vectorIndex > 0) // we could span more than one + { + if ((numberOfBits-1) > ((totalRemainingBits-1) % 32)) // we do span more than one + { + extractedBits = m_nixVector.at (vectorIndex) << (32 - (totalRemainingBits % 32)); + extractedBits = extractedBits >> ((32 - (totalRemainingBits % 32)) + - (numberOfBits - (totalRemainingBits % 32))); + extractedBits |= (m_nixVector.at (vectorIndex-1) + >> (32 - (numberOfBits - (totalRemainingBits % 32)))); + m_used += numberOfBits; + return extractedBits; + } + } + + // we don't span more than one + extractedBits = m_nixVector.at (vectorIndex) << (32 - (totalRemainingBits % 32)); + extractedBits = extractedBits >> (32 - (numberOfBits)); + m_used += numberOfBits; + return extractedBits; +} + +uint32_t +NixVector::GetSerializedSize (void) const +{ + uint32_t totalSizeInBytes; + totalSizeInBytes = sizeof (m_used) + sizeof (m_currentVectorBitSize) + + sizeof (m_totalBitSize) + (4 * m_nixVector.size ()); + + // add four to this to account + // for the nix-vector length + // entry + return totalSizeInBytes+4; +} + +void +NixVector::Serialize (Buffer::Iterator i, uint32_t size) const +{ + uint32_t bytesWritten = 0; + + i.WriteU32 (size); + bytesWritten += 4; + + i.WriteU32 (m_used); + bytesWritten += 4; + + i.WriteU32 (m_currentVectorBitSize); + bytesWritten += 4; + + i.WriteU32 (m_totalBitSize); + bytesWritten += 4; + + for (uint32_t j = 0; j < m_nixVector.size (); j++) + { + i.WriteU32 (m_nixVector.at(j)); + bytesWritten += 4; + } + + NS_ASSERT (bytesWritten == size); +} + +uint32_t +NixVector::Deserialize (Buffer::Iterator i) +{ + NS_LOG_FUNCTION (this); + uint32_t totalSize = i.ReadU32 (); + uint32_t size = totalSize; + size -= 4; + + NS_ASSERT (size >= 4); + m_used = i.ReadU32 (); + size -=4; + + NS_ASSERT (size >= 4); + m_currentVectorBitSize = i.ReadU32 (); + size -=4; + + NS_ASSERT (size >= 4); + m_totalBitSize = i.ReadU32 (); + size -=4; + + // make sure the nix-vector + // is empty + m_nixVector.clear (); + while (size > 0) + { + NS_ASSERT (size >= 4); + m_nixVector.push_back (i.ReadU32 ()); + size -=4; + } + + NS_ASSERT (size == 0); + return totalSize; +} + +void +NixVector::DumpNixVector (std::ostream &os) const +{ + NS_LOG_FUNCTION_NOARGS (); + uint32_t i = m_nixVector.size (); + std::vector::const_reverse_iterator rIter; + for (rIter = m_nixVector.rbegin (); rIter != m_nixVector.rend (); rIter++) + { + uint32_t numBits = BitCount (*rIter); + + // all this work just to get the nix + // vector to print out neat + + // if it's not the first entry in the vector, + // we may have to add some zeros and fill + // out the vector + if (m_totalBitSize > ((sizeof (uint32_t)*8) * i)) + { + PrintDec2BinNixFill (*rIter,numBits,os); + } + else if (m_totalBitSize%32 == 0) + { + PrintDec2BinNix (*rIter,32,os); + } + else + { + PrintDec2BinNix (*rIter,m_totalBitSize%32,os); + } + + i--; + + if (i > 0) + { + os << "--"; + } + } +} + +uint32_t +NixVector::GetRemainingBits (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + return (m_totalBitSize - m_used); +} + +uint32_t +NixVector::BitCount (uint32_t numberOfNeighbors) const +{ + NS_LOG_FUNCTION_NOARGS (); + + // Given the numberOfNeighbors, return the number + // of bits needed (essentially, log2(numberOfNeighbors-1) + uint32_t bitCount = 0; + + if (numberOfNeighbors < 2) + { + return 1; + } + else + { + for (numberOfNeighbors -= 1; numberOfNeighbors != 0; numberOfNeighbors >>= 1) + { + bitCount++; + } + return bitCount; + } +} + +void +NixVector::PrintDec2BinNix (uint32_t decimalNum, uint32_t bitCount, std::ostream &os) const +{ + if(decimalNum == 0) + { + for (; bitCount > 0; bitCount--) + { + os << 0; + } + return; + } + if(decimalNum == 1) + { + for (; bitCount > 1; bitCount--) + { + os << 0; + } + os << 1; + } + else + { + PrintDec2BinNix (decimalNum / 2,bitCount-1, os); + os << decimalNum % 2; + } +} + +void +NixVector::PrintDec2BinNixFill (uint32_t decimalNum, uint32_t bitCount, std::ostream &os) const +{ + if(decimalNum == 0) + { + os << 0; + return; + } + if(decimalNum == 1) + { + // check to see if we need to + // print out some zeros at the + // beginning of the nix vector + if ((uint32_t)(sizeof (uint32_t)*8) > bitCount) + { + for (uint32_t i = ((sizeof (uint32_t)*8)-bitCount); i > 0; i--) + { + os << 0; + } + } + os << 1; + } + else + { + PrintDec2BinNixFill (decimalNum / 2, bitCount, os); + os << decimalNum % 2; + } +} + +} // namespace ns3 diff --git a/src/common/nix-vector.h b/src/common/nix-vector.h new file mode 100644 index 000000000..fced817a8 --- /dev/null +++ b/src/common/nix-vector.h @@ -0,0 +1,166 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2009 The Georgia Institute of Technology + * + * 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 + * + * Authors: Josh Pelkey + */ + +#ifndef __NIX_VECTOR_H__ +#define __NIX_VECTOR_H__ + +#include "ns3/object.h" +#include "ns3/buffer.h" + +namespace ns3 { + +/** + * \ingroup packet + * + * \brief Neighbor-index data structure for nix-vector routing + * + * This data structure holds a vector of "neighbor-indexes" for + * a simulation specific routing protocol, nix-vector routing. + * Theses neighbor-indexes correspond to the net-device which a + * node should use to route a packet. A nix-vector is built + * (or fetched from a cache) on-demand. The nix-vector is + * transmitted with the packet, and along each hop of the + * route, the current node extracts the appropriate + * neighbor-index and routes the packet. + * + * \internal + * The implementation of NixVector uses a vector to store + * the neighbor-indexes. Each entry in the vector is 32 + * bits long and can store multiple neighbor-indexes. A + * fair amount of bit manipulation is used to store these + * neighbor-indexes efficiently. A vector is used so that + * the nix-vector can grow arbitraily if the topoplogy and + * route requires a large number of neighbor-indexes. + * + * As the nix-vector travels along the route, an internal + * private member variable keeps track of how many bits + * have been used. At a particular node, the nix-vector + * is used to return the next neighbor-index. This + * neighbor-index is used to determine which net-device + * to use. The number of bits used would then be + * incremented accordingly, and the packet would be + * routed. + */ + +class NixVector : public Object +{ + public: + NixVector (); + NixVector (const NixVector &o); + ~NixVector (); + Ptr Copy (void) const; + NixVector &operator = (const NixVector &o); + static TypeId GetTypeId (void); + /** + * \param newBits the neighbor-index to be added to the vector + * \param numberOfBits the number of bits that newBits contains + * + * Adds the neighbor index to the vector using a fair amount of + * bit manipulation to pack everything in efficiently. + * + * Note: This function assumes that the number of bits to be added + * is always less than or equal to 32, ie., you can only span one + * entry of a nix-vector at a time. This is reasonable, since 32 + * bits gives you 2^32 possible neighbors. + */ + void AddNeighborIndex (uint32_t newBits, uint32_t numberOfBits); + /** + * \return the neighbor index + * + * \param numberOfBits the number of bits to extract from the vector + * + * Extracts the number of bits specified from + * the vector and returns the value extracted + * + * Note: This function assumes that the number of bits to be extracted + * is always less than or equal to 32, ie., you can only span one + * entry of a nix-vector at a time. This is reasonable, since 32 + * bits gives you 2^32 possible neighbors. + */ + uint32_t ExtractNeighborIndex (uint32_t numberOfBits); + /** + * \return number of bits remaining in the + * nix-vector (ie m_total - m_used) + */ + uint32_t GetRemainingBits (void); + /** + * \return the number of bytes required for serialization + */ + uint32_t GetSerializedSize (void) const; + /** + * \param i Buffer iterator for writing + * + * \param size number of bytes to write + */ + void Serialize (Buffer::Iterator i, uint32_t size) const; + /** + * \return the number of bytes deserialized + * + * \param i Buffer iterator for reading + */ + uint32_t Deserialize (Buffer::Iterator i); + /** + * \return number of bits of numberOfNeighbors + * + * \param numberOfNeighbors the total number of neighbors + * + * This function is used to determine the number of bits of + * numberOfNeighbors so that this value can be passed in to + * AddNeighborIndex or ExtractNeighborIndex. + */ + uint32_t BitCount (uint32_t numberOfNeighbors) const; + /* for printing of nix-vector */ + void DumpNixVector (std::ostream &os) const; + /* for printing of nix-vector */ + friend std::ostream & operator <<( std::ostream &outs, const NixVector &nix); + + + private: + typedef std::vector NixBits_t; + + /* the actual nix-vector */ + NixBits_t m_nixVector; + + /* for tracking where we are + * in the nix-vector + */ + uint32_t m_used; + + /* for tracking how many bits we + * have used in the current vector + * entry. need this in order to + * expand the vector passed 32bits + */ + uint32_t m_currentVectorBitSize; + + /* a counter of how total bits are in + * the nix-vector + */ + uint32_t m_totalBitSize; + + /* internal for pretty printing of nix-vector */ + void PrintDec2BinNixFill (uint32_t, uint32_t, std::ostream &os) const; + + /* internal for pretty printing of nix-vector */ + void PrintDec2BinNix (uint32_t, uint32_t, std::ostream &os) const; +}; +} // namespace ns3 + +#endif diff --git a/src/common/packet.cc b/src/common/packet.cc index 13c024675..d90056d5a 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -138,6 +138,7 @@ Packet::Packet () m_byteTagList (), m_packetTagList (), m_metadata (m_globalUid, 0), + m_nixVector (0), m_refCount (1) { m_globalUid++; @@ -149,7 +150,10 @@ Packet::Packet (const Packet &o) m_packetTagList (o.m_packetTagList), m_metadata (o.m_metadata), m_refCount (1) -{} +{ + o.m_nixVector ? m_nixVector = o.m_nixVector->Copy () + : m_nixVector = 0; +} Packet & Packet::operator = (const Packet &o) @@ -162,6 +166,8 @@ Packet::operator = (const Packet &o) m_byteTagList = o.m_byteTagList; m_packetTagList = o.m_packetTagList; m_metadata = o.m_metadata; + o.m_nixVector ? m_nixVector = o.m_nixVector->Copy () + : m_nixVector = 0; return *this; } @@ -170,6 +176,7 @@ Packet::Packet (uint32_t size) m_byteTagList (), m_packetTagList (), m_metadata (m_globalUid, size), + m_nixVector (0), m_refCount (1) { m_globalUid++; @@ -179,6 +186,7 @@ Packet::Packet (uint8_t const*buffer, uint32_t size) m_byteTagList (), m_packetTagList (), m_metadata (m_globalUid, size), + m_nixVector (0), m_refCount (1) { m_globalUid++; @@ -193,6 +201,7 @@ Packet::Packet (const Buffer &buffer, const ByteTagList &byteTagList, m_byteTagList (byteTagList), m_packetTagList (packetTagList), m_metadata (metadata), + m_nixVector (0), m_refCount (1) {} @@ -209,6 +218,18 @@ Packet::CreateFragment (uint32_t start, uint32_t length) const return Ptr (new Packet (buffer, m_byteTagList, m_packetTagList, metadata), false); } +void +Packet::SetNixVector (Ptr nixVector) +{ + m_nixVector = nixVector; +} + +Ptr +Packet::GetNixVector (void) const +{ + return m_nixVector; +} + uint32_t Packet::GetSize (void) const { @@ -677,7 +698,6 @@ Packet::GetPacketTagIterator (void) const return PacketTagIterator (m_packetTagList.Head ()); } - std::ostream& operator<< (std::ostream& os, const Packet &packet) { packet.Print (os); diff --git a/src/common/packet.h b/src/common/packet.h index a272eb2f6..549a77ce0 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -28,6 +28,7 @@ #include "tag.h" #include "byte-tag-list.h" #include "packet-tag-list.h" +#include "nix-vector.h" #include "ns3/callback.h" #include "ns3/assert.h" #include "ns3/ptr.h" @@ -520,6 +521,15 @@ public: */ PacketTagIterator GetPacketTagIterator (void) const; + /* Note: These function support a temporary solution + * to a specific problem in this generic class, i.e. + * how to associate something specific like nix-vector + * with a packet. This design methodology + * should _not_ be followed, and is only here as an + * impetus to fix this general issue. */ + void SetNixVector (Ptr); + Ptr GetNixVector (void) const; + private: Packet (const Buffer &buffer, const ByteTagList &byteTagList, const PacketTagList &packetTagList, const PacketMetadata &metadata); @@ -527,6 +537,10 @@ private: ByteTagList m_byteTagList; PacketTagList m_packetTagList; PacketMetadata m_metadata; + + /* Please see comments above about nix-vector */ + Ptr m_nixVector; + mutable uint32_t m_refCount; static uint32_t m_globalUid; }; diff --git a/src/common/wscript b/src/common/wscript index 077d139d4..0e3b20c46 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -17,6 +17,7 @@ def build(bld): 'byte-tag-list.cc', 'tag-buffer.cc', 'packet-tag-list.cc', + 'nix-vector.cc', 'ascii-writer.cc', 'pcap-file.cc', 'pcap-file-test-suite.cc', @@ -38,6 +39,7 @@ def build(bld): 'byte-tag-list.h', 'tag-buffer.h', 'packet-tag-list.h', + 'nix-vector.h', 'ascii-writer.h', 'sgi-hashmap.h', 'pcap-file.h', diff --git a/src/helper/ipv4-nix-vector-helper.cc b/src/helper/ipv4-nix-vector-helper.cc new file mode 100644 index 000000000..3ac2d1eda --- /dev/null +++ b/src/helper/ipv4-nix-vector-helper.cc @@ -0,0 +1,39 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2009 The Georgia Institute of Technology + * + * 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 + * + * Authors: Josh Pelkey + */ + +#include "ipv4-nix-vector-helper.h" +#include "ns3/ipv4-nix-vector-routing.h" + +namespace ns3 { + +Ipv4NixVectorHelper::Ipv4NixVectorHelper () +{ + m_agentFactory.SetTypeId ("ns3::Ipv4NixVectorRouting"); +} + +Ptr +Ipv4NixVectorHelper::Create (Ptr node) const +{ + Ptr agent = m_agentFactory.Create (); + agent->SetNode(node); + node->AggregateObject (agent); + return agent; +} +} // namespace ns3 diff --git a/src/helper/ipv4-nix-vector-helper.h b/src/helper/ipv4-nix-vector-helper.h new file mode 100644 index 000000000..38452b2c6 --- /dev/null +++ b/src/helper/ipv4-nix-vector-helper.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2009 The Georgia Institute of Technology + * + * 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 + * + * Authors: Josh Pelkey + */ + +#ifndef IPV4_NIX_VECTOR_HELPER_H +#define IPV4_NIX_VECTOR_HELPER_H + +#include "ns3/object-factory.h" +#include "ns3/ipv4-routing-helper.h" + +namespace ns3 { + +/** + * \brief Helper class that adds Nix-vector routing to nodes. + * + * This class is expected to be used in conjunction with + * ns3::InternetStackHelper::SetRoutingHelper + * + */ + +class Ipv4NixVectorHelper : public Ipv4RoutingHelper +{ +public: + Ipv4NixVectorHelper (); + + /** + * \param node the node on which the routing protocol will run + * \returns a newly-created routing protocol + * + * This method will be called by ns3::InternetStackHelper::Install + */ + virtual Ptr Create (Ptr) const; + +private: + ObjectFactory m_agentFactory; +}; +} // namespace ns3 + +#endif /* IPV4_NIX_VECTOR_HELPER_H */ diff --git a/src/helper/wscript b/src/helper/wscript index 115f83d7a..1d6ddd850 100644 --- a/src/helper/wscript +++ b/src/helper/wscript @@ -1,7 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def build(bld): - helper = bld.create_ns3_module('helper', ['internet-stack', 'wifi', 'point-to-point', 'csma', 'olsr', 'global-routing', 'onoff', 'packet-sink', 'udp-echo']) + helper = bld.create_ns3_module('helper', ['internet-stack', 'wifi', 'point-to-point', 'csma', 'olsr', 'nix-vector-routing', 'global-routing', 'onoff', 'packet-sink', 'udp-echo']) helper.source = [ 'node-container.cc', 'net-device-container.cc', @@ -25,6 +25,7 @@ def build(bld): 'v4ping-helper.cc', 'nqos-wifi-mac-helper.cc', 'qos-wifi-mac-helper.cc', + 'ipv4-nix-vector-helper.cc', 'ipv4-global-routing-helper.cc', 'ipv4-list-routing-helper.cc', 'ipv4-routing-helper.cc', @@ -66,6 +67,7 @@ def build(bld): 'v4ping-helper.h', 'nqos-wifi-mac-helper.h', 'qos-wifi-mac-helper.h', + 'ipv4-nix-vector-helper.h', 'ipv4-global-routing-helper.h', 'ipv4-list-routing-helper.h', 'ipv4-routing-helper.h', diff --git a/src/routing/nix-vector-routing/ipv4-nix-vector-routing.cc b/src/routing/nix-vector-routing/ipv4-nix-vector-routing.cc new file mode 100644 index 000000000..c6e65de7c --- /dev/null +++ b/src/routing/nix-vector-routing/ipv4-nix-vector-routing.cc @@ -0,0 +1,840 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2009 The Georgia Institute of Technology + * + * 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 + * + * Authors: Josh Pelkey + */ + +#include + +#include "ns3/log.h" +#include "ns3/abort.h" +#include "ns3/ipv4-list-routing.h" + +#include "ipv4-nix-vector-routing.h" + +NS_LOG_COMPONENT_DEFINE ("Ipv4NixVectorRouting"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (Ipv4NixVectorRouting); + +TypeId +Ipv4NixVectorRouting::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::Ipv4NixVectorRouting") + .SetParent () + .AddConstructor () + ; + return tid; +} + +Ipv4NixVectorRouting::Ipv4NixVectorRouting () +:m_totalNeighbors (0) +{ + NS_LOG_FUNCTION_NOARGS (); +} + +Ipv4NixVectorRouting::~Ipv4NixVectorRouting () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +void +Ipv4NixVectorRouting::SetIpv4 (Ptr ipv4) +{ + NS_ASSERT (ipv4 != 0); + NS_ASSERT (m_ipv4 == 0); + NS_LOG_DEBUG ("Created Ipv4NixVectorProtocol"); + + m_ipv4 = ipv4; +} + +void +Ipv4NixVectorRouting::DoDispose () +{ + NS_LOG_FUNCTION_NOARGS (); + + m_node = 0; + m_ipv4 = 0; + + Ipv4RoutingProtocol::DoDispose (); +} + + +void +Ipv4NixVectorRouting::SetNode (Ptr node) +{ + NS_LOG_FUNCTION_NOARGS (); + + m_node = node; +} + +void +Ipv4NixVectorRouting::FlushGlobalNixRoutingCache () +{ + NS_LOG_FUNCTION_NOARGS (); + NodeList::Iterator listEnd = NodeList::End (); + for (NodeList::Iterator i = NodeList::Begin (); i != listEnd; i++) + { + Ptr node = *i; + Ptr rp = node->GetObject (); + if (!rp) + { + continue; + } + NS_LOG_LOGIC ("Flushing Nix caches."); + rp->FlushNixCache (); + rp->FlushIpv4RouteCache (); + } +} + +void +Ipv4NixVectorRouting::FlushNixCache () +{ + NS_LOG_FUNCTION_NOARGS (); + m_nixCache.clear (); +} + +void +Ipv4NixVectorRouting::FlushIpv4RouteCache () +{ + NS_LOG_FUNCTION_NOARGS (); + m_ipv4RouteCache.clear (); +} + +Ptr +Ipv4NixVectorRouting::GetNixVector (Ptr source, Ipv4Address dest) +{ + NS_LOG_FUNCTION_NOARGS (); + + Ptr nixVector = CreateObject (); + + // not in cache, must build the nix vector + // First, we have to figure out the nodes + // associated with these IPs + Ptr destNode = GetNodeByIp (dest); + if (destNode == 0) + { + NS_LOG_ERROR ("No routing path exists"); + return 0; + } + + // if source == dest, then we have a special case + // because the node is sending to itself. have to + // build the nix vector a little differently + if (source == destNode) + { + BuildNixVectorLocal(nixVector); + return nixVector; + } + else + { + // otherwise proceed as normal + // and build the nix vector + std::vector< Ptr > parentVector; + BFS (NodeList::GetNNodes (), source, destNode, parentVector); + + if (BuildNixVector (parentVector, source->GetId (), destNode->GetId (), nixVector)) + { + return nixVector; + } + else + { + NS_LOG_ERROR ("No routing path exists"); + return 0; + } + } +} + +Ptr +Ipv4NixVectorRouting::GetNixVectorInCache (Ipv4Address address) +{ + NS_LOG_FUNCTION_NOARGS (); + + NixMap_t::iterator iter = m_nixCache.find (address); + if (iter != m_nixCache.end ()) + { + NS_LOG_LOGIC ("Found Nix-vector in cache."); + return iter->second; + } + + // not in cache + return 0; +} + +Ptr +Ipv4NixVectorRouting::GetIpv4RouteInCache (Ipv4Address address) +{ + NS_LOG_FUNCTION_NOARGS (); + + Ipv4RouteMap_t::iterator iter = m_ipv4RouteCache.find (address); + if (iter != m_ipv4RouteCache.end ()) + { + NS_LOG_LOGIC ("Found Ipv4Route in cache."); + return iter->second; + } + + // not in cache + return 0; +} + +bool +Ipv4NixVectorRouting::BuildNixVectorLocal (Ptr nixVector) +{ + NS_LOG_FUNCTION_NOARGS (); + + uint32_t numberOfDevices = m_node->GetNDevices (); + + // here we are building a nix vector to + // ourself, so we need to find the loopback + // interface and add that to the nix vector + Ipv4Address loopback ("127.0.0.1"); + for (uint32_t i = 0; i < numberOfDevices; i++) + { + uint32_t interfaceIndex = (m_ipv4)->GetInterfaceForDevice(m_node->GetDevice(i)); + Ipv4InterfaceAddress ifAddr = m_ipv4->GetAddress (interfaceIndex, 0); + if (ifAddr.GetLocal() == loopback) + { + NS_LOG_LOGIC ("Adding loopback to nix."); + NS_LOG_LOGIC ("Adding Nix: " << i << " with " << nixVector->BitCount (numberOfDevices) + << " bits, for node " << m_node->GetId()); + nixVector->AddNeighborIndex (i, nixVector->BitCount (numberOfDevices)); + return true; + } + } + return false; +} + +bool +Ipv4NixVectorRouting::BuildNixVector (const std::vector< Ptr > & parentVector, uint32_t source, uint32_t dest, Ptr nixVector) +{ + NS_LOG_FUNCTION_NOARGS (); + + if (source == dest) + { + return true; + } + + if (parentVector.at (dest) == 0) + { + return false; + } + + Ptr parentNode = parentVector.at (dest); + + uint32_t numberOfDevices = parentNode->GetNDevices (); + uint32_t destId = 0; + uint32_t totalNeighbors = 0; + + // scan through the net devices on the parent node + // and then look at the nodes adjacent to them + for (uint32_t i = 0; i < numberOfDevices; i++) + { + // Get a net device from the node + // as well as the channel, and figure + // out the adjacent net devices + Ptr localNetDevice = parentNode->GetDevice (i); + if (localNetDevice->IsBridge ()) + { + continue; + } + Ptr channel = localNetDevice->GetChannel (); + if (channel == 0) + { + continue; + } + + // this function takes in the local net dev, and channnel, and + // writes to the netDeviceContainer the adjacent net devs + NetDeviceContainer netDeviceContainer; + GetAdjacentNetDevices (localNetDevice, channel, netDeviceContainer); + + // Finally we can get the adjacent nodes + // and scan through them. If we find the + // node that matches "dest" then we can add + // the index to the nix vector. + // the index corresponds to the neighbor index + uint32_t offset = 0; + for (NetDeviceContainer::Iterator iter = netDeviceContainer.Begin (); iter != netDeviceContainer.End (); iter++) + { + Ptr remoteNode = (*iter)->GetNode (); + + if (remoteNode->GetId () == dest) + { + destId = totalNeighbors + offset; + } + offset += 1; + } + + totalNeighbors += netDeviceContainer.GetN (); + } + NS_LOG_LOGIC ("Adding Nix: " << destId << " with " + << nixVector->BitCount (totalNeighbors) << " bits, for node " << parentNode->GetId()); + nixVector->AddNeighborIndex (destId, nixVector->BitCount (totalNeighbors)); + + // recurse through parent vector, grabbing the path + // and building the nix vector + BuildNixVector (parentVector, source, (parentVector.at (dest))->GetId (), nixVector); + return true; +} + +void +Ipv4NixVectorRouting::GetAdjacentNetDevices (Ptr netDevice, Ptr channel, NetDeviceContainer & netDeviceContainer) +{ + NS_LOG_FUNCTION_NOARGS (); + + for (uint32_t i = 0; i < channel->GetNDevices (); i++) + { + Ptr remoteDevice = channel->GetDevice (i); + if (remoteDevice != netDevice) + { + Ptr bd = NetDeviceIsBridged (remoteDevice); + // we have a bridged device, we need to add all + // bridged devices + if (bd) + { + NS_LOG_LOGIC ("Looking through bridge ports of bridge net device " << bd); + for (uint32_t j = 0; j < bd->GetNBridgePorts (); ++j) + { + Ptr ndBridged = bd->GetBridgePort (j); + if (ndBridged == remoteDevice) + { + NS_LOG_LOGIC ("That bridge port is me, don't walk backward"); + continue; + } + Ptr chBridged = ndBridged->GetChannel (); + if (channel == 0) + { + continue; + } + GetAdjacentNetDevices (ndBridged, chBridged, netDeviceContainer); + } + } + else + { + netDeviceContainer.Add (channel->GetDevice (i)); + } + } + } +} + +Ptr +Ipv4NixVectorRouting::GetNodeByIp (Ipv4Address dest) +{ + NS_LOG_FUNCTION_NOARGS (); + + NodeContainer allNodes = NodeContainer::GetGlobal (); + Ptr destNode; + + for (NodeContainer::Iterator i = allNodes.Begin (); i != allNodes.End (); ++i) + { + Ptr node = *i; + Ptr ipv4 = node->GetObject (); + if (ipv4->GetInterfaceForAddress (dest) != -1) + { + destNode = node; + break; + } + } + + if (!destNode) + { + NS_LOG_ERROR ("Couldn't find dest node given the IP" << dest); + return 0; + } + + return destNode; +} + +uint32_t +Ipv4NixVectorRouting::FindTotalNeighbors () +{ + uint32_t numberOfDevices = m_node->GetNDevices (); + uint32_t totalNeighbors = 0; + + // scan through the net devices on the parent node + // and then look at the nodes adjacent to them + for (uint32_t i = 0; i < numberOfDevices; i++) + { + // Get a net device from the node + // as well as the channel, and figure + // out the adjacent net devices + Ptr localNetDevice = m_node->GetDevice (i); + Ptr channel = localNetDevice->GetChannel (); + if (channel == 0) + { + continue; + } + + // this function takes in the local net dev, and channnel, and + // writes to the netDeviceContainer the adjacent net devs + NetDeviceContainer netDeviceContainer; + GetAdjacentNetDevices (localNetDevice, channel, netDeviceContainer); + + totalNeighbors += netDeviceContainer.GetN (); + } + + return totalNeighbors; +} + +Ptr +Ipv4NixVectorRouting::NetDeviceIsBridged (Ptr nd) const +{ + NS_LOG_FUNCTION (nd); + + Ptr node = nd->GetNode (); + uint32_t nDevices = node->GetNDevices(); + + // + // There is no bit on a net device that says it is being bridged, so we have + // to look for bridges on the node to which the device is attached. If we + // find a bridge, we need to look through its bridge ports (the devices it + // bridges) to see if we find the device in question. + // + for (uint32_t i = 0; i < nDevices; ++i) + { + Ptr ndTest = node->GetDevice(i); + NS_LOG_LOGIC ("Examine device " << i << " " << ndTest); + + if (ndTest->IsBridge ()) + { + NS_LOG_LOGIC ("device " << i << " is a bridge net device"); + Ptr bnd = ndTest->GetObject (); + NS_ABORT_MSG_UNLESS (bnd, "Ipv4NixVectorRouting::NetDeviceIsBridged (): GetObject for failed"); + + for (uint32_t j = 0; j < bnd->GetNBridgePorts (); ++j) + { + NS_LOG_LOGIC ("Examine bridge port " << j << " " << bnd->GetBridgePort (j)); + if (bnd->GetBridgePort (j) == nd) + { + NS_LOG_LOGIC ("Net device " << nd << " is bridged by " << bnd); + return bnd; + } + } + } + } + NS_LOG_LOGIC ("Net device " << nd << " is not bridged"); + return 0; +} + +uint32_t +Ipv4NixVectorRouting::FindNetDeviceForNixIndex (uint32_t nodeIndex, Ipv4Address & gatewayIp) +{ + uint32_t numberOfDevices = m_node->GetNDevices (); + uint32_t index = 0; + uint32_t totalNeighbors = 0; + + // scan through the net devices on the parent node + // and then look at the nodes adjacent to them + for (uint32_t i = 0; i < numberOfDevices; i++) + { + // Get a net device from the node + // as well as the channel, and figure + // out the adjacent net devices + Ptr localNetDevice = m_node->GetDevice (i); + Ptr channel = localNetDevice->GetChannel (); + if (channel == 0) + { + continue; + } + + // this function takes in the local net dev, and channnel, and + // writes to the netDeviceContainer the adjacent net devs + NetDeviceContainer netDeviceContainer; + GetAdjacentNetDevices (localNetDevice, channel, netDeviceContainer); + + // check how many neighbors we have + if (nodeIndex < (totalNeighbors + netDeviceContainer.GetN ())) + { + // found the proper net device + index = i; + Ptr gatewayDevice = netDeviceContainer.Get (nodeIndex-totalNeighbors); + Ptr gatewayNode = gatewayDevice->GetNode (); + Ptr ipv4 = gatewayNode->GetObject (); + + uint32_t interfaceIndex = (ipv4)->GetInterfaceForDevice(gatewayDevice); + Ipv4InterfaceAddress ifAddr = ipv4->GetAddress (interfaceIndex, 0); + gatewayIp = ifAddr.GetLocal (); + break; + } + totalNeighbors += netDeviceContainer.GetN (); + } + + return index; +} + +Ptr +Ipv4NixVectorRouting::RouteOutput (Ptr p, const Ipv4Header &header, uint32_t oif, Socket::SocketErrno &sockerr) +{ + NS_LOG_FUNCTION_NOARGS (); + Ptr rtentry; + Ptr nixVectorInCache; + Ptr nixVectorForPacket; + + NS_LOG_DEBUG ("Dest IP from header: " << header.GetDestination ()); + // check if cache + nixVectorInCache = GetNixVectorInCache(header.GetDestination ()); + + // not in cache + if (!nixVectorInCache) + { + NS_LOG_LOGIC ("Nix-vector not in cache, build: "); + // Build the nix-vector, given this node and the + // dest IP address + nixVectorInCache = GetNixVector (m_node, header.GetDestination ()); + + // cache it + m_nixCache.insert (NixMap_t::value_type (header.GetDestination (), nixVectorInCache)); + } + + // path exists + if (nixVectorInCache) + { + NS_LOG_LOGIC ("Nix-vector contents: " << *nixVectorInCache); + + // create a new nix vector to be used, + // we want to keep the cached version clean + nixVectorForPacket = CreateObject (); + nixVectorForPacket = nixVectorInCache->Copy(); + + // Get the interface number that we go out of, by extracting + // from the nix-vector + if (m_totalNeighbors == 0) + { + m_totalNeighbors = FindTotalNeighbors (); + } + + // Get the interface number that we go out of, by extracting + // from the nix-vector + uint32_t numberOfBits = nixVectorForPacket->BitCount (m_totalNeighbors); + uint32_t nodeIndex = nixVectorForPacket->ExtractNeighborIndex (numberOfBits); + + // Possibly search here in a cache for this node index + // and look for a Ipv4Route. If we have it, don't + // need to do the next 3 lines. + rtentry = GetIpv4RouteInCache (header.GetDestination ()); + // not in cache + if (!rtentry) + { + NS_LOG_LOGIC ("Ipv4Route not in cache, build: "); + Ipv4Address gatewayIp; + uint32_t index = FindNetDeviceForNixIndex (nodeIndex, gatewayIp); + + uint32_t interfaceIndex = (m_ipv4)->GetInterfaceForDevice(m_node->GetDevice(index)); + Ipv4InterfaceAddress ifAddr = m_ipv4->GetAddress (interfaceIndex, 0); + + // start filling in the Ipv4Route info + rtentry = Create (); + rtentry->SetSource (ifAddr.GetLocal ()); + + rtentry->SetGateway (gatewayIp); + rtentry->SetDestination (header.GetDestination ()); + rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIndex)); + + sockerr = Socket::ERROR_NOTERROR; + + // add rtentry to cache + m_ipv4RouteCache.insert(Ipv4RouteMap_t::value_type(header.GetDestination (), rtentry)); + } + + NS_LOG_LOGIC ("Nix-vector contents: " << *nixVectorInCache << " : Remaining bits: " << nixVectorForPacket->GetRemainingBits()); + + // Add nix-vector in the packet class + // make sure the packet exists first + if (p) + { + NS_LOG_LOGIC ("Adding Nix-vector to packet: " << *nixVectorForPacket); + p->SetNixVector (nixVectorForPacket); + } + } + else // path doesn't exist + { + NS_LOG_ERROR ("No path to the dest: " << header.GetDestination ()); + sockerr = Socket::ERROR_NOROUTETOHOST; + } + + return rtentry; +} + +bool +Ipv4NixVectorRouting::RouteInput (Ptr p, const Ipv4Header &header, Ptr idev, + UnicastForwardCallback ucb, MulticastForwardCallback mcb, + LocalDeliverCallback lcb, ErrorCallback ecb) +{ + NS_LOG_FUNCTION_NOARGS (); + + Ptr rtentry; + + // Get the nix-vector from the packet + Ptr nixVector = p->GetNixVector(); + + // make sure it exists, if not something + // went wrong + if (!nixVector) + { + NS_LOG_ERROR ("Nix-vector wasn't in the packet! Rebuild."); + + Ptr nixVectorInCache; + + NS_LOG_DEBUG ("Dest IP from header: " << header.GetDestination ()); + + // check if cache + nixVectorInCache = GetNixVectorInCache(header.GetDestination ()); + + // not in cache + if (!nixVectorInCache) + { + NS_LOG_LOGIC ("RouteInput(): Nix-vector not in cache, build: "); + + // Build the nix-vector, given this node and the + // dest IP address + nixVectorInCache = GetNixVector (m_node, header.GetDestination ()); + } + + // path exists + if (nixVectorInCache) + { + NS_LOG_LOGIC ("Nix-vector contents: " << *nixVectorInCache); + + // cache it + m_nixCache.insert(NixMap_t::value_type(header.GetDestination (), nixVectorInCache)); + + // create a new nix vector to be used, + // we want to keep the cached version clean + Ptr nixVectorForPacket; + nixVectorForPacket = CreateObject (); + nixVectorForPacket = nixVectorInCache->Copy(); + + // Get the interface number that we go out of, by extracting + // from the nix-vector + if (m_totalNeighbors == 0) + { + m_totalNeighbors = FindTotalNeighbors (); + } + uint32_t numberOfBits = nixVectorForPacket->BitCount (m_totalNeighbors); + uint32_t nodeIndex = nixVectorForPacket->ExtractNeighborIndex (numberOfBits); + + rtentry = GetIpv4RouteInCache (header.GetDestination ()); + // not in cache + if (!rtentry) + { + NS_LOG_LOGIC ("Ipv4Route not in cache, build: "); + Ipv4Address gatewayIp; + uint32_t index = FindNetDeviceForNixIndex (nodeIndex, gatewayIp); + + uint32_t interfaceIndex = (m_ipv4)->GetInterfaceForDevice(m_node->GetDevice(index)); + Ipv4InterfaceAddress ifAddr = m_ipv4->GetAddress (interfaceIndex, 0); + + // start filling in the Ipv4Route info + rtentry = Create (); + rtentry->SetSource (ifAddr.GetLocal ()); + + rtentry->SetGateway (Ipv4Address(gatewayIp)); + rtentry->SetDestination (header.GetDestination ()); + rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIndex)); + + // add rtentry to cache + m_ipv4RouteCache.insert(Ipv4RouteMap_t::value_type(header.GetDestination (), rtentry)); + } + + NS_LOG_LOGIC ("Nix-vector contents: " << *nixVectorInCache << " : Remaining bits: " << nixVectorForPacket->GetRemainingBits()); + + // Add nix-vector in the packet class + // have to copy the packet first b/c + // it is const + Ptr newPacket = Create (); + newPacket = p->Copy(); + + NS_LOG_LOGIC ("Adding Nix-vector to packet: " << *nixVectorForPacket); + newPacket->SetNixVector(nixVectorForPacket); + + // call the unicast callback + // local deliver is handled by Ipv4StaticRoutingImpl + // so this code is never even called if the packet is + // destined for this node. + ucb (rtentry, newPacket, header); + return true; + } + else // path doesn't exist + { + NS_LOG_ERROR ("No path to the dest: " << header.GetDestination ()); + return false; + } + } + else + { + // Get the interface number that we go out of, by extracting + // from the nix-vector + if (m_totalNeighbors == 0) + { + m_totalNeighbors = FindTotalNeighbors (); + } + uint32_t numberOfBits = nixVector->BitCount (m_totalNeighbors); + uint32_t nodeIndex = nixVector->ExtractNeighborIndex (numberOfBits); + + rtentry = GetIpv4RouteInCache (header.GetDestination ()); + // not in cache + if (!rtentry) + { + NS_LOG_LOGIC ("Ipv4Route not in cache, build: "); + Ipv4Address gatewayIp; + uint32_t index = FindNetDeviceForNixIndex (nodeIndex, gatewayIp); + uint32_t interfaceIndex = (m_ipv4)->GetInterfaceForDevice(m_node->GetDevice(index)); + Ipv4InterfaceAddress ifAddr = m_ipv4->GetAddress (interfaceIndex, 0); + + // start filling in the Ipv4Route info + rtentry = Create (); + rtentry->SetSource (ifAddr.GetLocal ()); + + rtentry->SetGateway (gatewayIp); + rtentry->SetDestination (header.GetDestination ()); + rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIndex)); + + // add rtentry to cache + m_ipv4RouteCache.insert(Ipv4RouteMap_t::value_type(header.GetDestination (), rtentry)); + } + + NS_LOG_LOGIC ("At Node " << m_node->GetId() << ", Extracting " << numberOfBits << + " bits from Nix-vector: " << nixVector << " : " << *nixVector); + + // call the unicast callback + // local deliver is handled by Ipv4StaticRoutingImpl + // so this code is never even called if the packet is + // destined for this node. + ucb (rtentry, p, header); + + return true; + } +} + +// virtual functions from Ipv4RoutingProtocol +void +Ipv4NixVectorRouting::NotifyInterfaceUp (uint32_t i) +{ + FlushGlobalNixRoutingCache (); +} +void +Ipv4NixVectorRouting::NotifyInterfaceDown (uint32_t i) +{ + FlushGlobalNixRoutingCache (); +} +void +Ipv4NixVectorRouting::NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address) +{ + FlushGlobalNixRoutingCache (); +} +void +Ipv4NixVectorRouting::NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address) +{ + FlushGlobalNixRoutingCache (); +} + +bool +Ipv4NixVectorRouting::BFS (uint32_t numberOfNodes, Ptr source, Ptr dest, std::vector< Ptr > & parentVector) +{ + NS_LOG_FUNCTION_NOARGS (); + + NS_LOG_LOGIC ("Going from Node " << source->GetId() << " to Node " << dest->GetId()); + std::queue< Ptr > greyNodeList; // discovered nodes with unexplored children + + // reset the parent vector + parentVector.clear (); + parentVector.reserve (sizeof (Ptr)*numberOfNodes); + parentVector.insert (parentVector.begin (), sizeof (Ptr)*numberOfNodes, 0); // initialize to 0 + + // Add the source node to the queue, set its parent to itself + greyNodeList.push (source); + parentVector.at (source->GetId()) = source; + + // BFS loop + while (greyNodeList.size () != 0) + { + Ptr currNode = greyNodeList.front (); + Ptr ipv4 = currNode->GetObject (); + + if (currNode == dest) + { + NS_LOG_LOGIC ("Made it to Node " << currNode->GetId()); + return true; + } + + + // Iterate over the current node's adjacent vertices + // and push them into the queue + for (uint32_t i = 0; i < (currNode->GetNDevices ()); i++) + { + // Get a net device from the node + // as well as the channel, and figure + // out the adjacent net device + Ptr localNetDevice = currNode->GetDevice (i); + + // make sure that we can go this way + if (ipv4) + { + uint32_t interfaceIndex = (ipv4)->GetInterfaceForDevice(currNode->GetDevice(i)); + if (!(ipv4->IsUp (interfaceIndex))) + { + NS_LOG_LOGIC ("Ipv4Interface is down"); + continue; + } + } + if (!(localNetDevice->IsLinkUp ())) + { + NS_LOG_LOGIC ("Link is down."); + continue; + } + Ptr channel = localNetDevice->GetChannel (); + if (channel == 0) + { + continue; + } + + // this function takes in the local net dev, and channnel, and + // writes to the netDeviceContainer the adjacent net devs + NetDeviceContainer netDeviceContainer; + GetAdjacentNetDevices (localNetDevice, channel, netDeviceContainer); + + // Finally we can get the adjacent nodes + // and scan through them. We push them + // to the greyNode queue, if they aren't + // already there. + for (NetDeviceContainer::Iterator iter = netDeviceContainer.Begin (); iter != netDeviceContainer.End (); iter++) + { + Ptr remoteNode = (*iter)->GetNode (); + + // check to see if this node has been pushed before + // by checking to see if it has a parent + // if it doesn't (null or 0), then set its parent and + // push to the queue + if (parentVector.at (remoteNode->GetId ()) == 0) + { + parentVector.at (remoteNode->GetId ()) = currNode; + greyNodeList.push (remoteNode); + } + } + } + + // Pop off the head grey node. We have all its children. + // It is now black. + greyNodeList.pop (); + } + + // Didn't find the dest... + return false; +} + +} // namespace ns3 diff --git a/src/routing/nix-vector-routing/ipv4-nix-vector-routing.h b/src/routing/nix-vector-routing/ipv4-nix-vector-routing.h new file mode 100644 index 000000000..d4792bccf --- /dev/null +++ b/src/routing/nix-vector-routing/ipv4-nix-vector-routing.h @@ -0,0 +1,157 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2009 The Georgia Institute of Technology + * + * 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 + * + * Authors: Josh Pelkey + */ + +#ifndef __IPV4_NIX_VECTOR_ROUTING_H__ +#define __IPV4_NIX_VECTOR_ROUTING_H__ + +#include + +#include "ns3/channel.h" +#include "ns3/node-container.h" +#include "ns3/node-list.h" +#include "ns3/net-device-container.h" +#include "ns3/ipv4-routing-protocol.h" +#include "ns3/ipv4-route.h" +#include "ns3/bridge-net-device.h" + +namespace ns3 { + +typedef std::map > NixMap_t; +typedef std::map > Ipv4RouteMap_t; + +class Ipv4NixVectorRouting : public Ipv4RoutingProtocol +{ + public: + Ipv4NixVectorRouting (); + ~Ipv4NixVectorRouting (); + /** + * @brief The Interface ID of the Global Router interface. + * + * @see Object::GetObject () + */ + static TypeId GetTypeId (void); + /** + * @brief Set the Node pointer of the node for which this + * routing protocol is to be placed + * + * @param node Node pointer + */ + void SetNode (Ptr); + + /** + * @brief Called when run-time link topology change occurs + * which iterates through the node list and flushes any + * nix vector caches + * + */ + void FlushGlobalNixRoutingCache (void); + + private: + /* flushes the cache which stores nix-vector based on + * destination IP */ + void FlushNixCache (void); + + /* flushes the cache which stores the Ipv4 route + * based on the destination IP */ + void FlushIpv4RouteCache (void); + + /* upon a run-time topology change caches are + * flushed and the total number of neighbors is + * reset to zero */ + void ResetTotalNeighbors (void); + + /* takes in the source node and dest IP and calls GetNodeByIp, + * BFS, and BuildNixVector to finally return the built + * nix-vector */ + Ptr GetNixVector (Ptr, Ipv4Address); + + /* checks the cache based on dest IP for the nix-vector */ + Ptr GetNixVectorInCache (Ipv4Address); + + /* checks the cache based on dest IP for the Ipv4Route */ + Ptr GetIpv4RouteInCache (Ipv4Address); + + /* given a net-device returns all the adjacent net-devices, + * essentially getting the neighbors on that channel */ + void GetAdjacentNetDevices (Ptr, Ptr, NetDeviceContainer &); + + /* iterates through the node list and finds the one + * corresponding to the given Ipv4Address */ + Ptr GetNodeByIp (Ipv4Address); + + /* Recurses the parent vector, created by BFS and actually builds the nixvector */ + bool BuildNixVector (const std::vector< Ptr > & parentVector, uint32_t source, uint32_t dest, Ptr nixVector); + + /* special variation of BuildNixVector for when a node is sending to itself */ + bool BuildNixVectorLocal (Ptr nixVector); + + /* simple iterates through the nodes net-devices and determines + * how many neighbors it has */ + uint32_t FindTotalNeighbors (void); + + /* determine if the netdevice is bridged */ + Ptr NetDeviceIsBridged (Ptr nd) const; + + + /* Nix index is with respect to the neighbors. The net-device index must be + * derived from this */ + uint32_t FindNetDeviceForNixIndex (uint32_t nodeIndex, Ipv4Address & gatewayIp); + + /* Breadth first search algorithm + * Param1: Vector containing all nodes in the graph + * Param2: Source Node + * Param3: Dest Node + * Param4: (returned) Parent vector for retracing routes + * Returns: false if dest not found, true o.w. + */ + bool BFS (uint32_t numberOfNodes, + Ptr source, + Ptr dest, + std::vector< Ptr > & parentVector); + + void DoDispose (void); + + /* From Ipv4RoutingProtocol */ + virtual Ptr RouteOutput (Ptr p, const Ipv4Header &header, uint32_t oif, Socket::SocketErrno &sockerr); + virtual bool RouteInput (Ptr p, const Ipv4Header &header, Ptr idev, + UnicastForwardCallback ucb, MulticastForwardCallback mcb, + LocalDeliverCallback lcb, ErrorCallback ecb); + virtual void NotifyInterfaceUp (uint32_t interface); + virtual void NotifyInterfaceDown (uint32_t interface); + virtual void NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address); + virtual void NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address); + virtual void SetIpv4 (Ptr ipv4); + + + /* cache stores nix-vectors based on destination ip */ + NixMap_t m_nixCache; + + /* cache stores Ipv4Routes based on destination ip */ + Ipv4RouteMap_t m_ipv4RouteCache; + + Ptr m_ipv4; + Ptr m_node; + + /* total neighbors used for nix-vector to determine + * number of bits */ + uint32_t m_totalNeighbors; +}; +} // namepace ns3 +#endif diff --git a/src/routing/nix-vector-routing/nix-vector-routing.h b/src/routing/nix-vector-routing/nix-vector-routing.h new file mode 100644 index 000000000..8492f9ffa --- /dev/null +++ b/src/routing/nix-vector-routing/nix-vector-routing.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2009 The Georgia Institute of Technology + * + * 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 + * + * Authors: Josh Pelkey + */ + +/** + * \ingroup routing + * \defgroup nixvectorrouting Nix-vector Routing + * + * \section model Model + * + * Nix-vector routing is a simulation specific routing protocol and is + * intended for large network topologies. The on-demand nature of this + * protocol as well as the low-memory footprint of the nix-vector provides + * improved performance in terms of memory usage and simulation run time + * when dealing with a large number of nodes. + * + * Currently, the ns-3 model of nix-vector routing supports IPv4 p2p links + * as well as CSMA links. It does not (yet) provide support for + * efficient adaptation to link failures. It simply flushes all nix-vector + * routing caches. Finally, IPv6 is not supported. + * + * \section api API and Usage + * + * Nix-vector routing has been rolled into a helper class. In order to + * utilize these helper functions, users must include ns3/helper-module.h. + * The Nix-vector routing protocol must be added to a list of routing + * protocols. It is important that list routing is utilized. + * + * Example: + * + * Ipv4NixVectorHelper nixRouting; + * Ipv4StaticRoutingHelper staticRouting; + * + * Ipv4ListRoutingHelper list; + * list.Add (staticRouting, 0); + * list.Add (nixRouting, 10); + * + * InternetStackHelper stack; + * stack.SetRoutingHelper (list); + * stack.Install (allNodes); + * + * \section impl Implementation + * + * ns-3 nix-vector-routing performs on-demand route computation using + * a breadth-first search and an efficient route-storage data structure + * known as a nix-vector. When a packet is generated at a node for + * transmission, the route is calculated, and the nix-vector is built. + * The nix-vector stores an index for each hop along the path, which + * corresponds to the neighbor-index. This index is used to determine + * which net-device and gateway should be used. To route a packet, the + * nix-vector must be transmitted with the packet (in the metadata). + * At each hop, the current node extracts the appropriate neighbor-index + * from the nix-vector and transmits the packet through the corresponding + * net-device. This continues until the packet reaches the destination. + * */ diff --git a/src/routing/nix-vector-routing/waf b/src/routing/nix-vector-routing/waf new file mode 100644 index 000000000..4283ec141 --- /dev/null +++ b/src/routing/nix-vector-routing/waf @@ -0,0 +1 @@ +exec "`dirname "$0"`"/../../../waf "$@" diff --git a/src/routing/nix-vector-routing/wscript b/src/routing/nix-vector-routing/wscript new file mode 100644 index 000000000..d126d2510 --- /dev/null +++ b/src/routing/nix-vector-routing/wscript @@ -0,0 +1,15 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + module = bld.create_ns3_module('nix-vector-routing', ['internet-stack', 'contrib']) + module.includes = '.' + module.source = [ + 'ipv4-nix-vector-routing.cc', + ] + + headers = bld.new_task_gen('ns3header') + headers.module = 'nix-vector-routing' + headers.source = [ + 'ipv4-nix-vector-routing.h', + ] + diff --git a/src/wscript b/src/wscript index da8d27117..a76ff20ce 100644 --- a/src/wscript +++ b/src/wscript @@ -27,6 +27,7 @@ all_modules = ( 'applications/onoff', 'applications/packet-sink', 'applications/udp-echo', + 'routing/nix-vector-routing', 'routing/olsr', 'routing/global-routing', 'routing/static-routing',