src/devices/mesh/dot11s/hwmp-rtable.cc
author Kirill Andreev <andreev@iitp.ru>
Wed, 22 Jul 2009 16:43:43 +0400
changeset 5132 aee541a30256
parent 5130 b5062e8e0da1
child 5135 10c2f3ae8c2f
permissions -rw-r--r--
Restored newline at namespace

/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2008,2009 IITP RAS
 *
 * 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: Kirill Andreev <andreev@iitp.ru>
 */

#include "ns3/object.h"
#include "ns3/assert.h"
#include "ns3/simulator.h"
#include "ns3/test.h"
#include "ns3/log.h"

#include "hwmp-rtable.h"

namespace ns3 {
namespace dot11s {

NS_LOG_COMPONENT_DEFINE ("HwmpRtable");

NS_OBJECT_ENSURE_REGISTERED (HwmpRtable);

TypeId
HwmpRtable::GetTypeId ()
{
  static TypeId tid = TypeId ("ns3::dot11s::HwmpRtable")
    .SetParent<Object> ()
    .AddConstructor<HwmpRtable> ();
  return tid;
}
HwmpRtable::HwmpRtable ()
{
  DeleteProactivePath ();
}
HwmpRtable::~HwmpRtable ()
{
}
void
HwmpRtable::DoDispose ()
{
  m_routes.clear ();
}
void
HwmpRtable::AddReactivePath (Mac48Address destination, Mac48Address retransmitter, uint32_t interface,
    uint32_t metric, Time lifetime, uint32_t seqnum)
{
  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
  if (i == m_routes.end ())
    {
      ReactiveRoute newroute;
      m_routes[destination] = newroute;
    }
  i = m_routes.find (destination);
  NS_ASSERT (i != m_routes.end ());
  i->second.retransmitter = retransmitter;
  i->second.interface = interface;
  i->second.metric = metric;
  i->second.whenExpire = Simulator::Now () + lifetime;
  i->second.seqnum = seqnum;
}
void
HwmpRtable::AddProactivePath (uint32_t metric, Mac48Address root, Mac48Address retransmitter,
    uint32_t interface, Time lifetime, uint32_t seqnum)
{
  m_root.root = root;
  m_root.retransmitter = retransmitter;
  m_root.metric = metric;
  m_root.whenExpire = Simulator::Now () + lifetime;
  m_root.seqnum = seqnum;
  m_root.interface = interface;
}
void
HwmpRtable::AddPrecursor (Mac48Address destination, uint32_t precursorInterface,
    Mac48Address precursorAddress)
{
  std::pair<uint32_t, Mac48Address> precursor;
  precursor.first = precursorInterface;
  precursor.second = precursorAddress;
  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
  if (i != m_routes.end ())
    {
      bool should_add = true;
      for (unsigned int j = 0; j < i->second.precursors.size (); j++)
        {
          //NB: Only one active route may exist, so do not check
          //interface ID, just address
          if (i->second.precursors[j].second == precursorAddress)
            {
              should_add = false;
              break;
            }
        }
      if (should_add)
        {
          i->second.precursors.push_back (precursor);
        }
    }
  if (m_root.root == destination)
    {
      for (unsigned int j = 0; j < m_root.precursors.size (); j++)
        {
          if (m_root.precursors[j].second == precursorAddress)
            {
              return;
            }
        }
    }
  m_root.precursors.push_back (precursor);
}
void
HwmpRtable::DeleteProactivePath ()
{
  m_root.precursors.clear ();
  m_root.interface = INTERFACE_ANY;
  m_root.metric = MAX_METRIC;
  m_root.retransmitter = Mac48Address::GetBroadcast ();
  m_root.seqnum = 0;
  m_root.whenExpire = Simulator::Now ();
}
void
HwmpRtable::DeleteProactivePath (Mac48Address root)
{
  if (m_root.root == root)
    {
      DeleteProactivePath ();
    }
}
void
HwmpRtable::DeleteReactivePath (Mac48Address destination)
{
  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
  if (i != m_routes.end ())
    {
      m_routes.erase (i);
    }
}
HwmpRtable::LookupResult
HwmpRtable::LookupReactive (Mac48Address destination)
{
  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
  if (i == m_routes.end ())
    {
      return LookupResult ();
    }
  if ((i->second.whenExpire < Simulator::Now ()) && (i->second.whenExpire != Seconds (0)))
    {
      NS_LOG_DEBUG ("Reactive route has expired, sorry.");
      return LookupResult ();
    }
  return LookupReactiveExpired (destination);
}
HwmpRtable::LookupResult
HwmpRtable::LookupReactiveExpired (Mac48Address destination)
{
  std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
  if (i == m_routes.end ())
    {
      return LookupResult ();
    }
  return LookupResult (i->second.retransmitter, i->second.interface, i->second.metric, i->second.seqnum,
      i->second.whenExpire - Simulator::Now ());
}
HwmpRtable::LookupResult
HwmpRtable::LookupProactive ()
{
  if (m_root.whenExpire < Simulator::Now ())
    {
      NS_LOG_DEBUG ("Proactive route has expired and will be deleted, sorry.");
      DeleteProactivePath ();
    }
  return LookupProactiveExpired ();
}
HwmpRtable::LookupResult
HwmpRtable::LookupProactiveExpired ()
{
  return LookupResult (m_root.retransmitter, m_root.interface, m_root.metric, m_root.seqnum,
      m_root.whenExpire - Simulator::Now ());
}
std::vector<IePerr::FailedDestination>
HwmpRtable::GetUnreachableDestinations (Mac48Address peerAddress)
{
  IePerr::FailedDestination dst;
  std::vector<IePerr::FailedDestination> retval;
  for (std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.begin (); i != m_routes.end (); i++)
  {
      if (i->second.retransmitter == peerAddress)
        {
          dst.destination = i->first;
          i->second.seqnum++;
          dst.seqnum = i->second.seqnum;
          retval.push_back (dst);
        }
  }
  //Lookup a path to root
  if (m_root.retransmitter == peerAddress)
    {
      dst.destination = m_root.root;
      dst.seqnum = m_root.seqnum;
      retval.push_back (dst);
    }
  return retval;
}
HwmpRtable::PrecursorList
HwmpRtable::GetPrecursors (Mac48Address destination)
{
  //We suppose that no duplicates here can be
  PrecursorList retval;
  std::map<Mac48Address, ReactiveRoute>::iterator route = m_routes.find (destination);
  if (route != m_routes.end ())
    {
      for (unsigned int i = 0; i < route->second.precursors.size (); i++)
        {
          retval.push_back (route->second.precursors[i]);
        }
    }
  if (m_root.root == destination)
    {
      for (unsigned int i = 0; i < m_root.precursors.size (); i++)
        {
          bool should_add = true;
          for (unsigned int j = 0; j < retval.size (); j++)
            {
              if (retval[j].second == m_root.precursors[i].second)
                {
                  should_add = false;
                  break;
                }
            }
          if (should_add)
            {
              retval.push_back (m_root.precursors[i]);
            }
        }
    }
  return retval;
}
bool
HwmpRtable::LookupResult::operator== (const HwmpRtable::LookupResult & o) const
{
  return (retransmitter == o.retransmitter && ifIndex == o.ifIndex && metric == o.metric && seqnum
      == o.seqnum);
}
bool
HwmpRtable::LookupResult::IsValid () const
{
  return !(retransmitter == Mac48Address::GetBroadcast () && ifIndex == INTERFACE_ANY && metric == MAX_METRIC
      && seqnum == 0);
}
#ifdef RUN_SELF_TESTS
/// Unit test for HwmpRtable
class HwmpRtableTest : public Test
{
public:
  HwmpRtableTest ();
  virtual bool
  RunTests ();

private:
  /// Test Add apth and lookup path;
  void
  TestLookup ();
  /**
   * \name Test add path and try to lookup after entry has expired
   * \{
   */
  void
  TestAddPath ();
  void
  TestExpire ();
  ///\}
  /**
   * \name Test add precursors and find precursor list in rtable
   * \{
   */
  void
  TestPrecursorAdd ();
  void
  TestPrecursorFind ();
  ///\}
private:
  bool result;

  Mac48Address dst;
  Mac48Address hop;
  uint32_t iface;
  uint32_t metric;
  uint32_t seqnum;
  Time expire;
  Ptr<HwmpRtable> table;
  std::vector<Mac48Address> precursors;
};
/// Test instance
static HwmpRtableTest g_HwmpRtableTest;

HwmpRtableTest::HwmpRtableTest () :
  Test ("Mesh/802.11s/HwmpRtable"), result (true), dst ("01:00:00:01:00:01"), hop ("01:00:00:01:00:03"),
      iface (8010), metric (10), seqnum (1), expire (Seconds (10))
{
  precursors.push_back (Mac48Address ("00:10:20:30:40:50"));
  precursors.push_back (Mac48Address ("00:11:22:33:44:55"));
  precursors.push_back (Mac48Address ("00:01:02:03:04:05"));
}
void
HwmpRtableTest::TestLookup ()
{
  HwmpRtable::LookupResult correct (hop, iface, metric, seqnum);

  // Reactive path
  table->AddReactivePath (dst, hop, iface, metric, expire, seqnum);
  NS_TEST_ASSERT (table->LookupReactive (dst) == correct);
  table->DeleteReactivePath (dst);
  NS_TEST_ASSERT (!table->LookupReactive (dst).IsValid ());

  // Proactive
  table->AddProactivePath (metric, dst, hop, iface, expire, seqnum);
  NS_TEST_ASSERT (table->LookupProactive () == correct);
  table->DeleteProactivePath (dst);
  NS_TEST_ASSERT (!table->LookupProactive ().IsValid ());
}
void
HwmpRtableTest::TestAddPath ()
{
  table->AddReactivePath (dst, hop, iface, metric, expire, seqnum);
  table->AddProactivePath (metric, dst, hop, iface, expire, seqnum);
}
void
HwmpRtableTest::TestExpire ()
{
  // this is assumed to be called when path records are already expired
  HwmpRtable::LookupResult correct (hop, iface, metric, seqnum);
  NS_TEST_ASSERT (table->LookupReactiveExpired (dst) == correct);
  NS_TEST_ASSERT (table->LookupProactiveExpired () == correct);

  NS_TEST_ASSERT (!table->LookupReactive (dst).IsValid ());
  NS_TEST_ASSERT (!table->LookupProactive ().IsValid ());
}
void
HwmpRtableTest::TestPrecursorAdd ()
{
  for (std::vector<Mac48Address>::const_iterator i = precursors.begin (); i != precursors.end (); i++)
    {
      table->AddPrecursor (dst, iface, *i);
      // Check that duplicates are filtered
      table->AddPrecursor (dst, iface, *i);
    }
}
void
HwmpRtableTest::TestPrecursorFind ()
{
  HwmpRtable::PrecursorList precursorList = table->GetPrecursors (dst);
  NS_TEST_ASSERT (precursors.size () == precursorList.size ());
  for (unsigned int i = 0; i < precursors.size (); i++)
    {
      NS_TEST_ASSERT (precursorList[i].first == iface);
      NS_TEST_ASSERT (precursorList[i].second == precursors[i]);
    }
}
bool
HwmpRtableTest::RunTests ()
{
  table = CreateObject<HwmpRtable> ();

  Simulator::Schedule (Seconds (0), &HwmpRtableTest::TestLookup, this);
  Simulator::Schedule (Seconds (1), &HwmpRtableTest::TestAddPath, this);
  Simulator::Schedule (Seconds (2), &HwmpRtableTest::TestPrecursorAdd, this);
  Simulator::Schedule (expire + Seconds (2), &HwmpRtableTest::TestExpire, this);
  Simulator::Schedule (expire + Seconds (3), &HwmpRtableTest::TestPrecursorFind, this);

  Simulator::Run ();
  Simulator::Destroy ();

  return result;
}
#endif // RUN_SELF_TESTS
} //namespace dot11s
} //namespace ns3