Add metric and longest prefix match support for IPv6.
authorSebastien Vincent <vincent@clarinet.u-strasbg.fr>
Mon, 07 Sep 2009 18:03:01 +0200
changeset 4761 8c0b3a413f4b
parent 4760 f774ff724ee4
child 4762 1b184e8be367
Add metric and longest prefix match support for IPv6.
CHANGES.html
examples/radvd-two-prefix.cc
examples/simple-routing-ping6.cc
src/internet-stack/icmpv6-l4-protocol.cc
src/internet-stack/icmpv6-l4-protocol.h
src/internet-stack/ipv6-l3-protocol.cc
src/node/inet6-socket-address.h
src/node/ipv6-address.cc
src/node/ipv6-address.h
src/node/ipv6-routing-protocol.h
src/routing/list-routing/ipv6-list-routing.cc
src/routing/list-routing/ipv6-list-routing.h
src/routing/static-routing/ipv6-routing-table-entry.cc
src/routing/static-routing/ipv6-static-routing.cc
src/routing/static-routing/ipv6-static-routing.h
--- a/CHANGES.html	Mon Sep 07 11:59:10 2009 +0100
+++ b/CHANGES.html	Mon Sep 07 18:03:01 2009 +0200
@@ -52,7 +52,7 @@
 
 <h2>New API:</h2>
 <ul>
-<li><b>Longest prefix match, support for metrics, for Ipv4StaticRouting</b>
+<li><b>Longest prefix match, support for metrics, for Ipv4StaticRouting and Ipv6StaticRouting</b>
 <p>When performing route lookup, first match for longest prefix, and then
 based on metrics (default metric = 0).  If metrics are equal, most recent
 addition is picked.  Extends API for support of metrics but preserves
--- a/examples/radvd-two-prefix.cc	Mon Sep 07 11:59:10 2009 +0100
+++ b/examples/radvd-two-prefix.cc	Mon Sep 07 18:03:01 2009 +0200
@@ -77,7 +77,7 @@
       routing = routingHelper.GetStaticRouting (ipv6);
 
       std::cout << "Routing table of " << n << " : " << std::endl;
-      std::cout << "Destination\t\t\t\t" << "Gateway\t\t\t\t\t" << "Interface\t" << std::endl;
+      std::cout << "Destination\t\t\t\t" << "Gateway\t\t\t\t\t" << "Interface\t" << "Prefix to use" << std::endl;
 
       nbRoutes = routing->GetNRoutes ();
       for (uint32_t i = 0 ; i < nbRoutes ; i++)
@@ -85,7 +85,9 @@
         route = routing->GetRoute (i);
         std::cout << route.GetDest () << "\t"
           << route.GetGateway () << "\t"
-          << route.GetInterface () << "\t" << std::endl;
+          << route.GetInterface () << "\t"
+          << route.GetPrefixToUse () << "\t"
+          << std::endl;
       }
     }
 };
--- a/examples/simple-routing-ping6.cc	Mon Sep 07 11:59:10 2009 +0100
+++ b/examples/simple-routing-ping6.cc	Mon Sep 07 18:03:01 2009 +0200
@@ -33,12 +33,59 @@
 #include "ns3/simulator-module.h"
 #include "ns3/helper-module.h"
 
+#include "ns3/ipv6-routing-table-entry.h"
+
 using namespace ns3;
 
 NS_LOG_COMPONENT_DEFINE ("SimpleRoutingPing6Example");
 
-int 
-main (int argc, char** argv)
+class StackHelper
+{
+  public:
+
+    /**
+     * \brief Add an address to a IPv6 node.
+     * \param n node
+     * \param interface interface index
+     * \param address IPv6 address to add
+     */
+    inline void AddAddress (Ptr<Node>& n, uint32_t interface, Ipv6Address address)
+    {
+      Ptr<Ipv6> ipv6 = n->GetObject<Ipv6> ();
+      ipv6->AddAddress (interface, address);
+    }
+
+    /**
+     * \brief Print the routing table.
+     * \param n the node
+     */
+    inline void PrintRoutingTable (Ptr<Node>& n)
+    {
+      Ptr<Ipv6StaticRouting> routing = 0;
+      Ipv6StaticRoutingHelper routingHelper;
+      Ptr<Ipv6> ipv6 = n->GetObject<Ipv6> ();
+      uint32_t nbRoutes = 0;
+      Ipv6RoutingTableEntry route;
+
+      routing = routingHelper.GetStaticRouting (ipv6);
+
+      std::cout << "Routing table of " << n << " : " << std::endl;
+      std::cout << "Destination\t\t\t\t" << "Gateway\t\t\t\t\t" << "Interface\t" <<  "Prefix to use" << std::endl;
+
+      nbRoutes = routing->GetNRoutes ();
+      for (uint32_t i = 0 ; i < nbRoutes ; i++)
+      {
+        route = routing->GetRoute (i);
+        std::cout << route.GetDest () << "\t"
+          << route.GetGateway () << "\t"
+          << route.GetInterface () << "\t"
+          << route.GetPrefixToUse () << "\t"
+          << std::endl;
+      }
+    }
+};
+
+int main (int argc, char** argv)
 {
 #if 0 
   LogComponentEnable ("Ipv6L3Protocol", LOG_LEVEL_ALL);
@@ -50,6 +97,8 @@
 
 	CommandLine cmd;
   cmd.Parse (argc, argv);
+
+  StackHelper stackHelper;
   
 	NS_LOG_INFO ("Create nodes.");
 	Ptr<Node> n0 = CreateObject<Node> ();
@@ -80,6 +129,8 @@
 	Ipv6InterfaceContainer i2 = ipv6.Assign (d2);
   i2.SetRouter (0, true);
 
+  stackHelper.PrintRoutingTable(n0);
+
   /* Create a Ping6 application to send ICMPv6 echo request from n0 to n1 via r */
   uint32_t packetSize = 1024;
   uint32_t maxPacketCount = 5;
@@ -88,7 +139,6 @@
 
   ping6.SetLocal (i1.GetAddress (0, 1));
   ping6.SetRemote (i2.GetAddress (1, 1)); 
-  /* ping6.SetRemote (Ipv6Address::GetAllNodesMulticast ()); */
 
   ping6.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
   ping6.SetAttribute ("Interval", TimeValue (interPacketInterval));
--- a/src/internet-stack/icmpv6-l4-protocol.cc	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/internet-stack/icmpv6-l4-protocol.cc	Mon Sep 07 18:03:01 2009 +0200
@@ -1086,6 +1086,19 @@
   return cache;
 }
 
