Commit d1c7c905 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[2238] Pool6 implemented, Subnet6 work in progress.

parent a7a5b8a6
......@@ -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");
}
}
......
......@@ -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
......
......@@ -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
......
......@@ -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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment