src/internet-stack/ipv4-l3-protocol.cc
changeset 4472 e20a31541404
parent 4379 44c7757fb216
child 4481 9250a25ee683
child 5028 01f02baebba9
--- a/src/internet-stack/ipv4-l3-protocol.cc	Thu May 28 20:16:56 2009 +0200
+++ b/src/internet-stack/ipv4-l3-protocol.cc	Thu May 28 21:37:25 2009 -0700
@@ -31,14 +31,16 @@
 #include "ns3/object-vector.h"
 #include "ns3/ipv4-header.h"
 #include "ns3/boolean.h"
+#include "ns3/ipv4-routing-table-entry.h"
+#include "ns3/ipv4-static-routing.h"
+
+#include "loopback-net-device.h"
 #include "arp-l3-protocol.h"
-
 #include "ipv4-l3-protocol.h"
 #include "ipv4-l4-protocol.h"
+#include "ipv4-list-routing-impl.h"
 #include "icmpv4-l4-protocol.h"
 #include "ipv4-interface.h"
-#include "ipv4-loopback-interface.h"
-#include "arp-ipv4-interface.h"
 #include "ipv4-raw-socket-impl.h"
 
 NS_LOG_COMPONENT_DEFINE ("Ipv4L3Protocol");
@@ -83,8 +85,6 @@
     m_identification (0)
 {
   NS_LOG_FUNCTION_NOARGS ();
-  m_staticRouting = CreateObject<Ipv4StaticRouting> ();
-  AddRoutingProtocol (m_staticRouting, 0);
 }
 
 Ipv4L3Protocol::~Ipv4L3Protocol ()
@@ -119,6 +119,7 @@
 Ipv4L3Protocol::SetNode (Ptr<Node> node)
 {
   m_node = node;
+  // Add a LoopbackNetDevice if needed, and an Ipv4Interface on top of it
   SetupLoopback ();
 }
 
@@ -145,18 +146,48 @@
     }
   return;
 }
+/*
+ * This method is called by AddAgregate and completes the aggregation
+ * by setting the node in the ipv4 stack
+ */
+void
+Ipv4L3Protocol::NotifyNewAggregate ()
+{
+  Ptr<Node>node = this->GetObject<Node>();
+  // verify that it's a valid node and that
+  // the node has not been set before
+  if (node!= 0 && m_node == 0)
+    {
+      this->SetNode (node);
+    }
+  Object::NotifyNewAggregate ();
+}
+
+void 
+Ipv4L3Protocol::SetRoutingProtocol (Ptr<Ipv4RoutingProtocol> routing)
+{
+  NS_LOG_FUNCTION (this);
+  m_routingProtocol = routing;
+  // XXX should check all interfaces to see if any were set to Up state
+  // prior to a routing protocol being added
+  if (GetStaticRouting () != 0)
+    {
+      GetStaticRouting ()->AddHostRouteTo (Ipv4Address::GetLoopback (), 0);
+    }
+}
+
+
+Ptr<Ipv4RoutingProtocol> 
+Ipv4L3Protocol::GetRoutingProtocol (void) const
+{
+  return m_routingProtocol;
+}
 
 void 
 Ipv4L3Protocol::DoDispose (void)
 {
   NS_LOG_FUNCTION (this);
- 
-  for (SocketList::iterator i = m_sockets.begin (); i != m_sockets.end (); ++i)
-    {
-      *i = 0;
-    }
-
- for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
+  for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
     {
       *i = 0;
     }
@@ -167,10 +198,12 @@
       *i = 0;
     }
   m_interfaces.clear ();
-  m_routingProtocols.clear ();
   m_node = 0;
-  m_staticRouting->Dispose ();
-  m_staticRouting = 0;
+  if (m_routingProtocol)
+    {
+      m_routingProtocol->Dispose ();
+      m_routingProtocol = 0;
+    }
   Object::DoDispose ();
 }
 
@@ -179,12 +212,33 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 
-  Ptr<Ipv4LoopbackInterface> interface = CreateObject<Ipv4LoopbackInterface> ();
+  Ptr<Ipv4Interface> interface = CreateObject<Ipv4Interface> ();
+  Ptr<LoopbackNetDevice> device = 0;
+  // First check whether an existing LoopbackNetDevice exists on the node
+  for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
+    {
+      if (device = DynamicCast<LoopbackNetDevice> (m_node->GetDevice (i)))
+        {
+          break;
+        }
+    }
+  if (device == 0)
+    {
+      device = CreateObject<LoopbackNetDevice> (); 
+      m_node->AddDevice (device);
+    }
+  interface->SetDevice (device);
   interface->SetNode (m_node);
   Ipv4InterfaceAddress ifaceAddr = Ipv4InterfaceAddress (Ipv4Address::GetLoopback (), Ipv4Mask::GetLoopback ());
   interface->AddAddress (ifaceAddr);
   uint32_t index = AddIpv4Interface (interface);
-  AddHostRouteTo (Ipv4Address::GetLoopback (), index);
+  Ptr<Node> node = GetObject<Node> ();
+  node->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this), 
+                                 Ipv4L3Protocol::PROT_NUMBER, device);
+  if (GetStaticRouting () != 0)
+    {
+      GetStaticRouting ()->AddHostRouteTo (Ipv4Address::GetLoopback (), index);
+    }
   interface->SetUp ();
 }
 
@@ -195,192 +249,24 @@
   m_defaultTtl = ttl;
 }
     
