Commit 835553eb authored by Mukund Sivaraman's avatar Mukund Sivaraman
Browse files

Merge branch 'master' into trac2504

parents a6b558c0 cb4d9b01
518. [func] stephen
Extend DHCP MySQL backend to handle IPv4 addresses.
(Trac #2404, git ce7db48d3ff5d5aad12b1da5e67ae60073cb2607)
517. [func] stephen
Added IOAddress::toBytes() to get byte representation of address.
Also added convenience methods for V4/V6 address determination.
(Trac #2396, git c23f87e8ac3ea781b38d688f8f7b58539f85e35a)
516. [bug] marcin
Fixed 'make distcheck' failure when running perfdhcp unit tests.
The unit tests used to read files from the folder specified
with the path relative to current folder, thus when the test was
run from a different folder the files could not be found.
(Trac #2479, git 4e8325e1b309f1d388a3055ec1e1df98c377f383)
515. [bug] jinmei
The in-memory data source now accepts an RRSIG provided without
a covered RRset in loading. A subsequent query for its owner name
......
......@@ -1308,7 +1308,7 @@ AC_CONFIG_FILES([Makefile
tests/tools/badpacket/tests/Makefile
tests/tools/perfdhcp/Makefile
tests/tools/perfdhcp/tests/Makefile
tests/tools/perfdhcp/templates/Makefile
tests/tools/perfdhcp/tests/testdata/Makefile
dns++.pc
])
AC_OUTPUT([doc/version.ent
......
......@@ -580,8 +580,8 @@ INPUT = ../src/lib/exceptions ../src/lib/cc \
../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
../src/bin/sockcreator/ ../src/lib/util/ ../src/lib/util/io/ \
../src/lib/util/threads/ ../src/lib/resolve ../src/lib/acl \
../src/lib/statistics ../src/bin/dhcp6 ../src/lib/dhcp ../src/bin/dhcp4 \
../tests/tools/perfdhcp devel
../src/lib/statistics ../src/bin/dhcp6 ../src/lib/dhcp ../src/lib/dhcpsrv \
../src/bin/dhcp4 ../tests/tools/perfdhcp devel
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
......
......@@ -472,7 +472,7 @@ var/
<title>Packages</title>
<para>
Some operating systems or softare package vendors may
Some operating systems or software package vendors may
provide ready-to-use, pre-built software packages for
the BIND 10 suite.
Installing a pre-built package means you do not need to
......@@ -2157,7 +2157,7 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
you indicate that the system is not usable without the
component and if such component fails, the system shuts
down no matter when the failure happened. This is the
behaviour of the core components (the ones you can't turn
behavior of the core components (the ones you can't turn
off), but you can declare any other components as core as
well if you wish (but you can turn these off, they just
can't fail).
......
......@@ -225,7 +225,7 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
message.setHeaderFlag(Message::HEADERFLAG_AA);
RRsetPtr rrset_version = RRsetPtr(new RRset(version_name, RRClass::CH(),
RRType::TXT(), RRTTL(0)));
rrset_version->addRdata(generic::TXT(PACKAGE_STRING));
rrset_version->addRdata(generic::TXT("\"" PACKAGE_STRING "\""));
message.addRRset(Message::SECTION_ANSWER, rrset_version);
RRsetPtr rrset_version_ns = RRsetPtr(new RRset(apex_name, RRClass::CH(),
......
......@@ -193,7 +193,8 @@ class ZonemgrRefresh:
def zone_handle_notify(self, zone_name_class, master):
"""Handle zone notify"""
if (self._zone_not_exist(zone_name_class)):
logger.error(ZONEMGR_UNKNOWN_ZONE_NOTIFIED, zone_name_class[0], zone_name_class[1])
logger.error(ZONEMGR_UNKNOWN_ZONE_NOTIFIED, zone_name_class[0],
zone_name_class[1], master)
raise ZonemgrException("[b10-zonemgr] Notified zone (%s, %s) "
"doesn't belong to zonemgr" % zone_name_class)
self._set_zone_notifier_master(zone_name_class, master)
......
......@@ -138,7 +138,7 @@ zone, or, if this error appears without the administrator giving transfer
commands, it can indicate an error in the program, as it should not have
initiated transfers of unknown zones on its own.
% ZONEMGR_UNKNOWN_ZONE_NOTIFIED notified zone %1 (class %2) is not known to the zone manager
% ZONEMGR_UNKNOWN_ZONE_NOTIFIED notified zone %1/%2 from %3 is not known to the zone manager
A NOTIFY was received but the zone that was the subject of the operation
is not being managed by the zone manager. This may indicate an error
in the program (as the operation should not have been initiated if this
......
......@@ -76,6 +76,21 @@ IOAddress::fromBytes(short family, const uint8_t* data) {
return IOAddress(string(addr_str));
}
std::vector<uint8_t>
IOAddress::toBytes() const {
if (asio_address_.is_v4()) {
const asio::ip::address_v4::bytes_type bytes4 =
asio_address_.to_v4().to_bytes();
return (std::vector<uint8_t>(bytes4.begin(), bytes4.end()));
}
// Not V4 address, so must be a V6 address (else we could never construct
// this object).
const asio::ip::address_v6::bytes_type bytes6 =
asio_address_.to_v6().to_bytes();
return (std::vector<uint8_t>(bytes6.begin(), bytes6.end()));
}
short
IOAddress::getFamily() const {
if (asio_address_.is_v4()) {
......
......@@ -24,6 +24,7 @@
#include <functional>
#include <string>
#include <vector>
#include <exceptions/exceptions.h>
......@@ -103,6 +104,19 @@ public:
/// \return AF_INET for IPv4 or AF_INET6 for IPv6.
short getFamily() const;
/// \brief Convenience function to check for an IPv4 address
///
/// \return true if the address is a V4 address
bool isV4() const {
return (asio_address_.is_v4());
}
/// \brief Convenience function to check for an IPv6 address
///
/// \return true if the address is a V6 address
bool isV6() const {
return (asio_address_.is_v6());
}
/// \brief Creates an address from over wire data.
///
......@@ -110,8 +124,13 @@ public:
/// \param data pointer to first char of data
///
/// \return Created IOAddress object
static IOAddress
fromBytes(short family, const uint8_t* data);
static IOAddress fromBytes(short family, const uint8_t* data);
/// \brief Return address as set of bytes
///
/// \return Contents of the address as a set of bytes in network-byte
/// order.
std::vector<uint8_t> toBytes() const;
/// \brief Compare addresses for equality
///
......
......@@ -18,7 +18,9 @@
#include <asiolink/io_error.h>
#include <asiolink/io_address.h>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace isc::asiolink;
......@@ -84,6 +86,45 @@ TEST(IOAddressTest, fromBytes) {
EXPECT_EQ(addr.toText(), IOAddress("192.0.2.3").toText());
}
TEST(IOAddressTest, toBytesV4) {
// Address and network byte-order representation of the address.
const char* V4STRING = "192.0.2.1";
uint8_t V4[] = {0xc0, 0x00, 0x02, 0x01};
std::vector<uint8_t> actual = IOAddress(V4STRING).toBytes();
ASSERT_EQ(sizeof(V4), actual.size());
EXPECT_TRUE(std::equal(actual.begin(), actual.end(), V4));
}
TEST(IOAddressTest, toBytesV6) {
// Address and network byte-order representation of the address.
const char* V6STRING = "2001:db8:1::dead:beef";
uint8_t V6[] = {
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef
};
std::vector<uint8_t> actual = IOAddress(V6STRING).toBytes();
ASSERT_EQ(sizeof(V6), actual.size());
EXPECT_TRUE(std::equal(actual.begin(), actual.end(), V6));
}
TEST(IOAddressTest, isV4) {
const IOAddress address4("192.0.2.1");
const IOAddress address6("2001:db8:1::dead:beef");
EXPECT_TRUE(address4.isV4());
EXPECT_FALSE(address6.isV4());
}
TEST(IOAddressTest, isV6) {
const IOAddress address4("192.0.2.1");
const IOAddress address6("2001:db8:1::dead:beef");
EXPECT_FALSE(address4.isV6());
EXPECT_TRUE(address6.isV6());
}
TEST(IOAddressTest, uint32) {
IOAddress addr1("192.0.2.5");
......
......@@ -40,7 +40,7 @@ libb10_dhcp___la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
libb10_dhcp___la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
libb10_dhcp___la_LDFLAGS = -no-undefined -version-info 2:0:0
EXTRA_DIST = README
EXTRA_DIST = README libdhcp++.dox
if USE_CLANGPP
# Disable unused parameter warning caused by some of the
......
......@@ -33,7 +33,7 @@ DUID::DUID(const std::vector<uint8_t>& duid) {
}
}
DUID::DUID(const uint8_t * data, size_t len) {
DUID::DUID(const uint8_t* data, size_t len) {
if (len > MAX_DUID_LEN) {
isc_throw(OutOfRange, "DUID too large");
}
......@@ -72,36 +72,36 @@ std::string DUID::toText() const {
return (tmp.str());
}
bool DUID::operator == (const DUID& other) const {
bool DUID::operator==(const DUID& other) const {
return (this->duid_ == other.duid_);
}
bool DUID::operator != (const DUID& other) const {
bool DUID::operator!=(const DUID& other) const {
return (this->duid_ != other.duid_);
}
/// constructor based on vector<uint8_t>
// Constructor based on vector<uint8_t>
ClientId::ClientId(const std::vector<uint8_t>& clientid)
:DUID(clientid) {
: DUID(clientid) {
}
/// constructor based on C-style data
// Constructor based on C-style data
ClientId::ClientId(const uint8_t *clientid, size_t len)
:DUID(clientid, len) {
: DUID(clientid, len) {
}
/// @brief returns a copy of client-id data
// Returns a copy of client-id data
const std::vector<uint8_t> ClientId::getClientId() const {
return (duid_);
}
// compares two client-ids
bool ClientId::operator == (const ClientId& other) const {
// Compares two client-ids
bool ClientId::operator==(const ClientId& other) const {
return (this->duid_ == other.duid_);
}
// compares two client-ids
bool ClientId::operator != (const ClientId& other) const {
// Compares two client-ids
bool ClientId::operator!=(const ClientId& other) const {
return (this->duid_ != other.duid_);
}
......
......@@ -45,13 +45,13 @@ class DUID {
DUID_MAX ///< not a real type, just maximum defined value + 1
} DUIDType;
/// @brief creates a DUID
/// @brief Constructor from vector
DUID(const std::vector<uint8_t>& duid);
/// @brief creates a DUID
DUID(const uint8_t *duid, size_t len);
/// @brief Constructor from array and array size
DUID(const uint8_t* duid, size_t len);
/// @brief returns a const reference to the actual DUID value
/// @brief Returns a const reference to the actual DUID value
///
/// Note: For safety reasons, this method returns a copy of data as
/// otherwise the reference would be only valid as long as the object that
......@@ -60,47 +60,58 @@ class DUID {
/// (e.g. storeSelf()) that will avoid data copying.
const std::vector<uint8_t> getDuid() const;
/// @brief returns DUID type
/// @brief Returns the DUID type
DUIDType getType() const;
/// returns textual prepresentation (e.g. 00:01:02:03:ff)
/// @brief Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
std::string toText() const;
/// compares two DUIDs
/// @brief Compares two DUIDs for equality
bool operator==(const DUID& other) const;
/// compares two DUIDs
/// @brief Compares two DUIDs for inequality
bool operator!=(const DUID& other) const;
protected:
/// the actual content of the DUID
/// The actual content of the DUID
std::vector<uint8_t> duid_;
};
/// @brief Shared pointer to a DUID
typedef boost::shared_ptr<DUID> DuidPtr;
/// @brief Holds Client identifier or client IPv4 address
///
/// This class is intended to be a generic IPv4 client identifier. It can hold
/// a client-id
class ClientId : DUID {
public:
public:
/// @brief Maximum size of a client ID
///
/// This is the same as the maximum size of the underlying DUID.
///
/// @note RFC 2131 does not specify an upper length of a client ID, the
/// value chosen here just being that of the underlying DUID. For
/// some backend database, there may be a possible (minor)
/// performance enhancement if this were smaller.
static const size_t MAX_CLIENT_ID_LEN = DUID::MAX_DUID_LEN;
/// constructor based on vector<uint8_t>
/// @brief Constructor based on vector<uint8_t>
ClientId(const std::vector<uint8_t>& clientid);
/// constructor based on C-style data
ClientId(const uint8_t *clientid, size_t len);
/// @brief Constructor based on array and array size
ClientId(const uint8_t* clientid, size_t len);
/// @brief returns reference to the client-id data
///
/// @brief Returns reference to the client-id data
const std::vector<uint8_t> getClientId() const;
// compares two client-ids
bool operator == (const ClientId& other) const;
/// @brief Compares two client-ids for equality
bool operator==(const ClientId& other) const;
// compares two client-ids
bool operator != (const ClientId& other) const;
/// @brief Compares two client-ids for inequality
bool operator!=(const ClientId& other) const;
};
}; // end of isc::dhcp namespace
......
......@@ -48,5 +48,5 @@ libb10_dhcpsrv_la_CXXFLAGS += -Wno-unused-parameter
endif
# Distribute MySQL schema creation script and backend documentation
EXTRA_DIST = dhcpdb_create.mysql database_backends.dox
EXTRA_DIST = dhcpdb_create.mysql database_backends.dox libdhcpsrv.dox
dist_pkgdata_DATA = dhcpdb_create.mysql
......@@ -8,6 +8,17 @@
the abstract isc::dhcp::LeaseMgr class. This provides methods to
create, retrieve, modify and delete leases in the database.
There are currently two available Lease Managers, MySQL and Memfile:
- The MySQL lease manager uses the freely available MySQL as its backend
database. This is not included in BIND 10 DHCP by default:
the --with-dhcp-mysql switch must be supplied to "configure" for support
to be compiled into the software.
- Memfile is an in-memory lease database, with (currently) nothing being
written to persistent storage. The long-term plans for the backend do
include the ability to store this on disk, but it is currently a
low-priority item.
@section dhcpdb-instantiation Instantiation of Lease Managers
A lease manager is instantiated through the LeaseMgrFactory class. This
......@@ -32,6 +43,8 @@
- <b>type</b> - specifies the type of database backend. The following values
for the type keyword are supported:
- <B>memfile</b> - In-memory database. Nothing is written to any
external storage, so this should not be used in production.
- <b>mysql</b> - Use MySQL as the database
The following sections list the database-specific keywords:
......
......@@ -34,7 +34,7 @@ CREATE TABLE lease4 (
address INT UNSIGNED PRIMARY KEY NOT NULL, # IPv4 address
hwaddr VARBINARY(20), # Hardware address
client_id VARBINARY(128), # Client ID
lease_time INT UNSIGNED, # Length of the lease (seconds)
valid_lifetime INT UNSIGNED, # Length of the lease (seconds)
expire TIMESTAMP, # Expiration time of the lease
subnet_id INT UNSIGNED # Subnet identification
) ENGINE = INNODB;
......@@ -43,7 +43,7 @@ CREATE TABLE lease4 (
# N.B. The use of a VARCHAR for the address is temporary for development:
# it will eventually be replaced by BINARY(16).
CREATE TABLE lease6 (
address VARCHAR(40) PRIMARY KEY NOT NULL, # IPv6 address
address VARCHAR(39) PRIMARY KEY NOT NULL, # IPv6 address
duid VARBINARY(128), # DUID
valid_lifetime INT UNSIGNED, # Length of the lease (seconds)
expire TIMESTAMP, # Expiration time of the lease
......@@ -72,12 +72,17 @@ COMMIT;
# This table is only modified during schema upgrades. For historical reasons
# (related to the names of the columns in the BIND 10 DNS database file), the
# first column is called "version" and not "major".
#
# NOTE: this MUST be kept in step with src/lib/dhcpsrv/tests/schema_copy.h,
# which defines the schema for the unit tests. If you are updating
# the version number, the schema has changed: please ensure that
# schema_copy.h has been updated as well.
CREATE TABLE schema_version (
version INT PRIMARY KEY NOT NULL, # Major version number
minor INT # Minor version number
);
START TRANSACTION;
INSERT INTO schema_version VALUES (0, 1);
INSERT INTO schema_version VALUES (1, 0);
COMMIT;
# Notes:
......
......@@ -29,15 +29,16 @@
using namespace std;
using namespace isc::dhcp;
namespace isc {
namespace dhcp {
Lease6::Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
uint32_t t2, SubnetID subnet_id, uint8_t prefixlen)
:type_(type), addr_(addr), prefixlen_(prefixlen), iaid_(iaid), duid_(duid),
preferred_lft_(preferred), valid_lft_(valid), t1_(t1), t2_(t2),
subnet_id_(subnet_id), fixed_(false), fqdn_fwd_(false),
fqdn_rev_(false) {
Lease6::Lease6(LeaseType type, const isc::asiolink::IOAddress& addr,
DuidPtr duid, uint32_t iaid, uint32_t preferred, uint32_t valid,
uint32_t t1, uint32_t t2, SubnetID subnet_id, uint8_t prefixlen)
: addr_(addr), type_(type), prefixlen_(prefixlen), iaid_(iaid), duid_(duid),
preferred_lft_(preferred), valid_lft_(valid), t1_(t1), t2_(t2),
subnet_id_(subnet_id), fixed_(false), fqdn_fwd_(false),
fqdn_rev_(false) {
if (!duid) {
isc_throw(InvalidOperation, "DUID must be specified for a lease");
}
......@@ -82,17 +83,47 @@ Lease6::toText() {
return (stream.str());
}
bool
Lease4::operator==(const Lease4& other) const {
return (
addr_ == other.addr_ &&
ext_ == other.ext_ &&
hwaddr_ == other.hwaddr_ &&
*client_id_ == *other.client_id_ &&
t1_ == other.t1_ &&
t2_ == other.t2_ &&
valid_lft_ == other.valid_lft_ &&
cltt_ == other.cltt_ &&
subnet_id_ == other.subnet_id_ &&
fixed_ == other.fixed_ &&
hostname_ == other.hostname_ &&
fqdn_fwd_ == other.fqdn_fwd_ &&
fqdn_rev_ == other.fqdn_rev_ &&
comments_ == other.comments_
);
}
bool
Lease6::operator==(const Lease6& other) const {
return (
type_ == other.type_ &&
addr_ == other.addr_ &&
type_ == other.type_ &&
prefixlen_ == other.prefixlen_ &&
iaid_ == other.iaid_ &&
*duid_ == *other.duid_ &&
preferred_lft_ == other.preferred_lft_ &&
valid_lft_ == other.valid_lft_ &&
t1_ == other.t1_ &&
t2_ == other.t2_ &&
cltt_ == other.cltt_ &&
subnet_id_ == other.subnet_id_
);
subnet_id_ == other.subnet_id_ &&
fixed_ == other.fixed_ &&
hostname_ == other.hostname_ &&
fqdn_fwd_ == other.fqdn_fwd_ &&
fqdn_rev_ == other.fqdn_rev_ &&
comments_ == other.comments_
);
}
} // namespace isc::dhcp
} // namespace isc
......@@ -87,6 +87,13 @@ public:
isc::Exception(file, line, what) {}
};
/// @brief Multiple lease records found where one expected
class MultipleRecords : public Exception {
public:
MultipleRecords(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Attempt to update lease that was not there
class NoSuchLease : public Exception {
public:
......@@ -94,6 +101,13 @@ public:
isc::Exception(file, line, what) {}
};
/// @brief Data is truncated
class DataTruncated : public Exception {
public:
DataTruncated(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Structure that holds a lease for IPv4 address
///
/// For performance reasons it is a simple structure, not a class. If we chose
......@@ -101,191 +115,253 @@ public:
/// would be required. As this is a critical part of the code that will be used
/// extensively, direct access is warranted.
struct Lease4 {
/// @brief Maximum size of a hardware address
static const size_t HWADDR_MAX = 20;
/// @brief Constructor
///
/// @param addr IPv4 address as unsigned 32-bit integer in network byte
/// order.
/// @param hwaddr Hardware address buffer
/// @param hwaddr_len Length of hardware address buffer
/// @param clientid Client identification buffer
/// @param clientid_len Length of client identification buffer
/// @param valid_lft Lifetime of the lease
/// @param cltt Client last transmission time
/// @param subnet_id Subnet identification
Lease4(uint32_t addr, const uint8_t* hwaddr, size_t hwaddr_len,
const uint8_t* clientid, size_t clientid_len, uint32_t valid_lft,
time_t cltt, uint32_t subnet_id)
: addr_(addr), ext_(0), hwaddr_(hwaddr, hwaddr + hwaddr_len),
client_id_(new ClientId(clientid, clientid_len)), t1_(0), t2_(0),
valid_lft_(valid_lft), cltt_(cltt), subnet_id_(subnet_id),
fixed_(false), hostname_(), fqdn_fwd_(false), fqdn_rev_(false),
comments_()
{}
/// @brief Default Constructor
///
/// Initialize fields that don't have a default constructor.
Lease4() : addr_(0) {}
/// IPv4 address
isc::asiolink::IOAddress addr_;
/// @brief Address extension
///
/// It is envisaged that in some cases IPv4 address will be accompanied with some
/// additional data. One example of such use are Address + Port solutions (or
/// Port-restricted Addresses), where several clients may get the same address, but
/// different port ranges. This feature is not expected to be widely used.
/// Under normal circumstances, the value should be 0.
/// It is envisaged that in some cases IPv4 address will be accompanied
/// with some additional data. One example of such use are Address + Port
/// solutions (or Port-restricted Addresses), where several clients may get
/// the same address, but different port ranges. This feature is not
/// expected to be widely used. Under normal circumstances, the value
/// should be 0.
uint32_t ext_;
/// @brief hardware address
/// @brief Hardware address
std::vector<uint8_t> hwaddr_;
/// @brief client identifier
/// @brief Client identifier
///
/// @todo Should this be a pointer to a client ID or the ID itself?
/// Compare with the DUID in the Lease6 structure.
boost::shared_ptr<ClientId> client_id_;
/// @brief renewal timer
/// @brief Renewal timer
///
/// Specifies renewal time. Although technically it is a property of IA container,
/// not the address itself, since our data model does not define separate IA
/// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
/// for the same IA, each must have consistent T1 and T2 values. Specified in