// -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*-
//
// Copyright (c) 2006 Georgia Tech Research Corporation
//
// 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: George F. Riley<riley@ece.gatech.edu>
// Gustavo Carneiro <gjc@inescporto.pt>
#define NS_LOG_APPEND_CONTEXT \
if (m_ipv4 && m_ipv4->GetObject<Node> ()) { \
std::clog << Simulator::Now ().GetSeconds () \
<< " [node " << m_ipv4->GetObject<Node> ()->GetId () << "] "; }
#include <iomanip>
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/packet.h"
#include "ns3/node.h"
#include "ns3/simulator.h"
#include "ns3/ipv4-route.h"
#include "ns3/output-stream-wrapper.h"
#include "ipv4-static-routing.h"
#include "ipv4-routing-table-entry.h"
NS_LOG_COMPONENT_DEFINE ("Ipv4StaticRouting");
using std::make_pair;
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (Ipv4StaticRouting);
TypeId
Ipv4StaticRouting::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::Ipv4StaticRouting")
.SetParent<Ipv4RoutingProtocol> ()
.AddConstructor<Ipv4StaticRouting> ()
;
return tid;
}
Ipv4StaticRouting::Ipv4StaticRouting ()
: m_ipv4 (0)
{
NS_LOG_FUNCTION (this);
}
void
Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network,
Ipv4Mask networkMask,
Ipv4Address nextHop,
uint32_t interface,
uint32_t metric)
{
NS_LOG_FUNCTION (this << network << " " << networkMask << " " << nextHop << " " << interface << " " << metric);
Ipv4RoutingTableEntry *route = new Ipv4RoutingTableEntry ();
*route = Ipv4RoutingTableEntry::CreateNetworkRouteTo (network,
networkMask,
nextHop,
interface);
m_networkRoutes.push_back (make_pair (route,metric));
}
void
Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network,
Ipv4Mask networkMask,
uint32_t interface,
uint32_t metric)
{
NS_LOG_FUNCTION (this << network << " " << networkMask << " " << interface << " " << metric);
Ipv4RoutingTableEntry *route = new Ipv4RoutingTableEntry ();
*route = Ipv4RoutingTableEntry::CreateNetworkRouteTo (network,
networkMask,
interface);
m_networkRoutes.push_back (make_pair (route,metric));
}
void
Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest,
Ipv4Address nextHop,
uint32_t interface,
uint32_t metric)
{
NS_LOG_FUNCTION (this << dest << " " << nextHop << " " << interface << " " << metric);
AddNetworkRouteTo (dest, Ipv4Mask::GetOnes (), nextHop, interface, metric);
}
void
Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest,
uint32_t interface,
uint32_t metric)
{
NS_LOG_FUNCTION (this << dest << " " << interface << " " << metric);
AddNetworkRouteTo (dest, Ipv4Mask::GetOnes (), interface, metric);
}
void
Ipv4StaticRouting::SetDefaultRoute (Ipv4Address nextHop,
uint32_t interface,
uint32_t metric)
{
NS_LOG_FUNCTION (this << nextHop << " " << interface << " " << metric);
AddNetworkRouteTo (Ipv4Address ("0.0.0.0"), Ipv4Mask::GetZero (), nextHop, interface, metric);
}
void
Ipv4StaticRouting::AddMulticastRoute (Ipv4Address origin,
Ipv4Address group,
uint32_t inputInterface,
std::vector<uint32_t> outputInterfaces)
{
NS_LOG_FUNCTION (this << origin << " " << group << " " << inputInterface);
Ipv4MulticastRoutingTableEntry *route = new Ipv4MulticastRoutingTableEntry ();
*route = Ipv4MulticastRoutingTableEntry::CreateMulticastRoute (origin, group,
inputInterface, outputInterfaces);
m_multicastRoutes.push_back (route);
}
// default multicast routes are stored as a network route
// these routes are _not_ consulted in the forwarding process-- only
// for originating packets
void
Ipv4StaticRouting::SetDefaultMulticastRoute (uint32_t outputInterface)
{
NS_LOG_FUNCTION (this << outputInterface);
Ipv4RoutingTableEntry *route = new Ipv4RoutingTableEntry ();
Ipv4Address network = Ipv4Address ("224.0.0.0");
Ipv4Mask networkMask = Ipv4Mask ("240.0.0.0");
*route = Ipv4RoutingTableEntry::CreateNetworkRouteTo (network,
networkMask,
outputInterface);
m_networkRoutes.push_back (make_pair (route,0));
}
uint32_t
Ipv4StaticRouting::GetNMulticastRoutes (void) const
{
NS_LOG_FUNCTION (this);
return m_multicastRoutes.size ();
}
Ipv4MulticastRoutingTableEntry
Ipv4StaticRouting::GetMulticastRoute (uint32_t index) const
{
NS_LOG_FUNCTION (this << index);
NS_ASSERT_MSG (index < m_multicastRoutes.size (),
"Ipv4StaticRouting::GetMulticastRoute (): Index out of range");
if (index < m_multicastRoutes.size ())
{
uint32_t tmp = 0;
for (MulticastRoutesCI i = m_multicastRoutes.begin ();
i != m_multicastRoutes.end ();
i++)
{
if (tmp == index)
{
return *i;
}
tmp++;
}
}
return 0;
}
bool
Ipv4StaticRouting::RemoveMulticastRoute (Ipv4Address origin,
Ipv4Address group,
uint32_t inputInterface)
{
NS_LOG_FUNCTION (this << origin << " " << group << " " << inputInterface);
for (MulticastRoutesI i = m_multicastRoutes.begin ();
i != m_multicastRoutes.end ();
i++)
{
Ipv4MulticastRoutingTableEntry *route = *i;
if (origin == route->GetOrigin () &&
group == route->GetGroup () &&
inputInterface == route->GetInputInterface ())
{
delete *i;
m_multicastRoutes.erase (i);
return true;
}
}
return false;
}
void
Ipv4StaticRouting::RemoveMulticastRoute (uint32_t index)
{
NS_LOG_FUNCTION (this << index);
uint32_t tmp = 0;
for (MulticastRoutesI i = m_multicastRoutes.begin ();
i != m_multicastRoutes.end ();
i++)
{
if (tmp == index)
{
delete *i;
m_multicastRoutes.erase (i);
return;
}
tmp++;
}
}
Ptr<Ipv4Route>
Ipv4StaticRouting::LookupStatic (Ipv4Address dest, Ptr<NetDevice> oif)
{
NS_LOG_FUNCTION (this << dest << " " << oif);
Ptr<Ipv4Route> rtentry = 0;
uint16_t longest_mask = 0;
uint32_t shortest_metric = 0xffffffff;
/* when sending on local multicast, there have to be interface specified */
if (dest.IsLocalMulticast ())
{
NS_ASSERT_MSG (oif, "Try to send on link-local multicast address, and no interface index is given!");
rtentry = Create<Ipv4Route> ();
rtentry->SetDestination (dest);
rtentry->SetGateway (Ipv4Address::GetZero ());
rtentry->SetOutputDevice (oif);
rtentry->SetSource (m_ipv4->GetAddress (oif->GetIfIndex (), 0).GetLocal ());
return rtentry;
}
for (NetworkRoutesI i = m_networkRoutes.begin ();
i != m_networkRoutes.end ();
i++)
{
Ipv4RoutingTableEntry *j=i->first;
uint32_t metric =i->second;
Ipv4Mask mask = (j)->GetDestNetworkMask ();
uint16_t masklen = mask.GetPrefixLength ();
Ipv4Address entry = (j)->GetDestNetwork ();
NS_LOG_LOGIC ("Searching for route to " << dest << ", checking against route to " << entry << "/" << masklen);
if (mask.IsMatch (dest, entry))
{
NS_LOG_LOGIC ("Found global network route " << j << ", mask length " << masklen << ", metric " << metric);
if (oif != 0)
{
if (oif != m_ipv4->GetNetDevice (j->GetInterface ()))
{
NS_LOG_LOGIC ("Not on requested interface, skipping");
continue;
}
}
if (masklen < longest_mask) // Not interested if got shorter mask
{
NS_LOG_LOGIC ("Previous match longer, skipping");
continue;
}
if (masklen > longest_mask) // Reset metric if longer masklen
{
shortest_metric = 0xffffffff;
}
longest_mask = masklen;
if (metric > shortest_metric)
{
NS_LOG_LOGIC ("Equal mask length, but previous metric shorter, skipping");
continue;
}
shortest_metric = metric;
Ipv4RoutingTableEntry* route = (j);
uint32_t interfaceIdx = route->GetInterface ();
rtentry = Create<Ipv4Route> ();
rtentry->SetDestination (route->GetDest ());
rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetDest ()));
rtentry->SetGateway (route->GetGateway ());
rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIdx));
}
}
if (rtentry != 0)
{
NS_LOG_LOGIC ("Matching route via " << rtentry->GetGateway () << " at the end");
}
else
{
NS_LOG_LOGIC ("No matching route to " << dest << " found");
}
return rtentry;
}
Ptr<Ipv4MulticastRoute>
Ipv4StaticRouting::LookupStatic (
Ipv4Address origin,
Ipv4Address group,
uint32_t interface)
{
NS_LOG_FUNCTION (this << origin << " " << group << " " << interface);
Ptr<Ipv4MulticastRoute> mrtentry = 0;
for (MulticastRoutesI i = m_multicastRoutes.begin ();
i != m_multicastRoutes.end ();
i++)
{
Ipv4MulticastRoutingTableEntry *route = *i;
//
// We've been passed an origin address, a multicast group address and an
// interface index. We have to decide if the current route in the list is
// a match.
//
// The first case is the restrictive case where the origin, group and index
// matches.
//
if (origin == route->GetOrigin () && group == route->GetGroup ())
{
// Skipping this case (SSM) for now
NS_LOG_LOGIC ("Found multicast source specific route" << *i);
}
if (group == route->GetGroup ())
{
if (interface == Ipv4::IF_ANY ||
interface == route->GetInputInterface ())
{
NS_LOG_LOGIC ("Found multicast route" << *i);
mrtentry = Create<Ipv4MulticastRoute> ();
mrtentry->SetGroup (route->GetGroup ());
mrtentry->SetOrigin (route->GetOrigin ());
mrtentry->SetParent (route->GetInputInterface ());
for (uint32_t j = 0; j < route->GetNOutputInterfaces (); j++)
{
if (route->GetOutputInterface (j))
{
NS_LOG_LOGIC ("Setting output interface index " << route->GetOutputInterface (j));
mrtentry->SetOutputTtl (route->GetOutputInterface (j), Ipv4MulticastRoute::MAX_TTL - 1);
}
}
return mrtentry;
}
}
}
return mrtentry;
}
uint32_t
Ipv4StaticRouting::GetNRoutes (void) const
{
NS_LOG_FUNCTION (this);
return m_networkRoutes.size ();;
}
Ipv4RoutingTableEntry
Ipv4StaticRouting::GetDefaultRoute ()
{
NS_LOG_FUNCTION (this);
// Basically a repeat of LookupStatic, retained for backward compatibility
Ipv4Address dest ("0.0.0.0");
uint32_t shortest_metric = 0xffffffff;
Ipv4RoutingTableEntry *result = 0;
for (NetworkRoutesI i = m_networkRoutes.begin ();
i != m_networkRoutes.end ();
i++)
{
Ipv4RoutingTableEntry *j = i->first;
uint32_t metric = i->second;
Ipv4Mask mask = (j)->GetDestNetworkMask ();
uint16_t masklen = mask.GetPrefixLength ();
if (masklen != 0)
{
continue;
}
if (metric > shortest_metric)
{
continue;
}
shortest_metric = metric;
result = j;
}
if (result)
{
return result;
}
else
{
return Ipv4RoutingTableEntry ();
}
}
Ipv4RoutingTableEntry
Ipv4StaticRouting::GetRoute (uint32_t index) const
{
NS_LOG_FUNCTION (this << index);
uint32_t tmp = 0;
for (NetworkRoutesCI j = m_networkRoutes.begin ();
j != m_networkRoutes.end ();
j++)
{
if (tmp == index)
{
return j->first;
}
tmp++;
}
NS_ASSERT (false);
// quiet compiler.
return 0;
}
uint32_t
Ipv4StaticRouting::GetMetric (uint32_t index)
{
NS_LOG_FUNCTION (this << index);
uint32_t tmp = 0;
for (NetworkRoutesI j = m_networkRoutes.begin ();
j != m_networkRoutes.end ();
j++)
{
if (tmp == index)
{
return j->second;
}
tmp++;
}
NS_ASSERT (false);
// quiet compiler.
return 0;
}
void
Ipv4StaticRouting::RemoveRoute (uint32_t index)
{
NS_LOG_FUNCTION (this << index);
uint32_t tmp = 0;
for (NetworkRoutesI j = m_networkRoutes.begin ();
j != m_networkRoutes.end ();
j++)
{
if (tmp == index)
{
delete j->first;
m_networkRoutes.erase (j);
return;
}
tmp++;
}
NS_ASSERT (false);
}
Ptr<Ipv4Route>
Ipv4StaticRouting::RouteOutput (Ptr<Packet> p, const Ipv4Header &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr)
{
NS_LOG_FUNCTION (this << header << oif);
Ipv4Address destination = header.GetDestination ();
Ptr<Ipv4Route> rtentry = 0;
// Multicast goes here
if (destination.IsMulticast ())
{
// Note: Multicast routes for outbound packets are stored in the
// normal unicast table. An implication of this is that it is not
// possible to source multicast datagrams on multiple interfaces.
// This is a well-known property of sockets implementation on
// many Unix variants.
// So, we just log it and fall through to LookupStatic ()
NS_LOG_LOGIC ("RouteOutput()::Multicast destination");
}
rtentry = LookupStatic (destination, oif);
if (rtentry)
{
sockerr = Socket::ERROR_NOTERROR;
}
else
{
sockerr = Socket::ERROR_NOROUTETOHOST;
}
return rtentry;
}
bool
Ipv4StaticRouting::RouteInput (Ptr<const Packet> p, const Ipv4Header &ipHeader, Ptr<const NetDevice> idev,
UnicastForwardCallback ucb, MulticastForwardCallback mcb,
LocalDeliverCallback lcb, ErrorCallback ecb)
{
NS_LOG_FUNCTION (this << p << ipHeader << ipHeader.GetSource () << ipHeader.GetDestination () << idev);
NS_ASSERT (m_ipv4 != 0);
// Check if input device supports IP
NS_ASSERT (m_ipv4->GetInterfaceForDevice (idev) >= 0);
uint32_t iif = m_ipv4->GetInterfaceForDevice (idev);
// Multicast recognition; handle local delivery here
//
if (ipHeader.GetDestination ().IsMulticast ())
{
NS_LOG_LOGIC ("Multicast destination");
Ptr<Ipv4MulticastRoute> mrtentry = LookupStatic (ipHeader.GetSource (),
ipHeader.GetDestination (), m_ipv4->GetInterfaceForDevice (idev));
if (mrtentry)
{
NS_LOG_LOGIC ("Multicast route found");
mcb (mrtentry, p, ipHeader); // multicast forwarding callback
return true;
}
else
{
NS_LOG_LOGIC ("Multicast route not found");
return false; // Let other routing protocols try to handle this
}
}
if (ipHeader.GetDestination ().IsBroadcast ())
{
NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)");
// TODO: Local Deliver for broadcast
// TODO: Forward broadcast
}
NS_LOG_LOGIC ("Unicast destination");
// TODO: Configurable option to enable RFC 1222 Strong End System Model
// Right now, we will be permissive and allow a source to send us
// a packet to one of our other interface addresses; that is, the
// destination unicast address does not match one of the iif addresses,
// but we check our other interfaces. This could be an option
// (to remove the outer loop immediately below and just check iif).
for (uint32_t j = 0; j < m_ipv4->GetNInterfaces (); j++)
{
for (uint32_t i = 0; i < m_ipv4->GetNAddresses (j); i++)
{
Ipv4InterfaceAddress iaddr = m_ipv4->GetAddress (j, i);
Ipv4Address addr = iaddr.GetLocal ();
if (addr.IsEqual (ipHeader.GetDestination ()))
{
if (j == iif)
{
NS_LOG_LOGIC ("For me (destination " << addr << " match)");
}
else
{
NS_LOG_LOGIC ("For me (destination " << addr << " match) on another interface " << ipHeader.GetDestination ());
}
lcb (p, ipHeader, iif);
return true;
}
if (ipHeader.GetDestination ().IsEqual (iaddr.GetBroadcast ()))
{
NS_LOG_LOGIC ("For me (interface broadcast address)");
lcb (p, ipHeader, iif);
return true;
}
NS_LOG_LOGIC ("Address "<< addr << " not a match");
}
}
// Check if input device supports IP forwarding
if (m_ipv4->IsForwarding (iif) == false)
{
NS_LOG_LOGIC ("Forwarding disabled for this interface");
ecb (p, ipHeader, Socket::ERROR_NOROUTETOHOST);
return false;
}
// Next, try to find a route
Ptr<Ipv4Route> rtentry = LookupStatic (ipHeader.GetDestination ());
if (rtentry != 0)
{
NS_LOG_LOGIC ("Found unicast destination- calling unicast callback");
ucb (rtentry, p, ipHeader); // unicast forwarding callback
return true;
}
else
{
NS_LOG_LOGIC ("Did not find unicast destination- returning false");
return false; // Let other routing protocols try to handle this
}
}
Ipv4StaticRouting::~Ipv4StaticRouting ()
{
}
void
Ipv4StaticRouting::DoDispose (void)
{
for (NetworkRoutesI j = m_networkRoutes.begin ();
j != m_networkRoutes.end ();
j = m_networkRoutes.erase (j))
{
delete (j->first);
}
for (MulticastRoutesI i = m_multicastRoutes.begin ();
i != m_multicastRoutes.end ();
i = m_multicastRoutes.erase (i))
{
delete (*i);
}
m_ipv4 = 0;
Ipv4RoutingProtocol::DoDispose ();
}
void
Ipv4StaticRouting::NotifyInterfaceUp (uint32_t i)
{
NS_LOG_FUNCTION (this << i);
// If interface address and network mask have been set, add a route
// to the network of the interface (like e.g. ifconfig does on a
// Linux box)
for (uint32_t j = 0; j < m_ipv4->GetNAddresses (i); j++)
{
if (m_ipv4->GetAddress (i,j).GetLocal () != Ipv4Address () &&
m_ipv4->GetAddress (i,j).GetMask () != Ipv4Mask () &&
m_ipv4->GetAddress (i,j).GetMask () != Ipv4Mask::GetOnes ())
{
AddNetworkRouteTo (m_ipv4->GetAddress (i,j).GetLocal ().CombineMask (m_ipv4->GetAddress (i,j).GetMask ()),
m_ipv4->GetAddress (i,j).GetMask (), i);
}
}
}
void
Ipv4StaticRouting::NotifyInterfaceDown (uint32_t i)
{
NS_LOG_FUNCTION (this << i);
// Remove all static routes that are going through this interface
uint32_t j = 0;
while (j < GetNRoutes ())
{
Ipv4RoutingTableEntry route = GetRoute (j);
if (route.GetInterface () == i)
{
RemoveRoute (j);
}
else
{
j++;
}
}
}
void
Ipv4StaticRouting::NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address)
{
NS_LOG_FUNCTION (this << interface << " " << address.GetLocal ());
if (!m_ipv4->IsUp (interface))
{
return;
}
Ipv4Address networkAddress = address.GetLocal ().CombineMask (address.GetMask ());
Ipv4Mask networkMask = address.GetMask ();
if (address.GetLocal () != Ipv4Address () &&
address.GetMask () != Ipv4Mask ())
{
AddNetworkRouteTo (networkAddress,
networkMask, interface);
}
}
void
Ipv4StaticRouting::NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address)
{
NS_LOG_FUNCTION (this << interface << " " << address.GetLocal ());
if (!m_ipv4->IsUp (interface))
{
return;
}
Ipv4Address networkAddress = address.GetLocal ().CombineMask (address.GetMask ());
Ipv4Mask networkMask = address.GetMask ();
// Remove all static routes that are going through this interface
// which reference this network
for (uint32_t j = 0; j < GetNRoutes (); j++)
{
Ipv4RoutingTableEntry route = GetRoute (j);
if (route.GetInterface () == interface &&
route.IsNetwork () &&
route.GetDestNetwork () == networkAddress &&
route.GetDestNetworkMask () == networkMask)
{
RemoveRoute (j);
}
}
}
void
Ipv4StaticRouting::SetIpv4 (Ptr<Ipv4> ipv4)
{
NS_LOG_FUNCTION (this << ipv4);
NS_ASSERT (m_ipv4 == 0 && ipv4 != 0);
m_ipv4 = ipv4;
for (uint32_t i = 0; i < m_ipv4->GetNInterfaces (); i++)
{
if (m_ipv4->IsUp (i))
{
NotifyInterfaceUp (i);
}
else
{
NotifyInterfaceDown (i);
}
}
}
// Formatted like output of "route -n" command
void
Ipv4StaticRouting::PrintRoutingTable (Ptr<OutputStreamWrapper> stream) const
{
std::ostream* os = stream->GetStream ();
if (GetNRoutes () > 0)
{
*os << "Destination Gateway Genmask Flags Metric Ref Use Iface" << std::endl;
for (uint32_t j = 0; j < GetNRoutes (); j++)
{
std::ostringstream dest, gw, mask, flags;
Ipv4RoutingTableEntry route = GetRoute (j);
dest << route.GetDest ();
*os << std::setiosflags (std::ios::left) << std::setw (16) << dest.str ();
gw << route.GetGateway ();
*os << std::setiosflags (std::ios::left) << std::setw (16) << gw.str ();
mask << route.GetDestNetworkMask ();
*os << std::setiosflags (std::ios::left) << std::setw (16) << mask.str ();
flags << "U";
if (route.IsHost ())
{
flags << "HS";
}
else if (route.IsGateway ())
{
flags << "GS";
}
*os << std::setiosflags (std::ios::left) << std::setw (6) << flags.str ();
// Metric not implemented
*os << "-" << " ";
// Ref ct not implemented
*os << "-" << " ";
// Use not implemented
*os << "-" << " ";
if (Names::FindName (m_ipv4->GetNetDevice (route.GetInterface ())) != "")
{
*os << Names::FindName (m_ipv4->GetNetDevice (route.GetInterface ()));
}
else
{
*os << route.GetInterface ();
}
*os << std::endl;
}
}
}
Ipv4Address
Ipv4StaticRouting::SourceAddressSelection (uint32_t interfaceIdx, Ipv4Address dest)
{
NS_LOG_FUNCTION (this << interfaceIdx << " " << dest);
if (m_ipv4->GetNAddresses (interfaceIdx) == 1) // common case
{
return m_ipv4->GetAddress (interfaceIdx, 0).GetLocal ();
}
// no way to determine the scope of the destination, so adopt the
// following rule: pick the first available address (index 0) unless
// a subsequent address is on link (in which case, pick the primary
// address if there are multiple)
Ipv4Address candidate = m_ipv4->GetAddress (interfaceIdx, 0).GetLocal ();
for (uint32_t i = 0; i < m_ipv4->GetNAddresses (interfaceIdx); i++)
{
Ipv4InterfaceAddress test = m_ipv4->GetAddress (interfaceIdx, i);
if (test.GetLocal ().CombineMask (test.GetMask ()) == dest.CombineMask (test.GetMask ()))
{
if (test.IsSecondary () == false)
{
return test.GetLocal ();
}
}
}
return candidate;
}
} // namespace ns3