mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
Merge branch 'master' into trac2276
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
484. [func] tomek
|
||||
A new library (libb10-dhcpsrv) has been created. At present, it
|
||||
only holds the code for the DHCP Configuration Manager. Currently
|
||||
this object only supports basic configuration storage for the DHCPv6
|
||||
server, but that capability will be expanded.
|
||||
(Trac #2238, git 6f29861b92742da34be9ae76968e82222b5bfd7d)
|
||||
|
||||
bind10-devel-20120927 released on September 27, 2012
|
||||
|
||||
483. [func] marcin
|
||||
|
@@ -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,58 @@ 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 lessThan(const IOAddress& other) const {
|
||||
if (this->getFamily() == other.getFamily()) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
return (this->getFamily() < other.getFamily());
|
||||
}
|
||||
|
||||
/// \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 (lessThan(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 (lessThan(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.
|
||||
///
|
||||
|
@@ -99,3 +99,35 @@ TEST(IOAddressTest, uint32) {
|
||||
|
||||
EXPECT_EQ(addr3.toText(), "192.0.2.5");
|
||||
}
|
||||
|
||||
TEST(IOAddressTest, lessThanEqual) {
|
||||
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);
|
||||
}
|
||||
|
@@ -20,6 +20,8 @@
|
||||
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
#include <dns/name.h>
|
||||
|
||||
#include <datasrc/sqlite3_accessor.h>
|
||||
#include <datasrc/logger.h>
|
||||
#include <datasrc/data_source.h>
|
||||
@@ -84,8 +86,13 @@ const char* const text_statements[NUM_STATEMENTS] = {
|
||||
"SELECT id FROM zones WHERE name=?1 AND rdclass = ?2", // ZONE
|
||||
"SELECT rdtype, ttl, sigtype, rdata FROM records " // ANY
|
||||
"WHERE zone_id=?1 AND name=?2",
|
||||
"SELECT rdtype, ttl, sigtype, rdata " // ANY_SUB
|
||||
"FROM records WHERE zone_id=?1 AND name LIKE (\"%.\" || ?2)",
|
||||
|
||||
// ANY_SUB:
|
||||
// This query returns records in the specified zone for the domain
|
||||
// matching the passed name, and its sub-domains.
|
||||
"SELECT rdtype, ttl, sigtype, rdata "
|
||||
"FROM records WHERE zone_id=?1 AND rname LIKE ?2",
|
||||
|
||||
"BEGIN", // BEGIN
|
||||
"COMMIT", // COMMIT
|
||||
"ROLLBACK", // ROLLBACK
|
||||
@@ -660,17 +667,27 @@ public:
|
||||
statement_(NULL),
|
||||
name_(name)
|
||||
{
|
||||
// Choose the statement text depending on the query type
|
||||
const char* statement(NULL);
|
||||
// Choose the statement text depending on the query type, and
|
||||
// prepare a statement to get data from it.
|
||||
switch (qtype) {
|
||||
case QT_ANY:
|
||||
statement = text_statements[ANY];
|
||||
statement_ = prepare(accessor->dbparameters_->db_,
|
||||
text_statements[ANY]);
|
||||
bindZoneId(id);
|
||||
bindName(name_);
|
||||
break;
|
||||
case QT_SUBDOMAINS:
|
||||
statement = text_statements[ANY_SUB];
|
||||
statement_ = prepare(accessor->dbparameters_->db_,
|
||||
text_statements[ANY_SUB]);
|
||||
bindZoneId(id);
|
||||
// Done once, this should not be very inefficient.
|
||||
bindName(isc::dns::Name(name_).reverse().toText() + "%");
|
||||
break;
|
||||
case QT_NSEC3:
|
||||
statement = text_statements[NSEC3];
|
||||
statement_ = prepare(accessor->dbparameters_->db_,
|
||||
text_statements[NSEC3]);
|
||||
bindZoneId(id);
|
||||
bindName(name_);
|
||||
break;
|
||||
default:
|
||||
// Can Not Happen - there isn't any other type of query
|
||||
@@ -680,11 +697,6 @@ public:
|
||||
"Invalid qtype passed - unreachable code branch "
|
||||
"reached");
|
||||
}
|
||||
|
||||
// We create the statement now and then just keep getting data from it
|
||||
statement_ = prepare(accessor->dbparameters_->db_, statement);
|
||||
bindZoneId(id);
|
||||
bindName(name_);
|
||||
}
|
||||
|
||||
bool getNext(std::string (&data)[COLUMN_COUNT]) {
|
||||
|
@@ -13,7 +13,7 @@ AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
|
||||
|
||||
CLEANFILES = *.gcno *.gcda
|
||||
|
||||
lib_LTLIBRARIES = libb10-dhcp++.la
|
||||
lib_LTLIBRARIES = libb10-dhcp++.la libb10-dhcpsrv.la
|
||||
libb10_dhcp___la_SOURCES =
|
||||
libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
|
||||
libb10_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
|
||||
@@ -29,8 +29,18 @@ libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
|
||||
libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
|
||||
libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
|
||||
|
||||
libb10_dhcpsrv_la_SOURCES = cfgmgr.cc cfgmgr.h
|
||||
libb10_dhcpsrv_la_SOURCES += pool.cc pool.h
|
||||
libb10_dhcpsrv_la_SOURCES += subnet.cc subnet.h
|
||||
libb10_dhcpsrv_la_SOURCES += triplet.h
|
||||
libb10_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
|
||||
libb10_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
libb10_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
|
||||
libb10_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
|
||||
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
|
||||
libb10_dhcpsrv_la_LDFLAGS = -no-undefined -version-info 2:0:0
|
||||
|
||||
EXTRA_DIST = README
|
||||
#EXTRA_DIST += log_messages.mes
|
||||
|
||||
libb10_dhcp___la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
libb10_dhcp___la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
|
||||
|
@@ -1,11 +1,9 @@
|
||||
This directory holds implementation for libdhcp++.
|
||||
This directory holds implementation for DHCP libraries:
|
||||
|
||||
libdhcp++ - this is a generic purpose DHCP library. Please be careful
|
||||
what is put here. It is going to be shared by various servers (the "regular"
|
||||
one and the embedded as well), clients, relays and performance tools.
|
||||
|
||||
Basic Ideas
|
||||
===========
|
||||
libdhcpsrv - Server specific code goes in here. It will be used by
|
||||
dhcp4 and dhcp6 server.
|
||||
|
||||
|
||||
Notes
|
||||
=====
|
||||
This work just begun. Don't expect to see much useful code here.
|
||||
We are working on it.
|
||||
|
96
src/lib/dhcp/addr_utilities.cc
Normal file
96
src/lib/dhcp/addr_utilities.cc
Normal file
@@ -0,0 +1,96 @@
|
||||
// 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 <string.h>
|
||||
#include <dhcp/addr_utilities.h>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
isc::asiolink::IOAddress firstAddrInPrefix(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.
|
||||
memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
|
||||
|
||||
// If the length is divisible by 8, it is simple. We just zero out the host
|
||||
// part. Otherwise we need to handle the byte that has to be partially
|
||||
// zeroed.
|
||||
if (len % 8 != 0) {
|
||||
|
||||
// Get the appropriate mask. It has relevant bits (those that should
|
||||
// stay) set and irrelevant (those that should be wiped) cleared.
|
||||
uint8_t mask = bitMask[len % 8];
|
||||
|
||||
// Let's leave only whatever the mask says should not be cleared.
|
||||
packed[len / 8] = packed[len / 8] & mask;
|
||||
|
||||
// Since we have just dealt with this byte, let's move the prefix length
|
||||
// to the beginning of the next byte (len is expressed in bits).
|
||||
len = (len / 8 + 1) * 8;
|
||||
}
|
||||
|
||||
// Clear out the remaining bits.
|
||||
for (int i = len / 8; i < sizeof(packed); ++i) {
|
||||
packed[i] = 0x0;
|
||||
}
|
||||
|
||||
// Finally, let's wrap this into nice and easy IOAddress object.
|
||||
return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
|
||||
}
|
||||
|
||||
isc::asiolink::IOAddress lastAddrInPrefix(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.
|
||||
memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
|
||||
|
||||
// if the length is divisible by 8, it is simple. We just fill the host part
|
||||
// with ones. Otherwise we need to handle the byte that has to be partially
|
||||
// zeroed.
|
||||
if (len % 8 != 0) {
|
||||
// Get the appropriate mask. It has relevant bits (those that should
|
||||
// stay) set and irrelevant (those that should be set to 1) cleared.
|
||||
uint8_t mask = bitMask[len % 8];
|
||||
|
||||
// Let's set those irrelevant bits with 1. It would be perhaps
|
||||
// easier to not use negation here and invert bitMask content. However,
|
||||
// with this approach, we can use the same mask in first and last
|
||||
// address calculations.
|
||||
packed[len / 8] = packed[len / 8] | ~mask;
|
||||
|
||||
// Since we have just dealt with this byte, let's move the prefix length
|
||||
// to the beginning of the next byte (len is expressed in bits).
|
||||
len = (len / 8 + 1) * 8;
|
||||
}
|
||||
|
||||
// Finally set remaining bits to 1.
|
||||
for (int i = len / 8; i < sizeof(packed); ++i) {
|
||||
packed[i] = 0xff;
|
||||
}
|
||||
|
||||
// Finally, let's wrap this into nice and easy IOAddress object.
|
||||
return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
|
||||
}
|
||||
|
||||
};
|
||||
};
|
53
src/lib/dhcp/addr_utilities.h
Normal file
53
src/lib/dhcp/addr_utilities.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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 dhcp {
|
||||
|
||||
/// This code is based on similar code from the Dibbler project. I, Tomasz Mrugalski,
|
||||
/// as a sole creator 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:be00. See also @ref lastAddrInPrefix.
|
||||
///
|
||||
/// @todo It currently works for v6 only and will throw if v4 address is passed.
|
||||
///
|
||||
/// @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.
|
||||
///
|
||||
/// @todo It currently works for v6 only and will throw if v4 address is passed.
|
||||
///
|
||||
/// @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);
|
||||
|
||||
};
|
||||
};
|
78
src/lib/dhcp/cfgmgr.cc
Normal file
78
src/lib/dhcp/cfgmgr.cc
Normal file
@@ -0,0 +1,78 @@
|
||||
// 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>
|
||||
#include <dhcp/cfgmgr.h>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::util;
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
|
||||
|
||||
|
||||
CfgMgr&
|
||||
CfgMgr::instance() {
|
||||
static CfgMgr cfg_mgr;
|
||||
return (cfg_mgr);
|
||||
}
|
||||
|
||||
Subnet6Ptr
|
||||
CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
|
||||
|
||||
// If there's only one subnet configured, let's just use it
|
||||
// The idea is to keep small deployments easy. In a small network - one
|
||||
// router that also runs DHCPv6 server. Users specifies a single pool and
|
||||
// expects it to just work. Without this, the server would complain that it
|
||||
// doesn't have IP address on its interfaces that matches that
|
||||
// configuration. Such requirement makes sense in IPv4, but not in IPv6.
|
||||
// The server does not need to have a global address (using just link-local
|
||||
// is ok for DHCPv6 server) from the pool it serves.
|
||||
if (subnets6_.size() == 1) {
|
||||
return (subnets6_[0]);
|
||||
}
|
||||
|
||||
// If there is more than one, we need to choose the proper one
|
||||
for (Subnet6Collection::iterator subnet = subnets6_.begin();
|
||||
subnet != subnets6_.end(); ++subnet) {
|
||||
if ((*subnet)->inRange(hint)) {
|
||||
return (*subnet);
|
||||
}
|
||||
}
|
||||
|
||||
// sorry, we don't support that subnet
|
||||
return (Subnet6Ptr());
|
||||
}
|
||||
|
||||
Subnet6Ptr CfgMgr::getSubnet6(OptionPtr /*interfaceId*/) {
|
||||
/// @todo: Implement get subnet6 by interface-id (for relayed traffic)
|
||||
isc_throw(NotImplemented, "Relayed DHCPv6 traffic is not supported yet.");
|
||||
}
|
||||
|
||||
void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
|
||||
/// @todo: Check that this new subnet does not cross boundaries of any
|
||||
/// other already defined subnet.
|
||||
subnets6_.push_back(subnet);
|
||||
}
|
||||
|
||||
CfgMgr::CfgMgr() {
|
||||
}
|
||||
|
||||
CfgMgr::~CfgMgr() {
|
||||
}
|
||||
|
||||
}; // end of isc::dhcp namespace
|
||||
}; // end of isc namespace
|
126
src/lib/dhcp/cfgmgr.h
Normal file
126
src/lib/dhcp/cfgmgr.h
Normal file
@@ -0,0 +1,126 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CFGMGR_H
|
||||
#define CFGMGR_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <asiolink/io_address.h>
|
||||
#include <util/buffer.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/pool.h>
|
||||
#include <dhcp/subnet.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
|
||||
/// @brief Configuration Manager
|
||||
///
|
||||
/// This singleton class holds the whole configuration for DHCPv4 and DHCPv6
|
||||
/// servers. It currently holds information about zero or more subnets6.
|
||||
/// Each subnet may contain zero or more pools. Pool4 and Pool6 is the most
|
||||
/// basic "chunk" of configuration. It contains a range of assigneable
|
||||
/// addresses.
|
||||
///
|
||||
/// Below is a sketch of configuration inheritance (not implemented yet).
|
||||
/// Let's investigate the following configuration:
|
||||
///
|
||||
/// preferred-lifetime 500;
|
||||
/// valid-lifetime 1000;
|
||||
/// subnet6 2001:db8:1::/48 {
|
||||
/// pool6 2001::db8:1::1 - 2001::db8:1::ff;
|
||||
/// };
|
||||
/// subnet6 2001:db8:2::/48 {
|
||||
/// valid-lifetime 2000;
|
||||
/// pool6 2001::db8:2::1 - 2001::db8:2::ff;
|
||||
/// };
|
||||
/// Parameters defined in a global scope are applicable to everything until
|
||||
/// they are overwritten in a smaller scope, in this case subnet6.
|
||||
/// In the example above, the first subnet6 has preferred lifetime of 500s
|
||||
/// and a valid lifetime of 1000s. The second subnet has preferred lifetime
|
||||
/// of 500s, but valid lifetime of 2000s.
|
||||
///
|
||||
/// Parameter inheritance is likely to be implemented in configuration handling
|
||||
/// routines, so there is no storage capability in a global scope for
|
||||
/// subnet-specific parameters.
|
||||
///
|
||||
/// @todo: Implement Subnet4 support (ticket #2237)
|
||||
/// @todo: Implement option definition support
|
||||
/// @todo: Implement parameter inheritance
|
||||
class CfgMgr : public boost::noncopyable {
|
||||
public:
|
||||
|
||||
/// @brief returns a single instance of Configuration Manager
|
||||
///
|
||||
/// CfgMgr is a singleton and this method is the only way of
|
||||
/// accessing it.
|
||||
static CfgMgr& instance();
|
||||
|
||||
/// @brief get subnet by address
|
||||
///
|
||||
/// Finds a matching subnet, based on an address. This can be used
|
||||
/// in two cases: when trying to find an appropriate lease based on
|
||||
/// a) relay link address (that must be the address that is on link)
|
||||
/// b) our global address on the interface the message was received on
|
||||
/// (for directly connected clients)
|
||||
///
|
||||
/// @param hint an address that belongs to a searched subnet
|
||||
Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint);
|
||||
|
||||
/// @brief get subnet by interface-id
|
||||
///
|
||||
/// Another possibility to find a subnet is based on interface-id.
|
||||
///
|
||||
/// @param interface_id content of interface-id option returned by a relay
|
||||
/// @todo This method is not currently supported.
|
||||
Subnet6Ptr getSubnet6(OptionPtr interface_id);
|
||||
|
||||
/// @brief adds a subnet6
|
||||
void addSubnet6(const Subnet6Ptr& subnet);
|
||||
|
||||
/// @todo: Add subnet6 removal routines. Currently it is not possible
|
||||
/// to remove subnets. The only case where subnet6 removal would be
|
||||
/// needed is a dynamic server reconfiguration - a use case that is not
|
||||
/// planned to be supported any time soon.
|
||||
protected:
|
||||
|
||||
/// @brief Protected constructor.
|
||||
///
|
||||
/// This constructor is protected for 2 reasons. First, it forbids any
|
||||
/// instantiations of this class (CfgMgr is a singleton). Second, it
|
||||
/// allows derived class to instantiate it. That is useful for testing
|
||||
/// purposes.
|
||||
CfgMgr();
|
||||
|
||||
/// @brief virtual desctructor
|
||||
virtual ~CfgMgr();
|
||||
|
||||
/// @brief a container for Subnet6
|
||||
///
|
||||
/// That is a simple vector of pointers. It does not make much sense to
|
||||
/// optimize access time (e.g. using a map), because typical search
|
||||
/// pattern will use calling inRange() method on each subnet until
|
||||
/// a match is found.
|
||||
Subnet6Collection subnets6_;
|
||||
};
|
||||
|
||||
} // namespace isc::dhcp
|
||||
} // namespace isc
|
||||
|
||||
#endif
|
87
src/lib/dhcp/pool.cc
Normal file
87
src/lib/dhcp/pool.cc
Normal file
@@ -0,0 +1,87 @@
|
||||
// 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>
|
||||
#include <dhcp/addr_utilities.h>
|
||||
#include <dhcp/pool.h>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
Pool::Pool(const isc::asiolink::IOAddress& first,
|
||||
const isc::asiolink::IOAddress& last)
|
||||
:id_(getNextID()), first_(first), last_(last) {
|
||||
}
|
||||
|
||||
bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
|
||||
return (first_.smallerEqual(addr) && addr.smallerEqual(last_));
|
||||
}
|
||||
|
||||
Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
|
||||
const isc::asiolink::IOAddress& last)
|
||||
:Pool(first, last), type_(type), prefix_len_(0) {
|
||||
|
||||
// check if specified address boundaries are sane
|
||||
if (first.getFamily() != AF_INET6 || last.getFamily() != AF_INET6) {
|
||||
isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
|
||||
}
|
||||
|
||||
if (last < first) {
|
||||
isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
|
||||
// This check is a bit strict. If we decide that it is too strict,
|
||||
// we need to comment it and uncomment lines below.
|
||||
// On one hand, letting the user specify 2001::f - 2001::1 is nice, but
|
||||
// on the other hand, 2001::1 may be a typo and the user really meant
|
||||
// 2001::1:0 (or 1 followed by some hex digit), so a at least a warning
|
||||
// would be useful.
|
||||
|
||||
// first_ = last;
|
||||
// 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)
|
||||
if ((type != TYPE_IA) && (type != TYPE_TA)) {
|
||||
isc_throw(BadValue, "Invalid Pool6 type specified");
|
||||
}
|
||||
}
|
||||
|
||||
Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
|
||||
uint8_t prefix_len)
|
||||
:Pool(prefix, IOAddress("::")),
|
||||
type_(type), prefix_len_(prefix_len) {
|
||||
|
||||
// check if the prefix is sane
|
||||
if (prefix.getFamily() != AF_INET6) {
|
||||
isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
|
||||
}
|
||||
|
||||
// check if the prefix length is sane
|
||||
if (prefix_len == 0 || prefix_len > 128) {
|
||||
isc_throw(BadValue, "Invalid prefix length");
|
||||
}
|
||||
|
||||
/// @todo: We should probably implement checks against weird addresses
|
||||
/// here, like ::, starting with fe80, starting with ff etc. .
|
||||
|
||||
// Let's now calculate the last address in defined pool
|
||||
last_ = lastAddrInPrefix(prefix, prefix_len);
|
||||
}
|
||||
|
||||
}; // end of isc::dhcp namespace
|
||||
}; // end of isc namespace
|
155
src/lib/dhcp/pool.h
Normal file
155
src/lib/dhcp/pool.h
Normal file
@@ -0,0 +1,155 @@
|
||||
// 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.
|
||||
|
||||
#ifndef POOL_H
|
||||
#define POOL_H
|
||||
|
||||
#include <vector>
|
||||
#include <asiolink/io_address.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief base class for Pool4 and Pool6
|
||||
///
|
||||
/// Stores information about pool of IPv4 or IPv6 addresses.
|
||||
/// That is a basic component of a configuration.
|
||||
class Pool {
|
||||
|
||||
public:
|
||||
|
||||
/// @brief returns Pool-id
|
||||
///
|
||||
/// @return pool-id value
|
||||
/// Pool-id is an unique value that can be used to identify a pool.
|
||||
uint32_t getId() const {
|
||||
return (id_);
|
||||
}
|
||||
|
||||
/// @brief Returns the first address in a pool.
|
||||
///
|
||||
/// @return first address in a pool
|
||||
const isc::asiolink::IOAddress& getFirstAddress() const {
|
||||
return (first_);
|
||||
}
|
||||
|
||||
/// @brief Returns the last address in a pool.
|
||||
/// @return last address in a pool
|
||||
const isc::asiolink::IOAddress& getLastAddress() const {
|
||||
return (last_);
|
||||
}
|
||||
|
||||
/// @brief Checks if a given address is in the range.
|
||||
///
|
||||
/// @return true, if the address is in pool
|
||||
bool inRange(const isc::asiolink::IOAddress& addr) const;
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief protected constructor
|
||||
///
|
||||
/// This constructor is protected to prevent anyone from instantiating
|
||||
/// Pool class directly. Instances of Pool4 and Pool6 should be created
|
||||
/// instead.
|
||||
Pool(const isc::asiolink::IOAddress& first,
|
||||
const isc::asiolink::IOAddress& last);
|
||||
|
||||
/// @brief returns the next unique Pool-ID
|
||||
///
|
||||
/// @return the next unique Pool-ID
|
||||
static uint32_t getNextID() {
|
||||
static uint32_t id = 0;
|
||||
return (id++);
|
||||
}
|
||||
|
||||
/// @brief pool-id
|
||||
///
|
||||
/// This ID is used to identify this specific pool.
|
||||
uint32_t id_;
|
||||
|
||||
/// @brief The first address in a pool
|
||||
isc::asiolink::IOAddress first_;
|
||||
|
||||
/// @brief The last address in a pool
|
||||
isc::asiolink::IOAddress last_;
|
||||
|
||||
/// @brief Comments field
|
||||
///
|
||||
/// @todo: This field is currently not used.
|
||||
std::string comments_;
|
||||
};
|
||||
|
||||
/// @brief Pool information for IPv6 addresses and prefixes
|
||||
///
|
||||
/// It holds information about pool6, i.e. a range of IPv6 address space that
|
||||
/// is configured for DHCP allocation.
|
||||
class Pool6 : public Pool {
|
||||
public:
|
||||
|
||||
/// @brief specifies Pool type
|
||||
///
|
||||
/// Currently there are 3 pool types defined in DHCPv6:
|
||||
/// - Non-temporary addresses (conveyed in IA_NA)
|
||||
/// - Temporary addresses (conveyed in IA_TA)
|
||||
/// - Delegated Prefixes (conveyed in IA_PD)
|
||||
/// There is a new one being worked on (IA_PA, see draft-ietf-dhc-host-gen-id), but
|
||||
/// support for it is not planned for now.
|
||||
typedef enum {
|
||||
TYPE_IA,
|
||||
TYPE_TA,
|
||||
TYPE_PD
|
||||
} Pool6Type;
|
||||
|
||||
/// @brief the constructor for Pool6 "min-max" style definition
|
||||
///
|
||||
/// @param first the first address in a pool
|
||||
/// @param last the last address in a pool
|
||||
Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
|
||||
const isc::asiolink::IOAddress& last);
|
||||
|
||||
/// @brief the constructor for Pool6 "prefix/len" style definition
|
||||
///
|
||||
/// @param prefix specifies prefix of the pool
|
||||
/// @param prefix_len specifies length of the prefix of the pool
|
||||
Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
|
||||
uint8_t prefix_len);
|
||||
|
||||
/// @brief returns pool type
|
||||
///
|
||||
/// @return pool type
|
||||
Pool6Type getType() const {
|
||||
return (type_);
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief defines a pool type
|
||||
Pool6Type type_;
|
||||
|
||||
/// @brief prefix length
|
||||
/// used by TYPE_PD only (zeroed for other types)
|
||||
uint8_t prefix_len_;
|
||||
};
|
||||
|
||||
/// @brief a pointer an IPv6 Pool
|
||||
typedef boost::shared_ptr<Pool6> Pool6Ptr;
|
||||
|
||||
/// @brief a container for IPv6 Pools
|
||||
typedef std::vector<Pool6Ptr> Pool6Collection;
|
||||
|
||||
} // end of isc::dhcp namespace
|
||||
} // end of isc namespace
|
||||
|
||||
|
||||
#endif // POOL_H
|
91
src/lib/dhcp/subnet.cc
Normal file
91
src/lib/dhcp/subnet.cc
Normal file
@@ -0,0 +1,91 @@
|
||||
// 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 <dhcp/addr_utilities.h>
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/subnet.h>
|
||||
#include <dhcp/pool.h>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
|
||||
const Triplet<uint32_t>& t1,
|
||||
const Triplet<uint32_t>& t2,
|
||||
const Triplet<uint32_t>& valid_lifetime)
|
||||
:id_(getNextID()), prefix_(prefix), prefix_len_(len), t1_(t1),
|
||||
t2_(t2), valid_(valid_lifetime) {
|
||||
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) const {
|
||||
IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
|
||||
IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
|
||||
|
||||
return ((first <= addr) && (addr <= last));
|
||||
}
|
||||
|
||||
Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
|
||||
const Triplet<uint32_t>& t1,
|
||||
const Triplet<uint32_t>& t2,
|
||||
const Triplet<uint32_t>& preferred_lifetime,
|
||||
const Triplet<uint32_t>& valid_lifetime)
|
||||
:Subnet(prefix, length, t1, t2, valid_lifetime),
|
||||
preferred_(preferred_lifetime){
|
||||
if (prefix.getFamily() != AF_INET6) {
|
||||
isc_throw(BadValue, "Non IPv6 prefix " << prefix.toText()
|
||||
<< " specified in subnet6");
|
||||
}
|
||||
}
|
||||
|
||||
void Subnet6::addPool6(const Pool6Ptr& pool) {
|
||||
IOAddress first_addr = pool->getFirstAddress();
|
||||
IOAddress last_addr = pool->getLastAddress();
|
||||
|
||||
if (!inRange(first_addr) || !inRange(last_addr)) {
|
||||
isc_throw(BadValue, "Pool6 (" << first_addr.toText() << "-" << last_addr.toText()
|
||||
<< " does not belong in this (" << prefix_ << "/" << prefix_len_
|
||||
<< ") subnet6");
|
||||
}
|
||||
|
||||
/// @todo: Check that pools do not overlap
|
||||
|
||||
pools_.push_back(pool);
|
||||
}
|
||||
|
||||
Pool6Ptr Subnet6::getPool6(const isc::asiolink::IOAddress& hint /* = IOAddress("::")*/ ) {
|
||||
Pool6Ptr candidate;
|
||||
for (Pool6Collection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
|
||||
|
||||
// if we won't find anything better, then let's just use the first pool
|
||||
if (!candidate) {
|
||||
candidate = *pool;
|
||||
}
|
||||
|
||||
// if the client provided a pool and there's a pool that hint is valid in,
|
||||
// then let's use that pool
|
||||
if ((*pool)->inRange(hint)) {
|
||||
return (*pool);
|
||||
}
|
||||
}
|
||||
return (candidate);
|
||||
}
|
||||
|
||||
} // end of isc::dhcp namespace
|
||||
} // end of isc namespace
|
161
src/lib/dhcp/subnet.h
Normal file
161
src/lib/dhcp/subnet.h
Normal file
@@ -0,0 +1,161 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SUBNET_H
|
||||
#define SUBNET_H
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/pool.h>
|
||||
#include <dhcp/triplet.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief a base class for Subnet4 and Subnet6
|
||||
///
|
||||
/// This class presents a common base for IPv4 and IPv6 subnets.
|
||||
/// In a physical sense, a subnet defines a single network link with all devices
|
||||
/// attached to it. In most cases all devices attached to a single link can
|
||||
/// share the same parameters. Therefore Subnet holds several values that are
|
||||
/// typically shared by all hosts: renew timer (T1), rebind timer (T2) and
|
||||
/// leased addresses lifetime (valid-lifetime).
|
||||
///
|
||||
/// @todo: Implement support for options here
|
||||
class Subnet {
|
||||
public:
|
||||
/// @brief checks if specified address is in range
|
||||
bool inRange(const isc::asiolink::IOAddress& addr) const;
|
||||
|
||||
/// @brief return valid-lifetime for addresses in that prefix
|
||||
Triplet<uint32_t> getValid() const {
|
||||
return (valid_);
|
||||
}
|
||||
|
||||
/// @brief returns T1 (renew timer), expressed in seconds
|
||||
Triplet<uint32_t> getT1() const {
|
||||
return (t1_);
|
||||
}
|
||||
|
||||
/// @brief returns T2 (rebind timer), expressed in seconds
|
||||
Triplet<uint32_t> getT2() const {
|
||||
return (t2_);
|
||||
}
|
||||
|
||||
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,
|
||||
const Triplet<uint32_t>& t1,
|
||||
const Triplet<uint32_t>& t2,
|
||||
const Triplet<uint32_t>& valid_lifetime);
|
||||
|
||||
/// @brief returns the next unique Subnet-ID
|
||||
///
|
||||
/// @return the next unique Subnet-ID
|
||||
static uint32_t getNextID() {
|
||||
static uint32_t id = 0;
|
||||
return (id++);
|
||||
}
|
||||
|
||||
/// @brief subnet-id
|
||||
///
|
||||
/// Subnet-id is a unique value that can be used to find or identify
|
||||
/// a Subnet4 or Subnet6.
|
||||
uint32_t id_;
|
||||
|
||||
/// @brief a prefix of the subnet
|
||||
isc::asiolink::IOAddress prefix_;
|
||||
|
||||
/// @brief a prefix length of the subnet
|
||||
uint8_t prefix_len_;
|
||||
|
||||
/// @brief a tripet (min/default/max) holding allowed renew timer values
|
||||
Triplet<uint32_t> t1_;
|
||||
|
||||
/// @brief a tripet (min/default/max) holding allowed rebind timer values
|
||||
Triplet<uint32_t> t2_;
|
||||
|
||||
/// @brief a tripet (min/default/max) holding allowed valid lifetime values
|
||||
Triplet<uint32_t> valid_;
|
||||
};
|
||||
|
||||
/// @brief A configuration holder for IPv6 subnet.
|
||||
///
|
||||
/// This class represents an IPv6 subnet.
|
||||
class Subnet6 : public Subnet {
|
||||
public:
|
||||
|
||||
/// @brief Constructor with all parameters
|
||||
///
|
||||
/// @param prefix Subnet6 prefix
|
||||
/// @param length prefix length
|
||||
/// @param t1 renewal timer (in seconds)
|
||||
/// @param t2 rebind timer (in seconds)
|
||||
/// @param preferred_lifetime preferred lifetime of leases (in seconds)
|
||||
/// @param valid_lifetime preferred lifetime of leases (in seconds)
|
||||
Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
|
||||
const Triplet<uint32_t>& t1,
|
||||
const Triplet<uint32_t>& t2,
|
||||
const Triplet<uint32_t>& preferred_lifetime,
|
||||
const Triplet<uint32_t>& valid_lifetime);
|
||||
|
||||
/// @brief Returns preverred lifetime (in seconds)
|
||||
///
|
||||
/// @return a triplet with preferred lifetime
|
||||
Triplet<uint32_t> getPreferred() const {
|
||||
return (preferred_);
|
||||
}
|
||||
|
||||
/// @brief Returns a pool that specified address belongs to
|
||||
///
|
||||
/// @param hint address that the returned pool should cover (optional)
|
||||
/// @return Pointer to found pool6 (or NULL)
|
||||
Pool6Ptr getPool6(const isc::asiolink::IOAddress& hint =
|
||||
isc::asiolink::IOAddress("::"));
|
||||
|
||||
/// @brief Adds a new pool.
|
||||
/// @param pool pool to be added
|
||||
void addPool6(const Pool6Ptr& pool);
|
||||
|
||||
/// @brief returns all pools
|
||||
///
|
||||
/// The reference is only valid as long as the object that
|
||||
/// returned it.
|
||||
///
|
||||
/// @return a collection of all pools
|
||||
const Pool6Collection& getPools() const {
|
||||
return pools_;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// @brief collection of pools in that list
|
||||
Pool6Collection pools_;
|
||||
|
||||
/// @brief a triplet with preferred lifetime (in seconds)
|
||||
Triplet<uint32_t> preferred_;
|
||||
};
|
||||
|
||||
/// @brief A pointer to a Subnet6 object
|
||||
typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
|
||||
|
||||
/// @brief A collection of Subnet6 objects
|
||||
typedef std::vector<Subnet6Ptr> Subnet6Collection;
|
||||
|
||||
} // end of isc::dhcp namespace
|
||||
} // end of isc namespace
|
||||
|
||||
#endif // SUBNET_T
|
@@ -24,7 +24,7 @@ TESTS_ENVIRONMENT = \
|
||||
|
||||
TESTS =
|
||||
if HAVE_GTEST
|
||||
TESTS += libdhcp++_unittests
|
||||
TESTS += libdhcp++_unittests libdhcpsrv_unittests
|
||||
libdhcp___unittests_SOURCES = run_unittests.cc
|
||||
libdhcp___unittests_SOURCES += libdhcp++_unittest.cc
|
||||
libdhcp___unittests_SOURCES += iface_mgr_unittest.cc
|
||||
@@ -38,20 +38,37 @@ libdhcp___unittests_SOURCES += pkt4_unittest.cc
|
||||
|
||||
libdhcp___unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
|
||||
libdhcp___unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
||||
|
||||
libdhcp___unittests_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
|
||||
libdhcpsrv_unittests_SOURCES = run_unittests.cc
|
||||
libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc triplet_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += pool_unittest.cc subnet_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
|
||||
|
||||
libdhcpsrv_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
|
||||
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
|
||||
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
|
||||
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
|
||||
|
||||
|
||||
if USE_CLANGPP
|
||||
# This is to workaround unused variables tcout and tcerr in
|
||||
# log4cplus's streams.h and unused parameters from some of the
|
||||
# Boost headers.
|
||||
libdhcp___unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
|
||||
libdhcpsrv_unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
|
||||
endif
|
||||
|
||||
libdhcp___unittests_LDADD = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
|
||||
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
|
||||
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
|
||||
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
|
||||
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
|
||||
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
|
||||
libdhcp___unittests_LDADD += $(GTEST_LDADD)
|
||||
endif
|
||||
|
||||
|
93
src/lib/dhcp/tests/addr_utilities_unittest.cc
Normal file
93
src/lib/dhcp/tests/addr_utilities_unittest.cc
Normal file
@@ -0,0 +1,93 @@
|
||||
|
||||
// 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 <dhcp/addr_utilities.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::dhcp;
|
||||
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());
|
||||
|
||||
// Let's check extreme cases
|
||||
IOAddress anyAddr("::");
|
||||
EXPECT_EQ("7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
|
||||
lastAddrInPrefix(anyAddr, 1).toText());
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
|
||||
lastAddrInPrefix(anyAddr, 0).toText());
|
||||
EXPECT_EQ("::", lastAddrInPrefix(anyAddr, 128).toText());
|
||||
}
|
||||
|
||||
TEST(Pool6Test, firstAddrInPrefix) {
|
||||
IOAddress addr1("2001:db8:1:1234:5678:1234:abcd:beef");
|
||||
|
||||
// Prefixes rounded to nibbles are easy...
|
||||
EXPECT_EQ("2001:db8:1:1234:5678:1234::",
|
||||
firstAddrInPrefix(addr1, 96).toText());
|
||||
EXPECT_EQ("2001:db8:1:1234:5678:1230::",
|
||||
firstAddrInPrefix(addr1, 92).toText());
|
||||
EXPECT_EQ("2001:db8:1:1234:5678:1200::",
|
||||
firstAddrInPrefix(addr1, 88).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());
|
||||
}
|
63
src/lib/dhcp/tests/cfgmgr_unittest.cc
Normal file
63
src/lib/dhcp/tests/cfgmgr_unittest.cc
Normal file
@@ -0,0 +1,63 @@
|
||||
// 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 <config.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <arpa/inet.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <dhcp/cfgmgr.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::util;
|
||||
using namespace isc;
|
||||
|
||||
// don't import the entire boost namespace. It will unexpectedly hide uint8_t
|
||||
// for some systems.
|
||||
using boost::scoped_ptr;
|
||||
|
||||
namespace {
|
||||
|
||||
// This test verifies if the configuration manager is able to hold and return
|
||||
// valid leases
|
||||
TEST(CfgMgrTest, subnet6) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
|
||||
ASSERT_TRUE(&cfg_mgr != 0);
|
||||
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
|
||||
|
||||
// there shouldn't be any subnet configured at this stage
|
||||
EXPECT_EQ( Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("2000::1")));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet1);
|
||||
|
||||
// Now we have only one subnet, any request will be served from it
|
||||
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2001:db8::1")));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet2);
|
||||
cfg_mgr.addSubnet6(subnet3);
|
||||
|
||||
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123")));
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef")));
|
||||
EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("5000::1")));
|
||||
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
109
src/lib/dhcp/tests/pool_unittest.cc
Normal file
109
src/lib/dhcp/tests/pool_unittest.cc
Normal file
@@ -0,0 +1,109 @@
|
||||
// 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 <config.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <gtest/gtest.h>
|
||||
#include <dhcp/pool.h>
|
||||
#include <asiolink/io_address.h>
|
||||
|
||||
using boost::scoped_ptr;
|
||||
using namespace isc;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::asiolink;
|
||||
|
||||
namespace {
|
||||
|
||||
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"));
|
||||
|
||||
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());
|
||||
|
||||
// This is Pool6, IPv4 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 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")), BadValue);
|
||||
}
|
||||
|
||||
TEST(Pool6Test, constructor_prefix_len) {
|
||||
|
||||
// let's construct 2001:db8:1::/96 pool
|
||||
Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"), 96);
|
||||
|
||||
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());
|
||||
|
||||
// No such thing as /130 prefix
|
||||
EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 130),
|
||||
BadValue);
|
||||
|
||||
// /0 prefix does not make sense
|
||||
EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 0),
|
||||
BadValue);
|
||||
|
||||
// This is Pool6, IPv4 addresses do not belong here
|
||||
EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"), 96),
|
||||
BadValue);
|
||||
}
|
||||
|
||||
TEST(Pool6Test, in_range) {
|
||||
Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::1"),
|
||||
IOAddress("2001:db8:1::f"));
|
||||
|
||||
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;
|
||||
std::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"))));
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}; // end of anonymous namespace
|
||||
|
@@ -13,7 +13,6 @@
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <log/logger_support.h>
|
||||
|
||||
int
|
||||
|
112
src/lib/dhcp/tests/subnet_unittest.cc
Normal file
112
src/lib/dhcp/tests/subnet_unittest.cc
Normal file
@@ -0,0 +1,112 @@
|
||||
// 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 <config.h>
|
||||
#include <dhcp/subnet.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <asiolink/io_address.h>
|
||||
|
||||
// don't import the entire boost namespace. It will unexpectedly hide uint8_t
|
||||
// for some systems.
|
||||
using boost::scoped_ptr;
|
||||
using namespace isc;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::asiolink;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(Subnet6Test, constructor) {
|
||||
|
||||
EXPECT_NO_THROW(Subnet6 subnet1(IOAddress("2001:db8:1::"), 64,
|
||||
1, 2, 3, 4));
|
||||
|
||||
EXPECT_THROW(Subnet6 subnet2(IOAddress("2001:db8:1::"), 129, 1, 2, 3, 4),
|
||||
BadValue); // invalid prefix length
|
||||
EXPECT_THROW(Subnet6 subnet3(IOAddress("192.168.0.0"), 32, 1, 2, 3, 4),
|
||||
BadValue); // IPv4 addresses are not allowed in Subnet6
|
||||
}
|
||||
|
||||
TEST(Subnet6Test, in_range) {
|
||||
Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);
|
||||
|
||||
EXPECT_EQ(1000, subnet.getT1());
|
||||
EXPECT_EQ(2000, subnet.getT2());
|
||||
EXPECT_EQ(3000, subnet.getPreferred());
|
||||
EXPECT_EQ(4000, subnet.getValid());
|
||||
|
||||
|
||||
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("::")));
|
||||
}
|
||||
|
||||
TEST(Subnet6Test, Pool6InSubnet6) {
|
||||
|
||||
Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
|
||||
|
||||
Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
|
||||
Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:2::"), 64));
|
||||
Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:3::"), 64));
|
||||
|
||||
subnet->addPool6(pool1);
|
||||
|
||||
// If there's only one pool, get that pool
|
||||
Pool6Ptr mypool = subnet->getPool6();
|
||||
EXPECT_EQ(mypool, pool1);
|
||||
|
||||
|
||||
subnet->addPool6(pool2);
|
||||
subnet->addPool6(pool3);
|
||||
|
||||
// If there are more than one pool and we didn't provide hint, we
|
||||
// should get the first pool
|
||||
mypool = subnet->getPool6();
|
||||
|
||||
EXPECT_EQ(mypool, pool1);
|
||||
|
||||
// If we provide a hint, we should get a pool that this hint belongs to
|
||||
mypool = subnet->getPool6(IOAddress("2001:db8:1:3::dead:beef"));
|
||||
|
||||
EXPECT_EQ(mypool, pool3);
|
||||
|
||||
}
|
||||
|
||||
TEST(Subnet6Test, Subnet6_Pool6_checks) {
|
||||
|
||||
Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
|
||||
|
||||
// this one is in subnet
|
||||
Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
|
||||
subnet->addPool6(pool1);
|
||||
|
||||
// this one is larger than the subnet!
|
||||
Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 48));
|
||||
|
||||
EXPECT_THROW(subnet->addPool6(pool2), BadValue);
|
||||
|
||||
|
||||
// this one is totally out of blue
|
||||
Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("3000::"), 16));
|
||||
EXPECT_THROW(subnet->addPool6(pool3), BadValue);
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
104
src/lib/dhcp/tests/triplet_unittest.cc
Normal file
104
src/lib/dhcp/tests/triplet_unittest.cc
Normal file
@@ -0,0 +1,104 @@
|
||||
// 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 <config.h>
|
||||
#include <stdint.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <dhcp/triplet.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc;
|
||||
|
||||
namespace {
|
||||
|
||||
// constructor validation
|
||||
TEST(TripletTest, constructor) {
|
||||
|
||||
const uint32_t min = 10;
|
||||
const uint32_t value = 20;
|
||||
const uint32_t max = 30;
|
||||
|
||||
Triplet<uint32_t> x(min, value, max);
|
||||
|
||||
EXPECT_EQ(min, x.getMin());
|
||||
EXPECT_EQ(value, x.get());
|
||||
EXPECT_EQ(max, x.getMax());
|
||||
|
||||
// requested values below min should return allowed min value
|
||||
EXPECT_EQ(min, x.get(min - 5));
|
||||
|
||||
EXPECT_EQ(min, x.get(min));
|
||||
|
||||
// requesting a value from within the range (min < x < max) should
|
||||
// return the requested value
|
||||
EXPECT_EQ(17, x.get(17));
|
||||
|
||||
EXPECT_EQ(max, x.get(max));
|
||||
|
||||
EXPECT_EQ(max, x.get(max + 5));
|
||||
|
||||
// this will be boring. It is expected to return 42 no matter what
|
||||
Triplet<uint32_t> y(42);
|
||||
|
||||
EXPECT_EQ(42, y.getMin()); // min, default and max are equal to 42
|
||||
EXPECT_EQ(42, y.get()); // it returns ...
|
||||
EXPECT_EQ(42, y.getMax()); // the exact value...
|
||||
|
||||
// requested values below or above are ignore
|
||||
EXPECT_EQ(42, y.get(5)); // all...
|
||||
EXPECT_EQ(42, y.get(42)); // the...
|
||||
EXPECT_EQ(42, y.get(80)); // time!
|
||||
}
|
||||
|
||||
// Triplets must be easy to use.
|
||||
// Simple to/from int conversions must be done on the fly.
|
||||
TEST(TripletTest, operator) {
|
||||
|
||||
uint32_t x = 47;
|
||||
|
||||
Triplet<uint32_t> foo(1,2,3);
|
||||
Triplet<uint32_t> bar(4,5,6);
|
||||
|
||||
foo = bar;
|
||||
|
||||
EXPECT_EQ(4, foo.getMin());
|
||||
EXPECT_EQ(5, foo.get());
|
||||
EXPECT_EQ(6, foo.getMax());
|
||||
|
||||
// assignment operator: uint32_t => triplet
|
||||
Triplet<uint32_t> y(0);
|
||||
y = x;
|
||||
|
||||
EXPECT_EQ(x, y.get());
|
||||
|
||||
// let's try the other way around: triplet => uint32_t
|
||||
uint32_t z = 0;
|
||||
z = y;
|
||||
|
||||
EXPECT_EQ(x, z);
|
||||
}
|
||||
|
||||
// check if specified values are sane
|
||||
TEST(TripletTest, sanity_check) {
|
||||
|
||||
// min is larger than default
|
||||
EXPECT_THROW(Triplet<uint32_t>(6,5,5), BadValue);
|
||||
|
||||
// max is smaller than default
|
||||
EXPECT_THROW(Triplet<uint32_t>(5,5,4), BadValue);
|
||||
|
||||
}
|
||||
|
||||
}; // end of anonymous namespace
|
110
src/lib/dhcp/triplet.h
Normal file
110
src/lib/dhcp/triplet.h
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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 <exceptions/exceptions.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief this template specifies a parameter value
|
||||
///
|
||||
/// This template class is used to store configuration parameters, like lifetime or T1.
|
||||
/// It defines 3 parameters: min, default, and max value. There are 2 constructors:
|
||||
/// - simple (just one value that sets all parameters)
|
||||
/// - extended (that sets default value and two thresholds)
|
||||
/// It will be used with integer types. It provides necessary operators, so
|
||||
/// it can be assigned to a plain integer or integer assigned to a Triplet.
|
||||
/// See TripletTest.operator test for details on an easy Triplet usage.
|
||||
template <class T>
|
||||
class Triplet {
|
||||
public:
|
||||
|
||||
/// @brief base type to Triple conversion
|
||||
///
|
||||
/// Typically: uint32_t to Triplet assignment. It is very convenient
|
||||
/// to be able to simply write Triplet<uint32_t> x = 7;
|
||||
Triplet<T> operator=(T other) {
|
||||
min_ = other;
|
||||
default_ = other;
|
||||
max_ = other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief triplet to base type conversion
|
||||
///
|
||||
/// Typically: Triplet to uint32_t assignment. It is very convenient
|
||||
/// to be able to simply write uint32_t z = x; (where x is a Triplet)
|
||||
operator T() const {
|
||||
return (default_);
|
||||
}
|
||||
|
||||
/// @brief sets a fixed value
|
||||
///
|
||||
/// This constructor assigns a fixed (i.e. no range, just a single value)
|
||||
/// value.
|
||||
Triplet(T value)
|
||||
:min_(value), default_(value), max_(value) {
|
||||
}
|
||||
|
||||
/// @brief sets the default value and thresholds
|
||||
///
|
||||
/// @throw BadValue if min <= def <= max rule is violated
|
||||
Triplet(T min, T def, T max)
|
||||
:min_(min), default_(def), max_(max) {
|
||||
if ( (min_ > def) || (def > max_) ) {
|
||||
isc_throw(BadValue, "Invalid triplet values.");
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief returns a minimum allowed value
|
||||
T getMin() const { return min_;}
|
||||
|
||||
/// @brief returns the default value
|
||||
T get() const { return default_;}
|
||||
|
||||
/// @brief returns value with a hint
|
||||
///
|
||||
/// DHCP protocol treats any values sent by a client as hints.
|
||||
/// This is a method that implements that. We can assign any value
|
||||
/// from configured range that client asks.
|
||||
T get(T hint) const {
|
||||
if (hint <= min_) {
|
||||
return (min_);
|
||||
}
|
||||
|
||||
if (hint >= max_) {
|
||||
return (max_);
|
||||
}
|
||||
|
||||
return (hint);
|
||||
}
|
||||
|
||||
/// @brief returns a maximum allowed value
|
||||
T getMax() const { return max_; }
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief the minimum value
|
||||
T min_;
|
||||
|
||||
/// @brief the default value
|
||||
T default_;
|
||||
|
||||
/// @brief the maximum value
|
||||
T max_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace isc::dhcp
|
||||
} // namespace isc
|
Reference in New Issue
Block a user