BIND 10 trac2238, updated. d1c7c9057bb24595f9dcefe226dc7f326f390486 [2238] Pool6 implemented, Subnet6 work in progress.
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Sep 14 17:37:59 UTC 2012
The branch, trac2238 has been updated
via d1c7c9057bb24595f9dcefe226dc7f326f390486 (commit)
via a7a5b8a6e3605e3a3788f6920a45e9fa3c215be0 (commit)
via eda12494283d717f4fb095be4ff57608f4003502 (commit)
via a66bc5d487b4b095bb9e322e33ed31c55d8af339 (commit)
via c16a30cbaf082a05c0fbd5c929bf0be6f007503f (commit)
from e9498651c8bc59ba17f353f196c0675dd7b8e2ff (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit d1c7c9057bb24595f9dcefe226dc7f326f390486
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Sep 14 19:37:17 2012 +0200
[2238] Pool6 implemented, Subnet6 work in progress.
commit a7a5b8a6e3605e3a3788f6920a45e9fa3c215be0
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Sep 14 19:36:22 2012 +0200
[2238] Missing tests for {first,last}AddrInPrefix() added.
commit eda12494283d717f4fb095be4ff57608f4003502
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Sep 14 19:32:43 2012 +0200
[2238] <= operator for IOAddress implemented.
commit a66bc5d487b4b095bb9e322e33ed31c55d8af339
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Sep 14 19:11:54 2012 +0200
[2238] firstAddrInPrefix(), lastAddrInPrefix() implemented
commit c16a30cbaf082a05c0fbd5c929bf0be6f007503f
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Sep 14 18:28:21 2012 +0200
[2238] IOAddress comparison operator.
-----------------------------------------------------------------------
Summary of changes:
src/lib/asiolink/io_address.h | 58 ++++++++++++-
src/lib/asiolink/tests/io_address_unittest.cc | 32 +++++++
src/lib/dhcp/cfgmgr.cc | 92 ++++++++++++++++++++
src/lib/dhcp/cfgmgr.h | 116 ++++++++++++++++++-------
src/lib/dhcp/tests/Makefile.am | 1 +
src/lib/dhcp/tests/cfgmgr_unittest.cc | 105 +++++++++++++++++++++-
src/lib/util/Makefile.am | 1 +
src/lib/util/addr_utilities.cc | 61 +++++++++++++
src/lib/util/addr_utilities.h | 49 +++++++++++
src/lib/util/tests/Makefile.am | 2 +
src/lib/util/tests/addr_utilities_unittest.cc | 85 ++++++++++++++++++
11 files changed, 567 insertions(+), 35 deletions(-)
create mode 100644 src/lib/util/addr_utilities.cc
create mode 100644 src/lib/util/addr_utilities.h
create mode 100644 src/lib/util/tests/addr_utilities_unittest.cc
-----------------------------------------------------------------------
diff --git a/src/lib/asiolink/io_address.h b/src/lib/asiolink/io_address.h
index c40e5b9..2e09260 100644
--- a/src/lib/asiolink/io_address.h
+++ b/src/lib/asiolink/io_address.h
@@ -131,7 +131,7 @@ public:
return equals(other);
}
- // \brief Compare addresses for inequality
+ /// \brief Compare addresses for inequality
///
/// \param other Address to compare against.
///
@@ -140,7 +140,61 @@ public:
return (!equals(other));
}
- // \brief Compare addresses for inequality
+ /// \brief Checks if one address is smaller than the other
+ ///
+ /// \param other Address to compare against.
+ ///
+ /// \return true if this address is smaller than the other address.
+ ///
+ /// It is useful for comparing which address is bigger.
+ /// Operations within one protocol family are obvious.
+ /// Comparisons between v4 and v6 will allways return v4
+ /// being smaller. This follows boost::asio::ip implementation
+ bool smallerThan(const IOAddress& other) const {
+ if (this->getFamily() < other.getFamily()) {
+ return (true);
+ }
+ if (this->getFamily() > other.getFamily()) {
+ return (false);
+ }
+ if (this->getFamily() == AF_INET6) {
+ return (this->asio_address_.to_v6() < other.asio_address_.to_v6());
+ } else {
+ return (this->asio_address_.to_v4() < other.asio_address_.to_v4());
+ }
+ }
+
+ /// \brief Checks if one address is smaller or equal than the other
+ ///
+ /// \param other Address to compare against.
+ ///
+ /// \return true if this address is smaller than the other address.
+ bool smallerEqual(const IOAddress& other) const {
+ if (equals(other)) {
+ return (true);
+ }
+ return (smallerThan(other));
+ }
+
+ /// \brief Checks if one address is smaller than the other
+ ///
+ /// \param other Address to compare against.
+ ///
+ /// See \ref smaller_than method for details.
+ bool operator<(const IOAddress& other) const {
+ return (smallerThan(other));
+ }
+
+ /// \brief Checks if one address is smaller or equal than the other
+ ///
+ /// \param other Address to compare against.
+ ///
+ /// See \ref smaller_equal method for details.
+ bool operator<=(const IOAddress& other) const {
+ return (smallerEqual(other));
+ }
+
+ /// \brief Compare addresses for inequality
///
/// \param other Address to compare against.
///
diff --git a/src/lib/asiolink/tests/io_address_unittest.cc b/src/lib/asiolink/tests/io_address_unittest.cc
index 4322283..2530ca5 100644
--- a/src/lib/asiolink/tests/io_address_unittest.cc
+++ b/src/lib/asiolink/tests/io_address_unittest.cc
@@ -99,3 +99,35 @@ TEST(IOAddressTest, uint32) {
EXPECT_EQ(addr3.toText(), "192.0.2.5");
}
+
+TEST(IOAddressTest, compare) {
+ IOAddress addr1("192.0.2.5");
+ IOAddress addr2("192.0.2.6");
+ IOAddress addr3("0.0.0.0");
+
+ IOAddress addr4("::");
+ IOAddress addr5("2001:db8::1");
+ IOAddress addr6("2001:db8::1:0");
+ IOAddress addr7("2001:db8::1:0"); // the same as 6
+
+ // v4 comparisons
+ EXPECT_TRUE(addr1 < addr2);
+ EXPECT_FALSE(addr2 < addr1);
+ EXPECT_FALSE(addr2 <= addr1);
+ EXPECT_TRUE(addr3 < addr1);
+ EXPECT_TRUE(addr3 < addr2);
+ EXPECT_TRUE(addr3 <= addr2);
+
+ // v6 comparisons
+ EXPECT_TRUE(addr4 < addr5);
+ EXPECT_TRUE(addr5 < addr6);
+ EXPECT_FALSE(addr6 < addr5);
+ EXPECT_FALSE(addr6 <= addr5);
+
+ // v4 to v6 - v4 should always be smaller
+ EXPECT_TRUE(addr1 < addr4);
+ EXPECT_TRUE(addr3 < addr4);
+ EXPECT_TRUE(addr2 < addr5);
+
+ EXPECT_TRUE(addr6 <= addr7);
+}
diff --git a/src/lib/dhcp/cfgmgr.cc b/src/lib/dhcp/cfgmgr.cc
index 4b3084a..a4a4b5f 100644
--- a/src/lib/dhcp/cfgmgr.cc
+++ b/src/lib/dhcp/cfgmgr.cc
@@ -12,11 +12,103 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <util/addr_utilities.h>
+#include <asiolink/io_address.h>
#include <dhcp/cfgmgr.h>
+using namespace isc::asiolink;
+using namespace isc::util;
+
namespace isc {
namespace dhcp {
+Pool::Pool(const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& valid_lifetime)
+ :id_(getNextID()), first_(first), last_(last), t1_(t1), t2_(t2), valid_(valid_lifetime) {
+
+}
+
+bool Pool::inRange(const isc::asiolink::IOAddress& addr) {
+ return ( first_.smallerEqual(addr) && addr.smallerEqual(last_) );
+}
+
+Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& preferred_lifetime,
+ const Triplet<uint32_t>& valid_lifetime)
+ :Pool(first, last, t1, t2, valid_lifetime),
+ type_(type), prefix_len_(0), preferred_(preferred_lifetime) {
+
+ if (last < first) {
+ isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
+ // This check is strict. If we decide that it is too strict,
+ // we need to comment it and uncomment lines below.
+
+ // first_ = last;
+ // last_ = first;
+ }
+
+ if (first.getFamily() != AF_INET6 || last.getFamily() != AF_INET6) {
+ isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
+ }
+
+ // TYPE_PD is not supported by this constructor. first-last style
+ // parameters are for IA and TA only. There is another dedicated
+ // constructor for that (it uses prefix/length)
+ if ((type != TYPE_IA) && (type != TYPE_TA)) {
+ isc_throw(BadValue, "Invalid Pool6 type specified");
+ }
+}
+
+Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& addr,
+ uint8_t prefix_len,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& preferred_lifetime,
+ const Triplet<uint32_t>& valid_lifetime)
+ :Pool(addr, IOAddress("::"), t1, t2, valid_lifetime),
+ type_(type), prefix_len_(prefix_len), preferred_(preferred_lifetime) {
+
+ if (prefix_len == 0 || prefix_len > 128) {
+ isc_throw(BadValue, "Invalid prefix length");
+ }
+
+ if (addr.getFamily() != AF_INET6) {
+ isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
+ }
+
+ // Let's now calculate the last address in defined pool
+ last_ = lastAddrInPrefix(addr, prefix_len);
+}
+
+
+Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len)
+ :id_(getNextID()), prefix_(prefix), len_(len) {
+ if ( (prefix.getFamily() == AF_INET6 && len > 128) ||
+ (prefix.getFamily() == AF_INET && len > 32) ) {
+ isc_throw(BadValue, "Invalid prefix length specified for subnet: " << len);
+ }
+}
+
+bool Subnet::inRange(const isc::asiolink::IOAddress& addr) {
+ IOAddress first = firstAddrInPrefix(prefix_, len_);
+ IOAddress last = lastAddrInPrefix(prefix_, len_);
+
+ return ( (first <= addr) && (addr <= last) );
+}
+
+Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length)
+ :Subnet(prefix, length) {
+ if (prefix.getFamily() != AF_INET6) {
+ isc_throw(BadValue, "Invalid prefix " << prefix.toText() << " specified in subnet6");
+ }
+}
+
diff --git a/src/lib/dhcp/cfgmgr.h b/src/lib/dhcp/cfgmgr.h
index b377732..989801f 100644
--- a/src/lib/dhcp/cfgmgr.h
+++ b/src/lib/dhcp/cfgmgr.h
@@ -107,27 +107,15 @@ protected:
T max_;
};
-class Pool6 {
-public:
- typedef enum {
- TYPE_IA,
- TYPE_TA,
- TYPE_PD
- } Pool6Type;
-
- Pool6(Pool6Type type, const isc::asiolink::IOAddress first,
- const isc::asiolink::IOAddress last,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& preferred_lifetime,
- const Triplet<uint32_t>& valid_lifetime);
+class Pool {
+public:
uint32_t getId() const {
return (id_);
}
- Pool6Type getType() const {
- return (type_);
+ Triplet<uint32_t> getValid() const {
+ return (valid_);
}
const isc::asiolink::IOAddress& getFirstAddress() const {
@@ -146,22 +134,28 @@ public:
return (t2_);
}
- Triplet<uint32_t> getPreferred() const {
- return (preferred_);
- }
+ /// @brief checks if specified address is in range
+ bool inRange(const isc::asiolink::IOAddress& addr);
- Triplet<uint32_t> getValid() const {
- return (valid_);
+protected:
+
+ /// @brief protected constructor
+ Pool(const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& valid_lifetime);
+
+ static uint32_t getNextID() {
+ static uint32_t id = 0;
+ return (id++);
}
-protected:
/// @brief pool-id
///
/// This ID is used to indentify this specific pool.
uint32_t id_;
- Pool6Type type_;
-
isc::asiolink::IOAddress first_;
isc::asiolink::IOAddress last_;
@@ -170,32 +164,94 @@ protected:
Triplet<uint32_t> t2_;
- Triplet<uint32_t> preferred_;
-
Triplet<uint32_t> valid_;
+ std::string comments_;
+
///uint128_t available_leases_;
///uint128_t total_leases_;
+};
- std::string comments_;
+class Pool6 : public Pool {
+public:
+ typedef enum {
+ TYPE_IA,
+ TYPE_TA,
+ TYPE_PD
+ } Pool6Type;
+
+ Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& preferred_lifetime,
+ const Triplet<uint32_t>& valid_lifetime);
+
+ Pool6(Pool6Type type, const isc::asiolink::IOAddress& addr,
+ uint8_t prefix_len,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& preferred_lifetime,
+ const Triplet<uint32_t>& valid_lifetime);
+
+ Pool6Type getType() const {
+ return (type_);
+ }
+
+ Triplet<uint32_t> getPreferred() const {
+ return (preferred_);
+ }
+
+protected:
+
+ Pool6Type type_;
+
+ /// @brief prefix length
+ /// used by TYPE_PD only (zeroed for other types)
+ uint8_t prefix_len_;
+
+ Triplet<uint32_t> preferred_;
};
+typedef boost::shared_ptr<Pool> PoolPtr;
typedef boost::shared_ptr<Pool6> Pool6Ptr;
typedef std::vector<Pool6Ptr> Pool6Collection;
-class Subnet6 {
+class Subnet {
public:
+ /// @brief checks if specified address is in range
+ bool inRange(const isc::asiolink::IOAddress& addr);
+
+protected:
+ /// @brief protected constructor
+ //
+ /// By making the constructor protected, we make sure that noone will
+ /// ever instantiate that class. Pool4 and Pool6 should be used instead.
+ Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len);
+
+ static uint32_t getNextID() {
+ static uint32_t id = 0;
+ return (id++);
+ }
+
/// @brief subnet-id
uint32_t id_;
- isc::asiolink::IOAddress addr_;
+ isc::asiolink::IOAddress prefix_;
- uint8_t prefix_len_;
+ uint8_t len_;
+};
+class Subnet6 : public Subnet {
+public:
+ Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length);
+
+protected:
/// collection of pools in that list
Pool6Collection pools_;
+
};
} // namespace isc::dhcp
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index 74751cc..d061d0d 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -52,6 +52,7 @@ libdhcpsrv_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
libdhcpsrv_unittests_CXXFLAGS = $(AM_CXXFLAGS)
libdhcpsrv_unittests_LDADD = $(GTEST_LDADD)
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
if USE_CLANGPP
diff --git a/src/lib/dhcp/tests/cfgmgr_unittest.cc b/src/lib/dhcp/tests/cfgmgr_unittest.cc
index fad5c57..3b08e66 100644
--- a/src/lib/dhcp/tests/cfgmgr_unittest.cc
+++ b/src/lib/dhcp/tests/cfgmgr_unittest.cc
@@ -55,7 +55,7 @@ TEST(TripletTest, constructor) {
EXPECT_EQ(17, x.get(17));
EXPECT_EQ(30, x.get(30));
-
+
EXPECT_EQ(30, x.get(35));
// this will be boring. It is expected to return 42 no matter what
@@ -71,8 +71,8 @@ TEST(TripletTest, constructor) {
EXPECT_EQ(42, y.get(80)); // time!
}
-// triplets must be easy to use
-// simple int conversions must be done on the fly
+// Triplets must be easy to use.
+// Simple to/from int conversions must be done on the fly.
TEST(TripletTest, operator) {
uint32_t x = 47;
@@ -99,4 +99,103 @@ TEST(TripletTest, sanity_check) {
}
+TEST(Pool6Test, constructor_first_last) {
+
+ // let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
+ Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+ IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
+ 1000, 2000, 3000, 4000);
+
+ EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
+ EXPECT_EQ(IOAddress("2001:db8:1::"), pool1.getFirstAddress());
+ EXPECT_EQ(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
+ pool1.getLastAddress());
+ EXPECT_EQ(1000, pool1.getT1());
+ EXPECT_EQ(2000, pool1.getT2());
+ EXPECT_EQ(3000, pool1.getPreferred());
+ EXPECT_EQ(4000, pool1.getValid());
+
+ // This is Pool6, IPv4 addresses do not belong here
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
+ IOAddress("192.168.0.5"),
+ 1000, 2000, 3000, 4000), BadValue);
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
+ IOAddress("2001:db8::1"),
+ 1000, 2000, 3000, 4000), BadValue);
+
+
+ // Should throw. Range should be 2001:db8::1 - 2001:db8::2, not
+ // the other way around.
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::2"),
+ IOAddress("2001:db8::1"),
+ 1000, 2000, 3000, 4000), BadValue);
+}
+
+TEST(Pool6Test, constructor_prefix_len) {
+
+ // let's construct 2001:db8:1::/96 pool
+ Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+ 96, 1000, 2000, 3000, 4000);
+
+ EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
+ EXPECT_EQ("2001:db8:1::", pool1.getFirstAddress().toText());
+ EXPECT_EQ("2001:db8:1::ffff:ffff", pool1.getLastAddress().toText());
+ EXPECT_EQ(1000, pool1.getT1());
+ EXPECT_EQ(2000, pool1.getT2());
+ EXPECT_EQ(3000, pool1.getPreferred());
+ EXPECT_EQ(4000, pool1.getValid());
+
+ // This is Pool6, IPv4 addresses do not belong here
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
+ 96, 1000, 2000, 3000, 4000),
+ BadValue);
+}
+
+TEST(Pool6Test, in_range) {
+ Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::1"),
+ IOAddress("2001:db8:1::f"),
+ 1000, 2000, 3000, 4000);
+
+ EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::1")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::7")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::f")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::10")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("::")));
+}
+
+// This test creates 100 pools and verifies that their IDs are unique.
+TEST(Pool6Test, unique_id) {
+
+ const int num_pools = 100;
+ vector<Pool6Ptr> pools;
+
+ for (int i = 0; i < num_pools; ++i) {
+ pools.push_back(Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+ IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
+ 1000, 2000, 3000, 4000)));
+ }
+
+ for (int i = 0; i < num_pools; ++i) {
+ for (int j = i + 1; j < num_pools; ++j) {
+ if (pools[i]->getId() == pools[j]->getId()) {
+ FAIL() << "Pool-ids must be unique";
+ }
+ }
+ }
+
+}
+
+
+TEST(Subnet6Test, in_range) {
+ Subnet6 subnet(IOAddress("2001:db8:1::"), 64);
+
+ EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:0:ffff:ffff:ffff:ffff:ffff")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::0")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::1")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:1:1::")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("::")));
+}
+
} // end of anonymous namespace
diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am
index c56e4b8..d599668 100644
--- a/src/lib/util/Makefile.am
+++ b/src/lib/util/Makefile.am
@@ -28,6 +28,7 @@ libb10_util_la_SOURCES += encode/binary_from_base32hex.h
libb10_util_la_SOURCES += encode/binary_from_base16.h
libb10_util_la_SOURCES += random/qid_gen.h random/qid_gen.cc
libb10_util_la_SOURCES += random/random_number_generator.h
+libb10_util_la_SOURCES += addr_utilities.cc addr_utilities.h
EXTRA_DIST = python/pycppwrapper_util.h
diff --git a/src/lib/util/addr_utilities.cc b/src/lib/util/addr_utilities.cc
new file mode 100644
index 0000000..481c0e3
--- /dev/null
+++ b/src/lib/util/addr_utilities.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <util/addr_utilities.h>
+
+namespace isc {
+namespace util {
+
+isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+
+ static char bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ uint8_t packed[16];
+
+ memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
+
+ if (len % 8 != 0) {
+ uint8_t mask = bitMask[len % 8];
+ packed[len / 8] = packed[len / 8] & mask;
+ len = (len/8 + 1) * 8;
+ }
+ for (int i = len / 8; i < 16; ++i) {
+ packed[i] = 0x0;
+ }
+
+ return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
+}
+
+isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+
+ static char bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ uint8_t packed[16];
+
+ memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
+
+ if (len % 8 != 0) {
+ uint8_t mask = bitMask[len % 8];
+ packed[len / 8] = packed[len / 8] | ~mask;
+ len = (len/8 + 1) * 8;
+ }
+ for (int i = len / 8; i < 16; ++i) {
+ packed[i] = 0xff;
+ }
+
+ return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
+}
+
+};
+};
diff --git a/src/lib/util/addr_utilities.h b/src/lib/util/addr_utilities.h
new file mode 100644
index 0000000..7f35326
--- /dev/null
+++ b/src/lib/util/addr_utilities.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <asiolink/io_address.h>
+
+namespace isc {
+namespace util {
+
+/// This code is based on similar code from the Dibbler project. I, Tomasz Mrugalski,
+/// as a sole creater of that code hereby release it under BSD license for the benefit
+/// of the BIND10 project.
+
+/// @brief returns a first address in a given prefix
+///
+/// Example: For 2001:db8:1::deaf:beef and length /120 the function will return
+/// 2001:db8:1::dead:bee0. See also @ref lastAddrInPrefix.
+///
+/// @param prefix and address that belongs to a prefix
+/// @param len prefix length
+///
+/// @return first address from a prefix
+isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len);
+
+/// @brief returns a last address in a given prefix
+///
+/// Example: For 2001:db8:1::deaf:beef and length /112 the function will return
+/// 2001:db8:1::dead:ffff. See also @ref firstAddrInPrefix.
+///
+/// @param prefix and address that belongs to a prefix
+/// @param len prefix length
+///
+/// @return first address from a prefix
+isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len);
+
+};
+};
diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am
index 105322f..5f3705d 100644
--- a/src/lib/util/tests/Makefile.am
+++ b/src/lib/util/tests/Makefile.am
@@ -41,6 +41,7 @@ run_unittests_SOURCES += socketsession_unittest.cc
run_unittests_SOURCES += strutil_unittest.cc
run_unittests_SOURCES += time_utilities_unittest.cc
run_unittests_SOURCES += range_utilities_unittest.cc
+run_unittests_SOURCES += addr_utilities_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
@@ -50,6 +51,7 @@ run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libb10-util-io.la
run_unittests_LDADD += \
$(top_builddir)/src/lib/util/unittests/libutil_unittests.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
run_unittests_LDADD += $(GTEST_LDADD)
endif
diff --git a/src/lib/util/tests/addr_utilities_unittest.cc b/src/lib/util/tests/addr_utilities_unittest.cc
new file mode 100644
index 0000000..6fef61c
--- /dev/null
+++ b/src/lib/util/tests/addr_utilities_unittest.cc
@@ -0,0 +1,85 @@
+
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <gtest/gtest.h>
+#include <vector>
+
+#include <util/addr_utilities.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::asiolink;
+
+TEST(Pool6Test, lastAddrInPrefix) {
+ IOAddress addr1("2001:db8:1:1234:5678:abcd:1234:beef");
+
+ // Prefixes rounded to nibbles are easy...
+ EXPECT_EQ("2001:db8:1:1234:5678:abcd:1234:ffff",
+ lastAddrInPrefix(addr1, 112).toText());
+ EXPECT_EQ("2001:db8:1:1234:5678:abcd:123f:ffff",
+ lastAddrInPrefix(addr1, 108).toText());
+ EXPECT_EQ("2001:db8:1:1234:5678:abcd:12ff:ffff",
+ lastAddrInPrefix(addr1, 104).toText());
+ EXPECT_EQ("2001:db8:1:1234:ffff:ffff:ffff:ffff",
+ lastAddrInPrefix(addr1, 64).toText());
+
+ IOAddress addr2("2001::");
+
+ // These are tricker, though, as they are done in 1 bit increments
+
+ // the last address in 2001::/127 pool should be 2001::1
+ EXPECT_EQ("2001::1", lastAddrInPrefix(addr2, 127).toText());
+
+ EXPECT_EQ("2001::3", lastAddrInPrefix(addr2, 126).toText());
+ EXPECT_EQ("2001::7", lastAddrInPrefix(addr2, 125).toText());
+ EXPECT_EQ("2001::f", lastAddrInPrefix(addr2, 124).toText());
+ EXPECT_EQ("2001::1f", lastAddrInPrefix(addr2, 123).toText());
+ EXPECT_EQ("2001::3f", lastAddrInPrefix(addr2, 122).toText());
+ EXPECT_EQ("2001::7f", lastAddrInPrefix(addr2, 121).toText());
+ EXPECT_EQ("2001::ff", lastAddrInPrefix(addr2, 120).toText());
+}
+
+TEST(Pool6Test, firstAddrInPrefix) {
+ IOAddress addr1("2001:db8:1:1234:5678:abcd:1234:beef");
+
+ // Prefixes rounded to nibbles are easy...
+ EXPECT_EQ("2001:db8:1:1234:5678:abcd:1234:0",
+ firstAddrInPrefix(addr1, 112).toText());
+ EXPECT_EQ("2001:db8:1:1234:5678:abcd:1230:0",
+ firstAddrInPrefix(addr1, 108).toText());
+ EXPECT_EQ("2001:db8:1:1234:5678:abcd:1200:0",
+ firstAddrInPrefix(addr1, 104).toText());
+ EXPECT_EQ("2001:db8:1:1234::",
+ firstAddrInPrefix(addr1, 64).toText());
+
+ IOAddress addr2("2001::ffff");
+
+ // These are tricker, though, as they are done in 1 bit increments
+
+ // the first address in 2001::/127 pool should be 2001::1
+ EXPECT_EQ("2001::fffe", firstAddrInPrefix(addr2, 127).toText());
+
+ EXPECT_EQ("2001::fffc", firstAddrInPrefix(addr2, 126).toText());
+ EXPECT_EQ("2001::fff8", firstAddrInPrefix(addr2, 125).toText());
+ EXPECT_EQ("2001::fff0", firstAddrInPrefix(addr2, 124).toText());
+ EXPECT_EQ("2001::ffe0", firstAddrInPrefix(addr2, 123).toText());
+ EXPECT_EQ("2001::ffc0", firstAddrInPrefix(addr2, 122).toText());
+ EXPECT_EQ("2001::ff80", firstAddrInPrefix(addr2, 121).toText());
+ EXPECT_EQ("2001::ff00", firstAddrInPrefix(addr2, 120).toText());
+}
More information about the bind10-changes
mailing list