-
-void 
-Ipv4L3Protocol::AddHostRouteTo (Ipv4Address dest, 
-                      Ipv4Address nextHop, 
-                      uint32_t interface)
-{
-  NS_LOG_FUNCTION (this << dest << nextHop << interface);
-  m_staticRouting->AddHostRouteTo (dest, nextHop, interface);
-}
-
-void 
-Ipv4L3Protocol::AddHostRouteTo (Ipv4Address dest, 
-				uint32_t interface)
-{
-  NS_LOG_FUNCTION (this << dest << interface);
-  m_staticRouting->AddHostRouteTo (dest, interface);
-}
-
-void 
-Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network, 
-				   Ipv4Mask networkMask, 
-				   Ipv4Address nextHop, 
-				   uint32_t interface)
-{
-  NS_LOG_FUNCTION (this << network << networkMask << nextHop << interface);
-  m_staticRouting->AddNetworkRouteTo (network, networkMask, nextHop, interface);
-}
-
-void 
-Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network, 
-				   Ipv4Mask networkMask, 
-				   uint32_t interface)
-{
-  NS_LOG_FUNCTION (this << network << networkMask << interface);
-  m_staticRouting->AddNetworkRouteTo (network, networkMask, interface);
-}
-
-void 
-Ipv4L3Protocol::SetDefaultRoute (Ipv4Address nextHop, 
-				 uint32_t interface)
-{
-  NS_LOG_FUNCTION (this << nextHop << interface);
-  m_staticRouting->SetDefaultRoute (nextHop, interface);
-}
-
-void
-Ipv4L3Protocol::Lookup (
-  Ipv4Header const &ipHeader,
-  Ptr<Packet> packet,
-  Ipv4RoutingProtocol::RouteReplyCallback routeReply)
-{
-  NS_LOG_FUNCTION (this << &ipHeader << packet << &routeReply);
-
-  Lookup (Ipv4RoutingProtocol::INTERFACE_ANY, ipHeader, packet, routeReply);
-}
-
-void
-Ipv4L3Protocol::Lookup (
-  uint32_t interface,
-  Ipv4Header const &ipHeader,
-  Ptr<Packet> packet,
-  Ipv4RoutingProtocol::RouteReplyCallback routeReply)
-{
-  NS_LOG_FUNCTION (this << interface << &ipHeader << packet << &routeReply);
-
-  for (Ipv4RoutingProtocolList::const_iterator rprotoIter = 
-         m_routingProtocols.begin ();
-       rprotoIter != m_routingProtocols.end (); 
-       rprotoIter++)
-    {
-      NS_LOG_LOGIC ("Requesting route");
-      if ((*rprotoIter).second->RequestRoute (interface, ipHeader, packet, 
-                                              routeReply))
-        return;
-    }
-
-  if (ipHeader.GetDestination ().IsMulticast () && 
-      interface == Ipv4RoutingProtocol::INTERFACE_ANY)
-    {
-      NS_LOG_LOGIC ("Multicast destination with local source");
-//
-// We have a multicast packet originating from the current node and were not
-// able to send it using the usual RequestRoute process.  Since the usual
-// process includes trying to use a default multicast route, this means that
-// there was no specific route out of the node found, and there was no default
-// multicast route set.
-//
-// The fallback position is to look for a default unicast route and use that
-// to get the packet off the node if we have one.
-//
-      Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
-
-      if (route)
-        {
-          NS_LOG_LOGIC ("Local source. Using unicast default route for "
-            "multicast packet");
-
-          routeReply (true, *route, packet, ipHeader);
-          return;
-        }
-    }
-//
-// No route found
-//
-  routeReply (false, Ipv4Route (), packet, ipHeader);
-}
-
-void
-Ipv4L3Protocol::AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
-                                    int16_t priority)
-{
-  NS_LOG_FUNCTION (this << &routingProtocol << priority);
-  m_routingProtocols.push_back
-    (std::pair<int, Ptr<Ipv4RoutingProtocol> > (-priority, routingProtocol));
-  m_routingProtocols.sort ();
-}
-
-uint32_t 
-Ipv4L3Protocol::GetNRoutes (void)
+// XXX need to remove dependencies on Ipv4StaticRouting from this class
+Ptr<Ipv4StaticRouting>
+Ipv4L3Protocol::GetStaticRouting (void) const
 {
   NS_LOG_FUNCTION_NOARGS ();
-  return m_staticRouting->GetNRoutes ();
-}
-
-Ipv4Route 
-Ipv4L3Protocol::GetRoute (uint32_t index)
-{
-  NS_LOG_FUNCTION_NOARGS ();
-  return *m_staticRouting->GetRoute (index);
-}
-
-void 
-Ipv4L3Protocol::RemoveRoute (uint32_t index)
-{
-  NS_LOG_FUNCTION (this << index);
-  m_staticRouting->RemoveRoute (index);
-}
-
-void 
-Ipv4L3Protocol::AddMulticastRoute (Ipv4Address origin,
-                                   Ipv4Address group,
-                                   uint32_t inputInterface,
-                                   std::vector<uint32_t> outputInterfaces)
-{
-  NS_LOG_FUNCTION (this << origin << group << inputInterface << &outputInterfaces);
-
-  m_staticRouting->AddMulticastRoute (origin, group, inputInterface,
-    outputInterfaces);
-}
-
-void 
-Ipv4L3Protocol::SetDefaultMulticastRoute (uint32_t outputInterface)
-{
-  NS_LOG_FUNCTION (this << outputInterface);
-
-  m_staticRouting->SetDefaultMulticastRoute (outputInterface);
-}
-
-uint32_t 
-Ipv4L3Protocol::GetNMulticastRoutes (void) const
-{
-  NS_LOG_FUNCTION_NOARGS ();
-  return m_staticRouting->GetNMulticastRoutes ();
-}
-
-Ipv4MulticastRoute 
-Ipv4L3Protocol::GetMulticastRoute (uint32_t index) const
-{
-  NS_LOG_FUNCTION (this << index);
-  return *m_staticRouting->GetMulticastRoute (index);
-}
-
-void 
-Ipv4L3Protocol::RemoveMulticastRoute (Ipv4Address origin,
-                                       Ipv4Address group,
-                                       uint32_t inputInterface)
-{
-  NS_LOG_FUNCTION (this << origin << group << inputInterface);
-  m_staticRouting->RemoveMulticastRoute (origin, group, inputInterface);
-}
-
-void 
-Ipv4L3Protocol::RemoveMulticastRoute (uint32_t index)
-{
-  NS_LOG_FUNCTION (this << index);
-  m_staticRouting->RemoveMulticastRoute (index);
+  Ptr<Ipv4StaticRouting> staticRouting;
+  if (m_routingProtocol != 0)
+    {
+      Ptr<Ipv4StaticRoutingImpl> sr = DynamicCast<Ipv4StaticRoutingImpl> (m_routingProtocol);
+      if (sr != 0)
+        {
+          return sr;
+        }
+      Ptr<Ipv4ListRoutingImpl> lr = DynamicCast<Ipv4ListRoutingImpl> (m_routingProtocol);
+      NS_ASSERT (lr);
+      staticRouting = lr->GetStaticRouting ();
+    }
+  return staticRouting;
 }
 
 uint32_t 
