Commit 09e6e71a authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[master] Merge branch 'trac3360'

Conflicts:
	doc/guide/bind10-guide.xml
parents 67d67f42 d78c0095
......@@ -3836,10 +3836,44 @@ Dhcp4/dhcp-ddns/qualifying-suffix "example.com" string
</para>
<section>
<title>Default storage for leases</title>
<para>
The server is able to store lease data in different repositories. Larger deployments
may elect to store leases in a database.
<xref linkend="database-configuration4"/> describes one way to do it.
By default, the server will use a CSV file rather than a database to store
lease information. One of the advantages of using a file is that it eliminates
dependency on third party database software.
</para>
<para>
The configuration of the file backend (Memfile)
is controlled through the Dhcp4/lease-database parameters. When default
parameters are used, the Memfile backend will write leases to a disk in the
[bind10-install-dir]/var/bind10/kea-leases4.csv.
</para>
<para>
It is possible to alter the default location of the lease file. The following
configuration:
<screen>
&gt; <userinput>config set Dhcp4/lease-database/type "memfile"</userinput>
&gt; <userinput>config set Dhcp4/lease-database/persist true</userinput>
&gt; <userinput>config set Dhcp4/lease-database/name "/tmp/kea-leases4.csv"</userinput>
&gt; <userinput>config commit</userinput>
</screen>
will change the default location of the lease file to /tmp/kea-leases4.csv.
</para>
<para>
The "persist" parameter controls whether the leases are written to disk.
It is strongly recommended that this parameter is set to "true" at all times
during the normal operation of the server
</para>
</section>
<section id="database-configuration4">
<title>Database Configuration</title>
<para>
All leases issued by the server are stored in the lease database. Currently
there are 3 database backends available: MySQL, PostgreSQL and experimental memfile.
there are 3 database backends available: MySQL, PostgreSQL and memfile.
<footnote>
<para>
The server comes with an in-memory database ("memfile") configured as the default
......@@ -5313,10 +5347,44 @@ Dhcp6/dhcp-ddns/qualifying-suffix "example.com" string
</note>
<section>
<title>Default storage for leases</title>
<para>
The server is able to store lease data in different repositories. Larger deployments
may elect to store leases in a database.
<xref linkend="database-configuration6"/> describes one way to do it.
By default, the server will use a CSV file rather than a database to store
lease information. One of the advantages of using a file is that it eliminates
dependency on third party database software.
</para>
<para>
The configuration of the file backend (Memfile)
is controlled through the Dhcp6/lease-database parameters. When default
parameters are left, the Memfile backend will write leases to a disk in the
[bind10-install-dir]/var/bind10/kea-leases6.csv.
</para>
<para>
It is possible to alter the default location of the lease file. The following
configuration:
<screen>
&gt; <userinput>config set Dhcp4/lease-database/type "memfile"</userinput>
&gt; <userinput>config set Dhcp4/lease-database/persist true</userinput>
&gt; <userinput>config set Dhcp4/lease-database/leasefile "/tmp/kea-leases6.csv"</userinput>
&gt; <userinput>config commit</userinput>
</screen>
will change the default location of the lease file to /tmp/kea-leases6.csv.
</para>
<para>
The "persist" parameter controls whether the leases are written to disk.
It is strongly recommended that this parameter is set to "true" at all times
during the normal operation of the server.
</para>
</section>
<section id="database-configuration6">
<title>Database Configuration</title>
<para>
All leases issued by the server are stored in the lease database. Currently
there are 3 database backends available: MySQL, PostgreSQL and experimental memfile.
there are 3 database backends available: MySQL, PostgreSQL and memfile.
<footnote>
<para>
The server comes with an in-memory database ("memfile") configured as the default
......
......@@ -412,7 +412,7 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
parser = new StringParser(config_id,
globalContext()->string_values_);
} else if (config_id.compare("lease-database") == 0) {
parser = new DbAccessParser(config_id);
parser = new DbAccessParser(config_id, *globalContext());
} else if (config_id.compare("hooks-libraries") == 0) {
parser = new HooksLibrariesParser(config_id);
} else if (config_id.compare("echo-client-id") == 0) {
......
......@@ -191,6 +191,12 @@
"item_type": "string",
"item_optional": true,
"item_default": ""
},
{
"item_name": "persist",
"item_type": "boolean",
"item_optional": true,
"item_default": true
}
]
},
......
......@@ -88,7 +88,7 @@ public:
/// @param direct_response_desired specifies if it is desired to
/// use direct V4 traffic.
Dhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT,
const char* dbconfig = "type=memfile",
const char* dbconfig = "type=memfile universe=4",
const bool use_bcast = true,
const bool direct_response_desired = true);
......
......@@ -117,7 +117,8 @@ public:
/// @param port port number to listen on; the default value 0 indicates
/// that sockets should not be opened.
NakedDhcpv4Srv(uint16_t port = 0)
: Dhcpv4Srv(port, "type=memfile", false, false) {
: Dhcpv4Srv(port, "type=memfile universe=4 persist=false",
false, false) {
// Create fixed server id.
server_id_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
asiolink::IOAddress("192.0.3.1")));
......
......@@ -643,7 +643,7 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id) {
parser = new StringParser(config_id,
globalContext()->string_values_);
} else if (config_id.compare("lease-database") == 0) {
parser = new DbAccessParser(config_id);
parser = new DbAccessParser(config_id, *globalContext());
} else if (config_id.compare("hooks-libraries") == 0) {
parser = new HooksLibrariesParser(config_id);
} else if (config_id.compare("dhcp-ddns") == 0) {
......
......@@ -185,6 +185,12 @@
"item_type": "string",
"item_optional": true,
"item_default": ""
},
{
"item_name": "persist",
"item_type": "boolean",
"item_optional": true,
"item_default": true
}
]
},
......
......@@ -45,7 +45,7 @@ class NakedDhcpv6Srv: public isc::dhcp::Dhcpv6Srv {
public:
NakedDhcpv6Srv(uint16_t port) : isc::dhcp::Dhcpv6Srv(port) {
// Open the "memfile" database for leases
std::string memfile = "type=memfile";
std::string memfile = "type=memfile universe=6 persist=false";
isc::dhcp::LeaseMgrFactory::create(memfile);
}
......
// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2014 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
......@@ -14,8 +14,11 @@
#include <dhcp/duid.h>
#include <exceptions/exceptions.h>
#include <util/encode/hex.h>
#include <util/io_utilities.h>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/constants.hpp>
#include <boost/algorithm/string/split.hpp>
#include <iomanip>
#include <sstream>
#include <vector>
......@@ -46,6 +49,41 @@ DUID::DUID(const uint8_t* data, size_t len) {
duid_ = std::vector<uint8_t>(data, data + len);
}
std::vector<uint8_t>
DUID::decode(const std::string& text) {
/// @todo optimize stream operations here.
std::vector<std::string> split_text;
boost::split(split_text, text, boost::is_any_of(":"),
boost::algorithm::token_compress_off);
std::ostringstream s;
for (size_t i = 0; i < split_text.size(); ++i) {
// If there are multiple tokens and the current one is empty, it
// means that two consecutive colons were specified. This is not
// allowed for client identifier.
if ((split_text.size() > 1) && split_text[i].empty()) {
isc_throw(isc::BadValue, "invalid identifier '" << text << "': "
<< " tokens must be separated with a single colon");
} else if (split_text[i].size() == 1) {
s << "0";
} else if (split_text[i].size() > 2) {
isc_throw(isc::BadValue, "invalid identifier '" << text << "'");
}
s << split_text[i];
}
std::vector<uint8_t> binary;
try {
util::encode::decodeHex(s.str(), binary);
} catch (const Exception& ex) {
isc_throw(isc::BadValue, "failed to create identifier from text '"
<< text << "': " << ex.what());
}
return (binary);
}
const std::vector<uint8_t>& DUID::getDuid() const {
return (duid_);
}
......@@ -62,6 +100,12 @@ DUID::DUIDType DUID::getType() const {
}
}
DUID
DUID::fromText(const std::string& text) {
std::vector<uint8_t> binary = decode(text);
return DUID(binary);
}
std::string DUID::toText() const {
std::stringstream tmp;
tmp << std::hex;
......@@ -118,6 +162,12 @@ std::string ClientId::toText() const {
return (DUID::toText());
}
ClientIdPtr
ClientId::fromText(const std::string& text) {
std::vector<uint8_t> binary = decode(text);
return (ClientIdPtr(new ClientId(binary)));
}
// Compares two client-ids
bool ClientId::operator==(const ClientId& other) const {
return (this->duid_ == other.duid_);
......
// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2014 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
......@@ -69,6 +69,17 @@ class DUID {
/// @brief Returns the DUID type
DUIDType getType() const;
/// @brief Create DUID from the textual format.
///
/// This static function parses a DUID specified in the textual format.
/// Internally it uses @c DUID::decode to parse the DUID.
///
/// @param text DUID in the hexadecimal format with digits representing
/// individual bytes separated by colons.
///
/// @throw isc::BadValue if parsing the DUID failed.
static DUID fromText(const std::string& text);
/// @brief Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
std::string toText() const;
......@@ -79,6 +90,23 @@ class DUID {
bool operator!=(const DUID& other) const;
protected:
/// @brief Decodes the textual format of the DUID.
///
/// The format being parsed should match the DUID representation returned
/// by the @c DUID::toText method, i.e. the pairs of hexadecimal digits
/// representing bytes of DUID must be separated by colons. Usually the
/// single byte is represented by two hexadecimal digits. However, this
/// function allows one digit per byte. In this case, a zero is prepended
/// before the conversion. For example, a DUID 0:1:2::4:5 equals to
/// 00:01:02:00:04:05.
///
/// @param text DUID in the hexadecimal format with digits representing
/// individual bytes separated by colons.
///
/// @throw isc::BadValue if parsing the DUID failed.
static std::vector<uint8_t> decode(const std::string& text);
/// The actual content of the DUID
std::vector<uint8_t> duid_;
};
......@@ -86,7 +114,10 @@ class DUID {
/// @brief Shared pointer to a DUID
typedef boost::shared_ptr<DUID> DuidPtr;
/// @brief Forward declaration to the @c ClientId class.
class ClientId;
/// @brief Shared pointer to a Client ID.
typedef boost::shared_ptr<ClientId> ClientIdPtr;
/// @brief Holds Client identifier or client IPv4 address
///
......@@ -130,6 +161,19 @@ public:
/// @brief Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
std::string toText() const;
/// @brief Create client identifier from the textual format.
///
/// This static function creates the instance of the @c ClientId from the
/// textual format. Internally it calls @c DUID::fromText. The format of
/// the input must match the format of the DUID in @c DUID::fromText.
///
/// @param text Client identifier in the textual format.
///
/// @return Pointer to the instance of the @c ClientId.
/// @throw isc::BadValue if parsing the client identifier failed.
/// @throw isc::OutOfRange if the client identifier is truncated.
static ClientIdPtr fromText(const std::string& text);
/// @brief Compares two client-ids for equality
bool operator==(const ClientId& other) const;
......@@ -137,9 +181,6 @@ public:
bool operator!=(const ClientId& other) const;
};
/// @brief Shared pointer to a Client ID.
typedef boost::shared_ptr<ClientId> ClientIdPtr;
}; // end of isc::dhcp namespace
}; // end of isc namespace
......
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2014 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
......@@ -15,6 +15,10 @@
#include <dhcp/hwaddr.h>
#include <dhcp/dhcp4.h>
#include <exceptions/exceptions.h>
#include <util/encode/hex.h>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/constants.hpp>
#include <boost/algorithm/string/split.hpp>
#include <iomanip>
#include <sstream>
#include <vector>
......@@ -42,9 +46,11 @@ HWAddr::HWAddr(const std::vector<uint8_t>& hwaddr, uint8_t htype)
}
}
std::string HWAddr::toText() const {
std::string HWAddr::toText(bool include_htype) const {
std::stringstream tmp;
tmp << "hwtype=" << static_cast<int>(htype_) << " ";
if (include_htype) {
tmp << "hwtype=" << static_cast<int>(htype_) << " ";
}
tmp << std::hex;
bool delim = false;
for (std::vector<uint8_t>::const_iterator it = hwaddr_.begin();
......@@ -58,6 +64,42 @@ std::string HWAddr::toText() const {
return (tmp.str());
}
HWAddr
HWAddr::fromText(const std::string& text, const uint8_t htype) {
/// @todo optimize stream operations here.
std::vector<std::string> split_text;
boost::split(split_text, text, boost::is_any_of(":"),
boost::algorithm::token_compress_off);
std::ostringstream s;
for (size_t i = 0; i < split_text.size(); ++i) {
// If there are multiple tokens and the current one is empty, it
// means that two consecutive colons were specified. This is not
// allowed for hardware address.
if ((split_text.size() > 1) && split_text[i].empty()) {
isc_throw(isc::BadValue, "failed to create hardware address"
" from text '" << text << "': tokens of the hardware"
" address must be separated with a single colon");
} else if (split_text[i].size() == 1) {
s << "0";
} else if (split_text[i].size() > 2) {
isc_throw(isc::BadValue, "invalid hwaddr '" << text << "'");
}
s << split_text[i];
}
std::vector<uint8_t> binary;
try {
util::encode::decodeHex(s.str(), binary);
} catch (const Exception& ex) {
isc_throw(isc::BadValue, "failed to create hwaddr from text '"
<< text << "': " << ex.what());
}
return (HWAddr(binary, htype));
}
bool HWAddr::operator==(const HWAddr& other) const {
return ((this->htype_ == other.htype_) &&
(this->hwaddr_ == other.hwaddr_));
......
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2013-2014 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
......@@ -54,8 +54,36 @@ public:
// Hardware type
uint8_t htype_;
/// @brief Returns textual representation of a client-id (e.g. 00:01:02:03)
std::string toText() const;
/// @brief Returns textual representation of a hardware address
/// (e.g. 00:01:02:03:04:05)
///
/// @param include_htype Boolean value which controls whether the hardware
/// type is included in the returned string (true), or not (false).
///
/// @return Hardware address in the textual format.
std::string toText(bool include_htype = true) const;
/// @brief Creates instance of the hardware address from textual format.
///
/// This function parses HW address specified as text and creates the
/// corresponding @c HWAddr instance. The hexadecimal digits representing
/// individual bytes of the hardware address should be separated with
/// colons. Typically, two digits per byte are used. However, this function
/// allows for 1 digit per HW address byte. In this case, the digit is
/// prepended with '0' during conversion to binary value.
///
/// This function can be used to perform a reverse operation to the
/// @c HWAddr::toText(false).
///
/// The instance created by this function sets HTYPE_ETHER as a hardware
/// type.
///
/// @param text HW address in the textual format.
/// @param htype Hardware type.
///
/// @return Instance of the HW address created from text.
static HWAddr fromText(const std::string& text,
const uint8_t htype = HTYPE_ETHER);
/// @brief Compares two hardware addresses for equality
bool operator==(const HWAddr& other) const;
......
// Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2014 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
......@@ -126,6 +126,37 @@ TEST(DuidTest, getType) {
EXPECT_EQ(DUID::DUID_UNKNOWN, duid_invalid->getType());
}
// This test checks that the DUID instance can be created from the textual
// format and that error is reported if the textual format is invalid.
TEST(DuidTest, fromText) {
scoped_ptr<DUID> duid;
// DUID with only decimal digits.
ASSERT_NO_THROW(
duid.reset(new DUID(DUID::fromText("00:01:02:03:04:05:06")))
);
EXPECT_EQ("00:01:02:03:04:05:06", duid->toText());
// DUID with some hexadecimal digits (upper case and lower case).
ASSERT_NO_THROW(
duid.reset(new DUID(DUID::fromText("00:aa:bb:CD:ee:EF:ab")))
);
EXPECT_EQ("00:aa:bb:cd:ee:ef:ab", duid->toText());
// DUID with one digit for a particular byte.
ASSERT_NO_THROW(
duid.reset(new DUID(DUID::fromText("00:a:bb:D:ee:EF:ab")))
);
EXPECT_EQ("00:0a:bb:0d:ee:ef:ab", duid->toText());
// Repeated colon sign is not allowed.
EXPECT_THROW(
duid.reset(new DUID(DUID::fromText("00::bb:D:ee:EF:ab"))),
isc::BadValue
);
// DUID with excessive number of digits for one of the bytes.
EXPECT_THROW(
duid.reset(new DUID(DUID::fromText("00:01:021:03:04:05:06"))),
isc::BadValue
);
}
// Test checks if the toText() returns valid texual representation
TEST(DuidTest, toText) {
uint8_t data1[] = {0, 1, 2, 3, 4, 0xff, 0xfe};
......@@ -249,4 +280,37 @@ TEST(ClientIdTest, toText) {
EXPECT_EQ("00:01:02:03:04:ff:fe", clientid.toText());
}
// This test checks that the ClientId instance can be created from the textual
// format and that error is reported if the textual format is invalid.
TEST(ClientIdTest, fromText) {
ClientIdPtr cid;
// ClientId with only decimal digits.
ASSERT_NO_THROW(
cid = ClientId::fromText("00:01:02:03:04:05:06")
);
EXPECT_EQ("00:01:02:03:04:05:06", cid->toText());
// ClientId with some hexadecimal digits (upper case and lower case).
ASSERT_NO_THROW(
cid = ClientId::fromText("00:aa:bb:CD:ee:EF:ab")
);
EXPECT_EQ("00:aa:bb:cd:ee:ef:ab", cid->toText());
// ClientId with one digit for a particular byte.
ASSERT_NO_THROW(
cid = ClientId::fromText("00:a:bb:D:ee:EF:ab")
);
EXPECT_EQ("00:0a:bb:0d:ee:ef:ab", cid->toText());
// Repeated colon sign in the ClientId is not allowed.
EXPECT_THROW(
ClientId::fromText("00::bb:D:ee:EF:ab"),
isc::BadValue
);
// ClientId with excessive number of digits for one of the bytes.
EXPECT_THROW(
ClientId::fromText("00:01:021:03:04:05:06"),
isc::BadValue
);
}
} // end of anonymous namespace
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012, 2014 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
......@@ -108,6 +108,9 @@ TEST(HWAddrTest, toText) {
EXPECT_EQ("hwtype=15 00:01:02:03:04:05", hw->toText());
// In some cases we don't want htype value to be included. Check that
// it can be forced.
EXPECT_EQ("00:01:02:03:04:05", hw->toText(false));
}
TEST(HWAddrTest, stringConversion) {
......@@ -131,5 +134,33 @@ TEST(HWAddrTest, stringConversion) {
EXPECT_EQ(std::string("hwtype=1 c3:07:a2:e8:42"), result);
}
// Checks that the HW address can be created from the textual format.
TEST(HWAddrTest, fromText) {
scoped_ptr<HWAddr> hwaddr;
// Create HWAddr from text.
ASSERT_NO_THROW(
hwaddr.reset(new HWAddr(HWAddr::fromText("00:01:A:bc:d:67")));
);
EXPECT_EQ("00:01:0a:bc:0d:67", hwaddr->toText(false));
// HWAddr class should allow empty address.
ASSERT_NO_THROW(
hwaddr.reset(new HWAddr(HWAddr::fromText("")));
);
EXPECT_TRUE(hwaddr->toText(false).empty());
// HWAddr should not allow multiple consecutive colons.
EXPECT_THROW(
hwaddr.reset(new HWAddr(HWAddr::fromText("00::01:00:bc:0d:67"))),
isc::BadValue
);
// There should be no more than two digits per byte of the HW addr.
EXPECT_THROW(
hwaddr.reset(new HWAddr(HWAddr::fromText("00:01:00A:bc:0d:67"))),
isc::BadValue
);
}
} // end of anonymous namespace
......@@ -36,12 +36,16 @@ AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
# Make sure the generated files are deleted in a "clean" operation
CLEANFILES = *.gcno *.gcda dhcpsrv_messages.h dhcpsrv_messages.cc s-messages
# Remove CSV files created by the CSVLeaseFile6 and CSVLeaseFile4 unit tests.
CLEANFILES += *.csv
lib_LTLIBRARIES = libb10-dhcpsrv.la
libb10_dhcpsrv_la_SOURCES =
libb10_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
libb10_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
libb10_dhcpsrv_la_SOURCES += callout_handle_store.h
libb10_dhcpsrv_la_SOURCES += csv_lease_file4.cc csv_lease_file4.h
libb10_dhcpsrv_la_SOURCES += csv_lease_file6.cc csv_lease_file6.h
libb10_dhcpsrv_la_SOURCES += d2_client_cfg.cc d2_client_cfg.h
libb10_dhcpsrv_la_SOURCES += d2_client_mgr.cc d2_client_mgr.h
libb10_dhcpsrv_la_SOURCES += dbaccess_parser.cc dbaccess_parser.h
......
// Copyright (C) 2014 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