# the --with-mysql-config (default to /usr/bin/mysql-config). By default,
# the software is not built with MySQL support enabled.
mysql_config="no"
-AC_ARG_WITH([mysql-config],
- AC_HELP_STRING([--with-mysql-config=PATH],
- [specify the path to the mysql_config script]),
+AC_ARG_WITH([dhcp-mysql],
+ AC_HELP_STRING([--with-dhcp-mysql=PATH],
+ [path to the MySQL 'mysql_config' script (MySQL is used for the DHCP database)]),
[mysql_config="$withval"])
if test "${mysql_config}" = "yes" ; then
fi
if test "$MYSQL_CONFIG" != "" ; then
- if test -d "$MYSQL_CONFIG" ; then
- AC_MSG_ERROR([Specified mysql_config program ${MYSQL_CONFIG} is a directory])
- fi
- if ! test -x "$MYSQL_CONFIG" ; then
- AC_MSG_ERROR([--with-mysql-config should point to a mysql_config program])
+ if test -d "$MYSQL_CONFIG" -o ! -x "$MYSQL_CONFIG" ; then
+ AC_MSG_ERROR([--with-dhcp-mysql should point to a mysql_config program])
fi
MYSQL_CPPFLAGS=`$MYSQL_CONFIG --cflags`
${LOG4CPLUS_LIBS}
SQLite: $SQLITE_CFLAGS
$SQLITE_LIBS
- MySQL: $MYSQL_CPPFLAGS
- $MYSQL_LIBS
Features:
$enable_features
libb10_dhcp___la_SOURCES =
libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
libb10_dhcp___la_SOURCES += duid.cc duid.h
-libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
libb10_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
+libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
libb10_dhcp___la_SOURCES += iface_mgr_linux.cc
libb10_dhcp___la_SOURCES += iface_mgr_sun.cc
libb10_dhcp___la_SOURCES += lease_mgr.cc lease_mgr.h
#
# source dhcpdb_create.mysql
+
# Holds the IPv4 leases.
CREATE TABLE lease4 (
- address INT UNSIGNED UNIQUE NOT NULL, # IPv4 address
- hwaddr VARBINARY(20), # Hardware address
- client_id VARBINARY(128), # Client ID
- lease_time INT UNSIGNED, # Length of the lease (seconds)
- expire TIMESTAMP, # Expiration time of the lease
- subnet_id INT UNSIGNED # Subnet identification
+ 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)
+ expire TIMESTAMP, # Expiration time of the lease
+ subnet_id INT UNSIGNED # Subnet identification
) ENGINE = INNODB;
-# Holds the IPv6 leases
+# Holds the IPv6 leases.
+# 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) UNIQUE NOT NULL, # IPv6 address (actually 39 is max)
- hwaddr VARBINARY(20), # Hardware address
- client_id VARBINARY(128), # Client ID
- lease_time INT UNSIGNED, # Length of the lease (seconds)
- expire TIMESTAMP, # Expiration time of the lease
- subnet_id INT UNSIGNED, # Subnet identification
- pref_lifetime INT UNSIGNED, # Preferred lifetime
- lease_type TINYINT, # Lease type
- iaid INT UNSIGNED, # IA ID
- prefix_len TINYINT UNSIGNED # For IA_PD only
+ address VARCHAR(40) PRIMARY KEY NOT NULL, # IPv6 address
+ hwaddr VARBINARY(20), # Hardware address
+ client_id VARBINARY(128), # Client ID
+ lease_time INT UNSIGNED, # Length of the lease (seconds)
+ expire TIMESTAMP, # Expiration time of the lease
+ subnet_id INT UNSIGNED, # Subnet identification
+ pref_lifetime INT UNSIGNED, # Preferred lifetime
+ lease_type TINYINT, # Lease type (see lease6_types
+ # table for possible values)
+ iaid INT UNSIGNED, # See Section 10 of RFC 3315
+ prefix_len TINYINT UNSIGNED # For IA_PD only
) ENGINE = INNODB;
# ... and a definition of lease6 types. This table is a convenience for
# users of the database - if they want to view the lease table and use the
# type names, they can join this table with the lease6 table
CREATE TABLE lease6_types (
- lease_type TINYINT UNIQUE NOT NULL, # Lease type code
- name VARCHAR(5) # Name of the lease type
+ lease_type TINYINT PRIMARY KEY NOT NULL, # Lease type code.
+ name VARCHAR(5) # Name of the lease type
);
+START TRANSACTION;
INSERT INTO lease6_types VALUES (0, "IA_NA"); # Non-temporary v6 addresses
INSERT INTO lease6_types VALUES (1, "IA_TA"); # Temporary v6 addresses
INSERT INTO lease6_types VALUES (2, "IA_PD"); # Prefix delegations
+COMMIT;
# Finally, the version of the schema. We start at 0.1 during development.
# 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".
CREATE TABLE schema_version (
- version INT NOT NULL, # Major version number
- minor INT NOT NULL # Minor version number
+ version INT PRIMARY KEY NOT NULL, # Major version number
+ minor INT # Minor version number
);
+START TRANSACTION;
INSERT INTO schema_version VALUES (0, 1);
-
COMMIT;
+# Notes:
+#
+# Indexes
+# =======
# It is likely that additional indexes will be needed. However, the
# increase in lookup performance from these will come at the expense
# of a decrease in performance during insert operations due to the need
# For lease stability: if a client requests a new lease, try to find an
# existing or recently expired lease for it so that it can keep using the
# same IP address.
+#
+# Field Sizes
+# ===========
+# If any of the VARxxx field sizes are altered, the lengths in the MySQL
+# backend source file (mysql_lease_mgr.cc) must be correspondingly changed.
+#
+# Portability
+# ===========
+# The "ENGINE = INNODB" on some tables is not portablea to another database
+# and will need to be removed.
+#
+# Some columns contain binary data so are stored as VARBINARY instead of
+# VARCHAR. This may be non-portable between databases: in this case, the
+# definition should be changed to VARCHAR.
/// @brief Constructor
///
/// Initialize fields that don't have a default constructor.
+ /// @TODO Remove this
Lease4() : addr_(0) {}
};
/// @brief Constructor
///
/// Initialize fields that don't have a default constructor.
- Lease6() : addr_(0) {}
+ Lease6() : addr_("::") {}
};
/// @brief Pointer to a Lease6 structure.
/// @exception DbOperationError Database function failed
virtual bool addLease(const Lease6Ptr& lease) = 0;
- /// @brief Returns existing IPv4 lease for specified IPv4 address and subnet_id
+ /// @brief Returns IPv4 lease for specified IPv4 address and subnet_id
///
/// This method is used to get a lease for specific subnet_id. There can be
/// at most one lease for any given subnet, so this method returns a single
/// As host reservation is outside of scope for 2012, support for hosts
/// is currently postponed.
-
protected:
/// @brief returns value of the parameter
std::string getParameter(const std::string& name) const;
ParameterMap parameters_;
};
-/// @brief Pointer to a Lease Manager
-typedef boost::shared_ptr<LeaseMgr> LeaseMgrPtr;
-
}; // end of isc::dhcp namespace
}; // end of isc namespace
#include <utility>
#include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
#include <boost/algorithm/string.hpp>
#include <exceptions/exceptions.h>
#include <dhcp/lease_mgr_factory.h>
namespace isc {
namespace dhcp {
+boost::scoped_ptr<LeaseMgr>&
+LeaseMgrFactory::getLeaseMgrPtr() {
+ static boost::scoped_ptr<LeaseMgr> leaseMgrPtr;
+ return (leaseMgrPtr);
+}
+
LeaseMgr::ParameterMap
LeaseMgrFactory::parse(const std::string& dbconfig) {
LeaseMgr::ParameterMap mapped_tokens;
return (mapped_tokens);
}
-LeaseMgrPtr
+void
LeaseMgrFactory::create(const std::string& dbconfig) {
const std::string type = "type";
// Yes, check what it is.
#ifdef HAVE_MYSQL
if (parameters[type] == string("mysql")) {
- return LeaseMgrPtr(new MySqlLeaseMgr(parameters));
+ getLeaseMgrPtr().reset(new MySqlLeaseMgr(parameters));
+ return;
}
#endif
// Get here on no match
- isc_throw(InvalidParameter, "Database configuration parameter 'type' does "
+ isc_throw(InvalidType, "Database configuration parameter 'type' does "
"not specify a supported database backend");
}
+void
+LeaseMgrFactory::destroy() {
+ getLeaseMgrPtr().reset();
+}
+
+LeaseMgr&
+LeaseMgrFactory::instance() {
+ LeaseMgr* lmptr = getLeaseMgrPtr().get();
+ if (lmptr == NULL) {
+ isc_throw(NoLeaseManager, "no current lease manager is available");
+ }
+ return (*lmptr);
+}
+
+
}; // namespace dhcp
}; // namespace isc
namespace isc {
namespace dhcp {
-/// @brief Invalid Type Exception
+/// @brief Invalid type exception
///
/// Thrown when the factory doesn't recognise the type of the backend.
class InvalidType : public Exception {
+public:
InvalidType(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
+/// @brief No lease manager exception
+///
+/// Thrown if an attempt is made to get a reference to the current lease
+/// manager and none is currently available.
+class NoLeaseManager : public Exception {
+public:
+ NoLeaseManager(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
/// @brief Lease Manager Factory
///
/// This class comprises nothing but static methods used to create a lease
/// @brief Create an instance of a lease manager.
///
/// Each database backend has its own lease manager type. This static
- /// method returns a lease manager of the appropriate type, based on the
- /// the data in the input argument.
+ /// method sets the "current" lease manager to be a manager of the
+ /// appropriate type. The actual lease manager is returned by the
+ /// "instance" method.
+ ///
+ /// Note: when called, the current lease manager is *always* destroyed
+ /// and a new one created - even if the parameters are the same.
///
/// dbconfig is a generic way of passing parameters. Parameters are passed
/// in the "name=value" format, separated by spaces. The data MUST include
/// are back-end specific, although must include the "type" keyword
/// which gives the backend in use.
///
- /// @return Implementation of lease manager for the specified database.
- static LeaseMgrPtr create(const std::string& dbconfig);
+ /// @exception InvalidParameter dbconfig string does not contain the
+ /// "type" keyword.
+ /// @exception InvalidType The "type" keyword in dbconfig does not identify
+ /// a supported backend.
+ static void create(const std::string& dbconfig);
+
+ /// @brief Destroy lease manager
+ ///
+ /// Destroys the current lease manager object. This should have the effect
+ /// of closing the database connection. The method is a no-op if no
+ /// lease manager is available.
+ static void destroy();
+
+ /// @brief Return Current Lease Manager
+ ///
+ /// Returns an instance of the "current" lease manager. An exception
+ /// will be thrown if none is available.
+ ///
+ /// @exception NoLeaseManager No lease manager is available: use create()
+ /// to create one before calling this method.
+ static LeaseMgr& instance();
/// @brief Parse Database Parameters
///
///
/// @return std::map<>std::string, std::string> Map of keyword/value pairs.
static LeaseMgr::ParameterMap parse(const std::string& dbconfig);
+
+private:
+ /// @brief Hold pointer to lease manager
+ ///
+ /// Holds a pointer to the singleton lease manager. The singleton
+ /// is encapsulated in this method to avoid a "static initialization
+ /// fiasco" if defined in an external static variable.
+ static boost::scoped_ptr<LeaseMgr>& getLeaseMgrPtr();
+
};
}; // end of isc::dhcp namespace
using namespace std;
+namespace {
+///@{
+/// @brief Maximum Size of Database Fields
+///
+/// The following constants define buffer sizes for variable length database
+/// fields. The values should be greater than or equal to the length set in
+/// the schema definition.
+///
+/// The exception is the length of any VARCHAR fields: these should be set
+/// greater than or equal to the length of the field plus 2: this allows for
+/// the insertion of a trailing null regardless of whether the data returned
+/// contains a trailing null (the documentation is not clear on this point).
+
+const size_t ADDRESS6_TEXT_MAX_LEN = 42; // Max size of a IPv6 text buffer
+const size_t DUID_MAX_LEN = 128; // Max size of a DUID
+const size_t HWADDR_MAX_LEN = 20; // Max size of a hardware address
+///@}
+};
+
namespace isc {
namespace dhcp {
// Note: All array legths are equal to the corresponding variable in the
// schema.
std::string addr6_; ///< String form of address
- char addr6_buffer_[42]; ///< Character array form of V6 address
+ char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN]; ///< Character
+ ///< array form of V6 address
unsigned long addr6_length_; ///< Length of the address
MYSQL_BIND bind_[10]; ///< Static array for speed of access
std::vector<uint8_t> clientid_; ///< Client identification
- uint8_t clientid_buffer_[128]; ///< Buffer form of client ID
+ uint8_t clientid_buffer_[DUID_MAX_LEN]; ///< Buffer form of DUID
unsigned long clientid_length_; ///< Length of client ID
my_bool error_[10]; ///< For error reporting
MYSQL_TIME expire_; ///< Lease expiry time
const my_bool false_; ///< "false" for MySql
- uint8_t hwaddr_buffer_[20]; ///< Hardware address buffer
+ uint8_t hwaddr_buffer_[HWADDR_MAX_LEN]; ///< Hardware address buffer
unsigned long hwaddr_length_; ///< Length of hardware address
uint32_t iaid_; ///< Identity association ID
Lease6Ptr lease_; ///< Pointer to lease object
/// @exception DbOperationError if the commit failed.
virtual void commit();
-
/// @brief Rollback Transactions
///
/// Rolls back all pending database operations. On databases that don't
/// Open the database.
MySqlLeaseMgrTest() {
- lmptr_ = LeaseMgrFactory::create(validConnectionString());
+ LeaseMgrFactory::create(validConnectionString());
+ lmptr_ = &(LeaseMgrFactory::instance());
}
/// @brief Destructor
virtual ~MySqlLeaseMgrTest() {
lmptr_->rollback();
+ LeaseMgrFactory::destroy();
}
- LeaseMgrPtr lmptr_; // Pointer to the lease manager
+ LeaseMgr* lmptr_; // Pointer to the lease manager
};
/// opened: the fixtures assume that and check basic operations.
TEST(MySqlOpenTest, OpenDatabase) {
- LeaseMgrPtr lmptr;
+ // Check that attempting to get an instance of the lease manager when
+ // none is set throws an exception.
+ EXPECT_THROW(LeaseMgrFactory::instance(), NoLeaseManager);
// Check that wrong specification of backend throws an exception.
// (This is really a check on LeaseMgrFactory, but is convenient to
// perform here.)
- EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
- InvalidParameter);
+ InvalidType);
// Check that invalid login data causes an exception.
- EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
DbOpenError);
- // Check that database opens correctly and that version is as expected
- ASSERT_NO_THROW(lmptr = LeaseMgrFactory::create(validConnectionString()));
- ASSERT_TRUE(lmptr);
+ // Check that database opens correctly.
+ ASSERT_NO_THROW(LeaseMgrFactory::create(validConnectionString()));
+ EXPECT_NO_THROW((void) LeaseMgrFactory::instance());
+
+ // ... and tidy up.
+ LeaseMgrFactory::destroy();
}
/// @brief Check conversion functions