+bool Icmpv6L4Protocol::Lookup (Ipv6Address dst, Ptr<NetDevice> device, Ptr<NdiscCache> cache, Address* hardwareDestination)
+{
+  NS_LOG_FUNCTION (this << dst << device << hardwareDestination);
+
+  if (!cache)
+  {
+    /* try to find the cache */
+    cache = FindCache (device);
+  }
+
+  return cache->Lookup (dst);
+}
+
 bool Icmpv6L4Protocol::Lookup (Ptr<Packet> p, Ipv6Address dst, Ptr<NetDevice> device, Ptr<NdiscCache> cache, Address* hardwareDestination)
 {
   NS_LOG_FUNCTION (this << p << dst << device << hardwareDestination);
--- a/src/internet-stack/icmpv6-l4-protocol.h	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/internet-stack/icmpv6-l4-protocol.h	Mon Sep 07 18:03:01 2009 +0200
@@ -226,7 +226,6 @@
      * \param id id of the packet
      * \param seq sequence number
      * \param data auxiliary data
-     * \todo Change data to be a char[], change it too in icmpv6-header.
      */
     void SendEchoReply (Ipv6Address src, Ipv6Address dst, uint16_t id, uint16_t seq, Ptr<Packet> data);
 
@@ -350,7 +349,19 @@
     static void FunctionDadTimeout (Ptr<Icmpv6L4Protocol> icmpv6, Ipv6Interface* interface, Ipv6Address addr);
 
     /**
+     * \brief Lookup in the ND cache for the IPv6 address
+     * \param dst destination address
+     * \param device device
+     * \param cache the neighbor cache
+     * \param hardwareDestination hardware address
+     * \note Unlike other Lookup method, it does not send NS request!
+     */
+    bool Lookup (Ipv6Address dst, Ptr<NetDevice> device, Ptr<NdiscCache> cache, Address* hardwareDestination);
+
+    /**
      * \brief Lookup in the ND cache for the IPv6 address (similar as ARP protocol).
+     *
+     * It also send NS request to target and store the waiting packet.
      * \param p the packet
      * \param dst destination address
      * \param device device
--- a/src/internet-stack/ipv6-l3-protocol.cc	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/internet-stack/ipv6-l3-protocol.cc	Mon Sep 07 18:03:01 2009 +0200
@@ -269,12 +269,6 @@
         (*it)->StopPreferredTimer ();
         (*it)->StopValidTimer ();
         (*it)->StartPreferredTimer ();
-
-        /* Suppose a link with two prefixes advertised, 
-         * when first prefix (which is the default route) expires,
-         * the second ones router has to be default router
-         */
-        GetRoutingProtocol ()->NotifyAddRoute (Ipv6Address::GetAny (), Ipv6Prefix ((uint8_t)0), defaultRouter, interface, network);
         return;
       }
     }
@@ -284,10 +278,7 @@
     AddAddress (interface, address);
 
     /* add default router
-     * check to know if default route already exists is done 
-     * in Ipv6StaticRouting class
-     *
-     * If default route is already set, this function does nothing.
+     * if a previous default route exists, the new ones is simply added 
      */
     GetRoutingProtocol ()->NotifyAddRoute (Ipv6Address::GetAny (), Ipv6Prefix ((uint8_t)0), defaultRouter, interface, network);
 
@@ -327,7 +318,7 @@
     }
   }
 
-  GetRoutingProtocol ()->NotifyRemoveRoute (Ipv6Address::GetAny (), Ipv6Prefix ((uint8_t)0), defaultRouter, interface);
+  GetRoutingProtocol ()->NotifyRemoveRoute (Ipv6Address::GetAny (), Ipv6Prefix ((uint8_t)0), defaultRouter, interface, network);
 }
 
 bool Ipv6L3Protocol::AddAddress (uint32_t i, Ipv6InterfaceAddress address)
@@ -811,7 +802,7 @@
 
     copy->AddHeader (header);
     
-    if (icmpv6->Lookup (copy, target, rtentry->GetOutputDevice (), 0, &hardwareTarget))
+    if (icmpv6->Lookup (target, rtentry->GetOutputDevice (), 0, &hardwareTarget))
     {
       icmpv6->SendRedirection (copy, src, target, dst, hardwareTarget);
     }
@@ -820,7 +811,7 @@
       icmpv6->SendRedirection (copy, src, target, dst, Address ());
     }
   }
-
+  
   SendRealOut (rtentry, packet, ipHeader);
 }
 
--- a/src/node/inet6-socket-address.h	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/node/inet6-socket-address.h	Mon Sep 07 18:03:01 2009 +0200
@@ -28,6 +28,7 @@
 namespace ns3 {
 
 /**
+ * \ingroup address
  * \class Inet6SocketAddress
  * \brief An Inet6 address class.
  */
--- a/src/node/ipv6-address.cc	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/node/ipv6-address.cc	Mon Sep 07 18:03:01 2009 +0200
@@ -483,6 +483,12 @@
   return loopback;
 }
 
+Ipv6Address Ipv6Address::GetOnes ()
+{
+  static Ipv6Address ones ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+  return ones; 
+}
+
 void Ipv6Address::GetBytes (uint8_t buf[16]) const
 {
   memcpy (buf, m_address, 16);
@@ -491,7 +497,7 @@
 bool Ipv6Address::IsLinkLocal () const
 {
   Ipv6Address linkLocal ("fe80::0");
-  if (!IsMulticast () && ((Ipv6Address*)this)->CombinePrefix (Ipv6Prefix (64))==linkLocal)
+  if (!IsMulticast () && ((Ipv6Address*)this)->CombinePrefix (Ipv6Prefix (64)) == linkLocal)
   {
     return true;
   }
@@ -627,6 +633,12 @@
   return prefix;
 }
 
+Ipv6Prefix Ipv6Prefix::GetOnes ()
+{
+  static Ipv6Prefix ones ((uint8_t)128);
+  return ones; 
+}
+
 Ipv6Prefix Ipv6Prefix::GetZero ()
 {
   Ipv6Prefix prefix ((uint8_t)0);
@@ -638,6 +650,25 @@
   memcpy (buf, m_prefix, 16);
 }
 
+uint8_t Ipv6Prefix::GetPrefixLength () const
+{
+  uint8_t i = 0;
+  uint8_t prefixLength = 0;
+
+  for(i = 0 ; i < 16 ; i++)
+  {
+    uint8_t mask = m_prefix[i];
+
+    while(mask != 0)
+    {
+      mask = mask << 1;
+      prefixLength++;
+    }
+  }
+  
+  return prefixLength;
+}
+
 bool Ipv6Prefix::IsEqual (const Ipv6Prefix& other) const
 {
   if (!memcmp (m_prefix, other.m_prefix, 16))
--- a/src/node/ipv6-address.h	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/node/ipv6-address.h	Mon Sep 07 18:03:01 2009 +0200
@@ -35,6 +35,7 @@
 class Mac48Address;
 
 /**
+ * \ingroup address
  * \class Ipv6Address
  * \brief Describes an IPv6 address.
  * \see Ipv6Prefix
@@ -254,6 +255,12 @@
     static Ipv6Address GetLoopback ();
 
     /**
+     * \brief Get the "all-1" IPv6 address (ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff).
+     * \return all-1 Ipv6Address representation
+     */
+    static Ipv6Address GetOnes ();
+
+    /**
      * \brief Get the bytes corresponding to the address.
      * \param buf buffer to store the data
      * \return bytes of the address
@@ -284,6 +291,7 @@
 };
 
 /**
+ * \ingroup address
  * \class Ipv6Prefix
  * \brief Describes an IPv6 prefix. It is just a bitmask like Ipv4Mask.
  * \see Ipv6Address
@@ -347,6 +355,12 @@
     void GetBytes (uint8_t buf[16]) const;
 
     /**
+     * \brief Get prefix length.
+     * \return prefix length
+     */
+    uint8_t GetPrefixLength () const;
+
+    /**
      * \brief Comparison operation between two Ipv6Prefix.
      * \param other the IPv6 prefix to which to compare this prefix
      * \return true if the prefixes are equal, false otherwise
@@ -368,6 +382,12 @@
     static Ipv6Prefix GetLoopback ();
 
     /**
+     * \brief Get the "all-1" IPv6 mask (ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff).
+     * \return /128 Ipv6Prefix representation
+     */
+    static Ipv6Prefix GetOnes ();
+
+    /**
      * \brief Get the zero prefix ( /0).
      * \return an Ipv6Prefix
      */
--- a/src/node/ipv6-routing-protocol.h	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/node/ipv6-routing-protocol.h	Mon Sep 07 18:03:01 2009 +0200
@@ -37,14 +37,16 @@
 
 /**
  * \ingroup node 
- * \defgroup ipv6Routing Ipv6 Routing
- *
- * Abstract base class for Ipv6 routing protocols.  Defines two
- * virtual functions for packet routing and forwarding.  The first, 
+ * \defgroup ipv6Routing Ipv6RoutingProtocol
+ */
+/**
+ * \ingroup ipv6Routing
+ * \brief Abstract base class for Ipv6 routing protocols.
+ * 
+ * Defines two virtual functions for packet routing and forwarding.  The first, 
  * RouteOutput (), is used for locally originated packets, and the second,
  * RouteInput (), is used for forwarding and/or delivering received packets. 
  * Also defines the signatures of four callbacks used in RouteInput ().
- *
  */
 class Ipv6RoutingProtocol : public Object
 {
@@ -153,8 +155,9 @@
    * \param mask destination mask
    * \param nextHop nextHop for this destination
    * \param interface output interface
+   * \param prefixToUse prefix to use as source with this route
    */
-  virtual void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface) = 0;
+  virtual void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address::GetZero ()) = 0;
 
   /**
    * \param ipv6 the ipv6 object this routing protocol is being associated with
--- a/src/routing/list-routing/ipv6-list-routing.cc	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/routing/list-routing/ipv6-list-routing.cc	Mon Sep 07 18:03:01 2009 +0200
@@ -257,7 +257,7 @@
     }
 }
 
-void Ipv6ListRouting::NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface)
+void Ipv6ListRouting::NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
 {
   NS_LOG_FUNCTION (this << dst << mask << nextHop << interface);
   for (Ipv6RoutingProtocolList::const_iterator rprotoIter =
@@ -265,7 +265,7 @@
        rprotoIter != m_routingProtocols.end ();
        rprotoIter++)
     {
-      (*rprotoIter).second->NotifyRemoveRoute (dst, mask, nextHop, interface);
+      (*rprotoIter).second->NotifyRemoveRoute (dst, mask, nextHop, interface, prefixToUse);
     }
 }
 
@@ -352,7 +352,7 @@
   void NotifyAddAddress (uint32_t interface, Ipv6InterfaceAddress address) {}
   void NotifyRemoveAddress (uint32_t interface, Ipv6InterfaceAddress address) {}
   void NotifyAddRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address::GetZero ()) {}
-  void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface) {}
+  void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse) {}
   void SetIpv6 (Ptr<Ipv6> ipv6) {}
 };
 
@@ -367,7 +367,7 @@
   void NotifyAddAddress (uint32_t interface, Ipv6InterfaceAddress address) {}
   void NotifyRemoveAddress (uint32_t interface, Ipv6InterfaceAddress address) {}
   void NotifyAddRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address::GetZero ()) {}
-  void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface) {}
+  void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse) {}
   void SetIpv6 (Ptr<Ipv6> ipv6) {}
 };
 
--- a/src/routing/list-routing/ipv6-list-routing.h	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/routing/list-routing/ipv6-list-routing.h	Mon Sep 07 18:03:01 2009 +0200
@@ -85,7 +85,7 @@
   virtual void NotifyAddAddress (uint32_t interface, Ipv6InterfaceAddress address);
   virtual void NotifyRemoveAddress (uint32_t interface, Ipv6InterfaceAddress address);
   virtual void NotifyAddRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address::GetZero ());
-  virtual void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface);
+  virtual void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address::GetZero ());
   virtual void SetIpv6 (Ptr<Ipv6> ipv6);
 
 protected:
--- a/src/routing/static-routing/ipv6-routing-table-entry.cc	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/routing/static-routing/ipv6-routing-table-entry.cc	Mon Sep 07 18:03:01 2009 +0200
@@ -57,7 +57,7 @@
 
 Ipv6RoutingTableEntry::Ipv6RoutingTableEntry (Ipv6Address dest, uint32_t interface)
   : m_dest (dest),
-  m_destNetworkPrefix (Ipv6Prefix (128)),
+  m_destNetworkPrefix (Ipv6Prefix::GetOnes ()),
   m_gateway (Ipv6Address::GetZero ()),
   m_interface (interface),
   m_prefixToUse (Ipv6Address ("::"))
@@ -107,8 +107,7 @@
 
 bool Ipv6RoutingTableEntry::IsHost () const
 {
-  static Ipv6Prefix prefix (128);
-  if (m_destNetworkPrefix.IsEqual (prefix))
+  if (m_destNetworkPrefix.IsEqual (Ipv6Prefix::GetOnes ()))
   {
     return true;
   }
@@ -170,7 +169,7 @@
 
 Ipv6RoutingTableEntry Ipv6RoutingTableEntry::CreateHostRouteTo (Ipv6Address dest, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
 {
-  return Ipv6RoutingTableEntry (dest, Ipv6Prefix (128), nextHop, interface, prefixToUse);
+  return Ipv6RoutingTableEntry (dest, Ipv6Prefix::GetOnes (), nextHop, interface, prefixToUse);
 }
 
 Ipv6RoutingTableEntry Ipv6RoutingTableEntry::CreateHostRouteTo (Ipv6Address dest, uint32_t interface)
--- a/src/routing/static-routing/ipv6-static-routing.cc	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/routing/static-routing/ipv6-static-routing.cc	Mon Sep 07 18:03:01 2009 +0200
@@ -40,9 +40,8 @@
   return tid;
 }
 
-Ipv6StaticRouting::Ipv6StaticRouting ()
-  : m_defaultRoute (0),
-  m_ipv6 (0)
+  Ipv6StaticRouting::Ipv6StaticRouting ()
+: m_ipv6 (0)
 {
   NS_LOG_FUNCTION_NOARGS ();
 }
@@ -58,7 +57,7 @@
   NS_ASSERT (m_ipv6 == 0 && ipv6 != 0);
   uint32_t i = 0; 
   m_ipv6 = ipv6;
-  
+
   for (i = 0 ; i < m_ipv6->GetNInterfaces () ; i++)
   {
     if (m_ipv6->IsUp (i))
@@ -72,65 +71,47 @@
   }
 }
 
-void Ipv6StaticRouting::AddHostRouteTo (Ipv6Address dst, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
+void Ipv6StaticRouting::AddHostRouteTo (Ipv6Address dst, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse, uint32_t metric)
 {
-  NS_LOG_FUNCTION (this << dst << nextHop << interface << prefixToUse);
-  Ipv6RoutingTableEntry* route = new Ipv6RoutingTableEntry ();
-  *route = Ipv6RoutingTableEntry::CreateHostRouteTo (dst, nextHop, interface, prefixToUse);
-  m_hostRoutes.push_back (route);
+  NS_LOG_FUNCTION (this << dst << nextHop << interface << prefixToUse << metric);
+  AddNetworkRouteTo (dst, Ipv6Prefix::GetOnes (), nextHop, interface, prefixToUse, metric);
+}
+
+void Ipv6StaticRouting::AddHostRouteTo (Ipv6Address dst, uint32_t interface, uint32_t metric)
+{
+  NS_LOG_FUNCTION (this << dst << interface << metric);
+  AddNetworkRouteTo (dst, Ipv6Prefix::GetOnes (), interface, metric);
 }
 
-void Ipv6StaticRouting::AddHostRouteTo (Ipv6Address dst, uint32_t interface)
+void Ipv6StaticRouting::AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface, uint32_t metric)
 {
-  NS_LOG_FUNCTION (this << dst << interface);
+  NS_LOG_FUNCTION (this << network << networkPrefix << nextHop << interface << metric);
   Ipv6RoutingTableEntry* route = new Ipv6RoutingTableEntry ();
-  *route = Ipv6RoutingTableEntry::CreateHostRouteTo (dst, interface);
-  m_hostRoutes.push_back (route);
+  *route = Ipv6RoutingTableEntry::CreateNetworkRouteTo (network, networkPrefix, nextHop, interface);
+  m_networkRoutes.push_back (std::make_pair (route, metric));
 }
 
-void Ipv6StaticRouting::AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface)
+void Ipv6StaticRouting::AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse, uint32_t metric)
 {
-  NS_LOG_FUNCTION (this << network << networkPrefix << nextHop << interface);
-  Ipv6RoutingTableEntry* route = new Ipv6RoutingTableEntry ();
-  *route = Ipv6RoutingTableEntry::CreateNetworkRouteTo (network, networkPrefix, nextHop, interface);
-  m_networkRoutes.push_back (route);
-}
-
-void Ipv6StaticRouting::AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
-{
-  NS_LOG_FUNCTION (this << network << networkPrefix << nextHop << interface << prefixToUse);
+  NS_LOG_FUNCTION (this << network << networkPrefix << nextHop << interface << prefixToUse << metric);
   Ipv6RoutingTableEntry* route = new Ipv6RoutingTableEntry ();
   *route = Ipv6RoutingTableEntry::CreateNetworkRouteTo (network, networkPrefix, nextHop, interface, prefixToUse);
-  m_networkRoutes.push_back (route);
+  m_networkRoutes.push_back (std::make_pair (route, metric));
 }
 
 
-void Ipv6StaticRouting::AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, uint32_t interface)
+void Ipv6StaticRouting::AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, uint32_t interface, uint32_t metric)
 {
   NS_LOG_FUNCTION (this << network << networkPrefix << interface);
   Ipv6RoutingTableEntry* route = new Ipv6RoutingTableEntry ();
   *route = Ipv6RoutingTableEntry::CreateNetworkRouteTo (network, networkPrefix, interface);
-  m_networkRoutes.push_back (route);
+  m_networkRoutes.push_back (std::make_pair (route, metric));
 }
 
-void Ipv6StaticRouting::SetDefaultRoute (Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
+void Ipv6StaticRouting::SetDefaultRoute (Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse, uint32_t metric)
 {
   NS_LOG_FUNCTION (this << nextHop << interface << prefixToUse);
-  Ipv6RoutingTableEntry* route = new Ipv6RoutingTableEntry ();
-  *route = Ipv6RoutingTableEntry::CreateDefaultRoute (nextHop, interface);
-  route->SetPrefixToUse (prefixToUse);
-  delete m_defaultRoute;
-  m_defaultRoute = route;
-}
-
-void Ipv6StaticRouting::RemoveDefaultRoute ()
-{
-  NS_LOG_FUNCTION_NOARGS ();
-  if (m_defaultRoute)
-  {
-    delete m_defaultRoute;
-    m_defaultRoute = 0;
-  }
+  AddNetworkRouteTo (Ipv6Address ("::"), Ipv6Prefix::GetZero (), nextHop, interface, prefixToUse, metric);
 }
 
 void Ipv6StaticRouting::AddMulticastRoute (Ipv6Address origin, Ipv6Address group, uint32_t inputInterface, std::vector<uint32_t> outputInterfaces)
@@ -148,7 +129,7 @@
   Ipv6Address network = Ipv6Address ("ff00::"); /* RFC 3513 */
   Ipv6Prefix networkMask = Ipv6Prefix (8);
   *route = Ipv6RoutingTableEntry::CreateNetworkRouteTo (network, networkMask, outputInterface);
-  m_networkRoutes.push_back (route);
+  m_networkRoutes.push_back (std::make_pair (route, 0));
 }
 
 uint32_t Ipv6StaticRouting::GetNMulticastRoutes () const
@@ -199,7 +180,7 @@
 {
   NS_LOG_FUNCTION (this << index);
   uint32_t tmp = 0;
-  
+
   for (MulticastRoutesI i = m_multicastRoutes.begin () ; i != m_multicastRoutes.end () ; i++)
   {
     if (tmp == index)
@@ -219,11 +200,11 @@
   /* in the network table */
   for (NetworkRoutesI j = m_networkRoutes.begin () ; j != m_networkRoutes.end () ; j++)
   {
-    NS_ASSERT ((*j)->IsNetwork ());
-    Ipv6Prefix prefix = (*j)->GetDestNetworkPrefix ();
-    Ipv6Address entry = (*j)->GetDestNetwork ();
+    Ipv6RoutingTableEntry* rtentry = j->first;
+    Ipv6Prefix prefix = rtentry->GetDestNetworkPrefix ();
+    Ipv6Address entry = rtentry->GetDestNetwork ();
 
-    if (prefix.IsMatch (network, entry) && (*j)->GetInterface () == interfaceIndex)
+    if (prefix.IsMatch (network, entry) && rtentry->GetInterface () == interfaceIndex)
     {
       return true;
     }
@@ -237,10 +218,12 @@
 {
   NS_LOG_FUNCTION (this << dst << interface);
   Ptr<Ipv6Route> rtentry = 0;
+  uint16_t longestMask = 0;
+  uint32_t shortestMetric = 0xffffffff;
 
   /* when sending on link-local multicast, there have to be interface specified */
   if (dst == Ipv6Address::GetAllNodesMulticast () || dst.IsSolicitedMulticast () || 
-     dst == Ipv6Address::GetAllRoutersMulticast () || dst == Ipv6Address::GetAllHostsMulticast ())
+      dst == Ipv6Address::GetAllRoutersMulticast () || dst == Ipv6Address::GetAllHostsMulticast ())
   {
     NS_ASSERT_MSG (interface > 0, "Try to send on link-local multicast address, and no interface index is given!");
     rtentry = Create<Ipv6Route> ();
@@ -251,110 +234,81 @@
     return rtentry;
   }
 
-  /* is the destination in hosts table */
-  for (HostRoutesCI i = m_hostRoutes.begin () ; i != m_hostRoutes.end () ; i++)
+  for (NetworkRoutesI it = m_networkRoutes.begin () ; it != m_networkRoutes.end () ; it++)
   {
-    NS_ASSERT ((*i)->IsHost ());
-    if ((*i)->GetDest ().IsEqual (dst))
+    Ipv6RoutingTableEntry* j = it->first;
+    uint32_t metric = it->second;
+    Ipv6Prefix mask = j->GetDestNetworkPrefix ();
+    uint16_t maskLen = mask.GetPrefixLength ();
+    Ipv6Address entry = j->GetDestNetwork ();
+
+    NS_LOG_LOGIC ("Searching for route to " << dst << ", mask length " << maskLen << ", metric " << metric);
+
+    if (mask.IsMatch (dst, entry))
     {
-      if (!interface || interface == (*i)->GetInterface ())
+      NS_LOG_LOGIC ("Found global network route " << j << ", mask length " << maskLen << ", metric " << metric);
+
+      /* if interface is given, check the route will output on this interface */
+      if (!interface || interface == j->GetInterface ())
       {
-        NS_LOG_LOGIC ("Found global host route " << *i);
-        Ipv6RoutingTableEntry* route = (*i);
+        if (maskLen < longestMask)
+        {
+          NS_LOG_LOGIC ("Previous match longer, skipping");
+          continue;
+        }
+
+        if (maskLen > longestMask)
+        {
+          shortestMetric = 0xffffffff;
+        }
+
+        longestMask = maskLen;
+        if (metric > shortestMetric)
+        {
+          NS_LOG_LOGIC ("Equal mask length, but previous metric shorter, skipping");
+          continue;
+        }
+
+        shortestMetric = metric;
+        Ipv6RoutingTableEntry* route = j;
+        uint32_t interfaceIdx = route->GetInterface ();
         rtentry = Create<Ipv6Route> ();
-        uint32_t interfaceIdx = route->GetInterface ();
-        rtentry->SetDestination (route->GetDest ());
+
 
         if (route->GetGateway ().IsAny ())
         {
           rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetDest ()));
         }
+        else if (route->GetDest ().IsAny ()) /* default route */
+        {
+          rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetPrefixToUse ().IsAny () ? route->GetGateway () : route->GetPrefixToUse ()));
+        }
         else
         {
           rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetGateway ()));
         }
 
+        rtentry->SetDestination (route->GetDest ());
         rtentry->SetGateway (route->GetGateway ());
         rtentry->SetOutputDevice (m_ipv6->GetNetDevice (interfaceIdx));
-        return rtentry;
       }
     }
   }
 
-  /* or in the network table */
-  for (NetworkRoutesI j = m_networkRoutes.begin () ; j != m_networkRoutes.end () ; j++)
-  {
-    NS_ASSERT ((*j)->IsNetwork ());
-    Ipv6Prefix prefix = (*j)->GetDestNetworkPrefix ();
-    Ipv6Address entry = (*j)->GetDestNetwork ();
-
-    if (prefix.IsMatch (dst, entry))
-    {
-      /* if interface is given, check the route will output on this interface */
-      if (!interface || interface == (*j)->GetInterface ())
-      {
-        NS_LOG_LOGIC ("Found global network route " << *j);
-        Ipv6RoutingTableEntry* route = (*j);
-        rtentry = Create<Ipv6Route>();
-        uint32_t interfaceIdx = route->GetInterface ();
-        rtentry->SetDestination (route->GetDest ());
-        
-        if (route->GetGateway ().IsAny ())
-        {
-          rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetDest ()));
-        }
-        else
-        {
-          rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetGateway ()));
-        }
-
-        rtentry->SetGateway (route->GetGateway ());
-        rtentry->SetOutputDevice (m_ipv6->GetNetDevice (interfaceIdx));
-        return rtentry;
-      }
-    }
-  }
-
-  /* not found, return the default route if any */
-  if (m_defaultRoute != 0)
-  {
-    NS_ASSERT (m_defaultRoute->IsDefault ());
-    NS_LOG_LOGIC ("Found global network route via default route " << m_defaultRoute);
-    Ipv6RoutingTableEntry* route = m_defaultRoute;
-    rtentry = Create<Ipv6Route>();
-    uint32_t interfaceIdx = route->GetInterface ();
-    rtentry->SetDestination (route->GetDest ());
-    rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetPrefixToUse ().IsAny () ? route->GetGateway () : route->GetPrefixToUse ()));
-    rtentry->SetGateway (route->GetGateway ());
-    rtentry->SetOutputDevice (m_ipv6->GetNetDevice (interfaceIdx));
-    return rtentry;
-  }  
-
-  /* beuh!!! not route at all */
-  return 0;
+  NS_LOG_LOGIC ("Matching route via " << rtentry->GetDestination () << " (throught " << rtentry->GetGateway () << ") at the end");
+  return rtentry;
 }
 
 void Ipv6StaticRouting::DoDispose ()
 {
   NS_LOG_FUNCTION_NOARGS ();
-  for (HostRoutesI i = m_hostRoutes.begin () ; i != m_hostRoutes.end () ; i = m_hostRoutes.erase (i))
-  {
-    delete (*i);
-  }
-  m_hostRoutes.clear ();
-  
+
   for (NetworkRoutesI j = m_networkRoutes.begin () ;  j != m_networkRoutes.end () ; j = m_networkRoutes.erase (j))
   {
-    delete (*j);
+    delete j->first;
   }
   m_networkRoutes.clear ();
-  
-  if (m_defaultRoute != 0)
-  {
-    delete m_defaultRoute;
-    m_defaultRoute = 0;
-  }
-  
+
   for (MulticastRoutesI i = m_multicastRoutes.begin () ; i != m_multicastRoutes.end () ; i = m_multicastRoutes.erase (i))
   {
     delete (*i);
@@ -392,23 +346,23 @@
 
     if (group == route->GetGroup ())
     {
-       if (interface == Ipv6::IF_ANY || interface == route->GetInputInterface ())
-       {
-          NS_LOG_LOGIC ("Found multicast route" << *i);
-          mrtentry = Create<Ipv6MulticastRoute>();
-          mrtentry->SetGroup (route->GetGroup ());
-          mrtentry->SetOrigin (route->GetOrigin ());
-          mrtentry->SetParent (route->GetInputInterface ());
-          for (uint32_t j = 0 ; j < route->GetNOutputInterfaces () ; j++)
+      if (interface == Ipv6::IF_ANY || interface == route->GetInputInterface ())
+      {
+        NS_LOG_LOGIC ("Found multicast route" << *i);
+        mrtentry = Create<Ipv6MulticastRoute> ();
+        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))
           {
-            if (route->GetOutputInterface (j))
-            {
-              NS_LOG_LOGIC ("Setting output interface index " << route->GetOutputInterface (j));
-              mrtentry->SetOutputTtl (route->GetOutputInterface (j), Ipv6MulticastRoute::MAX_TTL - 1);
-            }
+            NS_LOG_LOGIC ("Setting output interface index " << route->GetOutputInterface (j));
+            mrtentry->SetOutputTtl (route->GetOutputInterface (j), Ipv6MulticastRoute::MAX_TTL - 1);
           }
-          return mrtentry;
-       } 
+        }
+        return mrtentry;
+      } 
     }
   }
   return mrtentry;
@@ -416,23 +370,40 @@
 
 uint32_t Ipv6StaticRouting::GetNRoutes ()
 {
-  NS_LOG_FUNCTION_NOARGS ();
-  uint32_t n = 0;
-  if (m_defaultRoute != 0)
-  {
-    n++;
-  }
-  n += m_hostRoutes.size ();
-  n += m_networkRoutes.size ();
-  return n;
+  return m_networkRoutes.size ();
 }
 
 Ipv6RoutingTableEntry Ipv6StaticRouting::GetDefaultRoute ()
 {
   NS_LOG_FUNCTION_NOARGS ();
-  if (m_defaultRoute != 0)
+  Ipv6Address dst ("::");
+  uint32_t shortestMetric = 0xffffffff;
+  Ipv6RoutingTableEntry* result = 0;
+
+  for (NetworkRoutesI it = m_networkRoutes.begin () ; it != m_networkRoutes.end () ; it++)
   {
-    return *m_defaultRoute;
+    Ipv6RoutingTableEntry* j = it->first;
+    uint32_t metric = it->second;
+    Ipv6Prefix mask = j->GetDestNetworkPrefix ();
+    uint16_t maskLen = mask.GetPrefixLength ();
+    Ipv6Address entry = j->GetDestNetwork ();
+
+    if (maskLen)
+    {
+      continue;
+    }
+
+    if (metric > shortestMetric)
+    {
+      continue;
+    }
+    shortestMetric = metric;
+    result = j;
+  }
+
+  if (result)
+  {
+    return result;
   }
   else
   {
@@ -443,38 +414,13 @@
 Ipv6RoutingTableEntry Ipv6StaticRouting::GetRoute (uint32_t index)
 {
   NS_LOG_FUNCTION (this << 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++)
+  for (NetworkRoutesI it = m_networkRoutes.begin () ; it != m_networkRoutes.end () ; it++)
   {
     if (tmp == index)
     {
-      return *j;
+      return it->first;
     }
     tmp++;
   }
@@ -483,43 +429,36 @@
   return 0;
 }
 
+uint32_t Ipv6StaticRouting::GetMetric (uint32_t index)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  uint32_t tmp = 0;
+
+  for (NetworkRoutesI it = m_networkRoutes.begin () ; it != m_networkRoutes.end () ; it++)
+  {
+    if (tmp == index)
+    {
+      return it->second;
+    }
+    tmp++;
+  }
+  NS_ASSERT (false);
+  // quiet compiler.
+  return 0;
+}
+
+
 void Ipv6StaticRouting::RemoveRoute (uint32_t index)
 {
   NS_LOG_FUNCTION (this << 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++)
+
+  for (NetworkRoutesI it = m_networkRoutes.begin () ; it != m_networkRoutes.end () ; it++)
   {
     if (tmp == index)
     {
-      delete *j;
-      m_networkRoutes.erase (j);
+      delete it->first;
+      m_networkRoutes.erase (it);
       return;
     }
     tmp++;
@@ -527,15 +466,18 @@
   NS_ASSERT (false);
 }
 
-void Ipv6StaticRouting::RemoveRoute (Ipv6Address network, Ipv6Prefix prefix, uint32_t ifIndex)
+void Ipv6StaticRouting::RemoveRoute (Ipv6Address network, Ipv6Prefix prefix, uint32_t ifIndex, Ipv6Address prefixToUse)
 {
   NS_LOG_FUNCTION (this << network << prefix << ifIndex);
-  for (NetworkRoutesI i = m_networkRoutes.begin () ; i != m_networkRoutes.end () ; i++)
+
+  for (NetworkRoutesI it = m_networkRoutes.begin () ; it != m_networkRoutes.end () ; it++)
   {
-    if (network == (*i)->GetDest () and (*i)->GetInterface () == ifIndex)
+    Ipv6RoutingTableEntry* rtentry = it->first;
+    if (network == rtentry->GetDest () && rtentry->GetInterface () == ifIndex && 
+        rtentry->GetPrefixToUse () == prefixToUse)
     {
-      delete *i;
-      m_networkRoutes.erase (i);
+      delete it->first;
+      m_networkRoutes.erase (it);
       return;
     }
   }
@@ -557,7 +499,7 @@
     // So, we just log it and fall through to LookupStatic ()
     NS_LOG_LOGIC ("RouteOutput ()::Multicast destination");
   }
-  
+
   rtentry = LookupStatic (destination, oif);
   if (rtentry)
   {
@@ -580,7 +522,8 @@
   {
     NS_LOG_LOGIC ("Multicast destination");
     Ptr<Ipv6MulticastRoute> mrtentry = LookupStatic (ipHeader.GetSourceAddress (),
-    ipHeader.GetDestinationAddress (), m_ipv6->GetInterfaceForDevice (idev));
+                                                    ipHeader.GetDestinationAddress ()
+                                                    , m_ipv6->GetInterfaceForDevice (idev));
 
     if (mrtentry)
     {
@@ -594,9 +537,9 @@
       return false; // Let other routing protocols try to handle this
     }
   }
-//
-// This is a unicast packet.  Check to see if we have a route for it.
-//
+  //
+  // This is a unicast packet.  Check to see if we have a route for it.
+  //
   NS_LOG_LOGIC ("Unicast destination");
   Ptr<Ipv6Route> rtentry = LookupStatic (ipHeader.GetDestinationAddress ());
 
@@ -618,7 +561,7 @@
   for (uint32_t j = 0 ; j < m_ipv6->GetNAddresses (i) ; j++)
   {
     if (m_ipv6->GetAddress (i, j).GetAddress () != Ipv6Address () &&
-       m_ipv6->GetAddress (i, j).GetPrefix () != Ipv6Prefix ())
+        m_ipv6->GetAddress (i, j).GetPrefix () != Ipv6Prefix ())
     {
       if (m_ipv6->GetAddress (i, j).GetPrefix () == Ipv6Prefix (128))
       {
@@ -628,7 +571,7 @@
       else
       {
         AddNetworkRouteTo (m_ipv6->GetAddress (i, j).GetAddress ().CombinePrefix (m_ipv6->GetAddress (i, j).GetPrefix ()),
-                          m_ipv6->GetAddress (i, j).GetPrefix (), i);
+            m_ipv6->GetAddress (i, j).GetPrefix (), i);
       }
     }
   }
@@ -636,8 +579,12 @@
 
 void Ipv6StaticRouting::NotifyInterfaceDown (uint32_t i)
 {
+  NS_LOG_FUNCTION (this << i);
+  uint32_t j = 0;
+  uint32_t max = GetNRoutes ();
+
   /* remove all static routes that are going through this interface */
-  for (uint32_t j = 0 ; j < GetNRoutes () ; j++)
+  while (j < max)
   {
     Ipv6RoutingTableEntry route = GetRoute (j);
 
@@ -645,6 +592,10 @@
     {
       RemoveRoute (j);
     }
+    else
+    {
+      j++;
+    }
   }
 }
 
@@ -673,13 +624,13 @@
 
   Ipv6Address networkAddress = address.GetAddress ().CombinePrefix (address.GetPrefix ());
   Ipv6Prefix networkMask = address.GetPrefix ();
-  
+
   // Remove all static routes that are going through this interface
   // which reference this network
   for (uint32_t j = 0 ; j < GetNRoutes () ; j++)
   {
     Ipv6RoutingTableEntry route = GetRoute (j);
-    
+
     if (route.GetInterface () == interface &&
         route.IsNetwork () &&
         route.GetDestNetwork () == networkAddress &&
@@ -693,11 +644,7 @@
 void Ipv6StaticRouting::NotifyAddRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
 {
   NS_LOG_INFO (this << dst << mask << nextHop << interface << prefixToUse);
-  if (mask == Ipv6Prefix (128))
-  {
-    AddHostRouteTo (dst, nextHop, interface);
-  }
-  else if (dst != Ipv6Address::GetZero ())
+  if (dst != Ipv6Address::GetZero ())
   {
     AddNetworkRouteTo (dst, mask, nextHop, interface);
   }
@@ -706,40 +653,24 @@
     /* this case is mainly used by configuring default route following RA processing,
      * in case of multipe prefix in RA, the first will configured default route
      */
-    if (!m_defaultRoute)
-    {
-      SetDefaultRoute (nextHop, interface, prefixToUse);
-    }
+    SetDefaultRoute (nextHop, interface, prefixToUse);
   }
 }
 
-void Ipv6StaticRouting::NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface)
+void Ipv6StaticRouting::NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
 {
   NS_LOG_FUNCTION (this << dst << mask << nextHop << interface);
-  if (mask == Ipv6Prefix (128))
-  {
-    for (HostRoutesI j = m_hostRoutes.begin () ; j != m_hostRoutes.end () ; j++)
-    {
-      Ipv6Prefix prefix = (*j)->GetDestNetworkPrefix ();
-      Ipv6Address entry = (*j)->GetDestNetwork ();
-
-      if (dst == entry && prefix == mask && (*j)->GetInterface () == interface)
-      {
-        delete (*j);
-        m_hostRoutes.erase (j);
-      } 
-    }
-  }
-  else if (dst != Ipv6Address::GetZero ())
+  if (dst != Ipv6Address::GetZero ())
   {
     for (NetworkRoutesI j = m_networkRoutes.begin () ; j != m_networkRoutes.end () ; j++)
     {
-      Ipv6Prefix prefix = (*j)->GetDestNetworkPrefix ();
-      Ipv6Address entry = (*j)->GetDestNetwork ();
+      Ipv6RoutingTableEntry* rtentry = j->first;
+      Ipv6Prefix prefix = rtentry->GetDestNetworkPrefix ();
+      Ipv6Address entry = rtentry->GetDestNetwork ();
 
-      if (dst == entry && prefix == mask && (*j)->GetInterface () == interface)
+      if (dst == entry && prefix == mask && rtentry->GetInterface () == interface)
       {
-        delete (*j);
+        delete j->first;
         m_networkRoutes.erase (j);
       } 
     }
@@ -747,17 +678,7 @@
   else
   {
     /* default route case */
-    if (!m_defaultRoute)
-    {
-      return;
-    }
-
-    if (m_defaultRoute->GetInterface () == interface && m_defaultRoute->GetGateway () == nextHop)
-    {
-      NS_LOG_LOGIC ("Remove default route (maybe because autoconfigured address expired)");
-      delete m_defaultRoute;
-      m_defaultRoute = 0;
-    }
+    RemoveRoute (dst, mask, interface, prefixToUse);
   }
 }
 
@@ -785,7 +706,7 @@
       return test.GetAddress ();
     }
   }
