nobase_dist_doc_DATA += examples/kea4/backends.json
nobase_dist_doc_DATA += examples/kea4/cassandra.json
nobase_dist_doc_DATA += examples/kea4/classify.json
+nobase_dist_doc_DATA += examples/kea4/comments.json
nobase_dist_doc_DATA += examples/kea4/dhcpv4-over-dhcpv6.json
nobase_dist_doc_DATA += examples/kea4/hooks.json
nobase_dist_doc_DATA += examples/kea4/leases-expiration.json
nobase_dist_doc_DATA += examples/kea6/backends.json
nobase_dist_doc_DATA += examples/kea6/cassandra.json
nobase_dist_doc_DATA += examples/kea6/classify.json
+nobase_dist_doc_DATA += examples/kea6/comments.json
nobase_dist_doc_DATA += examples/kea6/dhcpv4-over-dhcpv6.json
nobase_dist_doc_DATA += examples/kea6/duid.json
nobase_dist_doc_DATA += examples/kea6/hooks.json
--- /dev/null
+// This is an example configuration file for the DHCPv4 server in Kea.
+// It uses embedded (i.e., which will be included in configuration objets
+// and not stripped by at lexical analysis) comments.
+
+{ "Dhcp4":
+
+{
+ // Global scope
+ "comment": "A DHCPv4 server",
+
+ // In interface config
+ "interfaces-config": {
+ "comment": "Use wildcard",
+ "interfaces": [ "*" ] },
+
+ // In option definitions
+ "option-def": [ {
+ "comment": "An option definition",
+ "name": "foo",
+ "code": 100,
+ "type": "ipv4-address",
+ "space": "isc"
+ } ],
+
+ // In option data
+ "option-data": [ {
+ "comment": "Set option value",
+ "name": "dhcp-message",
+ "data": "ABCDEF0105",
+ "csv-format": false
+ } ],
+
+ // In client classes
+ "client-classes": [
+ {
+ "comment": "match all",
+ "name": "all",
+ "test": "'' == ''"
+ },
+ // Of course comments are optional
+ {
+ "name": "none"
+ },
+ // Two comments (or user contexts) in the same scope are combined
+ {
+ "comment": "first comment",
+ "comment": "second comment",
+ "name": "two"
+ },
+ // Of course this applies to a comment and a user context too
+ {
+ "comment": "a comment",
+ "name": "both",
+ "user-context": {
+ "version": 1
+ }
+ }
+ ],
+
+ // In control socket (more for the agent)
+ "control-socket": {
+ "comment": "REST API",
+ "socket-type": "unix",
+ "socket-name": "/tmp/kea4-ctrl-socket",
+ "user-context": { "comment": "Indirect comment" }
+ },
+
+ // In shared networks
+ "shared-networks": [ {
+ "comment": "A shared network",
+ "name": "foo",
+
+ // In subnets
+ "subnet4": [
+ {
+ "comment": "A subnet",
+ "subnet": "192.0.1.0/24",
+ "id": 100,
+
+ // In pools
+ "pools": [
+ {
+ "comment": "A pool",
+ "pool": "192.0.1.1-192.0.1.10"
+ }
+ ],
+
+ // In host reservations
+ "reservations": [
+ {
+ "comment": "A host reservation",
+ "hw-address": "AA:BB:CC:DD:EE:FF",
+ "hostname": "foo.example.com",
+
+ // Again in an option data
+ "option-data": [ {
+ "comment": "An option in a reservation",
+ "name": "domain-name",
+ "data": "example.com"
+ } ]
+ }
+ ]
+ }
+ ]
+ } ],
+
+ // In dhcp ddns
+ "dhcp-ddns": {
+ "comment": "No dynamic DNS",
+ "enable-updates": false
+ }
+},
+
+"Logging": {
+ // In loggers
+ "loggers": [ {
+ "comment": "A logger",
+ "name": "kea-dhcp4"
+ } ]
+}
+
+}
+
--- /dev/null
+// This is an example configuration file for the DHCPv6 server in Kea.
+// It uses embedded (i.e., which will be included in configuration objets
+// and not stripped by at lexical analysis) comments.
+
+{ "Dhcp6":
+
+{
+ // Global scope
+ "comment": "A DHCPv6 server",
+
+ // In interface config
+ "interfaces-config": {
+ "comment": "Use wildcard",
+ "interfaces": [ "*" ] },
+
+ // In option definitions
+ "option-def": [ {
+ "comment": "An option definition",
+ "name": "foo",
+ "code": 100,
+ "type": "ipv6-address",
+ "space": "isc"
+ } ],
+
+ // In option data
+ "option-data": [ {
+ "comment": "Set option value",
+ "name": "subscriber-id",
+ "data": "ABCDEF0105",
+ "csv-format": false
+ } ],
+
+ // In client classes
+ "client-classes": [
+ {
+ "comment": "match all",
+ "name": "all",
+ "test": "'' == ''"
+ },
+ // Of course comments are optional
+ {
+ "name": "none"
+ },
+ // Two comments (or user contexts) in the same scope are combined
+ {
+ "comment": "first comment",
+ "comment": "second comment",
+ "name": "two"
+ },
+ // Of course this applies to a comment and a user context too
+ {
+ "comment": "a comment",
+ "name": "both",
+ "user-context": {
+ "version": 1
+ }
+ }
+ ],
+
+ // In control socket (more for the agent)
+ "control-socket": {
+ "comment": "REST API",
+ "socket-type": "unix",
+ "socket-name": "/tmp/kea6-ctrl-socket",
+ "user-context": { "comment": "Indirect comment" }
+ },
+
+ // In shared networks
+ "shared-networks": [ {
+ "comment": "A shared network",
+ "name": "foo",
+
+ // In subnets
+ "subnet6": [
+ {
+ "comment": "A subnet",
+ "subnet": "2001:db1::/64",
+ "id": 100,
+
+ // In pools
+ "pools": [
+ {
+ "comment": "A pool",
+ "pool": "2001:db1::/64"
+ }
+ ],
+
+ // In prefix pools
+ "pd-pools": [
+ {
+ "comment": "A prefix pool",
+ "prefix": "2001:db2::",
+ "prefix-len": 48,
+ "delegated-len": 64
+ }
+ ],
+
+ // In host reservations
+ "reservations": [
+ {
+ "comment": "A host reservation",
+ "hw-address": "AA:BB:CC:DD:EE:FF",
+ "hostname": "foo.example.com",
+
+ // Again in an option data
+ "option-data": [ {
+ "comment": "An option in a reservation",
+ "name": "domain-search",
+ "data": "example.com"
+ } ]
+ }
+ ]
+ }
+ ]
+ } ],
+
+ // In dhcp ddns
+ "dhcp-ddns": {
+ "comment": "No dynamic DNS",
+ "enable-updates": false
+ }
+},
+
+"Logging": {
+ // In loggers
+ "loggers": [ {
+ "comment": "A logger",
+ "name": "kea-dhcp6"
+ } ]
+}
+
+}
+
hooks-libraries was a list of strings, each string being the name of
a library. The change was made in Kea 1.0 to facilitate the
specification of library-specific parameters, a capability
- available in Kea 1.1.0 onwards.
+ available in Kea 1.1.0 onwards. Libraries should allow a parameter
+ entry where to put documentation as it is done for many configuration
+ scopes with comment and user context.
</para></note>
<note>
<para>
As of Kea 1.3, the structures that allow user contexts are
pools of all types (addresses and prefixes) and subnets. Kea
- 1.4 extended to the global scope, shared-networks, client
- classes, and option data and definitions. These are supported
- in both DHCPv4 and DHCPv6. It is expected that host
- reservations and other structures will be extended in the
- future to provide the user context capability.
+ 1.4 extended to the global scope, interfaces config,
+ shared networks, subnets, client classes, option datas and definitions,
+ host reservations, control socket, dhcp ddns, loggers and server id.
+ These are supported in both DHCPv4 and DHCPv6 at the exception
+ of server id which is DHCPv6 only.
</para>
</section>
" },\n"
" \"renew-timer\": 900,\n"
" \"reservation-mode\": \"all\",\n"
+" \"reservations\": [\n"
+" {\n"
+" \"comment\": \"A host reservation\",\n"
+" \"boot-file-name\": \"\",\n"
+" \"client-classes\": [ ],\n"
+" \"hostname\": \"foo.example.com\",\n"
+" \"hw-address\": \"aa:bb:cc:dd:ee:ff\",\n"
+" \"next-server\": \"0.0.0.0\",\n"
+" \"option-data\": [\n"
+" {\n"
+" \"comment\": \"An option in a reservation\",\n"
+" \"always-send\": false,\n"
+" \"code\": 15,\n"
+" \"csv-format\": true,\n"
+" \"data\": \"example.com\",\n"
+" \"name\": \"domain-name\",\n"
+" \"space\": \"dhcp4\"\n"
+" }\n"
+" ],\n"
+" \"server-hostname\": \"\"\n"
+" }\n"
+" ],\n"
" \"server-hostname\": \"\",\n"
" \"subnet\": \"192.0.1.0/24\",\n"
" \"valid-lifetime\": 7200\n"
"backends.json",
"cassandra.json",
"classify.json",
+ // "comments.json",
"dhcpv4-over-dhcpv6.json",
"hooks.json",
"leases-expiration.json",
" },\n"
" \"renew-timer\": 900,\n"
" \"reservation-mode\": \"all\",\n"
+" \"reservations\": [\n"
+" {\n"
+" \"comment\": \"A host reservation\",\n"
+" \"client-classes\": [ ],\n"
+" \"hostname\": \"foo.example.com\",\n"
+" \"hw-address\": \"aa:bb:cc:dd:ee:ff\",\n"
+" \"ip-addresses\": [ ],\n"
+" \"option-data\": [\n"
+" {\n"
+" \"comment\": \"An option in a reservation\",\n"
+" \"always-send\": false,\n"
+" \"code\": 24,\n"
+" \"csv-format\": true,\n"
+" \"data\": \"example.com\",\n"
+" \"name\": \"domain-search\",\n"
+" \"space\": \"dhcp6\"\n"
+" }\n"
+" ],\n"
+" \"prefixes\": [ ]\n"
+" }\n"
+" ],\n"
" \"subnet\": \"2001:db1::/48\",\n"
" \"valid-lifetime\": 7200\n"
" }\n"
configs.push_back("backends.json");
configs.push_back("cassandra.json");
configs.push_back("classify.json");
+ // configs.push_back("comments.json");
configs.push_back("dhcpv4-over-dhcpv6.json");
configs.push_back("duid.json");
configs.push_back("hooks.json");
}
// Set the reservation
const IOAddress& address = getIPv4Reservation();
- map->set("ip-address", Element::create(address.toText()));
+ if (!address.isV4Zero()) {
+ map->set("ip-address", Element::create(address.toText()));
+ }
// Set the hostname
const std::string& hostname = getHostname();
map->set("hostname", Element::create(hostname));
private:
/// @brief Number of columns returned for SELECT queries send by this class.
- static const size_t HOST_COLUMNS = 12;
+ static const size_t HOST_COLUMNS = 13;
public:
dhcp4_subnet_id_(0), dhcp6_subnet_id_(0), ipv4_address_(0),
hostname_length_(0), dhcp4_client_classes_length_(0),
dhcp6_client_classes_length_(0),
+ user_context_length_(0),
dhcp4_next_server_(0),
dhcp4_server_hostname_length_(0),
dhcp4_boot_file_name_length_(0),
ipv4_address_null_(MLM_FALSE), hostname_null_(MLM_FALSE),
dhcp4_client_classes_null_(MLM_FALSE),
dhcp6_client_classes_null_(MLM_FALSE),
+ user_context_null_(MLM_FALSE),
dhcp4_next_server_null_(MLM_FALSE),
dhcp4_server_hostname_null_(MLM_FALSE),
dhcp4_boot_file_name_null_(MLM_FALSE) {
memset(hostname_, 0, sizeof(hostname_));
memset(dhcp4_client_classes_, 0, sizeof(dhcp4_client_classes_));
memset(dhcp6_client_classes_, 0, sizeof(dhcp6_client_classes_));
+ memset(user_context_, 0, sizeof(user_context_));
memset(dhcp4_server_hostname_, 0, sizeof(dhcp4_server_hostname_));
memset(dhcp4_boot_file_name_, 0, sizeof(dhcp4_boot_file_name_));
columns_[6] = "hostname";
columns_[7] = "dhcp4_client_classes";
columns_[8] = "dhcp6_client_classes";
- columns_[9] = "dhcp4_next_server";
- columns_[10] = "dhcp4_server_hostname";
- columns_[11] = "dhcp4_boot_file_name";
+ columns_[9] = "user_context";
+ columns_[10] = "dhcp4_next_server";
+ columns_[11] = "dhcp4_server_hostname";
+ columns_[12] = "dhcp4_boot_file_name";
- BOOST_STATIC_ASSERT(11 < HOST_COLUMNS);
+ BOOST_STATIC_ASSERT(12 < HOST_COLUMNS);
};
/// @brief Virtual destructor.
bind_[8].buffer = dhcp6_client_classes_;
bind_[8].buffer_length = classes6_txt.length();
+ // user_context : TEXT NULL
+ ConstElementPtr ctx = host->getContext();
+ if (ctx) {
+ bind_[9].buffer_type = MYSQL_TYPE_STRING;
+ string ctx_txt = ctx->str();
+ strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
+ bind_[9].buffer = user_context_;
+ bind_[9].buffer_length = ctx_txt.length();
+ } else {
+ bind_[9].buffer_type = MYSQL_TYPE_NULL;
+ }
+
// ipv4_address : INT UNSIGNED NULL
// The address in the Host structure is an IOAddress object. Convert
// this to an integer for storage.
dhcp4_next_server_ = host->getNextServer().toUint32();
- bind_[9].buffer_type = MYSQL_TYPE_LONG;
- bind_[9].buffer = reinterpret_cast<char*>(&dhcp4_next_server_);
- bind_[9].is_unsigned = MLM_TRUE;
- // bind_[9].is_null = &MLM_FALSE; // commented out for performance
- // reasons, see memset() above
+ bind_[10].buffer_type = MYSQL_TYPE_LONG;
+ bind_[10].buffer = reinterpret_cast<char*>(&dhcp4_next_server_);
+ bind_[10].is_unsigned = MLM_TRUE;
+ // bind_[10].is_null = &MLM_FALSE; // commented out for performance
+ // reasons, see memset() above
// dhcp4_server_hostname
- bind_[10].buffer_type = MYSQL_TYPE_STRING;
+ bind_[11].buffer_type = MYSQL_TYPE_STRING;
std::string server_hostname = host->getServerHostname();
strncpy(dhcp4_server_hostname_, server_hostname.c_str(),
SERVER_HOSTNAME_MAX_LEN - 1);
- bind_[10].buffer = dhcp4_server_hostname_;
- bind_[10].buffer_length = server_hostname.length();
+ bind_[11].buffer = dhcp4_server_hostname_;
+ bind_[11].buffer_length = server_hostname.length();
// dhcp4_boot_file_name
- bind_[11].buffer_type = MYSQL_TYPE_STRING;
+ bind_[12].buffer_type = MYSQL_TYPE_STRING;
std::string boot_file_name = host->getBootFileName();
strncpy(dhcp4_boot_file_name_, boot_file_name.c_str(),
BOOT_FILE_NAME_MAX_LEN - 1);
- bind_[11].buffer = dhcp4_boot_file_name_;
- bind_[11].buffer_length = boot_file_name.length();
+ bind_[12].buffer = dhcp4_boot_file_name_;
+ bind_[12].buffer_length = boot_file_name.length();
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
bind_[8].length = &dhcp6_client_classes_length_;
bind_[8].is_null = &dhcp6_client_classes_null_;
+ // user_context : TEXT NULL
+ user_context_null_ = MLM_FALSE;
+ user_context_length_ = sizeof(user_context_);
+ bind_[9].buffer_type = MYSQL_TYPE_STRING;
+ bind_[9].buffer = reinterpret_cast<char*>(user_context_);
+ bind_[9].buffer_length = user_context_length_;
+ bind_[9].length = &user_context_length_;
+ bind_[9].is_null = &user_context_null_;
+
// dhcp4_next_server
dhcp4_next_server_null_ = MLM_FALSE;
- bind_[9].buffer_type = MYSQL_TYPE_LONG;
- bind_[9].buffer = reinterpret_cast<char*>(&dhcp4_next_server_);
- bind_[9].is_unsigned = MLM_TRUE;
- bind_[9].is_null = &dhcp4_next_server_null_;
+ bind_[10].buffer_type = MYSQL_TYPE_LONG;
+ bind_[10].buffer = reinterpret_cast<char*>(&dhcp4_next_server_);
+ bind_[10].is_unsigned = MLM_TRUE;
+ bind_[10].is_null = &dhcp4_next_server_null_;
// dhcp4_server_hostname
dhcp4_server_hostname_null_ = MLM_FALSE;
dhcp4_server_hostname_length_ = sizeof(dhcp4_server_hostname_);
- bind_[10].buffer_type = MYSQL_TYPE_STRING;
- bind_[10].buffer = reinterpret_cast<char*>(dhcp4_server_hostname_);
- bind_[10].buffer_length = dhcp4_server_hostname_length_;
- bind_[10].length = &dhcp4_server_hostname_length_;
- bind_[10].is_null = &dhcp4_server_hostname_null_;
+ bind_[11].buffer_type = MYSQL_TYPE_STRING;
+ bind_[11].buffer = reinterpret_cast<char*>(dhcp4_server_hostname_);
+ bind_[11].buffer_length = dhcp4_server_hostname_length_;
+ bind_[11].length = &dhcp4_server_hostname_length_;
+ bind_[11].is_null = &dhcp4_server_hostname_null_;
// dhcp4_boot_file_name
dhcp4_boot_file_name_null_ = MLM_FALSE;
dhcp4_boot_file_name_length_ = sizeof(dhcp4_boot_file_name_);
- bind_[11].buffer_type = MYSQL_TYPE_STRING;
- bind_[11].buffer = reinterpret_cast<char*>(dhcp4_boot_file_name_);
- bind_[11].buffer_length = dhcp4_boot_file_name_length_;
- bind_[11].length = &dhcp4_boot_file_name_length_;
- bind_[11].is_null = &dhcp4_boot_file_name_null_;
+ bind_[12].buffer_type = MYSQL_TYPE_STRING;
+ bind_[12].buffer = reinterpret_cast<char*>(dhcp4_boot_file_name_);
+ bind_[12].buffer_length = dhcp4_boot_file_name_length_;
+ bind_[12].length = &dhcp4_boot_file_name_length_;
+ bind_[12].is_null = &dhcp4_boot_file_name_null_;
// Add the error flags
setErrorIndicators(bind_, error_);
dhcp6_client_classes_length_);
}
+ // Convert user_context to string as well.
+ std::string user_context;
+ if (user_context_null_ == MLM_FALSE) {
+ user_context_[user_context_length_] = '\0';
+ user_context.assign(user_context_);
+ }
+
// Set next server value (siaddr) if non NULL value returned.
asiolink::IOAddress next_server = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
if (dhcp4_next_server_null_ == MLM_FALSE) {
dhcp4_boot_file_name));
h->setHostId(host_id_);
+ // Set the user context if there is one.
+ if (!user_context.empty()) {
+ try {
+ ConstElementPtr ctx = Element::fromJSON(user_context);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "user context '" << user_context
+ << "' is no a JSON map");
+ }
+ h->setContext(ctx);
+ } catch (const isc::data::JSONError& ex) {
+ isc_throw(BadValue, "user context '" << user_context
+ << "' is invalid JSON: " << ex.what());
+ }
+ }
+
return (h);
};
/// client classes.
unsigned long dhcp6_client_classes_length_;
+ /// @brief Buffer holding textual user context.
+ char user_context_[USER_CONTEXT_MAX_LEN];
+
+ /// @brief User context length.
+ unsigned long user_context_length_;
+
/// Next server address (siaddr).
uint32_t dhcp4_next_server_;
/// NULL.
my_bool dhcp6_client_classes_null_;
+ /// @brief Boolean flag indicating if the value of user context is NULL.
+ my_bool user_context_null_;
+
/// Boolean flag indicating if the value of next server is NULL.
my_bool dhcp4_next_server_null_;
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
"h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ "h.user_context, "
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
"o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
"o4.persistent, o4.user_context, "
{MySqlHostDataSourceImpl::GET_HOST_ADDR,
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- "h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
"o.persistent, o.user_context "
{MySqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID,
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- "h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
"o.persistent, o.user_context "
"SELECT h.host_id, h.dhcp_identifier, "
"h.dhcp_identifier_type, h.dhcp4_subnet_id, "
"h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- "h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
"o.persistent, o.user_context, "
{MySqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- "h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
"o.persistent, o.user_context "
"SELECT h.host_id, h.dhcp_identifier, "
"h.dhcp_identifier_type, h.dhcp4_subnet_id, "
"h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- "h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
"o.persistent, o.user_context,"
"SELECT h.host_id, h.dhcp_identifier, "
"h.dhcp_identifier_type, h.dhcp4_subnet_id, "
"h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- "h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
+
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
"o.persistent, o.user_context, "
{MySqlHostDataSourceImpl::INSERT_HOST,
"INSERT INTO hosts(host_id, dhcp_identifier, dhcp_identifier_type, "
"dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
- "dhcp4_client_classes, dhcp6_client_classes, dhcp4_next_server, "
+ "dhcp4_client_classes, dhcp6_client_classes, "
+ "user_context, dhcp4_next_server, "
"dhcp4_server_hostname, dhcp4_boot_file_name) "
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
// Inserts a single IPv6 reservation into 'reservations' table.
{MySqlHostDataSourceImpl::INSERT_V6_RESRV,
static const int HOSTNAME_COL = 6;
static const int DHCP4_CLIENT_CLASSES_COL = 7;
static const int DHCP6_CLIENT_CLASSES_COL = 8;
- static const int DHCP4_NEXT_SERVER_COL = 9;
- static const int DHCP4_SERVER_HOSTNAME_COL = 10;
- static const int DHCP4_BOOT_FILE_NAME_COL = 11;
+ static const int USER_CONTEXT_COL = 9;
+ static const int DHCP4_NEXT_SERVER_COL = 10;
+ static const int DHCP4_SERVER_HOSTNAME_COL = 11;
+ static const int DHCP4_BOOT_FILE_NAME_COL = 12;
/// @brief Number of columns returned for SELECT queries send by this class.
- static const size_t HOST_COLUMNS = 12;
+ static const size_t HOST_COLUMNS = 13;
public:
columns_[HOSTNAME_COL] = "hostname";
columns_[DHCP4_CLIENT_CLASSES_COL] = "dhcp4_client_classes";
columns_[DHCP6_CLIENT_CLASSES_COL] = "dhcp6_client_classes";
+ columns_[USER_CONTEXT_COL] = "user_context";
columns_[DHCP4_NEXT_SERVER_COL] = "dhcp4_next_server";
columns_[DHCP4_SERVER_HOSTNAME_COL] = "dhcp4_server_hostname";
columns_[DHCP4_BOOT_FILE_NAME_COL] = "dhcp4_boot_file_name";
- BOOST_STATIC_ASSERT(11 < HOST_COLUMNS);
+ BOOST_STATIC_ASSERT(12 < HOST_COLUMNS);
};
/// @brief Virtual destructor.
// dhcp6_client_classes : VARCHAR(255) NULL
bind_array->addTempString(host->getClientClasses6().toText(","));
+ // user_context: TEXT NULL
+ ConstElementPtr ctx = host->getContext();
+ if (ctx) {
+ std::string user_context_ = ctx->str();
+ bind_array->addTempString(user_context_);
+ } else {
+ bind_array->addNull();
+ }
+
// dhcp4_next_server : BIGINT NULL
bind_array->add((host->getNextServer()));
getColumnValue(r, row, DHCP6_CLIENT_CLASSES_COL, dhcp6_client_classes);
}
+ // user_context: TEXT
+ std::string user_context;
+ if (!isColumnNull(r, row, USER_CONTEXT_COL)) {
+ getColumnValue(r, row, USER_CONTEXT_COL, user_context);
+ }
+
// dhcp4_next_server : BIGINT NULL
uint32_t dhcp4_next_server_as_uint32(0);
if (!isColumnNull(r, row, DHCP4_NEXT_SERVER_COL)) {
dhcp4_next_server, dhcp4_server_hostname,
dhcp4_boot_file_name));
+ // Set the user context if there is one.
+ if (!user_context.empty()) {
+ try {
+ ConstElementPtr ctx = Element::fromJSON(user_context);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "user context '" << user_context
+ << "' is no a JSON map");
+ }
+ host->setContext(ctx);
+ } catch (const isc::data::JSONError& ex) {
+ isc_throw(BadValue, "user context '" << user_context
+ << "' is invalid JSON: " << ex.what());
+ }
+ }
+
host->setHostId(host_id);
} catch (const isc::Exception& ex) {
isc_throw(DbOperationError, "Could not create host: " << ex.what());
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
" h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
" h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ " h.user_context, "
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
" o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
" o4.persistent, o4.user_context, "
{ OID_INT8 }, "get_host_addr",
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
" h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- " h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
" o.persistent, o.user_context "
"get_host_subid4_dhcpid",
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
" h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- " h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
" o.persistent, o.user_context "
"SELECT h.host_id, h.dhcp_identifier, "
" h.dhcp_identifier_type, h.dhcp4_subnet_id, "
" h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- " h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
" o.persistent, o.user_context, "
"get_host_subid_addr",
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
" h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- " h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
" o.persistent, o.user_context "
"SELECT h.host_id, h.dhcp_identifier, "
" h.dhcp_identifier_type, h.dhcp4_subnet_id, "
" h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- " h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
" o.persistent, o.user_context, "
"SELECT h.host_id, h.dhcp_identifier, "
" h.dhcp_identifier_type, h.dhcp4_subnet_id, "
" h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- " h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
" o.persistent, o.user_context, "
// PgSqlHostDataSourceImpl::INSERT_HOST
// Inserts a host into the 'hosts' table. Returns the inserted host id.
- {11,
+ {12,
{ OID_BYTEA, OID_INT2,
OID_INT4, OID_INT4, OID_INT8, OID_VARCHAR,
- OID_VARCHAR, OID_VARCHAR },
+ OID_VARCHAR, OID_VARCHAR, OID_TEXT },
"insert_host",
"INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
" dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
- " dhcp4_client_classes, dhcp6_client_classes, "
+ " dhcp4_client_classes, dhcp6_client_classes, user_context, "
" dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name) "
- "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING host_id"
+ "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) "
+ "RETURNING host_id"
},
//PgSqlHostDataSourceImpl::INSERT_V6_RESRV
const Subnet4Collection* subnets = cfg_subnets4_->getAll();
for (Subnet4Collection::const_iterator subnet = subnets->cbegin();
subnet != subnets->cend(); ++subnet) {
- ElementPtr subnet_cfg = (*subnet)->toElement();
- sn_list.push_back(subnet_cfg);
-
// Skip subnets which are in a shared-network
SharedNetwork4Ptr network;
(*subnet)->getSharedNetwork(network);
if (network) {
continue;
}
+ ElementPtr subnet_cfg = (*subnet)->toElement();
+ sn_list.push_back(subnet_cfg);
plain_subnets->add(subnet_cfg);
}
dhcp->set("subnet4", plain_subnets);
- ConstElementPtr shared_networks = cfg_shared_networks4_->toElement();
+ ElementPtr shared_networks = cfg_shared_networks4_->toElement();
+ const std::vector<ElementPtr> networks = shared_networks->listValue();
+ for (auto network = networks.cbegin();
+ network != networks.cend(); ++network) {
+ const std::vector<ElementPtr> sh_list =
+ (*network)->get("subnet4")->listValue();
+ for (auto subnet = sh_list.cbegin();
+ subnet != sh_list.cend(); ++subnet) {
+ sn_list.push_back(*subnet);
+ }
+ }
dhcp->set("shared-networks", shared_networks);
} else {
const Subnet6Collection* subnets = cfg_subnets6_->getAll();
for (Subnet6Collection::const_iterator subnet = subnets->cbegin();
subnet != subnets->cend(); ++subnet) {
- ElementPtr subnet_cfg = (*subnet)->toElement();
- sn_list.push_back(subnet_cfg);
-
// Skip subnets which are in a shared-network
SharedNetwork6Ptr network;
(*subnet)->getSharedNetwork(network);
if (network) {
continue;
}
+ ElementPtr subnet_cfg = (*subnet)->toElement();
+ sn_list.push_back(subnet_cfg);
plain_subnets->add(subnet_cfg);
}
dhcp->set("subnet6", plain_subnets);
- ConstElementPtr shared_networks = cfg_shared_networks6_->toElement();
+ ElementPtr shared_networks = cfg_shared_networks6_->toElement();
+ const std::vector<ElementPtr> networks = shared_networks->listValue();
+ for (auto network = networks.cbegin();
+ network != networks.cend(); ++network) {
+ const std::vector<ElementPtr> sh_list =
+ (*network)->get("subnet6")->listValue();
+ for (auto subnet = sh_list.cbegin();
+ subnet != sh_list.cend(); ++subnet) {
+ sn_list.push_back(*subnet);
+ }
+ }
dhcp->set("shared-networks", shared_networks);
}
// Insert reservations
"\"comment\": \"a host reservation\", "
"\"hostname\": \"\", "
"\"hw-address\": \"01:02:03:04:05:06\", "
- "\"ip-address\": \"0.0.0.0\", "
"\"next-server\": \"0.0.0.0\", "
"\"option-data\": [ ], "
"\"server-hostname\": \"\" "
"\"client-classes\": [ ], "
"\"duid\": \"11:12:13:14:15\", "
"\"hostname\": \"myhost\", "
- "\"ip-address\": \"0.0.0.0\", "
"\"next-server\": \"0.0.0.0\", "
"\"option-data\": [ ], "
"\"server-hostname\": \"\" "
"\"client-classes\": [ \"modem\", \"router\" ], "
"\"duid\": \"11:12:13:14:15\", "
"\"hostname\": \"myhost\", "
- "\"ip-address\": \"0.0.0.0\", "
"\"next-server\": \"0.0.0.0\", "
"\"option-data\": [ ], "
"\"server-hostname\": \"\" "
"\"client-classes\": [ \"modem\", \"router\" ], "
"\"duid\": \"11:12:13:14:15\", "
"\"hostname\": \"myhost\", "
- "\"ip-address\": \"0.0.0.0\", "
"\"next-server\": \"0.0.0.0\", "
"\"option-data\": [ ], "
"\"server-hostname\": \"\" "
$$
DELIMITER ;
+# Add user context into table holding hosts
+ALTER TABLE hosts ADD COLUMN user_context TEXT NULL;
+
# Add user contexts into tables holding DHCP options
ALTER TABLE dhcp4_options ADD COLUMN user_context TEXT NULL;
ALTER TABLE dhcp6_options ADD COLUMN user_context TEXT NULL;
$$
DELIMITER ;
+# Add user context into table holding hosts
+ALTER TABLE hosts ADD COLUMN user_context TEXT NULL;
+
# Add user contexts into tables holding DHCP options
ALTER TABLE dhcp4_options ADD COLUMN user_context TEXT NULL;
ALTER TABLE dhcp6_options ADD COLUMN user_context TEXT NULL;
(dhcp_identifier ASC, dhcp_identifier_type ASC, dhcp6_subnet_id ASC)
WHERE (dhcp6_subnet_id IS NOT NULL AND dhcp6_subnet_id <> 0);
+-- Add a column holding hosts for user context.
+ALTER TABLE hosts ADD COLUMN user_context TEXT;
+
-- Add a column holding DHCP options for user context.
ALTER TABLE dhcp4_options ADD COLUMN user_context TEXT;
ALTER TABLE dhcp6_options ADD COLUMN user_context TEXT;
(dhcp_identifier ASC, dhcp_identifier_type ASC, dhcp6_subnet_id ASC)
WHERE (dhcp6_subnet_id IS NOT NULL AND dhcp6_subnet_id <> 0);
+-- Add a column holding hosts for user context.
+ALTER TABLE hosts ADD COLUMN user_context TEXT;
+
-- Add a column holding DHCP options for user context.
ALTER TABLE dhcp4_options ADD COLUMN user_context TEXT;
ALTER TABLE dhcp6_options ADD COLUMN user_context TEXT;