@@ -394,7 +280,7 @@
   node->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject<ArpL3Protocol> ())),
                                  ArpL3Protocol::PROT_NUMBER, device);
 
-  Ptr<ArpIpv4Interface> interface = CreateObject<ArpIpv4Interface> ();
+  Ptr<Ipv4Interface> interface = CreateObject<Ipv4Interface> ();
   interface->SetNode (m_node);
   interface->SetDevice (device);
   return AddIpv4Interface (interface);
@@ -433,60 +319,60 @@
   return m_nInterfaces;
 }
 
-uint32_t 
-Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr) const
+int32_t 
+Ipv4L3Protocol::GetInterfaceForAddress (
+  Ipv4Address address) const
 {
-  NS_LOG_FUNCTION (this << addr);
+  NS_LOG_FUNCTION (this << address);
 
-  uint32_t interface = 0;
+  int32_t interface = 0;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
        i != m_interfaces.end (); 
        i++, interface++)
     {
-      for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++) 
+      for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++)
         {
-          if ((*i)->GetAddress (j).GetLocal () == addr)
+          if ((*i)->GetAddress (j).GetLocal () == address)
             {
               return interface;
             }
         }
     }
 
-  NS_FATAL_ERROR ("Ipv4L3Protocol::FindInterfaceForAddr (): "
-                  "Interface not found for IP address " << addr);
-  return 0;
+  return -1;
 }
 
-uint32_t 
-Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const
+int32_t 
+Ipv4L3Protocol::GetInterfaceForPrefix (
+  Ipv4Address address, 
+  Ipv4Mask mask) const
 {
-  NS_LOG_FUNCTION (this << addr << mask);
+  NS_LOG_FUNCTION (this << address << mask);
 
-  uint32_t interface = 0;
+  int32_t interface = 0;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
        i != m_interfaces.end (); 
        i++, interface++)
     {
       for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++)
         {
-          if ((*i)->GetAddress (j).GetLocal ().CombineMask (mask) == addr.CombineMask (mask))
+          if ((*i)->GetAddress (j).GetLocal ().CombineMask (mask) == address.CombineMask (mask))
             {
               return interface;
             }
         }
     }
 
-  NS_ASSERT_MSG(false, "Ipv4L3Protocol::FindInterfaceForAddr (): "
-    "Interface not found for masked IP address");
-  return 0;
+  return -1;
 }
 
 int32_t 
-Ipv4L3Protocol::FindInterfaceForDevice (Ptr<NetDevice> device) const
+Ipv4L3Protocol::GetInterfaceForDevice (
+  Ptr<const NetDevice> device) const
 {
-  NS_LOG_FUNCTION (this << device);
+  NS_LOG_FUNCTION (this << device->GetIfIndex());
 
-  uint32_t interface = 0;
+  int32_t interface = 0;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
        i != m_interfaces.end (); 
        i++, interface++)
@@ -500,31 +386,18 @@
   return -1;
 }
 
-Ptr<Ipv4Interface>
-Ipv4L3Protocol::FindInterfaceForDevice (Ptr<const NetDevice> device)
-{
-  NS_LOG_FUNCTION (this << &device);
-  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
-    {
-      if ((*i)->GetDevice () == device)
-        {
-          return *i;
-        }
-    }
-  return 0;
-}  
-
 void 
 Ipv4L3Protocol::Receive( Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from,
                          const Address &to, NetDevice::PacketType packetType)
 {
   NS_LOG_FUNCTION (this << &device << p << protocol <<  from);
 
-  NS_LOG_LOGIC ("Packet from " << from << " received on node " << m_node->GetId ());
+  NS_LOG_LOGIC ("Packet from " << from << " received on node " << 
+    m_node->GetId ());
 
+  uint32_t interface = 0;
   Ptr<Packet> packet = p->Copy ();
 
-  uint32_t index = 0;
   Ptr<Ipv4Interface> ipv4Interface;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
        i != m_interfaces.end (); 
@@ -535,9 +408,9 @@
         {
           if (ipv4Interface->IsUp ())
             {
-              m_rxTrace (packet, index);
+              m_rxTrace (packet, interface);
               break;
-            } 
+            }
           else
             {
               NS_LOG_LOGIC ("Dropping received packet-- interface is down");
@@ -545,8 +418,9 @@
               return;
             }
         }
-      index++;
+      interface++;
     }
+
   Ipv4Header ipHeader;
   if (m_calcChecksum)
     {
@@ -566,12 +440,13 @@
       socket->ForwardUp (packet, ipHeader, device);
     }
 
-  if (Forwarding (index, packet, ipHeader, device)) 
-    {
-      return;
-    }
+  m_routingProtocol->RouteInput (packet, ipHeader, device, 
+    MakeCallback (&Ipv4L3Protocol::IpForward, this),
+    MakeCallback (&Ipv4L3Protocol::IpMulticastForward, this),
+    MakeCallback (&Ipv4L3Protocol::LocalDeliver, this),
+    MakeNullCallback <void, Ptr<const Packet>, const Ipv4Header &> ()
+  );
 
-  ForwardUp (packet, ipHeader, ipv4Interface);
 }
 
 Ptr<Icmpv4L4Protocol> 
@@ -598,75 +473,35 @@
 Ipv4L3Protocol::Send (Ptr<Packet> packet, 
             Ipv4Address source, 
             Ipv4Address destination,
-            uint8_t protocol)
+            uint8_t protocol,
+            Ptr<Ipv4Route> route)
 {
-  NS_LOG_FUNCTION (this << packet << source << destination << protocol);
+  NS_LOG_FUNCTION (this << packet << source << destination << uint32_t(protocol) << route);
 
   Ipv4Header ipHeader;
-
-  if (m_calcChecksum)
-    {
-      ipHeader.EnableChecksum ();
-    }
-
-  ipHeader.SetSource (source);
-  ipHeader.SetDestination (destination);
-  ipHeader.SetProtocol (protocol);
-  ipHeader.SetPayloadSize (packet->GetSize ());
-  ipHeader.SetIdentification (m_identification);
-
-  m_identification ++;
-
-  SocketSetDontFragmentTag dfTag;
-  bool found = packet->FindFirstMatchingTag (dfTag);
+  bool mayFragment = true;
+  uint8_t ttl = m_defaultTtl;
+  SocketIpTtlTag tag;
+  bool found = packet->FindFirstMatchingTag (tag);
   if (found)
     {
-      if (dfTag.IsEnabled ())
-        {
-          ipHeader.SetDontFragment ();
-        }
-      else
-        {
-          ipHeader.SetMayFragment ();
-        }
+      ttl = tag.GetTtl ();
+      // XXX remove tag here?  
     }
+
+  // Handle a few cases:
+  // 1) packet is destined to limited broadcast address
+  // 2) packet is destined to a subnet-directed broadcast address
+  // 3) packet is not broadcast, and is passed in with a route entry
+  // 4) packet is not broadcast, and is passed in with a route entry but route->GetGateway is not set (e.g., on-demand)
+  // 5) packet is not broadcast, and route is NULL (e.g., a raw socket call, or ICMP)
   
-
-  // Set TTL to 1 if it is a broadcast packet of any type.  Otherwise,
-  // possibly override the default TTL if the packet is tagged
-  SocketIpTtlTag tag;
-  found = packet->FindFirstMatchingTag (tag);
-
+  // 1) packet is destined to limited broadcast address
   if (destination.IsBroadcast ()) 
     {
-      ipHeader.SetTtl (1);
-    }
-  else if (found)
-    {
-      ipHeader.SetTtl (tag.GetTtl ());
-      // XXX remove tag here?  
-    }
-  else
-    {
-      ipHeader.SetTtl (m_defaultTtl);
-      uint32_t ifaceIndex = 0;
-      for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
-           ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
-        {
-          Ptr<Ipv4Interface> outInterface = *ifaceIter;
-          // XXX this logic might not be completely correct for multi-addressed interface
-          for (uint32_t j = 0; j < outInterface->GetNAddresses(); j++)
-            {
-              if (destination.IsSubnetDirectedBroadcast (
-                outInterface->GetAddress (j).GetMask ()))
-                {
-                  ipHeader.SetTtl (1);
-                }
-            }
-        }
-    }
-  if (destination.IsBroadcast ())
-    {
+      NS_LOG_LOGIC ("Ipv4L3Protocol::Send case 1:  limited broadcast");
+      ttl = 1;
+      ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, mayFragment);
       uint32_t ifaceIndex = 0;
       for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
            ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
@@ -674,209 +509,216 @@
           Ptr<Ipv4Interface> outInterface = *ifaceIter;
           Ptr<Packet> packetCopy = packet->Copy ();
 
+          NS_ASSERT (packetCopy->GetSize () <= outInterface->GetMtu ());
           packetCopy->AddHeader (ipHeader);
-          // XXX Handle multiple address on interface
-          if (packetCopy->GetSize () > outInterface->GetMtu () &&
-              ipHeader.IsDontFragment () &&
-              IsUnicast (ipHeader.GetDestination (), outInterface->GetAddress (0).GetMask ()))
-            {
-              Ptr<Icmpv4L4Protocol> icmp = GetIcmp ();
-              NS_ASSERT (icmp != 0);
-              icmp->SendDestUnreachFragNeeded (ipHeader, packet, outInterface->GetMtu ());
-              m_dropTrace (packetCopy);
-            }
-          else if (packet->GetSize () > outInterface->GetMtu () &&
-                   !ipHeader.IsDontFragment ())
+          m_txTrace (packetCopy, ifaceIndex);
+          outInterface->Send (packetCopy, destination);
+        }
+      return;
+    }
+
+  // 2) check: packet is destined to a subnet-directed broadcast address
+  uint32_t ifaceIndex = 0;
+  for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
+    ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
+    {
+      Ptr<Ipv4Interface> outInterface = *ifaceIter;
+      for (uint32_t j = 0; j < GetNAddresses (ifaceIndex); j++)
+        {
+          Ipv4InterfaceAddress ifAddr = GetAddress (ifaceIndex, j);
+          NS_LOG_LOGIC ("Testing address " << ifAddr.GetLocal () << " with mask " << ifAddr.GetMask ());
+          if (destination.IsSubnetDirectedBroadcast (ifAddr.GetMask ()) && 
+              destination.CombineMask (ifAddr.GetMask ()) == ifAddr.GetLocal ().CombineMask (ifAddr.GetMask ())   )  
             {
-              NS_LOG_LOGIC ("Too big: need fragmentation but no frag support.");
-              m_dropTrace (packet);
-            }
-          else
-            {
-              NS_ASSERT (packetCopy->GetSize () <= outInterface->GetMtu ());
-              if (outInterface->IsUp ())
-                {
-                  m_txTrace (packetCopy, ifaceIndex);
-                  outInterface->Send (packetCopy, destination);
-                }
-              else
-                {
-                  m_dropTrace (packetCopy);
-                }
+              NS_LOG_LOGIC ("Ipv4L3Protocol::Send case 2:  subnet directed bcast to " << ifAddr.GetLocal ());
+              ttl = 1;
+              ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, mayFragment);
+              Ptr<Packet> packetCopy = packet->Copy ();
+              packetCopy->AddHeader (ipHeader);
+              m_txTrace (packetCopy, ifaceIndex);
+              outInterface->Send (packetCopy, destination);
+              return;
             }
         }
     }
+
+  // 3) packet is not broadcast, and is passed in with a route entry
+  //    with a valid Ipv4Address as the gateway
+  if (route && route->GetGateway () != Ipv4Address ())
+    {
+      NS_LOG_LOGIC ("Ipv4L3Protocol::Send case 3:  passed in with route");
+      ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, mayFragment);
+      SendRealOut (route, packet, ipHeader);
+      return; 
+    } 
+  // 4) packet is not broadcast, and is passed in with a route entry but route->GetGateway is not set (e.g., on-demand)
+  if (route && route->GetGateway () != Ipv4Address ())
+    {
+      // This could arise because the synchronous RouteOutput() call
+      // returned to the transport protocol with a source address but
+      // there was no next hop available yet (since a route may need
+      // to be queried).  So, call asynchronous version of RouteOutput?
+      NS_FATAL_ERROR("XXX This case not yet implemented");
+    }
+  // 5) packet is not broadcast, and route is NULL (e.g., a raw socket call)
+  NS_LOG_LOGIC ("Ipv4L3Protocol::Send case 4:  passed in with no route " << destination);
+  Socket::SocketErrno errno; 
+  uint32_t oif = 0; // unused for now
+  ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, mayFragment);
+  Ptr<Ipv4Route> newRoute = m_routingProtocol->RouteOutput (ipHeader, oif, errno);
+  if (newRoute)
+    {
+      SendRealOut (newRoute, packet, ipHeader);
+    }
   else
     {
-      // 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.
-      Lookup (ipHeader, packet,
-              MakeCallback (&Ipv4L3Protocol::SendRealOut, this));
+      NS_LOG_WARN ("No route to host.  Drop.");
+      m_dropTrace (packet);
     }
 }
 
+// XXX when should we set ip_id?   check whether we are incrementing
+// m_identification on packets that may later be dropped in this stack
+// and whether that deviates from Linux
+Ipv4Header
+Ipv4L3Protocol::BuildHeader (
+            Ipv4Address source, 
+            Ipv4Address destination,
+            uint8_t protocol,
+            uint16_t payloadSize,
+            uint8_t ttl,
+            bool mayFragment)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  Ipv4Header ipHeader;
+  ipHeader.SetSource (source);
+  ipHeader.SetDestination (destination);
+  ipHeader.SetProtocol (protocol);
+  ipHeader.SetPayloadSize (payloadSize);
+  ipHeader.SetTtl (ttl);
+  if (mayFragment == true)
+    {
+      ipHeader.SetMayFragment ();
+      ipHeader.SetIdentification (m_identification);
+      m_identification ++;
+    }
+  else
+    {
+      ipHeader.SetDontFragment ();
+      // TBD:  set to zero here; will cause traces to change
+      ipHeader.SetIdentification (m_identification);
+      m_identification ++;
+    }
+  if (m_calcChecksum)
+    {
+      ipHeader.EnableChecksum ();
+    }
+  return ipHeader;
+}
+
 void
