diff --git a/.hgtags b/.hgtags index 35f08ab9c..45520a625 100644 --- a/.hgtags +++ b/.hgtags @@ -6,3 +6,4 @@ 08046b6aef37932507696a2f2f427b42d693781e release ns-3.0.5 267e2ebc28e4e4ae2f579e1cfc29902acade0c34 buffer-working-before-breaking 606df29888e7573b825fc891a002f0757166b616 release ns-3.0.6 +36472385a1cc7c44d34fb7a5951b930010f4e8d2 release ns-3.0.7 diff --git a/README b/README index 23c9a6c71..01d2c2ccf 100644 --- a/README +++ b/README @@ -84,12 +84,12 @@ following set of platforms: - linux x86 gcc 4.2, 4.1, and, 3.4. - linux x86_64 gcc 4.0 - MacOS X ppc and x86 + - cygwin The current codebase is expected to fail to build on the following platforms: - gcc 3.3 and earlier - optimized builds on linux x86 gcc 4.0 - - cygwin Other platforms may or may not work: we welcome patches to improve the portability of the code to these @@ -102,17 +102,17 @@ On recent Linux systems, once you have built ns-3, it should be easy to run the sample programs with the following command: -./waf --run simple-p2p +./waf --run simple-point-to-point -That program should generate a simple-p2p.tr text -trace file and a set of simple-p2p-xx-xx.pcap binary +That program should generate a simple-point-to-point.tr text +trace file and a set of simple-point-to-point-xx-xx.pcap binary pcap trace files, which can be read by tcpdump. 5) Getting access to the ns-3 documentation ------------------------------------------- Once you have verified that your build of ns-3 works by running -the simple-p2p example as outlined in 4) above, it is +the simple-point-to-point example as outlined in 4) above, it is quite likely that you will want to get started on reading some ns-3 documentation. diff --git a/RELEASE_NOTES b/RELEASE_NOTES index e429e5fec..4aff62726 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -3,6 +3,13 @@ This file contains ns-3 release notes (most recent releases first). +Release 3.0.7 (2007/10/15) +======================== + - OLSR routing protocol + - A timer class + - Additional mobility models (random waypoint, random 2D walk) + - A mobility visualization tool + Release 3.0.6 (2007/09/15) ======================== - Static multicast IPv4 routing diff --git a/VERSION b/VERSION index 818bd47ab..2451c27ca 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.6 +3.0.7 diff --git a/doc/build.txt b/doc/build.txt index bfb2b518d..95bc068e1 100644 --- a/doc/build.txt +++ b/doc/build.txt @@ -3,79 +3,62 @@ build system (http://www.freehackers.org/~tnagy/waf.html) === Installing Waf === -If this file is part of a development release tarball, the top-level -ns-3 directory should contain a current waf script. - -However, the ns-3 Mercurial code repository does not contain the waf -script. Instead, developers should check it out from a subversion -repository: - - svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf - -[ note: 'tags/ns3' is a tag that represents the last svn version -tested to work correctly with ns3, although 'trunk' will likely work - as well ] - -Then it can be installed system-wide with 'sudo waf-light install'. -When preparing a distribution, the resulting 'waf' script, which is -self contained (no external files needed), can be easily included in -the tarball so that users downloading ns-3 can easily build it without -having Waf installed (although Python >= 2.3 is still needed). +The top-level ns-3 directory should contain a current waf script. === Building with Waf === -To build ns-3 with waf type the commands: - 1. waf configure [options] - 2. waf +To build ns-3 with waf type the commands from the top-level directory: + 1. ./waf configure [options] + 2. ./waf -To see valid configure options, type waf --help. The most important +To see valid configure options, type ./waf --help. The most important option is -d . Valid debug levels (which are listed in -waf --help) are: ultradebug, debug, release, and optimized. It is +waf --help) are: "debug" or "optimized". It is also possible to change the flags used for compilation with (e.g.): -CXXFLAGS="-O3" waf configure. +CXXFLAGS="-O3" ./waf configure. [ Note: Unlike some other build tools, to change the build target, the option must be supplied during the configure stage rather than -the build stage (i.e., "waf -d optimized" will not work; instead, do -"waf -d optimized configure; waf" ] +the build stage (i.e., "./waf -d optimized" will not work; instead, do +"./waf -d optimized configure; ./waf" ] The resulting binaries are placed in build//srcpath. Other waf usages include: - 1. waf check + 1. ./waf check Runs the unit tests - 2. waf --doxygen + 2. ./waf --doxygen Run doxygen to generate documentation - 3. waf --lcov-report + 3. ./waf --lcov-report Run code coverage analysis (assuming the project was configured with --enable-gcov) - 4. waf --run "program [args]" + 4. ./waf --run "program [args]" Run a ns3 program, given its target name, with the given arguments. This takes care of automatically modifying the the path for finding the ns3 dynamic libraries in the environment before running the program. Note: the "program [args]" string is parsed using POSIX shell rules. - 4.1 waf --run programname --command-template "... %s ..." + 4.1 ./waf --run programname --command-template "... %s ..." Same as --run, but uses a command template with %s replaced by the actual program (whose name is given by --run). This can be use to run ns-3 programs with helper tools. For example, to run unit tests with valgrind, use the command: - waf --run run-tests --command-template "valgrind %s" + ./waf --run run-tests --command-template "valgrind %s" - 5. waf --shell + 5. ./waf --shell Starts a nested system shell with modified environment to run ns3 programs. - 6. waf distclean + 6. ./waf distclean Cleans out the entire build/ directory - 7. waf dist + 7. ./waf dist The command 'waf dist' can be used to create a distribution tarball. It includes all files in the source directory, except some particular extensions that are blacklisted, such as back files (ending in ~). diff --git a/doc/doxygen.conf b/doc/doxygen.conf index 07925290d..6f3f7e2bb 100644 --- a/doc/doxygen.conf +++ b/doc/doxygen.conf @@ -472,6 +472,9 @@ RECURSIVE = YES # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = \ + src/routing/olsr/olsr-state.h \ + src/routing/olsr/repositories.h \ + src/routing/olsr/routing-table.h \ src/simulator/high-precision.h \ src/simulator/high-precision-128.h \ src/simulator/high-precision-double.h diff --git a/doc/main.txt b/doc/main.txt index 37e1ed92d..1027eb97f 100644 --- a/doc/main.txt +++ b/doc/main.txt @@ -65,4 +65,4 @@ /** * \defgroup constants Constants * \brief Constants you can change - */ \ No newline at end of file + */ diff --git a/doc/release_steps.txt b/doc/release_steps.txt index 5fe843d77..d949b5575 100644 --- a/doc/release_steps.txt +++ b/doc/release_steps.txt @@ -1,24 +1,32 @@ Steps in doing an ns-3 release +0. check out a clean ns-3-dev somewhere 1. prepare the source files - revise and check in AUTHORS, if needed - revise and check in RELEASE_NOTES - update and check in VERSION to the latest release number 2. make a new "architecture.pdf" document and place it in the doc/ directory -3. cd ns-3-dev; ./waf configure; ./waf dist + of the ns-3-dev working directory +3. ./waf configure; ./waf dist + - this will create a ns-3.0.x.tar.bz2 tarball 4. test tarball on release platforms (waf check and maybe some other scripts) -5. tag ns-3-dev with "release ns-3.0.X" - - hg tag "release ns-3.0.x" - - hg push +5. once you are happy with the tarball, tag ns-3-dev with "release ns-3.0.X" + - hg tag "release ns-3.0.x" + - hg push 6. clone the tagged ns-3-dev and place it on the repository - - ssh code.nsnam.org; sudo; su code; - - cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.0.x - - cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately -7. upload "ns-3.0.x.tar.bz2" to the releases/ directory on the server + - ssh code.nsnam.org; sudo; su code; + - cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.0.x + - cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately +7. upload "ns-3.0.x.tar.bz2" to the /var/www/html/releases/ directory on + the www.nsnam.org server 8. update web page - add link to news.html - - update download.html - - update roadmap.html + - update getting_started.html + - update documents.html + - update roadmap on wiki - build and update Doxygen directory on the server + -- ssh www.nsnam.org; sudo tcsh; su nsnam; + -- ~/bin/update-doxygen-release - update and upload software architecture document (PDF, HTML) + -- note: HTML image generation is not currently automatic 9. announce to ns-developers, with summary of release notes diff --git a/examples/simple-alternate-routing.cc b/examples/simple-alternate-routing.cc new file mode 100644 index 000000000..e9cedff04 --- /dev/null +++ b/examples/simple-alternate-routing.cc @@ -0,0 +1,224 @@ +/* -*- 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 + * + */ + +// +// Network topology +// +// n0 +// \ 5 Mb/s, 2ms +// \ 1.5Mb/s, 10ms +// n2 ------------------------n3 +// / / +// / 5 Mb/s, 2ms / +// n1-------------------------- +// 1.5 Mb/s, 100ms +// +// this is a modification of simple-global-routing to allow for +// a single hop but higher-cost path between n1 and n3 +// +// - Tracing of queues and packet receptions to file "simple-rerouting.tr" + +#include +#include +#include +#include + +#include "ns3/log.h" + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/ipv4-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4-route.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/global-route-manager.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("SimpleAlternateRoutingExample"); + +int +main (int argc, char *argv[]) +{ + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +#if 0 + LogComponentEnable("GlobalRouteManager", LOG_LOGIC); + LogComponentEnable("GlobalRouter", LOG_LOGIC); + LogComponentEnable("Object", LOG_LEVEL_ALL); + LogComponentEnable("Queue", LOG_LEVEL_ALL); + LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL); + LogComponentEnable("Channel", LOG_LEVEL_ALL); + LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL); + LogComponentEnable("NetDevice", LOG_LEVEL_ALL); + LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL); + LogComponentEnable("PacketSocket", LOG_LEVEL_ALL); + LogComponentEnable("Socket", LOG_LEVEL_ALL); + LogComponentEnable("UdpSocket", LOG_LEVEL_ALL); + LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL); + LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL); + LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL); + LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL); + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL); +#endif + // Set up some default values for the simulation. Use the + // DefaultValue::Bind () technique to tell the system what subclass of + // Queue to use, and what the queue limit is + + // The below Bind command tells the queue factory which class to + // instantiate, when the queue factory is invoked in the topology code + DefaultValue::Bind ("Queue", "DropTailQueue"); + + DefaultValue::Bind ("OnOffApplicationPacketSize", "210"); + DefaultValue::Bind ("OnOffApplicationDataRate", "300b/s"); + + // The below metric, if set to 3 or higher, will cause packets between + // n1 and n3 to take the 2-hop route through n2 + // + // Additionally, we plumb this metric into the default value / command + // line argument system as well, for exemplary purposes. This means + // that it can be resettable at the command-line to the program, + // rather than recompiling + // e.g. waf --run "simple-alternate-routing --AlternateCost=5" + uint16_t sampleMetric = 1; + CommandLine::AddArgValue ("AlternateCost", + "This metric is used in the example script between n3 and n1 ", + sampleMetric); + + // Allow the user to override any of the defaults and the above + // DefaultValue::Bind ()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create four nodes. In more sophisticated + // topologies, we could configure a node factory. + NS_LOG_INFO ("Create nodes."); + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + Ptr n3 = Create (); + + // We create the channels first without any IP addressing information + NS_LOG_INFO ("Create channels."); + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n2, DataRate (5000000), MilliSeconds (2)); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate (5000000), MilliSeconds (2)); + + Ptr channel2 = + PointToPointTopology::AddPointToPointLink ( + n2, n3, DataRate (1500000), MilliSeconds (10)); + + Ptr channel3 = + PointToPointTopology::AddPointToPointLink ( + n1, n3, DataRate (1500000), MilliSeconds (100)); + + // Later, we add IP addresses. The middle two octets correspond to + // the channel number. + NS_LOG_INFO ("Assign IP Addresses."); + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address ("10.0.0.1"), + n2, Ipv4Address ("10.0.0.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address ("10.1.1.1"), + n2, Ipv4Address ("10.1.1.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel2, n2, Ipv4Address ("10.2.2.1"), + n3, Ipv4Address ("10.2.2.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel3, n1, Ipv4Address ("10.3.3.1"), + n3, Ipv4Address ("10.3.3.2")); + + PointToPointTopology::SetIpv4Metric ( + channel3, n1, n3, sampleMetric); + + // Create router nodes, initialize routing database and set up the routing + // tables in the nodes. + GlobalRouteManager::PopulateRoutingTables (); + + // Create the OnOff application to send UDP datagrams + NS_LOG_INFO ("Create Application."); + uint16_t port = 9; // Discard port (RFC 863) + + // Create a flow from n3 to n1, starting at time 1.1 seconds + Ptr ooff = Create ( + n3, + InetSocketAddress ("10.1.1.1", port), + "Udp", + ConstantVariable (1), + ConstantVariable (0)); + // Start the application + ooff->Start (Seconds (1.1)); + ooff->Stop (Seconds (10.0)); + + // Create a packet sink to receive these packets + Ptr sink = Create ( + n1, + InetSocketAddress (Ipv4Address::GetAny (), port), + "Udp"); + // Start the sink + sink->Start (Seconds (1.1)); + sink->Stop (Seconds (10.0)); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-alternate-routing.tr file + NS_LOG_INFO ("Configure Tracing."); + AsciiTrace asciitrace ("simple-alternate-routing.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named simple-p2p.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("simple-alternate-routing.pcap"); + pcaptrace.TraceAllIp (); + + NS_LOG_INFO ("Run Simulation."); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); + + return 0; +} diff --git a/examples/simple-point-to-point-olsr.cc b/examples/simple-point-to-point-olsr.cc new file mode 100644 index 000000000..b4343acfe --- /dev/null +++ b/examples/simple-point-to-point-olsr.cc @@ -0,0 +1,233 @@ +/* -*- 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 + * + * ns-2 simple.tcl script (ported from ns-2) + * Originally authored by Steve McCanne, 12/19/1996 + */ + +// Port of ns-2/tcl/ex/simple.tcl to ns-3 +// +// Network topology +// +// n0 +// \ 5 Mb/s, 2ms +// \ 1.5Mb/s, 10ms +// n2 -------------------------n3 +// / +// / 5 Mb/s, 2ms +// n1 +// +// - all links are point-to-point links with indicated one-way BW/delay +// - CBR/UDP flows from n0 to n3, and from n3 to n1 +// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec. +// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. +// (i.e., DataRate of 448,000 bps) +// - DropTail queues +// - Tracing of queues and packet receptions to file +// "simple-point-to-point.tr" + +#include "ns3/log.h" +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/olsr.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("SimplePointToPointExample"); + +int +main (int argc, char *argv[]) +{ + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +#if 0 + LogComponentEnable ("SimplePointToPointExample", LOG_LEVEL_INFO); + + LogComponentEnable("Object", LOG_LEVEL_ALL); + LogComponentEnable("Queue", LOG_LEVEL_ALL); + LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL); + LogComponentEnable("Channel", LOG_LEVEL_ALL); + LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL); + LogComponentEnable("NetDevice", LOG_LEVEL_ALL); + LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL); + LogComponentEnable("PacketSocket", LOG_LEVEL_ALL); + LogComponentEnable("Socket", LOG_LEVEL_ALL); + LogComponentEnable("UdpSocket", LOG_LEVEL_ALL); + LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL); + LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL); + LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL); + LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL); + LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL); + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL); +#endif + + // Set up some default values for the simulation. Use the Bind() + // technique to tell the system what subclass of Queue to use, + // and what the queue limit is + + // The below Bind command tells the queue factory which class to + // instantiate, when the queue factory is invoked in the topology code + DefaultValue::Bind ("Queue", "DropTailQueue"); + + DefaultValue::Bind ("OnOffApplicationPacketSize", "210"); + DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s"); + + //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30); + + // Allow the user to override any of the defaults and the above + // Bind()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create four nodes. In more sophisticated + // topologies, we could configure a node factory. + NS_LOG_INFO ("Create nodes."); + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + Ptr n3 = Create (); + + // We create the channels first without any IP addressing information + NS_LOG_INFO ("Create channels."); + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n2, DataRate(5000000), MilliSeconds(2)); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate(5000000), MilliSeconds(2)); + + Ptr channel2 = + PointToPointTopology::AddPointToPointLink ( + n2, n3, DataRate(1500000), MilliSeconds(10)); + + // Later, we add IP addresses. + NS_LOG_INFO ("Assign IP Addresses."); + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address("10.1.1.1"), + n2, Ipv4Address("10.1.1.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address("10.1.2.1"), + n2, Ipv4Address("10.1.2.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel2, n2, Ipv4Address("10.1.3.1"), + n3, Ipv4Address("10.1.3.2")); + + // Finally, we add static routes. These three steps (Channel and + // NetDevice creation, IP Address assignment, and routing) are + // separated because there may be a need to postpone IP Address + // assignment (emulation) or modify to use dynamic routing + NS_LOG_INFO ("Enabling OLSR Routing."); + olsr::EnableAllNodes (); + + // Create the OnOff application to send UDP datagrams of size + // 210 bytes at a rate of 448 Kb/s + NS_LOG_INFO ("Create Applications."); + uint16_t port = 9; // Discard port (RFC 863) + Ptr ooff = Create ( + n0, + InetSocketAddress ("10.1.3.2", port), + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.0)); + ooff->Stop (Seconds(10.0)); + + // Create an optional packet sink to receive these packets + Ptr sink = Create ( + n3, + InetSocketAddress (Ipv4Address::GetAny (), port), + "Udp"); + // Start the sink + sink->Start (Seconds (1.0)); + sink->Stop (Seconds (10.0)); + + // Create a similar flow from n3 to n1, starting at time 1.1 seconds + ooff = Create ( + n3, + InetSocketAddress ("10.1.2.1", port), + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.1)); + ooff->Stop (Seconds(10.0)); + + // Create a packet sink to receive these packets + sink = Create ( + n1, + InetSocketAddress (Ipv4Address::GetAny (), port), + "Udp"); + // Start the sink + sink->Start (Seconds (1.1)); + sink->Stop (Seconds (10.0)); + + // Here, finish off packet routing configuration + // This will likely set by some global StaticRouting object in the future + NS_LOG_INFO ("Set Default Routes."); + Ptr ipv4; + ipv4 = n0->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1); + ipv4 = n3->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-point-to-point.tr file + NS_LOG_INFO ("Configure Tracing."); + AsciiTrace asciitrace ("simple-point-to-point-olsr.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named + // simple-point-to-point.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("simple-point-to-point-olsr.pcap"); + pcaptrace.TraceAllIp (); + + NS_LOG_INFO ("Run Simulation."); + Simulator::StopAt (Seconds (10)); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +} diff --git a/examples/simple-point-to-point.cc b/examples/simple-point-to-point.cc index 5bbde9bca..d1e132211 100644 --- a/examples/simple-point-to-point.cc +++ b/examples/simple-point-to-point.cc @@ -227,6 +227,7 @@ main (int argc, char *argv[]) pcaptrace.TraceAllIp (); NS_LOG_INFO ("Run Simulation."); + Simulator::StopAt (Seconds (10)); Simulator::Run (); Simulator::Destroy (); NS_LOG_INFO ("Done."); diff --git a/examples/wscript b/examples/wscript index a1f16e29b..f597225fb 100644 --- a/examples/wscript +++ b/examples/wscript @@ -6,6 +6,10 @@ def build(bld): ['point-to-point', 'internet-node', 'global-routing']) obj.source = 'simple-global-routing.cc' + obj = bld.create_ns3_program('simple-alternate-routing', + ['point-to-point', 'internet-node', 'global-routing']) + obj.source = 'simple-alternate-routing.cc' + obj = bld.create_ns3_program('simple-point-to-point', ['point-to-point', 'internet-node']) obj.source = 'simple-point-to-point.cc' @@ -33,3 +37,7 @@ def build(bld): obj = bld.create_ns3_program( 'mixed-global-routing', ['point-to-point', 'internet-node', 'global-routing' , 'csma-cd']) obj.source = 'mixed-global-routing.cc' + + obj = bld.create_ns3_program('simple-point-to-point-olsr', + ['point-to-point', 'internet-node', 'olsr']) + obj.source = 'simple-point-to-point-olsr.cc' diff --git a/src/common/packet.h b/src/common/packet.h index f1e14cf02..58e842292 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -244,6 +244,16 @@ public: * A packet is allocated a new uid when it is created * empty or with zero-filled payload. * + * Note: This uid is an internal uid and cannot be counted on to + * provide an accurate counter of how many "simulated packets" of a + * particular protocol are in the system. It is not trivial to make + * this uid into such a counter, because of questions such as what + * should the uid be when the packet is sent over broadcast media, or + * when fragmentation occurs. If a user wants to trace actual packet + * counts, he or she should look at e.g. the IP ID field or transport + * sequence numbers, or other packet or frame counters at other + * protocol layers. + * * \returns an integer identifier which uniquely * identifies this packet. */ diff --git a/src/core/default-value.cc b/src/core/default-value.cc index 09f06a1ed..e9020ebe3 100644 --- a/src/core/default-value.cc +++ b/src/core/default-value.cc @@ -496,6 +496,8 @@ DefaultValueTest::RunTests (void) DefaultValueList::Remove ("bool-a"); DefaultValueList::Remove ("test-i"); DefaultValueList::Remove ("test-c"); + DefaultValueList::Remove ("test-x"); + DefaultValueList::Remove ("test-y"); DefaultValueList::Remove ("test-ui32"); return result; diff --git a/src/core/log.cc b/src/core/log.cc index 6f5bd6acf..de43712cf 100644 --- a/src/core/log.cc +++ b/src/core/log.cc @@ -18,6 +18,8 @@ * Author: Mathieu Lacage */ +// What about print-list!!!!!!??????? + #ifdef NS3_LOG_ENABLE #include @@ -44,29 +46,33 @@ ComponentList *GetComponentList (void) return &components; } -void -LogComponentEnableEnvVar (void) +LogComponent::LogComponent (char const * name) + : m_levels (0), m_name (name) { - static bool isFirstLog = true; - if (!isFirstLog) + EnvVarCheck (name); + + ComponentList *components = GetComponentList (); + for (ComponentListI i = components->begin (); + i != components->end (); + i++) { - return; + NS_ASSERT (i->first != name); } + components->push_back (std::make_pair (name, this)); +} + +void +LogComponent::EnvVarCheck (char const * name) +{ #ifdef HAVE_GETENV char *envVar = getenv("NS_LOG"); if (envVar == 0) { - isFirstLog = false; return; } std::string env = envVar; - if (env == "print-list") - { - LogComponentPrintList (); - isFirstLog = false; - return; - } - bool allFound = true; + std::string myName = name; + std::string::size_type cur = 0; std::string::size_type next = 0; while (true) @@ -88,106 +94,101 @@ LogComponentEnableEnvVar (void) } std::string::size_type equal = tmp.find ("="); std::string component; - int level; if (equal == std::string::npos) { component = tmp; - level = LOG_DEBUG; + if (component == myName || component == "*") + { + Enable (LOG_DEBUG); + return; + } } else { component = tmp.substr (0, equal); - std::string::size_type cur_lev; - std::string::size_type next_lev = equal; - do + if (component == myName || component == "*") { - cur_lev = next_lev + 1; - next_lev = tmp.find ("|", cur_lev); - std::string lev = tmp.substr (cur_lev, next_lev - cur_lev); - if (lev == "error") + int level = 0; + std::string::size_type cur_lev; + std::string::size_type next_lev = equal; + do { - level |= LOG_ERROR; - } - else if (lev == "warn") - { - level |= LOG_WARN; - } - else if (lev == "debug") - { - level |= LOG_DEBUG; - } - else if (lev == "info") - { - level |= LOG_INFO; - } - else if (lev == "function") - { - level |= LOG_FUNCTION; - } - else if (lev == "param") - { - level |= LOG_PARAM; - } - else if (lev == "logic") - { - level |= LOG_LOGIC; - } - else if (lev == "all") - { - level |= LOG_ALL; - } - else if (lev == "errorlevel") - { - level |= LOG_LEVEL_ERROR; - } - else if (lev == "warnlevel") - { - level |= LOG_LEVEL_WARN; - } - else if (lev == "debuglevel") - { - level |= LOG_LEVEL_DEBUG; - } - else if (lev == "infolevel") - { - level |= LOG_LEVEL_INFO; - } - else if (lev == "functionlevel") - { - level |= LOG_LEVEL_FUNCTION; - } - else if (lev == "paramlevel") - { - level |= LOG_LEVEL_PARAM; - } - else if (lev == "logiclevel") - { - level |= LOG_LEVEL_LOGIC; - } - else if (lev == "alllevel") - { - level |= LOG_LEVEL_ALL; - } - } while (next_lev != std::string::npos); - } - bool found = false; - ComponentList *components = GetComponentList (); - for (ComponentListI i = components->begin (); - i != components->end (); - i++) - { - if (i->first.compare (component) == 0) - { - found = true; - - i->second->Enable ((enum LogLevel)level); - break; + cur_lev = next_lev + 1; + next_lev = tmp.find ("|", cur_lev); + std::string lev = tmp.substr (cur_lev, next_lev - cur_lev); + if (lev == "error") + { + level |= LOG_ERROR; + } + else if (lev == "warn") + { + level |= LOG_WARN; + } + else if (lev == "debug") + { + level |= LOG_DEBUG; + } + else if (lev == "info") + { + level |= LOG_INFO; + } + else if (lev == "function") + { + level |= LOG_FUNCTION; + } + else if (lev == "param") + { + level |= LOG_PARAM; + } + else if (lev == "logic") + { + level |= LOG_LOGIC; + } + else if (lev == "all") + { + level |= LOG_ALL; + } + else if (lev == "prefix") + { + level |= LOG_PREFIX_ALL; + } + else if (lev == "level_error") + { + level |= LOG_LEVEL_ERROR; + } + else if (lev == "level_warn") + { + level |= LOG_LEVEL_WARN; + } + else if (lev == "level_debug") + { + level |= LOG_LEVEL_DEBUG; + } + else if (lev == "level_info") + { + level |= LOG_LEVEL_INFO; + } + else if (lev == "level_function") + { + level |= LOG_LEVEL_FUNCTION; + } + else if (lev == "level_param") + { + level |= LOG_LEVEL_PARAM; + } + else if (lev == "level_logic") + { + level |= LOG_LEVEL_LOGIC; + } + else if (lev == "level_all") + { + level |= LOG_LEVEL_ALL; + } + } while (next_lev != std::string::npos); + + Enable ((enum LogLevel)level); } } - if (!found) - { - allFound = false; - } if (next == std::string::npos) { break; @@ -198,31 +199,14 @@ LogComponentEnableEnvVar (void) break; } } - if (allFound) - { - isFirstLog = false; - } - #endif } -LogComponent::LogComponent (char const * name) - : m_levels (0) -{ - ComponentList *components = GetComponentList (); - for (ComponentListI i = components->begin (); - i != components->end (); - i++) - { - NS_ASSERT (i->first != name); - } - components->push_back (std::make_pair (name, this)); -} bool LogComponent::IsEnabled (enum LogLevel level) const { - LogComponentEnableEnvVar (); + // LogComponentEnableEnvVar (); return (level & m_levels) ? 1 : 0; } @@ -244,6 +228,13 @@ LogComponent::Disable (enum LogLevel level) m_levels &= ~level; } +char const * +LogComponent::Name (void) const +{ + return m_name; +} + + void LogComponentEnable (char const *name, enum LogLevel level) { @@ -260,6 +251,18 @@ LogComponentEnable (char const *name, enum LogLevel level) } } +void +LogComponentEnableAll (enum LogLevel level) +{ + ComponentList *components = GetComponentList (); + for (ComponentListI i = components->begin (); + i != components->end (); + i++) + { + i->second->Enable (level); + } +} + void LogComponentDisable (char const *name, enum LogLevel level) { @@ -276,6 +279,18 @@ LogComponentDisable (char const *name, enum LogLevel level) } } +void +LogComponentDisableAll (enum LogLevel level) +{ + ComponentList *components = GetComponentList (); + for (ComponentListI i = components->begin (); + i != components->end (); + i++) + { + i->second->Disable (level); + } +} + void LogComponentPrintList (void) { diff --git a/src/core/log.h b/src/core/log.h index 267419bf5..c027fa022 100644 --- a/src/core/log.h +++ b/src/core/log.h @@ -32,22 +32,23 @@ * send information out on screen. All logging messages * are disabled by default. To enable selected logging * messages, use the ns3::LogComponentEnable - * function. - * - * Alternatively, you can use the NS_LOG - * environment variable to define a ';'-separated list of + * function or use the NS_LOG environment variable and + * ns3::LogComponentEnableEnvVar + * + * Use the environment variable NS_LOG to define a ';'-separated list of * logging components to enable. For example, NS_LOG=a;b;c;DAFD;GH * would enable the components 'a', 'b', 'c', 'DAFD', and, 'GH'. + * NS_LOG=* will enable all available log components. * * For each component, the "debug" log level is enabled by default * but more components can be enabled selectively with the following * syntax: NS_LOG='Component1=func|param|warn;Component2=error|debug' * This example would enable the 'func', 'param', and 'warn' log * levels for 'Component1' and the 'error' and 'debug' log levels - * for 'Component2'. + * for 'Component2'. The wildcard can be used here as well. For example + * NS_LOG='*=level_all|prefix' would enable all log levels and prefix all + * prints with the component and function names. * - * The list of available log components can be printed on stdout - * with the NS_LOG=print-list syntax. */ /** @@ -92,20 +93,25 @@ { \ if (g_log.IsEnabled (level)) \ { \ - std::clog << __PRETTY_FUNCTION__ << " ==> " << \ - msg << std::endl; \ + if (g_log.IsEnabled (ns3::LOG_PREFIX_ALL)) \ + { \ + std::clog << g_log.Name () << ":" << \ + __FUNCTION__ << "(): "; \ + } \ + std::clog << msg << std::endl; \ } \ } \ while (false) -#define NS_LOG_F(level) \ - do \ - { \ - if (g_log.IsEnabled (level)) \ - { \ - std::clog << __PRETTY_FUNCTION__ << std::endl;\ - } \ - } \ +#define NS_LOG_F(level) \ + do \ + { \ + if (g_log.IsEnabled (level)) \ + { \ + std::clog << g_log.Name () << ":" << __FUNCTION__ << \ + "()" << std::endl; \ + } \ + } \ while (false) #define NS_LOG_ERROR(msg) \ @@ -129,9 +135,6 @@ #define NS_LOG_LOGIC(msg) \ NS_LOG(ns3::LOG_LOGIC, msg) -#define NS_LOG_ALL(msg) \ - NS_LOG(ns3::LOG_ALL, msg) - #define NS_LOG_UNCOND(msg) \ do \ { \ @@ -150,7 +153,6 @@ #define NS_LOG_FUNCTION #define NS_LOG_PARAM(msg) #define NS_LOG_LOGIC(msg) -#define NS_LOG_ALL(msg) #define NS_LOG_UNCOND(msg) #endif @@ -160,70 +162,95 @@ namespace ns3 { #ifdef NS3_LOG_ENABLE enum LogLevel { - LOG_ERROR = 0x0001, // serious error messages only - LOG_LEVEL_ERROR = 0x0001, + LOG_NONE = 0x00000000, // no logging - LOG_WARN = 0x0002, // warning messages - LOG_LEVEL_WARN = 0x0003, + LOG_ERROR = 0x00000001, // serious error messages only + LOG_LEVEL_ERROR = 0x00000001, - LOG_DEBUG = 0x0004, // rare ad-hoc debug messages - LOG_LEVEL_DEBUG = 0x0007, + LOG_WARN = 0x00000002, // warning messages + LOG_LEVEL_WARN = 0x00000003, - LOG_INFO = 0x0008, // informational messages (e.g., banners) - LOG_LEVEL_INFO = 0x000f, + LOG_DEBUG = 0x00000004, // rare ad-hoc debug messages + LOG_LEVEL_DEBUG = 0x00000007, - LOG_FUNCTION = 0x0010, // function tracing - LOG_LEVEL_FUNCTION = 0x001f, + LOG_INFO = 0x00000008, // informational messages (e.g., banners) + LOG_LEVEL_INFO = 0x0000000f, - LOG_PARAM = 0x0020, // parameters to functions - LOG_LEVEL_PARAM = 0x003f, + LOG_FUNCTION = 0x00000010, // function tracing + LOG_LEVEL_FUNCTION = 0x0000001f, - LOG_LOGIC = 0x0040, // control flow tracing within functions - LOG_LEVEL_LOGIC = 0x007f, + LOG_PARAM = 0x00000020, // parameters to functions + LOG_LEVEL_PARAM = 0x0000003f, - LOG_ALL = 0x4000, // print everything - LOG_LEVEL_ALL = 0x7fff + LOG_LOGIC = 0x00000040, // control flow tracing within functions + LOG_LEVEL_LOGIC = 0x0000007f, + + LOG_ALL = 0x7fffffff, // print everything + LOG_LEVEL_ALL = LOG_ALL, + + LOG_PREFIX_ALL = 0x80000000 // prefix all trace prints with function }; #endif +#ifdef NS3_LOG_ENABLE /** * \param name a log component name + * \param level a logging level + * \param decorate whether or not to add function names to all logs * \ingroup logging * * Enable the logging output associated with that log component. * The logging output can be later disabled with a call * to ns3::LogComponentDisable. */ -#ifdef NS3_LOG_ENABLE -void LogComponentEnable (char const *name, enum LogLevel level); -#else -#define LogComponentEnable(a,b) -#endif + void LogComponentEnable (char const *name, enum LogLevel level); +/** + * \param level a logging level + * \param decorate whether or not to add function names to all logs + * \ingroup logging + * + * Enable the logging output for all registered log components. + */ + void LogComponentEnableAll (enum LogLevel level); +#else +#define LogComponentEnable(a,b) +#define LogComponentEnableAll(a) +#endif + +#ifdef NS3_LOG_ENABLE /** * \param name a log component name + * \param level a logging level * \ingroup logging * * Disable the logging output associated with that log component. * The logging output can be later re-enabled with a call * to ns3::LogComponentEnable. */ -#ifdef NS3_LOG_ENABLE void LogComponentDisable (char const *name, enum LogLevel level); + +/** + * \param name a log component name + * \param level a logging level + * \ingroup logging + * + * Disable the logging output associated with that log component. + * The logging output can be later re-enabled with a call + * to ns3::LogComponentEnable. + */ +void LogComponentDisableAll (enum LogLevel level); + #else #define LogComponentDisable(a,b) +#define LogComponentDisableAll(a) #endif /** * \ingroup logging * * Print the list of logging messages available. - * The output of this function can be obtained by setting - * the NS_LOG environment variable to the special value - * 'print-list'. - * - * For example: NS_LOG=print-list */ #ifdef NS3_LOG_ENABLE void LogComponentPrintList (void); @@ -236,12 +263,17 @@ void LogComponentPrintList (void); class LogComponent { public: LogComponent (char const *name); + void EnvVarCheck (char const *name); bool IsEnabled (enum LogLevel level) const; bool IsNoneEnabled (void) const; void Enable (enum LogLevel level); void Disable (enum LogLevel level); + bool Decorate (void) const; + char const *Name (void) const; private: - int32_t m_levels; + int32_t m_levels; + char const *m_name; + bool m_decorate; }; #endif diff --git a/src/devices/csma/csma-ipv4-topology.cc b/src/devices/csma/csma-ipv4-topology.cc index 750860f4d..43e8bcf42 100644 --- a/src/devices/csma/csma-ipv4-topology.cc +++ b/src/devices/csma/csma-ipv4-topology.cc @@ -96,7 +96,8 @@ CsmaIpv4Topology::AddIpv4Address( Ptr node, uint32_t netDeviceNumber, const Ipv4Address address, - const Ipv4Mask mask) + const Ipv4Mask mask, + uint16_t metric) { Ptr nd = node->GetDevice(netDeviceNumber); @@ -105,6 +106,7 @@ CsmaIpv4Topology::AddIpv4Address( ipv4->SetAddress (ifIndex, address); ipv4->SetNetworkMask (ifIndex, mask); + ipv4->SetMetric (ifIndex, metric); ipv4->SetUp (ifIndex); return ifIndex; } diff --git a/src/devices/csma/csma-ipv4-topology.h b/src/devices/csma/csma-ipv4-topology.h index 415ea6257..9cb4ab30a 100644 --- a/src/devices/csma/csma-ipv4-topology.h +++ b/src/devices/csma/csma-ipv4-topology.h @@ -103,6 +103,7 @@ public: * the address. * \param address The Ipv4 Address for the interface. * \param network The network mask for the interface + * \param metric (optional) metric (cost) to assign for routing calculations * * Add an Ipv4Address to the Ipv4 interface associated with the * ndNum CsmaIpv4NetDevices on the provided CsmaIpv4Channel @@ -110,7 +111,8 @@ public: static uint32_t AddIpv4Address(Ptr node, uint32_t netDeviceNumber, const Ipv4Address address, - const Ipv4Mask mask); + const Ipv4Mask mask, + uint16_t metric = 1); /** * \param nd1 Node diff --git a/src/devices/point-to-point/point-to-point-topology.cc b/src/devices/point-to-point/point-to-point-topology.cc index 4c99eaf88..7e0fd4efd 100644 --- a/src/devices/point-to-point/point-to-point-topology.cc +++ b/src/devices/point-to-point/point-to-point-topology.cc @@ -103,6 +103,59 @@ PointToPointTopology::AddIpv4Addresses( } +void +PointToPointTopology::SetIpv4Metric( + Ptr chan, + Ptr n1, Ptr n2, const uint16_t metric) +{ + + // The PointToPoint channel is used to find the relevant NetDevices + NS_ASSERT (chan->GetNDevices () == 2); + Ptr nd1 = chan->GetDevice (0); + Ptr nd2 = chan->GetDevice (1); + // Make sure that nd1 belongs to n1 and nd2 to n2 + if ( (nd1->GetNode ()->GetId () == n2->GetId () ) && + (nd2->GetNode ()->GetId () == n1->GetId () ) ) + { + std::swap(nd1, nd2); + } + NS_ASSERT (nd1->GetNode ()->GetId () == n1->GetId ()); + NS_ASSERT (nd2->GetNode ()->GetId () == n2->GetId ()); + + // The NetDevice ifIndex does not correspond to the + // ifIndex used by Ipv4. Therefore, we have to iterate + // through the NetDevices until we find the Ipv4 ifIndex + // that corresponds to NetDevice nd1 + // Get interface indexes for both nodes corresponding to the right channel + uint32_t index = 0; + bool found = false; + Ptr ip1 = n1->QueryInterface (Ipv4::iid); + for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++) + { + if (ip1 ->GetNetDevice (i) == nd1) + { + index = i; + found = true; + } + } + NS_ASSERT(found); + ip1->SetMetric (index, metric); + + index = 0; + found = false; + Ptr ip2 = n2->QueryInterface (Ipv4::iid); + for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++) + { + if (ip2 ->GetNetDevice (i) == nd2) + { + index = i; + found = true; + } + } + NS_ASSERT(found); + ip2->SetMetric (index, metric); +} + void PointToPointTopology::AddIpv4Routes ( Ptr n1, Ptr n2, Ptr chan) diff --git a/src/devices/point-to-point/point-to-point-topology.h b/src/devices/point-to-point/point-to-point-topology.h index c1f037380..35a452269 100644 --- a/src/devices/point-to-point/point-to-point-topology.h +++ b/src/devices/point-to-point/point-to-point-topology.h @@ -70,6 +70,20 @@ public: Ptr n1, const Ipv4Address& addr1, Ptr n2, const Ipv4Address& addr2); + /** + * \param chan PointToPointChannel to use + * \param n1 Node + * \param n2 Node + * \param metric link metric to assign on Ipv4Link on chan between n1 and n2 + * + * Add a non-unit-cost link metric (bidirectionally) to the Ipv4 + * interfaces associated with the two PointToPointNetDevices on the + * provided PointToPointChannel + */ + static void SetIpv4Metric( + Ptr chan, + Ptr n1, Ptr n2, const uint16_t metric); + /** * \param channel PointToPointChannel to use * \param n1 Node diff --git a/src/internet-node/ipv4-impl.cc b/src/internet-node/ipv4-impl.cc index a67c6a4e8..bff1bfd0b 100644 --- a/src/internet-node/ipv4-impl.cc +++ b/src/internet-node/ipv4-impl.cc @@ -201,6 +201,18 @@ Ipv4Impl::GetAddress (uint32_t i) const return m_ipv4->GetAddress (i); } +void +Ipv4Impl::SetMetric (uint32_t i, uint16_t metric) +{ + m_ipv4->SetMetric (i, metric); +} + +uint16_t +Ipv4Impl::GetMetric (uint32_t i) const +{ + return m_ipv4->GetMetric (i); +} + bool Ipv4Impl::GetIfIndexForDestination (Ipv4Address dest, uint32_t &ifIndex) const { diff --git a/src/internet-node/ipv4-impl.h b/src/internet-node/ipv4-impl.h index 1f4a79f5c..0494c7c0a 100644 --- a/src/internet-node/ipv4-impl.h +++ b/src/internet-node/ipv4-impl.h @@ -88,6 +88,8 @@ public: virtual void SetNetworkMask (uint32_t i, Ipv4Mask mask); virtual Ipv4Mask GetNetworkMask (uint32_t t) const; virtual Ipv4Address GetAddress (uint32_t i) const; + virtual void SetMetric (uint32_t i, uint16_t metric); + virtual uint16_t GetMetric (uint32_t i) const; virtual Ipv4Address GetSourceAddress (Ipv4Address destination) const; virtual bool GetIfIndexForDestination (Ipv4Address dest, uint32_t &ifIndex) const; diff --git a/src/internet-node/ipv4-interface.cc b/src/internet-node/ipv4-interface.cc index e78d75c2d..bcc346394 100644 --- a/src/internet-node/ipv4-interface.cc +++ b/src/internet-node/ipv4-interface.cc @@ -37,7 +37,8 @@ namespace ns3 { */ Ipv4Interface::Ipv4Interface (Ptr nd) : m_netdevice (nd), - m_ifup(false) + m_ifup(false), + m_metric(1) { NS_LOG_FUNCTION; NS_LOG_PARAM ("(" << &nd << ")"); @@ -96,6 +97,21 @@ Ipv4Interface::GetNetworkMask (void) const return m_netmask; } +void +Ipv4Interface::SetMetric (uint16_t metric) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAM ("(" << metric << ")"); + m_metric = metric; +} + +uint16_t +Ipv4Interface::GetMetric (void) const +{ + NS_LOG_FUNCTION; + return m_metric; +} + Ipv4Address Ipv4Interface::GetAddress (void) const { diff --git a/src/internet-node/ipv4-interface.h b/src/internet-node/ipv4-interface.h index 1836aa3b7..66e841746 100644 --- a/src/internet-node/ipv4-interface.h +++ b/src/internet-node/ipv4-interface.h @@ -96,6 +96,14 @@ public: * \returns the ipv4 netmask of this interface */ Ipv4Mask GetNetworkMask (void) const; + /** + * \param configured routing metric (cost) of this interface + */ + void SetMetric (uint16_t); + /** + * \returns configured routing metric (cost) of this interface + */ + uint16_t GetMetric (void) const; /** * \returns the ipv4 address of this interface */ @@ -147,6 +155,7 @@ private: bool m_ifup; Ipv4Address m_address; Ipv4Mask m_netmask; + uint16_t m_metric; }; }; // namespace ns3 diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index 4691b977a..908a7bb99 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -821,6 +821,24 @@ Ipv4L3Protocol::GetAddress (uint32_t i) const return interface->GetAddress (); } +void +Ipv4L3Protocol::SetMetric (uint32_t i, uint16_t metric) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAM ("(" << i << ", " << metric << ")"); + Ptr interface = GetInterface (i); + interface->SetMetric (metric); +} + +uint16_t +Ipv4L3Protocol::GetMetric (uint32_t i) const +{ + NS_LOG_FUNCTION; + NS_LOG_PARAM ("(" << i << ")"); + Ptr interface = GetInterface (i); + return interface->GetMetric (); +} + bool Ipv4L3Protocol::GetIfIndexForDestination ( Ipv4Address destination, uint32_t& ifIndex) const diff --git a/src/internet-node/ipv4-l3-protocol.h b/src/internet-node/ipv4-l3-protocol.h index bea82707e..54dec0678 100644 --- a/src/internet-node/ipv4-l3-protocol.h +++ b/src/internet-node/ipv4-l3-protocol.h @@ -198,6 +198,8 @@ public: void SetNetworkMask (uint32_t i, Ipv4Mask mask); Ipv4Mask GetNetworkMask (uint32_t t) const; Ipv4Address GetAddress (uint32_t i) const; + void SetMetric (uint32_t i, uint16_t metric); + uint16_t GetMetric (uint32_t i) const; bool GetIfIndexForDestination (Ipv4Address destination, uint32_t& ifIndex) const; uint16_t GetMtu (uint32_t i) const; diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index 7e264b4cf..f01dbed51 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -151,16 +151,6 @@ Ipv4Address::Set (char const *address) m_address = AsciiToIpv4Host (address); } -bool -Ipv4Address::IsEqual (Ipv4Address other) const -{ - if (other.m_address == m_address) { - return true; - } else { - return false; - } -} - Ipv4Address Ipv4Address::CombineMask (Ipv4Mask const &mask) const { @@ -296,19 +286,6 @@ Ipv4Address::GetLoopback (void) return loopback; } -bool operator == (Ipv4Address const &a, Ipv4Address const &b) -{ - return a.IsEqual (b); -} -bool operator != (Ipv4Address const &a, Ipv4Address const &b) -{ - return !a.IsEqual (b); -} -bool operator < (Ipv4Address const &addrA, Ipv4Address const &addrB) -{ - return (addrA.GetHostOrder () < addrB.GetHostOrder ()); -} - size_t Ipv4AddressHash::operator()(Ipv4Address const &x) const { return x.GetHostOrder (); diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index 8a7807a49..2f41421af 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -73,7 +73,10 @@ public: * \param other address to which to compare this address * \return True if the addresses are equal. False otherwise. */ - bool IsEqual (Ipv4Address other) const; + bool IsEqual (const Ipv4Address &other) const + { + return m_address == other.m_address; + } /** * \brief Get the host-order 32-bit IP address @@ -142,6 +145,10 @@ private: Address ConvertTo (void) const; static uint8_t GetType (void); uint32_t m_address; + + friend bool operator == (Ipv4Address const &a, Ipv4Address const &b); + friend bool operator != (Ipv4Address const &a, Ipv4Address const &b); + friend bool operator < (Ipv4Address const &addrA, Ipv4Address const &addrB); }; @@ -177,9 +184,19 @@ private: std::ostream& operator<< (std::ostream& os, Ipv4Address const& address); std::ostream& operator<< (std::ostream& os, Ipv4Mask const& mask); -bool operator == (Ipv4Address const &a, Ipv4Address const &b); -bool operator != (Ipv4Address const &a, Ipv4Address const &b); -bool operator < (Ipv4Address const &addrA, Ipv4Address const &addrB); +inline bool operator == (const Ipv4Address &a, const Ipv4Address &b) +{ + return (a.m_address == b.m_address); +} +inline bool operator != (const Ipv4Address &a, const Ipv4Address &b) +{ + return (a.m_address != b.m_address); +} +inline bool operator < (const Ipv4Address &a, const Ipv4Address &b) +{ + return (a.m_address < b.m_address); +} + class Ipv4AddressHash : public std::unary_function { public: diff --git a/src/node/ipv4.h b/src/node/ipv4.h index ba4868a4a..4dba6b2a2 100644 --- a/src/node/ipv4.h +++ b/src/node/ipv4.h @@ -383,6 +383,20 @@ public: */ virtual Ipv4Mask GetNetworkMask (uint32_t i) const = 0; + /** + * \param i index of ipv4 interface + * \param metric routing metric (cost) associated to the underlying + * ipv4 interface + */ + virtual void SetMetric (uint32_t i, uint16_t metric) = 0; + + /** + * \param i index of ipv4 interface + * \returns routing metric (cost) associated to the underlying + * ipv4 interface + */ + virtual uint16_t GetMetric (uint32_t i) const = 0; + /** * \param i index of ipv4 interface * \returns the address associated to the underlying ipv4 interface diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index 88d9def84..ed61f7f5c 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -529,7 +529,8 @@ GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) // Get w_lsa: In case of V is Router-LSA if (v->GetVertexType () == SPFVertex::VertexRouter) { - NS_LOG_LOGIC ("Examining " << v->GetVertexId () << "'s " << + NS_LOG_LOGIC ("Examining link " << i << " of " << + v->GetVertexId () << "'s " << v->GetLSA ()->GetNLinkRecords () << " link records"); // // (a) If this is a link to a stub network, examine the next link in V's LSA. @@ -637,7 +638,8 @@ GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) candidate.Push (w); NS_LOG_LOGIC ("Pushing " << w->GetVertexId () << ", parent vertexId: " << - v->GetVertexId ()); + v->GetVertexId () << ", distance: " << + w->GetDistanceFromRoot ()); } } else if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_CANDIDATE) @@ -688,7 +690,7 @@ GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) } // -// This method is derived from quagga ospf_next_hop_calculation() 16.1.1. +// This method is derived from quagga ospf_nexthop_calculation() 16.1.1. // // Calculate nexthop from root through V (parent) to vertex W (destination) // with given distance from root->W. @@ -784,11 +786,13 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( // w->SetOutgoingInterfaceId ( FindOutgoingInterfaceId (l->GetLinkData ())); - + w->SetDistanceFromRoot (distance); + w->SetParent (v); NS_LOG_LOGIC ("Next hop from " << v->GetVertexId () << " to " << w->GetVertexId () << " goes through next hop " << w->GetNextHop () << - " via outgoing interface " << w->GetOutgoingInterfaceId ()); + " via outgoing interface " << w->GetOutgoingInterfaceId () << + " with distance " << distance); } // end W is a router vertes else { @@ -804,7 +808,8 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( w->SetParent (v); NS_LOG_LOGIC ("Next hop from " << v->GetVertexId () << " to network " << w->GetVertexId () << - " via outgoing interface " << w->GetOutgoingInterfaceId ()); + " via outgoing interface " << w->GetOutgoingInterfaceId () << + " with distance " << distance); return 1; } } // end v is the root @@ -997,6 +1002,7 @@ GlobalRouteManagerImpl::SPFCalculate (Ipv4Address root) m_spfroot= v; v->SetDistanceFromRoot (0); v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE); + NS_LOG_LOGIC ("Starting SPFCalculate for node " << root); for (;;) { diff --git a/src/routing/global-routing/global-router-interface.cc b/src/routing/global-routing/global-router-interface.cc index 2819b7a24..ee49733c1 100644 --- a/src/routing/global-routing/global-router-interface.cc +++ b/src/routing/global-routing/global-router-interface.cc @@ -50,7 +50,7 @@ GlobalRoutingLinkRecord::GlobalRoutingLinkRecord ( LinkType linkType, Ipv4Address linkId, Ipv4Address linkData, - uint32_t metric) + uint16_t metric) : m_linkId (linkId), m_linkData (linkData), @@ -110,7 +110,7 @@ GlobalRoutingLinkRecord::SetLinkType ( m_linkType = linkType; } - uint32_t + uint16_t GlobalRoutingLinkRecord::GetMetric (void) const { NS_LOG_FUNCTION; @@ -118,7 +118,7 @@ GlobalRoutingLinkRecord::GetMetric (void) const } void -GlobalRoutingLinkRecord::SetMetric (uint32_t metric) +GlobalRoutingLinkRecord::SetMetric (uint16_t metric) { NS_LOG_FUNCTION; m_metric = metric; @@ -202,6 +202,7 @@ GlobalRoutingLSA::CopyLinkRecords (const GlobalRoutingLSA& lsa) pDst->SetLinkType (pSrc->GetLinkType ()); pDst->SetLinkId (pSrc->GetLinkId ()); pDst->SetLinkData (pSrc->GetLinkData ()); + pDst->SetMetric (pSrc->GetMetric ()); m_linkRecords.push_back(pDst); pDst = 0; @@ -397,6 +398,7 @@ GlobalRoutingLSA::Print (std::ostream &os) const os << "----------" << std::endl; os << "m_linkId = " << p->GetLinkId () << std::endl; os << "m_linkData = " << p->GetLinkData () << std::endl; + os << "m_metric = " << p->GetMetric () << std::endl; } } else if (m_lsType == GlobalRoutingLSA::NetworkLSA) @@ -547,6 +549,7 @@ GlobalRouter::DiscoverLSAs (void) Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal); Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); NS_LOG_LOGIC ("Working with local address " << addrLocal); + uint16_t metricLocal = ipv4Local->GetMetric (ifIndexLocal); // // Now, we're going to walk over to the remote net device on the other end of // the point-to-point channel we now know we have. This is where our adjacent @@ -566,8 +569,7 @@ GlobalRouter::DiscoverLSAs (void) Ipv4Address maskLocalAddr; maskLocalAddr.Set(maskLocal.GetHostOrder ()); plr->SetLinkData (maskLocalAddr); - // Cost is interface's configured output cost (NOTYET) - plr->SetMetric (1); + plr->SetMetric (metricLocal); pLSA->AddLinkRecord(plr); plr = 0; continue; @@ -589,8 +591,7 @@ GlobalRouter::DiscoverLSAs (void) plr->SetLinkId (desigRtr); // Link Data is router's own IP address plr->SetLinkData (addrLocal); - // Cost is interface's configured output cost (NOTYET) - plr->SetMetric (1); + plr->SetMetric (metricLocal); pLSA->AddLinkRecord (plr); plr = 0; continue; @@ -613,6 +614,7 @@ GlobalRouter::DiscoverLSAs (void) Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal); Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); NS_LOG_LOGIC ("Working with local address " << addrLocal); + uint16_t metricLocal = ipv4Local->GetMetric (ifIndexLocal); // // Now, we're going to walk over to the remote net device on the other end of // the point-to-point channel we now know we have. This is where our adjacent @@ -659,6 +661,7 @@ GlobalRouter::DiscoverLSAs (void) plr->SetLinkType (GlobalRoutingLinkRecord::PointToPoint); plr->SetLinkId (rtrIdRemote); plr->SetLinkData (addrLocal); + plr->SetMetric (metricLocal); pLSA->AddLinkRecord (plr); plr = 0; @@ -666,6 +669,7 @@ GlobalRouter::DiscoverLSAs (void) plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork); plr->SetLinkId (addrRemote); plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder())); // Frown + plr->SetMetric (metricLocal); pLSA->AddLinkRecord (plr); plr = 0; } diff --git a/src/routing/global-routing/global-router-interface.h b/src/routing/global-routing/global-router-interface.h index cf3f94166..87626700b 100644 --- a/src/routing/global-routing/global-router-interface.h +++ b/src/routing/global-routing/global-router-interface.h @@ -82,7 +82,7 @@ public: LinkType linkType, Ipv4Address linkId, Ipv4Address linkData, - uint32_t metric); + uint16_t metric); /** * @brief Destroy a Global Routing Link Record. @@ -176,7 +176,7 @@ public: * * @returns The metric field of the Global Routing Link Record. */ - uint32_t GetMetric(void) const; + uint16_t GetMetric(void) const; /** * @brief Set the Metric Data field of the Global Routing Link Record. @@ -189,7 +189,7 @@ public: * * @param metric The new metric for the current Global Routing Link Record. */ - void SetMetric(uint32_t metric); + void SetMetric(uint16_t metric); private: /** @@ -230,7 +230,7 @@ private: * of two hops relate to the cost of sending a packet); rather you should * use something like delay. */ - uint32_t m_metric; + uint16_t m_metric; }; /** diff --git a/src/simulator/event-garbage-collector.cc b/src/routing/olsr/event-garbage-collector.cc similarity index 89% rename from src/simulator/event-garbage-collector.cc rename to src/routing/olsr/event-garbage-collector.cc index 776f2a999..212ad7d69 100644 --- a/src/simulator/event-garbage-collector.cc +++ b/src/routing/olsr/event-garbage-collector.cc @@ -1,7 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2007 INESC Porto - * All rights reserved. * * 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 @@ -34,17 +33,11 @@ EventGarbageCollector::EventGarbageCollector () : void EventGarbageCollector::Track (EventId event) { - m_events.push_back (event); + m_events.insert (event); if (m_events.size () >= m_nextCleanupSize) Cleanup (); } -inline bool -EventExpiredPredicate (const EventId &event) -{ - return event.IsExpired (); -} - void EventGarbageCollector::Grow () { @@ -64,7 +57,15 @@ EventGarbageCollector::Shrink () void EventGarbageCollector::Cleanup () { - m_events.remove_if (EventExpiredPredicate); + for (EventList::iterator iter = m_events.begin (); iter != m_events.end ();) + { + if ((*iter).IsExpired ()) + { + m_events.erase (iter++); + } + else + break; // EventIds are sorted by timestamp => further events are not expired for sure + } // If after cleanup we are still over the limit, increase the limit. if (m_events.size () >= m_nextCleanupSize) @@ -76,7 +77,7 @@ EventGarbageCollector::Cleanup () EventGarbageCollector::~EventGarbageCollector () { - for (std::list::iterator event = m_events.begin (); + for (EventList::iterator event = m_events.begin (); event != m_events.end (); event++) { Simulator::Cancel (*event); diff --git a/src/simulator/event-garbage-collector.h b/src/routing/olsr/event-garbage-collector.h similarity index 81% rename from src/simulator/event-garbage-collector.h rename to src/routing/olsr/event-garbage-collector.h index b03b86322..674de1a42 100644 --- a/src/simulator/event-garbage-collector.h +++ b/src/routing/olsr/event-garbage-collector.h @@ -1,7 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2007 INESC Porto - * All rights reserved. * * 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 @@ -21,9 +20,9 @@ #ifndef EVENT_GARBAGE_COLLECTOR_H #define EVENT_GARBAGE_COLLECTOR_H -#include -#include "event-id.h" -#include "simulator.h" +#include +#include "ns3/event-id.h" +#include "ns3/simulator.h" namespace ns3 { @@ -49,8 +48,18 @@ public: private: - std::list::size_type m_nextCleanupSize; - std::list m_events; + struct EventIdLessThanTs + { + bool operator () (const EventId &a, const EventId &b) const + { + return (a.GetTs () < b.GetTs ()); + } + }; + + typedef std::multiset EventList; + + EventList::size_type m_nextCleanupSize; + EventList m_events; void Cleanup (); void Grow (); diff --git a/src/routing/olsr/olsr-agent-impl.cc b/src/routing/olsr/olsr-agent-impl.cc new file mode 100644 index 000000000..fb684bc9b --- /dev/null +++ b/src/routing/olsr/olsr-agent-impl.cc @@ -0,0 +1,2110 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2004 Francisco J. Ros + * Copyright (c) 2007 INESC Porto + * + * 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: Francisco J. Ros + * Gustavo J. A. M. Carneiro + */ + + +/// +/// \file OLSR.cc +/// \brief Implementation of OLSR agent and related classes. +/// +/// This is the main file of this software because %OLSR's behaviour is +/// implemented here. +/// + +#include "olsr-agent-impl.h" +#include "ns3/socket-factory.h" +#include "ns3/udp.h" +#include "ns3/internet-node.h" +#include "ns3/simulator.h" +#include "ns3/debug.h" +#include "ns3/random-variable.h" +#include "ns3/inet-socket-address.h" + + + +/********** Useful macros **********/ + +/// +/// \brief Gets the delay between a given time and the current time. +/// +/// If given time is previous to the current one, then this macro returns +/// a number close to 0. This is used for scheduling events at a certain moment. +/// +#define DELAY(time) (((time) < (Simulator::Now ())) ? Seconds (0.000001) : \ + (time - Simulator::Now () + Seconds (0.000001))) + + + +/********** Intervals **********/ + +/// HELLO messages emission interval. +#define OLSR_HELLO_INTERVAL Seconds (2) + +/// TC messages emission interval. +#define OLSR_TC_INTERVAL Seconds (5) + +/// MID messages emission interval. +#define OLSR_MID_INTERVAL OLSR_TC_INTERVAL + +/// +/// \brief Period at which a node must cite every link and every neighbor. +/// +/// We only use this value in order to define OLSR_NEIGHB_HOLD_TIME. +/// +#define OLSR_REFRESH_INTERVAL Seconds (2) + + +/********** Holding times **********/ + +/// Neighbor holding time. +#define OLSR_NEIGHB_HOLD_TIME (Scalar (3) * OLSR_REFRESH_INTERVAL) +/// Top holding time. +#define OLSR_TOP_HOLD_TIME (Scalar (3) * OLSR_TC_INTERVAL) +/// Dup holding time. +#define OLSR_DUP_HOLD_TIME Seconds (30) +/// MID holding time. +#define OLSR_MID_HOLD_TIME (Scalar (3) * OLSR_MID_INTERVAL) + + +/********** Link types **********/ + +/// Unspecified link type. +#define OLSR_UNSPEC_LINK 0 +/// Asymmetric link type. +#define OLSR_ASYM_LINK 1 +/// Symmetric link type. +#define OLSR_SYM_LINK 2 +/// Lost link type. +#define OLSR_LOST_LINK 3 + +/********** Neighbor types **********/ + +/// Not neighbor type. +#define OLSR_NOT_NEIGH 0 +/// Symmetric neighbor type. +#define OLSR_SYM_NEIGH 1 +/// Asymmetric neighbor type. +#define OLSR_MPR_NEIGH 2 + + +/********** Willingness **********/ + +/// Willingness for forwarding packets from other nodes: never. +#define OLSR_WILL_NEVER 0 +/// Willingness for forwarding packets from other nodes: low. +#define OLSR_WILL_LOW 1 +/// Willingness for forwarding packets from other nodes: medium. +#define OLSR_WILL_DEFAULT 3 +/// Willingness for forwarding packets from other nodes: high. +#define OLSR_WILL_HIGH 6 +/// Willingness for forwarding packets from other nodes: always. +#define OLSR_WILL_ALWAYS 7 + + +/********** Miscellaneous constants **********/ + +/// Maximum allowed jitter. +#define OLSR_MAXJITTER (OLSR_HELLO_INTERVAL.GetSeconds () / 4) +/// Maximum allowed sequence number. +#define OLSR_MAX_SEQ_NUM 65535 +/// Random number between [0-OLSR_MAXJITTER] used to jitter OLSR packet transmission. +#define JITTER (Seconds (UniformVariable::GetSingleValue (0, OLSR_MAXJITTER))) + + +#define OLSR_PORT_NUMBER 698 +/// Maximum number of messages per packet. +#define OLSR_MAX_MSGS 64 + +/// Maximum number of hellos per message (4 possible link types * 3 possible nb types). +#define OLSR_MAX_HELLOS 12 + +/// Maximum number of addresses advertised on a message. +#define OLSR_MAX_ADDRS 64 + + +namespace ns3 { + +NS_DEBUG_COMPONENT_DEFINE ("OlsrAgent"); + + +/********** OLSR class **********/ + + +OlsrAgentImpl::OlsrAgentImpl (Ptr node) + : + m_useL2Notifications (false), + m_helloTimer (Timer::CANCEL_ON_DESTROY), + m_tcTimer (Timer::CANCEL_ON_DESTROY), + m_midTimer (Timer::CANCEL_ON_DESTROY) +{ + m_helloTimer.SetFunction (&OlsrAgentImpl::HelloTimerExpire, this); + m_tcTimer.SetFunction (&OlsrAgentImpl::TcTimerExpire, this); + m_midTimer.SetFunction (&OlsrAgentImpl::MidTimerExpire, this); + m_queuedMessagesTimer.SetFunction (&OlsrAgentImpl::SendQueuedMessages, this); + + + SetInterfaceId (OlsrAgentImpl::iid); + + // Aggregate with the Node, so that OLSR dies when the node is destroyed. + node->AddInterface (this); + + m_packetSequenceNumber = OLSR_MAX_SEQ_NUM; + m_messageSequenceNumber = OLSR_MAX_SEQ_NUM; + m_ansn = OLSR_MAX_SEQ_NUM; + + m_helloInterval = OLSR_HELLO_INTERVAL; + m_tcInterval = OLSR_TC_INTERVAL; + m_midInterval = OLSR_MID_INTERVAL; + m_willingness = OLSR_WILL_ALWAYS; + + m_linkTupleTimerFirstTime = true; + + m_ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT (m_ipv4); + + Ptr socketFactory = node->QueryInterface (Udp::iid); + + m_receiveSocket = socketFactory->CreateSocket (); + if (m_receiveSocket->Bind (InetSocketAddress (OLSR_PORT_NUMBER))) + NS_ASSERT_MSG (false, "Failed to bind() OLSR receive socket"); + + m_sendSocket = socketFactory->CreateSocket (); + m_sendSocket->Connect (InetSocketAddress (Ipv4Address (0xffffffff), OLSR_PORT_NUMBER)); + +} + +void OlsrAgentImpl::DoDispose () +{ + m_ipv4 = 0; + if (m_receiveSocket) + { + m_receiveSocket->Dispose (); + m_receiveSocket = 0; + } + if (m_sendSocket) + { + m_sendSocket->Dispose (); + m_sendSocket = 0; + } + if (m_routingTable) + { + m_routingTable->Dispose (); + m_routingTable = 0; + } + + Object::DoDispose (); +} + +void OlsrAgentImpl::Start () +{ + if (m_mainAddress == Ipv4Address ()) + { + Ipv4Address loopback ("127.0.0.1"); + for (uint32_t i = 0; i < m_ipv4->GetNInterfaces (); i++) + { + Ipv4Address addr = m_ipv4->GetAddress (i); + if (addr != loopback) + { + m_mainAddress = addr; + break; + } + } + + NS_ASSERT (m_mainAddress != Ipv4Address ()); + } + + NS_DEBUG ("Starting OLSR on node " << m_mainAddress); + + m_routingTable = Create (m_ipv4, m_mainAddress); + // Add OLSR as routing protocol, with slightly lower priority than + // static routing. + m_ipv4->AddRoutingProtocol (m_routingTable, -10); + + if (m_sendSocket->Bind (InetSocketAddress (m_mainAddress, OLSR_PORT_NUMBER))) + NS_ASSERT_MSG (false, "Failed to bind() OLSR send socket"); + m_receiveSocket->SetRecvCallback (MakeCallback (&OlsrAgentImpl::RecvOlsr, this)); + + HelloTimerExpire (); + TcTimerExpire (); + MidTimerExpire (); + + NS_DEBUG ("OLSR on node " << m_mainAddress << " started"); +} + +void OlsrAgentImpl::SetMainInterface (uint32_t interface) +{ + m_mainAddress = m_ipv4->GetAddress (interface); +} + + +// +// \brief Processes an incoming %OLSR packet following RFC 3626 specification. +void +OlsrAgentImpl::RecvOlsr (Ptr socket, + const Packet &receivedPacket, + const Address &sourceAddress) +{ + NS_DEBUG ("OLSR node " << m_mainAddress << " received a OLSR packet"); + InetSocketAddress inetSourceAddr = InetSocketAddress::ConvertFrom (sourceAddress); + + // All routing messages are sent from and to port RT_PORT, + // so we check it. + NS_ASSERT (inetSourceAddr.GetPort () == OLSR_PORT_NUMBER); + + Packet packet = receivedPacket; + + OlsrPacketHeader olsrPacketHeader; + packet.RemoveHeader (olsrPacketHeader); + NS_ASSERT (olsrPacketHeader.GetPacketLength () >= olsrPacketHeader.GetSerializedSize ()); + uint32_t sizeLeft = olsrPacketHeader.GetPacketLength () - olsrPacketHeader.GetSerializedSize (); + + while (sizeLeft) + { + OlsrMessageHeader messageHeader; + if (packet.RemoveHeader (messageHeader) == 0) + NS_ASSERT (false); + + sizeLeft -= messageHeader.GetSerializedSize (); + + NS_DEBUG ("Olsr Msg received with type " + << std::dec << int (messageHeader.GetMessageType ()) + << " TTL=" << int (messageHeader.GetTimeToLive ()) + << " origAddr=" << messageHeader.GetOriginatorAddress ()); + + // If ttl is less than or equal to zero, or + // the receiver is the same as the originator, + // the message must be silently dropped + if (messageHeader.GetTimeToLive () == 0 + || messageHeader.GetOriginatorAddress () == m_mainAddress) + { + packet.RemoveAtStart (messageHeader.GetSerializedSize () + - messageHeader.GetSerializedSize ()); + continue; + } + + // If the message has been processed it must not be processed again + bool do_forwarding = true; + DuplicateTuple *duplicated = m_state.FindDuplicateTuple + (messageHeader.GetOriginatorAddress (), + messageHeader.GetMessageSequenceNumber ()); + + if (duplicated == NULL) + { + switch (messageHeader.GetMessageType ()) + { + case OlsrMessageHeader::HELLO_MESSAGE: + NS_DEBUG ("OLSR node received HELLO message of size " << messageHeader.GetSerializedSize ()); + ProcessHello (messageHeader, m_mainAddress, inetSourceAddr.GetIpv4 ()); + break; + + case OlsrMessageHeader::TC_MESSAGE: + NS_DEBUG ("OLSR node received TC message of size " << messageHeader.GetSerializedSize ()); + ProcessTc (messageHeader, inetSourceAddr.GetIpv4 ()); + break; + + case OlsrMessageHeader::MID_MESSAGE: + NS_DEBUG ("OLSR node received MID message of size " << messageHeader.GetSerializedSize ()); + ProcessMid (messageHeader, inetSourceAddr.GetIpv4 ()); + break; + + default: + NS_DEBUG ("OLSR message type " << + int (messageHeader.GetMessageType ()) << + " not implemented"); + } + } + else + { + NS_DEBUG ("OLSR message is duplicated, not reading it."); + + // If the message has been considered for forwarding, it should + // not be retransmitted again + for (std::vector::const_iterator it = duplicated->ifaceList.begin (); + it != duplicated->ifaceList.end(); it++) + { + if (*it == m_mainAddress) + { + do_forwarding = false; + break; + } + } + } + + if (do_forwarding) + { + // HELLO messages are never forwarded. + // TC and MID messages are forwarded using the default algorithm. + // Remaining messages are also forwarded using the default algorithm. + if (messageHeader.GetMessageType () != OlsrMessageHeader::HELLO_MESSAGE) + ForwardDefault (messageHeader, duplicated, + m_mainAddress, inetSourceAddr.GetIpv4 ()); + } + + } + + // After processing all OLSR messages, we must recompute the routing table + RoutingTableComputation (); +} + +/// +/// \brief This auxiliary function (defined in RFC 3626) is used for calculating the MPR Set. +/// +/// \param tuple the neighbor tuple which has the main address of the node we are going to calculate its degree to. +/// \return the degree of the node. +/// +int +OlsrAgentImpl::Degree (NeighborTuple const &tuple) +{ + int degree = 0; + for (TwoHopNeighborSet::const_iterator it = m_state.GetTwoHopNeighbors ().begin (); + it != m_state.GetTwoHopNeighbors ().end (); it++) + { + TwoHopNeighborTuple const &nb2hop_tuple = *it; + if (nb2hop_tuple.neighborMainAddr == tuple.neighborMainAddr) + { + NeighborTuple *nb_tuple = + m_state.FindNeighborTuple (nb2hop_tuple.neighborMainAddr); + if (nb_tuple == NULL) + degree++; + } + } + return degree; +} + +/// +/// \brief Computates MPR set of a node following RFC 3626 hints. +/// +void +OlsrAgentImpl::MprComputation() +{ + // MPR computation should be done for each interface. See section 8.3.1 + // (RFC 3626) for details. + + m_state.ClearMprSet (); + + // N is the subset of neighbors of the node, which are + // neighbor "of the interface I" + NeighborSet N; + for (NeighborSet::const_iterator it = m_state.GetNeighbors ().begin(); + it != m_state.GetNeighbors ().end (); it++) + { + if ((*it).status == NeighborTuple::STATUS_SYM) // I think that we need this check + N.push_back (*it); + } + + // N2 is the set of 2-hop neighbors reachable from "the interface + // I", excluding: + // (i) the nodes only reachable by members of N with willingness WILL_NEVER + // (ii) the node performing the computation + // (iii) all the symmetric neighbors: the nodes for which there exists a symmetric + // link to this node on some interface. + TwoHopNeighborSet N2; + for (TwoHopNeighborSet::const_iterator it = m_state.GetTwoHopNeighbors ().begin (); + it != m_state.GetTwoHopNeighbors ().end (); it++) + { + TwoHopNeighborTuple const &twoHopNeigh = *it; + bool ok = true; + NeighborTuple *nb_tuple = m_state.FindSymNeighborTuple (twoHopNeigh.neighborMainAddr); + if (nb_tuple == NULL) + { + ok = false; + } + else + { + nb_tuple = m_state.FindNeighborTuple (twoHopNeigh.neighborMainAddr, OLSR_WILL_NEVER); + if (nb_tuple != NULL) + { + ok = false; + } + else + { + nb_tuple = m_state.FindSymNeighborTuple (twoHopNeigh.neighborMainAddr); + if (nb_tuple != NULL) + ok = false; + } + } + + if (ok) + N2.push_back (twoHopNeigh); + } + + // 1. Start with an MPR set made of all members of N with + // N_willingness equal to WILL_ALWAYS + for (NeighborSet::const_iterator it = N.begin (); it != N.end (); it++) + { + NeighborTuple const &nb_tuple = *it; + if (nb_tuple.willingness == OLSR_WILL_ALWAYS) + m_state.InsertMprAddress (nb_tuple.neighborMainAddr); + } + + // 2. Calculate D(y), where y is a member of N, for all nodes in N. + // We will do this later. + // FIXME + + // 3. Add to the MPR set those nodes in N, which are the *only* + // nodes to provide reachability to a node in N2. Remove the + // nodes from N2 which are now covered by a node in the MPR set. + MprSet foundset; + std::set deleted_addrs; + for (TwoHopNeighborSet::iterator it = N2.begin (); it != N2.end (); it++) + { + TwoHopNeighborTuple const &nb2hop_tuple1 = *it; + + MprSet::const_iterator pos = foundset.find (nb2hop_tuple1.twoHopNeighborAddr); + if (pos != foundset.end ()) + continue; + + bool found = false; + for (NeighborSet::const_iterator it2 = N.begin (); + it2 != N.end (); it2++) + { + if ((*it2).neighborMainAddr == nb2hop_tuple1.neighborMainAddr) { + found = true; + break; + } + } + if (!found) + continue; + + found = false; + for (TwoHopNeighborSet::const_iterator it2 = it + 1; + it2 != N2.end (); it2++) + { + TwoHopNeighborTuple const &nb2hop_tuple2 = *it2; + if (nb2hop_tuple1.twoHopNeighborAddr == nb2hop_tuple2.twoHopNeighborAddr) + { + foundset.insert (nb2hop_tuple1.twoHopNeighborAddr); + found = true; + break; + } + } + if (!found) + { + m_state.InsertMprAddress (nb2hop_tuple1.neighborMainAddr); + + for (TwoHopNeighborSet::iterator it2 = it + 1; it2 != N2.end (); it2++) + { + TwoHopNeighborTuple const &nb2hop_tuple2 = *it2; + if (nb2hop_tuple1.neighborMainAddr == nb2hop_tuple2.neighborMainAddr) + { + deleted_addrs.insert (nb2hop_tuple2.twoHopNeighborAddr); + it2 = N2.erase (it2); + it2--; + } + } + it = N2.erase (it); + it--; + } + + for (std::set::iterator it2 = deleted_addrs.begin (); + it2 != deleted_addrs.end (); + it2++) + { + for (TwoHopNeighborSet::iterator it3 = N2.begin (); + it3 != N2.end (); + it3++) + { + if ((*it3).twoHopNeighborAddr == *it2) + { + it3 = N2.erase (it3); + it3--; + // I have to reset the external iterator because it + // may have been invalidated by the latter deletion + it = N2.begin (); + it--; + } + } + } + deleted_addrs.clear (); + } + + // 4. While there exist nodes in N2 which are not covered by at + // least one node in the MPR set: + while (N2.begin () != N2.end ()) + { + // 4.1. For each node in N, calculate the reachability, i.e., the + // number of nodes in N2 which are not yet covered by at + // least one node in the MPR set, and which are reachable + // through this 1-hop neighbor + std::map > reachability; + std::set rs; + for (NeighborSet::iterator it = N.begin(); it != N.end(); it++) + { + NeighborTuple const &nb_tuple = *it; + int r = 0; + for (TwoHopNeighborSet::iterator it2 = N2.begin (); it2 != N2.end (); it2++) + { + TwoHopNeighborTuple const &nb2hop_tuple = *it2; + if (nb_tuple.neighborMainAddr == nb2hop_tuple.neighborMainAddr) + r++; + } + rs.insert (r); + reachability[r].push_back (&nb_tuple); + } + + // 4.2. Select as a MPR the node with highest N_willingness among + // the nodes in N with non-zero reachability. In case of + // multiple choice select the node which provides + // reachability to the maximum number of nodes in N2. In + // case of multiple nodes providing the same amount of + // reachability, select the node as MPR whose D(y) is + // greater. Remove the nodes from N2 which are now covered + // by a node in the MPR set. + NeighborTuple const *max = NULL; + int max_r = 0; + for (std::set::iterator it = rs.begin (); it != rs.end (); it++) + { + int r = *it; + if (r > 0) + { + for (std::vector::iterator it2 = reachability[r].begin (); + it2 != reachability[r].end (); + it2++) + { + const NeighborTuple *nb_tuple = *it2; + if (max == NULL || nb_tuple->willingness > max->willingness) + { + max = nb_tuple; + max_r = r; + } + else if (nb_tuple->willingness == max->willingness) + { + if (r > max_r) + { + max = nb_tuple; + max_r = r; + } + else if (r == max_r) + { + if (Degree (*nb_tuple) > Degree (*max)) + { + max = nb_tuple; + max_r = r; + } + } + } + } + } + } + + if (max != NULL) + { + m_state.InsertMprAddress (max->neighborMainAddr); + std::set nb2hop_addrs; + for (TwoHopNeighborSet::iterator it = N2.begin (); + it != N2.end (); it++) + { + TwoHopNeighborTuple const &nb2hop_tuple = *it; + if (nb2hop_tuple.neighborMainAddr == max->neighborMainAddr) + { + nb2hop_addrs.insert (nb2hop_tuple.twoHopNeighborAddr); + it = N2.erase (it); + it--; + } + } + for (TwoHopNeighborSet::iterator it = N2.begin (); + it != N2.end (); it++) + { + TwoHopNeighborTuple const &nb2hop_tuple = *it; + std::set::iterator it2 = + nb2hop_addrs.find (nb2hop_tuple.twoHopNeighborAddr); + if (it2 != nb2hop_addrs.end ()) + { + it = N2.erase (it); + it--; + } + } + } + } +} + +/// +/// \brief Gets the main address associated with a given interface address. +/// +/// \param iface_addr the interface address. +/// \return the corresponding main address. +/// +Ipv4Address +OlsrAgentImpl::GetMainAddress (Ipv4Address iface_addr) +{ + IfaceAssocTuple *tuple = + m_state.FindIfaceAssocTuple (iface_addr); + + if (tuple != NULL) + return tuple->mainAddr; + else + return iface_addr; +} + +/// +/// \brief Creates the routing table of the node following RFC 3626 hints. +/// +void +OlsrAgentImpl::RoutingTableComputation () +{ + // 1. All the entries from the routing table are removed. + m_routingTable->Clear (); + + // 2. The new routing entries are added starting with the + // symmetric neighbors (h=1) as the destination nodes. + for (NeighborSet::const_iterator it = m_state.GetNeighbors ().begin (); + it != m_state.GetNeighbors ().end(); it++) + { + NeighborTuple const &nb_tuple = *it; + if (nb_tuple.status == NeighborTuple::STATUS_SYM) + { + bool nb_main_addr = false; + const LinkTuple *lt = NULL; + for (LinkSet::const_iterator it2 = m_state.GetLinks ().begin(); + it2 != m_state.GetLinks ().end(); it2++) + { + LinkTuple const &link_tuple = *it2; + if ((GetMainAddress (link_tuple.neighborIfaceAddr) + == nb_tuple.neighborMainAddr) + && link_tuple.time >= Simulator::Now ()) + { + lt = &link_tuple; + m_routingTable->AddEntry (link_tuple.neighborIfaceAddr, + link_tuple.neighborIfaceAddr, + link_tuple.localIfaceAddr, + 1); + if (link_tuple.neighborIfaceAddr + == nb_tuple.neighborMainAddr) + nb_main_addr = true; + } + } + if (!nb_main_addr && lt != NULL) + { + m_routingTable->AddEntry(nb_tuple.neighborMainAddr, + lt->neighborIfaceAddr, + lt->localIfaceAddr, + 1); + } + } + } + + // N2 is the set of 2-hop neighbors reachable from this node, excluding: + // (i) the nodes only reachable by members of N with willingness WILL_NEVER + // (ii) the node performing the computation + // (iii) all the symmetric neighbors: the nodes for which there exists a symmetric + // link to this node on some interface. + for (TwoHopNeighborSet::const_iterator it = m_state.GetTwoHopNeighbors ().begin (); + it != m_state.GetTwoHopNeighbors ().end (); it++) + { + TwoHopNeighborTuple const &nb2hop_tuple = *it; + bool ok = true; + NeighborTuple *nb_tuple = m_state.FindSymNeighborTuple + (nb2hop_tuple.neighborMainAddr); + if (nb_tuple == NULL) + ok = false; + else + { + nb_tuple = m_state.FindNeighborTuple (nb2hop_tuple.neighborMainAddr, + OLSR_WILL_NEVER); + if (nb_tuple != NULL) + ok = false; + else + { + nb_tuple = m_state.FindSymNeighborTuple (nb2hop_tuple.twoHopNeighborAddr); + + if (nb_tuple != NULL) + ok = false; + } + } + + // 3. For each node in N2 create a new entry in the routing table + if (ok) + { + RoutingTableEntry entry; + bool foundEntry = m_routingTable->Lookup (nb2hop_tuple.neighborMainAddr, entry); + if (!foundEntry) + NS_FATAL_ERROR ("m_routingTable->Lookup failure"); + + m_routingTable->AddEntry (nb2hop_tuple.twoHopNeighborAddr, + entry.nextAddr, + entry.interface, + 2); + } + } + + for (uint32_t h = 2; ; h++) + { + bool added = false; + + // 4.1. For each topology entry in the topology table, if its + // T_dest_addr does not correspond to R_dest_addr of any + // route entry in the routing table AND its T_last_addr + // corresponds to R_dest_addr of a route entry whose R_dist + // is equal to h, then a new route entry MUST be recorded in + // the routing table (if it does not already exist) + for (TopologySet::const_iterator it = m_state.GetTopologySet ().begin (); + it != m_state.GetTopologySet ().end (); + it++) + { + TopologyTuple const &topology_tuple = *it; + RoutingTableEntry entry1, entry2; + bool have_entry1 = m_routingTable->Lookup (topology_tuple.destAddr, entry1); + bool have_entry2 = m_routingTable->Lookup (topology_tuple.lastAddr, entry2); + if (!have_entry1 && have_entry2 && entry2.distance == h) + { + m_routingTable->AddEntry (topology_tuple.destAddr, + entry2.nextAddr, + entry2.interface, + h + 1); + added = true; + } + } + + // 5. For each entry in the multiple interface association base + // where there exists a routing entry such that: + // R_dest_addr == I_main_addr (of the multiple interface association entry) + // AND there is no routing entry such that: + // R_dest_addr == I_iface_addr + // then a route entry is created in the routing table + for (IfaceAssocSet::const_iterator it = m_state.GetIfaceAssocSet ().begin (); + it != m_state.GetIfaceAssocSet ().end (); + it++) + { + IfaceAssocTuple const &tuple = *it; + RoutingTableEntry entry1, entry2; + bool have_entry1 = m_routingTable->Lookup (tuple.mainAddr, entry1); + bool have_entry2 = m_routingTable->Lookup (tuple.ifaceAddr, entry2); + if (have_entry1 && !have_entry2) + { + m_routingTable->AddEntry (tuple.ifaceAddr, + entry1.nextAddr, + entry1.interface, + entry1.distance); + added = true; + } + } + + if (!added) + break; + } +} + + +/// +/// \brief Processes a HELLO message following RFC 3626 specification. +/// +/// Link sensing and population of the Neighbor Set, 2-hop Neighbor Set and MPR +/// Selector Set are performed. +/// +/// \param msg the %OLSR message which contains the HELLO message. +/// \param receiver_iface the address of the interface where the message was received from. +/// \param sender_iface the address of the interface where the message was sent from. +/// +void +OlsrAgentImpl::ProcessHello (const OlsrMessageHeader &msg, + const Ipv4Address &receiverIface, + const Ipv4Address &senderIface) +{ + const OlsrMessageHeader::Hello &hello = msg.GetHello (); + LinkSensing (msg, hello, receiverIface, senderIface); + PopulateNeighborSet (msg, hello); + PopulateTwoHopNeighborSet (msg, hello); + MprComputation (); + PopulateMprSelectorSet (msg, hello); +} + +/// +/// \brief Processes a TC message following RFC 3626 specification. +/// +/// The Topology Set is updated (if needed) with the information of +/// the received TC message. +/// +/// \param msg the %OLSR message which contains the TC message. +/// \param sender_iface the address of the interface where the message was sent from. +/// +void +OlsrAgentImpl::ProcessTc (const OlsrMessageHeader &msg, + const Ipv4Address &senderIface) +{ + const OlsrMessageHeader::Tc &tc = msg.GetTc (); + Time now = Simulator::Now (); + + // 1. If the sender interface of this message is not in the symmetric + // 1-hop neighborhood of this node, the message MUST be discarded. + LinkTuple *link_tuple = m_state.FindSymLinkTuple (senderIface, now); + if (link_tuple == NULL) + return; + + // 2. If there exist some tuple in the topology set where: + // T_last_addr == originator address AND + // T_seq > ANSN, + // then further processing of this TC message MUST NOT be + // performed. + TopologyTuple *topologyTuple = + m_state.FindNewerTopologyTuple (msg.GetOriginatorAddress (), tc.ansn); + if (topologyTuple != NULL) + return; + + // 3. All tuples in the topology set where: + // T_last_addr == originator address AND + // T_seq < ANSN + // MUST be removed from the topology set. + m_state.EraseOlderTopologyTuples (msg.GetOriginatorAddress (), tc.ansn); + + // 4. For each of the advertised neighbor main address received in + // the TC message: + for (std::vector::const_iterator i = tc.neighborAddresses.begin (); + i != tc.neighborAddresses.end (); i++) + { + const Ipv4Address &addr = *i; + // 4.1. If there exist some tuple in the topology set where: + // T_dest_addr == advertised neighbor main address, AND + // T_last_addr == originator address, + // then the holding time of that tuple MUST be set to: + // T_time = current time + validity time. + TopologyTuple *topologyTuple = + m_state.FindTopologyTuple (addr, msg.GetOriginatorAddress ()); + + if (topologyTuple != NULL) + { + topologyTuple->expirationTime = now + msg.GetVTime (); + } + else + { + // 4.2. Otherwise, a new tuple MUST be recorded in the topology + // set where: + // T_dest_addr = advertised neighbor main address, + // T_last_addr = originator address, + // T_seq = ANSN, + // T_time = current time + validity time. + TopologyTuple topologyTuple;; + topologyTuple.destAddr = addr; + topologyTuple.lastAddr = msg.GetOriginatorAddress (); + topologyTuple.sequenceNumber = tc.ansn; + topologyTuple.expirationTime = now + msg.GetVTime (); + AddTopologyTuple (topologyTuple); + + // Schedules topology tuple deletion + m_events.Track (Simulator::Schedule (DELAY (topologyTuple.expirationTime), + &OlsrAgentImpl::TopologyTupleTimerExpire, + this, topologyTuple)); + } + } +} + +/// +/// \brief Processes a MID message following RFC 3626 specification. +/// +/// The Interface Association Set is updated (if needed) with the information +/// of the received MID message. +/// +/// \param msg the %OLSR message which contains the MID message. +/// \param sender_iface the address of the interface where the message was sent from. +/// +void +OlsrAgentImpl::ProcessMid (const OlsrMessageHeader &msg, + const Ipv4Address &senderIface) +{ + const OlsrMessageHeader::Mid &mid = msg.GetMid (); + Time now = Simulator::Now (); + + // 1. If the sender interface of this message is not in the symmetric + // 1-hop neighborhood of this node, the message MUST be discarded. + LinkTuple *linkTuple = m_state.FindSymLinkTuple (senderIface, now); + if (linkTuple == NULL) + return; + + // 2. For each interface address listed in the MID message + for (std::vector::const_iterator i = mid.interfaceAddresses.begin (); + i != mid.interfaceAddresses.end (); i++) + { + bool updated = false; + IfaceAssocSet &ifaceAssoc = m_state.GetIfaceAssocSetMutable (); + for (IfaceAssocSet::iterator tuple = ifaceAssoc.begin(); + tuple != ifaceAssoc.end(); tuple++) + { + if (tuple->ifaceAddr == *i + && tuple->mainAddr == msg.GetOriginatorAddress ()) + { + tuple->time = now + msg.GetVTime (); + updated = true; + } + } + if (!updated) + { + IfaceAssocTuple tuple; + tuple.ifaceAddr = *i; + tuple.mainAddr = msg.GetOriginatorAddress (); + tuple.time = now + msg.GetVTime (); + AddIfaceAssocTuple (tuple); + // Schedules iface association tuple deletion + Simulator::Schedule (DELAY (tuple.time), + &OlsrAgentImpl::IfaceAssocTupleTimerExpire, this, tuple); + } + } +} + + +/// +/// \brief OLSR's default forwarding algorithm. +/// +/// See RFC 3626 for details. +/// +/// \param p the %OLSR packet which has been received. +/// \param msg the %OLSR message which must be forwarded. +/// \param dup_tuple NULL if the message has never been considered for forwarding, +/// or a duplicate tuple in other case. +/// \param local_iface the address of the interface where the message was received from. +/// +void +OlsrAgentImpl::ForwardDefault (OlsrMessageHeader olsrMessage, + DuplicateTuple *duplicated, + const Ipv4Address &localIface, + const Ipv4Address &senderAddress) +{ + Time now = Simulator::Now (); + + // If the sender interface address is not in the symmetric + // 1-hop neighborhood the message must not be forwarded + LinkTuple *linkTuple = m_state.FindSymLinkTuple (senderAddress, now); + if (linkTuple == NULL) + return; + + // If the message has already been considered for forwarding, + // it must not be retransmitted again + if (duplicated != NULL && duplicated->retransmitted) + { +// debug("%f: Node %d does not forward a message received" +// " from %d because it is duplicated\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(dup_tuple->addr())); + return; + } + + // If the sender interface address is an interface address + // of a MPR selector of this node and ttl is greater than 1, + // the message must be retransmitted + bool retransmitted = false; + if (olsrMessage.GetTimeToLive () > 1) + { + MprSelectorTuple *mprselTuple = + m_state.FindMprSelectorTuple (GetMainAddress (senderAddress)); + if (mprselTuple != NULL) + { + olsrMessage.SetTimeToLive (olsrMessage.GetTimeToLive () - 1); + olsrMessage.SetHopCount (olsrMessage.GetHopCount () + 1); + // We have to introduce a random delay to avoid + // synchronization with neighbors. + QueueMessage (olsrMessage, JITTER); + retransmitted = true; + } + } + + // Update duplicate tuple... + if (duplicated != NULL) + { + duplicated->expirationTime = now + OLSR_DUP_HOLD_TIME; + duplicated->retransmitted = retransmitted; + duplicated->ifaceList.push_back (localIface); + } + // ...or create a new one + else + { + DuplicateTuple newDup; + newDup.address = olsrMessage.GetOriginatorAddress (); + newDup.sequenceNumber = olsrMessage.GetMessageSequenceNumber (); + newDup.expirationTime = now + OLSR_DUP_HOLD_TIME; + newDup.retransmitted = retransmitted; + newDup.ifaceList.push_back (localIface); + AddDuplicateTuple (newDup); + // Schedule dup tuple deletion + Simulator::Schedule (OLSR_DUP_HOLD_TIME, + &OlsrAgentImpl::DupTupleTimerExpire, this, newDup); + } +} + +/// +/// \brief Enques an %OLSR message which will be sent with a delay of (0, delay]. +/// +/// This buffering system is used in order to piggyback several %OLSR messages in +/// a same %OLSR packet. +/// +/// \param msg the %OLSR message which must be sent. +/// \param delay maximum delay the %OLSR message is going to be buffered. +/// +void +OlsrAgentImpl::QueueMessage (const OlsrMessageHeader &message, Time delay) +{ + m_queuedMessages.push_back (message); + if (not m_queuedMessagesTimer.IsRunning ()) + { + m_queuedMessagesTimer.SetDelay (delay); + m_queuedMessagesTimer.Schedule (); + } +} + +void +OlsrAgentImpl::SendPacket (Packet packet) +{ + NS_DEBUG ("OLSR node " << m_mainAddress << " sending a OLSR packet"); + // Add a header + OlsrPacketHeader header; + header.SetPacketLength (header.GetSerializedSize () + packet.GetSize ()); + header.SetPacketSequenceNumber (GetPacketSequenceNumber ()); + packet.AddHeader (header); + // Send it + m_sendSocket->Send (packet); +} + +/// +/// \brief Creates as many %OLSR packets as needed in order to send all buffered +/// %OLSR messages. +/// +/// Maximum number of messages which can be contained in an %OLSR packet is +/// dictated by OLSR_MAX_MSGS constant. +/// +void +OlsrAgentImpl::SendQueuedMessages () +{ + Packet packet; + int numMessages = 0; + + NS_DEBUG ("Olsr node " << m_mainAddress << ": SendQueuedMessages"); + + for (std::vector::const_iterator message = m_queuedMessages.begin (); + message != m_queuedMessages.end (); + message++) + { + Packet p; + p.AddHeader (*message); + packet.AddAtEnd (p); + if (++numMessages == OLSR_MAX_MSGS) + { + SendPacket (packet); + // Reset variables for next packet + numMessages = 0; + packet = Packet (); + } + } + + if (packet.GetSize ()) + { + SendPacket (packet); + } + + m_queuedMessages.clear (); +} + +/// +/// \brief Creates a new %OLSR HELLO message which is buffered for being sent later on. +/// +void +OlsrAgentImpl::SendHello () +{ + OlsrMessageHeader msg; + Time now = Simulator::Now (); + + msg.SetVTime (OLSR_NEIGHB_HOLD_TIME); + msg.SetOriginatorAddress (m_mainAddress); + msg.SetTimeToLive (1); + msg.SetHopCount (0); + msg.SetMessageSequenceNumber (GetMessageSequenceNumber ()); + OlsrMessageHeader::Hello &hello = msg.GetHello (); + + hello.SetHTime (m_helloInterval); + hello.willingness = m_willingness; + + std::vector + &linkMessages = hello.linkMessages; + + for (LinkSet::const_iterator link_tuple = m_state.GetLinks ().begin (); + link_tuple != m_state.GetLinks ().end (); link_tuple++) + { + if (not (link_tuple->localIfaceAddr == m_mainAddress + && link_tuple->time >= now)) + continue; + + uint8_t link_type, nb_type = 0xff; + + // Establishes link type + if (m_useL2Notifications && link_tuple->lostTime >= now) + { + link_type = OLSR_LOST_LINK; + } + else if (link_tuple->symTime >= now) + { + link_type = OLSR_SYM_LINK; + } + else if (link_tuple->asymTime >= now) + { + link_type = OLSR_ASYM_LINK; + } + else + { + link_type = OLSR_LOST_LINK; + } + // Establishes neighbor type. + if (m_state.FindMprAddress (GetMainAddress (link_tuple->neighborIfaceAddr))) + { + nb_type = OLSR_MPR_NEIGH; + } + else + { + bool ok = false; + for (NeighborSet::const_iterator nb_tuple = m_state.GetNeighbors ().begin (); + nb_tuple != m_state.GetNeighbors ().end (); + nb_tuple++) + { + if (nb_tuple->neighborMainAddr == link_tuple->neighborIfaceAddr) + { + if (nb_tuple->status == NeighborTuple::STATUS_SYM) + { + nb_type = OLSR_SYM_NEIGH; + } + else if (nb_tuple->status == NeighborTuple::STATUS_NOT_SYM) + { + nb_type = OLSR_NOT_NEIGH; + } + else + { + NS_ASSERT (!"There is a neighbor tuple with an unknown status!\n"); + } + ok = true; + break; + } + } + if (!ok) + { + NS_ASSERT (!"Link tuple has no corresponding neighbor tuple\n"); + } + } + + OlsrMessageHeader::Hello::LinkMessage linkMessage; + linkMessage.linkCode = (link_type & 0x03) | ((nb_type << 2) & 0x0f); + linkMessage.neighborInterfaceAddresses.push_back + (link_tuple->neighborIfaceAddr); + + std::vector interfaces = + m_state.FindNeighborInterfaces (link_tuple->neighborIfaceAddr); + + linkMessage.neighborInterfaceAddresses.insert + (linkMessage.neighborInterfaceAddresses.end (), + interfaces.begin (), interfaces.end ()); + + linkMessages.push_back (linkMessage); + } + NS_DEBUG ("OLSR HELLO message size: " << int (msg.GetSerializedSize ()) + << " (with " << int (linkMessages.size ()) << " link messages)"); + QueueMessage (msg, JITTER); +} + +/// +/// \brief Creates a new %OLSR TC message which is buffered for being sent later on. +/// +void +OlsrAgentImpl::SendTc () +{ + OlsrMessageHeader msg; + + msg.SetVTime (OLSR_TOP_HOLD_TIME); + msg.SetOriginatorAddress (m_mainAddress); + msg.SetTimeToLive (255); + msg.SetHopCount (0); + msg.SetMessageSequenceNumber (GetMessageSequenceNumber ()); + + OlsrMessageHeader::Tc &tc = msg.GetTc (); + tc.ansn = m_ansn; + for (MprSelectorSet::const_iterator mprsel_tuple = m_state.GetMprSelectors ().begin(); + mprsel_tuple != m_state.GetMprSelectors ().end(); mprsel_tuple++) + { + tc.neighborAddresses.push_back (mprsel_tuple->mainAddr); + } + QueueMessage (msg, JITTER); +} + +/// +/// \brief Creates a new %OLSR MID message which is buffered for being sent later on. +/// +void +OlsrAgentImpl::SendMid () +{ + OlsrMessageHeader msg; + OlsrMessageHeader::Mid &mid = msg.GetMid (); + + // A node which has only a single interface address participating in + // the MANET (i.e., running OLSR), MUST NOT generate any MID + // message. + + // A node with several interfaces, where only one is participating + // in the MANET and running OLSR (e.g., a node is connected to a + // wired network as well as to a MANET) MUST NOT generate any MID + // messages. + + // A node with several interfaces, where more than one is + // participating in the MANET and running OLSR MUST generate MID + // messages as specified. + + // [ Note: assuming here that all interfaces participate in the + // MANET; later we may want to make this configurable. ] + + Ipv4Address loopback ("127.0.0.1"); + for (uint32_t i = 0; i < m_ipv4->GetNInterfaces (); i++) + { + Ipv4Address addr = m_ipv4->GetAddress (i); + if (addr != m_mainAddress && addr != loopback) + mid.interfaceAddresses.push_back (addr); + } + if (mid.interfaceAddresses.size () == 0) + return; + + msg.SetVTime (OLSR_MID_HOLD_TIME); + msg.SetOriginatorAddress (m_mainAddress); + msg.SetTimeToLive (255); + msg.SetHopCount (0); + msg.SetMessageSequenceNumber (GetMessageSequenceNumber ()); + + QueueMessage (msg, JITTER); +} + +/// +/// \brief Updates Link Set according to a new received HELLO message (following RFC 3626 +/// specification). Neighbor Set is also updated if needed. +void +OlsrAgentImpl::LinkSensing (const OlsrMessageHeader &msg, + const OlsrMessageHeader::Hello &hello, + const Ipv4Address &receiverIface, + const Ipv4Address &senderIface) +{ + Time now = Simulator::Now (); + bool updated = false; + bool created = false; + + LinkTuple *link_tuple = m_state.FindLinkTuple (senderIface); + if (link_tuple == NULL) + { + LinkTuple newLinkTuple; + // We have to create a new tuple + newLinkTuple.neighborIfaceAddr = senderIface; + newLinkTuple.localIfaceAddr = receiverIface; + newLinkTuple.symTime = now - Seconds (1); + newLinkTuple.lostTime = Seconds (0); + newLinkTuple.time = now + msg.GetVTime (); + link_tuple = &AddLinkTuple (newLinkTuple, hello.willingness); + created = true; + } + else + updated = true; + + link_tuple->asymTime = now + msg.GetVTime (); + for (std::vector::const_iterator linkMessage = + hello.linkMessages.begin (); + linkMessage != hello.linkMessages.end (); + linkMessage++) + { + int lt = linkMessage->linkCode & 0x03; // Link Type + int nt = linkMessage->linkCode >> 2; // Neighbor Type + + // We must not process invalid advertised links + if ((lt == OLSR_SYM_LINK && nt == OLSR_NOT_NEIGH) || + (nt != OLSR_SYM_NEIGH && nt != OLSR_MPR_NEIGH + && nt != OLSR_NOT_NEIGH)) + { + continue; + } + + for (std::vector::const_iterator neighIfaceAddr = + linkMessage->neighborInterfaceAddresses.begin (); + neighIfaceAddr != linkMessage->neighborInterfaceAddresses.end (); + neighIfaceAddr++) + { + if (*neighIfaceAddr == receiverIface) + { + if (lt == OLSR_LOST_LINK) + { + link_tuple->symTime = now - Seconds (1); + updated = true; + } + else if (lt == OLSR_SYM_LINK || lt == OLSR_ASYM_LINK) + { + link_tuple->symTime = now + msg.GetVTime (); + link_tuple->time = link_tuple->symTime + OLSR_NEIGHB_HOLD_TIME; + link_tuple->lostTime = Seconds (0); + updated = true; + } + break; + } + } + } + link_tuple->time = std::max(link_tuple->time, link_tuple->asymTime); + + if (updated) + LinkTupleUpdated (*link_tuple); + + // Schedules link tuple deletion + if (created && link_tuple != NULL) + { + m_events.Track (Simulator::Schedule (DELAY (std::min (link_tuple->time, link_tuple->symTime)), + &OlsrAgentImpl::LinkTupleTimerExpire, this, *link_tuple)); + } +} + +/// +/// \brief Updates the Neighbor Set according to the information contained in a new received +/// HELLO message (following RFC 3626). +void +OlsrAgentImpl::PopulateNeighborSet (const OlsrMessageHeader &msg, + const OlsrMessageHeader::Hello &hello) +{ + NeighborTuple *nb_tuple = m_state.FindNeighborTuple (msg.GetOriginatorAddress ()); + if (nb_tuple != NULL) + nb_tuple->willingness = hello.willingness; +} + + +/// +/// \brief Updates the 2-hop Neighbor Set according to the information contained in a new +/// received HELLO message (following RFC 3626). +void +OlsrAgentImpl::PopulateTwoHopNeighborSet (const OlsrMessageHeader &msg, + const OlsrMessageHeader::Hello &hello) +{ + Time now = Simulator::Now (); + + for (LinkSet::const_iterator link_tuple = m_state.GetLinks ().begin (); + link_tuple != m_state.GetLinks ().end (); link_tuple++) + { + if (GetMainAddress (link_tuple->neighborIfaceAddr) == msg.GetOriginatorAddress ()) + { + if (link_tuple->symTime >= now) + { + typedef std::vector LinkMessageVec; + for (LinkMessageVec::const_iterator linkMessage = + hello.linkMessages.begin (); + linkMessage != hello.linkMessages.end (); + linkMessage++) + { + int nt = linkMessage->linkCode >> 2; + + for (std::vector::const_iterator nb2hop_addr = + linkMessage->neighborInterfaceAddresses.begin (); + nb2hop_addr != linkMessage->neighborInterfaceAddresses.end (); + nb2hop_addr++) + { + if (nt == OLSR_SYM_NEIGH || nt == OLSR_MPR_NEIGH) + { + // if the main address of the 2-hop + // neighbor address = main address of + // the receiving node: silently + // discard the 2-hop neighbor address + if (*nb2hop_addr != m_routingAgentAddr) + { + // Otherwise, a 2-hop tuple is created + TwoHopNeighborTuple *nb2hop_tuple = + m_state.FindTwoHopNeighborTuple (msg.GetOriginatorAddress (), + *nb2hop_addr); + if (nb2hop_tuple == NULL) + { + TwoHopNeighborTuple new_nb2hop_tuple; + new_nb2hop_tuple.neighborMainAddr = msg.GetOriginatorAddress (); + new_nb2hop_tuple.twoHopNeighborAddr = *nb2hop_addr; + AddTwoHopNeighborTuple (new_nb2hop_tuple); + new_nb2hop_tuple.expirationTime = + now + msg.GetVTime (); + // Schedules nb2hop tuple + // deletion + m_events.Track (Simulator::Schedule (DELAY (new_nb2hop_tuple.expirationTime), + &OlsrAgentImpl::Nb2hopTupleTimerExpire, this, + new_nb2hop_tuple)); + } + else + { + nb2hop_tuple->expirationTime = + now + msg.GetVTime (); + } + + } + } + else if (nt == OLSR_NOT_NEIGH) + { + // For each 2-hop node listed in the HELLO + // message with Neighbor Type equal to + // NOT_NEIGH all 2-hop tuples where: + // N_neighbor_main_addr == Originator + // Address AND N_2hop_addr == main address + // of the 2-hop neighbor are deleted. + m_state.EraseTwoHopNeighborTuples + (msg.GetOriginatorAddress (), *nb2hop_addr); + } + } + } + } + } + } +} + + + +/// +/// \brief Updates the MPR Selector Set according to the information contained in a new +/// received HELLO message (following RFC 3626). +void +OlsrAgentImpl::PopulateMprSelectorSet (const OlsrMessageHeader &msg, + const OlsrMessageHeader::Hello &hello) +{ + Time now = Simulator::Now (); + + typedef std::vector LinkMessageVec; + for (LinkMessageVec::const_iterator linkMessage = hello.linkMessages.begin (); + linkMessage != hello.linkMessages.end (); + linkMessage++) + { + int nt = linkMessage->linkCode >> 2; + if (nt == OLSR_MPR_NEIGH) + { + for (std::vector::const_iterator nb_iface_addr = + linkMessage->neighborInterfaceAddresses.begin (); + nb_iface_addr != linkMessage->neighborInterfaceAddresses.end (); + nb_iface_addr++) + { + if (*nb_iface_addr == m_mainAddress) + { + // We must create a new entry into the mpr selector set + MprSelectorTuple *existing_mprsel_tuple = + m_state.FindMprSelectorTuple (msg.GetOriginatorAddress ()); + if (existing_mprsel_tuple == NULL) + { + MprSelectorTuple mprsel_tuple; + + mprsel_tuple.mainAddr = msg.GetOriginatorAddress (); + mprsel_tuple.expirationTime = now + msg.GetVTime (); + AddMprSelectorTuple (mprsel_tuple); + + // Schedules mpr selector tuple deletion + m_events.Track (Simulator::Schedule + (DELAY (mprsel_tuple.expirationTime), + &OlsrAgentImpl::MprSelTupleTimerExpire, this, + mprsel_tuple)); + } + else + { + existing_mprsel_tuple->expirationTime = now + msg.GetVTime (); + } + } + } + } + } +} + + +#if 0 +/// +/// \brief Drops a given packet because it couldn't be delivered to the corresponding +/// destination by the MAC layer. This may cause a neighbor loss, and appropiate +/// actions are then taken. +/// +/// \param p the packet which couldn't be delivered by the MAC layer. +/// +void +OLSR::mac_failed(Packet* p) { + double now = Simulator::Now (); + struct hdr_ip* ih = HDR_IP(p); + struct hdr_cmn* ch = HDR_CMN(p); + + debug("%f: Node %d MAC Layer detects a breakage on link to %d\n", + now, + OLSR::node_id(ra_addr()), + OLSR::node_id(ch->next_hop())); + + if ((u_int32_t)ih->daddr() == IP_BROADCAST) { + drop(p, DROP_RTR_MAC_CALLBACK); + return; + } + + OLSR_link_tuple* link_tuple = state_.find_link_tuple(ch->next_hop()); + if (link_tuple != NULL) { + link_tuple->lost_time() = now + OLSR_NEIGHB_HOLD_TIME; + link_tuple->time() = now + OLSR_NEIGHB_HOLD_TIME; + nb_loss(link_tuple); + } + drop(p, DROP_RTR_MAC_CALLBACK); +} +#endif + + + + +/// +/// \brief Performs all actions needed when a neighbor loss occurs. +/// +/// Neighbor Set, 2-hop Neighbor Set, MPR Set and MPR Selector Set are updated. +/// +/// \param tuple link tuple with the information of the link to the neighbor which has been lost. +/// +void +OlsrAgentImpl::NeighborLoss (const LinkTuple &tuple) +{ +// debug("%f: Node %d detects neighbor %d loss\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->neighborIfaceAddr)); + + LinkTupleUpdated (tuple); + m_state.EraseTwoHopNeighborTuples (GetMainAddress (tuple.neighborIfaceAddr)); + m_state.EraseMprSelectorTuples (GetMainAddress (tuple.neighborIfaceAddr)); + + MprComputation(); + RoutingTableComputation(); +} + +/// +/// \brief Adds a duplicate tuple to the Duplicate Set. +/// +/// \param tuple the duplicate tuple to be added. +/// +void +OlsrAgentImpl::AddDuplicateTuple (const DuplicateTuple &tuple) +{ + /*debug("%f: Node %d adds dup tuple: addr = %d seq_num = %d\n", + Simulator::Now (), + OLSR::node_id(ra_addr()), + OLSR::node_id(tuple->addr()), + tuple->seq_num());*/ + m_state.InsertDuplicateTuple (tuple); +} + +/// +/// \brief Removes a duplicate tuple from the Duplicate Set. +/// +/// \param tuple the duplicate tuple to be removed. +/// +void +OlsrAgentImpl::RemoveDuplicateTuple (const DuplicateTuple &tuple) +{ + /*debug("%f: Node %d removes dup tuple: addr = %d seq_num = %d\n", + Simulator::Now (), + OLSR::node_id(ra_addr()), + OLSR::node_id(tuple->addr()), + tuple->seq_num());*/ + m_state.EraseDuplicateTuple (tuple); +} + +/// +/// \brief Adds a link tuple to the Link Set (and an associated neighbor tuple to the Neighbor Set). +/// +/// \param tuple the link tuple to be added. +/// \param willingness willingness of the node which is going to be inserted in the Neighbor Set. +/// +LinkTuple& +OlsrAgentImpl::AddLinkTuple (const LinkTuple &tuple, uint8_t willingness) +{ +// debug("%f: Node %d adds link tuple: nb_addr = %d\n", +// now, +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->neighborIfaceAddr)); + LinkTuple &addedLinkTuple = m_state.InsertLinkTuple (tuple); + // Creates associated neighbor tuple + NeighborTuple nb_tuple; + nb_tuple.neighborMainAddr = GetMainAddress (tuple.neighborIfaceAddr); + nb_tuple.willingness = willingness; + + if (tuple.symTime >= Simulator::Now ()) + nb_tuple.status = NeighborTuple::STATUS_SYM; + else + nb_tuple.status = NeighborTuple::STATUS_NOT_SYM; + + AddNeighborTuple (nb_tuple); + return addedLinkTuple; +} + +/// +/// \brief Removes a link tuple from the Link Set. +/// +/// \param tuple the link tuple to be removed. +/// +void +OlsrAgentImpl::RemoveLinkTuple (const LinkTuple &tuple) +{ +// nsaddr_t nb_addr = get_main_addr(tuple->neighborIfaceAddr); +// double now = Simulator::Now (); + +// debug("%f: Node %d removes link tuple: nb_addr = %d\n", +// now, +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->neighborIfaceAddr)); + // Prints this here cause we are not actually calling rm_nb_tuple() (efficiency stuff) + // debug("%f: Node %d removes neighbor tuple: nb_addr = %d\n", + // now, + // OLSR::node_id(ra_addr()), + // OLSR::node_id(nb_addr)); + + m_state.EraseLinkTuple (tuple); + m_state.EraseNeighborTuple (GetMainAddress (tuple.neighborIfaceAddr)); +} + +/// +/// \brief This function is invoked when a link tuple is updated. Its aim is to +/// also update the corresponding neighbor tuple if it is needed. +/// +/// \param tuple the link tuple which has been updated. +/// +void +OlsrAgentImpl::LinkTupleUpdated (const LinkTuple &tuple) +{ + // Each time a link tuple changes, the associated neighbor tuple must be recomputed + NeighborTuple *nb_tuple = + m_state.FindNeighborTuple (GetMainAddress (tuple.neighborIfaceAddr)); + if (nb_tuple != NULL) + { + if (m_useL2Notifications && tuple.lostTime >= Simulator::Now ()) + { + nb_tuple->status = NeighborTuple::STATUS_NOT_SYM; + } + else if (tuple.symTime >= Simulator::Now ()) + { + nb_tuple->status = NeighborTuple::STATUS_SYM; + } + else + { + nb_tuple->status = NeighborTuple::STATUS_NOT_SYM; + } + } + +// debug("%f: Node %d has updated link tuple: nb_addr = %d status = %s\n", +// now, +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->neighborIfaceAddr), +// ((nb_tuple->status() == OLSR_STATUS_SYM) ? "sym" : "not_sym")); + +} + +/// +/// \brief Adds a neighbor tuple to the Neighbor Set. +/// +/// \param tuple the neighbor tuple to be added. +/// +void +OlsrAgentImpl::AddNeighborTuple (const NeighborTuple &tuple) +{ +// debug("%f: Node %d adds neighbor tuple: nb_addr = %d status = %s\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->neighborMainAddr), +// ((tuple->status() == OLSR_STATUS_SYM) ? "sym" : "not_sym")); + + m_state.InsertNeighborTuple (tuple); +} + +/// +/// \brief Removes a neighbor tuple from the Neighbor Set. +/// +/// \param tuple the neighbor tuple to be removed. +/// +void +OlsrAgentImpl::RemoveNeighborTuple (const NeighborTuple &tuple) +{ +// debug("%f: Node %d removes neighbor tuple: nb_addr = %d status = %s\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->neighborMainAddr), +// ((tuple->status() == OLSR_STATUS_SYM) ? "sym" : "not_sym")); + + m_state.EraseNeighborTuple (tuple); +} + +/// +/// \brief Adds a 2-hop neighbor tuple to the 2-hop Neighbor Set. +/// +/// \param tuple the 2-hop neighbor tuple to be added. +/// +void +OlsrAgentImpl::AddTwoHopNeighborTuple (const TwoHopNeighborTuple &tuple) +{ +// debug("%f: Node %d adds 2-hop neighbor tuple: nb_addr = %d nb2hop_addr = %d\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->neighborMainAddr), +// OLSR::node_id(tuple->twoHopNeighborAddr)); + + m_state.InsertTwoHopNeighborTuple (tuple); +} + +/// +/// \brief Removes a 2-hop neighbor tuple from the 2-hop Neighbor Set. +/// +/// \param tuple the 2-hop neighbor tuple to be removed. +/// +void +OlsrAgentImpl::RemoveTwoHopNeighborTuple (const TwoHopNeighborTuple &tuple) +{ +// debug("%f: Node %d removes 2-hop neighbor tuple: nb_addr = %d nb2hop_addr = %d\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->neighborMainAddr), +// OLSR::node_id(tuple->twoHopNeighborAddr)); + + m_state.EraseTwoHopNeighborTuple (tuple); +} + +/// +/// \brief Adds an MPR selector tuple to the MPR Selector Set. +/// +/// Advertised Neighbor Sequence Number (ANSN) is also updated. +/// +/// \param tuple the MPR selector tuple to be added. +/// +void +OlsrAgentImpl::AddMprSelectorTuple (const MprSelectorTuple &tuple) +{ +// debug("%f: Node %d adds MPR selector tuple: nb_addr = %d\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->main_addr())); + + m_state.InsertMprSelectorTuple (tuple); + m_ansn = (m_ansn + 1) % (OLSR_MAX_SEQ_NUM + 1); +} + +/// +/// \brief Removes an MPR selector tuple from the MPR Selector Set. +/// +/// Advertised Neighbor Sequence Number (ANSN) is also updated. +/// +/// \param tuple the MPR selector tuple to be removed. +/// +void +OlsrAgentImpl::RemoveMprSelectorTuple (const MprSelectorTuple &tuple) +{ +// debug("%f: Node %d removes MPR selector tuple: nb_addr = %d\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->main_addr())); + + m_state.EraseMprSelectorTuple (tuple); + m_ansn = (m_ansn + 1) % (OLSR_MAX_SEQ_NUM + 1); +} + +/// +/// \brief Adds a topology tuple to the Topology Set. +/// +/// \param tuple the topology tuple to be added. +/// +void +OlsrAgentImpl::AddTopologyTuple (const TopologyTuple &tuple) +{ +// debug("%f: Node %d adds topology tuple: dest_addr = %d last_addr = %d seq = %d\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->dest_addr()), +// OLSR::node_id(tuple->last_addr()), +// tuple->seq()); + + m_state.InsertTopologyTuple(tuple); +} + +/// +/// \brief Removes a topology tuple from the Topology Set. +/// +/// \param tuple the topology tuple to be removed. +/// +void +OlsrAgentImpl::RemoveTopologyTuple (const TopologyTuple &tuple) +{ +// debug("%f: Node %d removes topology tuple: dest_addr = %d last_addr = %d seq = %d\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->dest_addr()), +// OLSR::node_id(tuple->last_addr()), +// tuple->seq()); + + m_state.EraseTopologyTuple (tuple); +} + +/// +/// \brief Adds an interface association tuple to the Interface Association Set. +/// +/// \param tuple the interface association tuple to be added. +/// +void +OlsrAgentImpl::AddIfaceAssocTuple (const IfaceAssocTuple &tuple) +{ +// debug("%f: Node %d adds iface association tuple: main_addr = %d iface_addr = %d\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->main_addr()), +// OLSR::node_id(tuple->iface_addr())); + + m_state.InsertIfaceAssocTuple (tuple); +} + +/// +/// \brief Removes an interface association tuple from the Interface Association Set. +/// +/// \param tuple the interface association tuple to be removed. +/// +void +OlsrAgentImpl::RemoveIfaceAssocTuple (const IfaceAssocTuple &tuple) +{ +// debug("%f: Node %d removes iface association tuple: main_addr = %d iface_addr = %d\n", +// Simulator::Now (), +// OLSR::node_id(ra_addr()), +// OLSR::node_id(tuple->main_addr()), +// OLSR::node_id(tuple->iface_addr())); + + m_state.EraseIfaceAssocTuple (tuple); +} + + +uint16_t OlsrAgentImpl::GetPacketSequenceNumber () +{ + m_packetSequenceNumber = (m_packetSequenceNumber + 1) % (OLSR_MAX_SEQ_NUM + 1); + return m_packetSequenceNumber; +} + +/// Increments message sequence number and returns the new value. +uint16_t OlsrAgentImpl::GetMessageSequenceNumber () +{ + m_messageSequenceNumber = (m_messageSequenceNumber + 1) % (OLSR_MAX_SEQ_NUM + 1); + return m_messageSequenceNumber; +} + + +/// +/// \brief Sends a HELLO message and reschedules the HELLO timer. +/// \param e The event which has expired. +/// +void +OlsrAgentImpl::HelloTimerExpire () +{ + SendHello (); + m_helloTimer.Schedule (m_helloInterval); +} + +/// +/// \brief Sends a TC message (if there exists any MPR selector) and reschedules the TC timer. +/// \param e The event which has expired. +/// +void +OlsrAgentImpl::TcTimerExpire () +{ + if (m_state.GetMprSelectors ().size () > 0) + { + SendTc (); + } + m_tcTimer.Schedule (m_tcInterval); +} + +/// +/// \brief Sends a MID message (if the node has more than one interface) and resets the MID timer. +/// \warning Currently it does nothing because there is no support for multiple interfaces. +/// \param e The event which has expired. +/// +void +OlsrAgentImpl::MidTimerExpire () +{ + SendMid (); + m_midTimer.Schedule (m_midInterval); +} + +/// +/// \brief Removes tuple if expired. Else timer is rescheduled to expire at tuple.expirationTime. +/// +/// The task of actually removing the tuple is left to the OLSR agent. +/// +/// \param tuple The tuple which has expired. +/// +void +OlsrAgentImpl::DupTupleTimerExpire (DuplicateTuple tuple) +{ + if (tuple.expirationTime < Simulator::Now ()) + { + RemoveDuplicateTuple (tuple); + } + else + { + m_events.Track (Simulator::Schedule (DELAY (tuple.expirationTime), + &OlsrAgentImpl::DupTupleTimerExpire, this, + tuple)); + } +} + +/// +/// \brief Removes tuple_ if expired. Else if symmetric time +/// has expired then it is assumed a neighbor loss and agent_->nb_loss() +/// is called. In this case the timer is rescheduled to expire at +/// tuple_->time(). Otherwise the timer is rescheduled to expire at +/// the minimum between tuple_->time() and tuple_->sym_time(). +/// +/// The task of actually removing the tuple is left to the OLSR agent. +/// +/// \param e The event which has expired. +/// +void +OlsrAgentImpl::LinkTupleTimerExpire (LinkTuple tuple) +{ + Time now = Simulator::Now (); + + if (tuple.time < now) + { + RemoveLinkTuple (tuple); + } + else if (tuple.symTime < now) + { + if (m_linkTupleTimerFirstTime) + m_linkTupleTimerFirstTime = false; + else + NeighborLoss (tuple); + + m_events.Track (Simulator::Schedule (DELAY (tuple.time), + &OlsrAgentImpl::LinkTupleTimerExpire, this, + tuple)); + } + else + { + m_events.Track (Simulator::Schedule (DELAY (std::min (tuple.time, tuple.symTime)), + &OlsrAgentImpl::LinkTupleTimerExpire, this, + tuple)); + } +} + +/// +/// \brief Removes tuple_ if expired. Else the timer is rescheduled to expire at tuple_->time(). +/// +/// The task of actually removing the tuple is left to the OLSR agent. +/// +/// \param e The event which has expired. +/// +void +OlsrAgentImpl::Nb2hopTupleTimerExpire (TwoHopNeighborTuple tuple) +{ + if (tuple.expirationTime < Simulator::Now ()) + { + RemoveTwoHopNeighborTuple (tuple); + } + else + { + m_events.Track (Simulator::Schedule (DELAY (tuple.expirationTime), + &OlsrAgentImpl::Nb2hopTupleTimerExpire, + this, tuple)); + } +} + +/// +/// \brief Removes tuple_ if expired. Else the timer is rescheduled to expire at tuple_->time(). +/// +/// The task of actually removing the tuple is left to the OLSR agent. +/// +/// \param e The event which has expired. +/// +void +OlsrAgentImpl::MprSelTupleTimerExpire (MprSelectorTuple tuple) +{ + if (tuple.expirationTime < Simulator::Now ()) + { + RemoveMprSelectorTuple (tuple); + } + else + { + m_events.Track (Simulator::Schedule (DELAY (tuple.expirationTime), + &OlsrAgentImpl::MprSelTupleTimerExpire, + this, tuple)); + } +} + +/// +/// \brief Removes tuple_ if expired. Else the timer is rescheduled to expire at tuple_->time(). +/// +/// The task of actually removing the tuple is left to the OLSR agent. +/// +/// \param e The event which has expired. +/// +void +OlsrAgentImpl::TopologyTupleTimerExpire (TopologyTuple tuple) +{ + if (tuple.expirationTime < Simulator::Now ()) + { + RemoveTopologyTuple (tuple); + } + else + { + m_events.Track (Simulator::Schedule (DELAY (tuple.expirationTime), + &OlsrAgentImpl::TopologyTupleTimerExpire, + this, tuple)); + } +} + +/// +/// \brief Removes tuple_ if expired. Else timer is rescheduled to expire at tuple_->time(). +/// \warning Actually this is never invoked because there is no support for multiple interfaces. +/// \param e The event which has expired. +/// +void +OlsrAgentImpl::IfaceAssocTupleTimerExpire (IfaceAssocTuple tuple) +{ + if (tuple.time < Simulator::Now ()) + { + RemoveIfaceAssocTuple (tuple); + } + else + { + m_events.Track (Simulator::Schedule (DELAY (tuple.time), + &OlsrAgentImpl::IfaceAssocTupleTimerExpire, + this, tuple)); + } +} + + + +} // namespace ns3 + + + +#ifdef RUN_SELF_TESTS + + +#include "ns3/test.h" + +namespace ns3 { + +class OlsrTest : public ns3::Test { +private: +public: + OlsrTest (); + virtual bool RunTests (void); + + +}; + +OlsrTest::OlsrTest () + : ns3::Test ("Olsr") +{} + + +bool +OlsrTest::RunTests (void) +{ + bool result = true; + + + return result; +} + +static OlsrTest gOlsrTest; + +} + + +#endif /* RUN_SELF_TESTS */ diff --git a/src/routing/olsr/olsr-agent-impl.h b/src/routing/olsr/olsr-agent-impl.h new file mode 100644 index 000000000..a708a3818 --- /dev/null +++ b/src/routing/olsr/olsr-agent-impl.h @@ -0,0 +1,184 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2004 Francisco J. Ros + * Copyright (c) 2007 INESC Porto + * + * 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: Francisco J. Ros + * Gustavo J. A. M. Carneiro + */ + + +#ifndef __OLSR_AGENT_IMPL_H__ +#define __OLSR_AGENT_IMPL_H__ + +#include + +#include "olsr-agent.h" +#include "olsr-header.h" +#include "olsr-state.h" + +#include "routing-table.h" +#include "repositories.h" + +#include "ns3/object.h" +#include "ns3/packet.h" +#include "ns3/node.h" +#include "ns3/socket.h" +#include "event-garbage-collector.h" +#include "ns3/timer.h" + + +namespace ns3 { + +using namespace olsr; + + +class OlsrAgentImpl : public OlsrAgent +{ + friend class OlsrTest; + +public: + OlsrAgentImpl (Ptr node); + + virtual void Start (); + virtual void SetMainInterface (uint32_t interface); + +private: + EventGarbageCollector m_events; + + /// Address of the routing agent. + Ipv4Address m_routingAgentAddr; + + /// Packets sequence number counter. + uint16_t m_packetSequenceNumber; + /// Messages sequence number counter. + uint16_t m_messageSequenceNumber; + /// Advertised Neighbor Set sequence number. + uint16_t m_ansn; + + /// HELLO messages' emission interval. + Time m_helloInterval; + /// TC messages' emission interval. + Time m_tcInterval; + /// MID messages' emission interval. + Time m_midInterval; + /// Willingness for forwarding packets on behalf of other nodes. + uint8_t m_willingness; + /// Determines if layer 2 notifications are enabled or not. + bool m_useL2Notifications; + + /// Routing table. + Ptr m_routingTable; + /// Internal state with all needed data structs. + OlsrState m_state; + + Ptr m_ipv4; + +protected: + void DoDispose (); + void SendPacket (Packet packet); + + /// Increments packet sequence number and returns the new value. + inline uint16_t GetPacketSequenceNumber (); + /// Increments message sequence number and returns the new value. + inline uint16_t GetMessageSequenceNumber (); + + void RecvOlsr (Ptr socket, + const Packet &receivedPacket, + const Address &sourceAddress); + + void MprComputation (); + void RoutingTableComputation (); + Ipv4Address GetMainAddress (Ipv4Address iface_addr); + + // Timer handlers + Timer m_helloTimer; + void HelloTimerExpire (); + + Timer m_tcTimer; + void TcTimerExpire (); + + Timer m_midTimer; + void MidTimerExpire (); + + void DupTupleTimerExpire (DuplicateTuple tuple); + bool m_linkTupleTimerFirstTime; + void LinkTupleTimerExpire (LinkTuple tuple); + void Nb2hopTupleTimerExpire (TwoHopNeighborTuple tuple); + void MprSelTupleTimerExpire (MprSelectorTuple tuple); + void TopologyTupleTimerExpire (TopologyTuple tuple); + void IfaceAssocTupleTimerExpire (IfaceAssocTuple tuple); + + /// A list of pending messages which are buffered awaiting for being sent. + std::vector m_queuedMessages; + Timer m_queuedMessagesTimer; // timer for throttling outgoing messages + + void ForwardDefault (OlsrMessageHeader olsrMessage, + DuplicateTuple *duplicated, + const Ipv4Address &localIface, + const Ipv4Address &senderAddress); + void QueueMessage (const OlsrMessageHeader &message, Time delay); + void SendQueuedMessages (); + void SendHello (); + void SendTc (); + void SendMid (); + + void NeighborLoss (const LinkTuple &tuple); + void AddDuplicateTuple (const DuplicateTuple &tuple); + void RemoveDuplicateTuple (const DuplicateTuple &tuple); + LinkTuple & AddLinkTuple (const LinkTuple &tuple, uint8_t willingness); + void RemoveLinkTuple (const LinkTuple &tuple); + void LinkTupleUpdated (const LinkTuple &tuple); + void AddNeighborTuple (const NeighborTuple &tuple); + void RemoveNeighborTuple (const NeighborTuple &tuple); + void AddTwoHopNeighborTuple (const TwoHopNeighborTuple &tuple); + void RemoveTwoHopNeighborTuple (const TwoHopNeighborTuple &tuple); + void AddMprSelectorTuple (const MprSelectorTuple &tuple); + void RemoveMprSelectorTuple (const MprSelectorTuple &tuple); + void AddTopologyTuple (const TopologyTuple &tuple); + void RemoveTopologyTuple (const TopologyTuple &tuple); + void AddIfaceAssocTuple (const IfaceAssocTuple &tuple); + void RemoveIfaceAssocTuple (const IfaceAssocTuple &tuple); + + void ProcessHello (const OlsrMessageHeader &msg, + const Ipv4Address &receiverIface, + const Ipv4Address &senderIface); + void ProcessTc (const OlsrMessageHeader &msg, + const Ipv4Address &senderIface); + void ProcessMid (const OlsrMessageHeader &msg, + const Ipv4Address &senderIface); + + void LinkSensing (const OlsrMessageHeader &msg, + const OlsrMessageHeader::Hello &hello, + const Ipv4Address &receiverIface, + const Ipv4Address &sender_iface); + void PopulateNeighborSet (const OlsrMessageHeader &msg, + const OlsrMessageHeader::Hello &hello); + void PopulateTwoHopNeighborSet (const OlsrMessageHeader &msg, + const OlsrMessageHeader::Hello &hello); + void PopulateMprSelectorSet (const OlsrMessageHeader &msg, + const OlsrMessageHeader::Hello &hello); + + int Degree (NeighborTuple const &tuple); + + Ipv4Address m_mainAddress; + Ptr m_receiveSocket; // UDP socket for receving OSLR packets + Ptr m_sendSocket; // UDP socket for sending OSLR packets +}; + +} // namespace ns3 + +#endif diff --git a/src/routing/olsr/olsr-agent.cc b/src/routing/olsr/olsr-agent.cc new file mode 100644 index 000000000..c846aee4e --- /dev/null +++ b/src/routing/olsr/olsr-agent.cc @@ -0,0 +1,29 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INESC Porto + * + * 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: Gustavo J. A. M. Carneiro + */ + +#include "olsr-agent.h" +#include "olsr-agent-impl.h" + +namespace ns3 { + +const InterfaceId OlsrAgent::iid = MakeInterfaceId ("OlsrAgent", Object::iid); +const ClassId OlsrAgent::cid = MakeClassId< OlsrAgentImpl, Ptr > ("OlsrAgent", OlsrAgent::iid); + +} diff --git a/src/routing/olsr/olsr-agent.h b/src/routing/olsr/olsr-agent.h new file mode 100644 index 000000000..e9047e498 --- /dev/null +++ b/src/routing/olsr/olsr-agent.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INESC Porto + * + * 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: Gustavo J. A. M. Carneiro + */ + +#ifndef OLSR_AGENT_H +#define OLSR_AGENT_H + +#include "ns3/node.h" +#include "ns3/component-manager.h" + +namespace ns3 { + + +/** + * \brief Class implementing the OLSR state machine + * + * This class represents an instance of the OLSR protocol. It + * attaches itself to a Node, and its lifecycle is bound to that node. + * Normally the functions in the ns3::olsr namespace are more simple + * to use to start OLSR on nodes, but access to the underlying OLSR + * agent can be useful in order to customize the OLSR parameters. + * Example: + * + * \code + * Ptr olsr = ComponentManager::Create > (OlsrAgent::cid, OlsrAgent::iid, node); + * agent->SetMainInterface (2); + * agent->Start (); + * \endcode + */ +class OlsrAgent : public Object +{ +public: + static const InterfaceId iid; + static const ClassId cid; + + /** + * \brief Sets the main interface to be used by OLSR + * + * Normally OLSR supports multiple interfaces, but the protocol + * requires the definition of a "main interface". This interface's + * IPv4 address provides the identity of the node, and all outgoing + * OLSR routing messages must have the main interface address, + * regardless of the actual interface used to transmit the packet. + * This method allows one to explicitly select an interface as the + * main interface. It must be called before the agent starts, but + * calling it is optional; if not called, the agent tries to guess + * and uses a suitable interface. + */ + virtual void SetMainInterface (uint32_t interface) = 0; + + /** + * \brief Starts the OLSR protocol operation + * + * Calling this method essentially bootstraps the OLSR protocol, and + * causes the agent to start broadcasting OLSR messages to + * neighbors, as well start listening to messages from neighbors. + */ + virtual void Start () = 0; +}; + + +}; // namespace ns3 + +#endif /* OLSR_AGENT_H */ + diff --git a/src/routing/olsr/olsr-header.cc b/src/routing/olsr/olsr-header.cc new file mode 100644 index 000000000..5314b1e3e --- /dev/null +++ b/src/routing/olsr/olsr-header.cc @@ -0,0 +1,734 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INESC Porto + * + * 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: Gustavo J. A. M. Carneiro + */ + +#include "ns3/assert.h" + +#include "olsr-header.h" + +#define IPV4_ADDRESS_SIZE 4 +#define OLSR_MSG_HEADER_SIZE 12 +#define OLSR_PKT_HEADER_SIZE 4 + +namespace ns3 { + +/// Scaling factor used in RFC 3626. +#define OLSR_C 0.0625 + +/// +/// \brief Converts a decimal number of seconds to the mantissa/exponent format. +/// +/// \param seconds decimal number of seconds we want to convert. +/// \return the number of seconds in mantissa/exponent format. +/// +uint8_t +OlsrSecondsToEmf (double seconds) +{ + int a, b = 0; + + // find the largest integer 'b' such that: T/C >= 2^b + for (b = 0; (seconds/OLSR_C) >= (1 << b); ++b) + ; + NS_ASSERT ((seconds/OLSR_C) < (1 << b)); + b--; + NS_ASSERT ((seconds/OLSR_C) >= (1 << b)); + + // compute the expression 16*(T/(C*(2^b))-1), which may not be a integer + double tmp = 16*(seconds/(OLSR_C*(1<= 0 && a < 16); + NS_ASSERT (b >= 0 && b < 16); + + // the field will be a byte holding the value a*16+b + return (uint8_t) ((a << 4) | b); +} + +/// +/// \brief Converts a number of seconds in the mantissa/exponent format to a decimal number. +/// +/// \param olsr_format number of seconds in mantissa/exponent format. +/// \return the decimal number of seconds. +/// +double +OlsrEmfToSeconds (uint8_t olsrFormat) +{ + int a = (olsrFormat >> 4); + int b = (olsrFormat & 0xf); + // value = C*(1+a/16)*2^b [in seconds] + return OLSR_C * (1 + a/16.0) * (1 << b); +} + + + +// ---------------- OLSR Packet ------------------------------- + +OlsrPacketHeader::OlsrPacketHeader () +{} + +OlsrPacketHeader::~OlsrPacketHeader () +{} + +uint32_t +OlsrPacketHeader::GetUid (void) +{ + static uint32_t uid = AllocateUid + ("OlsrPacketHeader.nsnam.org"); + return uid; +} + +uint32_t +OlsrPacketHeader::GetSerializedSize (void) const +{ + return OLSR_PKT_HEADER_SIZE; +} + +void +OlsrPacketHeader::Print (std::ostream &os) const +{ + // TODO +} + +void +OlsrPacketHeader::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteHtonU16 (m_packetLength); + i.WriteHtonU16 (m_packetSequenceNumber); +} + +uint32_t +OlsrPacketHeader::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + m_packetLength = i.ReadNtohU16 (); + m_packetSequenceNumber = i.ReadNtohU16 (); + return GetSerializedSize (); +} + + +// ---------------- OLSR Message ------------------------------- + +OlsrMessageHeader::OlsrMessageHeader () + : m_messageType (OlsrMessageHeader::MessageType (0)) +{} + +OlsrMessageHeader::~OlsrMessageHeader () +{} + +uint32_t +OlsrMessageHeader::GetUid (void) +{ + static uint32_t uid = AllocateUid + ("OlsrMessageHeader.nsnam.org"); + return uid; +} + +uint32_t +OlsrMessageHeader::GetSerializedSize (void) const +{ + uint32_t size = OLSR_MSG_HEADER_SIZE; + switch (m_messageType) + { + case MID_MESSAGE: + size += m_message.mid.GetSerializedSize (); + break; + case HELLO_MESSAGE: + size += m_message.hello.GetSerializedSize (); + break; + case TC_MESSAGE: + size += m_message.tc.GetSerializedSize (); + break; + case HNA_MESSAGE: + size += m_message.hna.GetSerializedSize (); + break; + default: + NS_ASSERT (false); + } + return size; +} + +void +OlsrMessageHeader::Print (std::ostream &os) const +{ + // TODO +} + +void +OlsrMessageHeader::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteU8 (m_messageType); + i.WriteU8 (m_vTime); + i.WriteHtonU16 (GetSerializedSize () - OLSR_MSG_HEADER_SIZE); + i.WriteHtonU32 (m_originatorAddress.GetHostOrder ()); + i.WriteU8 (m_timeToLive); + i.WriteU8 (m_hopCount); + i.WriteHtonU16 (m_messageSequenceNumber); + + switch (m_messageType) + { + case MID_MESSAGE: + m_message.mid.Serialize (i); + break; + case HELLO_MESSAGE: + m_message.hello.Serialize (i); + break; + case TC_MESSAGE: + m_message.tc.Serialize (i); + break; + case HNA_MESSAGE: + m_message.hna.Serialize (i); + break; + default: + NS_ASSERT (false); + } + +} + +uint32_t +OlsrMessageHeader::Deserialize (Buffer::Iterator start) +{ + uint32_t size; + Buffer::Iterator i = start; + m_messageType = (MessageType) i.ReadU8 (); + NS_ASSERT (m_messageType >= HELLO_MESSAGE && m_messageType <= HNA_MESSAGE); + m_vTime = i.ReadU8 (); + m_messageSize = i.ReadNtohU16 (); + m_originatorAddress = Ipv4Address (i.ReadNtohU32 ()); + m_timeToLive = i.ReadU8 (); + m_hopCount = i.ReadU8 (); + m_messageSequenceNumber = i.ReadNtohU16 (); + size = OLSR_MSG_HEADER_SIZE; + switch (m_messageType) + { + case MID_MESSAGE: + size += m_message.mid.Deserialize (i, m_messageSize); + break; + case HELLO_MESSAGE: + size += m_message.hello.Deserialize (i, m_messageSize); + break; + case TC_MESSAGE: + size += m_message.tc.Deserialize (i, m_messageSize); + break; + case HNA_MESSAGE: + size += m_message.hna.Deserialize (i, m_messageSize); + break; + default: + NS_ASSERT (false); + } + return size; +} + + +// ---------------- OLSR MID Message ------------------------------- + +uint32_t +OlsrMessageHeader::Mid::GetSerializedSize (void) const +{ + return this->interfaceAddresses.size () * IPV4_ADDRESS_SIZE; +} + +void +OlsrMessageHeader::Mid::Print (std::ostream &os) const +{ + // TODO +} + +void +OlsrMessageHeader::Mid::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + for (std::vector::const_iterator iter = this->interfaceAddresses.begin (); + iter != this->interfaceAddresses.end (); iter++) + { + i.WriteHtonU32 (iter->GetHostOrder ()); + } +} + +uint32_t +OlsrMessageHeader::Mid::Deserialize (Buffer::Iterator start, uint32_t messageSize) +{ + Buffer::Iterator i = start; + + this->interfaceAddresses.clear (); + NS_ASSERT (messageSize >= 0); + NS_ASSERT (messageSize % IPV4_ADDRESS_SIZE == 0); + + int numAddresses = messageSize / IPV4_ADDRESS_SIZE; + this->interfaceAddresses.erase (this->interfaceAddresses.begin(), + this->interfaceAddresses.end ()); + for (int n = 0; n < numAddresses; ++n) + this->interfaceAddresses.push_back (Ipv4Address (i.ReadNtohU32 ())); + return GetSerializedSize (); +} + + + +// ---------------- OLSR HELLO Message ------------------------------- + +uint32_t +OlsrMessageHeader::Hello::GetSerializedSize (void) const +{ + uint32_t size = 4; + for (std::vector::const_iterator iter = this->linkMessages.begin (); + iter != this->linkMessages.end (); iter++) + { + const LinkMessage &lm = *iter; + size += 4; + size += IPV4_ADDRESS_SIZE * lm.neighborInterfaceAddresses.size (); + } + return size; +} + +void +OlsrMessageHeader::Hello::Print (std::ostream &os) const +{ + // TODO +} + +void +OlsrMessageHeader::Hello::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + i.WriteU16 (0); // Reserved + i.WriteU8 (this->hTime); + i.WriteU8 (this->willingness); + + for (std::vector::const_iterator iter = this->linkMessages.begin (); + iter != this->linkMessages.end (); iter++) + { + const LinkMessage &lm = *iter; + + i.WriteU8 (lm.linkCode); + i.WriteU8 (0); // Reserved + + // The size of the link message, counted in bytes and measured + // from the beginning of the "Link Code" field and until the + // next "Link Code" field (or - if there are no more link types + // - the end of the message). + i.WriteHtonU16 (4 + lm.neighborInterfaceAddresses.size () * IPV4_ADDRESS_SIZE); + + for (std::vector::const_iterator neigh_iter = lm.neighborInterfaceAddresses.begin (); + neigh_iter != lm.neighborInterfaceAddresses.end (); neigh_iter++) + { + i.WriteHtonU32 (neigh_iter->GetHostOrder ()); + } + } +} + +uint32_t +OlsrMessageHeader::Hello::Deserialize (Buffer::Iterator start, uint32_t messageSize) +{ + Buffer::Iterator i = start; + + NS_ASSERT (messageSize >= 4); + + this->linkMessages.clear (); + + uint16_t helloSizeLeft = messageSize; + + i.ReadNtohU16 (); // Reserved + this->hTime = i.ReadU8 (); + this->willingness = i.ReadU8 (); + + helloSizeLeft -= 4; + + while (helloSizeLeft) + { + LinkMessage lm; + NS_ASSERT (helloSizeLeft >= 4); + lm.linkCode = i.ReadU8 (); + i.ReadU8 (); // Reserved + uint16_t lmSize = i.ReadNtohU16 (); + NS_ASSERT ((lmSize - 4) % IPV4_ADDRESS_SIZE == 0); + for (int n = (lmSize - 4) / IPV4_ADDRESS_SIZE; n; --n) + { + lm.neighborInterfaceAddresses.push_back (Ipv4Address (i.ReadNtohU32 ())); + } + helloSizeLeft -= lmSize; + this->linkMessages.push_back (lm); + } + + return messageSize; +} + + + +// ---------------- OLSR TC Message ------------------------------- + +uint32_t +OlsrMessageHeader::Tc::GetSerializedSize (void) const +{ + return 4 + this->neighborAddresses.size () * IPV4_ADDRESS_SIZE; +} + +void +OlsrMessageHeader::Tc::Print (std::ostream &os) const +{ + // TODO +} + +void +OlsrMessageHeader::Tc::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + i.WriteHtonU16 (this->ansn); + i.WriteHtonU16 (0); // Reserved + + for (std::vector::const_iterator iter = this->neighborAddresses.begin (); + iter != this->neighborAddresses.end (); iter++) + { + i.WriteHtonU32 (iter->GetHostOrder ()); + } +} + +uint32_t +OlsrMessageHeader::Tc::Deserialize (Buffer::Iterator start, uint32_t messageSize) +{ + Buffer::Iterator i = start; + + this->neighborAddresses.clear (); + NS_ASSERT (messageSize >= 4); + + this->ansn = i.ReadNtohU16 (); + i.ReadNtohU16 (); // Reserved + + NS_ASSERT ((messageSize - 4) % IPV4_ADDRESS_SIZE == 0); + int numAddresses = (messageSize - 4) / IPV4_ADDRESS_SIZE; + this->neighborAddresses.clear (); + for (int n = 0; n < numAddresses; ++n) + this->neighborAddresses.push_back (Ipv4Address (i.ReadNtohU32 ())); + + return messageSize; +} + + +// ---------------- OLSR HNA Message ------------------------------- + +uint32_t +OlsrMessageHeader::Hna::GetSerializedSize (void) const +{ + return 2*this->associations.size () * IPV4_ADDRESS_SIZE; +} + +void +OlsrMessageHeader::Hna::Print (std::ostream &os) const +{ + // TODO +} + +void +OlsrMessageHeader::Hna::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + for (size_t n = 0; n < this->associations.size (); ++n) + { + i.WriteHtonU32 (this->associations[n].address.GetHostOrder ()); + i.WriteHtonU32 (this->associations[n].mask.GetHostOrder ()); + } +} + +uint32_t +OlsrMessageHeader::Hna::Deserialize (Buffer::Iterator start, uint32_t messageSize) +{ + Buffer::Iterator i = start; + + NS_ASSERT (messageSize % (IPV4_ADDRESS_SIZE*2) == 0); + int numAddresses = messageSize / IPV4_ADDRESS_SIZE / 2; + this->associations.clear (); + for (int n = 0; n < numAddresses; ++n) + { + Ipv4Address address (i.ReadNtohU32 ()); + Ipv4Mask mask (i.ReadNtohU32 ()); + this->associations.push_back ((Association) {address, mask}); + } + return messageSize; +} + + + +}; // namespace ns3 + + +#ifdef RUN_SELF_TESTS + + +#include "ns3/test.h" +#include "ns3/packet.h" +#include + + +namespace ns3 { + +class OlsrHeaderTest : public ns3::Test { +private: +public: + OlsrHeaderTest (); + virtual bool RunTests (void); + + +}; + +OlsrHeaderTest::OlsrHeaderTest () + : ns3::Test ("OlsrHeader") +{} + + +bool +OlsrHeaderTest::RunTests (void) +{ + bool result = true; + + // Testing packet header + message header + MID message + { + Packet packet; + + { + OlsrPacketHeader hdr; + OlsrMessageHeader msg1; + OlsrMessageHeader::Mid &mid1 = msg1.GetMid (); + OlsrMessageHeader msg2; + OlsrMessageHeader::Mid &mid2 = msg2.GetMid (); + + // MID message #1 + { + std::vector &addresses = mid1.interfaceAddresses; + addresses.clear (); + addresses.push_back (Ipv4Address ("1.2.3.4")); + addresses.push_back (Ipv4Address ("1.2.3.5")); + } + + msg1.SetTimeToLive (255); + msg1.SetOriginatorAddress (Ipv4Address ("11.22.33.44")); + msg1.SetVTime (Seconds (9)); + msg1.SetMessageSequenceNumber (7); + + // MID message #2 + { + std::vector &addresses = mid2.interfaceAddresses; + addresses.clear (); + addresses.push_back (Ipv4Address ("2.2.3.4")); + addresses.push_back (Ipv4Address ("2.2.3.5")); + } + + msg2.SetTimeToLive (254); + msg2.SetOriginatorAddress (Ipv4Address ("12.22.33.44")); + msg2.SetVTime (Seconds (10)); + msg2.SetMessageType (OlsrMessageHeader::MID_MESSAGE); + msg2.SetMessageSequenceNumber (7); + + // Build an OLSR packet header + hdr.SetPacketLength (hdr.GetSerializedSize () + msg1.GetSerializedSize () + msg2.GetSerializedSize ()); + hdr.SetPacketSequenceNumber (123); + + + // Now add all the headers in the correct order + packet.AddHeader (msg2); + packet.AddHeader (msg1); + packet.AddHeader (hdr); + } + + { + OlsrPacketHeader hdr; + packet.RemoveHeader (hdr); + NS_TEST_ASSERT_EQUAL (hdr.GetPacketSequenceNumber (), 123); + uint32_t sizeLeft = hdr.GetPacketLength () - hdr.GetSerializedSize (); + { + OlsrMessageHeader msg1; + + packet.RemoveHeader (msg1); + + NS_TEST_ASSERT_EQUAL (msg1.GetTimeToLive (), 255); + NS_TEST_ASSERT_EQUAL (msg1.GetOriginatorAddress (), Ipv4Address ("11.22.33.44")); + NS_TEST_ASSERT_EQUAL (msg1.GetVTime (), Seconds (9)); + NS_TEST_ASSERT_EQUAL (msg1.GetMessageType (), OlsrMessageHeader::MID_MESSAGE); + NS_TEST_ASSERT_EQUAL (msg1.GetMessageSequenceNumber (), 7); + + OlsrMessageHeader::Mid &mid1 = msg1.GetMid (); + NS_TEST_ASSERT_EQUAL (mid1.interfaceAddresses.size (), 2); + NS_TEST_ASSERT_EQUAL (*mid1.interfaceAddresses.begin (), Ipv4Address ("1.2.3.4")); + + sizeLeft -= msg1.GetSerializedSize (); + NS_TEST_ASSERT (sizeLeft > 0); + } + { + // now read the second message + OlsrMessageHeader msg2; + + packet.RemoveHeader (msg2); + + NS_TEST_ASSERT_EQUAL (msg2.GetTimeToLive (), 254); + NS_TEST_ASSERT_EQUAL (msg2.GetOriginatorAddress (), Ipv4Address ("12.22.33.44")); + NS_TEST_ASSERT_EQUAL (msg2.GetVTime (), Seconds (10)); + NS_TEST_ASSERT_EQUAL (msg2.GetMessageType (), OlsrMessageHeader::MID_MESSAGE); + NS_TEST_ASSERT_EQUAL (msg2.GetMessageSequenceNumber (), 7); + + OlsrMessageHeader::Mid mid2 = msg2.GetMid (); + NS_TEST_ASSERT_EQUAL (mid2.interfaceAddresses.size (), 2); + NS_TEST_ASSERT_EQUAL (*mid2.interfaceAddresses.begin (), Ipv4Address ("2.2.3.4")); + + sizeLeft -= msg2.GetSerializedSize (); + NS_TEST_ASSERT_EQUAL (sizeLeft, 0); + } + } + } + + // Test the HELLO message + { + Packet packet; + OlsrMessageHeader msgIn; + OlsrMessageHeader::Hello &helloIn = msgIn.GetHello (); + + helloIn.SetHTime (Seconds (7)); + helloIn.willingness = 66; + + { + OlsrMessageHeader::Hello::LinkMessage lm1; + lm1.linkCode = 2; + lm1.neighborInterfaceAddresses.push_back (Ipv4Address ("1.2.3.4")); + lm1.neighborInterfaceAddresses.push_back (Ipv4Address ("1.2.3.5")); + helloIn.linkMessages.push_back (lm1); + + OlsrMessageHeader::Hello::LinkMessage lm2; + lm2.linkCode = 3; + lm2.neighborInterfaceAddresses.push_back (Ipv4Address ("2.2.3.4")); + lm2.neighborInterfaceAddresses.push_back (Ipv4Address ("2.2.3.5")); + helloIn.linkMessages.push_back (lm2); + } + + packet.AddHeader (msgIn); + + OlsrMessageHeader msgOut; + packet.RemoveHeader (msgOut); + OlsrMessageHeader::Hello &helloOut = msgOut.GetHello (); + + NS_TEST_ASSERT_EQUAL (helloOut.GetHTime (), Seconds (7)); + NS_TEST_ASSERT_EQUAL (helloOut.willingness, 66); + NS_TEST_ASSERT_EQUAL (helloOut.linkMessages.size (), 2); + + NS_TEST_ASSERT_EQUAL (helloOut.linkMessages[0].linkCode, 2); + NS_TEST_ASSERT_EQUAL (helloOut.linkMessages[0].neighborInterfaceAddresses[0], + Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (helloOut.linkMessages[0].neighborInterfaceAddresses[1], + Ipv4Address ("1.2.3.5")); + + NS_TEST_ASSERT_EQUAL (helloOut.linkMessages[1].linkCode, 3); + NS_TEST_ASSERT_EQUAL (helloOut.linkMessages[1].neighborInterfaceAddresses[0], + Ipv4Address ("2.2.3.4")); + NS_TEST_ASSERT_EQUAL (helloOut.linkMessages[1].neighborInterfaceAddresses[1], + Ipv4Address ("2.2.3.5")); + + // check that all bytes of the message were read + NS_TEST_ASSERT_EQUAL (packet.GetSize (), 0); + } + + // Test the TC message + { + Packet packet; + OlsrMessageHeader msgIn; + OlsrMessageHeader::Tc &tcIn = msgIn.GetTc (); + + tcIn.ansn = 0x1234; + tcIn.neighborAddresses.push_back (Ipv4Address ("1.2.3.4")); + tcIn.neighborAddresses.push_back (Ipv4Address ("1.2.3.5")); + packet.AddHeader (msgIn); + + OlsrMessageHeader msgOut; + packet.RemoveHeader (msgOut); + OlsrMessageHeader::Tc &tcOut = msgOut.GetTc (); + + NS_TEST_ASSERT_EQUAL (tcOut.ansn, 0x1234); + NS_TEST_ASSERT_EQUAL (tcOut.neighborAddresses.size (), 2); + + NS_TEST_ASSERT_EQUAL (tcOut.neighborAddresses[0], + Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (tcOut.neighborAddresses[1], + Ipv4Address ("1.2.3.5")); + + // check that all bytes of the message were read + NS_TEST_ASSERT_EQUAL (packet.GetSize (), 0); + } + + // Test the HNA message + { + Packet packet; + OlsrMessageHeader msgIn; + OlsrMessageHeader::Hna &hnaIn = msgIn.GetHna (); + + hnaIn.associations.push_back ((OlsrMessageHeader::Hna::Association) + { Ipv4Address ("1.2.3.4"), Ipv4Mask ("255.255.255.0")}); + hnaIn.associations.push_back ((OlsrMessageHeader::Hna::Association) + {Ipv4Address ("1.2.3.5"), Ipv4Mask ("255.255.0.0")}); + packet.AddHeader (msgIn); + + OlsrMessageHeader msgOut; + packet.RemoveHeader (msgOut); + OlsrMessageHeader::Hna &hnaOut = msgOut.GetHna (); + + NS_TEST_ASSERT_EQUAL (hnaOut.associations.size (), 2); + + NS_TEST_ASSERT_EQUAL (hnaOut.associations[0].address, + Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (hnaOut.associations[0].mask, + Ipv4Mask ("255.255.255.0")); + + NS_TEST_ASSERT_EQUAL (hnaOut.associations[1].address, + Ipv4Address ("1.2.3.5")); + NS_TEST_ASSERT_EQUAL (hnaOut.associations[1].mask, + Ipv4Mask ("255.255.0.0")); + + // check that all bytes of the message were read + NS_TEST_ASSERT_EQUAL (packet.GetSize (), 0); + } + + for (int time = 1; time <= 30; time++) + { + uint8_t emf = OlsrSecondsToEmf (time); + double seconds = OlsrEmfToSeconds (emf); + if (seconds < 0 || fabs (seconds - time) > 0.1) + { + result = false; + Failure () << "In " << time << " out " << seconds << std::endl; + } + } + + return result; +} + +static OlsrHeaderTest gOlsrHeaderTest; + +}; // namespace + + +#endif /* RUN_SELF_TESTS */ diff --git a/src/routing/olsr/olsr-header.h b/src/routing/olsr/olsr-header.h new file mode 100644 index 000000000..c95b986df --- /dev/null +++ b/src/routing/olsr/olsr-header.h @@ -0,0 +1,440 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INESC Porto + * + * 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: Gustavo J. A. M. Carneiro + */ + +#ifndef OLSR_HEADER_H +#define OLSR_HEADER_H + +#include +#include +#include "ns3/header.h" +#include "ns3/ipv4-address.h" +#include "ns3/nstime.h" + + +namespace ns3 { + + +double OlsrEmfToSeconds (uint8_t emf); +uint8_t OlsrSecondsToEmf (double seconds); + +// 3.3. Packet Format +// +// The basic layout of any packet in OLSR is as follows (omitting IP and +// UDP headers): +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Packet Length | Packet Sequence Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Message Type | Vtime | Message Size | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Originator Address | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Time To Live | Hop Count | Message Sequence Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// : MESSAGE : +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Message Type | Vtime | Message Size | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Originator Address | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Time To Live | Hop Count | Message Sequence Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// : MESSAGE : +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : : +// (etc.) +class OlsrPacketHeader : public Header +{ +public: + OlsrPacketHeader (); + virtual ~OlsrPacketHeader (); + + void SetPacketLength (uint16_t length) + { + m_packetLength = length; + } + uint16_t GetPacketLength () const + { + return m_packetLength; + } + + void SetPacketSequenceNumber (uint16_t seqnum) + { + m_packetSequenceNumber = seqnum; + } + uint16_t GetPacketSequenceNumber () const + { + return m_packetSequenceNumber; + } + +private: + uint16_t m_packetLength; + uint16_t m_packetSequenceNumber; + +public: + static uint32_t GetUid (void); + virtual void Print (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + virtual std::string GetName (void) const { return "OlsrPacket"; } +}; + + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Message Type | Vtime | Message Size | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Originator Address | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Time To Live | Hop Count | Message Sequence Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +class OlsrMessageHeader : public Header +{ +public: + + enum MessageType { + HELLO_MESSAGE = 1, + TC_MESSAGE = 2, + MID_MESSAGE = 3, + HNA_MESSAGE = 4, + }; + + OlsrMessageHeader (); + virtual ~OlsrMessageHeader (); + + void SetMessageType (MessageType messageType) + { + m_messageType = messageType; + } + MessageType GetMessageType () const + { + return m_messageType; + } + + void SetVTime (Time time) + { + m_vTime = OlsrSecondsToEmf (time.GetSeconds ()); + } + Time GetVTime () const + { + return Seconds (OlsrEmfToSeconds (m_vTime)); + } + + void SetOriginatorAddress (Ipv4Address originatorAddress) + { + m_originatorAddress = originatorAddress; + } + Ipv4Address GetOriginatorAddress () const + { + return m_originatorAddress; + } + + void SetTimeToLive (uint8_t timeToLive) + { + m_timeToLive = timeToLive; + } + uint8_t GetTimeToLive () const + { + return m_timeToLive; + } + + void SetHopCount (uint8_t hopCount) + { + m_hopCount = hopCount; + } + uint8_t GetHopCount () const + { + return m_hopCount; + } + + void SetMessageSequenceNumber (uint16_t messageSequenceNumber) + { + m_messageSequenceNumber = messageSequenceNumber; + } + uint16_t GetMessageSequenceNumber () const + { + return m_messageSequenceNumber; + } + +// void SetMessageSize (uint16_t messageSize) +// { +// m_messageSize = messageSize; +// } +// uint16_t GetMessageSize () const +// { +// return m_messageSize; +// } + +private: + MessageType m_messageType; + uint8_t m_vTime; + Ipv4Address m_originatorAddress; + uint8_t m_timeToLive; + uint8_t m_hopCount; + uint16_t m_messageSequenceNumber; + uint16_t m_messageSize; + +public: + static uint32_t GetUid (void); + virtual void Print (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + virtual std::string GetName (void) const { return "OlsrMessage"; } + + // 5.1. MID Message Format + // + // The proposed format of a MID message is as follows: + // + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | OLSR Interface Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | OLSR Interface Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ... | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + struct Mid + { + std::vector interfaceAddresses; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start, uint32_t messageSize); + }; + + // 6.1. HELLO Message Format + // + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Reserved | Htime | Willingness | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Link Code | Reserved | Link Message Size | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Neighbor Interface Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Neighbor Interface Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // : . . . : + // : : + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Link Code | Reserved | Link Message Size | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Neighbor Interface Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Neighbor Interface Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // : : + // : : + // (etc.) + struct Hello + { + struct LinkMessage { + uint8_t linkCode; + std::vector neighborInterfaceAddresses; + }; + + uint8_t hTime; + void SetHTime (Time time) + { + this->hTime = OlsrSecondsToEmf (time.GetSeconds ()); + } + Time GetHTime () const + { + return Seconds (OlsrEmfToSeconds (this->hTime)); + } + + uint8_t willingness; + std::vector linkMessages; + + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start, uint32_t messageSize); + }; + + // 9.1. TC Message Format + // + // The proposed format of a TC message is as follows: + // + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ANSN | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Advertised Neighbor Main Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Advertised Neighbor Main Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ... | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + struct Tc + { + std::vector neighborAddresses; + uint16_t ansn; + + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start, uint32_t messageSize); + }; + + + // 12.1. HNA Message Format + // + // The proposed format of an HNA-message is: + // + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Network Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Netmask | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Network Address | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Netmask | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ... | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // Note: HNA stands for Host Network Association + struct Hna + { + struct Association + { + Ipv4Address address; + Ipv4Mask mask; + }; + std::vector associations; + + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start, uint32_t messageSize); + }; + +private: + struct + { + Mid mid; + Hello hello; + Tc tc; + Hna hna; + } m_message; // union not allowed + +public: + + Mid& GetMid () + { + if (m_messageType == 0) + { + m_messageType = MID_MESSAGE; + } + else + { + NS_ASSERT (m_messageType == MID_MESSAGE); + } + return m_message.mid; + } + + Hello& GetHello () + { + if (m_messageType == 0) + { + m_messageType = HELLO_MESSAGE; + } + else + { + NS_ASSERT (m_messageType == HELLO_MESSAGE); + } + return m_message.hello; + } + + Tc& GetTc () + { + if (m_messageType == 0) + { + m_messageType = TC_MESSAGE; + } + else + { + NS_ASSERT (m_messageType == TC_MESSAGE); + } + return m_message.tc; + } + + Hna& GetHna () + { + if (m_messageType == 0) + { + m_messageType = HNA_MESSAGE; + } + else + { + NS_ASSERT (m_messageType == HNA_MESSAGE); + } + return m_message.hna; + } + + + const Mid& GetMid () const + { + NS_ASSERT (m_messageType == MID_MESSAGE); + return m_message.mid; + } + + const Hello& GetHello () const + { + NS_ASSERT (m_messageType == HELLO_MESSAGE); + return m_message.hello; + } + + const Tc& GetTc () const + { + NS_ASSERT (m_messageType == TC_MESSAGE); + return m_message.tc; + } + + const Hna& GetHna () const + { + NS_ASSERT (m_messageType == HNA_MESSAGE); + return m_message.hna; + } + + +}; + +}; // namespace ns3 + +#endif /* OLSR_HEADER_H */ + diff --git a/src/routing/olsr/olsr-state.cc b/src/routing/olsr/olsr-state.cc new file mode 100644 index 000000000..519e9633e --- /dev/null +++ b/src/routing/olsr/olsr-state.cc @@ -0,0 +1,436 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2004 Francisco J. Ros + * Copyright (c) 2007 INESC Porto + * + * 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: Francisco J. Ros + * Gustavo J. A. M. Carneiro + */ + +/// +/// \file OlsrState.cc +/// \brief Implementation of all functions needed for manipulating the internal +/// state of an OLSR node. +/// + +#include "olsr-state.h" + + +namespace ns3 { + + +/********** MPR Selector Set Manipulation **********/ + +MprSelectorTuple* +OlsrState::FindMprSelectorTuple (Ipv4Address const &mainAddr) +{ + for (MprSelectorSet::iterator it = m_mprSelectorSet.begin (); + it != m_mprSelectorSet.end (); it++) + { + if (it->mainAddr == mainAddr) + return &(*it); + } + return NULL; +} + +void +OlsrState::EraseMprSelectorTuple (const MprSelectorTuple &tuple) +{ + for (MprSelectorSet::iterator it = m_mprSelectorSet.begin (); + it != m_mprSelectorSet.end (); it++) + { + if (*it == tuple) + { + m_mprSelectorSet.erase (it); + break; + } + } +} + +void +OlsrState::EraseMprSelectorTuples (const Ipv4Address &mainAddr) +{ + for (MprSelectorSet::iterator it = m_mprSelectorSet.begin (); + it != m_mprSelectorSet.end (); it++) + { + if (it->mainAddr == mainAddr) + { + it = m_mprSelectorSet.erase (it); + it--; + } + } +} + +void +OlsrState::InsertMprSelectorTuple (MprSelectorTuple const &tuple) +{ + m_mprSelectorSet.push_back (tuple); +} + +/********** Neighbor Set Manipulation **********/ + +NeighborTuple* +OlsrState::FindNeighborTuple (Ipv4Address const &mainAddr) +{ + for (NeighborSet::iterator it = m_neighborSet.begin (); + it != m_neighborSet.end (); it++) + { + if (it->neighborMainAddr == mainAddr) + return &(*it); + } + return NULL; +} + +NeighborTuple* +OlsrState::FindSymNeighborTuple (Ipv4Address const &mainAddr) +{ + for (NeighborSet::iterator it = m_neighborSet.begin (); + it != m_neighborSet.end (); it++) + { + if (it->neighborMainAddr == mainAddr && it->status == NeighborTuple::STATUS_SYM) + return &(*it); + } + return NULL; +} + +NeighborTuple* +OlsrState::FindNeighborTuple (Ipv4Address const &mainAddr, uint8_t willingness) +{ + for (NeighborSet::iterator it = m_neighborSet.begin (); + it != m_neighborSet.end (); it++) + { + if (it->neighborMainAddr == mainAddr && it->willingness == willingness) + return &(*it); + } + return NULL; +} + +void +OlsrState::EraseNeighborTuple (const NeighborTuple &tuple) +{ + for (NeighborSet::iterator it = m_neighborSet.begin (); + it != m_neighborSet.end (); it++) + { + if (*it == tuple) + { + m_neighborSet.erase (it); + break; + } + } +} + +void +OlsrState::EraseNeighborTuple (const Ipv4Address &mainAddr) +{ + for (NeighborSet::iterator it = m_neighborSet.begin (); + it != m_neighborSet.end (); it++) + { + if (it->neighborMainAddr == mainAddr) + { + it = m_neighborSet.erase (it); + break; + } + } +} + +void +OlsrState::InsertNeighborTuple (NeighborTuple const &tuple) +{ + m_neighborSet.push_back (tuple); +} + +/********** Neighbor 2 Hop Set Manipulation **********/ + +TwoHopNeighborTuple* +OlsrState::FindTwoHopNeighborTuple (Ipv4Address const &neighborMainAddr, + Ipv4Address const &twoHopNeighborAddr) +{ + for (TwoHopNeighborSet::iterator it = m_twoHopNeighborSet.begin (); + it != m_twoHopNeighborSet.end (); it++) + { + if (it->neighborMainAddr == neighborMainAddr + && it->twoHopNeighborAddr == twoHopNeighborAddr) + { + return &(*it); + } + } + return NULL; +} + +void +OlsrState::EraseTwoHopNeighborTuple (const TwoHopNeighborTuple &tuple) +{ + for (TwoHopNeighborSet::iterator it = m_twoHopNeighborSet.begin (); + it != m_twoHopNeighborSet.end (); it++) + { + if (*it == tuple) + { + m_twoHopNeighborSet.erase(it); + break; + } + } +} + +void +OlsrState::EraseTwoHopNeighborTuples (const Ipv4Address &neighborMainAddr, + const Ipv4Address &twoHopNeighborAddr) +{ + for (TwoHopNeighborSet::iterator it = m_twoHopNeighborSet.begin (); + it != m_twoHopNeighborSet.end (); it++) + { + if (it->neighborMainAddr == neighborMainAddr + && it->twoHopNeighborAddr == twoHopNeighborAddr) + { + it = m_twoHopNeighborSet.erase (it); + it--; // FIXME: is this correct in the case 'it' pointed to the first element? + } + } +} + +void +OlsrState::EraseTwoHopNeighborTuples (const Ipv4Address &neighborMainAddr) +{ + for (TwoHopNeighborSet::iterator it = m_twoHopNeighborSet.begin (); + it != m_twoHopNeighborSet.end (); it++) + { + if (it->neighborMainAddr == neighborMainAddr) { + it = m_twoHopNeighborSet.erase (it); + it--; + } + } +} + +void +OlsrState::InsertTwoHopNeighborTuple (TwoHopNeighborTuple const &tuple){ + m_twoHopNeighborSet.push_back (tuple); +} + +/********** MPR Set Manipulation **********/ + +bool +OlsrState::FindMprAddress (Ipv4Address const &addr) +{ + MprSet::iterator it = m_mprSet.find (addr); + return (it != m_mprSet.end ()); +} + +void +OlsrState::InsertMprAddress (Ipv4Address const & addr) +{ + m_mprSet.insert (addr); +} + +void +OlsrState::ClearMprSet () +{ + m_mprSet.clear (); +} + +/********** Duplicate Set Manipulation **********/ + +DuplicateTuple* +OlsrState::FindDuplicateTuple (Ipv4Address const &addr, uint16_t sequenceNumber) +{ + for (DuplicateSet::iterator it = m_duplicateSet.begin (); + it != m_duplicateSet.end(); it++) + { + if (it->address == addr && it->sequenceNumber == sequenceNumber) + return &(*it); + } + return NULL; +} + +void +OlsrState::EraseDuplicateTuple (const DuplicateTuple &tuple) +{ + for (DuplicateSet::iterator it = m_duplicateSet.begin (); + it != m_duplicateSet.end (); it++) + { + if (*it == tuple) + { + m_duplicateSet.erase (it); + break; + } + } +} + +void +OlsrState::InsertDuplicateTuple (DuplicateTuple const &tuple) +{ + m_duplicateSet.push_back (tuple); +} + +/********** Link Set Manipulation **********/ + +LinkTuple* +OlsrState::FindLinkTuple (Ipv4Address const & ifaceAddr) +{ + for (LinkSet::iterator it = m_linkSet.begin (); + it != m_linkSet.end (); it++) + { + if (it->neighborIfaceAddr == ifaceAddr) + return &(*it); + } + return NULL; +} + +LinkTuple* +OlsrState::FindSymLinkTuple (Ipv4Address const &ifaceAddr, Time now) +{ + for (LinkSet::iterator it = m_linkSet.begin (); + it != m_linkSet.end (); it++) + { + if (it->neighborIfaceAddr == ifaceAddr) + { + if (it->symTime > now) + return &(*it); + else + break; + } + } + return NULL; +} + +void +OlsrState::EraseLinkTuple (const LinkTuple &tuple) +{ + for (LinkSet::iterator it = m_linkSet.begin (); + it != m_linkSet.end (); it++) + { + if (*it == tuple) + { + m_linkSet.erase (it); + break; + } + } +} + +LinkTuple& +OlsrState::InsertLinkTuple (LinkTuple const &tuple) +{ + m_linkSet.push_back (tuple); + return m_linkSet.back (); +} + +/********** Topology Set Manipulation **********/ + +TopologyTuple* +OlsrState::FindTopologyTuple (Ipv4Address const &destAddr, + Ipv4Address const &lastAddr) +{ + for (TopologySet::iterator it = m_topologySet.begin (); + it != m_topologySet.end (); it++) + { + if (it->destAddr == destAddr && it->lastAddr == lastAddr) + return &(*it); + } + return NULL; +} + +TopologyTuple* +OlsrState::FindNewerTopologyTuple (Ipv4Address const & lastAddr, uint16_t ansn) +{ + for (TopologySet::iterator it = m_topologySet.begin (); + it != m_topologySet.end (); it++) + { + if (it->lastAddr == lastAddr && it->sequenceNumber > ansn) + return &(*it); + } + return NULL; +} + +void +OlsrState::EraseTopologyTuple(const TopologyTuple &tuple) +{ + for (TopologySet::iterator it = m_topologySet.begin (); + it != m_topologySet.end (); it++) + { + if (*it == tuple) + { + m_topologySet.erase (it); + break; + } + } +} + +void +OlsrState::EraseOlderTopologyTuples (const Ipv4Address &lastAddr, uint16_t ansn) +{ + for (TopologySet::iterator it = m_topologySet.begin(); + it != m_topologySet.end(); it++) + { + if (it->lastAddr == lastAddr && it->sequenceNumber < ansn) + { + it = m_topologySet.erase (it); + it--; + } + } +} + +void +OlsrState::InsertTopologyTuple (TopologyTuple const &tuple) +{ + m_topologySet.push_back (tuple); +} + +/********** Interface Association Set Manipulation **********/ + +IfaceAssocTuple* +OlsrState::FindIfaceAssocTuple (Ipv4Address const &ifaceAddr) +{ + for (IfaceAssocSet::iterator it = m_ifaceAssocSet.begin (); + it != m_ifaceAssocSet.end (); it++) + { + if (it->ifaceAddr == ifaceAddr) + return &(*it); + } + return NULL; +} + +void +OlsrState::EraseIfaceAssocTuple (const IfaceAssocTuple &tuple) +{ + for (IfaceAssocSet::iterator it = m_ifaceAssocSet.begin (); + it != m_ifaceAssocSet.end (); it++) + { + if (*it == tuple) + { + m_ifaceAssocSet.erase (it); + break; + } + } +} + +void +OlsrState::InsertIfaceAssocTuple (const IfaceAssocTuple &tuple) +{ + m_ifaceAssocSet.push_back (tuple); +} + +std::vector +OlsrState::FindNeighborInterfaces (const Ipv4Address &neighborMainAddr) const +{ + std::vector retval; + for (IfaceAssocSet::const_iterator it = m_ifaceAssocSet.begin (); + it != m_ifaceAssocSet.end (); it++) + { + if (it->mainAddr == neighborMainAddr) + retval.push_back (it->ifaceAddr); + } + return retval; +} + +} // namespace ns3 diff --git a/src/routing/olsr/olsr-state.h b/src/routing/olsr/olsr-state.h new file mode 100644 index 000000000..d7788a572 --- /dev/null +++ b/src/routing/olsr/olsr-state.h @@ -0,0 +1,144 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2004 Francisco J. Ros + * Copyright (c) 2007 INESC Porto + * + * 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: Francisco J. Ros + * Gustavo J. A. M. Carneiro + */ + +/// \brief This header file declares and defines internal state of an OLSR node. + +#ifndef __OLSR_STATE_H__ +#define __OLSR_STATE_H__ + +#include "repositories.h" + +namespace ns3 { + +using namespace olsr; + +/// This class encapsulates all data structures needed for maintaining internal state of an OLSR node. +class OlsrState +{ + // friend class Olsr; + +protected: + LinkSet m_linkSet; ///< Link Set (RFC 3626, section 4.2.1). + NeighborSet m_neighborSet; ///< Neighbor Set (RFC 3626, section 4.3.1). + TwoHopNeighborSet m_twoHopNeighborSet; ///< 2-hop Neighbor Set (RFC 3626, section 4.3.2). + TopologySet m_topologySet; ///< Topology Set (RFC 3626, section 4.4). + MprSet m_mprSet; ///< MPR Set (RFC 3626, section 4.3.3). + MprSelectorSet m_mprSelectorSet; ///< MPR Selector Set (RFC 3626, section 4.3.4). + DuplicateSet m_duplicateSet; ///< Duplicate Set (RFC 3626, section 3.4). + IfaceAssocSet m_ifaceAssocSet; ///< Interface Association Set (RFC 3626, section 4.1). + +public: + + // MPR selector + const MprSelectorSet & GetMprSelectors () const + { + return m_mprSelectorSet; + } + MprSelectorTuple* FindMprSelectorTuple (const Ipv4Address &mainAddr); + void EraseMprSelectorTuple (const MprSelectorTuple &tuple); + void EraseMprSelectorTuples (const Ipv4Address &mainAddr); + void InsertMprSelectorTuple (const MprSelectorTuple &tuple); + + // Neighbor + const NeighborSet & GetNeighbors () const + { + return m_neighborSet; + } + NeighborTuple* FindNeighborTuple (const Ipv4Address &mainAddr); + NeighborTuple* FindSymNeighborTuple (const Ipv4Address &mainAddr); + NeighborTuple* FindNeighborTuple (const Ipv4Address &mainAddr, + uint8_t willingness); + void EraseNeighborTuple (const NeighborTuple &neighborTuple); + void EraseNeighborTuple (const Ipv4Address &mainAddr); + void InsertNeighborTuple (const NeighborTuple &tuple); + + // Two-hop neighbor + const TwoHopNeighborSet & GetTwoHopNeighbors () const + { + return m_twoHopNeighborSet; + } + TwoHopNeighborTuple* FindTwoHopNeighborTuple (const Ipv4Address &neighbor, + const Ipv4Address &twoHopNeighbor); + void EraseTwoHopNeighborTuple (const TwoHopNeighborTuple &tuple); + void EraseTwoHopNeighborTuples (const Ipv4Address &neighbor); + void EraseTwoHopNeighborTuples (const Ipv4Address &neighbor, + const Ipv4Address &twoHopNeighbor); + void InsertTwoHopNeighborTuple (const TwoHopNeighborTuple &tuple); + + // MPR + bool FindMprAddress (const Ipv4Address &address); + void InsertMprAddress (const Ipv4Address &address); + void ClearMprSet (); + + // Duplicate + DuplicateTuple* FindDuplicateTuple (const Ipv4Address &address, + uint16_t sequenceNumber); + void EraseDuplicateTuple (const DuplicateTuple &tuple); + void InsertDuplicateTuple (const DuplicateTuple &tuple); + + // Link + const LinkSet & GetLinks () const + { + return m_linkSet; + } + LinkTuple* FindLinkTuple (const Ipv4Address &ifaceAddr); + LinkTuple* FindSymLinkTuple (const Ipv4Address &ifaceAddr, Time time); + void EraseLinkTuple (const LinkTuple &tuple); + LinkTuple& InsertLinkTuple (const LinkTuple &tuple); + + // Topology + const TopologySet & GetTopologySet () const + { + return m_topologySet; + } + TopologyTuple* FindTopologyTuple (const Ipv4Address &destAddr, + const Ipv4Address &lastAddr); + TopologyTuple* FindNewerTopologyTuple (const Ipv4Address &lastAddr, + uint16_t ansn); + void EraseTopologyTuple (const TopologyTuple &tuple); + void EraseOlderTopologyTuples (const Ipv4Address &lastAddr, + uint16_t ansn); + void InsertTopologyTuple (const TopologyTuple &tuple); + + // Interface association + const IfaceAssocSet & GetIfaceAssocSet () const + { + return m_ifaceAssocSet; + } + IfaceAssocSet & GetIfaceAssocSetMutable () + { + return m_ifaceAssocSet; + } + IfaceAssocTuple* FindIfaceAssocTuple (const Ipv4Address &ifaceAddr); + void EraseIfaceAssocTuple (const IfaceAssocTuple &tuple); + void InsertIfaceAssocTuple (const IfaceAssocTuple &tuple); + + // Returns a vector of all interfaces of a given neighbor, with the + // exception of the "main" one. + std::vector + FindNeighborInterfaces (const Ipv4Address &neighborMainAddr) const; + +}; + +} // namespace ns3 + +#endif diff --git a/src/routing/olsr/olsr.cc b/src/routing/olsr/olsr.cc new file mode 100644 index 000000000..dbcb6dfba --- /dev/null +++ b/src/routing/olsr/olsr.cc @@ -0,0 +1,42 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INESC Porto + * + * 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: Gustavo J. A. M. Carneiro + */ + +#include "olsr-agent.h" +#include "olsr.h" + +namespace ns3 { namespace olsr { + + +void +EnableAllNodes (void) +{ + EnableNodes (NodeList::Begin (), NodeList::End ()); +} + +void +EnableNode (Ptr node) +{ + ComponentManager::Create > + (OlsrAgent::cid, OlsrAgent::iid, node)->Start (); +} + + +}} // namespace ns3, olsr + diff --git a/src/routing/olsr/olsr.h b/src/routing/olsr/olsr.h new file mode 100644 index 000000000..1ba19c02d --- /dev/null +++ b/src/routing/olsr/olsr.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INESC Porto + * + * 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: Gustavo J. A. M. Carneiro + */ + +#ifndef OLSR_H +#define OLSR_H + +#include "ns3/node-list.h" + +namespace ns3 +{ + /** + * \namespace ns3::olsr + * \brief Includes a set of utility functions to enable OLSR on + * certain nodes with default parameters. For finer grained control + * of OLSR parameters, see OlsrAgent. + */ + namespace olsr + { + /// \brief Start the OLSR routing agent on all nodes + void EnableAllNodes (void); + + /// \brief Start the OLSR routing agent on a given list of nodes + template + void EnableNodes (InputIterator begin, InputIterator end); + + /// \brief Start the OLSR routing agent on the given node + void EnableNode (Ptr node); + } +} + + +// implementation +namespace ns3 +{ + namespace olsr + { + template + void EnableNodes (InputIterator begin, InputIterator end) + { + for (InputIterator i = begin; i != end; i++) + { + EnableNode (*i); + } + } + } +} + + +#endif /* OLSR_H */ diff --git a/src/routing/olsr/repositories.h b/src/routing/olsr/repositories.h new file mode 100644 index 000000000..d1e2101bf --- /dev/null +++ b/src/routing/olsr/repositories.h @@ -0,0 +1,198 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2004 Francisco J. Ros + * Copyright (c) 2007 INESC Porto + * + * 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: Francisco J. Ros + * Gustavo J. A. M. Carneiro + */ + +/// +/// \file OLSR_repositories.h +/// \brief Here are defined all data structures needed by an OLSR node. +/// + +#ifndef __OLSR_REPOSITORIES_H__ +#define __OLSR_REPOSITORIES_H__ + +#include +#include + +#include "ns3/ipv4-address.h" +#include "ns3/nstime.h" + +namespace ns3 { namespace olsr { + + + +/// An Interface Association Tuple. +struct IfaceAssocTuple +{ + /// Interface address of a node. + Ipv4Address ifaceAddr; + /// Main address of the node. + Ipv4Address mainAddr; + /// Time at which this tuple expires and must be removed. + Time time; +}; + +static inline bool +operator == (const IfaceAssocTuple &a, const IfaceAssocTuple &b) +{ + return (a.ifaceAddr == b.ifaceAddr + && a.mainAddr == b.mainAddr); +} + +/// A Link Tuple. +struct LinkTuple +{ + /// Interface address of the local node. + Ipv4Address localIfaceAddr; + /// Interface address of the neighbor node. + Ipv4Address neighborIfaceAddr; + /// The link is considered bidirectional until this time. + Time symTime; + /// The link is considered unidirectional until this time. + Time asymTime; + /// The link is considered lost until this time (used for link layer notification). + Time lostTime; + /// Time at which this tuple expires and must be removed. + Time time; +}; + +static inline bool +operator == (const LinkTuple &a, const LinkTuple &b) +{ + return (a.localIfaceAddr == b.localIfaceAddr + && a.neighborIfaceAddr == b.neighborIfaceAddr); +} + +/// A Neighbor Tuple. +struct NeighborTuple +{ + /// Main address of a neighbor node. + Ipv4Address neighborMainAddr; + /// Neighbor Type and Link Type at the four less significative digits. + enum Status { + STATUS_NOT_SYM = 0, // "not symmetric" + STATUS_SYM = 1, // "symmetric" + } status; + /// A value between 0 and 7 specifying the node's willingness to carry traffic on behalf of other nodes. + uint8_t willingness; +}; + +static inline bool +operator == (const NeighborTuple &a, const NeighborTuple &b) +{ + return (a.neighborMainAddr == b.neighborMainAddr + && a.status == b.status + && a.willingness == b.willingness); +} + +/// A 2-hop Tuple. +struct TwoHopNeighborTuple +{ + /// Main address of a neighbor. + Ipv4Address neighborMainAddr; + /// Main address of a 2-hop neighbor with a symmetric link to nb_main_addr. + Ipv4Address twoHopNeighborAddr; + /// Time at which this tuple expires and must be removed. + Time expirationTime; // previously called 'time_' +}; + +static inline bool +operator == (const TwoHopNeighborTuple &a, const TwoHopNeighborTuple &b) +{ + return (a.neighborMainAddr == b.neighborMainAddr + && a.twoHopNeighborAddr == b.twoHopNeighborAddr); +} + +/// An MPR-Selector Tuple. +struct MprSelectorTuple +{ + /// Main address of a node which have selected this node as a MPR. + Ipv4Address mainAddr; + /// Time at which this tuple expires and must be removed. + Time expirationTime; // previously called 'time_' +}; + +static inline bool +operator == (const MprSelectorTuple &a, const MprSelectorTuple &b) +{ + return (a.mainAddr == b.mainAddr); +} + + +/// The type "list of interface addresses" +//typedef std::vector addr_list_t; + +/// A Duplicate Tuple +struct DuplicateTuple +{ + /// Originator address of the message. + Ipv4Address address; + /// Message sequence number. + uint16_t sequenceNumber; + /// Indicates whether the message has been retransmitted or not. + bool retransmitted; + /// List of interfaces which the message has been received on. + std::vector ifaceList; + /// Time at which this tuple expires and must be removed. + Time expirationTime; +}; + +static inline bool +operator == (const DuplicateTuple &a, const DuplicateTuple &b) +{ + return (a.address == b.address + && a.sequenceNumber == b.sequenceNumber); +} + +/// A Topology Tuple +struct TopologyTuple +{ + /// Main address of the destination. + Ipv4Address destAddr; + /// Main address of a node which is a neighbor of the destination. + Ipv4Address lastAddr; + /// Sequence number. + uint16_t sequenceNumber; + /// Time at which this tuple expires and must be removed. + Time expirationTime; +}; + +static inline bool +operator == (const TopologyTuple &a, const TopologyTuple &b) +{ + return (a.destAddr == b.destAddr + && a.lastAddr == b.lastAddr + && a.sequenceNumber == b.sequenceNumber); +} + + +typedef std::set MprSet; ///< MPR Set type. +typedef std::vector MprSelectorSet; ///< MPR Selector Set type. +typedef std::vector LinkSet; ///< Link Set type. +typedef std::vector NeighborSet; ///< Neighbor Set type. +typedef std::vector TwoHopNeighborSet; ///< 2-hop Neighbor Set type. +typedef std::vector TopologySet; ///< Topology Set type. +typedef std::vector DuplicateSet; ///< Duplicate Set type. +typedef std::vector IfaceAssocSet; ///< Interface Association Set type. + + +}}; // namespace ns3, olsr + +#endif /* __OLSR_REPOSITORIES_H__ */ diff --git a/src/routing/olsr/routing-table.cc b/src/routing/olsr/routing-table.cc new file mode 100644 index 000000000..eb17adaf1 --- /dev/null +++ b/src/routing/olsr/routing-table.cc @@ -0,0 +1,290 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2004 Francisco J. Ros + * Copyright (c) 2007 INESC Porto + * + * 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: Francisco J. Ros + * Gustavo J. A. M. Carneiro + */ + +/// +/// \file OLSR_rtable.cc +/// \brief Implementation of our routing table. +/// + +#include "routing-table.h" +#include "ns3/packet.h" +#include "ns3/ipv4-header.h" +#include "ns3/debug.h" + +namespace ns3 { namespace olsr { + +NS_DEBUG_COMPONENT_DEFINE ("OlsrRoutingTable"); + +/// +/// \brief Clears the routing table and frees the memory assigned to each one of its entries. +/// +void +RoutingTable::Clear () +{ + m_table.clear (); +} + +/// +/// \brief Deletes the entry whose destination address is given. +/// \param dest address of the destination node. +/// +void +RoutingTable::RemoveEntry (Ipv4Address const &dest) +{ + m_table.erase (dest); +} + +/// +/// \brief Looks up an entry for the specified destination address. +/// \param dest destination address. +/// \param outEntry output parameter to hold the routing entry result, if fuond +/// \return true if found, false if not found +/// +bool +RoutingTable::Lookup (Ipv4Address const &dest, + RoutingTableEntry &outEntry) const +{ + // Get the iterator at "dest" position + std::map::const_iterator it = + m_table.find (dest); + // If there is no route to "dest", return NULL + if (it == m_table.end ()) + return false; + outEntry = it->second; + return true; +} + +/// +/// \brief Finds the appropiate entry which must be used in order to forward +/// a data packet to a next hop (given a destination). +/// +/// Imagine a routing table like this: [A,B] [B,C] [C,C]; being each pair of the +/// form [dest addr,next-hop addr]. In this case, if this function is invoked with +/// [A,B] then pair [C,C] is returned because C is the next hop that must be used +/// to forward a data packet destined to A. That is, C is a neighbor of this node, +/// but B isn't. This function finds the appropiate neighbor for forwarding a packet. +/// +/// \param entry the routing table entry which indicates the destination node +/// we are interested in. +/// \return the appropiate routing table entry which indicates the next +/// hop which must be used for forwarding a data packet, or NULL +/// if there is no such entry. +/// +bool +RoutingTable::FindSendEntry (RoutingTableEntry const &entry, + RoutingTableEntry &outEntry) const +{ + outEntry = entry; + while (outEntry.destAddr != outEntry.nextAddr) + { + if (not Lookup(outEntry.nextAddr, outEntry)) + return false; + } + return true; +} + + +bool +RoutingTable::RequestRoute (uint32_t ifIndex, + const Ipv4Header &ipHeader, + Packet packet, + RouteReplyCallback routeReply) +{ + RoutingTableEntry entry1, entry2; + if (Lookup (ipHeader.GetDestination (), entry1)) + { + bool foundSendEntry = FindSendEntry (entry1, entry2); + if (!foundSendEntry) + NS_FATAL_ERROR ("FindSendEntry failure"); + + Ipv4Route route = Ipv4Route::CreateHostRouteTo + (ipHeader.GetDestination (), entry2.nextAddr, entry2.interface); + + NS_DEBUG ("Olsr node" << m_mainAddress + << ": RouteRequest for dest=" << ipHeader.GetDestination () + << " --> destHop=" << entry2.nextAddr + << " interface=" << entry2.interface); + + routeReply (true, route, packet, ipHeader); + return true; + } + else + { + NS_DEBUG ("Olsr node" << m_mainAddress + << ": RouteRequest for dest=" << ipHeader.GetDestination () + << " --> NOT FOUND"); + return false; + } +} + +bool +RoutingTable::RequestIfIndex (Ipv4Address destination, + uint32_t& ifIndex) +{ + RoutingTableEntry entry1, entry2; + if (Lookup (destination, entry1)) + { + bool foundSendEntry = FindSendEntry (entry1, entry2); + if (!foundSendEntry) + NS_FATAL_ERROR ("FindSendEntry failure"); + ifIndex = entry2.interface; + return true; + } + else + { + return false; + } +} + + +/// +/// \brief Adds a new entry into the routing table. +/// +/// If an entry for the given destination existed, it is deleted and freed. +/// +/// \param dest address of the destination node. +/// \param next address of the next hop node. +/// \param iface address of the local interface. +/// \param dist distance to the destination node. +/// +void +RoutingTable::AddEntry (Ipv4Address const &dest, + Ipv4Address const &next, + uint32_t interface, + uint32_t distance) +{ + // Creates a new rt entry with specified values + RoutingTableEntry &entry = m_table[dest]; + + entry.destAddr = dest; + entry.nextAddr = next; + entry.interface = interface; + entry.distance = distance; +} + +void +RoutingTable::AddEntry (Ipv4Address const &dest, + Ipv4Address const &next, + Ipv4Address const &interfaceAddress, + uint32_t distance) +{ + RoutingTableEntry entry; + NS_ASSERT (m_ipv4); + for (uint32_t i = 0; i < m_ipv4->GetNInterfaces (); i++) + { + if (m_ipv4->GetAddress (i) == interfaceAddress) + { + AddEntry (dest, next, i, distance); + return; + } + } + NS_ASSERT (false); // should not be reached + AddEntry (dest, next, 0, distance); +} + + +/// +/// \brief Returns the number of entries in the routing table. +/// \return the number of entries in the routing table. +/// +// u_int32_t +// RoutingTable::size() { +// return rt_.size(); +// } + +}}; // namespace ns3, olsr + + + +#ifdef RUN_SELF_TESTS + + +#include "ns3/test.h" + + +namespace ns3 { namespace olsr { + +class OlsrRoutingTableTest : public ns3::Test { +private: +public: + OlsrRoutingTableTest (); + virtual bool RunTests (void); + + +}; + +OlsrRoutingTableTest::OlsrRoutingTableTest () + : ns3::Test ("OlsrRoutingTable") +{} + + +bool +OlsrRoutingTableTest::RunTests (void) +{ + bool result = true; + + RoutingTable table; + + table.AddEntry (Ipv4Address ("1.2.3.5"), + Ipv4Address ("1.2.3.4"), + 0, + 1); + + table.AddEntry (Ipv4Address ("1.2.3.4"), + Ipv4Address ("1.2.3.4"), + 0, + 1); + + RoutingTableEntry entry1; + NS_TEST_ASSERT (table.Lookup (Ipv4Address ("1.2.3.5"), entry1)); + NS_TEST_ASSERT_EQUAL (entry1.destAddr, Ipv4Address ("1.2.3.5")); + NS_TEST_ASSERT_EQUAL (entry1.nextAddr, Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (entry1.interface, 0); + NS_TEST_ASSERT_EQUAL (entry1.distance, 1); + + RoutingTableEntry entry2; + NS_TEST_ASSERT (table.Lookup (Ipv4Address ("1.2.3.4"), entry2)); + NS_TEST_ASSERT_EQUAL (entry2.destAddr, Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (entry2.nextAddr, Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (entry2.interface, 0); + NS_TEST_ASSERT_EQUAL (entry2.distance, 1); + + RoutingTableEntry sendEntry; + NS_TEST_ASSERT (table.FindSendEntry (entry1, sendEntry)); + NS_TEST_ASSERT_EQUAL (sendEntry.destAddr, Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (sendEntry.nextAddr, Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (sendEntry.interface, 0); + NS_TEST_ASSERT_EQUAL (sendEntry.distance, 1); + + table.RemoveEntry (Ipv4Address ("1.2.3.5")); + RoutingTableEntry removedEntry; + NS_TEST_ASSERT (not table.Lookup (Ipv4Address ("1.2.3.5"), removedEntry)); + + return result; +} + +static OlsrRoutingTableTest gOlsrRoutingTableTest; + +}}; // namespace + + +#endif /* RUN_SELF_TESTS */ diff --git a/src/routing/olsr/routing-table.h b/src/routing/olsr/routing-table.h new file mode 100644 index 000000000..c987106b0 --- /dev/null +++ b/src/routing/olsr/routing-table.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2004 Francisco J. Ros + * Copyright (c) 2007 INESC Porto + * + * 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: Francisco J. Ros + * Gustavo J. A. M. Carneiro + */ + +/// +/// \file OLSR_rtable.h +/// \brief Header file for routing table's related stuff. +/// + +#ifndef __OLSR_RTABLE_H__ +#define __OLSR_RTABLE_H__ + +#include "ns3/ipv4.h" +#include + + +namespace ns3 { namespace olsr { + +/// An %OLSR's routing table entry. +struct RoutingTableEntry +{ + Ipv4Address destAddr; ///< Address of the destination node. + Ipv4Address nextAddr; ///< Address of the next hop. + uint32_t interface; ///< Interface index + uint32_t distance; ///< Distance in hops to the destination. + + RoutingTableEntry () : // default values + destAddr (), nextAddr (), + interface (0), distance (0) {}; +}; + +/// +/// \brief Defines rtable_t as a map of OLSR_rt_entry, whose key is the destination address. +/// +/// The routing table is thus defined as pairs: [dest address, entry]. Each element +/// of the pair can be accesed via "first" and "second" members. +/// +//typedef std::map RoutingTable; + +/// +/// \brief This class is a representation of the OLSR's Routing Table. +/// +class RoutingTable : public Ipv4RoutingProtocol +{ + std::map m_table; ///< Data structure for the routing table. + Ptr m_ipv4; + + Ipv4Address m_mainAddress; // used only for printing debug messages + + void DoDispose () + { + m_ipv4 = 0; + Ipv4RoutingProtocol::DoDispose (); + } + +public: + + RoutingTable () {} + RoutingTable (Ptr ipv4, const Ipv4Address &mainAddress) + : + m_ipv4 (ipv4), + m_mainAddress (mainAddress) + {} + + ~RoutingTable () {} + + void Clear (); + void RemoveEntry (const Ipv4Address &dest); + void AddEntry (const Ipv4Address &dest, + const Ipv4Address &next, + uint32_t interface, + uint32_t distance); + void AddEntry (const Ipv4Address &dest, + const Ipv4Address &next, + const Ipv4Address &interfaceAddress, + uint32_t distance); + bool Lookup (const Ipv4Address &dest, + RoutingTableEntry &outEntry) const; + bool FindSendEntry (const RoutingTableEntry &entry, + RoutingTableEntry &outEntry) const; + + // From Ipv4RoutingProtocol + virtual bool RequestRoute (uint32_t ifIndex, + const Ipv4Header &ipHeader, + Packet packet, + RouteReplyCallback routeReply); + virtual bool RequestIfIndex (Ipv4Address destination, + uint32_t& ifIndex); + +}; + +}}; // namespace ns3, olsr + +#endif diff --git a/src/routing/olsr/wscript b/src/routing/olsr/wscript new file mode 100644 index 000000000..5086cd8fa --- /dev/null +++ b/src/routing/olsr/wscript @@ -0,0 +1,21 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + module = bld.create_ns3_module('olsr', ['internet-node']) + module.includes = '.' + module.source = [ + 'olsr-header.cc', + 'olsr-state.cc', + 'routing-table.cc', + 'olsr-agent.cc', + 'olsr-agent-impl.cc', + 'olsr.cc', + 'event-garbage-collector.cc', + ] + + headers = bld.create_obj('ns3header') + headers.source = [ + 'olsr-agent.h', + 'olsr.h', + ] + diff --git a/src/simulator/timer.cc b/src/simulator/timer.cc index 7569fa2b9..da36e2d13 100644 --- a/src/simulator/timer.cc +++ b/src/simulator/timer.cc @@ -20,7 +20,6 @@ #include "timer.h" #include "simulator.h" #include "simulation-singleton.h" -#include "event-garbage-collector.h" namespace ns3 { @@ -31,16 +30,8 @@ Timer::Timer () m_impl (0) {} -Timer::Timer (enum SchedulePolicy schedulePolicy, - enum DestroyPolicy destroyPolicy) - : m_flags (schedulePolicy | destroyPolicy), - m_delay (FemtoSeconds (0)), - m_event (), - m_impl (0) -{} - -Timer::Timer (enum GarbageCollectPolicy policy) - : m_flags (GARBAGE_COLLECT), +Timer::Timer (enum DestroyPolicy destroyPolicy) + : m_flags (destroyPolicy), m_delay (FemtoSeconds (0)), m_event (), m_impl (0) @@ -149,26 +140,11 @@ void Timer::Schedule (Time delay) { NS_ASSERT (m_impl != 0); - if (m_flags & CHECK_ON_SCHEDULE) + if (m_event.IsRunning ()) { - if (m_event.IsRunning ()) - { - NS_FATAL_ERROR ("Event is still running while re-scheduling."); - } - } - else if (m_flags & CANCEL_ON_SCHEDULE) - { - m_event.Cancel (); - } - else if (m_flags & REMOVE_ON_SCHEDULE) - { - Simulator::Remove (m_event); + NS_FATAL_ERROR ("Event is still running while re-scheduling."); } m_event = m_impl->Schedule (delay); - if (m_flags & GARBAGE_COLLECT) - { - SimulationSingleton::Get ()->Track (m_event); - } } void diff --git a/src/simulator/timer.h b/src/simulator/timer.h index 25e1cc63b..654c80083 100644 --- a/src/simulator/timer.h +++ b/src/simulator/timer.h @@ -43,23 +43,6 @@ class TimerImpl; class Timer { public: - enum SchedulePolicy { - /** - * This policy cancels the event before scheduling a new event - * for each call to Timer::Schedule. - */ - CANCEL_ON_SCHEDULE = (1<<0), - /** - * This policy removes the event from the simulation event list - * before scheduling a new event for each call to Timer::Schedule. - */ - REMOVE_ON_SCHEDULE = (1<<1), - /** - * This policy enforces a check before each call to Timer::Schedule - * to verify that the timer has already expired. - */ - CHECK_ON_SCHEDULE = (1<<2), - }; enum DestroyPolicy { /** * This policy cancels the event from the destructor of the Timer @@ -77,15 +60,6 @@ public: */ CHECK_ON_DESTROY = (1<<5) }; - enum GarbageCollectPolicy { - /** - * Every event scheduled with this policy is kept track of by an - * event garbage collector which makes sure that all events - * of timers with a GARBAGE_COLLECT policy are cancelled at the - * end of the simulation. - */ - GARBAGE_COLLECT = (1<<6) - }; enum State { RUNNING, EXPIRED, @@ -93,21 +67,13 @@ public: }; /** * create a timer with a default event lifetime management policy: - * - CHECK_ON_SCHEDULE * - CHECK_ON_DESTROY */ Timer (); /** - * \param scheduleFlags the event lifetime management policies to use for schedule events * \param destroyFlags the event lifetime management policies to use for destroy events */ - Timer (enum SchedulePolicy schedulePolicy, - enum DestroyPolicy destroyPolicy); - /** - * \param policy the garbage collect policy. Only one - * value is possible. - */ - Timer (enum GarbageCollectPolicy policy); + Timer (enum DestroyPolicy destroyPolicy); ~Timer (); /** diff --git a/src/simulator/wscript b/src/simulator/wscript index c2b9f161e..a4264b4b5 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -61,7 +61,6 @@ def build(bld): 'simulator.cc', 'time-default-value.cc', 'timer.cc', - 'event-garbage-collector.cc', 'watchdog.cc', ] diff --git a/src/wscript b/src/wscript index 759bd3059..32c455b04 100644 --- a/src/wscript +++ b/src/wscript @@ -21,6 +21,7 @@ all_modules = ( 'applications/onoff', 'applications/packet-sink', 'applications/udp-echo', + 'routing/olsr', 'routing/global-routing', 'mobility', 'devices/wifi', diff --git a/tutorial/hello-simulator.cc b/tutorial/hello-simulator.cc index 735d98130..50ded681c 100644 --- a/tutorial/hello-simulator.cc +++ b/tutorial/hello-simulator.cc @@ -15,6 +15,7 @@ */ #include "ns3/log.h" +#include "ns3/debug.h" NS_LOG_COMPONENT_DEFINE ("HelloSimulator"); @@ -23,7 +24,10 @@ using namespace ns3; int main (int argc, char *argv[]) { - LogComponentEnable ("HelloSimulator", LOG_LEVEL_INFO); + DebugComponentEnable ("Log"); + + // LogComponentEnable ("HelloSimulator", + // LogLevel (LOG_LEVEL_INFO | LOG_PREFIX_ALL)); NS_LOG_INFO ("Hello Simulator"); } diff --git a/utils/bench-event-collector.cc b/utils/bench-event-collector.cc new file mode 100644 index 000000000..2e3110476 --- /dev/null +++ b/utils/bench-event-collector.cc @@ -0,0 +1,35 @@ +#include +#include +#include +#include "ns3/event-collector.h" +#include "ns3/simulator.h" + +using namespace ns3; + +void Foo () +{ + +} + +int main (int argc, char *argv[]) +{ + EventCollector events; + + if (argc < 3) + { + std::cerr << "usage: bench-event-collector NUM_EVENTS NUM_REPETITIONS" << std::endl; + return 1; + } + int numEvents = atoi (argv[1]); + int numRepetitions = atoi (argv[2]); + + for (int repetition = 0; repetition < numRepetitions; ++repetition) + { + for (int n = 0; n < numEvents; ++n) + { + events.Track (Simulator::Schedule (Simulator::Now (), Foo)); + } + Simulator::Run (); + } +} + diff --git a/wscript b/wscript index 706014e24..430675d1f 100644 --- a/wscript +++ b/wscript @@ -174,6 +174,10 @@ def build(bld): check_shell() + if Params.g_options.doxygen: + doxygen() + raise SystemExit(0) + # process subfolders from here bld.add_subdirs('src') bld.add_subdirs('samples utils examples tutorial')