void RipNg::HandleResponses()

in simulation/src/internet/model/ripng.cc [925:1079]


void RipNg::HandleResponses (RipNgHeader hdr, Ipv6Address senderAddress, uint32_t incomingInterface, uint8_t hopLimit)
{
  NS_LOG_FUNCTION (this << senderAddress << incomingInterface << int (hopLimit) << hdr);

  if (m_interfaceExclusions.find (incomingInterface) != m_interfaceExclusions.end ())
    {
      NS_LOG_LOGIC ("Ignoring an update message from an excluded interface: " << incomingInterface);
      return;
    }

  if (!senderAddress.IsLinkLocal ())
    {
      NS_LOG_LOGIC ("Ignoring an update message from a non-link-local source: " << senderAddress);
      return;
    }

  if (hopLimit != 255)
    {
      NS_LOG_LOGIC ("Ignoring an update message with suspicious hop count: " << int (hopLimit));
      return;
    }

  std::list<RipNgRte> rtes = hdr.GetRteList ();

  // validate the RTEs before processing
  for (std::list<RipNgRte>::iterator iter = rtes.begin ();
      iter != rtes.end (); iter++)
    {
      if (iter->GetRouteMetric () == 0 || iter->GetRouteMetric () > m_linkDown)
        {
          NS_LOG_LOGIC ("Ignoring an update message with malformed metric: " << int (iter->GetRouteMetric ()));
          return;
        }
      if (iter->GetPrefixLen () > 128)
        {
          NS_LOG_LOGIC ("Ignoring an update message with malformed prefix length: " << int (iter->GetPrefixLen ()));
          return;
        }
      if (iter->GetPrefix ().IsLocalhost () ||
          iter->GetPrefix ().IsLinkLocal () ||
          iter->GetPrefix ().IsMulticast ())
        {
          NS_LOG_LOGIC ("Ignoring an update message with wrong prefixes: " << iter->GetPrefix ());
          return;
        }
    }

  bool changed = false;

  for (std::list<RipNgRte>::iterator iter = rtes.begin ();
      iter != rtes.end (); iter++)
    {
      Ipv6Prefix rtePrefix = Ipv6Prefix (iter->GetPrefixLen ());
      Ipv6Address rteAddr = iter->GetPrefix ().CombinePrefix (rtePrefix);

      NS_LOG_LOGIC ("Processing RTE " << *iter);

      uint8_t interfaceMetric = 1;
      if (m_interfaceMetrics.find (incomingInterface) != m_interfaceMetrics.end ())
        {
          interfaceMetric = m_interfaceMetrics[incomingInterface];
        }
      uint16_t rteMetric = iter->GetRouteMetric () + interfaceMetric;
      if (rteMetric > m_linkDown)
        {
          rteMetric = m_linkDown;
        }
      RoutesI it;
      bool found = false;
      for (it = m_routes.begin (); it != m_routes.end (); it++)
        {
          if (it->first->GetDestNetwork () == rteAddr &&
              it->first->GetDestNetworkPrefix () == rtePrefix)
            {
              found = true;
              if (rteMetric < it->first->GetRouteMetric ())
                {
                  if (senderAddress != it->first->GetGateway ())
                    {
                      RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry (rteAddr, rtePrefix, senderAddress, incomingInterface, Ipv6Address::GetAny ());
                      delete it->first;
                      it->first = route;
                    }
                  it->first->SetRouteMetric (rteMetric);
                  it->first->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
                  it->first->SetRouteTag (iter->GetRouteTag ());
                  it->first->SetRouteChanged (true);
                  it->second.Cancel ();
                  it->second = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, it->first);
                  changed = true;
                }
              else if (rteMetric == it->first->GetRouteMetric ())
                {
                  if (senderAddress == it->first->GetGateway ())
                    {
                      it->second.Cancel ();
                      it->second = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, it->first);
                    }
                  else
                    {
                      if (Simulator::GetDelayLeft (it->second) < m_timeoutDelay/2)
                        {
                          RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry (rteAddr, rtePrefix, senderAddress, incomingInterface, Ipv6Address::GetAny ());
                          route->SetRouteMetric (rteMetric);
                          route->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
                          route->SetRouteTag (iter->GetRouteTag ());
                          route->SetRouteChanged (true);
                          delete it->first;
                          it->first = route;
                          it->second.Cancel ();
                          it->second = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, route);
                          changed = true;
                        }
                    }
                }
              else if (rteMetric > it->first->GetRouteMetric () && senderAddress == it->first->GetGateway ())
                {
                  it->second.Cancel ();
                  if (rteMetric < m_linkDown)
                    {
                      it->first->SetRouteMetric (rteMetric);
                      it->first->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
                      it->first->SetRouteTag (iter->GetRouteTag ());
                      it->first->SetRouteChanged (true);
                      it->second.Cancel ();
                      it->second = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, it->first);
                    }
                  else
                    {
                      InvalidateRoute (it->first);
                    }
                  changed = true;
                }
            }
        }
      if (!found && rteMetric != m_linkDown)
        {
          NS_LOG_LOGIC ("Received a RTE with new route, adding.");

          RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry (rteAddr, rtePrefix, senderAddress, incomingInterface, Ipv6Address::GetAny ());
          route->SetRouteMetric (rteMetric);
          route->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
          route->SetRouteChanged (true);
          m_routes.push_front (std::make_pair (route, EventId ()));
          EventId invalidateEvent = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, route);
          (m_routes.begin ())->second = invalidateEvent;
          changed = true;
        }
    }

  if (changed)
    {
      SendTriggeredRouteUpdate ();
    }
}