From: Tomek Mrugalski Date: Tue, 2 Oct 2012 15:18:49 +0000 (+0200) Subject: [2237] Pool4 and tests implemented. X-Git-Tag: trac2402_base~17^2~9^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=574a6f8834ffa1ef3faddc637257efcde4eae445;p=thirdparty%2Fkea.git [2237] Pool4 and tests implemented. --- diff --git a/src/lib/dhcp/addr_utilities.cc b/src/lib/dhcp/addr_utilities.cc index ad728333d2..0396d1a0b7 100644 --- a/src/lib/dhcp/addr_utilities.cc +++ b/src/lib/dhcp/addr_utilities.cc @@ -13,17 +13,30 @@ // PERFORMANCE OF THIS SOFTWARE. #include +#include #include using namespace isc::asiolink; +const static uint32_t masks[] = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, + 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, + 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, + 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, + 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, + 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, + 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, + 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, + 0xffffffff }; + +const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + + namespace isc { namespace dhcp { -isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix, +isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& prefix, uint8_t len) { - const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; uint8_t packed[V6ADDRESS_LEN]; // First we copy the whole address as 16 bytes. @@ -55,7 +68,36 @@ isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefi return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed)); } -isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix, +isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& prefix, + uint8_t len) { + uint32_t addr = prefix; + if (len>32) { + isc_throw(BadValue, "Too large netmask. 0..32 is allowed in IPv4"); + } + + return (IOAddress(addr & (~masks[32-len]))); +} + +isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix, + uint8_t len) { + if (prefix.getFamily() == AF_INET) { + return firstAddrInPrefix4(prefix, len); + } else { + return firstAddrInPrefix6(prefix, len); + } +} + +isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefix, + uint8_t len) { + uint32_t addr = prefix; + if (len>32) { + isc_throw(BadValue, "Too large netmask. 0..32 is allowed in IPv4"); + } + + return (IOAddress(addr | masks[32-len])); +} + +isc::asiolink::IOAddress lastAddrInPrefix6(const isc::asiolink::IOAddress& prefix, uint8_t len) { const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; @@ -92,5 +134,14 @@ isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed)); } +isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix, + uint8_t len) { + if (prefix.getFamily() == AF_INET) { + return lastAddrInPrefix4(prefix, len); + } else { + return lastAddrInPrefix6(prefix, len); + } +} + }; }; diff --git a/src/lib/dhcp/pool.cc b/src/lib/dhcp/pool.cc index da8a2e3389..1cf47a31a7 100644 --- a/src/lib/dhcp/pool.cc +++ b/src/lib/dhcp/pool.cc @@ -30,6 +30,38 @@ bool Pool::inRange(const isc::asiolink::IOAddress& addr) const { return (first_.smallerEqual(addr) && addr.smallerEqual(last_)); } +Pool4::Pool4(const isc::asiolink::IOAddress& first, + const isc::asiolink::IOAddress& last) + :Pool(first, last) { + // check if specified address boundaries are sane + if (first.getFamily() != AF_INET || last.getFamily() != AF_INET) { + isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4"); + } + + if (last < first) { + isc_throw(BadValue, "Upper boundary is smaller than lower boundary."); + } +} + +Pool4::Pool4(const isc::asiolink::IOAddress& prefix, + uint8_t prefix_len) + :Pool(prefix, IOAddress("0.0.0.0")) { + + // check if the prefix is sane + if (prefix.getFamily() != AF_INET) { + isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4"); + } + + // check if the prefix length is sane + if (prefix_len == 0 || prefix_len > 32) { + isc_throw(BadValue, "Invalid prefix length"); + } + + // Let's now calculate the last address in defined pool + last_ = lastAddrInPrefix(prefix, prefix_len); +} + + Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first, const isc::asiolink::IOAddress& last) :Pool(first, last), type_(type), prefix_len_(0) { @@ -52,7 +84,6 @@ Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first, // last_ = first; } - // 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) diff --git a/src/lib/dhcp/pool.h b/src/lib/dhcp/pool.h index 8f6fd8675f..46f6578d3c 100644 --- a/src/lib/dhcp/pool.h +++ b/src/lib/dhcp/pool.h @@ -91,6 +91,33 @@ protected: std::string comments_; }; +/// @brief Pool information for IPv4 addresses +/// +/// It holds information about pool4, i.e. a range of IPv4 address space that +/// is configured for DHCP allocation. +class Pool4 : public Pool { +public: + /// @brief the constructor for Pool4 "min-max" style definition + /// + /// @param first the first address in a pool + /// @param last the last address in a pool + Pool4(const isc::asiolink::IOAddress& first, + const isc::asiolink::IOAddress& last); + + /// @brief the constructor for Pool4 "prefix/len" style definition + /// + /// @param prefix specifies prefix of the pool + /// @param prefix_len specifies length of the prefix of the pool + Pool4(const isc::asiolink::IOAddress& prefix, + uint8_t prefix_len); +}; + +/// @brief a pointer an IPv4 Pool +typedef boost::shared_ptr Pool4Ptr; + +/// @brief a container for IPv4 Pools +typedef std::vector Pool4Collection; + /// @brief Pool information for IPv6 addresses and prefixes /// /// It holds information about pool6, i.e. a range of IPv6 address space that diff --git a/src/lib/dhcp/tests/pool_unittest.cc b/src/lib/dhcp/tests/pool_unittest.cc index 61d4c4acf3..63d4289794 100644 --- a/src/lib/dhcp/tests/pool_unittest.cc +++ b/src/lib/dhcp/tests/pool_unittest.cc @@ -27,6 +27,79 @@ using namespace isc::asiolink; namespace { +TEST(Pool4Test, constructor_first_last) { + + // let's construct 192.0.2.1-192.0.2.255 pool + Pool4 pool1(IOAddress("192.0.2.1"), IOAddress("192.0.2.255")); + + EXPECT_EQ(IOAddress("192.0.2.1"), pool1.getFirstAddress()); + EXPECT_EQ(IOAddress("192.0.2.255"), pool1.getLastAddress()); + + // This is Pool4, IPv6 addresses do not belong here + EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"), + IOAddress("192.168.0.5")), BadValue); + EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"), + IOAddress("2001:db8::1")), BadValue); + + // Should throw. Range should be 192.0.2.1-192.0.2.2, not + // the other way around. + EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.0.2.2"), + IOAddress("192.0.2.1")), BadValue); +} + +TEST(Pool4Test, constructor_prefix_len) { + + // let's construct 2001:db8:1::/96 pool + Pool4 pool1(IOAddress("192.0.2.0"), 25); + + EXPECT_EQ("192.0.2.0", pool1.getFirstAddress().toText()); + EXPECT_EQ("192.0.2.127", pool1.getLastAddress().toText()); + + // No such thing as /33 prefix + EXPECT_THROW(Pool4(IOAddress("192.0.2.1"), 33), BadValue); + + // /0 prefix does not make sense + EXPECT_THROW(Pool4(IOAddress("192.0.2.0"), 0), BadValue); + + // This is Pool6, IPv4 addresses do not belong here + EXPECT_THROW(Pool4(IOAddress("2001:db8::1"), 20), BadValue); +} + +TEST(Pool4Test, in_range) { + Pool4 pool1(IOAddress("192.0.2.10"), IOAddress("192.0.2.20")); + + EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.0"))); + EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.10"))); + EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.17"))); + EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.20"))); + EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.21"))); + EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.255"))); + EXPECT_FALSE(pool1.inRange(IOAddress("255.255.255.255"))); + EXPECT_FALSE(pool1.inRange(IOAddress("0.0.0.0"))); +} + +// This test creates 100 pools and verifies that their IDs are unique. +TEST(Pool4Test, unique_id) { + + const int num_pools = 100; + std::vector pools; + + for (int i = 0; i < num_pools; ++i) { + pools.push_back(Pool4Ptr(new Pool4(IOAddress("192.0.2.0"), + IOAddress("192.0.2.255")))); + } + + 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(Pool6Test, constructor_first_last) { // let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool