29#include <boost/make_shared.hpp>
38static constexpr size_t HOSTNAME_MAX_LEN = 255u;
39static constexpr size_t ADDRESS6_TEXT_MAX_LEN = 39u;
40static constexpr char NULL_USER_CONTEXT[] =
"";
183 virtual boost::any
retrieve()
override;
250 cass_int32_t address_;
275 "INSERT INTO lease4( "
276 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
277 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
279 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? "
291 "valid_lifetime = ?, "
305 "DELETE FROM lease4 "
314 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
315 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
318 "AND valid_lifetime < 4294967295 "
328 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
329 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
337 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
338 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
344 {GET_LEASE4_CLIENTID,
345 {GET_LEASE4_CLIENTID,
347 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
348 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
350 "WHERE client_id = ? "
355 {GET_LEASE4_CLIENTID_SUBID,
356 {GET_LEASE4_CLIENTID_SUBID,
358 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
359 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
361 "WHERE client_id = ? "
370 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
371 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
378 {GET_LEASE4_HWADDR_SUBID,
379 {GET_LEASE4_HWADDR_SUBID,
381 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
382 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
393 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
394 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
404 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
405 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
407 "WHERE TOKEN(address) > TOKEN(?) "
416 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
417 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
419 "WHERE subnet_id = ? "
420 "ALLOW FILTERING "}},
423 {GET_LEASE4_HOSTNAME,
424 {GET_LEASE4_HOSTNAME,
426 "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
427 "fqdn_fwd, fqdn_rev, hostname, state, user_context "
429 "WHERE hostname = ? "
442 "Lease4 object is NULL");
453 address_ =
static_cast<cass_int32_t
>(lease->addr_.toUint32());
456 if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) {
460 << lease_->hwaddr_->toText() <<
" of length "
461 << lease_->hwaddr_->hwaddr_.size()
462 <<
" exceeds maximum allowed length of "
465 hwaddr_ = lease_->hwaddr_->hwaddr_;
471 if (lease_->client_id_ && lease_->client_id_->getClientId().size() > 0) {
472 client_id_ = lease_->client_id_->getClientId();
490 subnet_id_ =
static_cast<cass_int32_t
>(lease_->subnet_id_);
493 fqdn_fwd_ = lease_->fqdn_fwd_ ? cass_true : cass_false;
496 fqdn_rev_ = lease_->fqdn_rev_ ? cass_true : cass_false;
499 if (lease_->hostname_.size() > HOSTNAME_MAX_LEN) {
501 "hostname " << lease_->hostname_ <<
" of length "
502 << lease_->hostname_.size()
503 <<
" exceeds maximum allowed length of "
504 << HOSTNAME_MAX_LEN);
509 state_ =
static_cast<cass_int32_t
>(lease_->state_);
523 data.
add(&client_id_);
535 "could not create bind array from Lease4: " << lease_->addr_.toText()
536 <<
", reason: " << ex.
what());
545 "Lease4 object is NULL");
556 address_ =
static_cast<cass_int32_t
>(lease->addr_.toUint32());
559 if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) {
563 << lease_->hwaddr_->toText() <<
" of length "
564 << lease_->hwaddr_->hwaddr_.size()
565 <<
" exceeds maximum allowed length of "
568 hwaddr_ = lease_->hwaddr_->hwaddr_;
574 if (lease_->client_id_ && lease_->client_id_->getClientId().size() > 0) {
575 client_id_ = lease_->client_id_->getClientId();
593 subnet_id_ =
static_cast<cass_int32_t
>(lease_->subnet_id_);
596 fqdn_fwd_ = lease_->fqdn_fwd_ ? cass_true : cass_false;
599 fqdn_rev_ = lease_->fqdn_rev_ ? cass_true : cass_false;
602 if (lease_->hostname_.size() > HOSTNAME_MAX_LEN) {
604 "hostname " << lease_->hostname_ <<
" of length "
605 << lease_->hostname_.size()
606 <<
" exceeds maximum allowed length of "
607 << HOSTNAME_MAX_LEN);
612 state_ =
static_cast<cass_int32_t
>(lease_->state_);
625 data.
add(&client_id_);
637 lease_->current_valid_lft_,
642 "CqlLease4Exchange::createBindUpdate(): "
643 "could not create bind array from Lease4: "
644 << lease_->addr_.toText() <<
", reason: " << ex.
what());
653 "Lease4 object is NULL");
662 address_ =
static_cast<cass_int32_t
>(lease_->addr_.toUint32());
669 lease_->current_valid_lft_,
674 "CqlLease4Exchange::createBindForDelete(): "
675 "could not create bind array from Lease4: "
676 << lease_->addr_.toText() <<
", reason: " << ex.
what());
692 data.
add(&client_id_);
727 <<
" of length " <<
hwaddr_.size()
728 <<
" exceeds maximum allowed length of "
733 "client ID " <<
ClientId(client_id_).toText()
734 <<
" of length " << client_id_.size()
735 <<
" exceeds maximum allowed length of "
738 if (
hostname_.size() > HOSTNAME_MAX_LEN) {
742 <<
" exceeds maximum allowed length of "
743 << HOSTNAME_MAX_LEN);
751 uint32_t addr4 =
static_cast<uint32_t
>(address_);
756 if (!ctx || (ctx->getType() != Element::map)) {
758 <<
"' is not a JSON map");
762 Lease4Ptr result(boost::make_shared<Lease4>(addr4, hwaddr, client_id_.data(),
770 result->setContext(ctx);
776 "CqlLease4Exchange::retrieve(): "
777 "could not convert data to Lease4, reason: "
788 for (boost::any &element : collection) {
789 result.push_back(boost::any_cast<Lease4Ptr>(element));
802 const size_t collection_size = collection.size();
803 if (collection_size >= 2u) {
805 "CqlLease4Exchange::getLease(): multiple records were found in "
806 "the database where only one was expected for statement "
808 }
else if (collection_size == 0u) {
811 result = *collection.begin();
820 cass_int64_t timestamp =
static_cast<cass_int64_t
>(time(NULL));
824 cass_int32_t limit = max_leases > 0u ?
static_cast<cass_int32_t
>(max_leases) :
825 std::numeric_limits<cass_int32_t>::max();
829 if (state == keep_state) {
835 data.
add(×tamp);
843 for (
Lease4Ptr &lease : temp_collection) {
844 expired_leases.push_back(lease);
917 virtual boost::any
retrieve()
override;
968 std::string address_;
971 cass_int64_t pref_lifetime_;
980 cass_int32_t lease_type_;
983 cass_int32_t prefix_len_;
986 cass_int32_t hwtype_;
989 cass_int32_t hwaddr_source_;
1009 "INSERT INTO lease6("
1010 "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
1011 "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
1012 "hwaddr_source, state, user_context "
1014 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
1022 "UPDATE lease6 SET "
1023 "valid_lifetime = ?, "
1025 "pref_lifetime = ?, "
1036 "hwaddr_source = ?, "
1039 "WHERE address = ? "
1046 "DELETE FROM lease6 "
1047 "WHERE address = ? "
1055 "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
1056 "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
1057 "hwaddr_source, state, user_context "
1060 "AND valid_lifetime < 4294967295 "
1070 "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
1071 "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
1072 "hwaddr_source, state, user_context "
1074 "WHERE address = ? "
1075 "AND lease_type = ? "
1083 "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
1084 "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
1085 "hwaddr_source, state, user_context "
1092 {GET_LEASE6_DUID_IAID,
1093 {GET_LEASE6_DUID_IAID,
1095 "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
1096 "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
1097 "hwaddr_source, state, user_context "
1099 "WHERE duid = ? AND iaid = ? "
1100 "AND lease_type = ? "
1105 {GET_LEASE6_DUID_IAID_SUBID,
1106 {GET_LEASE6_DUID_IAID_SUBID,
1108 "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
1109 "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
1110 "hwaddr_source, state, user_context "
1112 "WHERE duid = ? AND iaid = ? "
1113 "AND lease_type = ? "
1114 "AND subnet_id = ? "
1122 "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
1123 "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
1124 "hwaddr_source, state, user_context "
1134 "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
1135 "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
1136 "hwaddr_source, state, user_context "
1138 "WHERE TOKEN(address) > TOKEN(?) "
1144 {GET_LEASE6_HOSTNAME,
1145 {GET_LEASE6_HOSTNAME,
1147 "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
1148 "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
1149 "hwaddr_source, state, user_context "
1151 "WHERE hostname = ? "
1157 :
CqlLeaseExchange(connection), pref_lifetime_(0), iaid_(0), lease_type_(0),
1158 prefix_len_(0), hwtype_(0), hwaddr_source_(0) {
1165 "Lease6 object is NULL");
1174 address_ = lease_->addr_.toText();
1175 if (address_.size() > ADDRESS6_TEXT_MAX_LEN) {
1177 <<
" exceeds maximum allowed length of " << ADDRESS6_TEXT_MAX_LEN);
1193 subnet_id_ =
static_cast<cass_int32_t
>(lease_->subnet_id_);
1196 pref_lifetime_ =
static_cast<cass_int64_t
>(lease_->preferred_lft_);
1199 if (!lease_->duid_) {
1201 <<
" is missing mandatory duid");
1203 duid_ = lease_->duid_->getDuid();
1206 iaid_ =
static_cast<cass_int32_t
>(lease_->iaid_);
1209 lease_type_ =
static_cast<cass_int32_t
>(lease_->type_);
1212 prefix_len_ =
static_cast<cass_int32_t
>(lease_->prefixlen_);
1215 fqdn_fwd_ = lease_->fqdn_fwd_ ? cass_true : cass_false;
1218 fqdn_rev_ = lease_->fqdn_rev_ ? cass_true : cass_false;
1221 if (lease_->hostname_.size() > HOSTNAME_MAX_LEN) {
1223 << lease_->hostname_.size() <<
" exceeds maximum allowed length of "
1224 << HOSTNAME_MAX_LEN);
1229 if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) {
1232 <<
" of length " << lease_->hwaddr_->hwaddr_.size()
1235 hwaddr_ = lease_->hwaddr_->hwaddr_;
1241 if (lease_->hwaddr_) {
1242 hwtype_ =
static_cast<cass_int32_t
>(lease_->hwaddr_->htype_);
1248 if (lease_->hwaddr_) {
1249 hwaddr_source_ =
static_cast<cass_int32_t
>(lease_->hwaddr_->source_);
1255 state_ =
static_cast<cass_int32_t
>(lease_->state_);
1269 data.
add(&address_);
1273 data.
add(&pref_lifetime_);
1276 data.
add(&lease_type_);
1277 data.
add(&prefix_len_);
1283 data.
add(&hwaddr_source_);
1289 "could not create bind array from Lease6: " << lease_->addr_.toText()
1290 <<
", reason: " << ex.
what());
1299 "Lease6 object is NULL");
1308 address_ = lease_->addr_.toText();
1309 if (address_.size() > ADDRESS6_TEXT_MAX_LEN) {
1311 "address " << address_ <<
" of length " << address_.size()
1312 <<
" exceeds maximum allowed length of "
1313 << ADDRESS6_TEXT_MAX_LEN);
1329 subnet_id_ =
static_cast<cass_int32_t
>(lease_->subnet_id_);
1332 pref_lifetime_ =
static_cast<cass_int64_t
>(lease_->preferred_lft_);
1335 if (!lease_->duid_) {
1337 "lease6 with address " << address_
1338 <<
" is missing mandatory duid");
1340 duid_ = lease_->duid_->getDuid();
1343 iaid_ =
static_cast<cass_int32_t
>(lease_->iaid_);
1346 lease_type_ =
static_cast<cass_int32_t
>(lease_->type_);
1349 prefix_len_ =
static_cast<cass_int32_t
>(lease_->prefixlen_);
1352 fqdn_fwd_ = lease_->fqdn_fwd_ ? cass_true : cass_false;
1355 fqdn_rev_ = lease_->fqdn_rev_ ? cass_true : cass_false;
1358 if (lease_->hostname_.size() > HOSTNAME_MAX_LEN) {
1360 "hostname" << lease_->hostname_ <<
" of length "
1361 << lease_->hostname_.size()
1362 <<
" exceeds maximum allowed length of "
1363 << HOSTNAME_MAX_LEN);
1368 if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) {
1372 << lease_->hwaddr_->toText() <<
" of length "
1373 << lease_->hwaddr_->hwaddr_.size()
1374 <<
" exceeds maximum allowed length of "
1377 hwaddr_ = lease_->hwaddr_->hwaddr_;
1383 if (lease_->hwaddr_) {
1384 hwtype_ =
static_cast<cass_int32_t
>(lease_->hwaddr_->htype_);
1390 if (lease_->hwaddr_) {
1391 hwaddr_source_ =
static_cast<cass_int32_t
>(lease_->hwaddr_->source_);
1397 state_ =
static_cast<cass_int32_t
>(lease_->state_);
1413 data.
add(&pref_lifetime_);
1417 data.
add(&lease_type_);
1418 data.
add(&prefix_len_);
1424 data.
add(&hwaddr_source_);
1427 data.
add(&address_);
1430 lease_->current_valid_lft_,
1435 "CqlLease6Exchange::createBindForUpdate(): "
1436 "could not create bind array from Lease6: "
1437 << lease_->addr_.toText() <<
", reason: " << ex.
what());
1446 "Lease6 object is NULL");
1455 address_ = lease_->addr_.toText();
1456 if (address_.size() > ADDRESS6_TEXT_MAX_LEN) {
1458 "address " << address_ <<
" of length " << address_.size()
1459 <<
" exceeds maximum allowed length of "
1460 << ADDRESS6_TEXT_MAX_LEN);
1465 data.
add(&address_);
1468 lease_->current_valid_lft_,
1473 "CqlLease6Exchange::createBindForDelete(): "
1474 "could not create bind array from Lease6: "
1475 << lease_->addr_.toText() <<
", reason: " << ex.
what());
1485 data.
add(&address_);
1497 data.
add(&pref_lifetime_);
1506 data.
add(&lease_type_);
1509 data.
add(&prefix_len_);
1527 data.
add(&hwaddr_source_);
1540 if (address_.size() > ADDRESS6_TEXT_MAX_LEN) {
1542 "address " << address_ <<
" of length " << address_.size()
1543 <<
" exceeds maximum allowed length of "
1544 << ADDRESS6_TEXT_MAX_LEN);
1548 "duid " <<
DUID(duid_).toText() <<
" of length "
1550 <<
" exceeds maximum allowed length of "
1556 "invalid lease type "
1557 << lease_type_ <<
" for lease with address "
1558 << address_ <<
". Expected 0, 1 or 2.");
1560 if (
hostname_.size() > HOSTNAME_MAX_LEN) {
1562 "hostname " <<
hostname_ <<
" of length "
1564 <<
" exceeds maximum allowed length of "
1565 << HOSTNAME_MAX_LEN);
1570 <<
" of length " <<
hwaddr_.size()
1571 <<
" exceeds maximum allowed length of "
1577 DuidPtr duid(boost::make_shared<DUID>(duid_));
1581 hwaddr = boost::make_shared<HWAddr>(
hwaddr_, hwtype_);
1582 hwaddr->source_ = hwaddr_source_;
1588 if (!ctx ||(ctx->getType() != Element::map)) {
1590 <<
"' is not a JSON map");
1599 hwaddr, prefix_len_));
1604 result->cltt_ = cltt;
1605 result->current_cltt_ = cltt;
1610 result->setContext(ctx);
1616 "CqlLease6Exchange::retrieve(): "
1617 "could not convert data to Lease6, reason: "
1629 for (boost::any &lease : collection) {
1630 result.push_back(boost::any_cast<Lease6Ptr>(lease));
1643 const size_t collection_size = collection.size();
1644 if (collection_size >= 2u) {
1646 "CqlLease6Exchange::getLease(): multiple records were found in "
1647 "the database where only one was expected for statement "
1649 }
else if (collection_size == 0u) {
1652 result = *collection.begin();
1661 cass_int64_t timestamp =
static_cast<cass_int64_t
>(time(NULL));
1665 cass_int32_t limit = max_leases > 0u ?
static_cast<cass_int32_t
>(max_leases) :
1666 std::numeric_limits<cass_int32_t>::max();
1670 if (state == keep_state) {
1676 data.
add(×tamp);
1684 for (
Lease6Ptr &lease : temp_collection) {
1685 expired_leases.push_back(lease);
1707 const bool fetch_type)
1708 : conn_(conn), statement_(statement), fetch_type_(fetch_type),
1709 cumulative_rows_(), next_row_(cumulative_rows_.begin()),
1710 subnet_id_(0), lease_type_(0), state_(0) {
1723 const bool fetch_type,
const SubnetID& subnet_id)
1725 fetch_type_(fetch_type), cumulative_rows_(),
1726 next_row_(cumulative_rows_.begin()),
1727 subnet_id_(0), lease_type_(0), state_(0) {
1742 const bool fetch_type,
const SubnetID& first_subnet_id,
1745 statement_(statement), fetch_type_(fetch_type), cumulative_rows_(),
1746 next_row_(cumulative_rows_.begin()),
1747 subnet_id_(0), lease_type_(0), state_(0) {
1846 std::map<LeaseStatsRow, int> cumulative_rows_;
1849 std::map<LeaseStatsRow, int>::iterator next_row_;
1852 cass_int32_t subnet_id_;
1855 cass_int32_t lease_type_;
1858 cass_int32_t state_;
1878 {SUBNET_LEASE4_STATS,
1879 {SUBNET_LEASE4_STATS,
1883 "WHERE subnet_id = ? "
1887 {SUBNET_RANGE_LEASE4_STATS,
1888 {SUBNET_RANGE_LEASE4_STATS,
1892 "WHERE subnet_id >= ? and subnet_id <= ? "
1900 "subnet_id, lease_type, state "
1905 {SUBNET_LEASE6_STATS,
1906 {SUBNET_LEASE6_STATS,
1908 "subnet_id, lease_type, state "
1910 "WHERE subnet_id = ? "
1914 {SUBNET_RANGE_LEASE6_STATS,
1915 {SUBNET_RANGE_LEASE6_STATS,
1917 "subnet_id, lease_type, state "
1919 "WHERE subnet_id >= ? and subnet_id <= ? "
1928 cass_int32_t first_subnet_id_data;
1929 cass_int32_t last_subnet_id_data;
1932 data.
add(&first_subnet_id_data);
1936 data.
add(&last_subnet_id_data);
1946 next_row_ = cumulative_rows_.begin();
1952 if (next_row_ == cumulative_rows_.end()) {
1957 row.
subnet_id_ = next_row_->first.subnet_id_;
1972 data.
add(&subnet_id_);
1974 data.
add(&lease_type_);
1984 CassStatement* statement = NULL;
1985 CassFuture* future = NULL;
1989 StatementMap::const_iterator it = connection.
statements_.find(statement_tag);
1992 "CqlLeastStatsQuery::executeSelect(): Statement "
1993 << statement_tag <<
"has not been prepared.");
1998 if (tagged_statement.
is_raw_) {
2000 std::string* query = boost::any_cast<std::string*>(local_data.back());
2001 local_data.pop_back();
2002 statement = cass_statement_new(query->c_str(), local_data.size());
2007 "CqlLeaseStatsQuery::executeSelect(): unable to bind statement "
2008 << tagged_statement.
name_);
2014 rc = cass_statement_set_consistency(statement, connection.
consistency_);
2015 if (rc != CASS_OK) {
2016 cass_statement_free(statement);
2018 "CqlLeaseStatsQuery::executeSelect(): unable to set statement "
2019 "consistency for statement "
2020 << tagged_statement.
name_
2021 <<
", Cassandra error code: " << cass_error_desc(rc));
2025 if (rc != CASS_OK) {
2026 cass_statement_free(statement);
2028 "CqlExchange::executeSelect(): unable to set statement "
2029 "serial consistency for statement "
2030 << tagged_statement.
name_
2031 <<
", Cassandra error code: " << cass_error_desc(rc));
2039 future = cass_session_execute(connection.
session_, statement);
2041 cass_statement_free(statement);
2043 "CqlLeaseStatsQuery::executeSelect(): no CassFuture for statement "
2044 << tagged_statement.
name_);
2048 cass_future_wait(future);
2050 "CqlLeaseStatsQuery::executeSelect(): cass_session_execute() != CASS_OK",
2051 future, statement_tag);
2052 rc = cass_future_error_code(future);
2053 if (rc != CASS_OK) {
2054 cass_future_free(future);
2055 cass_statement_free(statement);
2060 const CassResult* result_collection = cass_future_get_result(future);
2070 CassIterator* rows = cass_iterator_from_result(result_collection);
2071 while (cass_iterator_next(rows)) {
2072 const CassRow* row = cass_iterator_get_row(rows);
2084 auto cum_row = cumulative_rows_.find(raw_row);
2085 if (cum_row != cumulative_rows_.end()) {
2086 cumulative_rows_[raw_row] = cum_row->second + 1;
2088 cumulative_rows_.insert(std::make_pair(raw_row, 1));
2093 cass_iterator_free(rows);
2094 cass_result_free(result_collection);
2095 cass_future_free(future);
2096 cass_statement_free(statement);
2101 : parameters_(parameters), dbconn_(parameters) {
2105 std::pair<uint32_t, uint32_t> db_version =
getVersion();
2106 if (code_version != db_version) {
2108 << code_version.first <<
"." << code_version.second
2109 <<
" found version: " << db_version.first <<
"."
2110 << db_version.second);
2132 std::stringstream tmp;
2135 tmp <<
", library cassandra";
2142 .arg(lease->addr_.toText());
2147 exchange4->createBindForInsert(lease, data);
2152 .arg(exception.
what());
2158 lease->updateCurrentExpirationTime();
2166 .arg(lease->addr_.toText());
2171 exchange6->createBindForInsert(lease, data);
2176 .arg(exception.
what());
2182 lease->updateCurrentExpirationTime();
2195 cass_int32_t addr4 =
static_cast<cass_int32_t
>(addr.
toUint32());
2216 data.
add(&hwaddr_data);
2237 data.
add(&hwaddr_data);
2239 cass_int32_t subnet_id_data =
static_cast<cass_int32_t
>(subnet_id);
2240 data.
add(&subnet_id_data);
2259 data.
add(&client_id_data);
2279 data.
add(&client_id_data);
2281 cass_int32_t subnet_id_data =
static_cast<cass_int32_t
>(subnet_id);
2282 data.
add(&subnet_id_data);
2300 cass_int32_t subnet_id_data =
static_cast<cass_int32_t
>(subnet_id);
2301 data.
add(&subnet_id_data);
2319 std::string hostname_data(hostname);
2320 data.
add(&hostname_data);
2349 if (!lower_bound_address.
isV4()) {
2351 "retrieving leases from the lease database, got "
2352 << lower_bound_address);
2359 if (page_size.
page_size_ > std::numeric_limits<uint32_t>::max()) {
2361 << std::numeric_limits<uint32_t>::max());
2366 .arg(lower_bound_address.
toText());
2370 cass_int32_t address_data = 0;
2371 if (!lower_bound_address.
isV4Zero()) {
2372 address_data =
static_cast<cass_int32_t
>(lower_bound_address.
toUint32());
2373 data.
add(&address_data);
2376 cass_int32_t page_size_data =
static_cast<cass_int32_t
>(page_size.
page_size_);
2377 data.
add(&page_size_data);
2382 exchange4->getLeaseCollection(lower_bound_address.
isV4Zero() ?
2392 std::string addr_data = addr.
toText();
2400 if (addr_data.size() > ADDRESS6_TEXT_MAX_LEN) {
2402 "CqlLeaseMgr::getLease6(): "
2404 << addr_data <<
" of length " << addr_data.size()
2405 <<
" exceeds maximum allowed length of "
2406 << ADDRESS6_TEXT_MAX_LEN);
2408 data.
add(&addr_data);
2410 cass_int32_t lease_type_data =
static_cast<cass_int32_t
>(lease_type);
2411 data.
add(&lease_type_data);
2428 data.
add(&duid_data);
2450 cass_int32_t iaid_data =
static_cast<cass_int32_t
>(iaid);
2452 data.
add(&duid_data);
2453 data.
add(&iaid_data);
2455 cass_int32_t lease_type_data =
static_cast<cass_int32_t
>(lease_type);
2456 data.
add(&lease_type_data);
2479 cass_int32_t iaid_data =
static_cast<cass_int32_t
>(iaid);
2481 data.
add(&duid_data);
2482 data.
add(&iaid_data);
2484 cass_int32_t lease_type_data =
static_cast<cass_int32_t
>(lease_type);
2485 data.
add(&lease_type_data);
2487 cass_int32_t subnet_id_data =
static_cast<cass_int32_t
>(subnet_id);
2488 data.
add(&subnet_id_data);
2511 std::string hostname_data(hostname);
2512 data.
add(&hostname_data);
2531 if (!lower_bound_address.
isV6()) {
2533 "retrieving leases from the lease database, got "
2534 << lower_bound_address);
2541 if (page_size.
page_size_ > std::numeric_limits<uint32_t>::max()) {
2543 << std::numeric_limits<uint32_t>::max());
2548 .arg(lower_bound_address.
toText());
2552 std::string lb_address_data;
2553 if (!lower_bound_address.
isV6Zero()) {
2554 lb_address_data = lower_bound_address.
toText();
2555 if (lb_address_data.size() > ADDRESS6_TEXT_MAX_LEN) {
2557 "CqlLeaseMgr::getLeases6(lower_bound_address, page_size): "
2559 << lb_address_data <<
" of length " << lb_address_data.size()
2560 <<
" exceeds maximum allowed length of "
2561 << ADDRESS6_TEXT_MAX_LEN);
2563 data.
add(&lb_address_data);
2566 cass_int32_t page_size_data =
static_cast<cass_int32_t
>(page_size.
page_size_);
2567 data.
add(&page_size_data);
2572 exchange6->getLeaseCollection(lower_bound_address.
isV6Zero() ?
2582 const size_t max_leases)
const {
2587 exchange4->getExpiredLeases(max_leases, expired_leases);
2592 const size_t max_leases)
const {
2597 exchange6->getExpiredLeases(max_leases, expired_leases);
2603 .arg(lease->addr_.toText());
2616 lease->updateCurrentExpirationTime();
2622 .arg(lease->addr_.toText());
2635 lease->updateCurrentExpirationTime();
2641 std::string addr_data = addr.
toText();
2648 std::unique_ptr<CqlLease4Exchange> exchange4(
2656 .arg(exception.
what());
2665 std::string addr_data = addr.
toText();
2672 std::unique_ptr<CqlLease6Exchange> exchange6(
2680 .arg(exception.
what());
2692 uint64_t deleted = 0u;
2693 cass_int32_t limit = 1024;
2700 cass_int64_t expiration =
static_cast<cass_int64_t
>(time(NULL) -
static_cast<time_t
>(secs));
2701 data.
add(&expiration);
2723 uint64_t deleted = 0u;
2724 cass_int32_t limit = 1024;
2731 cass_int64_t expiration =
static_cast<cass_int64_t
>(time(NULL) -
static_cast<time_t
>(secs));
2732 data.
add(&expiration);
2771 false, first_subnet_id, last_subnet_id));
2799 true, first_subnet_id, last_subnet_id));
2818 std::string name =
"";
2829 return std::string(
"Cassandra Database");
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when a function is not implemented.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
The IOAddress class represents an IP addresses (version agnostic)
bool isV4Zero() const
Convenience function to check if it is an IPv4 zero address.
std::string toText() const
Convert the address to a string.
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
bool isV6() const
Convenience function to check for an IPv6 address.
bool isV4() const
Convenience function to check for an IPv4 address.
bool isV6Zero() const
Convenience function to check if it is an IPv4 zero address.
Structure used to bind C++ input values to dynamic CQL parameters.
void add(const boost::any &value)
Add a value at the end of the vector.
static void bindData(const AnyArray &data, CassStatement *statement)
Assigns values to every column of an INSERT or an UPDATE statement.
static void getData(const CassRow *row, AnyArray &data)
Retrieves data returned by Cassandra.
Common CQL connector pool.
StatementMap statements_
Pointer to external array of tagged statements containing statement name, array of names of bind para...
CassConsistency serial_consistency_
CQL serial consistency.
virtual void commit()
Commit Transactions.
virtual void rollback()
Rollback Transactions.
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap ¶meters)
Get the schema version.
CassSession * session_
CQL session handle.
bool force_consistency_
CQL consistency enabled.
void openDatabase()
Open database.
CassConsistency consistency_
CQL consistency.
static const std::string checkFutureError(const std::string &what, CassFuture *future, StatementTag statement_tag=NULL)
Check for errors.
void prepareStatements(StatementMap &statements)
Prepare statements.
AnyArray executeSelect(const CqlConnection &connection, const AnyArray &where_values, StatementTag statement_tag, const bool &single=false)
Executes SELECT statements.
static void convertFromDatabaseTime(const cass_int64_t &expire, const cass_int64_t &valid_lifetime, time_t &cltt)
Converts time from Cassandra format.
static void convertToDatabaseTime(const time_t &cltt, const uint32_t &valid_lifetime, cass_int64_t &expire)
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Exception thrown on failure to open database.
Exception thrown on failure to execute a database function.
Invalid address family used as input to Lease Manager.
Multiple lease records found where one expected.
Database statement not applied.
Holds Client identifier or client IPv4 address.
static const size_t MAX_CLIENT_ID_LEN
Maximum size of a client ID.
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Exchange Lease4 information between Kea and CQL.
static constexpr StatementTag GET_LEASE4_HWADDR_SUBID
static constexpr StatementTag GET_LEASE4_EXPIRE
void createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, StatementTag statement_tag=NULL)
Create CQL_BIND objects for Lease4 Pointer.
static StatementMap tagged_statements_
Cassandra statements.
static constexpr StatementTag GET_LEASE4_PAGE
void getLeaseCollection(StatementTag &statement_tag, AnyArray &data, Lease4Collection &result)
Retrieves zero or more IPv4 leases.
static constexpr StatementTag GET_LEASE4_LIMIT
void createBindForInsert(const Lease4Ptr &lease, AnyArray &data)
Create CQL_BIND objects for Lease4 Pointer.
void getLease(StatementTag &statement_tag, AnyArray &data, Lease4Ptr &result)
Retrieves one IPv4 lease.
virtual void createBindForSelect(AnyArray &data, StatementTag statement_tag=NULL) override
Create BIND array to receive data.
static constexpr StatementTag INSERT_LEASE4
Statement tags definitions.
CqlLease4Exchange(const CqlConnection &connection)
Constructor.
static constexpr StatementTag GET_LEASE4_CLIENTID_SUBID
static constexpr StatementTag UPDATE_LEASE4
virtual boost::any retrieve() override
Retrieves the Lease4 object in Kea format.
static constexpr StatementTag DELETE_LEASE4
static constexpr StatementTag GET_LEASE4
void createBindForDelete(const Lease4Ptr &lease, AnyArray &data, StatementTag statement_tag=NULL)
Create CQL_BIND objects for Lease4 Pointer.
static constexpr StatementTag GET_LEASE4_ADDR
static constexpr StatementTag GET_LEASE4_SUBID
void getExpiredLeases(const size_t &max_leases, Lease4Collection &expired_leases)
Returns expired leases.
static constexpr StatementTag GET_LEASE4_CLIENTID
static constexpr StatementTag GET_LEASE4_HOSTNAME
static constexpr StatementTag GET_LEASE4_HWADDR
Exchange Lease6 information between Kea and CQL.
void createBindForDelete(const Lease6Ptr &lease, AnyArray &data, StatementTag statement_tag=NULL)
Create CQL_BIND objects for Lease4 Pointer.
static constexpr StatementTag DELETE_LEASE6
virtual boost::any retrieve() override
Retrieves the Lease6 object in Kea format.
static StatementMap tagged_statements_
Cassandra statements.
static constexpr StatementTag GET_LEASE6_DUID
static constexpr StatementTag UPDATE_LEASE6
void createBindForInsert(const Lease6Ptr &lease, AnyArray &data)
Create CQL_BIND objects for Lease6 Pointer.
void getLease(StatementTag &statement_tag, AnyArray &data, Lease6Ptr &result)
Retrieves one IPv6 lease.
static constexpr StatementTag GET_LEASE6_HOSTNAME
static constexpr StatementTag GET_LEASE6_PAGE
virtual void createBindForSelect(AnyArray &data, StatementTag statement_tag=NULL) override
Create BIND array to receive data.
void getExpiredLeases(const size_t &max_leases, Lease6Collection &expired_leases)
Returns expired leases.
static constexpr StatementTag INSERT_LEASE6
Statement tags definitions.
static constexpr StatementTag GET_LEASE6_EXPIRE
static constexpr StatementTag GET_LEASE6_DUID_IAID
static constexpr StatementTag GET_LEASE6_ADDR
void createBindForUpdate(const Lease6Ptr &lease, AnyArray &data, StatementTag statement_tag=NULL)
Create CQL_BIND objects for Lease6 Pointer.
void getLeaseCollection(StatementTag &statement_tag, AnyArray &data, Lease6Collection &result)
Retrieves zero or more IPv6 leases.
static constexpr StatementTag GET_LEASE6_LIMIT
CqlLease6Exchange(const CqlConnection &connection)
Constructor.
static constexpr StatementTag GET_LEASE6_DUID_IAID_SUBID
Common CQL and Lease Data Methods.
virtual void createBindForSelect(AnyArray &data, StatementTag statement_tag=NULL) override=0
Create BIND array to receive C++ data.
cass_bool_t fqdn_fwd_
Has forward DNS update been performed?
std::string user_context_
User context.
std::string hostname_
Client hostname.
cass_int64_t valid_lifetime_
Lease timer.
cass_int32_t subnet_id_
Subnet identifier.
cass_int32_t state_
Lease state.
cass_bool_t fqdn_rev_
Has reverse DNS update been performed?
cass_int64_t expire_
Lease expiry time.
virtual boost::any retrieve() override=0
Copy received data into the derived class' object.
cass_int64_t current_expire_
Expiration time of lease before update.
const CqlConnection & connection_
Database connection.
CqlLeaseExchange(const CqlConnection &connection)
Constructor.
CassBlob hwaddr_
Hardware address.
virtual size_t wipeLeases6(const SubnetID &subnet_id) override
Removed specified IPv6 leases.
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv4 leases.
virtual LeaseStatsQueryPtr startLeaseStatsQuery4() override
Creates and runs the IPv4 lease stats query.
virtual Lease6Collection getLeases6() const override
Returns all IPv6 leases.
virtual void updateLease6(const Lease6Ptr &lease6) override
Updates IPv6 lease.
virtual std::string getDescription() const override
Returns description of the backend.
bool deleteLease(const Lease4Ptr &lease) override final
Deletes an IPv4 lease.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const override
Basic lease access methods.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id) override
Creates and runs the IPv6 lease stats query for a single subnet.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id) override
Creates and runs the IPv4 lease stats query for a single subnet.
static std::string getDBVersion()
Local version of getDBVersion() class method.
virtual std::string getName() const override
Returns name of the database.
virtual size_t wipeLeases4(const SubnetID &subnet_id) override
Removes specified IPv4 leases.
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv6 leases.
virtual bool addLease(const Lease4Ptr &lease) override
Adds an IPv4 lease.
virtual Lease4Collection getLeases4() const override
Returns all IPv4 leases.
virtual VersionPair getVersion() const override
Returns backend version.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id) override
Creates and runs the IPv4 lease stats query for a single subnet.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs) override
Deletes all expired and reclaimed DHCPv4 leases.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id) override
Creates and runs the IPv6 lease stats query for a single subnet.
virtual void rollback() override
Rollback Transactions.
virtual void updateLease4(const Lease4Ptr &lease4) override
Updates IPv4 lease.
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs) override
Deletes all expired and reclaimed DHCPv6 leases.
CqlLeaseMgr(const db::DatabaseConnection::ParameterMap ¶meters)
Constructor.
virtual ~CqlLeaseMgr()
Destructor (closes database)
virtual void commit() override
Commit Transactions.
virtual LeaseStatsQueryPtr startLeaseStatsQuery6() override
Creates and runs the IPv6 lease stats query.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const override
Returns existing IPv6 lease for a given IPv6 address.
Base CQL derivation of the statistical lease data query.
static constexpr StatementTag ALL_LEASE6_STATS
bool getNextRow(LeaseStatsRow &row)
Fetches the next row in the result set.
void executeSelect(const CqlConnection &connection, const AnyArray &data, StatementTag statement_tag)
Executes protocol specific lease query SELECT statement.
static StatementMap tagged_statements_
Cassandra statements.
static constexpr StatementTag SUBNET_LEASE4_STATS
Return lease4 lease statistics for a single subnet.
static constexpr StatementTag ALL_LEASE4_STATS
Statement tags definitions.
static constexpr StatementTag SUBNET_LEASE6_STATS
Return lease6 lease statistics for a single subnet.
static constexpr StatementTag SUBNET_RANGE_LEASE6_STATS
Return lease6 lease statistics for a range of subnets.
void start()
Creates the lease statistical data result set.
virtual ~CqlLeaseStatsQuery()
Destructor.
virtual void createBindForSelect(AnyArray &data, StatementTag statement_tag=NULL)
Create BIND array to receive C++ data.
CqlLeaseStatsQuery(CqlConnection &conn, StatementTag &statement, const bool fetch_type, const SubnetID &subnet_id)
Constructor to query for a single subnet's stats.
static constexpr StatementTag SUBNET_RANGE_LEASE4_STATS
Return lease4 lease statistics for a range of subnets.
CqlLeaseStatsQuery(CqlConnection &conn, StatementTag &statement, const bool fetch_type, const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor to query for the stats for a range of subnets.
CqlLeaseStatsQuery(CqlConnection &conn, StatementTag &statement, const bool fetch_type)
Constructor to query for all subnets' stats.
Holds DUID (DHCPv6 Unique Identifier)
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
static const size_t MAX_DUID_LEN
maximum duid size As defined in RFC 8415, section 11.1
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Wraps value holding size of the page with leases.
const size_t page_size_
Holds page size.
Base class for fulfilling a statistical lease data query.
SubnetID first_subnet_id_
First (or only) subnet_id in the selection criteria.
SelectMode getSelectMode() const
Returns the selection criteria mode The value returned is based upon the constructor variant used and...
SubnetID last_subnet_id_
Last subnet_id in the selection criteria when a range is given.
Attempt to update lease that was not there.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
boost::shared_ptr< const Element > ConstElementPtr
char const *const StatementTag
Statement index representing the statement name.
std::pair< uint32_t, uint32_t > VersionPair
Pair containing major and minor versions.
std::vector< cass_byte_t > CassBlob
Host identifier converted to Cassandra data type.
constexpr uint32_t CQL_SCHEMA_VERSION_MINOR
constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR
Define CQL schema version: 5.0.
std::unordered_map< StatementTag, CqlTaggedStatement, StatementTagHash, StatementTagEqual > StatementMap
A container for all statements.
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
const isc::log::MessageID DHCPSRV_CQL_UPDATE_ADDR4
const isc::log::MessageID DHCPSRV_CQL_GET_ADDR4
const isc::log::MessageID DHCPSRV_CQL_GET_SUBID_HWADDR
const isc::log::MessageID DHCPSRV_CQL_GET_SUBID_CLIENTID
const isc::log::MessageID DHCPSRV_CQL_GET_SUBID4
const isc::log::MessageID DHCPSRV_CQL_GET_HOSTNAME4
const isc::log::MessageID DHCPSRV_CQL_DELETE_EXPIRED_RECLAIMED6
const isc::log::MessageID DHCPSRV_CQL_GET_HWADDR
const isc::log::MessageID DHCPSRV_CQL_ADD_ADDR4
const isc::log::MessageID DHCPSRV_CQL_GET_VERSION
const isc::log::MessageID DHCPSRV_CQL_GET_EXPIRED4
boost::shared_ptr< DUID > DuidPtr
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
const isc::log::MessageID DHCPSRV_CQL_COMMIT
const isc::log::MessageID DHCPSRV_CQL_GET4
const isc::log::MessageID DHCPSRV_CQL_GET_CLIENTID
const isc::log::MessageID DHCPSRV_CQL_GET_ADDR6
const isc::log::MessageID DHCPSRV_CQL_ROLLBACK
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
const isc::log::MessageID DHCPSRV_CQL_UPDATE_ADDR6
const isc::log::MessageID DHCPSRV_CQL_DELETE_EXPIRED_RECLAIMED4
const isc::log::MessageID DHCPSRV_CQL_LEASE_EXCEPTION_THROWN
const isc::log::MessageID DHCPSRV_CQL_GET_IAID_DUID
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
const isc::log::MessageID DHCPSRV_CQL_GET_EXPIRED6
const isc::log::MessageID DHCPSRV_DEPRECATED
const isc::log::MessageID DHCPSRV_CQL_ADD_ADDR6
const isc::log::MessageID DHCPSRV_CQL_GET_IAID_SUBID_DUID
const isc::log::MessageID DHCPSRV_CQL_GET_HOSTNAME6
const isc::log::MessageID DHCPSRV_CQL_GET_PAGE4
const isc::log::MessageID DHCPSRV_CQL_DELETE_ADDR
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
@ HTYPE_ETHER
Ethernet 10Mbps.
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
const isc::log::MessageID DHCPSRV_CQL_GET_PAGE6
Defines the logger used by the top-level component of kea-lfc.
Defines a single statement or query.
StatementTag name_
Short description of the query.
bool is_raw_
Should the statement be executed raw or with binds?
const CassPrepared * prepared_statement_
Internal Cassandra object representing the prepared statement.
Hardware type that represents information from DHCPv4 packet.
static const size_t MAX_HWADDR_LEN
Maximum size of a hardware address.
std::vector< uint8_t > hwaddr_
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Contains a single row of lease statistical data.
int64_t state_count_
state_count The count of leases in the lease state
uint32_t lease_state_
The lease_state to which the count applies.
SubnetID subnet_id_
The subnet ID to which this data applies.
Lease::Type lease_type_
The lease_type to which the count applies.
static const uint32_t STATE_DEFAULT
A lease in the default state.
static const uint32_t STATE_DECLINED
Declined lease.
static const uint32_t STATE_EXPIRED_RECLAIMED
Expired and reclaimed lease.
Type
Type of lease or pool.
@ TYPE_TA
the lease contains temporary IPv6 address
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
@ TYPE_NA
the lease contains non-temporary IPv6 address