From a7089873e9b67bbc270fdb897947506492080b9c Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 26 Jul 2007 12:49:00 +0100 Subject: [PATCH] Add OLSR routing support, (loosely) based on Francisco J. Ros's NS-2 code (University of Murcia). --- examples/simple-p2p-olsr.cc | 198 +++ examples/wscript | 2 + src/routing/olsr/olsr-header.cc | 704 +++++++++ src/routing/olsr/olsr-header.h | 470 ++++++ src/routing/olsr/olsr-private.h | 187 +++ src/routing/olsr/olsr-repositories.h | 200 +++ src/routing/olsr/olsr-state.cc | 438 ++++++ src/routing/olsr/olsr-state.h | 147 ++ src/routing/olsr/olsr.cc | 2135 ++++++++++++++++++++++++++ src/routing/olsr/olsr.h | 45 + src/routing/olsr/routing-table.cc | 270 ++++ src/routing/olsr/routing-table.h | 110 ++ src/routing/olsr/wscript | 19 + src/wscript | 1 + 14 files changed, 4926 insertions(+) create mode 100644 examples/simple-p2p-olsr.cc create mode 100644 src/routing/olsr/olsr-header.cc create mode 100644 src/routing/olsr/olsr-header.h create mode 100644 src/routing/olsr/olsr-private.h create mode 100644 src/routing/olsr/olsr-repositories.h create mode 100644 src/routing/olsr/olsr-state.cc create mode 100644 src/routing/olsr/olsr-state.h create mode 100644 src/routing/olsr/olsr.cc create mode 100644 src/routing/olsr/olsr.h create mode 100644 src/routing/olsr/routing-table.cc create mode 100644 src/routing/olsr/routing-table.h create mode 100644 src/routing/olsr/wscript diff --git a/examples/simple-p2p-olsr.cc b/examples/simple-p2p-olsr.cc new file mode 100644 index 000000000..3a01240e3 --- /dev/null +++ b/examples/simple-p2p-olsr.cc @@ -0,0 +1,198 @@ +/* -*- 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 p2p 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-p2p.tr" + +#include +#include +#include +#include + +#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/p2p-channel.h" +#include "ns3/p2p-net-device.h" +#include "ns3/mac-address.h" +#include "ns3/ipv4-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/p2p-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/debug.h" + +#include "ns3/olsr.h" + +using namespace ns3; + +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 1 +// DebugComponentEnable("Ipv4L3Protocol"); +// DebugComponentEnable("ArpL3Protocol"); +// DebugComponentEnable("OlsrRoutingTable"); +// DebugComponentEnable("Object"); +// DebugComponentEnable("Queue"); +// DebugComponentEnable("DropTailQueue"); +// DebugComponentEnable("Channel"); +// DebugComponentEnable("PointToPointChannel"); +// DebugComponentEnable("PointToPointNetDevice"); +#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 + Bind ("Queue", "DropTailQueue"); + + Bind ("OnOffApplicationPacketSize", "210"); + Bind ("OnOffApplicationDataRate", "448kb/s"); + + //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. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + Ptr n3 = Create (); + + // We create the channels first without any IP addressing information + 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. + 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")); + + + // Run OLSR in each node. + ComponentManager::Create > + (Olsr::cid, Olsr::iid, n0)->Start (); + + ComponentManager::Create > + (Olsr::cid, Olsr::iid, n1)->Start (); + + ComponentManager::Create > + (Olsr::cid, Olsr::iid, n2)->Start (); + + ComponentManager::Create > + (Olsr::cid, Olsr::iid, n3)->Start (); + + +#if 1 + // Create the OnOff application to send UDP datagrams of size + // 210 bytes at a rate of 448 Kb/s + Ptr ooff = Create ( + n0, + Ipv4Address("10.1.3.2"), + 80, + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.0)); + ooff->Stop (Seconds(10.0)); + + // Create a similar flow from n3 to n1, starting at time 1.1 seconds + ooff = Create ( + n3, + Ipv4Address("10.1.2.1"), + 80, + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.1)); + ooff->Stop (Seconds(10.0)); +#endif + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-p2p.tr file +// AsciiTrace asciitrace ("simple-p2p-olsr.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-p2p-olsr.pcap"); + pcaptrace.TraceAllIp (); + + Simulator::StopAt (Seconds (10.0)); + Simulator::Run (); + + Simulator::Destroy (); +} diff --git a/examples/wscript b/examples/wscript index f535ea93f..201a5121f 100644 --- a/examples/wscript +++ b/examples/wscript @@ -10,4 +10,6 @@ def build(bld): return obj obj = create_ns_prog('simple-p2p', 'simple-p2p.cc', deps=['p2p', 'internet-node']) + obj = create_ns_prog('simple-p2p-olsr', 'simple-p2p-olsr.cc', + deps=['p2p', 'internet-node', 'olsr']) diff --git a/src/routing/olsr/olsr-header.cc b/src/routing/olsr/olsr-header.cc new file mode 100644 index 000000000..12061ab74 --- /dev/null +++ b/src/routing/olsr/olsr-header.cc @@ -0,0 +1,704 @@ +/* -*- 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 + * 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::GetSerializedSize (void) const +{ + return OLSR_PKT_HEADER_SIZE; +} + +void +OlsrPacketHeader::PrintTo (std::ostream &os) const +{ + // TODO +} + +void +OlsrPacketHeader::SerializeTo (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteHtonU16 (m_packetLength); + i.WriteHtonU16 (m_packetSequenceNumber); +} + +uint32_t +OlsrPacketHeader::DeserializeFrom (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + m_packetLength = i.ReadNtohU16 (); + m_packetSequenceNumber = i.ReadNtohU16 (); + return GetSerializedSize (); +} + + +// ---------------- OLSR Message ------------------------------- + +OlsrMessageHeader::OlsrMessageHeader () +{} + +OlsrMessageHeader::~OlsrMessageHeader () +{} + +uint32_t +OlsrMessageHeader::GetSerializedSize (void) const +{ + return OLSR_MSG_HEADER_SIZE; +} + +void +OlsrMessageHeader::PrintTo (std::ostream &os) const +{ + // TODO +} + +void +OlsrMessageHeader::SerializeTo (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteU8 (m_messageType); + i.WriteU8 (m_vTime); + i.WriteHtonU16 (m_messageSize); + i.WriteHtonU32 (m_originatorAddress.GetHostOrder ()); + i.WriteU8 (m_timeToLive); + i.WriteU8 (m_hopCount); + i.WriteHtonU16 (m_messageSequenceNumber); +} + +uint32_t +OlsrMessageHeader::DeserializeFrom (Buffer::Iterator start) +{ + 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 (); + return GetSerializedSize (); +} + + +// ---------------- OLSR MID Message ------------------------------- + +OlsrMidMessageHeader::OlsrMidMessageHeader () +{} + +OlsrMidMessageHeader::~OlsrMidMessageHeader () +{} + +uint32_t +OlsrMidMessageHeader::GetSerializedSize (void) const +{ + return m_interfaceAddresses.size () * IPV4_ADDRESS_SIZE; +} + +void +OlsrMidMessageHeader::PrintTo (std::ostream &os) const +{ + // TODO +} + +void +OlsrMidMessageHeader::SerializeTo (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + for (std::vector::const_iterator iter = m_interfaceAddresses.begin (); + iter != m_interfaceAddresses.end (); iter++) + { + i.WriteHtonU32 (iter->GetHostOrder ()); + } +} + +uint32_t +OlsrMidMessageHeader::DeserializeFrom (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + m_interfaceAddresses.clear (); + NS_ASSERT (m_messageSize >= 0); + NS_ASSERT (m_messageSize % IPV4_ADDRESS_SIZE == 0); + + int numAddresses = m_messageSize / IPV4_ADDRESS_SIZE; + m_interfaceAddresses.erase (m_interfaceAddresses.begin(), + m_interfaceAddresses.end ()); + for (int n = 0; n < numAddresses; ++n) + m_interfaceAddresses.push_back (Ipv4Address (i.ReadNtohU32 ())); + return GetSerializedSize (); +} + + + +// ---------------- OLSR HELLO Message ------------------------------- + +OlsrHelloMessageHeader::OlsrHelloMessageHeader () +{} + +OlsrHelloMessageHeader::~OlsrHelloMessageHeader () +{} + +uint32_t +OlsrHelloMessageHeader::GetSerializedSize (void) const +{ + uint32_t size = 4; + for (std::vector::const_iterator iter = m_linkMessages.begin (); + iter != m_linkMessages.end (); iter++) + { + const LinkMessage &lm = *iter; + size += 4; + size += IPV4_ADDRESS_SIZE * lm.neighborInterfaceAddresses.size (); + } + return size; +} + +void +OlsrHelloMessageHeader::PrintTo (std::ostream &os) const +{ + // TODO +} + +void +OlsrHelloMessageHeader::SerializeTo (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + i.WriteU16 (0); // Reserved + i.WriteU8 (m_hTime); + i.WriteU8 (m_willingness); + + for (std::vector::const_iterator iter = m_linkMessages.begin (); + iter != m_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 +OlsrHelloMessageHeader::DeserializeFrom (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + NS_ASSERT (m_messageSize >= 4); + + m_linkMessages.clear (); + + uint16_t helloSizeLeft = m_messageSize; + + i.ReadNtohU16 (); // Reserved + m_hTime = i.ReadU8 (); + m_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; + m_linkMessages.push_back (lm); + } + + return m_messageSize; +} + + + +// ---------------- OLSR TC Message ------------------------------- + +OlsrTcMessageHeader::OlsrTcMessageHeader () +{} + +OlsrTcMessageHeader::~OlsrTcMessageHeader () +{} + +uint32_t +OlsrTcMessageHeader::GetSerializedSize (void) const +{ + return 4 + m_neighborAddresses.size () * IPV4_ADDRESS_SIZE; +} + +void +OlsrTcMessageHeader::PrintTo (std::ostream &os) const +{ + // TODO +} + +void +OlsrTcMessageHeader::SerializeTo (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + i.WriteHtonU16 (m_ansn); + i.WriteHtonU16 (0); // Reserved + + for (std::vector::const_iterator iter = m_neighborAddresses.begin (); + iter != m_neighborAddresses.end (); iter++) + { + i.WriteHtonU32 (iter->GetHostOrder ()); + } +} + +uint32_t +OlsrTcMessageHeader::DeserializeFrom (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + m_neighborAddresses.clear (); + NS_ASSERT (m_messageSize >= 4); + + m_ansn = i.ReadNtohU16 (); + i.ReadNtohU16 (); // Reserved + + NS_ASSERT ((m_messageSize - 4) % IPV4_ADDRESS_SIZE == 0); + int numAddresses = (m_messageSize - 4) / IPV4_ADDRESS_SIZE; + m_neighborAddresses.clear (); + for (int n = 0; n < numAddresses; ++n) + m_neighborAddresses.push_back (Ipv4Address (i.ReadNtohU32 ())); + + return m_messageSize; +} + + +// ---------------- OLSR HNA Message ------------------------------- + +OlsrHnaMessageHeader::OlsrHnaMessageHeader () +{} + +OlsrHnaMessageHeader::~OlsrHnaMessageHeader () +{} + +uint32_t +OlsrHnaMessageHeader::GetSerializedSize (void) const +{ + return 2*m_associations.size () * IPV4_ADDRESS_SIZE; +} + +void +OlsrHnaMessageHeader::PrintTo (std::ostream &os) const +{ + // TODO +} + +void +OlsrHnaMessageHeader::SerializeTo (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + for (size_t n = 0; n < m_associations.size (); ++n) + { + i.WriteHtonU32 (m_associations[n].address.GetHostOrder ()); + i.WriteHtonU32 (m_associations[n].mask.GetHostOrder ()); + } +} + +uint32_t +OlsrHnaMessageHeader::DeserializeFrom (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + NS_ASSERT (m_messageSize % (IPV4_ADDRESS_SIZE*2) == 0); + int numAddresses = m_messageSize / IPV4_ADDRESS_SIZE / 2; + m_associations.clear (); + for (int n = 0; n < numAddresses; ++n) + { + Ipv4Address address (i.ReadNtohU32 ()); + Ipv4Mask mask (i.ReadNtohU32 ()); + m_associations.push_back ((Association) {address, mask}); + } + return m_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; + OlsrMidMessageHeader mid1; + OlsrMessageHeader msg2; + OlsrMidMessageHeader mid2; + + // MID message #1 + { + std::vector addresses; + addresses.push_back (Ipv4Address ("1.2.3.4")); + addresses.push_back (Ipv4Address ("1.2.3.5")); + mid1.SetInterfaceAddresses (addresses); + } + + msg1.SetMessageSize (mid1.GetSize () + msg1.GetSize ()); + msg1.SetTimeToLive (255); + msg1.SetOriginatorAddress (Ipv4Address ("11.22.33.44")); + msg1.SetVTime (Seconds (9)); + msg1.SetMessageType (OlsrMessageHeader::MID_MESSAGE); + msg1.SetMessageSequenceNumber (7); + + // MID message #2 + { + std::vector addresses; + addresses.push_back (Ipv4Address ("2.2.3.4")); + addresses.push_back (Ipv4Address ("2.2.3.5")); + mid2.SetInterfaceAddresses (addresses); + } + + msg2.SetMessageSize (mid2.GetSize () + msg2.GetSize ()); + 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.GetSize () + msg1.GetMessageSize () + msg2.GetMessageSize ()); + hdr.SetPacketSequenceNumber (123); + + + // Now add all the headers in the correct order + packet.AddHeader (mid2); + packet.AddHeader (msg2); + packet.AddHeader (mid1); + packet.AddHeader (msg1); + packet.AddHeader (hdr); + } + + { + OlsrPacketHeader hdr; + packet.RemoveHeader (hdr); + NS_TEST_ASSERT_EQUAL (hdr.GetPacketSequenceNumber (), 123); + uint32_t sizeLeft = hdr.GetPacketLength () - hdr.GetSize (); + { + OlsrMessageHeader msg1; + OlsrMidMessageHeader mid1; + + 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); + + mid1.SetMessageSize (msg1.GetMessageSize () - msg1.GetSize ()); + packet.RemoveHeader (mid1); + NS_TEST_ASSERT_EQUAL (mid1.GetInterfaceAddresses ().size (), 2); + NS_TEST_ASSERT_EQUAL (*mid1.GetInterfaceAddresses ().begin (), Ipv4Address ("1.2.3.4")); + + sizeLeft -= msg1.GetMessageSize (); + NS_TEST_ASSERT (sizeLeft > 0); + } + { + // now read the second message + OlsrMessageHeader msg2; + OlsrMidMessageHeader mid2; + + 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); + + mid2.SetMessageSize (msg2.GetMessageSize () - msg2.GetSize ()); + packet.RemoveHeader (mid2); + NS_TEST_ASSERT_EQUAL (mid2.GetInterfaceAddresses ().size (), 2); + NS_TEST_ASSERT_EQUAL (*mid2.GetInterfaceAddresses ().begin (), Ipv4Address ("2.2.3.4")); + + sizeLeft -= msg2.GetMessageSize (); + NS_TEST_ASSERT_EQUAL (sizeLeft, 0); + } + } + } + + // Test the HELLO message + { + Packet packet; + OlsrHelloMessageHeader helloIn; + + helloIn.SetHTime (Seconds (7)); + helloIn.SetWillingness (66); + + { + std::vector vec; + + OlsrHelloMessageHeader::LinkMessage lm1; + lm1.linkCode = 2; + lm1.neighborInterfaceAddresses.push_back (Ipv4Address ("1.2.3.4")); + lm1.neighborInterfaceAddresses.push_back (Ipv4Address ("1.2.3.5")); + vec.push_back (lm1); + + OlsrHelloMessageHeader::LinkMessage lm2; + lm2.linkCode = 3; + lm2.neighborInterfaceAddresses.push_back (Ipv4Address ("2.2.3.4")); + lm2.neighborInterfaceAddresses.push_back (Ipv4Address ("2.2.3.5")); + vec.push_back (lm2); + + helloIn.SetLinkMessages (vec); + } + + packet.AddHeader (helloIn); + + OlsrHelloMessageHeader helloOut; + helloOut.SetMessageSize (packet.GetSize ()); + packet.RemoveHeader (helloOut); + + NS_TEST_ASSERT_EQUAL (helloOut.GetHTime (), Seconds (7)); + NS_TEST_ASSERT_EQUAL (helloOut.GetWillingness (), 66); + NS_TEST_ASSERT_EQUAL (helloOut.GetLinkMessages ().size (), 2); + + NS_TEST_ASSERT_EQUAL (helloOut.GetLinkMessages ()[0].linkCode, 2); + NS_TEST_ASSERT_EQUAL (helloOut.GetLinkMessages ()[0].neighborInterfaceAddresses[0], + Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (helloOut.GetLinkMessages ()[0].neighborInterfaceAddresses[1], + Ipv4Address ("1.2.3.5")); + + NS_TEST_ASSERT_EQUAL (helloOut.GetLinkMessages ()[1].linkCode, 3); + NS_TEST_ASSERT_EQUAL (helloOut.GetLinkMessages ()[1].neighborInterfaceAddresses[0], + Ipv4Address ("2.2.3.4")); + NS_TEST_ASSERT_EQUAL (helloOut.GetLinkMessages ()[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; + OlsrTcMessageHeader tcIn; + + tcIn.SetAnsn (0x1234); + { + std::vector vec; + vec.push_back (Ipv4Address ("1.2.3.4")); + vec.push_back (Ipv4Address ("1.2.3.5")); + tcIn.SetNeighborAddresses (vec); + } + packet.AddHeader (tcIn); + + OlsrTcMessageHeader tcOut; + tcOut.SetMessageSize (packet.GetSize ()); + packet.RemoveHeader (tcOut); + + NS_TEST_ASSERT_EQUAL (tcOut.GetAnsn (), 0x1234); + NS_TEST_ASSERT_EQUAL (tcOut.GetNeighborAddresses ().size (), 2); + + NS_TEST_ASSERT_EQUAL (tcOut.GetNeighborAddresses ()[0], + Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (tcOut.GetNeighborAddresses ()[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; + OlsrHnaMessageHeader hnaIn; + + { + std::vector vec; + vec.push_back ((OlsrHnaMessageHeader::Association) + { Ipv4Address ("1.2.3.4"), Ipv4Mask ("255.255.255.0")}); + vec.push_back ((OlsrHnaMessageHeader::Association) + {Ipv4Address ("1.2.3.5"), Ipv4Mask ("255.255.0.0")}); + hnaIn.SetAssociations (vec); + } + packet.AddHeader (hnaIn); + + OlsrHnaMessageHeader hnaOut; + hnaOut.SetMessageSize (packet.GetSize ()); + packet.RemoveHeader (hnaOut); + + NS_TEST_ASSERT_EQUAL (hnaOut.GetAssociations ().size (), 2); + + NS_TEST_ASSERT_EQUAL (hnaOut.GetAssociations ()[0].address, + Ipv4Address ("1.2.3.4")); + NS_TEST_ASSERT_EQUAL (hnaOut.GetAssociations ()[0].mask, + Ipv4Mask ("255.255.255.0")); + + NS_TEST_ASSERT_EQUAL (hnaOut.GetAssociations ()[1].address, + Ipv4Address ("1.2.3.5")); + NS_TEST_ASSERT_EQUAL (hnaOut.GetAssociations ()[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..f55c266b2 --- /dev/null +++ b/src/routing/olsr/olsr-header.h @@ -0,0 +1,470 @@ +/* -*- 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 + * 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; + + virtual void PrintTo (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + virtual std::string DoGetName (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; + + virtual void PrintTo (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + virtual std::string DoGetName (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 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +class OlsrMidMessageHeader : public Header +{ +public: + + OlsrMidMessageHeader (); + virtual ~OlsrMidMessageHeader (); + + void SetMessageSize (uint32_t messageSize) { + m_messageSize = messageSize; + } + uint32_t GetMessageSize () const { + return m_messageSize; + } + + const std::vector & GetInterfaceAddresses () const + { + return m_interfaceAddresses; + } + void SetInterfaceAddresses (const std::vector &addresses) + { + m_interfaceAddresses = addresses; + } + + +private: + std::vector m_interfaceAddresses; + uint32_t m_messageSize; // has to be manually set before deserialization + + virtual void PrintTo (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + virtual std::string DoGetName (void) const { return "OlsrMidMessage"; } +}; + +// 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.) +class OlsrHelloMessageHeader : public Header +{ +public: + + OlsrHelloMessageHeader (); + virtual ~OlsrHelloMessageHeader (); + + + struct LinkMessage { + uint8_t linkCode; + std::vector neighborInterfaceAddresses; + }; + + + void SetMessageSize (uint32_t messageSize) { + m_messageSize = messageSize; + } + uint32_t GetMessageSize () const { + return m_messageSize; + } + + void SetWillingness (uint8_t willingness) + { + m_willingness = willingness; + } + uint8_t GetWillingness () const + { + return m_willingness; + } + + void SetHTime (Time time) + { + m_hTime = OlsrSecondsToEmf (time.GetSeconds ()); + } + Time GetHTime () const + { + return Seconds (OlsrEmfToSeconds (m_hTime)); + } + + const std::vector & GetLinkMessages () const + { + return m_linkMessages; + } + void SetLinkMessages (const std::vector &linkMessages) + { + m_linkMessages = linkMessages; + } + +private: + uint8_t m_hTime; + uint8_t m_willingness; + uint32_t m_messageSize; // has to be manually set before deserialization + std::vector m_linkMessages; + + virtual void PrintTo (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + virtual std::string DoGetName (void) const { return "OlsrHelloMessage"; } +}; + +// 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 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +class OlsrTcMessageHeader : public Header +{ +public: + + OlsrTcMessageHeader (); + virtual ~OlsrTcMessageHeader (); + + void SetMessageSize (uint32_t messageSize) { + m_messageSize = messageSize; + } + uint32_t GetMessageSize () const { + return m_messageSize; + } + + const std::vector & GetNeighborAddresses () const + { + return m_neighborAddresses; + } + void SetNeighborAddresses (const std::vector &addresses) + { + m_neighborAddresses = addresses; + } + + void SetAnsn (uint16_t ansn) + { + m_ansn = ansn; + } + uint16_t GetAnsn () const + { + return m_ansn; + } + +private: + std::vector m_neighborAddresses; + uint16_t m_ansn; + + uint32_t m_messageSize; // has to be manually set before deserialization + + virtual void PrintTo (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + virtual std::string DoGetName (void) const { return "OlsrTcMessage"; } +}; + + +// 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 +class OlsrHnaMessageHeader : public Header +{ +public: + + OlsrHnaMessageHeader (); + virtual ~OlsrHnaMessageHeader (); + + struct Association + { + Ipv4Address address; + Ipv4Mask mask; + }; + + void SetMessageSize (uint32_t messageSize) + { + m_messageSize = messageSize; + } + uint32_t GetMessageSize () const + { + return m_messageSize; + } + + const std::vector & GetAssociations () const + { + return m_associations; + } + void SetAssociations (const std::vector &associations) + { + m_associations = associations; + } + +private: + std::vector m_associations; + uint32_t m_messageSize; // has to be manually set before deserialization + + virtual void PrintTo (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + virtual std::string DoGetName (void) const { return "OlsrHnaMessage"; } +}; + + +}; // namespace ns3 + +#endif /* OLSR_HEADER_H */ + diff --git a/src/routing/olsr/olsr-private.h b/src/routing/olsr/olsr-private.h new file mode 100644 index 000000000..899ebc111 --- /dev/null +++ b/src/routing/olsr/olsr-private.h @@ -0,0 +1,187 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/*************************************************************************** + * Copyright (C) 2004 by Francisco J. Ros * + * fjrm@dif.um.es * + * * + * Modified on 2007 for NS-3 by Gustavo J. A. M. Carneiro, INESC Porto * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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. * + ***************************************************************************/ + + +#ifndef __OLSR_H__ +#define __OLSR_H__ + +#include "olsr.h" + +#include + +#include "olsr-header.h" +#include "olsr-state.h" +#include "routing-table.h" +#include "olsr-repositories.h" +#include "ns3/object.h" +#include "ns3/packet.h" +#include "ns3/node.h" +#include "ns3/socket.h" +#include "ns3/timer.h" + + +namespace ns3 { namespace olsr { + + + +class Olsr : public ::ns3::Olsr +{ + friend class OlsrTest; + +public: + Olsr (Ptr node); + + virtual void Start (); + virtual void SetMainInterface (uint32_t interface); + +private: + + /// 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 uint8_t *dataPtr, uint32_t dataSize, + const Ipv4Address &sourceAddr, + uint16_t sourcePort); + + 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, + Packet messagePayload, + DuplicateTuple *duplicated, + const Ipv4Address &localIface, + const Ipv4Address &senderAddress); + void QueueMessage (Packet 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 OlsrHelloMessageHeader &hello, + const Ipv4Address &receiverIface, + const Ipv4Address &senderIface); + void ProcessTc (const OlsrMessageHeader &msg, + const OlsrTcMessageHeader &tc, + const Ipv4Address &senderIface); + void ProcessMid (const OlsrMessageHeader &msg, + const OlsrMidMessageHeader &mid, + const Ipv4Address &senderIface); + + void LinkSensing (const OlsrMessageHeader &msg, + const OlsrHelloMessageHeader &hello, + const Ipv4Address &receiverIface, + const Ipv4Address &sender_iface); + void PopulateNeighborSet (const OlsrMessageHeader &msg, + const OlsrHelloMessageHeader &hello); + void PopulateTwoHopNeighborSet (const OlsrMessageHeader &msg, + const OlsrHelloMessageHeader &hello); + void PopulateMprSelectorSet (const OlsrMessageHeader &msg, + const OlsrHelloMessageHeader &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, olsr + +#endif diff --git a/src/routing/olsr/olsr-repositories.h b/src/routing/olsr/olsr-repositories.h new file mode 100644 index 000000000..d2362ccbb --- /dev/null +++ b/src/routing/olsr/olsr-repositories.h @@ -0,0 +1,200 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/*************************************************************************** + * Copyright (C) 2004 by Francisco J. Ros * + * fjrm@dif.um.es * + * * + * Modified on 2007 for NS-3 by Gustavo J. A. M. Carneiro, INESC Porto * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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. * + ***************************************************************************/ + +/// +/// \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/olsr-state.cc b/src/routing/olsr/olsr-state.cc new file mode 100644 index 000000000..7a1f69e4a --- /dev/null +++ b/src/routing/olsr/olsr-state.cc @@ -0,0 +1,438 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/*************************************************************************** + * Copyright (C) 2004 by Francisco J. Ros * + * fjrm@dif.um.es * + * * + * Modified for NS-3 by Gustavo J. A. M. Carneiro on 2007 * + * gjc@inescporto.pt * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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. * + ***************************************************************************/ + +/// +/// \file OlsrState.cc +/// \brief Implementation of all functions needed for manipulating the internal +/// state of an OLSR node. +/// + +#include "olsr-state.h" + + +namespace ns3 { namespace olsr { + + +/********** 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, olsr diff --git a/src/routing/olsr/olsr-state.h b/src/routing/olsr/olsr-state.h new file mode 100644 index 000000000..dfa8b78fb --- /dev/null +++ b/src/routing/olsr/olsr-state.h @@ -0,0 +1,147 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/*************************************************************************** + * Copyright (C) 2004 by Francisco J. Ros * + * fjrm@dif.um.es * + * * + * Modified for NS-3 by Gustavo J. A. M. Carneiro on 2007 * + * gjc@inescporto.pt * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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. * + ***************************************************************************/ + +/// +/// \file OLSR_state.h +/// \brief This header file declares and defines internal state of an OLSR node. +/// + +#ifndef __OLSR_state_h__ +#define __OLSR_state_h__ + +#include "olsr-repositories.h" + +namespace ns3 { 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, olsr + +#endif diff --git a/src/routing/olsr/olsr.cc b/src/routing/olsr/olsr.cc new file mode 100644 index 000000000..c3415e1f1 --- /dev/null +++ b/src/routing/olsr/olsr.cc @@ -0,0 +1,2135 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/*************************************************************************** + * Copyright (C) 2004 by Francisco J. Ros * + * fjrm@dif.um.es * + * * + * Modified on 2007 for NS-3 by Gustavo J. A. M. Carneiro, INESC Porto * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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. * + ***************************************************************************/ + +/// +/// \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 +// #include +// #include +// #include +// #include +#include +#include "olsr-private.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 + + +/********** 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 { + +const InterfaceId Olsr::iid = MakeInterfaceId ("Olsr", Object::iid); +const ClassId Olsr::cid = MakeClassId< olsr::Olsr, Ptr > ("Olsr", Olsr::iid); + +namespace olsr { + +NS_DEBUG_COMPONENT_DEFINE ("Olsr"); + + +/********** OLSR class **********/ + + +Olsr::Olsr (Ptr node) + : + m_useL2Notifications (false), + m_helloTimer (OLSR_HELLO_INTERVAL, MakeCallback (&Olsr::HelloTimerExpire, this)), + m_tcTimer (OLSR_TC_INTERVAL, MakeCallback (&Olsr::TcTimerExpire, this)), + m_midTimer (OLSR_MID_INTERVAL, MakeCallback (&Olsr::MidTimerExpire, this)), + m_queuedMessagesTimer (MakeCallback (&Olsr::SendQueuedMessages, this)) +{ + SetInterfaceId (Olsr::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 (OLSR_PORT_NUMBER)) + NS_ASSERT_MSG (false, "Failed to bind() OLSR receive socket"); + + m_sendSocket = socketFactory->CreateSocket (); + m_sendSocket->Connect (Ipv4Address (0xffffffff), OLSR_PORT_NUMBER); + +} + +void Olsr::DoDispose () +{ + m_ipv4 = 0; + m_receiveSocket->Dispose (); + m_receiveSocket = 0; + m_sendSocket->Dispose (); + m_sendSocket = 0; + m_routingTable->Dispose (); + m_routingTable = 0; + + Object::DoDispose (); +} + +void Olsr::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 (m_mainAddress, OLSR_PORT_NUMBER)) + NS_ASSERT_MSG (false, "Failed to bind() OLSR send socket"); + m_receiveSocket->Recv (MakeCallback (&Olsr::RecvOlsr, this)); + m_helloTimer.Expire (); + m_tcTimer.Expire (); + m_midTimer.Expire (); + + NS_DEBUG ("OLSR on node " << m_mainAddress << " started"); +} + +void Olsr::SetMainInterface (uint32_t interface) +{ + m_mainAddress = m_ipv4->GetAddress (interface); +} + + +// +// \brief Processes an incoming %OLSR packet following RFC 3626 specification. +void +Olsr::RecvOlsr (Ptr socket, + const uint8_t *dataPtr, uint32_t dataSize, + const Ipv4Address &sourceAddress, + uint16_t sourcePort) +{ + NS_DEBUG ("OLSR node " << m_mainAddress << " received a OLSR packet"); + + // All routing messages are sent from and to port RT_PORT, + // so we check it. + NS_ASSERT (sourcePort == OLSR_PORT_NUMBER); + + Packet packet (dataPtr, dataSize); + + OlsrPacketHeader olsrPacketHeader; + packet.RemoveHeader (olsrPacketHeader); + NS_ASSERT (olsrPacketHeader.GetPacketLength () >= olsrPacketHeader.GetSize ()); + uint32_t sizeLeft = olsrPacketHeader.GetPacketLength () - olsrPacketHeader.GetSize (); + + while (sizeLeft) + { + OlsrMessageHeader messageHeader; + NS_ASSERT (sizeLeft >= messageHeader.GetSize ()); + if (packet.RemoveHeader (messageHeader) == 0) + NS_ASSERT (false); + + sizeLeft -= messageHeader.GetMessageSize (); + + 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.GetMessageSize () + - messageHeader.GetSize ()); + continue; + } + + // Save the original message payload for forwarding + Packet messagePayload = packet.CreateFragment + (0, messageHeader.GetMessageSize () - messageHeader.GetSize ()); + + // 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) + { + OlsrHelloMessageHeader helloMsg; + OlsrTcMessageHeader tcMsg; + OlsrMidMessageHeader midMsg; + + switch (messageHeader.GetMessageType ()) + { + case OlsrMessageHeader::HELLO_MESSAGE: + helloMsg.SetMessageSize (messageHeader.GetMessageSize () - messageHeader.GetSize ()); + packet.RemoveHeader (helloMsg); + NS_DEBUG ("OLSR node received HELLO message of size " << messageHeader.GetMessageSize ()); + ProcessHello(messageHeader, helloMsg, m_mainAddress, sourceAddress); + break; + + case OlsrMessageHeader::TC_MESSAGE: + tcMsg.SetMessageSize (messageHeader.GetMessageSize () - messageHeader.GetSize ()); + packet.RemoveHeader (tcMsg); + NS_DEBUG ("OLSR node received TC message of size " << messageHeader.GetMessageSize ()); + ProcessTc(messageHeader, tcMsg, sourceAddress); + break; + + case OlsrMessageHeader::MID_MESSAGE: + midMsg.SetMessageSize (messageHeader.GetMessageSize () - messageHeader.GetSize ()); + packet.RemoveHeader (midMsg); + NS_DEBUG ("OLSR node received MID message of size " << messageHeader.GetMessageSize ()); + ProcessMid(messageHeader, midMsg, sourceAddress); + break; + + default: + packet.RemoveAtStart (messageHeader.GetMessageSize () - messageHeader.GetSize ()); + NS_DEBUG ("OLSR message type " << + int (messageHeader.GetMessageType ()) << + " not implemented"); + } + } + else + { + NS_DEBUG ("OLSR message is duplicated, not reading it."); + packet.RemoveAtStart (messageHeader.GetMessageSize () - messageHeader.GetSize ()); + + // 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, messagePayload, duplicated, + m_mainAddress, sourceAddress); + } + + } + + // 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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 found_entry = m_routingTable->Lookup (nb2hop_tuple.neighborMainAddr, entry); + NS_ASSERT (found_entry); + 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 +Olsr::ProcessHello (const OlsrMessageHeader &msg, + const OlsrHelloMessageHeader &hello, + const Ipv4Address &receiverIface, + const Ipv4Address &senderIface) +{ + 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 +Olsr::ProcessTc (const OlsrMessageHeader &msg, + const OlsrTcMessageHeader &tc, + const Ipv4Address &senderIface) +{ + 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.GetAnsn ()); + 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.GetAnsn ()); + + // 4. For each of the advertised neighbor main address received in + // the TC message: + for (std::vector::const_iterator i = tc.GetNeighborAddresses ().begin (); + i != tc.GetNeighborAddresses ().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.GetAnsn (); + topologyTuple.expirationTime = now + msg.GetVTime (); + AddTopologyTuple (topologyTuple); + + // Schedules topology tuple deletion + Simulator::Schedule (DELAY (topologyTuple.expirationTime), + &Olsr::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 +Olsr::ProcessMid (const OlsrMessageHeader &msg, + const OlsrMidMessageHeader &mid, + const Ipv4Address &senderIface) +{ + 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 + const std::vector &addrs = mid.GetInterfaceAddresses (); + for (std::vector::const_iterator i = addrs.begin (); + i != addrs.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), + &Olsr::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 +Olsr::ForwardDefault (OlsrMessageHeader olsrMessage, + Packet messagePayload, + 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. + messagePayload.AddHeader (olsrMessage); + QueueMessage (messagePayload, 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, + &Olsr::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 +Olsr::QueueMessage (Packet message, Time delay) +{ + m_queuedMessages.push_back (message); + if (not m_queuedMessagesTimer.IsRunning ()) + { + m_queuedMessagesTimer.SetInterval (delay); + m_queuedMessagesTimer.Schedule (); + } +} + +void +Olsr::SendPacket (Packet packet) +{ + NS_DEBUG ("OLSR node " << m_mainAddress << " sending a OLSR packet"); + // Add a header + OlsrPacketHeader header; + header.SetPacketLength (header.GetSize () + packet.GetSize ()); + header.SetPacketSequenceNumber (GetPacketSequenceNumber ()); + packet.AddHeader (header); + // Send it + m_sendSocket->Send (packet.PeekData (), packet.GetSize ()); +} + +/// +/// \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 +Olsr::SendQueuedMessages () +{ + Packet packet; + int numMessages = 0; + + NS_DEBUG ("Olsr node " << m_mainAddress << ": SendQueuedMessages"); + + for (std::vector::const_iterator messagePkt = m_queuedMessages.begin (); + messagePkt != m_queuedMessages.end (); + messagePkt++) + { + packet.AddAtEnd (*messagePkt); + 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 +Olsr::SendHello () +{ + OlsrMessageHeader msg; + OlsrHelloMessageHeader hello; + Time now = Simulator::Now (); + + msg.SetMessageType (OlsrMessageHeader::HELLO_MESSAGE); + msg.SetVTime (OLSR_NEIGHB_HOLD_TIME); + msg.SetOriginatorAddress (m_mainAddress); + msg.SetTimeToLive (1); + msg.SetHopCount (0); + msg.SetMessageSequenceNumber (GetMessageSequenceNumber ()); + + hello.SetHTime (m_helloInterval); + hello.SetWillingness (m_willingness); + + std::vector 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; + + // 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"); + } + } + + OlsrHelloMessageHeader::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); + } + hello.SetLinkMessages (linkMessages); + Packet packet; + packet.AddHeader (hello); + NS_DEBUG ("OLSR HELLO message size: " << int (packet.GetSize () + msg.GetSize ()) + << " (with " << int (linkMessages.size ()) << " link messages)"); + msg.SetMessageSize (packet.GetSize () + msg.GetSize ()); + packet.AddHeader (msg); + QueueMessage (packet, JITTER); +} + +/// +/// \brief Creates a new %OLSR TC message which is buffered for being sent later on. +/// +void +Olsr::SendTc () +{ + OlsrMessageHeader msg; + OlsrTcMessageHeader tc; + + msg.SetMessageType (OlsrMessageHeader::TC_MESSAGE); + msg.SetVTime (OLSR_TOP_HOLD_TIME); + msg.SetOriginatorAddress (m_mainAddress); + msg.SetTimeToLive (255); + msg.SetHopCount (0); + msg.SetMessageSequenceNumber (GetMessageSequenceNumber ()); + + tc.SetAnsn (m_ansn); + std::vector neighbors; + for (MprSelectorSet::const_iterator mprsel_tuple = m_state.GetMprSelectors ().begin(); + mprsel_tuple != m_state.GetMprSelectors ().end(); mprsel_tuple++) + { + neighbors.push_back (mprsel_tuple->mainAddr); + } + tc.SetNeighborAddresses (neighbors); + + Packet packet; + packet.AddHeader (tc); + msg.SetMessageSize (packet.GetSize () + msg.GetSize ()); + packet.AddHeader (msg); + QueueMessage (packet, JITTER); +} + +/// +/// \brief Creates a new %OLSR MID message which is buffered for being sent later on. +/// +void +Olsr::SendMid () +{ + OlsrMessageHeader msg; + OlsrMidMessageHeader mid; + + // 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"); + std::vector addresses; + for (uint32_t i = 0; i < m_ipv4->GetNInterfaces (); i++) + { + Ipv4Address addr = m_ipv4->GetAddress (i); + if (addr != m_mainAddress && addr != loopback) + addresses.push_back (addr); + } + if (addresses.size () == 0) + return; + mid.SetInterfaceAddresses (addresses); + + msg.SetMessageType (OlsrMessageHeader::MID_MESSAGE); + msg.SetVTime (OLSR_MID_HOLD_TIME); + msg.SetOriginatorAddress (m_mainAddress); + msg.SetTimeToLive (255); + msg.SetHopCount (0); + msg.SetMessageSequenceNumber (GetMessageSequenceNumber ()); + + Packet packet; + packet.AddHeader (mid); + msg.SetMessageSize (packet.GetSize () + msg.GetSize ()); + packet.AddHeader (msg); + QueueMessage (packet, JITTER); +} + +/// +/// \brief Updates Link Set according to a new received HELLO message (following RFC 3626 +/// specification). Neighbor Set is also updated if needed. +/// +/// \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 +Olsr::LinkSensing (const OlsrMessageHeader &msg, + const OlsrHelloMessageHeader &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.GetWillingness ()); + created = true; + } + else + updated = true; + + link_tuple->asymTime = now + msg.GetVTime (); + for (std::vector::const_iterator linkMessage = + hello.GetLinkMessages ().begin (); + linkMessage != hello.GetLinkMessages ().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) + { + Simulator::Schedule (DELAY (std::min (link_tuple->time, link_tuple->symTime)), + &Olsr::LinkTupleTimerExpire, this, *link_tuple); + } +} + +/// +/// \brief Updates the Neighbor Set according to the information contained in a new received +/// HELLO message (following RFC 3626). +/// +/// \param msg the %OLSR message which contains the HELLO message. +/// +void +Olsr::PopulateNeighborSet (const OlsrMessageHeader &msg, + const OlsrHelloMessageHeader &hello) +{ + NeighborTuple *nb_tuple = m_state.FindNeighborTuple (msg.GetOriginatorAddress ()); + if (nb_tuple != NULL) + nb_tuple->willingness = hello.GetWillingness (); +} + + +/// +/// \brief Updates the 2-hop Neighbor Set according to the information contained in a new +/// received HELLO message (following RFC 3626). +/// +/// \param msg the %OLSR message which contains the HELLO message. +/// +void +Olsr::PopulateTwoHopNeighborSet (const OlsrMessageHeader &msg, + const OlsrHelloMessageHeader &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.GetLinkMessages ().begin (); + linkMessage != hello.GetLinkMessages ().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 + Simulator::Schedule (DELAY (new_nb2hop_tuple.expirationTime), + &Olsr::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). +/// +/// \param msg the %OLSR message which contains the HELLO message. +/// +void +Olsr::PopulateMprSelectorSet (const OlsrMessageHeader &msg, + const OlsrHelloMessageHeader &hello) +{ + Time now = Simulator::Now (); + + typedef std::vector LinkMessageVec; + for (LinkMessageVec::const_iterator linkMessage = hello.GetLinkMessages ().begin (); + linkMessage != hello.GetLinkMessages ().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 + Simulator::Schedule (DELAY (mprsel_tuple.expirationTime), + &Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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& +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 +Olsr::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 Olsr::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 Olsr::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 +Olsr::HelloTimerExpire () +{ + SendHello (); + m_helloTimer.Schedule (); +} + +/// +/// \brief Sends a TC message (if there exists any MPR selector) and reschedules the TC timer. +/// \param e The event which has expired. +/// +void +Olsr::TcTimerExpire () +{ + if (m_state.GetMprSelectors ().size () > 0) + SendTc (); + m_tcTimer.Schedule (); +} + +/// +/// \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 +Olsr::MidTimerExpire () +{ + SendMid (); + m_midTimer.Schedule (); +} + +/// +/// \brief Removes tuple_ if expired. Else 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 +Olsr::DupTupleTimerExpire (DuplicateTuple tuple) +{ + if (tuple.expirationTime < Simulator::Now ()) + { + RemoveDuplicateTuple (tuple); + } + else + Simulator::Schedule (DELAY (tuple.expirationTime), &Olsr::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 +Olsr::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); + + Simulator::Schedule (DELAY(tuple.time), + &Olsr::LinkTupleTimerExpire, this, tuple); + + } + else + Simulator::Schedule (DELAY (std::min (tuple.time, tuple.symTime)), + &Olsr::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 +Olsr::Nb2hopTupleTimerExpire (TwoHopNeighborTuple tuple) +{ + if (tuple.expirationTime < Simulator::Now ()) + { + RemoveTwoHopNeighborTuple (tuple); + } + else + Simulator::Schedule (DELAY (tuple.expirationTime), + &Olsr::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 +Olsr::MprSelTupleTimerExpire (MprSelectorTuple tuple) +{ + if (tuple.expirationTime < Simulator::Now ()) + { + RemoveMprSelectorTuple (tuple); + } + else + Simulator::Schedule (DELAY (tuple.expirationTime), + &Olsr::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 +Olsr::TopologyTupleTimerExpire (TopologyTuple tuple) +{ + if (tuple.expirationTime < Simulator::Now ()) + { + RemoveTopologyTuple (tuple); + } + else + Simulator::Schedule (DELAY (tuple.expirationTime), + &Olsr::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 +Olsr::IfaceAssocTupleTimerExpire (IfaceAssocTuple tuple) +{ + if (tuple.time < Simulator::Now ()) + { + RemoveIfaceAssocTuple (tuple); + } + else + Simulator::Schedule (DELAY (tuple.time), + &Olsr::IfaceAssocTupleTimerExpire, this, tuple); +} + + + +}}; // namespace ns3, olsr + + + +#ifdef RUN_SELF_TESTS + + +#include "ns3/test.h" + +namespace ns3 { namespace olsr { + +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; + +}}; // namespace + + +#endif /* RUN_SELF_TESTS */ diff --git a/src/routing/olsr/olsr.h b/src/routing/olsr/olsr.h new file mode 100644 index 000000000..adc1e6d82 --- /dev/null +++ b/src/routing/olsr/olsr.h @@ -0,0 +1,45 @@ +/* -*- 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 + * 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.h" +#include "ns3/component-manager.h" + +namespace ns3 { + + +class Olsr : public Object +{ +public: + static const InterfaceId iid; + static const ClassId cid; + + virtual void Start () = 0; + virtual void SetMainInterface (uint32_t interface) = 0; +}; + + +}; // namespace ns3 + +#endif /* OLSR_H */ + diff --git a/src/routing/olsr/routing-table.cc b/src/routing/olsr/routing-table.cc new file mode 100644 index 000000000..aa41f49fd --- /dev/null +++ b/src/routing/olsr/routing-table.cc @@ -0,0 +1,270 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/*************************************************************************** + * Copyright (C) 2004 by Francisco J. Ros * + * fjrm@dif.um.es * + * * + * Modified on 2007 for NS-3 by Gustavo J. A. M. Carneiro, INESC Porto * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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. * + ***************************************************************************/ + +/// +/// \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 (const Ipv4Header &ipHeader, + Packet packet, + RouteReplyCallback routeReply) +{ + RoutingTableEntry entry1, entry2; + if (Lookup (ipHeader.GetDestination (), entry1)) + { + bool foundSendEntry = FindSendEntry (entry1, entry2); + NS_ASSERT (foundSendEntry); + 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; + } +} + + +/// +/// \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..aebed6316 --- /dev/null +++ b/src/routing/olsr/routing-table.h @@ -0,0 +1,110 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/*************************************************************************** + * Copyright (C) 2004 by Francisco J. Ros * + * fjrm@dif.um.es * + * * + * Modified on 2007 for NS-3 by Gustavo J. A. M. Carneiro, INESC Porto * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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. * + ***************************************************************************/ + +/// +/// \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 (const Ipv4Header &ipHeader, + Packet packet, + RouteReplyCallback routeReply); +}; + +}}; // namespace ns3, olsr + +#endif diff --git a/src/routing/olsr/wscript b/src/routing/olsr/wscript new file mode 100644 index 000000000..a2874de2a --- /dev/null +++ b/src/routing/olsr/wscript @@ -0,0 +1,19 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + obj = bld.create_obj('cpp', 'shlib') + obj.name = 'ns3-olsr' + obj.target = obj.name + obj.uselib_local = ['ns3-internet-node'] + obj.includes = '.' + obj.source = [ + 'olsr-header.cc', + 'olsr-state.cc', + 'routing-table.cc', + 'olsr.cc', + ] + + headers = bld.create_obj('ns3header') + headers.source = [ + 'olsr.h', + ] diff --git a/src/wscript b/src/wscript index 4b34a9156..7516909e5 100644 --- a/src/wscript +++ b/src/wscript @@ -17,6 +17,7 @@ all_modules = ( 'internet-node', 'devices/p2p', 'applications', + 'routing/olsr', 'mobility', )