src/devices/mesh/dot11s/hwmp-protocol.cc
author Kirill Andreev <andreev@iitp.ru>
Thu, 26 Mar 2009 16:53:49 +0300
changeset 4888 dec245c213ab
parent 4887 cbf02c77d5c1
child 4889 279b07de3327
permissions -rw-r--r--
Attach interfaces replaced with Install. Helper is simplifyed

/* -*-  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
 *
 * Authors: Kirill Andreev <andreev@iitp.ru>
 */


#include "hwmp-protocol.h"
#include "hwmp-mac-plugin.h"
#include "ns3/log.h"
#include "ns3/simulator.h"
#include "ns3/packet.h"
#include "ns3/mesh-point-device.h"
#include "ns3/wifi-net-device.h"
#include "ns3/mesh-point-device.h"
#include "ns3/mesh-wifi-interface-mac.h"

NS_LOG_COMPONENT_DEFINE ("HwmpProtocol");

namespace ns3 {
namespace dot11s {

NS_OBJECT_ENSURE_REGISTERED (HwmpProtocol);
//Class HWMP:
TypeId
HwmpProtocol::GetTypeId ()
{
  static TypeId tid = TypeId ("ns3::HwmpProtocol")
                      .SetParent<MeshL2RoutingProtocol> ()
                      .AddConstructor<HwmpProtocol> ();
  return tid;
}
HwmpProtocol::HwmpProtocol ()//:
//    m_rtable (CreateObject<HwmpRtable> ()),
//    m_maxTtl (32),
//    m_broadcastPerr (false)
{
}

HwmpProtocol::~HwmpProtocol ()
{
}

void
HwmpProtocol::DoDispose ()
{
#if 0
  for (std::map<Mac48Address, EventId>::iterator i = m_timeoutDatabase.begin (); i != m_timeoutDatabase.end(); i ++)
    i->second.Cancel ();
  m_timeoutDatabase.clear ();
  m_seqnoDatabase.clear ();
  m_rtable = 0;

  /**
   * clear routing queue:
   */
  for (
    std::map<Mac48Address, std::queue<QueuedPacket> >::iterator i =  m_rqueue.begin ();
    i != m_rqueue.end ();
    i++
  )
    {
      while (1)
        {
          if (i->second.empty ())
            break;
          i->second.pop ();
        }
    }
  m_rqueue.clear ();
  /**
   * clear HWMP states
   */
  for (unsigned int i = 0; i < m_hwmpStates.size (); i ++)
    m_hwmpStates[i] = 0;
  m_hwmpStates.clear ();
#endif
}

bool
HwmpProtocol::RequestRoute (
  uint32_t sourceIface,
  const Mac48Address source,
  const Mac48Address destination,
  Ptr<Packet> packet,
  uint16_t protocolType, //ethrnet 'Protocol' field
  MeshL2RoutingProtocol::RouteReplyCallback routeReply
)
{
  NS_LOG_UNCOND("Packet has come!");
#if 0
  HwmpRtable::LookupResult result;
  HwmpProtocolTag tag;
  if (sourceIface == GetMeshPoint ()->GetIfIndex())
    // packet from level 3
    {
      if (destination == Mac48Address::GetBroadcast ())
        {
          //set seqno!
          tag.SetSeqno (m_seqno++);
          if (m_seqno == MAX_SEQNO)
            m_seqno = 0;
        }
      tag.SetTtl (m_maxTtl);
    }
  else
    // packet from own interface
    {
      NS_ASSERT (packet->FindFirstMatchingTag(tag));
      //check seqno!
      if (destination == Mac48Address::GetBroadcast ())
        {
          std::map<Mac48Address, uint32_t>::iterator i = m_seqnoDatabase.find (source);
          if (i == m_seqnoDatabase.end ())
            m_seqnoDatabase[source] = tag.GetSeqno ();
          else
            {
              if (i->second >= tag.GetSeqno ())
                return false;
              m_seqnoDatabase[source] = tag.GetSeqno ();
            }
        }
    }
  tag.SetAddress (Mac48Address::GetBroadcast());
  if (tag.GetTtl () == 0)
    return false;
  tag.DecrementTtl ();
  if (destination == Mac48Address::GetBroadcast ())
    {
      //add RA tag RA = broadcast
      packet->RemoveAllTags ();
      packet->AddTag (tag);
      routeReply (
        true,
        packet,
        source,
        destination,
        protocolType,
        HwmpRtable::PORT_ANY
      );
      return true;
    }
  result = m_rtable->LookupReactive (destination);
  if (result.retransmitter == Mac48Address::GetBroadcast ())
    {
      //no actual route exists, queue packet and start route
      //discover procedure
      if (sourceIface != GetMeshPoint ()->GetIfIndex())
        {
          //Start path error procedure:
          NS_LOG_DEBUG ("Must Send PERR");
          std::vector<HwmpRtable::FailedDestination> destinations;
          HwmpRtable::FailedDestination dst;
          dst.seqnum = m_rtable->RequestSeqnum (destination);
          dst.destination = destination;
          destinations.push_back (dst);
          StartPathErrorProcedure (destinations, result.ifIndex);
        }
      MeshL2RoutingProtocol::QueuedPacket pkt;
      packet->RemoveAllTags ();
      packet->AddTag (tag);
      pkt.pkt = packet;
      pkt.dst = destination;
      pkt.src = source;
      pkt.protocol = protocolType;
      pkt.reply = routeReply;
      pkt.inPort = sourceIface;
      QueuePacket (pkt);
      for (unsigned int i = 0; i< m_requestCallback.size (); i++)
        {
          if ((m_modes[i] == REACTIVE) || (m_modes[i] == ROOT))
            {
              if (ShouldSendPreq (destination))
                m_requestCallback[i] (destination);
            }
          else
            {
              NS_ASSERT (false);
              //PROACTIVE mode
              //lookup a default route
              result = m_rtable->LookupProactive (m_hwmpStates[i]->GetAssociatedIfaceId());
              if (result.retransmitter == Mac48Address::GetBroadcast ())
                {
                  m_rtable->DeleteProactivePath (m_hwmpStates[i]->GetAssociatedIfaceId());
                  m_modes[i] = REACTIVE;
                  if (ShouldSendPreq (destination))
                    m_requestCallback[i] (destination);
                  continue;
                }
              tag.SetAddress (result.retransmitter);
              packet->RemoveAllTags ();
              packet->AddTag (tag);
              routeReply (
                true,
                packet,
                source,
                destination,
                protocolType,
                result.ifIndex
              );
            }
        }
      for (unsigned int i = 0; i< m_requestCallback.size (); i++)
        {
          m_requestCallback[i] (Mac48Address("00:00:00:00:00:19"));
        }
    }
  else
    {
      tag.SetAddress (result.retransmitter);
      packet->RemoveAllTags ();
      packet->AddTag (tag);
      routeReply (
        true,
        packet,
        source,
        destination,
        protocolType,
        result.ifIndex
      );
    }
#endif
  return true;
}
bool
HwmpProtocol::Install (Ptr<MeshPointDevice> mp)
{
  m_mp = mp;
  std::vector<Ptr<NetDevice> > interfaces = mp->GetInterfaces ();
  for (std::vector<Ptr<NetDevice> >::iterator i = interfaces.begin (); i != interfaces.end(); i++)
    {
      //Checking netdevice:
      const WifiNetDevice * wifiNetDev = dynamic_cast<const WifiNetDevice *> (PeekPointer (*i));
      if (wifiNetDev == NULL)
        return false;
      MeshWifiInterfaceMac * mac = dynamic_cast<MeshWifiInterfaceMac *> (PeekPointer (wifiNetDev->GetMac ()));
      if (mac == NULL)
        return false;
      //Installing plugins:
      Ptr<HwmpMacPlugin> hwmpMac = Create<HwmpMacPlugin> (wifiNetDev->GetIfIndex (), this);
      m_interfaces[wifiNetDev->GetIfIndex ()] = hwmpMac;
      mac->InstallPlugin (hwmpMac);
    }
  mp->SetRoutingProtocol(this);
  return true;
}
#if 0
void
HwmpProtocol::DisablePort (uint32_t port)
{
  int position = 0;
  for (std::vector<Ptr<HwmpProtocolState> >::iterator i = m_hwmpStates.begin (); i != m_hwmpStates.end(); i++)
    {
      if ((*i)->GetAssociatedIfaceId () == port)
        {
          m_states[position] = DISABLED;
          m_hwmpStates[position]->Disable ();
          return;
        }
      position ++;
    }
}

void
HwmpProtocol::EnablePort (uint32_t port)
{
  int position = 0;
  for (std::vector<Ptr<HwmpProtocolState> >::iterator i = m_hwmpStates.begin (); i != m_hwmpStates.end(); i++)
    {
      if ((*i)->GetAssociatedIfaceId () == port)
        {
          m_states[position] = ENABLED;
          m_hwmpStates[position]->Enable ();
          return;
        }
      position ++;
    }
}

void
HwmpProtocol::SetRoot (uint32_t port)
{
  int position = 0;
  for (std::vector<Ptr<HwmpProtocolState> >::iterator i = m_hwmpStates.begin (); i != m_hwmpStates.end(); i++)
    {
      if (((*i)->GetAssociatedIfaceId () == port)||(port == HwmpRtable::PORT_ANY))
        {
          if (m_hwmpStates[position]->SetRoot ())
            {
              m_modes[position] = ROOT;
              NS_LOG_DEBUG ("I am proactive");
            }
        }
      position ++;
    }
}
void
HwmpProtocol::SetProactive (uint32_t port)
{
  int position = 0;
  for (std::vector<Ptr<HwmpProtocolState> >::iterator i = m_hwmpStates.begin (); i != m_hwmpStates.end(); i++)
    {
      if ((*i)->GetAssociatedIfaceId () == port)
        {
          m_modes[position] = PROACTIVE;
          return;
        }
      position ++;
    }
}
bool
HwmpProtocol::IsRoot (uint32_t port)
{
  int position = 0;
  for (std::vector<Ptr<HwmpProtocolState> >::iterator i = m_hwmpStates.begin (); i != m_hwmpStates.end(); i++)
    {
      if ((*i)->GetAssociatedIfaceId () == port)
        if (m_modes[position] == ROOT)
          return true;
      position ++;
    }
  return false;
}
void
HwmpProtocol::UnSetRoot (uint32_t port)
{
  int position = 0;
  for (std::vector<Ptr<HwmpProtocolState> >::iterator i = m_hwmpStates.begin (); i != m_hwmpStates.end(); i++)
    {
      if (((*i)->GetAssociatedIfaceId () == port)||(port == HwmpRtable::PORT_ANY))
        {
          m_modes[position] = REACTIVE;
          m_hwmpStates[position]->UnSetRoot ();
        }
      position ++;
    }
}

void
HwmpProtocol::ObtainRoutingInformation (
  HwmpProtocolState::INFO info
)
{
  switch (info.type)
    {
    case HwmpProtocolState::INFO_PREP:
      if (info.me != info.source)
        {
          m_rtable->AddPrecursor (info.source, info.outPort, info.nextHop);
          m_rtable->AddPrecursor (info.destination, info.outPort, info.prevHop);
          NS_LOG_DEBUG ("path to "<<info.source<<" precursor is "<<info.nextHop);
          NS_LOG_DEBUG ("path to "<<info.destination<<" precursor is "<<info.prevHop);
        }
    case HwmpProtocolState::INFO_PREQ:
      m_rtable->AddReactivePath (
        info.destination,
        info.nextHop,
        info.outPort,
        info.metric,
        info.lifetime,
        info.dsn);
      SendAllPossiblePackets (info.destination);
      break;
    case HwmpProtocolState::INFO_PERR:
      //delete first subentry
    case HwmpProtocolState::INFO_PROACTIVE:
      //add information to the root MP.
      m_rtable->AddProactivePath (
        info.metric,
        info.destination,
        info.nextHop,
        info.outPort,
        info.lifetime,
        info.dsn);
      //Set mode as PROACTIVE:
      SetProactive (info.outPort);
      break;
    case HwmpProtocolState::INFO_NEW_PEER:
#if 0
      m_rtable->AddReactivePath (
        info.destination,
        info.nextHop,
        info.outPort,
        info.metric,
        Seconds (0),
        0);
#endif
      break;
    case HwmpProtocolState::INFO_FAILED_PEER:
      /**
       * Conditions for generating PERR
       */
    {
      NS_LOG_DEBUG ("Failed peer"<<info.destination);
      std::vector<HwmpRtable::FailedDestination> failedDestinations =
        m_rtable->GetUnreachableDestinations (info.destination, info.outPort);
      /**
       * Entry about peer does not contain seqnum
       */
      HwmpRtable::FailedDestination peer;
      peer.destination = info.destination;
      peer.seqnum = 0;
      failedDestinations.push_back (peer);
      StartPathErrorProcedure (failedDestinations, info.outPort);
    }
    break;
    default:
      return;
    }
}

HwmpRtable::LookupResult
HwmpProtocol::RequestRouteForAddress (const Mac48Address& dst)
{
  return m_rtable->LookupReactive (dst);
}

HwmpRtable::LookupResult
HwmpProtocol::RequestRootPathForPort (uint32_t port)
{
  return m_rtable->LookupProactive (port);
}

void
HwmpProtocol::StartPathErrorProcedure (std::vector<HwmpRtable::FailedDestination> destinations, uint32_t port)
{
  NS_LOG_DEBUG ("START PERR");
  for (unsigned int i  = 0; i < m_hwmpStates.size (); i++)
    if (m_hwmpStates[i]->GetAssociatedIfaceId () == port)
      m_pathErrorCallback[i] (destinations);
}
std::vector<Mac48Address>
HwmpProtocol::GetRetransmittersForFailedDestinations (std::vector<HwmpRtable::FailedDestination> failedDest, uint32_t port)
{
  std::vector<Mac48Address> retransmitters;
  if (m_broadcastPerr)
    retransmitters.push_back (Mac48Address::GetBroadcast());
  else
    for (unsigned int i = 0; i < failedDest.size (); i ++)
      {
        std::vector<Mac48Address> precursors =
          m_rtable->GetPrecursors (failedDest[i].destination, port);
        for (unsigned int j = 0; j < precursors.size (); j++)
          {
            for (unsigned int k = 0; k < retransmitters.size (); k ++)
              if (retransmitters[k] == precursors[j])
                break;
            retransmitters.push_back (precursors[j]);
          }
      }
  for (unsigned int i = 0; i < failedDest.size (); i ++)
    {
      m_rtable->DeleteReactivePath (failedDest[i].destination, port);
      m_rtable->DeleteProactivePath (failedDest[i].destination, port);
    }
  return retransmitters;
}
#endif
void
HwmpProtocol::SetMaxQueueSize (int maxPacketsPerDestination)
{
}
bool
HwmpProtocol::QueuePacket (MeshL2RoutingProtocol::QueuedPacket packet)
{
#if 0
  if ((int)m_rqueue[packet.dst].size () > m_maxQueueSize)
    return false;
  m_rqueue[packet.dst].push (packet);
#endif
  return true;
}

MeshL2RoutingProtocol::QueuedPacket
HwmpProtocol::DequeuePacket (Mac48Address dst)
{
  MeshL2RoutingProtocol::QueuedPacket retval;
#if 0
  retval.pkt = NULL;
  //Ptr<Packet> in this structure is NULL when queue is empty
  std::map<Mac48Address, std::queue<QueuedPacket> >:: iterator i = m_rqueue.find (dst);
  if (i == m_rqueue.end ())
    return retval;
  if ((int)m_rqueue[dst].size () == 0)
    return retval;
  if ((int)i->second.size () == 0)
    {
      m_rqueue.erase (i);
      return retval;
    }
  retval = m_rqueue[dst].front ();
  m_rqueue[dst].pop ();
#endif
  return retval;
}
void
HwmpProtocol::SendAllPossiblePackets (Mac48Address dst)
{
#if 0
  HwmpRtable::LookupResult result = m_rtable->LookupReactive (dst);
  MeshL2RoutingProtocol::QueuedPacket packet;
  while (1)

    {
      packet = DequeuePacket (dst);
      if (packet.pkt == NULL)
        return;
      //set RA tag for retransmitter:
      HwmpProtocolTag tag;
      NS_ASSERT (packet.pkt->FindFirstMatchingTag(tag));
      tag.SetAddress (result.retransmitter);
      NS_ASSERT (result.retransmitter != Mac48Address::GetBroadcast());
      packet.pkt->RemoveAllTags ();
      packet.pkt->AddTag (tag);
      packet.reply (true, packet.pkt, packet.src, packet.dst, packet.protocol, result.ifIndex);
    }
#endif
}
#if 0
bool
HwmpProtocol::ShouldSendPreq (Mac48Address dst)
{
  std::map<Mac48Address, EventId>::iterator i = m_timeoutDatabase.find (dst);
  if (i == m_timeoutDatabase.end ())
    {
      m_timeoutDatabase[dst] = Simulator::Schedule (
                                 MilliSeconds (2*(dot11sParameters::dot11MeshHWMPnetDiameterTraversalTime.GetMilliSeconds())),
                                 &HwmpProtocol::RetryPathDiscovery, this, dst, 0);
      return true;
    }
  return false;
}
void
HwmpProtocol::RetryPathDiscovery (Mac48Address dst, uint8_t numOfRetry)
{
  HwmpRtable::LookupResult result = m_rtable->LookupReactive (dst);
  if (result.retransmitter != Mac48Address::GetBroadcast ())
    {
      std::map<Mac48Address, EventId>::iterator i = m_timeoutDatabase.find (dst);
      NS_ASSERT (i !=  m_timeoutDatabase.end());
      m_timeoutDatabase.erase (i);
      return;
    }
  numOfRetry++;
  if (numOfRetry > dot11sParameters::dot11MeshHWMPmaxPREQretries)
    {
      MeshL2RoutingProtocol::QueuedPacket packet;
      //purge queue and delete entry from retryDatabase
      while (1)
        {
          packet = DequeuePacket (dst);
          if (packet.pkt == NULL)
            break;
          packet.reply (false, packet.pkt, packet.src, packet.dst, packet.protocol, HwmpRtable::MAX_METRIC);
        }
      std::map<Mac48Address, EventId>::iterator i = m_timeoutDatabase.find (dst);
      NS_ASSERT (i !=  m_timeoutDatabase.end());
      m_timeoutDatabase.erase (i);
      return;
    }
  for (unsigned int i = 0; i < m_requestCallback.size (); i++)
    if ((m_modes[i] == REACTIVE) || (m_modes[i] == ROOT))
      m_requestCallback[i] (dst);
  m_timeoutDatabase[dst] = Simulator::Schedule (
                             MilliSeconds (2*(dot11sParameters::dot11MeshHWMPnetDiameterTraversalTime.GetMilliSeconds())),
                             &HwmpProtocol::RetryPathDiscovery, this, dst, numOfRetry);
}
#endif
} //namespace dot11s
} //namespace ns3