IPv6 address generator
authorAtishay Jain <atishayjain25@gmail.com>
Sat, 26 Nov 2011 20:33:45 -0800
changeset 7599 33588b2b9557
parent 7598 d12d85a4faca
child 7600 57ba46094a0d
IPv6 address generator
src/internet/model/ipv6-address-generator.cc
src/internet/model/ipv6-address-generator.h
src/internet/test/ipv6-address-generator-test-suite.cc
src/internet/wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet/model/ipv6-address-generator.cc	Sat Nov 26 20:33:45 2011 -0800
@@ -0,0 +1,604 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 University of Washington
+ * Copyright (c) 2011 Atishay Jain
+ *
+ * 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
+ */
+
+#include <list>
+#include "ns3/abort.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/simulation-singleton.h"
+#include "ipv6-address-generator.h"
+
+NS_LOG_COMPONENT_DEFINE ("Ipv6AddressGenerator");
+
+namespace ns3 {
+
+class Ipv6AddressGeneratorImpl
+{
+public:
+  Ipv6AddressGeneratorImpl ();
+  virtual ~Ipv6AddressGeneratorImpl ();
+
+  void Init (const Ipv6Address net, const Ipv6Prefix prefix,
+             const Ipv6Address interfaceId);
+
+  Ipv6Address GetNetwork (const Ipv6Prefix prefix) const;
+  Ipv6Address NextNetwork (const Ipv6Prefix prefix);
+
+  void InitAddress (const Ipv6Address interfaceId, const Ipv6Prefix prefix);
+  Ipv6Address GetAddress (const Ipv6Prefix prefix) const;
+  Ipv6Address NextAddress (const Ipv6Prefix prefix);
+
+  void Reset (void);
+  bool AddAllocated (const Ipv6Address addr);
+
+  void TestMode (void);
+private:
+  static const uint32_t N_BITS = 128;
+  static const uint32_t MOST_SIGNIFICANT_BIT = 0x80;
+
+  uint32_t PrefixToIndex (Ipv6Prefix prefix) const;
+
+  class NetworkState
+  {
+public:
+    uint8_t prefix[16];
+    uint32_t shift;
+    uint8_t network[16];
+    uint8_t addr[16];
+    uint8_t addrMax[16];
+  };
+
+  NetworkState m_netTable[N_BITS];
+
+  class Entry
+  {
+public:
+    uint8_t addrLow[16];
+    uint8_t addrHigh[16];
+  };
+
+  std::list<Entry> m_entries;
+  Ipv6Address m_base;
+  bool m_test;
+};
+
+Ipv6AddressGeneratorImpl::Ipv6AddressGeneratorImpl ()
+  : m_entries (),
+    m_base ("::1"),
+    m_test (false)
+{
+  NS_LOG_FUNCTION (this);
+  Reset ();
+}
+
+void
+Ipv6AddressGeneratorImpl::Reset (void)
+{
+  NS_LOG_FUNCTION (this);
+
+  uint8_t prefix[16] = { 0};
+
+  for (uint32_t i = 0; i < N_BITS; ++i)
+    {
+      for (uint32_t j = 0; j < 16; ++j)
+        {
+          m_netTable[i].prefix[j] = prefix[j];
+        }
+      for (uint32_t j = 0; j < 15; ++j)
+        {
+          prefix[15 - j] >>= 1;
+          prefix[15 - j] |= (prefix[15 - j - 1] & 1);
+        }
+      prefix[0] |= MOST_SIGNIFICANT_BIT;
+      for (uint32_t j = 0; j < 15; ++j)
+        {
+          m_netTable[i].network[j] = 0;
+        }
+      m_netTable[i].network[15] = 1;
+      for (uint32_t j = 0; j < 15; ++j)
+        {
+          m_netTable[i].addr[j] = 0;
+        }
+      m_netTable[i].addr[15] = 1;
+      for (uint32_t j = 0; j < 16; ++j)
+        {
+          m_netTable[i].addrMax[j] = ~prefix[j];
+        }
+      m_netTable[i].shift = N_BITS - i;
+    }
+  m_entries.clear ();
+  m_base = Ipv6Address ("::1");
+  m_test = false;
+}
+
+Ipv6AddressGeneratorImpl::~Ipv6AddressGeneratorImpl ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+void
+Ipv6AddressGeneratorImpl::Init (
+  const Ipv6Address net,
+  const Ipv6Prefix prefix,
+  const Ipv6Address interfaceId)
+{
+  NS_LOG_FUNCTION (this << net << prefix << interfaceId);
+
+  m_base = interfaceId;
+  //
+  // We're going to be playing with the actual bits in the network and prefix so
+  // pull them out into ints.
+  //
+  uint8_t prefixBits[16];
+  prefix.GetBytes (prefixBits);
+  uint8_t netBits[16];
+  net.GetBytes (netBits);
+  uint8_t interfaceIdBits[16];
+  interfaceId.GetBytes (interfaceIdBits);
+  //
+  // Some quick reasonableness testing.
+  //
+  // Convert the network prefix into an index into the network number table.
+  // The network number comes in to us properly aligned for the prefix and so
+  // needs to be shifted right into the normalized position (lowest bit of the
+  // network number at bit zero of the int that holds it).
+  //
+  uint32_t index = PrefixToIndex (prefix);
+  uint32_t a = m_netTable[index].shift / 8;
+  uint32_t b = m_netTable[index].shift % 8;
+  for (int32_t j = 15 - a; j >= 0; j--)
+    {
+      m_netTable[index].network[j + a] = netBits[j];
+    }
+  for (uint32_t j = 0; j < a; j++)
+    {
+      m_netTable[index].network[j] = 0;
+    }
+  for (uint32_t j = 15; j >= a; j--)
+    {
+      m_netTable[index].network[j] = m_netTable[index].network[j] >> b;
+      m_netTable[index].network[j] |= m_netTable[index].network[j - 1] << (8 - b);
+    }
+  for (int32_t j = 0; j < 16; j++)
+    {
+      m_netTable[index].addr[j] = interfaceIdBits[j];
+    }
+  return;
+}
+
+Ipv6Address
+Ipv6AddressGeneratorImpl::GetNetwork (
+  const Ipv6Prefix prefix) const
+{
+  NS_LOG_FUNCTION (this);
+  uint8_t nw[16];
+  uint32_t index = PrefixToIndex (prefix);
+  uint32_t a = m_netTable[index].shift / 8;
+  uint32_t b = m_netTable[index].shift % 8;
+  for (uint32_t j = 0; j < 16 - a; ++j)
+    {
+      nw[j] = m_netTable[index].network[j + a];
+    }
+  for (uint32_t j = 16 - a; j < 16; ++j)
+    {
+      nw[j] = 0;
+    }
+  for (uint32_t j = 0; j < 15; j++)
+    {
+      nw[j] = nw[j] << b;
+      nw[j] |= nw[j + 1] >> (8 - b);
+    }
+  nw[15] = nw[15] << b;
+
+  return Ipv6Address (nw);
+}
+
+Ipv6Address
+Ipv6AddressGeneratorImpl::NextNetwork (
+  const Ipv6Prefix prefix)
+{
+  NS_LOG_FUNCTION (this);
+
+  uint32_t index = PrefixToIndex (prefix);
+  // Reset the base to what was initialized
+  uint8_t interfaceIdBits[16];
+  m_base.GetBytes (interfaceIdBits);
+  for (int32_t j = 0; j < 16; j++)
+    {
+      m_netTable[index].addr[j] = interfaceIdBits[j];
+    }
+
+  for (uint8_t j = 15; j >= 0; j--)
+    {
+      if (m_netTable[index].network[j] < 0xff)
+        {
+          ++m_netTable[index].network[j];
+          break;
+        }
+      else
+        {
+          ++m_netTable[index].network[j];
+        }
+    }
+
+  uint8_t nw[16];
+  uint32_t a = m_netTable[index].shift / 8;
+  uint32_t b = m_netTable[index].shift % 8;
+  for (uint32_t j = 0; j < 16 - a; ++j)
+    {
+      nw[j] = m_netTable[index].network[j + a];
+    }
+  for (uint32_t j = 16 - a; j < 16; ++j)
+    {
+      nw[j] = 0;
+    }
+  for (uint32_t j = 0; j < 15; j++)
+    {
+      nw[j] = nw[j] << b;
+      nw[j] |= nw[j + 1] >> (8 - b);
+    }
+  nw[15] = nw[15] << b;
+
+  return Ipv6Address (nw);
+
+}
+
+void
+Ipv6AddressGeneratorImpl::InitAddress (
+  const Ipv6Address interfaceId,
+  const Ipv6Prefix prefix)
+{
+  NS_LOG_FUNCTION (this);
+
+  uint32_t index = PrefixToIndex (prefix);
+  uint8_t interfaceIdBits[16];
+  interfaceId.GetBytes (interfaceIdBits);
+
+  for (uint32_t j = 0; j < 16; ++j)
+    {
+      m_netTable[index].addr[j] = interfaceIdBits[j];
+    }
+}
+
+Ipv6Address
+Ipv6AddressGeneratorImpl::GetAddress (const Ipv6Prefix prefix) const
+{
+  NS_LOG_FUNCTION (this);
+
+  uint32_t index = PrefixToIndex (prefix);
+
+  uint8_t nw[16];
+  uint32_t a = m_netTable[index].shift / 8;
+  uint32_t b = m_netTable[index].shift % 8;
+  for (uint32_t j = 0; j < 16 - a; ++j)
+    {
+      nw[j] = m_netTable[index].network[j + a];
+    }
+  for (uint32_t j = 16 - a; j < 16; ++j)
+    {
+      nw[j] = 0;
+    }
+  for (uint32_t j = 0; j < 15; j++)
+    {
+      nw[j] = nw[j] << b;
+      nw[j] |= nw[j + 1] >> (8 - b);
+    }
+  nw[15] = nw[15] << b;
+  for (uint32_t j = 0; j < 16; j++)
+    {
+      nw[j] |= m_netTable[index].addr[j];
+    }
+
+  return Ipv6Address (nw);
+}
+
+Ipv6Address
+Ipv6AddressGeneratorImpl::NextAddress (const Ipv6Prefix prefix)
+{
+  NS_LOG_FUNCTION (this);
+
+  uint32_t index = PrefixToIndex (prefix);
+
+  uint8_t ad[16];
+  uint32_t a = m_netTable[index].shift / 8;
+  uint32_t b = m_netTable[index].shift % 8;
+  for (uint32_t j = 0; j < 16 - a; ++j)
+    {
+      ad[j] = m_netTable[index].network[j + a];
+    }
+  for (uint32_t j = 16 - a; j < 16; ++j)
+    {
+      ad[j] = 0;
+    }
+  for (uint32_t j = 0; j < 15; j++)
+    {
+      ad[j] = ad[j] << b;
+      ad[j] |= ad[j + 1] >> (8 - b);
+    }
+  ad[15] = ad[15] << b;
+  for (uint32_t j = 0; j < 16; j++)
+    {
+      ad[j] |= m_netTable[index].addr[j];
+    }
+  Ipv6Address addr = Ipv6Address (ad);
+
+  for (uint8_t j = 15; j >= 0; j--)
+    {
+      if (m_netTable[index].addr[j] < 0xff)
+        {
+          ++m_netTable[index].addr[j];
+          break;
+        }
+      else
+        {
+          ++m_netTable[index].addr[j];
+        }
+    }
+
+  //
+  // Make a note that we've allocated this address -- used for address collision
+  // detection.
+  //
+  AddAllocated (addr);
+  return addr;
+}
+
+bool
+Ipv6AddressGeneratorImpl::AddAllocated (const Ipv6Address address)
+{
+  NS_LOG_FUNCTION (this << address);
+
+  uint8_t addr[16];
+  address.GetBytes (addr);
+
+  std::list<Entry>::iterator i;
+
+  for (i = m_entries.begin (); i != m_entries.end (); ++i)
+    {
+      NS_LOG_LOGIC ("examine entry: " << Ipv6Address ((*i).addrLow) <<
+                    " to " << Ipv6Address ((*i).addrHigh));
+      //
+      // First things first.  Is there an address collision -- that is, does the
+      // new address fall in a previously allocated block of addresses.
+      //
+      if (!(Ipv6Address (addr) < Ipv6Address ((*i).addrLow))
+          && ((Ipv6Address (addr) < Ipv6Address ((*i).addrHigh))
+              || (Ipv6Address (addr) == Ipv6Address ((*i).addrHigh))))
+        {
+          NS_LOG_LOGIC ("Ipv6AddressGeneratorImpl::Add(): Address Collision: " << Ipv6Address (addr));
+          if (!m_test)
+            {
+              NS_FATAL_ERROR ("Ipv6AddressGeneratorImpl::Add(): Address Collision: " << Ipv6Address (addr));
+            }
+          return false;
+        }
+      //
+      // If the new address is less than the lowest address in the current
+      // block and can't be merged into to the current block, then insert it
+      // as a new block before the current block.
+      //
+      uint8_t taddr[16];
+      for (uint32_t j = 0; j < 16; j++)
+        {
+          taddr[j] = (*i).addrLow[j];
+        }
+      taddr[15] -= 1;
+      if (Ipv6Address (addr) < Ipv6Address (taddr))
+        {
+          break;
+        }
+      //
+      // If the new address fits at the end of the block, look ahead to the next
+      // block and make sure it's not a collision there.  If we won't overlap,
+      // then just extend the current block by one address.  We expect that
+      // completely filled network ranges will be a fairly rare occurrence,
+      // so we don't worry about collapsing address range blocks.
+      //
+      for (uint32_t j = 0; j < 16; j++)
+        {
+          taddr[j] = (*i).addrLow[j];
+        }
+      taddr[15] += 1;
+      if (Ipv6Address (addr) == Ipv6Address (taddr))
+        {
+          std::list<Entry>::iterator j = i;
+          ++j;
+
+          if (j != m_entries.end ())
+            {
+              if (Ipv6Address (addr) == Ipv6Address ((*j).addrLow))
+                {
+                  NS_LOG_LOGIC ("Ipv6AddressGeneratorImpl::Add(): "
+                                "Address Collision: " << Ipv6Address (addr));
+                  if (!m_test)
+                    {
+                      NS_FATAL_ERROR ("Ipv6AddressGeneratorImpl::Add(): Address Collision: " << Ipv6Address (addr));
+                    }
+                  return false;
+                }
+            }
+
+          NS_LOG_LOGIC ("New addrHigh = " << Ipv6Address (addr));
+          for (uint32_t j = 0; j < 16; j++)
+            {
+              (*i).addrHigh[j] = addr[j];
+            }
+          return true;
+        }
+      //
+      // If we get here, we know that the next lower block of addresses
+      // couldn't have been extended to include this new address since the
+      // code immediately above would have been executed and that next lower
+      // block extended upward.  So we know it's safe to extend the current
+      // block down to includ the new address.
+      //
+      for (uint32_t j = 0; j < 16; j++)
+        {
+          taddr[j] = (*i).addrLow[j];
+        }
+      taddr[15] -= 1;
+      if ((Ipv6Address (addr) == Ipv6Address (taddr)))
+        {
+          NS_LOG_LOGIC ("New addrLow = " << Ipv6Address (addr));
+          for (uint32_t j = 0; j < 16; j++)
+            {
+              (*i).addrLow[j] = addr[j];
+            }
+          return true;
+        }
+    }
+
+  Entry entry;
+  for (uint32_t j = 0; j < 16; j++)
+    {
+      entry.addrLow[j] = entry.addrHigh[j] = addr[j];
+    }
+  m_entries.insert (i, entry);
+  return true;
+}
+
+void
+Ipv6AddressGeneratorImpl::TestMode (void)
+{
+  NS_LOG_FUNCTION (this);
+  m_test = true;
+}
+
+uint32_t
+Ipv6AddressGeneratorImpl::PrefixToIndex (Ipv6Prefix prefix) const
+{
+  //
+  // We've been given a prefix that has a higher order bit set for each bit of
+  // the network number.  In order to translate this prefix into an index,
+  // we just need to count the number of zero bits in the prefix.  We do this
+  // in a loop in which we shift the prefix right until we find the first
+  // nonzero bit.  This tells us the number of zero bits, and from this we
+  // infer the number of nonzero bits which is the number of bits in the prefix.
+  //
+  // We use the number of bits in the prefix as the number of bits in the
+  // network number and as the index into the network number state table.
+  //
+  uint8_t prefixBits[16];
+  prefix.GetBytes (prefixBits);
+
+  for (uint32_t i = 15; i >= 0; --i)
+    {
+      for (uint32_t j = 0; j < 8; ++j)
+        {
+          if (prefixBits[i] & 1)
+            {
+              uint32_t index = N_BITS - (15 - i) * 8 - j;
+              NS_ABORT_MSG_UNLESS (index > 0 && index < N_BITS, "Ip64AddressGenerator::PrefixToIndex(): Illegal Prefix");
+              return index;
+            }
+          prefixBits[i] >>= 1;
+        }
+    }
+  NS_ASSERT_MSG (false, "Ipv6AddressGenerator::PrefixToIndex(): Impossible");
+  return 0;
+}
+
+void
+Ipv6AddressGenerator::Init (
+  const Ipv6Address net,
+  const Ipv6Prefix prefix,
+  const Ipv6Address interfaceId)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  SimulationSingleton<Ipv6AddressGeneratorImpl>::Get ()
+  ->Init (net, prefix, interfaceId);
+}
+
+Ipv6Address
+Ipv6AddressGenerator::NextNetwork (const Ipv6Prefix prefix)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  return SimulationSingleton<Ipv6AddressGeneratorImpl>::Get ()
+         ->NextNetwork (prefix);
+}
+
+Ipv6Address
+Ipv6AddressGenerator::GetNetwork (const Ipv6Prefix prefix)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  return SimulationSingleton<Ipv6AddressGeneratorImpl>::Get ()
+         ->GetNetwork (prefix);
+}
+
+void
+Ipv6AddressGenerator::InitAddress (
+  const Ipv6Address interfaceId,
+  const Ipv6Prefix prefix)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  SimulationSingleton<Ipv6AddressGeneratorImpl>::Get ()
+  ->InitAddress (interfaceId, prefix);
+}
+
+Ipv6Address
+Ipv6AddressGenerator::GetAddress (const Ipv6Prefix prefix)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  return SimulationSingleton<Ipv6AddressGeneratorImpl>::Get ()
+         ->GetAddress (prefix);
+}
+
+Ipv6Address
+Ipv6AddressGenerator::NextAddress (const Ipv6Prefix prefix)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  return SimulationSingleton<Ipv6AddressGeneratorImpl>::Get ()
+         ->NextAddress (prefix);
+}
+
+void
+Ipv6AddressGenerator::Reset (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  return SimulationSingleton<Ipv6AddressGeneratorImpl>::Get ()
+         ->Reset ();
+}
+
+bool
+Ipv6AddressGenerator::AddAllocated (const Ipv6Address addr)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  return SimulationSingleton<Ipv6AddressGeneratorImpl>::Get ()
+         ->AddAllocated (addr);
+}
+
+void
+Ipv6AddressGenerator::TestMode (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  SimulationSingleton<Ipv6AddressGeneratorImpl>::Get ()
+  ->TestMode ();
+}
+
+} // namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet/model/ipv6-address-generator.h	Sat Nov 26 20:33:45 2011 -0800
@@ -0,0 +1,145 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 University of Washington
+ * Copyright (c) 2011 Atishay Jain
+ *
+ * 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
+ */
+
+#ifndef IPV6_ADDRESS_GENERATOR_H
+#define IPV6_ADDRESS_GENERATOR_H
+
+#include "ns3/ipv6-address.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup address
+ *
+ * \brief This generator assigns addresses sequentially from a provided
+ * network address; used in topology code. It also keeps track of all
+ * addresses assigned to perform duplicate detection.
+ *
+ * Global unicast IPv6 addresses based on RFC 4291 definition:
+ *
+ *     |         n bits          |   m bits  |       128-n-m bits         |
+ *     +-------------------------+-----------+----------------------------+
+ *     | global routing prefix   | subnet ID |       interface ID         |
+ *     +-------------------------+-----------+----------------------------+
+ *
+ * In this class, the first two quantities (n + m) are what is called the
+ * 'net', and the 'prefix' defines the length in bits of (n + m).
+ *
+ * The way this is expected to be used is that, after initializing the
+ * network and interfaceId to a number, a user can call NextAddress ()
+ * repeatedly to obtain new interface IDs with the current network (for
+ * multiple addresses on the link) and can call NextNetwork () to increment
+ * the subnet ID.
+ *
+ * The interface ID is often an EUI-64 address derived from the MAC address,
+ * but can also be a pseudo-random value (RFC 3041).  This implementation
+ * does not generate EUI-64-based interface IDs.
+ */
+class Ipv6AddressGenerator
+{
+public:
+  /**
+   * \brief Initialise the base network and interfaceId for the generator
+   *
+   * The first call to NextAddress() or GetAddress() will return the
+   * value passed in.
+   *
+   * \param net The network for the base Ipv6Address
+   * \param prefix The prefix of the base Ipv6Address
+   * \param interfaceId The base interface ID used for initialization
+   */
+  static void Init (const Ipv6Address net, const Ipv6Prefix prefix,
+                    const Ipv6Address interfaceId = "::1");
+
+  /**
+   * \brief Get the next network acoording to the given Ipv6Prefix
+   *
+   * This operation is a pre-increment, meaning that the internal state
+   * is changed before returning the new network address.
+   *
+   * This also resets the interface ID to the base interface ID that was
+   * used for initialization.
+   *
+   * \param prefix The Ipv6Prefix used to set the next network
+   */
+  static Ipv6Address NextNetwork (const Ipv6Prefix prefix);
+
+  /**
+   * \brief Get the current network of the given Ipv6Prefix
+   *
+   * Does not change the internal state; this just peeks at the current
+   * network
+   *
+   * \param prefix The Ipv6Prefix for the current network
+   */
+  static Ipv6Address GetNetwork (const Ipv6Prefix prefix);
+
+  /**
+   * \brief Set the interfaceId for the given Ipv6Prefix
+   *
+   * \param interfaceId The interfaceId to set for the current Ipv6Prefix
+   * \param prefix The Ipv6Prefix whose address is to be set
+   */
+  static void InitAddress (const Ipv6Address interfaceId, const Ipv6Prefix prefix);
+
+  /**
+   * \brief Allocate the next Ipv6Address for the configured network and prefix
+   *
+   * This operation is a post-increment, meaning that the first address
+   * allocated will be the one that was initially configured.
+   * .
+   * \param prefix The Ipv6Prefix for the current network
+   */
+  static Ipv6Address NextAddress (const Ipv6Prefix prefix);
+
+  /**
+   * \brief Get the Ipv6Address that will be allocated upon NextAddress()
+   *
+   * Does not change the internal state; just is used to peek the next
+   * address that will be allocated upon NextAddress ()
+   *
+   * \param prefix The Ipv6Prefix for the current network
+   */
+  static Ipv6Address GetAddress (const Ipv6Prefix prefix);
+
+  /**
+   * \brief Reset the networks and Ipv6Address to zero
+   */
+  static void Reset (void);
+
+  /**
+   * \brief Add the Ipv6Address to the list of IPv6 entries
+   *
+   * Typically, this is used by external address allocators that want
+   * to make use of this class's ability to track duplicates.  AddAllocated
+   * is always called internally for any address generated by NextAddress()
+   *
+   * \param addr The Ipv6Address to be added to the list of Ipv6 entries
+   */
+  static bool AddAllocated (const Ipv6Address addr);
+
+  /**
+   * \brief Used to turn off fatal errors and assertions, for testing
+   */
+  static void TestMode (void);
+};
+
+}; // namespace ns3
+
+#endif /* IPV6_ADDRESS_GENERATOR_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet/test/ipv6-address-generator-test-suite.cc	Sat Nov 26 20:33:45 2011 -0800
@@ -0,0 +1,291 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 University of Washington
+ * Copyright (c) 2011 Atishay Jain
+ *
+ * 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
+ */
+
+#include "ns3/test.h"
+#include "ns3/ipv6-address-generator.h"
+#include "ns3/simulation-singleton.h"
+
+namespace ns3 {
+
+class NetworkNumber6AllocatorTestCase : public TestCase
+{
+public:
+  NetworkNumber6AllocatorTestCase ();
+  virtual void DoRun (void);
+  virtual void DoTeardown (void);
+};
+
+NetworkNumber6AllocatorTestCase::NetworkNumber6AllocatorTestCase ()
+  : TestCase ("Make sure the network number allocator is working on some of network prefixes.")
+{
+}
+void
+NetworkNumber6AllocatorTestCase::DoTeardown (void)
+{
+  Ipv6AddressGenerator::Reset ();
+}
+void
+NetworkNumber6AllocatorTestCase::DoRun (void)
+{
+  Ipv6Address network;
+
+  Ipv6AddressGenerator::Init (Ipv6Address ("1::0:0:0"), Ipv6Prefix ("FFFF::0"),
+                              Ipv6Address ("::"));
+  network = Ipv6AddressGenerator::GetNetwork (Ipv6Prefix ("FFFF::0"));
+  NS_TEST_EXPECT_MSG_EQ (network, Ipv6Address ("1::0:0:0"), "network should equal the initialized network for given prefix");
+  network = Ipv6AddressGenerator::NextNetwork (Ipv6Prefix ("FFFF::0"));
+  NS_TEST_EXPECT_MSG_EQ (network, Ipv6Address ("2::0:0:0"), "network should equal next network");
+
+  Ipv6AddressGenerator::Init (Ipv6Address ("0:1::0:0"),
+                              Ipv6Prefix ("FFFF:FFFF::0"), Ipv6Address ("::"));
+  network = Ipv6AddressGenerator::GetNetwork (Ipv6Prefix ("FFFF:FFFF::0"));
+  NS_TEST_EXPECT_MSG_EQ (network, Ipv6Address ("0:1::0"), "network should equal the initialized network for given prefix");
+  network = Ipv6AddressGenerator::NextNetwork (Ipv6Prefix ("FFFF:FFFF::0"));
+  NS_TEST_EXPECT_MSG_EQ (network, Ipv6Address ("0:2::0"), "network should equal next network");
+
+  Ipv6AddressGenerator::Init (Ipv6Address ("0:0:1::0"),
+                              Ipv6Prefix ("FFFF:FFFF:FFFF::0"), Ipv6Address ("::0"));
+  network = Ipv6AddressGenerator::GetNetwork (Ipv6Prefix ("FFFF:FFFF:FFFF::0"));
+  NS_TEST_EXPECT_MSG_EQ (network, Ipv6Address ("0:0:1::0"), "network should equal the initialized network for given prefix");
+  network = Ipv6AddressGenerator::NextNetwork (Ipv6Prefix ("FFFF:FFFF:FFFF::0"));
+  NS_TEST_EXPECT_MSG_EQ (network, Ipv6Address ("0:0:2::0"), "network should equal next network");
+
+}
+
+class AddressAllocator6TestCase : public TestCase
+{
+public:
+  AddressAllocator6TestCase ();
+private:
+  virtual void DoRun (void);
+  virtual void DoTeardown (void);
+};
+
+AddressAllocator6TestCase::AddressAllocator6TestCase ()
+  : TestCase ("Sanity check on allocation of addresses")
+{
+}
+
+void
+AddressAllocator6TestCase::DoRun (void)
+{
+  Ipv6Address address;
+
+  Ipv6AddressGenerator::Init (Ipv6Address ("2001::0"), Ipv6Prefix (64));
+  address = Ipv6AddressGenerator::GetNetwork (Ipv6Prefix (64));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("2001::0"), "address should equal the initialized address for given prefix");
+  Ipv6AddressGenerator::NextNetwork (Ipv6Prefix (64));
+  address = Ipv6AddressGenerator::GetNetwork (Ipv6Prefix (64));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("2001:0:0:1::0"), "address should equal the initialized address for given prefix");
+  address = Ipv6AddressGenerator::GetAddress (Ipv6Prefix (64));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("2001:0:0:1::1"), "address should equal the initialized address for given prefix");
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (64));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("2001:0:0:1::1"), "address should equal the initialized address for given prefix");
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (64));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("2001:0:0:1::2"), "address should equal the initialized address for given prefix");
+
+  Ipv6AddressGenerator::Init (Ipv6Address ("1::"), Ipv6Prefix ("FFFF::"),
+                              Ipv6Address ("::3"));
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (16));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("1::3"), "address should equal initialized address for given prefix");
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (16));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("1::4"), "address should equal next address");
+
+}
+
+void
+AddressAllocator6TestCase::DoTeardown (void)
+{
+  Ipv6AddressGenerator::Reset ();
+  Simulator::Destroy ();
+}
+
+
+class NetworkAndAddress6TestCase : public TestCase
+{
+public:
+  NetworkAndAddress6TestCase ();
+  virtual void DoRun (void);
+  virtual void DoTeardown (void);
+};
+
+NetworkAndAddress6TestCase::NetworkAndAddress6TestCase ()
+  : TestCase ("Make sure Network and address allocation play together.")
+{
+}
+
+void
+NetworkAndAddress6TestCase::DoTeardown (void)
+{
+  Ipv6AddressGenerator::Reset ();
+  Simulator::Destroy ();
+}
+
+void
+NetworkAndAddress6TestCase::DoRun (void)
+{
+  Ipv6Address address;
+  Ipv6Address network;
+
+  Ipv6AddressGenerator::Init (Ipv6Address ("3::"), Ipv6Prefix ("FFFF::"),
+                              Ipv6Address ("::3"));
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (16));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("3::3"), "address should equal initialized address for given prefix");
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (16));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("3::4"), "address should equal next address for given prefix");
+
+  network = Ipv6AddressGenerator::NextNetwork (Ipv6Prefix ("FFFF::"));
+  NS_TEST_EXPECT_MSG_EQ (network, Ipv6Address ("4::0"), "address should equal next address for given prefix");
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (16));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("4::3"), "address should equal next address for given prefix");
+
+}
+
+class ExampleAddress6GeneratorTestCase : public TestCase
+{
+public:
+  ExampleAddress6GeneratorTestCase ();
+private:
+  virtual void DoRun (void);
+  virtual void DoTeardown (void);
+};
+
+ExampleAddress6GeneratorTestCase::ExampleAddress6GeneratorTestCase ()
+  : TestCase ("A typical real-world example")
+{
+}
+
+void
+ExampleAddress6GeneratorTestCase::DoTeardown (void)
+{
+  Ipv6AddressGenerator::Reset ();
+}
+
+void
+ExampleAddress6GeneratorTestCase::DoRun (void)
+{
+  Ipv6Address address;
+
+  Ipv6AddressGenerator::Init (Ipv6Address ("2001:0AB8::"),
+                              Ipv6Prefix ("FFFF:FFFF:FFFF::0"), Ipv6Address ("::3"));
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (48));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("2001:0AB8::0:3"), "address should equal initialized address for given prefix");
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (48));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("2001:0AB8::0:4"), "address should equal next address for given prefix");
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (48));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("2001:0AB8::0:5"), "address should equal next address for given prefix");
+  //
+  // Allocate the next network based on the prefix passed in, which should
+  // be 2001:0AB0:0001
+  //
+  Ipv6AddressGenerator::NextNetwork (Ipv6Prefix ("FFFF:FFFF:FFFF::0"));
+  //
+  // reset first address to be allocated back to ::0:3
+  //
+  Ipv6AddressGenerator::InitAddress (Ipv6Address ("::3"),
+                                     Ipv6Prefix (48));
+  //
+  // The first address we should get is the network and address ORed
+  //
+  address = Ipv6AddressGenerator::NextAddress (Ipv6Prefix (48));
+  NS_TEST_EXPECT_MSG_EQ (address, Ipv6Address ("2001:0AB8:1::3"), "address should equal initialized address for given prefix");
+}
+
+class AddressCollision6TestCase : public TestCase
+{
+public:
+  AddressCollision6TestCase ();
+private:
+  void DoRun (void);
+  void DoTeardown (void);
+};
+
+AddressCollision6TestCase::AddressCollision6TestCase ()
+  : TestCase ("Make sure that the address collision logic works.")
+{
+}
+
+void
+AddressCollision6TestCase::DoTeardown (void)
+{
+  Ipv6AddressGenerator::Reset ();
+  Simulator::Destroy ();
+}
+void
+AddressCollision6TestCase::DoRun (void)
+{
+  Ipv6AddressGenerator::AddAllocated ("0::0:5");
+  Ipv6AddressGenerator::AddAllocated ("0::0:10");
+  Ipv6AddressGenerator::AddAllocated ("0::0:15");
+  Ipv6AddressGenerator::AddAllocated ("0::0:20");
+
+  Ipv6AddressGenerator::AddAllocated ("0::0:4");
+  Ipv6AddressGenerator::AddAllocated ("0::0:3");
+  Ipv6AddressGenerator::AddAllocated ("0::0:2");
+  Ipv6AddressGenerator::AddAllocated ("0::0:1");
+
+  Ipv6AddressGenerator::AddAllocated ("0::0:6");
+  Ipv6AddressGenerator::AddAllocated ("0::0:7");
+  Ipv6AddressGenerator::AddAllocated ("0::0:8");
+  Ipv6AddressGenerator::AddAllocated ("0::0:9");
+
+  Ipv6AddressGenerator::AddAllocated ("0::0:11");
+  Ipv6AddressGenerator::AddAllocated ("0::0:12");
+  Ipv6AddressGenerator::AddAllocated ("0::0:13");
+  Ipv6AddressGenerator::AddAllocated ("0::0:14");
+
+  Ipv6AddressGenerator::AddAllocated ("0::0:19");
+  Ipv6AddressGenerator::AddAllocated ("0::0:18");
+  Ipv6AddressGenerator::AddAllocated ("0::0:17");
+  Ipv6AddressGenerator::AddAllocated ("0::0:16");
+
+  Ipv6AddressGenerator::TestMode ();
+  bool added = Ipv6AddressGenerator::AddAllocated ("0::0:21");
+  NS_TEST_EXPECT_MSG_EQ (added, true, "address should get allocated");
+
+  added = Ipv6AddressGenerator::AddAllocated ("0::0:4");
+  NS_TEST_EXPECT_MSG_EQ (added, false, "address should not get allocated");
+
+  added = Ipv6AddressGenerator::AddAllocated ("0::0:9");
+  NS_TEST_EXPECT_MSG_EQ (added, false, "address should not get allocated");
+
+  added = Ipv6AddressGenerator::AddAllocated ("0::0:16");
+  NS_TEST_EXPECT_MSG_EQ (added, false, "address should not get allocated");
+
+  added = Ipv6AddressGenerator::AddAllocated ("0::0:21");
+  NS_TEST_EXPECT_MSG_EQ (added, false, "address should not get allocated");
+}
+
+
+static class Ipv6AddressGeneratorTestSuite : public TestSuite
+{
+public:
+  Ipv6AddressGeneratorTestSuite ()
+    : TestSuite ("ipv6-address-generator")
+  {
+    AddTestCase (new NetworkNumber6AllocatorTestCase ());
+    AddTestCase (new AddressAllocator6TestCase ());
+    AddTestCase (new NetworkAndAddress6TestCase ());
+    AddTestCase (new ExampleAddress6GeneratorTestCase ());
+    AddTestCase (new AddressCollision6TestCase ());
+  }
+} g_ipv6AddressGeneratorTestSuite;
+
+} // namespace ns3
+
--- a/src/internet/wscript	Sat Nov 26 08:43:33 2011 -0800
+++ b/src/internet/wscript	Sat Nov 26 20:33:45 2011 -0800
@@ -183,6 +183,7 @@
         'helper/ipv6-address-helper.cc',
         'helper/ipv6-interface-container.cc',
         'helper/ipv6-routing-helper.cc',
+        'model/ipv6-address-generator.cc',
         ]
 
     internet_test = bld.create_ns3_module_test_library('internet')
@@ -204,6 +205,7 @@
         'test/ipv6-test.cc',
         'test/tcp-test.cc',
         'test/udp-test.cc',
+        'test/ipv6-address-generator-test-suite.cc',
         ]
 
     headers = bld.new_task_gen(features=['ns3header'])
@@ -276,6 +278,7 @@
         'helper/ipv6-address-helper.h',
         'helper/ipv6-interface-container.h',
         'helper/ipv6-routing-helper.h',
+        'model/ipv6-address-generator.h',
        ]
 
     if bld.env['NSC_ENABLED']: