571 lines
13 KiB
C++
571 lines
13 KiB
C++
// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
|
|
//
|
|
// Copyright (c) 2006 Georgia Tech Research Corporation
|
|
// 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: George F. Riley<riley@ece.gatech.edu>
|
|
//
|
|
|
|
#include "ns3/packet.h"
|
|
#include "ns3/debug.h"
|
|
#include "ns3/composite-trace-resolver.h"
|
|
#include "ns3/array-trace-resolver.h"
|
|
#include "ns3/callback.h"
|
|
#include "ns3/ipv4-address.h"
|
|
#include "ns3/ipv4-route.h"
|
|
#include "ns3/node.h"
|
|
|
|
#include "ipv4.h"
|
|
#include "ipv4-l4-protocol.h"
|
|
#include "ipv4-header.h"
|
|
#include "ipv4-interface.h"
|
|
#include "ipv4-loopback-interface.h"
|
|
#include "arp-ipv4-interface.h"
|
|
#include "ipv4-l4-demux.h"
|
|
|
|
NS_DEBUG_COMPONENT_DEFINE ("Ipv4");
|
|
|
|
namespace ns3 {
|
|
|
|
const uint16_t Ipv4::PROT_NUMBER = 0x0800;
|
|
|
|
Ipv4::Ipv4(Node *node)
|
|
: L3Protocol (PROT_NUMBER, 4),
|
|
m_nInterfaces (0),
|
|
m_defaultTtl (64),
|
|
m_identification (0),
|
|
m_defaultRoute (0),
|
|
m_node (node)
|
|
{
|
|
SetupLoopback ();
|
|
m_node->Ref ();
|
|
}
|
|
Ipv4::~Ipv4 ()
|
|
{
|
|
DoDispose ();
|
|
}
|
|
|
|
void
|
|
Ipv4::DoDispose (void)
|
|
{
|
|
for (Ipv4InterfaceList::iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
|
|
{
|
|
::delete (*i);
|
|
}
|
|
m_interfaces.clear ();
|
|
for (HostRoutesI i = m_hostRoutes.begin ();
|
|
i != m_hostRoutes.end ();
|
|
i = m_hostRoutes.erase (i))
|
|
{
|
|
delete (*i);
|
|
}
|
|
for (NetworkRoutesI j = m_networkRoutes.begin ();
|
|
j != m_networkRoutes.end ();
|
|
j = m_networkRoutes.erase (j))
|
|
{
|
|
delete (*j);
|
|
}
|
|
if (m_defaultRoute != 0)
|
|
{
|
|
delete m_defaultRoute;
|
|
m_defaultRoute = 0;
|
|
}
|
|
if (m_node != 0)
|
|
{
|
|
m_node->Unref ();
|
|
m_node = 0;
|
|
}
|
|
L3Protocol::DoDispose ();
|
|
}
|
|
|
|
void
|
|
Ipv4::SetupLoopback (void)
|
|
{
|
|
Ipv4LoopbackInterface * interface = new Ipv4LoopbackInterface (m_node);
|
|
interface->SetAddress (Ipv4Address::GetLoopback ());
|
|
interface->SetNetworkMask (Ipv4Mask::GetLoopback ());
|
|
uint32_t index = AddIpv4Interface (interface);
|
|
AddHostRouteTo (Ipv4Address::GetLoopback (), index);
|
|
interface->SetUp ();
|
|
}
|
|
|
|
TraceResolver *
|
|
Ipv4::CreateTraceResolver (TraceContext const &context)
|
|
{
|
|
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
|
|
resolver->Add ("tx", m_txTrace, Ipv4::TX);
|
|
resolver->Add ("rx", m_rxTrace, Ipv4::RX);
|
|
resolver->Add ("drop", m_dropTrace, Ipv4::DROP);
|
|
resolver->Add ("interfaces",
|
|
MakeCallback (&Ipv4::InterfacesCreateTraceResolver, this),
|
|
Ipv4::INTERFACES);
|
|
return resolver;
|
|
}
|
|
|
|
TraceResolver *
|
|
Ipv4::InterfacesCreateTraceResolver (TraceContext const &context) const
|
|
{
|
|
ArrayTraceResolver<Ipv4Interface> *resolver =
|
|
new ArrayTraceResolver<Ipv4Interface>
|
|
(context,
|
|
MakeCallback (&Ipv4::GetNInterfaces, this),
|
|
MakeCallback (&Ipv4::GetInterface, this));
|
|
return resolver;
|
|
}
|
|
|
|
void
|
|
Ipv4::SetDefaultTtl (uint8_t ttl)
|
|
{
|
|
m_defaultTtl = ttl;
|
|
}
|
|
|
|
|
|
void
|
|
Ipv4::AddHostRouteTo (Ipv4Address dest,
|
|
Ipv4Address nextHop,
|
|
uint32_t interface)
|
|
{
|
|
Ipv4Route *route = new Ipv4Route ();
|
|
*route = Ipv4Route::CreateHostRouteTo (dest, nextHop, interface);
|
|
m_hostRoutes.push_back (route);
|
|
}
|
|
void
|
|
Ipv4::AddHostRouteTo (Ipv4Address dest,
|
|
uint32_t interface)
|
|
{
|
|
Ipv4Route *route = new Ipv4Route ();
|
|
*route = Ipv4Route::CreateHostRouteTo (dest, interface);
|
|
m_hostRoutes.push_back (route);
|
|
}
|
|
void
|
|
Ipv4::AddNetworkRouteTo (Ipv4Address network,
|
|
Ipv4Mask networkMask,
|
|
Ipv4Address nextHop,
|
|
uint32_t interface)
|
|
{
|
|
Ipv4Route *route = new Ipv4Route ();
|
|
*route = Ipv4Route::CreateNetworkRouteTo (network,
|
|
networkMask,
|
|
nextHop,
|
|
interface);
|
|
m_networkRoutes.push_back (route);
|
|
}
|
|
void
|
|
Ipv4::AddNetworkRouteTo (Ipv4Address network,
|
|
Ipv4Mask networkMask,
|
|
uint32_t interface)
|
|
{
|
|
Ipv4Route *route = new Ipv4Route ();
|
|
*route = Ipv4Route::CreateNetworkRouteTo (network,
|
|
networkMask,
|
|
interface);
|
|
m_networkRoutes.push_back (route);
|
|
}
|
|
void
|
|
Ipv4::SetDefaultRoute (Ipv4Address nextHop,
|
|
uint32_t interface)
|
|
{
|
|
Ipv4Route *route = new Ipv4Route ();
|
|
*route = Ipv4Route::CreateDefaultRoute (nextHop, interface);
|
|
delete m_defaultRoute;
|
|
m_defaultRoute = route;
|
|
}
|
|
|
|
Ipv4Route *
|
|
Ipv4::Lookup (Ipv4Address dest)
|
|
{
|
|
for (HostRoutesCI i = m_hostRoutes.begin ();
|
|
i != m_hostRoutes.end ();
|
|
i++)
|
|
{
|
|
NS_ASSERT ((*i)->IsHost ());
|
|
if ((*i)->GetDest ().IsEqual (dest))
|
|
{
|
|
return (*i);
|
|
}
|
|
}
|
|
for (NetworkRoutesI j = m_networkRoutes.begin ();
|
|
j != m_networkRoutes.end ();
|
|
j++)
|
|
{
|
|
NS_ASSERT ((*j)->IsNetwork ());
|
|
Ipv4Mask mask = (*j)->GetDestNetworkMask ();
|
|
Ipv4Address entry = (*j)->GetDestNetwork ();
|
|
if (mask.IsMatch (dest, entry))
|
|
{
|
|
return (*j);
|
|
}
|
|
}
|
|
if (m_defaultRoute != 0)
|
|
{
|
|
NS_ASSERT (m_defaultRoute->IsDefault ());
|
|
return m_defaultRoute;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t
|
|
Ipv4::GetNRoutes (void)
|
|
{
|
|
uint32_t n = 0;
|
|
if (m_defaultRoute != 0)
|
|
{
|
|
n++;
|
|
}
|
|
n += m_hostRoutes.size ();
|
|
n += m_networkRoutes.size ();
|
|
return n;
|
|
}
|
|
Ipv4Route *
|
|
Ipv4::GetRoute (uint32_t index)
|
|
{
|
|
if (index == 0 && m_defaultRoute != 0)
|
|
{
|
|
return m_defaultRoute;
|
|
}
|
|
if (index > 0 && m_defaultRoute != 0)
|
|
{
|
|
index--;
|
|
}
|
|
if (index < m_hostRoutes.size ())
|
|
{
|
|
uint32_t tmp = 0;
|
|
for (HostRoutesCI i = m_hostRoutes.begin ();
|
|
i != m_hostRoutes.end ();
|
|
i++)
|
|
{
|
|
if (tmp == index)
|
|
{
|
|
return *i;
|
|
}
|
|
tmp++;
|
|
}
|
|
}
|
|
index -= m_hostRoutes.size ();
|
|
uint32_t tmp = 0;
|
|
for (NetworkRoutesI j = m_networkRoutes.begin ();
|
|
j != m_networkRoutes.end ();
|
|
j++)
|
|
{
|
|
if (tmp == index)
|
|
{
|
|
return *j;
|
|
}
|
|
tmp++;
|
|
}
|
|
NS_ASSERT (false);
|
|
// quiet compiler.
|
|
return 0;
|
|
}
|
|
void
|
|
Ipv4::RemoveRoute (uint32_t index)
|
|
{
|
|
if (index == 0 && m_defaultRoute != 0)
|
|
{
|
|
delete m_defaultRoute;
|
|
m_defaultRoute = 0;
|
|
}
|
|
if (index > 0 && m_defaultRoute != 0)
|
|
{
|
|
index--;
|
|
}
|
|
if (index < m_hostRoutes.size ())
|
|
{
|
|
uint32_t tmp = 0;
|
|
for (HostRoutesI i = m_hostRoutes.begin ();
|
|
i != m_hostRoutes.end ();
|
|
i++)
|
|
{
|
|
if (tmp == index)
|
|
{
|
|
delete *i;
|
|
m_hostRoutes.erase (i);
|
|
return;
|
|
}
|
|
tmp++;
|
|
}
|
|
}
|
|
index -= m_hostRoutes.size ();
|
|
uint32_t tmp = 0;
|
|
for (NetworkRoutesI j = m_networkRoutes.begin ();
|
|
j != m_networkRoutes.end ();
|
|
j++)
|
|
{
|
|
if (tmp == index)
|
|
{
|
|
delete *j;
|
|
m_networkRoutes.erase (j);
|
|
return;
|
|
}
|
|
tmp++;
|
|
}
|
|
NS_ASSERT (false);
|
|
}
|
|
|
|
|
|
uint32_t
|
|
Ipv4::AddInterface (NetDevice *device)
|
|
{
|
|
Ptr<Ipv4Interface> interface = new ArpIpv4Interface (m_node, device);
|
|
return AddIpv4Interface (interface);
|
|
}
|
|
uint32_t
|
|
Ipv4::AddIpv4Interface (Ptr<Ipv4Interface> interface)
|
|
{
|
|
uint32_t index = m_nInterfaces;
|
|
m_interfaces.push_back (interface);
|
|
m_nInterfaces++;
|
|
return index;
|
|
}
|
|
Ptr<Ipv4Interface>
|
|
Ipv4::GetInterface (uint32_t index) const
|
|
{
|
|
uint32_t tmp = 0;
|
|
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
|
|
{
|
|
if (index == tmp)
|
|
{
|
|
return *i;
|
|
}
|
|
tmp++;
|
|
}
|
|
return 0;
|
|
}
|
|
uint32_t
|
|
Ipv4::GetNInterfaces (void) const
|
|
{
|
|
return m_nInterfaces;
|
|
}
|
|
|
|
Ptr<Ipv4Interface>
|
|
Ipv4::FindInterfaceForDevice (NetDevice const*device)
|
|
{
|
|
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
|
|
{
|
|
if ((*i)->PeekDevice () == device)
|
|
{
|
|
return *i;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
Ipv4::Receive(Packet& packet, NetDevice *device)
|
|
{
|
|
uint32_t index = 0;
|
|
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
|
|
{
|
|
if ((*i)->PeekDevice () == device)
|
|
{
|
|
m_rxTrace (packet, index);
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
Ipv4Header ipHeader;
|
|
packet.RemoveHeader (ipHeader);
|
|
|
|
if (!ipHeader.IsChecksumOk ())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Forwarding (packet, ipHeader, device))
|
|
{
|
|
return;
|
|
}
|
|
|
|
ForwardUp (packet, ipHeader);
|
|
}
|
|
|
|
void
|
|
Ipv4::Send (Packet const &packet,
|
|
Ipv4Address source,
|
|
Ipv4Address destination,
|
|
uint8_t protocol)
|
|
{
|
|
Ipv4Header ipHeader;
|
|
|
|
ipHeader.SetSource (source);
|
|
ipHeader.SetDestination (destination);
|
|
ipHeader.SetProtocol (protocol);
|
|
ipHeader.SetPayloadSize (packet.GetSize ());
|
|
ipHeader.SetTtl (m_defaultTtl);
|
|
ipHeader.SetMayFragment ();
|
|
ipHeader.SetIdentification (m_identification);
|
|
|
|
m_identification ++;
|
|
|
|
// XXX Note here that in most ipv4 stacks in the world,
|
|
// the route calculation for an outgoing packet is not
|
|
// done in the ip layer. It is done within the application
|
|
// socket when the first packet is sent to avoid this
|
|
// costly lookup on a per-packet basis.
|
|
// That would require us to get the route from the packet,
|
|
// most likely with a packet tag. The higher layers do not
|
|
// do this yet for us.
|
|
Ipv4Route *route = Lookup (ipHeader.GetDestination ());
|
|
if (route == 0)
|
|
{
|
|
NS_DEBUG ("not for me -- forwarding but no route to host. drop.");
|
|
m_dropTrace (packet);
|
|
return;
|
|
}
|
|
|
|
SendRealOut (packet, ipHeader, *route);
|
|
}
|
|
|
|
void
|
|
Ipv4::SendRealOut (Packet const &p, Ipv4Header const &ip, Ipv4Route const &route)
|
|
{
|
|
Packet packet = p;
|
|
packet.AddHeader (ip);
|
|
Ptr<Ipv4Interface> outInterface = GetInterface (route.GetInterface ());
|
|
NS_ASSERT (packet.GetSize () <= outInterface->GetMtu ());
|
|
m_txTrace (packet, route.GetInterface ());
|
|
if (route.IsGateway ())
|
|
{
|
|
outInterface->Send (packet, route.GetGateway ());
|
|
}
|
|
else
|
|
{
|
|
outInterface->Send (packet, ip.GetDestination ());
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
Ipv4::Forwarding (Packet const &packet, Ipv4Header &ipHeader, NetDevice *device)
|
|
{
|
|
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
|
|
i != m_interfaces.end (); i++)
|
|
{
|
|
if ((*i)->GetAddress ().IsEqual (ipHeader.GetDestination ()))
|
|
{
|
|
NS_DEBUG ("for me 1");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
|
|
i != m_interfaces.end (); i++)
|
|
{
|
|
Ptr<Ipv4Interface> interface = *i;
|
|
if (interface->PeekDevice () == device)
|
|
{
|
|
if (ipHeader.GetDestination ().IsEqual (interface->GetBroadcast ()))
|
|
{
|
|
NS_DEBUG ("for me 2");
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetBroadcast ()))
|
|
{
|
|
NS_DEBUG ("for me 3");
|
|
return false;
|
|
}
|
|
if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetAny ()))
|
|
{
|
|
NS_DEBUG ("for me 4");
|
|
return false;
|
|
}
|
|
if (ipHeader.GetTtl () == 1)
|
|
{
|
|
// Should send ttl expired here
|
|
// XXX
|
|
NS_DEBUG ("not for me -- ttl expired. drop.");
|
|
m_dropTrace (packet);
|
|
return true;
|
|
}
|
|
ipHeader.SetTtl (ipHeader.GetTtl () - 1);
|
|
Ipv4Route *route = Lookup (ipHeader.GetDestination ());
|
|
if (route == 0)
|
|
{
|
|
NS_DEBUG ("not for me -- forwarding but no route to host. drop.");
|
|
m_dropTrace (packet);
|
|
return true;
|
|
}
|
|
NS_DEBUG ("not for me -- forwarding.");
|
|
SendRealOut (packet, ipHeader, *route);
|
|
return true;
|
|
}
|
|
|
|
|
|
void
|
|
Ipv4::ForwardUp (Packet p, Ipv4Header const&ip)
|
|
{
|
|
Ipv4L4Demux *demux = m_node->QueryInterface<Ipv4L4Demux> (Ipv4L4Demux::iid);
|
|
Ipv4L4Protocol *protocol = demux->PeekProtocol (ip.GetProtocol ());
|
|
demux->Unref ();
|
|
protocol->Receive (p, ip.GetSource (), ip.GetDestination ());
|
|
}
|
|
|
|
void
|
|
Ipv4::SetAddress (uint32_t i, Ipv4Address address)
|
|
{
|
|
Ptr<Ipv4Interface> interface = GetInterface (i);
|
|
interface->SetAddress (address);
|
|
}
|
|
void
|
|
Ipv4::SetNetworkMask (uint32_t i, Ipv4Mask mask)
|
|
{
|
|
Ptr<Ipv4Interface> interface = GetInterface (i);
|
|
interface->SetNetworkMask (mask);
|
|
}
|
|
Ipv4Mask
|
|
Ipv4::GetNetworkMask (uint32_t i) const
|
|
{
|
|
Ptr<Ipv4Interface> interface = GetInterface (i);
|
|
return interface->GetNetworkMask ();
|
|
}
|
|
Ipv4Address
|
|
Ipv4::GetAddress (uint32_t i) const
|
|
{
|
|
Ptr<Ipv4Interface> interface = GetInterface (i);
|
|
return interface->GetAddress ();
|
|
}
|
|
uint16_t
|
|
Ipv4::GetMtu (uint32_t i) const
|
|
{
|
|
Ptr<Ipv4Interface> interface = GetInterface (i);
|
|
return interface->GetMtu ();
|
|
}
|
|
bool
|
|
Ipv4::IsUp (uint32_t i) const
|
|
{
|
|
Ptr<Ipv4Interface> interface = GetInterface (i);
|
|
return interface->IsUp ();
|
|
}
|
|
void
|
|
Ipv4::SetUp (uint32_t i)
|
|
{
|
|
Ptr<Ipv4Interface> interface = GetInterface (i);
|
|
interface->SetUp ();
|
|
}
|
|
void
|
|
Ipv4::SetDown (uint32_t i)
|
|
{
|
|
Ptr<Ipv4Interface> interface = GetInterface (i);
|
|
interface->SetDown ();
|
|
}
|
|
|
|
|
|
}//namespace ns3
|