-Ipv4L3Protocol::SendRealOut (bool found,
-                             Ipv4Route const &route,
+Ipv4L3Protocol::SendRealOut (Ptr<Ipv4Route> route,
                              Ptr<Packet> packet,
                              Ipv4Header const &ipHeader)
 {
-  NS_LOG_FUNCTION (this << found << &route << packet << &ipHeader);
+  NS_LOG_FUNCTION (this << packet << &ipHeader);
 
+  // We add a header regardless of whether there is a route, since 
+  // we may want to drop trace
   packet->AddHeader (ipHeader);
-  if (!found)
+  if (route == 0)
     {
       NS_LOG_WARN ("No route to host.  Drop.");
       m_dropTrace (packet);
       return;
     }
 
-  NS_LOG_LOGIC ("Send via interface " << route.GetInterface ());
+  Ptr<NetDevice> outDev = route->GetOutputDevice ();
+  int32_t interface = GetInterfaceForDevice (outDev);
+  NS_ASSERT (interface >= 0);
+  Ptr<Ipv4Interface> outInterface = GetInterface (interface);
+  NS_LOG_LOGIC ("Send via NetDevice ifIndex " << outDev->GetIfIndex () << " ipv4InterfaceIndex " << interface);
 
-  Ptr<Ipv4Interface> outInterface = GetInterface (route.GetInterface ());
-  // XXX handle multiple address on interface
-  if (packet->GetSize () > outInterface->GetMtu () &&
-      ipHeader.IsDontFragment () &&
-      IsUnicast (ipHeader.GetDestination (), outInterface->GetAddress (0).GetMask ()))
-    {
-      NS_LOG_LOGIC ("Too big: need fragmentation but not allowed");
-      Ptr<Icmpv4L4Protocol> icmp = GetIcmp ();
-      NS_ASSERT (icmp != 0);
-      Ptr<Packet> copyNoHeader = packet->Copy ();
-      Ipv4Header tmp;
-      copyNoHeader->RemoveHeader (tmp);
-      icmp->SendDestUnreachFragNeeded (ipHeader, copyNoHeader, outInterface->GetMtu ());
-      m_dropTrace (packet);
-    }
-  else if (packet->GetSize () > outInterface->GetMtu () &&
-           !ipHeader.IsDontFragment ())
-    {
-      NS_LOG_LOGIC ("Too big: need fragmentation but no frag support.");
-      m_dropTrace (packet);
-    }
-  else
+  NS_ASSERT (packet->GetSize () <= outInterface->GetMtu ());
+  if (!route->GetGateway ().IsEqual (Ipv4Address ("0.0.0.0"))) 
     {
-      if (route.IsGateway ()) 
+      if (outInterface->IsUp ())
+        {
+          NS_LOG_LOGIC ("Send to gateway " << route->GetGateway ());
+          m_txTrace (packet, interface);
+          outInterface->Send (packet, route->GetGateway ());
+        }
+      else
         {
-          if (outInterface->IsUp ())
-            {
-              NS_LOG_LOGIC ("Send to gateway " << route.GetGateway ());
-              m_txTrace (packet, route.GetInterface ());
-              outInterface->Send (packet, route.GetGateway ());
-            }
-          else
-            {
-              NS_LOG_LOGIC ("Dropping-- outgoing interface is down: " << route.GetGateway ());
-              m_dropTrace (packet);
-            }
-        } 
-      else 
+          NS_LOG_LOGIC ("Dropping-- outgoing interface is down: " << route->GetGateway ());
+          m_dropTrace (packet);
+        }
+    } 
+  else 
+    {
+      if (outInterface->IsUp ())
         {
-          if (outInterface->IsUp ())
-            {
-              NS_LOG_LOGIC ("Send to destination " << ipHeader.GetDestination ());
-              m_txTrace (packet, route.GetInterface ());
-              outInterface->Send (packet, ipHeader.GetDestination ());
-            }
-          else
-            {
-              NS_LOG_LOGIC ("Dropping-- outgoing interface is down: " << route.GetGateway ());
-              m_dropTrace (packet);
-            }
+          NS_LOG_LOGIC ("Send to destination " << ipHeader.GetDestination ());
+          m_txTrace (packet, interface);
+          outInterface->Send (packet, ipHeader.GetDestination ());
+        }
+      else
+        {
+          NS_LOG_LOGIC ("Dropping-- outgoing interface is down: " << ipHeader.GetDestination ());
+          m_dropTrace (packet);
         }
     }
 }
 
-bool
-Ipv4L3Protocol::Forwarding (
-  uint32_t interface, 
-  Ptr<Packet> packet, 
-  Ipv4Header &ipHeader, 
-  Ptr<NetDevice> device)
+// This function analogous to Linux ip_mr_forward()
+void
+Ipv4L3Protocol::IpMulticastForward (Ptr<Ipv4MulticastRoute> mrtentry, Ptr<const Packet> p, const Ipv4Header &header)
 {
-  NS_LOG_FUNCTION (interface << packet << &ipHeader<< device);
-  NS_LOG_LOGIC ("Forwarding logic for node: " << m_node->GetId ());
-
-  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
-       i != m_interfaces.end (); i++) 
+  NS_LOG_FUNCTION (mrtentry << p << header);
+  NS_LOG_LOGIC ("Multicast forwarding logic for node: " << m_node->GetId ());
+  // The output interfaces we could forward this onto are encoded
+  // in the OutputTtl of the Ipv4MulticastRoute
+  for (uint32_t i = 0; i < Ipv4MulticastRoute::MAX_INTERFACES; i++)
     {
-      for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++)
+      if (mrtentry->GetOutputTtl (i) < Ipv4MulticastRoute::MAX_TTL)
         {
-          if ((*i)->GetAddress (j).GetLocal ().IsEqual (ipHeader.GetDestination ())) 
+          Ptr<Packet> packet = p->Copy ();
+          Ipv4Header h = header;
+          h.SetTtl (header.GetTtl () - 1);
+          if (h.GetTtl () == 0)
             {
-              NS_LOG_LOGIC ("For me (destination match)");
-              return false;
+              NS_LOG_WARN ("TTL exceeded.  Drop.");
+              m_dropTrace (packet);
+              return;
             }
+          NS_LOG_LOGIC ("Forward multicast via interface " << i);
+          Ptr<Ipv4Route> rtentry = Create<Ipv4Route> ();
+          rtentry->SetSource (h.GetSource ());
+          rtentry->SetDestination (h.GetDestination ());
+          rtentry->SetGateway (Ipv4Address::GetAny ());
+          rtentry->SetOutputDevice (GetNetDevice (i));
+          SendRealOut (rtentry, packet, h);
+          return; 
         }
     }
-  
-  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
-       i != m_interfaces.end (); i++) 
-    {
-      Ptr<Ipv4Interface> interface = *i;
-      if (interface->GetDevice () == device)
-	{
-          // XXX multi-address case
-	  if (ipHeader.GetDestination ().IsEqual (interface->GetAddress (0).GetBroadcast ())) 
-	    {
-              NS_LOG_LOGIC ("For me (interface broadcast address)");
-	      return false;
-	    }
-	  break;
-	}
-    }
-      
-  if (ipHeader.GetDestination ().IsBroadcast ()) 
-    {
-      NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)");
-      return false;
-    }
-
-  if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetAny ())) 
-    {
-      NS_LOG_LOGIC ("For me (Ipv4Addr any address)");
-      return false;
-    }
-//  
-// If this is a to a multicast address and this node is a member of the 
-// indicated group we need to return false so the multicast is forwarded up.
-//        
-  for (Ipv4MulticastGroupList::const_iterator i = m_multicastGroups.begin ();
-       i != m_multicastGroups.end (); i++)
-    {
-      if ((*i).first.IsEqual (ipHeader.GetSource ()) &&
-          (*i).second.IsEqual (ipHeader.GetDestination ()))
-        {
-          NS_LOG_LOGIC ("For me (Joined multicast group)");
-          // We forward with a packet copy, since forwarding may change
-          // the packet, affecting our local delivery
-          NS_LOG_LOGIC ("Forwarding (multicast).");
-          DoForward (interface, packet->Copy (), ipHeader);
-          return false;
-        }   
-    }
-
-  DoForward (interface, packet, ipHeader);
-  return true;
 }
 