-  
+
   return ret;
 }
 
--- a/src/routing/static-routing/ipv6-static-routing.h	Mon Sep 07 11:59:10 2009 +0100
+++ b/src/routing/static-routing/ipv6-static-routing.h	Mon Sep 07 18:03:01 2009 +0200
@@ -44,6 +44,9 @@
 /**
  * \ingroup routing
  * \defgroup ipv6StaticRouting Ipv6StaticRouting
+ */
+/**
+ * \ingroup ipv6StaticRouting
  * \class Ipv6StaticRouting
  * \brief Static routing protocol for IP version 6 stack.
  * \see Ipv6RoutingProtocol
@@ -74,15 +77,17 @@
      * \param nextHop next hop address to route the packet
      * \param interface interface index
      * \param prefixToUse prefix that should be used for source address for this destination
+     * \param metric metric of route in case of multiple routes to same destination
      */
-    void AddHostRouteTo (Ipv6Address dest, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address ("::"));
+    void AddHostRouteTo (Ipv6Address dest, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address ("::"), uint32_t metric = 0);
 
     /**
      * \brief Add route to host.
      * \param dest destination address.
      * \param interface interface index
+     * \param metric metric of route in case of multiple routes to same destination
      */
-    void AddHostRouteTo (Ipv6Address dest, uint32_t interface);
+    void AddHostRouteTo (Ipv6Address dest, uint32_t interface, uint32_t metric = 0);
 
     /**
      * \brief Add route to network.
@@ -90,8 +95,9 @@
      * \param networkPrefix network prefix*
      * \param nextHop next hop address to route the packet
      * \param interface interface index
+     * \param metric metric of route in case of multiple routes to same destination
      */
-    void AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface);
+    void AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface, uint32_t metric = 0);
 
     /**
      * \brief Add route to network.
@@ -100,29 +106,27 @@
      * \param nextHop next hop address to route the packet
      * \param interface interface index
      * \param prefixToUse prefix that should be used for source address for this destination
+     * \param metric metric of route in case of multiple routes to same destination
      */
-    void AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse);
+    void AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse, uint32_t metric = 0);
 
     /**
      * \brief Add route to network.
      * \param network network address
      * \param networkPrefix network prefix
      * \param interface interface index
+     * \param metric metric of route in case of multiple routes to same destination
      */
-    void AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, uint32_t interface);
+    void AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, uint32_t interface, uint32_t metric = 0);
 
     /**
      * \brief Set the default route.
      * \param nextHop next hop address to route the packet
      * \param interface interface index
      * \param prefixToUse prefix to use (i.e for multihoming)
+     * \param metric metric of route in case of multiple routes to same destination
      */
-    void SetDefaultRoute (Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address ("::"));
-
-    /**
-     * \brief Remove the default route.
-     */
-    void RemoveDefaultRoute ();
+    void SetDefaultRoute (Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address ("::"), uint32_t metric = 0);
 
     /**
      * \brief Get the number or entries in the routing table.
@@ -132,6 +136,8 @@
 
     /**
      * \brief Get the default route.
+     *
+     * If multiple default routes exist, the one with lowest metric is returned.
      * \return default Ipv6Route
      */
     Ipv6RoutingTableEntry GetDefaultRoute ();
@@ -143,6 +149,13 @@
      */
     Ipv6RoutingTableEntry GetRoute (uint32_t i);
 
+   /**
+    * \brief Get a metric for route from the static unicast routing table.
+    * \param index The index (into the routing table) of the route to retrieve.  
+    * \return If route is set, the metric is returned. If not, an infinity metric (0xffffffff) is returned
+    */
+    uint32_t GetMetric (uint32_t index);
+
     /**
      * \brief Remove a route from the routing table.
      * \param i index
@@ -154,8 +167,9 @@
      * \param network IPv6 network
      * \param prefix IPv6 prefix
      * \param ifIndex interface index
+     * \param prefixToUse IPv6 prefix to use with this route (multihoming)
      */
-    void RemoveRoute (Ipv6Address network, Ipv6Prefix prefix, uint32_t ifIndex);
+    void RemoveRoute (Ipv6Address network, Ipv6Prefix prefix, uint32_t ifIndex, Ipv6Address prefixToUse);
 
     /**
      * \brief Add a multicast route for a given multicast source and group.
@@ -219,7 +233,7 @@
     virtual void NotifyAddAddress (uint32_t interface, Ipv6InterfaceAddress address);
     virtual void NotifyRemoveAddress (uint32_t interface, Ipv6InterfaceAddress address);
     virtual void NotifyAddRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address::GetZero ());
-    virtual void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface);
+    virtual void NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse = Ipv6Address::GetZero ());
     virtual void SetIpv6 (Ptr<Ipv6> ipv6);
 
   protected:
@@ -229,12 +243,9 @@
     void DoDispose ();
 
   private:
-    typedef std::list<Ipv6RoutingTableEntry *> HostRoutes;
-    typedef std::list<Ipv6RoutingTableEntry *>::const_iterator HostRoutesCI;
-    typedef std::list<Ipv6RoutingTableEntry *>::iterator HostRoutesI;
-    typedef std::list<Ipv6RoutingTableEntry *> NetworkRoutes;
-    typedef std::list<Ipv6RoutingTableEntry *>::const_iterator NetworkRoutesCI;
-    typedef std::list<Ipv6RoutingTableEntry *>::iterator NetworkRoutesI;
+    typedef std::list<std::pair <Ipv6RoutingTableEntry *, uint32_t> > NetworkRoutes;
+    typedef std::list<std::pair <Ipv6RoutingTableEntry *, uint32_t> >::const_iterator NetworkRoutesCI;
+    typedef std::list<std::pair <Ipv6RoutingTableEntry *, uint32_t> >::iterator NetworkRoutesI;
 
     typedef std::list<Ipv6MulticastRoutingTableEntry *> MulticastRoutes;
     typedef std::list<Ipv6MulticastRoutingTableEntry *>::const_iterator MulticastRoutesCI;
@@ -266,21 +277,11 @@
     Ipv6Address SourceAddressSelection (uint32_t interface, Ipv6Address dest);
 
     /**
-     * \brief the forwarding table for hosts.
-     */
-    HostRoutes m_hostRoutes;
-
-    /**
      * \brief the forwarding table for network.
      */
     NetworkRoutes m_networkRoutes;
 
     /**
-     * \brief the default route.
-     */
-    Ipv6RoutingTableEntry *m_defaultRoute;
-
-    /**
      * \brief the forwarding table for multicast.
      */
     MulticastRoutes m_multicastRoutes;