+// This function analogous to Linux ip_forward()
 void
-Ipv4L3Protocol::DoForward (uint32_t interface, 
-                           Ptr<Packet> packet, 
-                           Ipv4Header ipHeader)
+Ipv4L3Protocol::IpForward (Ptr<Ipv4Route> rtentry, Ptr<const Packet> p, const Ipv4Header &header)
 {
-  NS_LOG_FUNCTION (this << interface << packet << ipHeader);
-
+  NS_LOG_FUNCTION (rtentry << p << header);
+  NS_LOG_LOGIC ("Forwarding logic for node: " << m_node->GetId ());
+  // Forwarding
+  Ipv4Header ipHeader = header;
+  Ptr<Packet> packet = p->Copy ();
   ipHeader.SetTtl (ipHeader.GetTtl () - 1);
   // XXX handle multi-interfaces
   if (ipHeader.GetTtl () == 0)
     {
+      Ptr<NetDevice> outDev = rtentry->GetOutputDevice ();
+      int32_t interface = GetInterfaceForDevice (outDev);
+      NS_ASSERT (interface >= 0);
       if (IsUnicast (ipHeader.GetDestination (), GetInterface (interface)->GetAddress (0).GetMask ()))
         {
           Ptr<Icmpv4L4Protocol> icmp = GetIcmp ();
@@ -885,18 +727,15 @@
       NS_LOG_WARN ("TTL exceeded.  Drop.");
       m_dropTrace (packet);
       return;
-    }  
-  NS_LOG_LOGIC ("Not for me, forwarding.");
-  Lookup (interface, ipHeader, packet,
-          MakeCallback (&Ipv4L3Protocol::SendRealOut, this));
+    }
+  SendRealOut (rtentry, packet, ipHeader);
 }
 
-
 void
-Ipv4L3Protocol::ForwardUp (Ptr<Packet> p, Ipv4Header const&ip,
-                           Ptr<Ipv4Interface> incomingInterface)
+Ipv4L3Protocol::LocalDeliver (Ptr<const Packet> packet, Ipv4Header const&ip, uint32_t iif)
 {
-  NS_LOG_FUNCTION (this << p << &ip);
+  NS_LOG_FUNCTION (this << packet << &ip);
+  Ptr<Packet> p = packet->Copy (); // need to pass a non-const packet up
 
   Ptr<Ipv4L4Protocol> protocol = GetProtocol (ip.GetProtocol ());
   if (protocol != 0)
@@ -905,15 +744,15 @@
       // RX_ENDPOINT_UNREACH codepath
       Ptr<Packet> copy = p->Copy ();
       enum Ipv4L4Protocol::RxStatus status = 
-        protocol->Receive (p, ip.GetSource (), ip.GetDestination (), incomingInterface);
+        protocol->Receive (p, ip.GetSource (), ip.GetDestination (), GetInterface (iif));
       switch (status) {
       case Ipv4L4Protocol::RX_OK:
         // fall through
       case Ipv4L4Protocol::RX_CSUM_FAILED:
         break;
       case Ipv4L4Protocol::RX_ENDPOINT_UNREACH:
-        // XXX handle multi-interface case
-        if (IsUnicast (ip.GetDestination (), incomingInterface->GetAddress (0).GetMask ()))
+        // XXX handle multi-interfaces
+        if (IsUnicast (ip.GetDestination (), GetInterface (iif)->GetAddress (0).GetMask ()))
           {
             GetIcmp ()->SendDestUnreachPort (ip, copy);
           }
@@ -922,32 +761,7 @@
     }
 }
 
-void 
-Ipv4L3Protocol::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group)
-{
-  NS_LOG_FUNCTION (this << origin << group);
-  m_multicastGroups.push_back(
-    std::pair<Ipv4Address, Ipv4Address> (origin, group));
-}
-
-void
-Ipv4L3Protocol::LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group)
-{
-  NS_LOG_FUNCTION (this << origin << group);
-
-  for (Ipv4MulticastGroupList::iterator i = m_multicastGroups.begin ();
-       i != m_multicastGroups.end (); 
-       i++)
-    {
-      if ((*i).first.IsEqual(origin) && (*i).second.IsEqual(group))
-        {
-          m_multicastGroups.erase (i);
-          return;
-        }
-    }
-}
-
-uint32_t
+uint32_t 
 Ipv4L3Protocol::AddAddress (uint32_t i, Ipv4InterfaceAddress address)
 {
   NS_LOG_FUNCTION (this << i << address);
@@ -955,7 +769,7 @@
   return interface->AddAddress (address);
 }
 
-Ipv4InterfaceAddress
+Ipv4InterfaceAddress 
 Ipv4L3Protocol::GetAddress (uint32_t interfaceIndex, uint32_t addressIndex) const
 {
   NS_LOG_FUNCTION (this << interfaceIndex << addressIndex);
@@ -963,7 +777,7 @@
   return interface->GetAddress (addressIndex);
 }
 
-uint32_t
+uint32_t 
 Ipv4L3Protocol::GetNAddresses (uint32_t interface) const
 {
   NS_LOG_FUNCTION (this << interface);
@@ -987,76 +801,6 @@
   return interface->GetMetric ();
 }
 
-bool
-Ipv4L3Protocol::GetInterfaceForDestination (
-  Ipv4Address destination, uint32_t& interface) const
-{
-  NS_LOG_FUNCTION (this << destination << &interface);
-//
-// The first thing we do in trying to determine a source address is to 
-// consult the routing protocols.  These will also check for a default route
-// if one has been set.
-//
-  for (Ipv4RoutingProtocolList::const_iterator i = m_routingProtocols.begin ();
-       i != m_routingProtocols.end (); 
-       i++)
-    {
-      NS_LOG_LOGIC ("Requesting Source Address");
-      uint32_t interfaceTmp;
-
-      if ((*i).second->RequestInterface (destination, interfaceTmp))
-        {
-          NS_LOG_LOGIC ("Found interface " << interfaceTmp);
-          interface = interfaceTmp;
-          return true;
-        }
-    }
-//
-// If there's no routing table entry telling us what *single* interface will 
-// be used to send a packet to this destination, we'll have to just pick one.  
-// If there's only one interface on this node, a good answer isn't very hard
-// to come up with.  Before jumping to any conclusions, remember that the 
-// zeroth interface is the loopback interface, so what we actually want is
-// a situation where there are exactly two interfaces on the node, in which
-// case interface one is the "single" interface connected to the outside world.
-//
-  if (GetNInterfaces () == 2)
-    {
-      NS_LOG_LOGIC ("One Interface.  Using interface 1.");
-      interface = 1;
-      return true;
-    }
-//
-// If we fall through to here, we have a node with multiple interfaces and
-// no routes to guide us in determining what interface to choose.  Either
-// no default route was found (for unicast or multicast), or in the case of a
-// multicast, the default route contained multiple outbound interfaces.
-//
-// The fallback position is to just get the unicast default route and use 
-// the outgoing interface specified there.  We don't want to leave the source
-// address unset, so we just assert here.
-//
-// N.B. that in the case of a multicast with a route containing multiple
-// outgoing interfaces, the source address of packets from that node will be
-// set to the IP address of the interface set in the default unicast route.
-// Also, in the case of a broadcast, the same will be true.
-//
-  NS_LOG_LOGIC ("Using default unicast route");
-  Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
-
-  if (route == NULL)
-    {
-      NS_LOG_LOGIC ("Ipv4L3Protocol::GetInterfaceForDestination (): "
-                    "Unable to determine outbound interface.  No default route set");
-      return false;
-    }
-
-  interface = route->GetInterface ();
-
-  NS_LOG_LOGIC ("Default route specifies interface " << interface);
-  return true;
-}
-
 uint16_t 
 Ipv4L3Protocol::GetMtu (uint32_t i) const
 {
@@ -1088,7 +832,9 @@
       if (((interface->GetAddress (j).GetLocal ()) != (Ipv4Address ()))
           && (interface->GetAddress (j).GetMask ()) != (Ipv4Mask ()))
         {
-          AddNetworkRouteTo (interface->GetAddress (j).GetLocal ().CombineMask (interface->GetAddress (j).GetMask ()), interface->GetAddress (j).GetMask (), i);
+          NS_ASSERT_MSG (GetStaticRouting(), "SetUp:: No static routing");
+          GetStaticRouting ()->AddNetworkRouteTo (interface->GetAddress (j).GetLocal ().CombineMask (interface->GetAddress (j).GetMask ()),
+            interface->GetAddress (j).GetMask (), i);
         }
     }
 }
@@ -1105,12 +851,12 @@
   while (modified)
     {
       modified = false;
-      for (uint32_t i = 0; i < GetNRoutes (); i++)
+      for (uint32_t i = 0; i < GetStaticRouting ()->GetNRoutes (); i++)
         {
-          Ipv4Route route = GetRoute (i);
+          Ipv4RoutingTableEntry route = GetStaticRouting ()->GetRoute (i);
           if (route.GetInterface () == ifaceIndex)
             {
-              RemoveRoute (i);
+              GetStaticRouting ()->RemoveRoute (i);
               modified = true;
               break;
             }
@@ -1118,43 +864,23 @@
     }
 }
 
-// Note:  This method will be removed in Ipv4 routing work
-Ipv4Address
-Ipv4L3Protocol::GetSourceAddress (Ipv4Address destination) const
-{
-  uint32_t interface = 0xffffffff;
-
-  bool result = GetInterfaceForDestination (destination, interface);
-
-  if (result)
-    {
-      // if multiple addresses exist, search for the first one on the same subnet
-      for (uint32_t i = 0; i < GetNAddresses (interface); i++)
-        {
-          Ipv4InterfaceAddress ipv4InAddr = GetAddress (interface, i);
-          if (ipv4InAddr.GetLocal().CombineMask(ipv4InAddr.GetMask ()) == destination.CombineMask (ipv4InAddr.GetMask ()))
-            {
-              return ipv4InAddr.GetLocal ();
-            }
-        }
-      // Destination is off-link, so return first address.
-      return GetAddress (interface, 0).GetLocal ();
-    }
-  else
-    {
-//
-// If we can't find any address, just leave it 0.0.0.0
-//
-      return Ipv4Address::GetAny ();
-    }
-}
-
 Ptr<NetDevice>
 Ipv4L3Protocol::GetNetDevice (uint32_t i)
 {
   return GetInterface (i)-> GetDevice ();
 }
 
+void 
+Ipv4L3Protocol::SetIpForward (bool forward) 
+{
+  m_ipForward = forward;
+}
+
+bool 
+Ipv4L3Protocol::GetIpForward (void) const
+{
+  return m_ipForward;
+}
 
 
 }//namespace ns3