From 233950bbf7e471420b44140c0ef44e243a31fd1f Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Feb 2018 15:50:27 +0200 Subject: [PATCH 01/34] added address plus port --- configure.ac | 82 ++-- src/bin/admin/tests/dhcpdb_create_1.0.cql | 2 +- src/bin/admin/tests/dhcpdb_create_1.0.mysql | 2 +- src/bin/admin/tests/mysql_tests.sh.in | 13 +- src/bin/d2/d2_cfg_mgr.cc | 2 +- src/bin/dhcp4/ctrl_dhcp4_srv.h | 2 +- src/bin/dhcp4/dhcp4_lexer.ll | 72 ++- src/bin/dhcp4/dhcp4_messages.mes | 2 +- src/bin/dhcp4/dhcp4_parser.yy | 60 ++- src/bin/dhcp4/dhcp4_srv.cc | 53 ++- src/bin/dhcp4/dhcp4_srv.h | 5 + .../dhcp4/tests/ctrl_dhcp4_srv_unittest.cc | 2 +- src/bin/dhcp6/ctrl_dhcp6_srv.cc | 8 +- src/bin/dhcp6/dhcp6_hooks.dox | 4 +- src/bin/dhcp6/dhcp6_lexer.ll | 43 +- src/bin/dhcp6/dhcp6_parser.yy | 31 +- .../dhcp6/tests/shared_network_unittest.cc | 2 +- src/lib/asiolink/io_address.cc | 77 +++- src/lib/asiolink/io_address.h | 191 +++++--- src/lib/dhcp/option_custom.cc | 2 +- src/lib/dhcp/option_data_types.h | 45 ++ src/lib/dhcp/pkt4.cc | 12 +- src/lib/dhcp/pkt4.h | 52 +++ src/lib/dhcp/tests/option_custom_unittest.cc | 2 +- src/lib/dhcpsrv/alloc_engine.cc | 48 +- src/lib/dhcpsrv/alloc_engine.h | 11 +- src/lib/dhcpsrv/cfg_4o6.h | 31 ++ src/lib/dhcpsrv/cfg_db_access.cc | 6 +- src/lib/dhcpsrv/cfg_subnets4.cc | 16 + src/lib/dhcpsrv/cfgmgr.cc | 4 + src/lib/dhcpsrv/cql_connection.cc | 20 + src/lib/dhcpsrv/cql_exchange.cc | 418 +----------------- src/lib/dhcpsrv/cql_exchange.h | 54 --- src/lib/dhcpsrv/cql_lease_mgr.cc | 35 +- src/lib/dhcpsrv/lease.h | 4 +- src/lib/dhcpsrv/mysql_connection.cc | 7 +- src/lib/dhcpsrv/mysql_lease_mgr.cc | 65 ++- src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 38 +- src/lib/dhcpsrv/parsers/simple_parser4.cc | 6 + src/lib/dhcpsrv/parsers/simple_parser6.cc | 2 + src/lib/dhcpsrv/pgsql_connection.cc | 5 +- src/lib/dhcpsrv/pgsql_lease_mgr.cc | 70 +-- src/lib/dhcpsrv/sql_common.h | 4 +- src/lib/dhcpsrv/subnet.cc | 7 + src/lib/dhcpsrv/subnet.h | 17 + src/lib/dhcpsrv/subnet_selector.h | 12 +- .../dhcpsrv/tests/cql_lease_mgr_unittest.cc | 18 + .../tests/mysql_host_data_source_unittest.cc | 30 +- .../dhcpsrv/tests/mysql_lease_mgr_unittest.cc | 30 +- .../dhcpsrv/tests/pgsql_exchange_unittest.cc | 2 +- .../tests/pgsql_host_data_source_unittest.cc | 32 +- .../dhcpsrv/tests/pgsql_lease_mgr_unittest.cc | 106 +++-- .../tests/shared_network_parser_unittest.cc | 4 + src/lib/dhcpsrv/testutils/cql_schema.cc | 6 +- src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc | 6 + src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h | 3 + src/lib/dhcpsrv/testutils/mysql_schema.cc | 5 +- src/lib/dhcpsrv/testutils/pgsql_schema.cc | 4 +- src/share/database/scripts/cql/.gitignore | 1 - src/share/database/scripts/cql/Makefile.am | 2 +- .../database/scripts/cql/dhcpdb_create.cql | 4 +- src/share/database/scripts/mysql/.gitignore | 15 +- src/share/database/scripts/mysql/Makefile.am | 4 +- .../scripts/mysql/dhcpdb_create.mysql | 8 +- .../scripts/mysql/upgrade_6.0_to_7.0.sh.in | 31 ++ src/share/database/scripts/pgsql/Makefile.am | 2 +- .../scripts/pgsql/dhcpdb_create.pgsql | 1 - 67 files changed, 1154 insertions(+), 806 deletions(-) create mode 100644 src/share/database/scripts/mysql/upgrade_6.0_to_7.0.sh.in diff --git a/configure.ac b/configure.ac index 40dd9a2301..f76d64a66b 100644 --- a/configure.ac +++ b/configure.ac @@ -133,15 +133,15 @@ AX_ISC_CPP11 # Check for std::is_base_of support AC_MSG_CHECKING([for std::is_base_of]) AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [#include - class A {}; - class B : A {};] - [static_assert(std::is_base_of::value, "");])], - [AC_MSG_RESULT(yes) - AC_DEFINE([HAVE_IS_BASE_OF], [1], - [Define to 1 if std::is_base_of is available])], - [AC_MSG_RESULT(no)]) + [AC_LANG_PROGRAM( + [#include + class A {}; + class B : A {};] + [static_assert(std::is_base_of::value, "");])], + [AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_IS_BASE_OF], [1], + [Define to 1 if std::is_base_of is available])], + [AC_MSG_RESULT(no)]) dnl Determine if we are using GNU sed GNU_SED=no @@ -408,7 +408,6 @@ case "$host" in ;; esac - # Kea-shell is written in python. It can work with python 2.7 or any 3.x. # It may likely work with earlier versions, but 2.7 was the oldest one we tested # it with. We require python only if kea-shell was enabled. It is disabled @@ -893,9 +892,9 @@ if test "x$enable_gtest" = "xyes" ; then AC_MSG_ERROR([no gtest source but it was selected]) fi else - if test ! -d $GTEST_SOURCE/src -a -d $GTEST_SOURCE/googletest; then - GTEST_SOURCE=$GTEST_SOURCE/googletest - fi + if test ! -d $GTEST_SOURCE/src -a -d $GTEST_SOURCE/googletest; then + GTEST_SOURCE=$GTEST_SOURCE/googletest + fi AC_CHECK_FILES([$GTEST_SOURCE/src/gtest-all.cc] [$GTEST_SOURCE/src/gtest_main.cc], [have_gtest_source=yes], @@ -905,7 +904,7 @@ if test "x$enable_gtest" = "xyes" ; then GTEST_LDADD="\$(top_builddir)/ext/gtest/libgtest.a" DISTCHECK_GTEST_CONFIGURE_FLAG="--with-gtest-source=$GTEST_SOURCE" GTEST_INCLUDES="-I$GTEST_SOURCE -I$GTEST_SOURCE/include" - GTEST_VERSION="`basename $GTEST_SOURCE`" + GTEST_VERSION="`basename $GTEST_SOURCE`" fi if test "$gtest_path" != "no" ; then @@ -970,15 +969,15 @@ if test $enable_gtest != "no"; then CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES $GTEST_INCLUDES" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( - [#include - #include - void foo() { - boost::shared_ptr bar; - ASSERT_TRUE(bar); + [#include + #include + void foo() { + boost::shared_ptr bar; + ASSERT_TRUE(bar); }], - [return 0;])], - [AC_MSG_RESULT(yes)], - [AC_MSG_ERROR([XXX_TRUE() Google Test macros won't compile; the most likely reason is that a later version of Google Test is required])]) + [return 0;])], + [AC_MSG_RESULT(yes)], + [AC_MSG_ERROR([XXX_TRUE() Google Test macros won't compile; the most likely reason is that a later version of Google Test is required])]) CPPFLAGS=$CPPFLAGS_SAVED fi @@ -989,21 +988,21 @@ if test $enable_gtest != "no"; then CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES $GTEST_INCLUDES" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( - [#include - #include - #include - #include - std::string nodiff(std::string text) { - std::vector lines; - boost::split(lines, text, boost::is_any_of("\n")); - using namespace testing::internal; - return (edit_distance::CreateUnifiedDiff(lines, lines)); - }], - [return 0;])], - [AC_MSG_RESULT(yes) - AC_DEFINE([HAVE_CREATE_UNIFIED_DIFF], [1], - [Define to 1 if gtest defines edit_distance::CreateUnifiedDiff])], - [AC_MSG_RESULT(no)]) + [#include + #include + #include + #include + std::string nodiff(std::string text) { + std::vector lines; + boost::split(lines, text, boost::is_any_of("\n")); + using namespace testing::internal; + return (edit_distance::CreateUnifiedDiff(lines, lines)); + }], + [return 0;])], + [AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_CREATE_UNIFIED_DIFF], [1], + [Define to 1 if gtest defines edit_distance::CreateUnifiedDiff])], + [AC_MSG_RESULT(no)]) CPPFLAGS=$CPPFLAGS_SAVED fi @@ -1039,7 +1038,7 @@ AC_CHECK_FUNCS([pselect]) # code will be updated by the time we really need it. AC_CHECK_HEADERS(sys/devpoll.h, ac_cv_have_devpoll=yes, ac_cv_have_devpoll=no) if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GXX" = "Xyes"; then - CPPFLAGS="$CPPFLAGS -DBOOST_ASIO_DISABLE_DEV_POLL=1" + CPPFLAGS="$CPPFLAGS -DBOOST_ASIO_DISABLE_DEV_POLL=1" fi # @@ -1332,6 +1331,7 @@ AC_CONFIG_FILES([Makefile src/share/database/scripts/mysql/upgrade_4.1_to_5.0.sh src/share/database/scripts/mysql/upgrade_5.0_to_5.1.sh src/share/database/scripts/mysql/upgrade_5.1_to_6.0.sh + src/share/database/scripts/mysql/upgrade_6.0_to_7.0.sh src/share/database/scripts/pgsql/Makefile src/share/database/scripts/pgsql/upgrade_1.0_to_2.0.sh src/share/database/scripts/pgsql/upgrade_2.0_to_3.0.sh @@ -1503,9 +1503,9 @@ if test "$CQL_CPPFLAGS" != "" ; then cat >> config.report << END Cassandra CQL: - CQL_VERSION: ${CQL_VERSION} - CQL_CPPFLAGS: ${CQL_CPPFLAGS} - CQL_LIBS: ${CQL_LIBS} + CQL_VERSION: ${CQL_VERSION} + CQL_CPPFLAGS: ${CQL_CPPFLAGS} + CQL_LIBS: ${CQL_LIBS} END else cat >> config.report << END diff --git a/src/bin/admin/tests/dhcpdb_create_1.0.cql b/src/bin/admin/tests/dhcpdb_create_1.0.cql index 577f2ae277..b6cf064ffd 100644 --- a/src/bin/admin/tests/dhcpdb_create_1.0.cql +++ b/src/bin/admin/tests/dhcpdb_create_1.0.cql @@ -47,7 +47,7 @@ -- Table `lease4` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS lease4 ( - address int, + address bigint, hwaddr blob, client_id blob, valid_lifetime bigint, diff --git a/src/bin/admin/tests/dhcpdb_create_1.0.mysql b/src/bin/admin/tests/dhcpdb_create_1.0.mysql index b4823afbff..9f68439ffe 100644 --- a/src/bin/admin/tests/dhcpdb_create_1.0.mysql +++ b/src/bin/admin/tests/dhcpdb_create_1.0.mysql @@ -123,7 +123,7 @@ COMMIT; # # Portability # =========== -# The "ENGINE = INNODB" on some tables is not portablea to another database +# The "ENGINE = INNODB" on some tables is not portable to another database # and will need to be removed. # # Some columns contain binary data so are stored as VARBINARY instead of diff --git a/src/bin/admin/tests/mysql_tests.sh.in b/src/bin/admin/tests/mysql_tests.sh.in index e5233c338d..6ca2e526f3 100644 --- a/src/bin/admin/tests/mysql_tests.sh.in +++ b/src/bin/admin/tests/mysql_tests.sh.in @@ -189,7 +189,7 @@ mysql_upgrade_test() { mysql -u$db_user -p$db_password $db_name < @abs_top_srcdir@/src/bin/admin/tests/dhcpdb_create_1.0.mysql # Sanity check - verify that it reports version 1.0. - version=$(${keaadmin} lease-version mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir) + version=$(${keaadmin} lease-version mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir) assert_str_eq "1.0" ${version} "Expected kea-admin to return %s, returned value was %s" @@ -382,9 +382,16 @@ EOF ERRCODE=$? assert_eq 0 $ERRCODE "select user_context from dhcp6_options failed. (expected status code %d, returned %d)" - # Verify upgraded schema reports version 6.0 + # table: lease4 (upgrade 6.0 -> 7.0) + qry="SELECT address FROM lease4" + text=`mysql_execute "${qry}"` + ERRCODE=$? + assert_eq 0 $ERRCODE "lease4 table is missing or broken. (expected status code %d, returned %d)" + + # Verify upgraded schema reports version 7. + version=$(${keaadmin} lease-version mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir) - assert_str_eq "6.0" ${version} "Expected kea-admin to return %s, returned value was %s" + assert_str_eq "7.0" ${version} "Expected kea-admin to return %s, returned value was %s" # Let's wipe the whole database mysql_wipe diff --git a/src/bin/d2/d2_cfg_mgr.cc b/src/bin/d2/d2_cfg_mgr.cc index 9a94b08643..cac492a37d 100644 --- a/src/bin/d2/d2_cfg_mgr.cc +++ b/src/bin/d2/d2_cfg_mgr.cc @@ -352,7 +352,7 @@ D2CfgMgr::buildParams(isc::data::ConstElementPtr params_config) { // Fetch the parameters in the config, performing any logical // validation required. - asiolink::IOAddress ip_address(0); + asiolink::IOAddress ip_address(0U); uint32_t port = 0; uint32_t dns_server_timeout = 0; dhcp_ddns::NameChangeProtocol ncr_protocol = dhcp_ddns::NCR_UDP; diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h index f9598041d1..2c124dac04 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.h +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h @@ -123,7 +123,7 @@ class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv { /// @brief Callback that will be called from iface_mgr when data /// is received over control socket. /// - /// This static callback method is called from IfaceMgr::receive6() method, + /// This static callback method is called from IfaceMgr::receive4() method, /// when there is a new command or configuration sent over control socket /// (that was sent from some yet unspecified sender). static void sessionReader(void); diff --git a/src/bin/dhcp4/dhcp4_lexer.ll b/src/bin/dhcp4/dhcp4_lexer.ll index d5d88ff41a..53277e5583 100644 --- a/src/bin/dhcp4/dhcp4_lexer.ll +++ b/src/bin/dhcp4/dhcp4_lexer.ll @@ -36,7 +36,7 @@ unsigned int comment_start_line = 0; using namespace isc::dhcp; -}; +} /* To avoid the call to exit... oops! */ #define YY_FATAL_ERROR(msg) isc::dhcp::Parser4Context::fatal(msg) @@ -410,6 +410,46 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } +\"tcp-nodelay\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::LEASE_DATABASE: + case isc::dhcp::Parser4Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp4Parser::make_TCP_NODELAY(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("tcp-nodelay", driver.loc_); + } +} + +\"reconnect-wait-time\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::LEASE_DATABASE: + case isc::dhcp::Parser4Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp4Parser::make_RECONNECT_WAIT_TIME(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("reconnect-wait-time", driver.loc_); + } +} + +\"request-timeout\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::LEASE_DATABASE: + case isc::dhcp::Parser4Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp4Parser::make_REQUEST_TIMEOUT(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("request-timeout", driver.loc_); + } +} + +\"tcp-keepalive\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::LEASE_DATABASE: + case isc::dhcp::Parser4Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp4Parser::make_TCP_KEEPALIVE(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("tcp-keepalive", driver.loc_); + } +} + \"connect-timeout\" { switch(driver.ctx_) { case isc::dhcp::Parser4Context::LEASE_DATABASE: @@ -985,7 +1025,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } - \"parameters\" { switch(driver.ctx_) { case isc::dhcp::Parser4Context::HOOKS_LIBRARIES: @@ -1382,6 +1421,33 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } +\"v4-psid-offset\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::SUBNET4: + return isc::dhcp::Dhcp4Parser::make_SUBNET_V4_PSID_OFFSET(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("v4-psid-offset", driver.loc_); + } +} + +\"v4-psid-len\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::SUBNET4: + return isc::dhcp::Dhcp4Parser::make_SUBNET_V4_PSID_LEN(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("v4-psid-len", driver.loc_); + } +} + +\"v4-excluded-psids\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::SUBNET4: + return isc::dhcp::Dhcp4Parser::make_SUBNET_V4_EXCLUDED_PSIDS(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("v4-excluded-psids", driver.loc_); + } +} + \"echo-client-id\" { switch(driver.ctx_) { case isc::dhcp::Parser4Context::DHCP4: @@ -1441,8 +1507,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } - - {JSONString} { /* A string has been matched. It contains the actual string and single quotes. We need to get those quotes out of the way and just use its content, e.g. diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index fef6ef62dc..6486fac74a 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -198,7 +198,7 @@ the message. % DHCP4_DHCP4O6_RECEIVING receiving DHCPv4o6 packet from DHCPv6 server This debug message is printed when the server is receiving a DHCPv4o6 -from the DHCPv6 server over inter-process communication socket. +from the DHCPv4 server over inter-process communication socket. % DHCP4_DHCP4O6_RESPONSE_DATA %1: responding with packet %2 (type %3), packet details: %4 A debug message including the detailed data about the packet being diff --git a/src/bin/dhcp4/dhcp4_parser.yy b/src/bin/dhcp4/dhcp4_parser.yy index 9c5f94262a..557e350768 100644 --- a/src/bin/dhcp4/dhcp4_parser.yy +++ b/src/bin/dhcp4/dhcp4_parser.yy @@ -81,6 +81,10 @@ using namespace std; LFC_INTERVAL "lfc-interval" READONLY "readonly" CONNECT_TIMEOUT "connect-timeout" + TCP_NODELAY "tcp-nodelay" + RECONNECT_WAIT_TIME "reconnect-wait-time" + REQUEST_TIMEOUT "request-timeout" + TCP_KEEPALIVE "tcp-keepalive" CONTACT_POINTS "contact-points" KEYSPACE "keyspace" @@ -92,6 +96,9 @@ using namespace std; SUBNET_4O6_INTERFACE "4o6-interface" SUBNET_4O6_INTERFACE_ID "4o6-interface-id" SUBNET_4O6_SUBNET "4o6-subnet" + SUBNET_V4_PSID_OFFSET "v4-psid-offset" + SUBNET_V4_PSID_LEN "v4-psid-len" + SUBNET_V4_EXCLUDED_PSIDS "v4-excluded-psids" OPTION_DEF "option-def" OPTION_DATA "option-data" NAME "name" @@ -470,7 +477,6 @@ match_client_id: MATCH_CLIENT_ID COLON BOOLEAN { ctx.stack_.back()->set("match-client-id", match); }; - interfaces_config: INTERFACES_CONFIG { ElementPtr i(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("interfaces-config", i); @@ -582,6 +588,10 @@ database_map_param: database_type | lfc_interval | readonly | connect_timeout + | tcp_nodelay + | reconnect_wait_time + | request_timeout + | tcp_keepalive | contact_points | keyspace | unknown_map_entry @@ -657,6 +667,26 @@ connect_timeout: CONNECT_TIMEOUT COLON INTEGER { ctx.stack_.back()->set("connect-timeout", n); }; +tcp_nodelay: TCP_NODELAY COLON BOOLEAN { + ElementPtr n(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("tcp-nodelay", n); +}; + +reconnect_wait_time: RECONNECT_WAIT_TIME COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("reconnect-wait-time", n); +}; + +request_timeout: REQUEST_TIMEOUT COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("request-timeout", n); +}; + +tcp_keepalive: TCP_KEEPALIVE COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("tcp-keepalive", n); +}; + contact_points: CONTACT_POINTS { ctx.enter(ctx.NO_KEYWORD); } COLON STRING { @@ -673,7 +703,6 @@ keyspace: KEYSPACE { ctx.leave(); }; - host_reservation_identifiers: HOST_RESERVATION_IDENTIFIERS { ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("host-reservation-identifiers", l); @@ -927,6 +956,9 @@ subnet4_param: valid_lifetime | subnet_4o6_interface | subnet_4o6_interface_id | subnet_4o6_subnet + | subnet_v4_psid_offset + | subnet_v4_psid_len + | subnet_v4_excluded_psids | user_context | comment | unknown_map_entry @@ -964,6 +996,28 @@ subnet_4o6_subnet: SUBNET_4O6_SUBNET { ctx.leave(); }; +subnet_v4_psid_offset: SUBNET_V4_PSID_OFFSET COLON INTEGER { + ElementPtr offset(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("v4-psid-offset", offset); +}; + +subnet_v4_psid_len: SUBNET_V4_PSID_LEN COLON INTEGER { + ElementPtr psid_len(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("v4-psid-len", psid_len); +}; + +// This defines the "v4-excluded-psids": [ ... ] entry that may appear +// in subnet4 entries. +subnet_v4_excluded_psids: SUBNET_V4_EXCLUDED_PSIDS { + ElementPtr l(new ListElement(ctx.loc2pos(@1))); + ctx.stack_.back()->set("v4-excluded-psids", l); + ctx.stack_.push_back(l); + ctx.enter(ctx.NO_KEYWORD); +} COLON LSQUARE_BRACKET list_content RSQUARE_BRACKET { + ctx.stack_.pop_back(); + ctx.leave(); +}; + interface: INTERFACE { ctx.enter(ctx.NO_KEYWORD); } COLON STRING { @@ -1826,7 +1880,7 @@ replace_client_name: REPLACE_CLIENT_NAME { replace_client_name_value: WHEN_PRESENT { - $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); + $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); } | NEVER { $$ = ElementPtr(new StringElement("never", ctx.loc2pos(@1))); diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 03b3873d73..3b4455d3d4 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -650,6 +650,10 @@ Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query, bool& drop) const { } } + selector.address_plus_port_ = query->getAddressPlusPort(); + selector.psid_offset_ = query->getPsidOffset(); + selector.psid_len_ = query->getPsidLen(); + CfgMgr& cfgmgr = CfgMgr::instance(); subnet = cfgmgr.getCurrentCfg()->getCfgSubnets4()->selectSubnet4o6(selector); @@ -1047,6 +1051,7 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) { callout_handle->getArgument("query4", query); } + updateDhcpV4AddressPlusPortPacket(query); try { switch (query->getType()) { case DHCPDISCOVER: @@ -1153,6 +1158,36 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) { } } +void Dhcpv4Srv::updateDhcpV4AddressPlusPortPacket(Pkt4Ptr& query) { + OptionUint8ArrayPtr option_prl = boost::dynamic_pointer_cast + (query->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST)); + if (option_prl) { + // PRL option exists, so check if the portparams option code is + // included in it. + const std::vector& + requested_opts = option_prl->getValues(); + if (std::find(requested_opts.begin(), requested_opts.end(), + DHO_V4_PORTPARAMS) != requested_opts.end()) { + // Client has requested DHO_V4_PORTPARAMS via Parameter Request + // List option. + query->setAddressPlusPort(true); + OptionPtr portparams = query->getOption(DHO_V4_PORTPARAMS); + if (portparams) { + OptionCustomPtr oc = boost::dynamic_pointer_cast(portparams); + if (oc) { + // Read offset for address plus port + query->setPsidOffset(PSIDOffset(oc->readInteger(0)).asUint8()); + PSIDTuple psid; + // Read PSID length / PSID value for address plus port + psid = oc->readPsid(1); + query->setPsidLen(psid.first.asUint8()); + query->setPsid(psid.second.asUint16()); + } + } + } + } +} + string Dhcpv4Srv::srvidToString(const OptionPtr& srvid) { if (!srvid) { @@ -1767,11 +1802,11 @@ Dhcpv4Srv::assignLease(Dhcpv4Exchange& ex) { OptionCustom>(query->getOption(DHO_DHCP_REQUESTED_ADDRESS)); IOAddress hint(IOAddress::IPV4_ZERO_ADDRESS()); if (opt_requested_address) { - hint = opt_requested_address->readAddress(); - + hint = IOAddress(opt_requested_address->readAddress().toText(), + query->getPsidOffset(), query->getPsidLen(), query->getPsid()); } else if (!query->getCiaddr().isV4Zero()) { - hint = query->getCiaddr(); - + hint = IOAddress(query->getCiaddr().toText(), + query->getPsidOffset(), query->getPsidLen(), query->getPsid()); } HWAddrPtr hwaddr = query->getHWAddr(); @@ -2026,6 +2061,16 @@ Dhcpv4Srv::assignLease(Dhcpv4Exchange& ex) { resp->addOption(t2); } + if (subnet->get4o6().enabled() && subnet->get4o6().getPsidLen() && + subnet->get4o6().getPsidLen() == lease->addr_.getPsidLen()) { + OptionDefinitionPtr portparams_def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE, + DHO_V4_PORTPARAMS); + OptionCustomPtr portparams(new OptionCustom(*portparams_def, Option::V4)); + portparams->writeInteger(lease->addr_.getPsidOffset(), 0); + portparams->writePsid(PSIDLen(lease->addr_.getPsidLen()), PSID(lease->addr_.getPsid()), 1); + resp->addOption(portparams); + } + // Create NameChangeRequests if DDNS is enabled and this is a // real allocation. if (!fake_allocation && CfgMgr::instance().ddnsEnabled()) { diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h index 2bf8c1c7da..91782488dc 100644 --- a/src/bin/dhcp4/dhcp4_srv.h +++ b/src/bin/dhcp4/dhcp4_srv.h @@ -261,6 +261,11 @@ class Dhcpv4Srv : public Daemon { /// @param rsp A pointer to the response void processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp); + /// @brief Update DHCPv4 packet with address plus port information. + /// + /// @param query A pointer to the packet to be updated. + void updateDhcpV4AddressPlusPortPacket(Pkt4Ptr& query); + /// @brief Instructs the server to shut down. void shutdown(); diff --git a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc index 1ac0981a51..bae5d2c60a 100644 --- a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc @@ -92,7 +92,7 @@ class NakedControlledDhcpv4Srv: public ControlledDhcpv4Srv { /// @brief Default control connection timeout. const size_t DEFAULT_CONNECTION_TIMEOUT = 10; -/// @brief Fixture class intended for testin control channel in the DHCPv4Srv +/// @brief Fixture class intended for testing control channel in the DHCPv4Srv class CtrlChannelDhcpv4SrvTest : public ::testing::Test { public: diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc index dceb6367fb..6b5aed2055 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc @@ -571,8 +571,8 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) { return (answer); } } catch (const std::exception& ex) { - return (isc::config::createAnswer(1, "Failed to process configuration:" - + string(ex.what()))); + return (isc::config::createAnswer(1, "Failed to process configuration:" + + string(ex.what()))); } // Re-open lease and host database with new parameters. @@ -582,8 +582,8 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) { cfg_db->createManagers(); } catch (const std::exception& ex) { - return (isc::config::createAnswer(1, "Unable to open database: " - + std::string(ex.what()))); + return (isc::config::createAnswer(1, "Unable to open database: " + + std::string(ex.what()))); } // Regenerate server identifier if needed. diff --git a/src/bin/dhcp6/dhcp6_hooks.dox b/src/bin/dhcp6/dhcp6_hooks.dox index 45afd6cb38..ec8cb952eb 100644 --- a/src/bin/dhcp6/dhcp6_hooks.dox +++ b/src/bin/dhcp6/dhcp6_hooks.dox @@ -273,7 +273,7 @@ to the end of this list. - name: @b response6, type: isc::dhcp::Pkt6Ptr, direction: in/out - @b Description: This callout is executed when server's response - is about to be send back to the client. The sole argument "response6" + is about to be sent back to the client. The sole argument "response6" contains a pointer to an @c isc::dhcp::Pkt6 object that contains the packet, with set source and destination addresses, interface over which it will be send, list of all options and relay information. All fields @@ -296,7 +296,7 @@ to the end of this list. - name: @b response6, type: isc::dhcp::Pkt6Ptr, direction: in/out - @b Description: This callout is executed when server's response is - assembled into binary form and is about to be send back to the + assembled into binary form and is about to be sent back to the client. The sole argument "response6" contains a pointer to an @c isc::dhcp::Pkt6 object that contains the packet, with set source and destination addresses, interface over which it will be sent, list of diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index 58808613ea..af3c7ae773 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -36,7 +36,7 @@ unsigned int comment_start_line = 0; using namespace isc::dhcp; -}; +} /* To avoid the call to exit... oops! */ #define YY_FATAL_ERROR(msg) isc::dhcp::Parser6Context::fatal(msg) @@ -575,6 +575,46 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } +\"tcp-nodelay\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp6Parser::make_TCP_NODELAY(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("tcp-nodelay", driver.loc_); + } +} + +\"reconnect-wait-time\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp6Parser::make_RECONNECT_WAIT_TIME(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("reconnect-wait-time", driver.loc_); + } +} + +\"request-timeout\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp6Parser::make_REQUEST_TIMEOUT(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("request-timeout", driver.loc_); + } +} + +\"tcp-keepalive\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp6Parser::make_TCP_KEEPALIVE(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("tcp-keepalive", driver.loc_); + } +} + \"connect-timeout\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::LEASE_DATABASE: @@ -1239,7 +1279,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } - \"parameters\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::HOOKS_LIBRARIES: diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index 5fd8df6db6..b70f402669 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -69,6 +69,10 @@ using namespace std; LFC_INTERVAL "lfc-interval" READONLY "readonly" CONNECT_TIMEOUT "connect-timeout" + TCP_NODELAY "tcp-nodelay" + RECONNECT_WAIT_TIME "reconnect-wait-time" + REQUEST_TIMEOUT "request-timeout" + TCP_KEEPALIVE "tcp-keepalive" CONTACT_POINTS "contact-points" KEYSPACE "keyspace" @@ -513,7 +517,6 @@ re_detect: RE_DETECT COLON BOOLEAN { ctx.stack_.back()->set("re-detect", b); }; - lease_database: LEASE_DATABASE { ElementPtr i(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("lease-database", i); @@ -552,6 +555,10 @@ database_map_param: database_type | lfc_interval | readonly | connect_timeout + | tcp_nodelay + | reconnect_wait_time + | request_timeout + | tcp_keepalive | contact_points | keyspace | unknown_map_entry @@ -627,6 +634,26 @@ connect_timeout: CONNECT_TIMEOUT COLON INTEGER { ctx.stack_.back()->set("connect-timeout", n); }; +tcp_nodelay: TCP_NODELAY COLON BOOLEAN { + ElementPtr n(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("tcp-nodelay", n); +}; + +reconnect_wait_time: RECONNECT_WAIT_TIME COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("reconnect-wait-time", n); +}; + +request_timeout: REQUEST_TIMEOUT COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("request-timeout", n); +}; + +tcp_keepalive: TCP_KEEPALIVE COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("tcp-keepalive", n); +}; + contact_points: CONTACT_POINTS { ctx.enter(ctx.NO_KEYWORD); } COLON STRING { @@ -1910,7 +1937,7 @@ replace_client_name: REPLACE_CLIENT_NAME { replace_client_name_value: WHEN_PRESENT { - $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); + $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); } | NEVER { $$ = ElementPtr(new StringElement("never", ctx.loc2pos(@1))); diff --git a/src/bin/dhcp6/tests/shared_network_unittest.cc b/src/bin/dhcp6/tests/shared_network_unittest.cc index 32fa5d53ec..e521451bdc 100644 --- a/src/bin/dhcp6/tests/shared_network_unittest.cc +++ b/src/bin/dhcp6/tests/shared_network_unittest.cc @@ -426,7 +426,7 @@ const char* NETWORKS_CONFIG[] = { " }" " ]," " \"subnet6\": [" - " \{" + " {" " \"subnet\": \"3000::/96\"," " \"id\": 1000," " \"interface\": \"eth0\"," diff --git a/src/lib/asiolink/io_address.cc b/src/lib/asiolink/io_address.cc index dae8074066..69bc305012 100644 --- a/src/lib/asiolink/io_address.cc +++ b/src/lib/asiolink/io_address.cc @@ -28,7 +28,19 @@ namespace asiolink { // XXX: we cannot simply construct the address in the initialization list, // because we'd like to throw our own exception on failure. -IOAddress::IOAddress(const std::string& address_str) { +IOAddress::IOAddress(const std::string& address_str) : + offset_(0), psid_len_(0), psid_(0) { + boost::system::error_code err; + asio_address_ = ip::address::from_string(address_str, err); + if (err) { + isc_throw(IOError, "Failed to convert string to address '" + << address_str << "': " << err.message()); + } +} + +IOAddress::IOAddress(const std::string& address_str, uint8_t offset, + uint8_t psid_len, uint16_t psid) : + offset_(offset), psid_len_(psid_len), psid_(psid) { boost::system::error_code err; asio_address_ = ip::address::from_string(address_str, err); if (err) { @@ -38,12 +50,30 @@ IOAddress::IOAddress(const std::string& address_str) { } IOAddress::IOAddress(const boost::asio::ip::address& asio_address) : - asio_address_(asio_address) -{} + asio_address_(asio_address), offset_(0), psid_len_(0), psid_(0) { +} -IOAddress::IOAddress(uint32_t v4address): - asio_address_(boost::asio::ip::address_v4(v4address)) { +IOAddress::IOAddress(uint32_t v4address) : + asio_address_(boost::asio::ip::address_v4(v4address)), + offset_(0), psid_len_(0), psid_(0) { +} +IOAddress::IOAddress(uint32_t v4address, uint8_t offset, uint8_t psid_len, + uint16_t psid) : asio_address_(boost::asio::ip::address_v4(v4address)), + offset_(offset), psid_len_(psid_len), psid_(psid) { +} + +IOAddress::IOAddress(uint64_t v4address) : + asio_address_(boost::asio::ip::address_v4(static_cast(v4address))), + offset_(0), psid_len_(0), psid_(0) { + offset_ = static_cast(v4address >> + (8 * (sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint8_t)))); + psid_len_ = static_cast((v4address << + (8 * sizeof(uint8_t))) >> + (8 * (sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint8_t)))); + psid_ = static_cast((v4address << + (8 * (sizeof(uint8_t) + sizeof(uint8_t)))) >> + (8 * (sizeof(uint32_t) + sizeof(uint16_t)))); } string @@ -117,6 +147,21 @@ IOAddress::toUint32() const { } } +uint64_t +IOAddress::addressPlusPortToUint64() const { + if (asio_address_.is_v4()) { + uint64_t addr = offset_; + addr = (addr << (8 * sizeof(uint8_t))) + psid_len_; + addr = (addr << (8 * sizeof(uint16_t))) + psid_; + addr = (addr << (8 * sizeof(uint32_t))) + + static_cast(asio_address_.to_v4().to_ulong()); + return addr; + } else { + isc_throw(BadValue, "Can't convert " << toText() + << " address to IPv4."); + } +} + std::ostream& operator<<(std::ostream& os, const IOAddress& address) { os << address.toText(); @@ -158,18 +203,26 @@ IOAddress::subtract(const IOAddress& a, const IOAddress& b) { } IOAddress -IOAddress::increase(const IOAddress& addr) { +IOAddress::increase(const IOAddress& addr, uint8_t, uint8_t psid_len) { + uint16_t increment = 0; + if (psid_len) { + increment = ((addr.psid_ + 1) & ((1 << psid_len) - 1)); + } + std::vector packed(addr.toBytes()); - // Start increasing the least significant byte - for (int i = packed.size() - 1; i >= 0; --i) { - // if we haven't overflowed (0xff -> 0x0), than we are done - if (++packed[i] != 0) { - break; + if (!increment) { + // Start increasing the least significant byte + for (int i = packed.size() - 1; i >= 0; --i) { + // if we haven't overflowed (0xff -> 0x0), than we are done + if (++packed[i] != 0) { + break; + } } } - return (IOAddress::fromBytes(addr.getFamily(), &packed[0])); + return IOAddress(IOAddress::fromBytes(addr.getFamily(), &packed[0]).toText(), + 0, 0, increment); } diff --git a/src/lib/asiolink/io_address.h b/src/lib/asiolink/io_address.h index 42f09d7a9f..4d6c0eeee0 100644 --- a/src/lib/asiolink/io_address.h +++ b/src/lib/asiolink/io_address.h @@ -38,20 +38,20 @@ namespace asiolink { /// separators. static constexpr size_t V6ADDRESS_TEXT_MAX_LEN = 39u; -/// \brief The \c IOAddress class represents an IP addresses (version +/// @brief The \c IOAddress class represents an IP addresses (version /// agnostic) /// /// This class is a wrapper for the ASIO \c ip::address class. class IOAddress { public: /// - /// \name Constructors and Destructor + /// @name Constructors and Destructor /// /// This class is copyable. We use default versions of copy constructor /// and the assignment operator. /// We use the default destructor. //@{ - /// \brief Constructor from string. + /// @brief Constructor from string. /// /// This constructor converts a textual representation of IPv4 and IPv6 /// addresses into an IOAddress object. @@ -60,17 +60,34 @@ class IOAddress { /// This constructor allocates memory for the object, and if that fails /// a corresponding standard exception will be thrown. /// - /// \param address_str Textual representation of address. + /// @param address_str Textual representation of address. IOAddress(const std::string& address_str); - /// \brief Constructor from an ASIO \c ip::address object. + /// @brief Constructor from string. + /// + /// This constructor converts a textual representation of IPv4, IPV4 + /// address plus port and IPv6 + /// addresses into an IOAddress object. + /// If \c address_str is not a valid representation of any type of + /// address, an exception of class \c IOError will be thrown. + /// This constructor allocates memory for the object, and if that fails + /// a corresponding standard exception will be thrown. + /// + /// @param address_str Textual representation of address. + /// @param offset value of offset in IPv4 address plus port. + /// @param psid_len value of psid_len in IPv4 address plus port. + /// @param psid value of psid in IPv4 address plus port. + IOAddress(const std::string& address_str, uint8_t offset, uint8_t psid_len, + uint16_t psid); + + /// @brief Constructor from an ASIO \c ip::address object. /// /// This constructor is intended to be used within the wrapper /// implementation; user applications of the wrapper API won't use it. /// /// This constructor never throws an exception. /// - /// \param asio_address The ASIO \c ip::address to be converted. + /// @param asio_address The ASIO \c ip::address to be converted. IOAddress(const boost::asio::ip::address& asio_address); //@} @@ -83,112 +100,136 @@ class IOAddress { /// @param v4address IPv4 address represented by uint32_t IOAddress(uint32_t v4address); - /// \brief Convert the address to a string. + /// @brief Constructor for ip::address_v4 address plus port object. + /// + /// This constructor is intended to be used when constructing + /// IPv4 address plus port out of uint32_t type, uint8_t offset, + /// uint8_t psid_len and uint16_t psid. Passed value for address + /// must be in network byte order + /// + /// @param v4address IPv4 address represented by uint32_t + /// @param offset PSID offset (see https://tools.ietf.org/html/rfc7618) + /// @param psid_len PSID length + /// @param psid PSID value + IOAddress(uint32_t v4address, + uint8_t offset, + uint8_t psid_len, + uint16_t psid); + + /// @brief Constructor for ip::address_v4 address plus port object. + /// + /// This constructor is intended to be used when constructing + /// IPv4 address plus port out of uint64_t type. + /// + /// @param v4address IPv4 address plus port represented by uint64_t + IOAddress(uint64_t v4address); + + /// @brief Convert the address to a string. /// /// This method is basically expected to be exception free, but /// generating the string will involve resource allocation, /// and if it fails the corresponding standard exception will be thrown. /// - /// \return A string representation of the address. + /// @return A string representation of the address. std::string toText() const; - /// \brief Returns the address family + /// @brief Returns the address family /// - /// \return AF_INET for IPv4 or AF_INET6 for IPv6. + /// @return AF_INET for IPv4 or AF_INET6 for IPv6. short getFamily() const; - /// \brief Convenience function to check for an IPv4 address + /// @brief Convenience function to check for an IPv4 address /// - /// \return true if the address is a V4 address + /// @return true if the address is a V4 address bool isV4() const { return (asio_address_.is_v4()); } - /// \brief Convenience function to check if it is an IPv4 zero address. + /// @brief Convenience function to check if it is an IPv4 zero address. /// - /// \return true if the address is the zero IPv4 address. + /// @return true if the address is the zero IPv4 address. bool isV4Zero() const { return (equals(IPV4_ZERO_ADDRESS())); } - /// \brief Convenience function to check if it is an IPv4 broadcast + /// @brief Convenience function to check if it is an IPv4 broadcast /// address. /// - /// \return true if the address is the broadcast IPv4 address. + /// @return true if the address is the broadcast IPv4 address. bool isV4Bcast() const { return (equals(IPV4_BCAST_ADDRESS())); } - /// \brief Convenience function to check for an IPv6 address + /// @brief Convenience function to check for an IPv6 address /// - /// \return true if the address is a V6 address + /// @return true if the address is a V6 address bool isV6() const { return (asio_address_.is_v6()); } - /// \brief Convenience function to check if it is an IPv4 zero address. + /// @brief Convenience function to check if it is an IPv4 zero address. /// - /// \return true if the address is the zero IPv4 address. + /// @return true if the address is the zero IPv4 address. bool isV6Zero() const { return (equals(IPV6_ZERO_ADDRESS())); } - /// \brief checks whether and address is IPv6 and is link-local + /// @brief checks whether and address is IPv6 and is link-local /// - /// \return true if the address is IPv6 link-local, false otherwise + /// @return true if the address is IPv6 link-local, false otherwise bool isV6LinkLocal() const; - /// \brief checks whether and address is IPv6 and is multicast + /// @brief checks whether and address is IPv6 and is multicast /// - /// \return true if the address is IPv6 multicast, false otherwise + /// @return true if the address is IPv6 multicast, false otherwise bool isV6Multicast() const; - /// \brief Creates an address from over wire data. + /// @brief Creates an address from over wire data. /// /// \param family AF_INET for IPv4 or AF_INET6 for IPv6. /// \param data pointer to first char of data /// - /// \return Created IOAddress object + /// @return Created IOAddress object static IOAddress fromBytes(short family, const uint8_t* data); - /// \brief Return address as set of bytes + /// @brief Return address as set of bytes /// - /// \return Contents of the address as a set of bytes in network-byte + /// @return Contents of the address as a set of bytes in network-byte /// order. std::vector toBytes() const; - /// \brief Compare addresses for equality + /// @brief Compare addresses for equality /// - /// \param other Address to compare against. + /// @param other Address to compare against. /// - /// \return true if addresses are equal, false if not. + /// @return true if addresses are equal, false if not. bool equals(const IOAddress& other) const { return (asio_address_ == other.asio_address_); } - /// \brief Compare addresses for equality + /// @brief Compare addresses for equality /// - /// \param other Address to compare against. + /// @param other Address to compare against. /// - /// \return true if addresses are equal, false if not. + /// @return true if addresses are equal, false if not. bool operator==(const IOAddress& other) const { return equals(other); } - /// \brief Compare addresses for inequality + /// @brief Compare addresses for inequality /// - /// \param other Address to compare against. + /// @param other Address to compare against. /// - /// \return false if addresses are equal, true if not. + /// @return false if addresses are equal, true if not. bool nequals(const IOAddress& other) const { return (!equals(other)); } - /// \brief Checks if one address is smaller than the other + /// @brief Checks if one address is smaller than the other /// - /// \param other Address to compare against. + /// @param other Address to compare against. /// - /// \return true if this address is smaller than the other address. + /// @return true if this address is smaller than the other address. /// /// It is useful for comparing which address is bigger. /// Operations within one protocol family are obvious. @@ -205,11 +246,11 @@ class IOAddress { return (this->getFamily() < other.getFamily()); } - /// \brief Checks if one address is smaller or equal than the other + /// @brief Checks if one address is smaller or equal than the other /// - /// \param other Address to compare against. + /// @param other Address to compare against. /// - /// \return true if this address is smaller than the other address. + /// @return true if this address is smaller than the other address. bool smallerEqual(const IOAddress& other) const { if (equals(other)) { return (true); @@ -217,29 +258,29 @@ class IOAddress { return (lessThan(other)); } - /// \brief Checks if one address is smaller than the other + /// @brief Checks if one address is smaller than the other /// - /// \param other Address to compare against. + /// @param other Address to compare against. /// - /// See \ref lessThan method for details. + /// See @ref lessThan method for details. bool operator<(const IOAddress& other) const { return (lessThan(other)); } - /// \brief Checks if one address is smaller or equal than the other + /// @brief Checks if one address is smaller or equal than the other /// - /// \param other Address to compare against. + /// @param other Address to compare against. /// - /// See \ref smallerEqual method for details. + /// See @ref smallerEqual method for details. bool operator<=(const IOAddress& other) const { return (smallerEqual(other)); } - /// \brief Compare addresses for inequality + /// @brief Compare addresses for inequality /// - /// \param other Address to compare against. + /// @param other Address to compare against. /// - /// \return false if addresses are equal, true if not. + /// @return false if addresses are equal, true if not. bool operator!=(const IOAddress& other) const { return (nequals(other)); } @@ -282,32 +323,43 @@ class IOAddress { /// could take extra parameter that specifies the value by which the /// address should be increased. /// - /// @param addr address to be increased + /// @param addr address being increased + /// @param offset PSID offset + /// @param psid_len PSID length /// @return address increased by one static IOAddress - increase(const IOAddress& addr); + increase(const IOAddress& addr, uint8_t offset = 0, uint8_t psid_len = 0); - /// \brief Converts IPv4 address to uint32_t + /// @brief Converts IPv4 address to uint32_t /// /// Will throw BadValue exception if that is not IPv4 /// address. /// - /// \return uint32_t that represents IPv4 address in + /// @return uint32_t that represents IPv4 address in /// network byte order uint32_t toUint32() const; + /// @brief Converts IPv4 address plus port to uint64_t + /// + /// Will throw BadValue exception if that is not IPv4 + /// address. + /// + /// @return uint64_t that represents IPv4 address plus port in + /// network byte order + uint64_t addressPlusPortToUint64() const; + /// @name Methods returning @c IOAddress objects encapsulating typical addresses. /// //@{ /// @brief Returns an address set to all zeros. static const IOAddress& IPV4_ZERO_ADDRESS() { - static IOAddress address(0); + static IOAddress address(0U); return (address); } /// @brief Returns a "255.255.255.255" broadcast address. static const IOAddress& IPV4_BCAST_ADDRESS() { - static IOAddress address(0xFFFFFFFF); + static IOAddress address(0xFFFFFFFFU); return (address); } @@ -317,13 +369,28 @@ class IOAddress { return (address); } + uint8_t getPsidOffset() const { + return offset_; + } + + uint8_t getPsidLen() const { + return psid_len_; + } + + uint16_t getPsid() const { + return psid_; + } + //@} private: boost::asio::ip::address asio_address_; + uint8_t offset_; + uint8_t psid_len_; + uint16_t psid_; }; -/// \brief Insert the IOAddress as a string into stream. +/// @brief Insert the IOAddress as a string into stream. /// /// This method converts the \c address into a string and inserts it /// into the output stream \c os. @@ -331,10 +398,10 @@ class IOAddress { /// This function overloads the global operator<< to behave as described /// in ostream::operator<< but applied to \c IOAddress objects. /// -/// \param os A \c std::ostream object on which the insertion operation is +/// @param os A \c std::ostream object on which the insertion operation is /// performed. -/// \param address The \c IOAddress object output by the operation. -/// \return A reference to the same \c std::ostream object referenced by +/// @param address The \c IOAddress object output by the operation. +/// @return A reference to the same \c std::ostream object referenced by /// parameter \c os after the insertion operation. std::ostream& operator<<(std::ostream& os, const IOAddress& address); diff --git a/src/lib/dhcp/option_custom.cc b/src/lib/dhcp/option_custom.cc index 68f4d23d8b..02e6fa0b47 100644 --- a/src/lib/dhcp/option_custom.cc +++ b/src/lib/dhcp/option_custom.cc @@ -113,7 +113,7 @@ OptionCustom::addArrayDataField(const PSIDLen& psid_len, const PSID& psid) { checkArrayType(); if (definition_.getType() != OPT_PSID_TYPE) { - isc_throw(BadDataTypeCast, "PSID value can be specified onlu for" + isc_throw(BadDataTypeCast, "PSID value can be specified only for" " an option comprising an array of PSID length / value" " tuples"); } diff --git a/src/lib/dhcp/option_data_types.h b/src/lib/dhcp/option_data_types.h index 358dcc0728..88a677e69d 100644 --- a/src/lib/dhcp/option_data_types.h +++ b/src/lib/dhcp/option_data_types.h @@ -197,6 +197,51 @@ struct OptionDataTypeTraits { static const OptionDataType type = OPT_STRING_TYPE; }; +/// @brief Encapsulates PSID offset. +class PSIDOffset { +public: + + /// @brief Default constructor. + PSIDOffset() : psid_offset_(0) { } + + /// @brief Constructor. + /// + /// It checks that the specified value is not greater than + /// 16, which is a maximum value for the PSID offset. + /// + /// @param psid_offset PSID offset. + /// @throw isc::OutOfRange If specified PSID offset is greater than 16. + explicit PSIDOffset(const uint8_t psid_offset) + : psid_offset_(psid_offset) { + if (psid_offset_ > sizeof(uint16_t) * 8) { + isc_throw(isc::OutOfRange, "invalid value " + << asUnsigned() << " of PSID offset"); + } + } + + /// @brief Returns PSID offset as uint8_t value. + uint8_t asUint8() const { + return (psid_offset_); + } + + /// @brief Returns PSID offset as unsigned int. + /// + /// This is useful to convert the value to a numeric type which + /// can be logged directly. Note that the uint8_t value has to + /// be cast to an integer value to be logged as a number. This + /// is because the uint8_t is often implemented as char, in which + /// case directly logging an uint8_t value prints a character rather + /// than a number. + unsigned int asUnsigned() const { + return (static_cast(psid_offset_)); + } + +private: + + /// @brief PSID offset. + uint8_t psid_offset_; +}; + /// @brief Encapsulates PSID length. class PSIDLen { public: diff --git a/src/lib/dhcp/pkt4.cc b/src/lib/dhcp/pkt4.cc index 007e3f91fc..ebd7a510ab 100644 --- a/src/lib/dhcp/pkt4.cc +++ b/src/lib/dhcp/pkt4.cc @@ -40,7 +40,11 @@ Pkt4::Pkt4(uint8_t msg_type, uint32_t transid) ciaddr_(DEFAULT_ADDRESS), yiaddr_(DEFAULT_ADDRESS), siaddr_(DEFAULT_ADDRESS), - giaddr_(DEFAULT_ADDRESS) + giaddr_(DEFAULT_ADDRESS), + address_plus_port_(false), + psid_offset_(0), + psid_len_(0), + psid_(0) { memset(sname_, 0, MAX_SNAME_LEN); memset(file_, 0, MAX_FILE_LEN); @@ -59,7 +63,11 @@ Pkt4::Pkt4(const uint8_t* data, size_t len) ciaddr_(DEFAULT_ADDRESS), yiaddr_(DEFAULT_ADDRESS), siaddr_(DEFAULT_ADDRESS), - giaddr_(DEFAULT_ADDRESS) + giaddr_(DEFAULT_ADDRESS), + address_plus_port_(false), + psid_offset_(0), + psid_len_(0), + psid_(0) { if (len < DHCPV4_PKT_HDR_LEN) { diff --git a/src/lib/dhcp/pkt4.h b/src/lib/dhcp/pkt4.h index 26ded314f1..a4312db83b 100644 --- a/src/lib/dhcp/pkt4.h +++ b/src/lib/dhcp/pkt4.h @@ -397,6 +397,46 @@ class Pkt4 : public Pkt { return (false); } + /// @brief Sets address plus port field. + /// + /// @param address_plus_port address plus port value to be set + void setAddressPlusPort(bool address_plus_port) { address_plus_port_ = address_plus_port; }; + + /// @brief Returns address plus port field. + /// + /// @return address plus port field + bool getAddressPlusPort() const { return (address_plus_port_); }; + + /// @brief Sets PSID offset. + /// + /// @param psid_offset PSID offset value to be set + void setPsidOffset(uint8_t psid_offset) { psid_offset_ = psid_offset; }; + + /// @brief Returns PSID offset. + /// + /// @return PSID offset field + uint8_t getPsidOffset() const { return (psid_offset_); }; + + /// @brief Sets PSID len. + /// + /// @param psid_len PSID len value to be set + void setPsidLen(uint8_t psid_len) { psid_len_ = psid_len; }; + + /// @brief Returns PSID len. + /// + /// @return PSID len field + uint8_t getPsidLen() const { return (psid_len_); }; + + /// @brief Sets PSID. + /// + /// @param psid PSID value to be set + void setPsid(uint16_t psid) { psid_ = psid; }; + + /// @brief Returns PSID. + /// + /// @return PSID field + uint16_t getPsid() const { return (psid_); }; + private: /// @brief Generic method that validates and sets HW address. @@ -539,6 +579,18 @@ class Pkt4 : public Pkt { /// file field (128 bytes) uint8_t file_[MAX_FILE_LEN]; + /// @brief Specifies if the packet contains address plus port information + bool address_plus_port_; + + /// @brief Specifies the packet offset for address plus port + uint8_t psid_offset_; + + /// @brief Specifies the packet psid-len for address plus port + uint8_t psid_len_; + + /// @brief Specifies the packet psid for address plus port + uint16_t psid_; + // end of real DHCPv4 fields }; // Pkt4 class diff --git a/src/lib/dhcp/tests/option_custom_unittest.cc b/src/lib/dhcp/tests/option_custom_unittest.cc index e0311e7c69..71ef0a3dce 100644 --- a/src/lib/dhcp/tests/option_custom_unittest.cc +++ b/src/lib/dhcp/tests/option_custom_unittest.cc @@ -1181,7 +1181,7 @@ TEST_F(OptionCustomTest, recordDataWithSuboption) { ASSERT_NO_THROW(value0 = option->readInteger(0)); EXPECT_EQ(0x01020304, value0); - IOAddress value1 = 0; + IOAddress value1 = 0U; ASSERT_NO_THROW(value1 = option->readAddress(1)); EXPECT_EQ("192.168.0.1", value1.toText()); diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index 301b8af6f2..7fe00fbe5a 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -147,9 +147,11 @@ AllocEngine::IterativeAllocator::increasePrefix(const isc::asiolink::IOAddress& isc::asiolink::IOAddress AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress& address, bool prefix, - const uint8_t prefix_len) { + const uint8_t prefix_len, + uint8_t psid_offset, + uint8_t psid_len) { if (!prefix) { - return (IOAddress::increase(address)); + return (IOAddress::increase(address, psid_offset, psid_len)); } else { return (increasePrefix(address, prefix_len)); } @@ -158,8 +160,29 @@ AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress& isc::asiolink::IOAddress AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet, const ClientClasses& client_classes, - const DuidPtr&, - const IOAddress&) { + const DuidPtr& duid, + const IOAddress& hint) { + uint8_t psid_offset = 0; + uint8_t psid_len = 0; + if (subnet->get().first.isV4()) { + Subnet4Ptr subnet4 = boost::dynamic_pointer_cast(subnet); + if (subnet4->get4o6().enabled()) { + psid_offset = subnet4->get4o6().getPsidOffset(); + psid_len = subnet4->get4o6().getPsidLen(); + } + } + const IOAddress& result = pickAddressInternal(subnet, client_classes, duid, hint, + psid_offset, psid_len); + return IOAddress(result.toText(), psid_offset, psid_len, result.getPsid()); +} + +isc::asiolink::IOAddress +AllocEngine::IterativeAllocator::pickAddressInternal(const SubnetPtr& subnet, + const ClientClasses& client_classes, + const DuidPtr&, + const IOAddress&, + uint8_t psid_offset, + uint8_t psid_len) { // Is this prefix allocation? bool prefix = pool_type_ == Lease::TYPE_PD; @@ -252,7 +275,7 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet, prefix_len = pool6->getLength(); } - IOAddress next = increaseAddress(last, prefix, prefix_len); + IOAddress next = increaseAddress(last, prefix, prefix_len, psid_offset, psid_len); if ((*it)->inRange(next)) { // the next one is in the pool as well, so we haven't hit // pool boundary yet @@ -2439,7 +2462,6 @@ void AllocEngine::reclaimLeaseInDatabase(const LeasePtrType& lease, // expired-reclaimed state or simply remove it. if (remove_lease) { lease_mgr.deleteLease(lease->addr_); - } else if (!lease_update_fun.empty()) { // Clear FQDN information as we have already sent the // name change request to remove the DNS record. @@ -2745,6 +2767,10 @@ AllocEngine::discoverLease4(AllocEngine::ClientContext4& ctx) { Lease4Ptr client_lease; findClientLease(ctx, client_lease); + if (client_lease && client_lease->addr_.getPsidLen() != ctx.requested_address_.getPsidLen()) { + client_lease = Lease4Ptr(); + } + // new_lease will hold the pointer to the lease that we will offer to the // caller. Lease4Ptr new_lease; @@ -2851,6 +2877,10 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { Lease4Ptr client_lease; findClientLease(ctx, client_lease); + if (client_lease && client_lease->addr_.getPsidLen() != ctx.requested_address_.getPsidLen()) { + client_lease = Lease4Ptr(); + } + // Obtain the sole instance of the LeaseMgr. LeaseMgr& lease_mgr = LeaseMgrFactory::instance(); @@ -3355,9 +3385,9 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) { client_id = ctx.clientid_; } - uint64_t possible_attempts = - subnet->getPoolCapacity(Lease::TYPE_V4, - ctx.query_->getClasses()); + uint64_t possible_attempts = (1 << subnet->get4o6().getPsidLen()) * + subnet->getPoolCapacity(Lease::TYPE_V4, + ctx.query_->getClasses()); uint64_t max_attempts = (attempts_ > 0 ? attempts_ : possible_attempts); // Skip trying if there is no chance to get something if (possible_attempts == 0) { diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index 7c3ee98822..020f2f5a10 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -140,6 +140,13 @@ class AllocEngine : public boost::noncopyable { const ClientClasses& client_classes, const DuidPtr& duid, const isc::asiolink::IOAddress& hint); + + virtual isc::asiolink::IOAddress + pickAddressInternal(const SubnetPtr& subnet, + const DuidPtr& duid, + const isc::asiolink::IOAddress& hint, + uint8_t psid_offset, + uint8_t psid_len); protected: /// @brief Returns the next prefix @@ -149,8 +156,8 @@ class AllocEngine : public boost::noncopyable { /// increased by prefix length /32 will become 2001:db9::. This method /// is used to iterate over IPv6 prefix pools /// - /// @param prefix prefix to be increased - /// @param prefix_len length of the prefix to be increased + /// @param prefix prefix being increased + /// @param prefix_len length of the prefix being increased /// @return result prefix static isc::asiolink::IOAddress increasePrefix(const isc::asiolink::IOAddress& prefix, diff --git a/src/lib/dhcpsrv/cfg_4o6.h b/src/lib/dhcpsrv/cfg_4o6.h index e231e775e6..cbede74239 100644 --- a/src/lib/dhcpsrv/cfg_4o6.h +++ b/src/lib/dhcpsrv/cfg_4o6.h @@ -8,6 +8,7 @@ #define CFG_4OVER6_H #include +#include #include #include @@ -79,6 +80,30 @@ struct Cfg4o6 : public isc::data::CfgToElement { enabled_ = true; } + /// @brief Returns the offset for address plus port. + /// @return the offset for address plus port + uint8_t getPsidOffset() const { + return (psid_offset_.asUint8()); + } + + /// @brief Sets the offset for address plus port + /// @param offset the offset for address plus port + void setPsidOffset(const uint8_t offset) { + psid_offset_ = PSIDOffset(offset); + } + + /// @brief Returns the psid-len for address plus port. + /// @return the psid-len for address plus port + uint8_t getPsidLen() const { + return (psid_len_.asUint8()); + } + + /// @brief Sets the psid-len for address plus port + /// @param psid_len the psid-len for address plus port + void setPsidLen(const uint8_t psid_len) { + psid_len_ = PSIDLen(psid_len); + } + /// @brief Unparse a configuration object /// /// @return a pointer to unparsed configuration @@ -97,6 +122,12 @@ struct Cfg4o6 : public isc::data::CfgToElement { /// Specifies the v6 interface-id used for v4 subnet selection. OptionPtr interface_id_; + + /// Specifies offset. + PSIDOffset psid_offset_; + + /// Specifies PSID len. + PSIDLen psid_len_; }; } // end of isc::dhcp namespace diff --git a/src/lib/dhcpsrv/cfg_db_access.cc b/src/lib/dhcpsrv/cfg_db_access.cc index 366cdf4be2..26d6917207 100644 --- a/src/lib/dhcpsrv/cfg_db_access.cc +++ b/src/lib/dhcpsrv/cfg_db_access.cc @@ -50,7 +50,7 @@ CfgDbAccess::createManagers() const { } } -std::string +std::string CfgDbAccess::getAccessString(const std::string& access_string) const { std::ostringstream s; s << access_string; @@ -81,6 +81,9 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) { std::string value = token.substr(pos + 1); if ((keyword == "lfc-interval") || (keyword == "connect-timeout") || + (keyword == "reconnect-wait-time") || + (keyword == "request-timeout") || + (keyword == "tcp-keepalive") || (keyword == "port")) { // integer parameters int64_t int_value; @@ -93,6 +96,7 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) { << keyword << "=" << value); } } else if ((keyword == "persist") || + (keyword == "tcp-nodelay") || (keyword == "readonly")) { if (value == "true") { result->set(keyword, Element::create(true)); diff --git a/src/lib/dhcpsrv/cfg_subnets4.cc b/src/lib/dhcpsrv/cfg_subnets4.cc index 0e47c6d0fc..945b71be3c 100644 --- a/src/lib/dhcpsrv/cfg_subnets4.cc +++ b/src/lib/dhcpsrv/cfg_subnets4.cc @@ -87,6 +87,22 @@ CfgSubnets4::selectSubnet4o6(const SubnetSelector& selector) const { continue; // No? Let's try the next one. } + if (selector.address_plus_port_ && + cfg4o6.getPsidOffset() == selector.psid_offset_ && + cfg4o6.getPsidLen() == selector.psid_len_) { + return (*subnet); + } + + if (selector.address_plus_port_ && + cfg4o6.getPsidLen() && !selector.psid_len_) { + return (*subnet); + } + + if (!selector.address_plus_port_ && + (cfg4o6.getPsidOffset() || cfg4o6.getPsidLen())) { + continue; + } + // First match criteria: check if we have a prefix/len defined. std::pair pref = cfg4o6.getSubnet4o6(); if (!pref.first.isV6Zero()) { diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc index 2896b8bc4a..625d249a73 100644 --- a/src/lib/dhcpsrv/cfgmgr.cc +++ b/src/lib/dhcpsrv/cfgmgr.cc @@ -172,6 +172,10 @@ CfgMgr::CfgMgr() // DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am // Note: the definition of DHCP_DATA_DIR needs to include quotation marks // See AM_CPPFLAGS definition in Makefile.am + const char* const env = getenv("KEA_DATA_DIR"); + if (env) { + datadir_ = env; + } } CfgMgr::~CfgMgr() { diff --git a/src/lib/dhcpsrv/cql_connection.cc b/src/lib/dhcpsrv/cql_connection.cc index 0e88de7824..3211a08bbe 100644 --- a/src/lib/dhcpsrv/cql_connection.cc +++ b/src/lib/dhcpsrv/cql_connection.cc @@ -177,6 +177,8 @@ CqlConnection::openDatabase() { try { port_number = boost::lexical_cast(port); if (port_number < 1 || port_number > 65535) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "port outside of range, expected " @@ -184,6 +186,8 @@ CqlConnection::openDatabase() { << port); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid " "port, expected castable to int, instead got " @@ -199,12 +203,16 @@ CqlConnection::openDatabase() { reconnect_wait_time_number = boost::lexical_cast(reconnect_wait_time); if (reconnect_wait_time_number < 0) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid reconnect " "wait time, expected positive number, instead got " << reconnect_wait_time); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "invalid reconnect wait time, expected " @@ -221,6 +229,8 @@ CqlConnection::openDatabase() { connect_timeout_number = boost::lexical_cast(connect_timeout); if (connect_timeout_number < 0) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "invalid connect timeout, expected " @@ -228,6 +238,8 @@ CqlConnection::openDatabase() { << connect_timeout); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid connect timeout, " "expected castable to int, instead got \"" @@ -242,6 +254,8 @@ CqlConnection::openDatabase() { request_timeout_number = boost::lexical_cast(request_timeout); if (request_timeout_number < 0) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "invalid request timeout, expected " @@ -249,6 +263,8 @@ CqlConnection::openDatabase() { << request_timeout); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid request timeout, " "expected castable to int, instead got \"" @@ -262,6 +278,8 @@ CqlConnection::openDatabase() { try { tcp_keepalive_number = boost::lexical_cast(tcp_keepalive); if (tcp_keepalive_number < 0) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "invalid TCP keepalive, expected " @@ -269,6 +287,8 @@ CqlConnection::openDatabase() { << tcp_keepalive); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid TCP keepalive, " "expected castable to int, instead got \"" diff --git a/src/lib/dhcpsrv/cql_exchange.cc b/src/lib/dhcpsrv/cql_exchange.cc index c84d7b72f4..c22feb9529 100644 --- a/src/lib/dhcpsrv/cql_exchange.cc +++ b/src/lib/dhcpsrv/cql_exchange.cc @@ -94,68 +94,7 @@ static AnyTypeMap ANY_TYPE_MAP = { {typeid(cass_int64_t*), EXCHANGE_DATA_TYPE_INT64}, {typeid(std::string*), EXCHANGE_DATA_TYPE_STRING}, {typeid(CassBlob*), EXCHANGE_DATA_TYPE_BYTES}, - {typeid(CassUuid*), EXCHANGE_DATA_TYPE_UUID}, - {typeid(Udt*), EXCHANGE_DATA_TYPE_UDT}, // user data type - {typeid(AnyCollection*), EXCHANGE_DATA_TYPE_COLLECTION}}; - -/// @brief Maps Cassandra type to exchange type -static CassTypeMap CASS_TYPE_MAP = { - {CASS_VALUE_TYPE_CUSTOM, EXCHANGE_DATA_TYPE_UDT}, - {CASS_VALUE_TYPE_ASCII, EXCHANGE_DATA_TYPE_STRING}, - {CASS_VALUE_TYPE_BIGINT, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_BLOB, EXCHANGE_DATA_TYPE_BYTES}, - {CASS_VALUE_TYPE_BOOLEAN, EXCHANGE_DATA_TYPE_BOOL}, - {CASS_VALUE_TYPE_COUNTER, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_DECIMAL, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_DOUBLE, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_FLOAT, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_INT, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_TEXT, EXCHANGE_DATA_TYPE_STRING}, - {CASS_VALUE_TYPE_TIMESTAMP, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_UUID, EXCHANGE_DATA_TYPE_UUID}, - {CASS_VALUE_TYPE_VARCHAR, EXCHANGE_DATA_TYPE_STRING}, - {CASS_VALUE_TYPE_VARINT, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_TIMEUUID, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_INET, EXCHANGE_DATA_TYPE_NONE}, - {CASS_VALUE_TYPE_DATE, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_TIME, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_SMALL_INT, EXCHANGE_DATA_TYPE_INT16}, - {CASS_VALUE_TYPE_TINY_INT, EXCHANGE_DATA_TYPE_INT8}, - {CASS_VALUE_TYPE_LIST, EXCHANGE_DATA_TYPE_COLLECTION}, - {CASS_VALUE_TYPE_MAP, EXCHANGE_DATA_TYPE_COLLECTION}, - {CASS_VALUE_TYPE_SET, EXCHANGE_DATA_TYPE_COLLECTION}, - {CASS_VALUE_TYPE_UDT, EXCHANGE_DATA_TYPE_UDT}, - {CASS_VALUE_TYPE_TUPLE, EXCHANGE_DATA_TYPE_UDT}}; - -/// @brief Udt (user data type) method implementations -/// @{ -Udt::Udt(const CqlConnection& connection, const std::string& name) - : AnyArray(), connection_(connection), name_(name) { - // Create type. - cass_data_type_ = cass_keyspace_meta_user_type_by_name( - connection_.keyspace_meta_, name_.c_str()); - if (!cass_data_type_) { - isc_throw(DbOperationError, - "Udt::Udt(): UDT " << name_ << " does not exist "); - } - // Create container. - cass_user_type_ = cass_user_type_new_from_data_type(cass_data_type_); - if (!cass_user_type_) { - isc_throw(DbOperationError, - "Udt::Udt(): Type " << name_ - << " is not a UDT as expected. "); - } -} - -Udt::~Udt() { - /// @todo: Need to get back to this issue. This is likely a memory leak. - // - // Bug: it seems that if there is no call to - // cass_user_type_set_*(cass_user_type_), then - // cass_user_type_free(cass_user_type_) might SIGSEGV, so we never - // free. Udt objects should have application scope though. - // cass_user_type_free(cass_user_type_); -} + {typeid(CassUuid*), EXCHANGE_DATA_TYPE_UUID}}; /// @} /// @brief AnyArray method implementations @@ -251,238 +190,8 @@ CqlBindUuid(const boost::any& value, return cass_statement_bind_uuid(statement, index, *boost::any_cast(value)); } - -static CassError -CqlBindUdt(const boost::any& value, - const size_t& index, - CassStatement* statement) { - Udt* udt = boost::any_cast(value); - - if (!udt) { - isc_throw(BadValue, "Invalid value specified, not an Udt object"); - } - - size_t i = 0u; - - // Let's iterate over all elements in udt and check that we indeed - // can assign the set function for each specified type. - for (boost::any& element : *udt) { - try { - KEA_CASS_CHECK( - CQL_FUNCTIONS[exchangeType(element)].cqlUdtSetFunction_( - element, i, udt->cass_user_type_)); - } catch (const boost::bad_any_cast& exception) { - isc_throw(DbOperationError, - "CqlCommon::udtSetData(): " - << exception.what() << " when binding parameter " - << " of type " << element.type().name() - << "in UDT with function CQL_FUNCTIONS[" - << exchangeType(element) << "].cqlUdtSetFunction_"); - } - ++i; - } - - return cass_statement_bind_user_type(statement, index, - udt->cass_user_type_); -} - -static CassError -CqlBindCollection(const boost::any& value, - const size_t& index, - CassStatement* statement) { - AnyCollection* elements = boost::any_cast(value); - - CassCollection* collection = - cass_collection_new(CASS_COLLECTION_TYPE_SET, elements->size()); - - // Iterate over all elements and assign appropriate append function - // for each. - for (boost::any& element : *elements) { - ExchangeDataType type = exchangeType(element); - KEA_CASS_CHECK(CQL_FUNCTIONS[type].cqlCollectionAppendFunction_( - element, collection)); - } - - const CassError cass_error = - cass_statement_bind_collection(statement, index, collection); - cass_collection_free(collection); - - return cass_error; -} -/// @} - -/// @name CqlUdtSet functions for binding data into Cassandra format for -/// insertion of a UDT: -/// @{ -static CassError -CqlUdtSetNone(const boost::any& /* udt_member */, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_null(cass_user_type, position); -} - -static CassError -CqlUdtSetBool(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_bool(cass_user_type, position, - *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetInt8(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_int8(cass_user_type, position, - *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetInt16(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_int16( - cass_user_type, position, *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetInt32(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_int32( - cass_user_type, position, *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetInt64(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_int64( - cass_user_type, position, *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetString(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_string( - cass_user_type, position, - boost::any_cast(udt_member)->c_str()); -} - -static CassError -CqlUdtSetBytes(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - CassBlob* blob_value = boost::any_cast(udt_member); - return cass_user_type_set_bytes(cass_user_type, position, - blob_value->data(), blob_value->size()); -} - -static CassError -CqlUdtSetUuid(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_uuid(cass_user_type, position, - *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetUdt(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_user_type( - cass_user_type, position, - boost::any_cast(udt_member)->cass_user_type_); -} - -static CassError -CqlUdtSetCollection(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_collection( - cass_user_type, position, boost::any_cast(udt_member)); -} /// @} -/// @name CqlCollectionAppend functions for binding data into Cassandra format -/// for insertion of a collection: -/// @{ -static CassError -CqlCollectionAppendNone(const boost::any& /* value */, - CassCollection* /* collection */) { - return CASS_OK; -} - -static CassError -CqlCollectionAppendBool(const boost::any& value, CassCollection* collection) { - return cass_collection_append_bool(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendInt8(const boost::any& value, CassCollection* collection) { - return cass_collection_append_int8(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendInt16(const boost::any& value, CassCollection* collection) { - return cass_collection_append_int16(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendInt32(const boost::any& value, CassCollection* collection) { - return cass_collection_append_int32(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendInt64(const boost::any& value, CassCollection* collection) { - return cass_collection_append_int64(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendString(const boost::any& value, CassCollection* collection) { - return cass_collection_append_string( - collection, boost::any_cast(value)->c_str()); -} - -static CassError -CqlCollectionAppendBytes(const boost::any& value, CassCollection* collection) { - CassBlob* blob_value = boost::any_cast(value); - return cass_collection_append_bytes(collection, blob_value->data(), - blob_value->size()); -} - -static CassError -CqlCollectionAppendUuid(const boost::any& value, CassCollection* collection) { - return cass_collection_append_uuid(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendUdt(const boost::any& value, CassCollection* collection) { - Udt* udt = boost::any_cast(value); - size_t i = 0u; - for (boost::any& element : *udt) { - KEA_CASS_CHECK(CQL_FUNCTIONS[exchangeType(element)].cqlUdtSetFunction_( - element, i, udt->cass_user_type_)); - ++i; - } - return cass_collection_append_user_type(collection, udt->cass_user_type_); -} - -static CassError -CqlCollectionAppendCollection(const boost::any& value, - CassCollection* collection) { - return cass_collection_append_collection( - collection, boost::any_cast(value)); -} -// @} - /// @name CqlGet functions for retrieving data of the proper Cassandra format: /// @{ static CassError @@ -541,101 +250,30 @@ static CassError CqlGetUuid(const boost::any& data, const CassValue* value) { return cass_value_get_uuid(value, boost::any_cast(data)); } - -static CassError -CqlGetUdt(const boost::any& data, const CassValue* value) { - Udt* udt = boost::any_cast(data); - - CassIterator* fields = cass_iterator_fields_from_user_type(value); - if (!fields) { - isc_throw(DbOperationError, "CqlGetUdt(): column is not a UDT"); - } - Udt::const_iterator it = udt->begin(); - while (cass_iterator_next(fields)) { - const CassValue* field_value = - cass_iterator_get_user_type_field_value(fields); - if (cass_value_is_null(field_value)) { - isc_throw(DbOperationError, - "CqlGetUdt(): null value returned in UDT"); - } - const CassValueType& type = cass_value_type(field_value); - KEA_CASS_CHECK(CQL_FUNCTIONS[exchangeType(type)].cqlGetFunction_( - *it, field_value)); - ++it; - // If cqlGetFunction_() returns != CASS_OK, don't - // cass_iterator_free(items_iterator) because we're returning from this - // function and throwing from the callee. - } - cass_iterator_free(fields); - return CASS_OK; -} - -static CassError -CqlGetCollection(const boost::any& data, const CassValue* value) { - AnyCollection* collection = boost::any_cast(data); - if (!collection) { - isc_throw(DbOperationError, "CqlGetCollection(): column is not a collection"); - } - - BOOST_ASSERT(collection->size() == 1); - - /// @todo: Create a copy of the underlying object rather than referencing to - /// it. - boost::any underlying_object = *collection->begin(); - - collection->clear(); - - CassIterator* items = cass_iterator_from_collection(value); - if (!items) { - isc_throw(DbOperationError, - "CqlGetCollection(): column is not a collection"); - } - while (cass_iterator_next(items)) { - const CassValue* item_value = cass_iterator_get_value(items); - if (cass_value_is_null(item_value)) { - isc_throw(DbOperationError, - "CqlGetCollection(): null value returned in collection"); - } - const CassValueType& type = cass_value_type(item_value); - - collection->push_back(underlying_object); - KEA_CASS_CHECK(CQL_FUNCTIONS[exchangeType(type)].cqlGetFunction_( - *collection->rbegin(), item_value)); - // If cqlGetFunction_() returns != CASS_OK, don't call - // cass_iterator_free(items_iterator) because we're returning from this - // function and throwing from the callee. - } - cass_iterator_free(items); - return CASS_OK; -} /// @} /// @brief Functions used to interface with the Cassandra C++ driver CqlFunctionMap CQL_FUNCTIONS = // {{EXCHANGE_DATA_TYPE_NONE, - {CqlBindNone, CqlUdtSetNone, CqlCollectionAppendNone, CqlGetNone}}, + {CqlBindNone, CqlGetNone}}, {EXCHANGE_DATA_TYPE_BOOL, - {CqlBindBool, CqlUdtSetBool, CqlCollectionAppendBool, CqlGetBool}}, + {CqlBindBool, CqlGetBool}}, {EXCHANGE_DATA_TYPE_INT8, - {CqlBindInt8, CqlUdtSetInt8, CqlCollectionAppendInt8, CqlGetInt8}}, + {CqlBindInt8, CqlGetInt8}}, {EXCHANGE_DATA_TYPE_INT16, - {CqlBindInt16, CqlUdtSetInt16, CqlCollectionAppendInt16, CqlGetInt16}}, + {CqlBindInt16, CqlGetInt16}}, {EXCHANGE_DATA_TYPE_INT32, - {CqlBindInt32, CqlUdtSetInt32, CqlCollectionAppendInt32, CqlGetInt32}}, + {CqlBindInt32, CqlGetInt32}}, {EXCHANGE_DATA_TYPE_INT64, - {CqlBindInt64, CqlUdtSetInt64, CqlCollectionAppendInt64, CqlGetInt64}}, + {CqlBindInt64, CqlGetInt64}}, + {EXCHANGE_DATA_TYPE_TIMESTAMP, + {CqlBindInt64, CqlGetInt64}}, {EXCHANGE_DATA_TYPE_STRING, - {CqlBindString, CqlUdtSetString, CqlCollectionAppendString, - CqlGetString}}, + {CqlBindString, CqlGetString}}, {EXCHANGE_DATA_TYPE_BYTES, - {CqlBindBytes, CqlUdtSetBytes, CqlCollectionAppendBytes, CqlGetBytes}}, + {CqlBindBytes, CqlGetBytes}}, {EXCHANGE_DATA_TYPE_UUID, - {CqlBindUuid, CqlUdtSetUuid, CqlCollectionAppendUuid, CqlGetUuid}}, - {EXCHANGE_DATA_TYPE_UDT, - {CqlBindUdt, CqlUdtSetUdt, CqlCollectionAppendUdt, CqlGetUdt}}, - {EXCHANGE_DATA_TYPE_COLLECTION, - {CqlBindCollection, CqlUdtSetCollection, CqlCollectionAppendCollection, - CqlGetCollection}}}; + {CqlBindUuid, CqlGetUuid}}}; ExchangeDataType exchangeType(const boost::any& object) { @@ -656,24 +294,6 @@ exchangeType(const boost::any& object) { return exchange_type; } -ExchangeDataType -exchangeType(const CassValueType& type) { - CassTypeMap::const_iterator exchange_type_it = CASS_TYPE_MAP.find(type); - if (exchange_type_it == CASS_TYPE_MAP.end()) { - isc_throw(DbOperationError, - "exchangeType(): Cassandra value type " - << type << " does not map to any exchange type"); - } - const ExchangeDataType exchange_type = exchange_type_it->second; - if (exchange_type >= CQL_FUNCTIONS.size()) { - isc_throw(BadValue, - "exchangeType(): index " << exchange_type << " out of bounds " - << 0 << " - " - << CQL_FUNCTIONS.size() - 1); - } - return exchange_type; -} - void CqlCommon::bindData(const AnyArray& data, CassStatement* statement) { size_t i = 0u; @@ -812,7 +432,12 @@ CqlExchange::executeSelect(const CqlConnection& connection, const AnyArray& data } } - CqlCommon::bindData(local_data, statement); + try { + CqlCommon::bindData(local_data, statement); + } catch (const std::exception& ex) { + cass_statement_free(statement); + isc_throw(DbOperationError, ex.what()); + } // Everything's ready. Call the actual statement. future = cass_session_execute(connection.session_, statement); @@ -902,7 +527,12 @@ CqlExchange::executeMutation(const CqlConnection& connection, const AnyArray& da } } - CqlCommon::bindData(data, statement); + try { + CqlCommon::bindData(data, statement); + } catch (const std::exception& ex) { + cass_statement_free(statement); + isc_throw(DbOperationError, ex.what()); + } future = cass_session_execute(connection.session_, statement); if (!future) { diff --git a/src/lib/dhcpsrv/cql_exchange.h b/src/lib/dhcpsrv/cql_exchange.h index c99f762e41..5f17399ffa 100644 --- a/src/lib/dhcpsrv/cql_exchange.h +++ b/src/lib/dhcpsrv/cql_exchange.h @@ -56,38 +56,6 @@ class AnyArray : public std::vector { void remove(const size_t& index); }; -// @brief Representation of a Cassandra User Defined Type -class Udt : public AnyArray { -public: - /// @brief Parameterized constructor - Udt(const CqlConnection& connection, const std::string& name); - - /// @brief Destructor - ~Udt(); - - /// @brief Frees the underlying container. - void freeUserType(); - - /// @brief Creates the underlying container. - void newUserType(); - - /// @brief Connection to the Cassandra database - const CqlConnection& connection_; - - /// @brief Name of the UDT in the schema: CREATE TYPE ___ { ... } - const std::string name_; - - /// @brief Internal Cassandra driver object representing a Cassandra data - /// type - const CassDataType* cass_data_type_; - - /// @brief Internal Cassandra driver object representing a user defined type - CassUserType* cass_user_type_; -}; - -/// @brief Defines an array of arbitrary objects (used by Cassandra backend) -typedef AnyArray AnyCollection; - /// @brief Binds a C++ object to a Cassandra statement's parameter. Used in all /// statements. /// @param value the value to be set or retreived @@ -97,20 +65,6 @@ typedef CassError (*CqlBindFunction)(const boost::any& value, const size_t& index, CassStatement* statement); -/// @brief Sets a member in a UDT. Used in INSERT & UPDATE statements. -/// @param value the value to be set or retreived -/// @param index offset of the value being processed -/// @param cass_user_type pointer to the user type that uses this member -typedef CassError (*CqlUdtSetFunction)(const boost::any& value, - const size_t& index, - CassUserType* cass_user_type); - -/// @brief Sets an item in a collection. Used in INSERT & UPDATE statements. -/// @param value pointer to a value to be inserted or updated -/// @param collection pointer to collection to be inserted or updated -typedef CassError (*CqlCollectionAppendFunction)(const boost::any& value, - CassCollection* collection); - /// @brief Converts a single Cassandra column value to a C++ object. Used in /// SELECT statements. /// @@ -124,10 +78,6 @@ struct CqlFunction { /// @brief Binds a C++ object to a Cassandra statement's parameter. Used in /// all statements. CqlBindFunction cqlBindFunction_; - /// @brief Sets a member in a UDT. Used in INSERT & UPDATE statements. - CqlUdtSetFunction cqlUdtSetFunction_; - /// @brief Sets an item in a collection. Used in INSERT & UPDATE statements. - CqlCollectionAppendFunction cqlCollectionAppendFunction_; /// @brief Converts a single Cassandra column value to a C++ object. Used in /// SELECT statements. CqlGetFunction cqlGetFunction_; @@ -314,10 +264,6 @@ class CqlCommon { ExchangeDataType exchangeType(const boost::any& object); -/// @brief Determine exchange type based on CassValueType. -ExchangeDataType -exchangeType(const CassValueType& type); - } // namespace dhcp } // namespace isc diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index 8f3c351b7f..24fde3f76d 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -222,8 +222,8 @@ class CqlLease4Exchange : public CqlLeaseExchange { private: // Pointer to lease object Lease4Ptr lease_; - // IPv4 address - cass_int32_t address_; + // IPv4 address plus port + cass_int64_t address_; // Client identification CassBlob client_id_; }; // CqlLease4Exchange @@ -355,10 +355,10 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) { // structure. try { - // address: int + // address: bigint // The address in the Lease structure is an IOAddress object. // Convert this to an integer for storage. - address_ = static_cast(lease->addr_.toUint32()); + address_ = lease_->addr_.addressPlusPortToUint64(); // hwaddr: blob if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { @@ -391,8 +391,7 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) { // For convenience for external tools, this is converted to lease // expiry time (expire). The relationship is given by: // expire = cltt_ + valid_lft_ - CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, - expire_); + CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, expire_); // subnet_id: int subnet_id_ = static_cast(lease_->subnet_id_); @@ -449,10 +448,10 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, // structure. try { - // address: int + // address: bigint // The address in the Lease structure is an IOAddress object. // Convert this to an integer for storage. - address_ = static_cast(lease->addr_.toUint32()); + address_ = lease_->addr_.addressPlusPortToUint64(); // hwaddr: blob if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { @@ -485,8 +484,7 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, // For convenience for external tools, this is converted to lease // expiry time (expire). The relationship is given by: // expire = cltt_ + valid_lft_ - CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, - expire_); + CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, expire_); // subnet_id: int subnet_id_ = static_cast(lease_->subnet_id_); @@ -538,8 +536,8 @@ CqlLease4Exchange::createBindForDelete(const IOAddress &address, AnyArray &data, // structure. try { - // address: int - address_ = static_cast(address.toUint32()); + // address: bigint + address_ = lease_->addr_.addressPlusPortToUint64(); // Start with a fresh array. data.clear(); @@ -623,7 +621,7 @@ CqlLease4Exchange::retrieve() { // Recreate the hardware address. HWAddrPtr hwaddr(new HWAddr(hwaddr_, HTYPE_ETHER)); - uint32_t addr4 = static_cast(address_); + uint64_t addr4 = static_cast(address_); Lease4Ptr result(new Lease4(addr4, hwaddr, client_id_.data(), client_id_.size(), valid_lifetime_, 0, 0, @@ -1112,8 +1110,7 @@ CqlLease6Exchange::createBindForUpdate(const Lease6Ptr &lease, AnyArray &data, // For convenience for external tools, this is converted to lease // expiry time (expire). The relationship is given by: // expire = cltt_ + valid_lft_ - CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, - expire_); + CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, expire_); // subnet_id: int subnet_id_ = static_cast(lease_->subnet_id_); @@ -1503,7 +1500,7 @@ CqlLeaseMgr::getLease4(const IOAddress &addr) const { // Set up the WHERE clause value AnyArray data; - cass_int32_t address = static_cast(addr.toUint32()); + cass_int64_t address = static_cast(addr.addressPlusPortToUint64()); data.add(&address); // Get the data. @@ -1833,7 +1830,7 @@ CqlLeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) { DHCPSRV_CQL_DELETE_EXPIRED_RECLAIMED6) .arg(secs); AnyArray data; - uint64_t n_of_deleted_leases = 0u; + uint64_t deleted = 0u; cass_int32_t limit = 1024; // State is reclaimed. @@ -1852,10 +1849,10 @@ CqlLeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) { exchange6->getLeaseCollection(CqlLease6Exchange::GET_LEASE6_EXPIRE, data, leases); for (Lease6Ptr &lease : leases) { if (deleteLease(lease->addr_)) { - ++n_of_deleted_leases; + ++deleted; } } - return n_of_deleted_leases; + return (deleted); } size_t diff --git a/src/lib/dhcpsrv/lease.h b/src/lib/dhcpsrv/lease.h index 7fabf6720d..5153802c2d 100644 --- a/src/lib/dhcpsrv/lease.h +++ b/src/lib/dhcpsrv/lease.h @@ -279,8 +279,7 @@ struct Lease4 : public Lease { /// @brief Default constructor /// /// Initialize fields that don't have a default constructor. - Lease4() : Lease(0, 0, 0, 0, 0, 0, false, false, "", HWAddrPtr()) - { + Lease4() : Lease(0U, 0, 0, 0, 0, 0, false, false, "", HWAddrPtr()) { } /// @brief Copy constructor @@ -420,7 +419,6 @@ typedef std::vector Lease4Collection; /// would be required. As this is a critical part of the code that will be used /// extensively, direct access is warranted. struct Lease6 : public Lease { - /// @brief Lease type /// /// One of normal address, temporary address, or prefix. diff --git a/src/lib/dhcpsrv/mysql_connection.cc b/src/lib/dhcpsrv/mysql_connection.cc index fdb6859359..13dbcc57a8 100644 --- a/src/lib/dhcpsrv/mysql_connection.cc +++ b/src/lib/dhcpsrv/mysql_connection.cc @@ -42,7 +42,10 @@ MySqlTransaction::~MySqlTransaction() { // Rollback if the MySqlTransaction::commit wasn't explicitly // called. if (!committed_) { - conn_.rollback(); + try { + conn_.rollback(); + } catch (...) { + } } } @@ -131,10 +134,8 @@ MySqlConnection::openDatabase() { // No timeout parameter, we are going to use the default timeout. stimeout = ""; } - if (stimeout.size() > 0) { // Timeout was given, so try to convert it to an integer. - try { connect_timeout = boost::lexical_cast(stimeout); } catch (...) { diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index 8c70a60afa..106e843fee 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -197,7 +197,8 @@ tagged_statements = { { {MySqlLeaseMgr::INSERT_LEASE4, "INSERT INTO lease4(address, hwaddr, client_id, " "valid_lifetime, expire, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state) " + "fqdn_fwd, fqdn_rev, hostname, " + "state) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"}, {MySqlLeaseMgr::INSERT_LEASE6, "INSERT INTO lease6(address, duid, valid_lifetime, " @@ -211,7 +212,8 @@ tagged_statements = { { "UPDATE lease4 SET address = ?, hwaddr = ?, " "client_id = ?, valid_lifetime = ?, expire = ?, " "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, " - "hostname = ?, state = ? " + "hostname = ?, " + "state = ? " "WHERE address = ?"}, {MySqlLeaseMgr::UPDATE_LEASE6, "UPDATE lease6 SET address = ?, duid = ?, " @@ -371,11 +373,11 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { // structure. try { - // Address: uint32_t + // address: uint64_t // The address in the Lease structure is an IOAddress object. Convert // this to an integer for storage. - addr4_ = lease_->addr_.toUint32(); - bind_[0].buffer_type = MYSQL_TYPE_LONG; + addr4_ = lease_->addr_.addressPlusPortToUint64(); + bind_[0].buffer_type = MYSQL_TYPE_LONGLONG; bind_[0].buffer = reinterpret_cast(&addr4_); bind_[0].is_unsigned = MLM_TRUE; // bind_[0].is_null = &MLM_FALSE; // commented out for performance @@ -471,6 +473,7 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { bind_[9].is_unsigned = MLM_TRUE; // bind_[9].is_null = &MLM_FALSE; // commented out for performance // reasons, see memset() above + // Add the error flags setErrorIndicators(bind_, error_, LEASE_COLUMNS); @@ -503,8 +506,8 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { // code that explicitly sets is_null is there, but is commented out. memset(bind_, 0, sizeof(bind_)); - // address: uint32_t - bind_[0].buffer_type = MYSQL_TYPE_LONG; + // address: uint64_t + bind_[0].buffer_type = MYSQL_TYPE_LONGLONG; bind_[0].buffer = reinterpret_cast(&addr4_); bind_[0].is_unsigned = MLM_TRUE; // bind_[0].is_null = &MLM_FALSE; // commented out for performance @@ -623,7 +626,10 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { client_id_buffer_, client_id_length_, valid_lifetime_, 0, 0, cltt, subnet_id_, fqdn_fwd_, fqdn_rev_, hostname)); + + // Set state. lease->state_ = state_; + return (lease); } @@ -646,10 +652,10 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { // Note: All array lengths are equal to the corresponding variable in the // schema. // Note: Arrays are declared fixed length for speed of creation - uint32_t addr4_; ///< IPv4 address + uint64_t addr4_; ///< IPv4 address plus port MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array - std::string columns_[LEASE_COLUMNS];///< Column names - my_bool error_[LEASE_COLUMNS]; ///< Error array + std::string columns_[LEASE_COLUMNS]; ///< Column names + my_bool error_[LEASE_COLUMNS]; ///< Error array std::vector hwaddr_; ///< Hardware address uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Hardware address buffer @@ -673,11 +679,9 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { ///< Client hostname unsigned long hostname_length_; ///< Client hostname length uint32_t state_; ///< Lease state - }; - /// @brief Exchange MySQL and Lease6 Data /// /// On any MySQL operation, arrays of MYSQL_BIND structures must be built to @@ -698,7 +702,7 @@ class MySqlLease6Exchange : public MySqlLeaseExchange { public: /// @brief Constructor /// - /// The initialization of the variables here is nonly to satisfy cppcheck - + /// The initialization of the variables here is only to satisfy cppcheck - /// all variables are initialized/set in the methods before they are used. MySqlLease6Exchange() : addr6_length_(0), duid_length_(0), iaid_(0), lease_type_(0), prefixlen_(0), @@ -981,7 +985,7 @@ class MySqlLease6Exchange : public MySqlLeaseExchange { // code that explicitly sets is_null is there, but is commented out. memset(bind_, 0, sizeof(bind_)); - // address: varchar(39) + // address: varchar(39) // A Lease6_ address has a maximum of 39 characters. The array is // one byte longer than this to guarantee that we can always null // terminate it whatever is returned. @@ -1100,6 +1104,7 @@ class MySqlLease6Exchange : public MySqlLeaseExchange { bind_[15].is_unsigned = MLM_TRUE; // bind_[15].is_null = &MLM_FALSE; // commented out for performance // reasons, see memset() above + // Add the error flags setErrorIndicators(bind_, error_, LEASE_COLUMNS); @@ -1202,11 +1207,11 @@ class MySqlLease6Exchange : public MySqlLeaseExchange { // schema. // Note: arrays are declared fixed length for speed of creation std::string addr6_; ///< String form of address - char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character + char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character ///< array form of V6 address unsigned long addr6_length_; ///< Length of the address MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array - std::string columns_[LEASE_COLUMNS];///< Column names + std::string columns_[LEASE_COLUMNS]; ///< Column names std::vector duid_; ///< Client identification uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID unsigned long duid_length_; ///< Length of the DUID @@ -1323,7 +1328,6 @@ class MySqlLeaseStatsQuery : public LeaseStatsQuery { conn_.checkError(status, statement_index_, "results storage failed"); } - /// @brief Fetches the next row in the result set /// /// Once the internal result set has been populated by invoking the @@ -1404,7 +1408,6 @@ MySqlLeaseMgr::MySqlLeaseMgr(const MySqlConnection::ParameterMap& parameters) exchange6_.reset(new MySqlLease6Exchange()); } - MySqlLeaseMgr::~MySqlLeaseMgr() { // There is no need to close the database in this destructor: it is // closed in the destructor of the mysql_ member variable. @@ -1562,7 +1565,6 @@ void MySqlLeaseMgr::getLeaseCollection(StatementIndex stindex, } } - void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind, Lease4Ptr& result) const { // Create appropriate collection object and get all leases matching @@ -1581,7 +1583,6 @@ void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind, } } - void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind, Lease6Ptr& result) const { // Create appropriate collection object and get all leases matching @@ -1600,7 +1601,6 @@ void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind, } } - // Basic lease access methods. Obtain leases from the database using various // criteria. @@ -1613,8 +1613,8 @@ MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const { MYSQL_BIND inbind[1]; memset(inbind, 0, sizeof(inbind)); - uint32_t addr4 = addr.toUint32(); - inbind[0].buffer_type = MYSQL_TYPE_LONG; + uint64_t addr4 = addr.addressPlusPortToUint64(); + inbind[0].buffer_type = MYSQL_TYPE_LONGLONG; inbind[0].buffer = reinterpret_cast(&addr4); inbind[0].is_unsigned = MLM_TRUE; @@ -1625,7 +1625,6 @@ MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const { return (result); } - Lease4Collection MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, @@ -1655,7 +1654,6 @@ MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const { return (result); } - Lease4Ptr MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, @@ -1690,7 +1688,6 @@ MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const { return (result); } - Lease4Collection MySqlLeaseMgr::getLease4(const ClientId& clientid) const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, @@ -1815,7 +1812,6 @@ MySqlLeaseMgr::getLease6(Lease::Type lease_type, return (result); } - Lease6Collection MySqlLeaseMgr::getLeases6(Lease::Type lease_type, const DUID& duid, uint32_t iaid) const { @@ -1959,8 +1955,6 @@ MySqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases, getLeaseCollection(statement_index, inbind, expired_leases); } - - // Update lease methods. These comprise common code that handles the actual // update, and type-specific methods that set up the parameters for the prepared // statement depending on the type of lease. @@ -1992,7 +1986,6 @@ MySqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, MYSQL_BIND* bind, } } - void MySqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { const StatementIndex stindex = UPDATE_LEASE4; @@ -2007,8 +2000,8 @@ MySqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { MYSQL_BIND where; memset(&where, 0, sizeof(where)); - uint32_t addr4 = lease->addr_.toUint32(); - where.buffer_type = MYSQL_TYPE_LONG; + uint64_t addr4 = lease->addr_.addressPlusPortToUint64(); + where.buffer_type = MYSQL_TYPE_LONGLONG; where.buffer = reinterpret_cast(&addr4); where.is_unsigned = MLM_TRUE; bind.push_back(where); @@ -2017,7 +2010,6 @@ MySqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { updateLeaseCommon(stindex, &bind[0], lease); } - void MySqlLeaseMgr::updateLease6(const Lease6Ptr& lease) { const StatementIndex stindex = UPDATE_LEASE6; @@ -2079,9 +2071,9 @@ MySqlLeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) { memset(inbind, 0, sizeof(inbind)); if (addr.isV4()) { - uint32_t addr4 = addr.toUint32(); + uint64_t addr4 = addr.addressPlusPortToUint64(); - inbind[0].buffer_type = MYSQL_TYPE_LONG; + inbind[0].buffer_type = MYSQL_TYPE_LONGLONG; inbind[0].buffer = reinterpret_cast(&addr4); inbind[0].is_unsigned = MLM_TRUE; @@ -2170,13 +2162,11 @@ MySqlLeaseMgr::getName() const { return (name); } - std::string MySqlLeaseMgr::getDescription() const { return (std::string("MySQL Database")); } - std::pair MySqlLeaseMgr::getVersion() const { const StatementIndex stindex = GET_VERSION; @@ -2253,7 +2243,6 @@ MySqlLeaseMgr::commit() { } } - void MySqlLeaseMgr::rollback() { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_ROLLBACK); diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index b10d7e7eda..2b9f61d3bb 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -738,6 +738,32 @@ Subnet4ConfigParser::initSubnet(data::ConstElementPtr params, /// client-class processing is now generic and handled in the common /// code (see isc::data::SubnetConfigParser::createSubnet) + // address plus port specific parameter: v4-psid-offset. If not explicitly specified, + // it will have the default value of "0". + uint8_t psid_offset = getInteger(params, "v4-psid-offset"); + if (psid_offset) { + subnet4->get4o6().setPsidOffset(psid_offset); + subnet4->get4o6().enabled(true); + } + + // address plus port specific parameter: v4-psid-len. If not explicitly + // specified, + // it will have the default value of "0". + uint8_t psid_len = getInteger(params, "v4-psid-len"); + if (psid_len) { + subnet4->get4o6().setPsidLen(psid_len); + subnet4->get4o6().enabled(true); + } + + ConstElementPtr excluded_psids = params->get("v4-excluded-psids"); + if (excluded_psids) { + BOOST_FOREACH (ConstElementPtr psid, excluded_psids->listValue()) { + int64_t value; + psid->getValue(value); + subnet4->getExcludedPSIDs().insert(static_cast(value)); + } + } + // Here globally defined options were merged to the subnet specific // options but this is no longer the case (they have a different // and not consecutive priority). @@ -849,7 +875,7 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) { OptionDataListParser opts_parser(AF_INET6); opts_parser.parse(options_, option_data); } - + ConstElementPtr user_context = pd_pool_->get("user-context"); if (user_context) { user_context_ = user_context; @@ -1000,7 +1026,7 @@ Subnet6ConfigParser::initSubnet(data::ConstElementPtr params, << ", rapid-commit is " << (rapid_commit ? "enabled" : "disabled"); - LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET4).arg(output.str()); + LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET6).arg(output.str()); // Create a new subnet. Subnet6* subnet6 = new Subnet6(addr, len, t1, t2, pref, valid, @@ -1155,9 +1181,9 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) { std::string sender_ip_str = getString(client_config, "sender-ip"); - uint32_t sender_port = getUint32(client_config, "sender-port"); + uint32_t sender_port = getUint32(client_config, "sender-port"); - uint32_t max_queue_size = getUint32(client_config, "max-queue-size"); + uint32_t max_queue_size = getUint32(client_config, "max-queue-size"); dhcp_ddns::NameChangeProtocol ncr_protocol = getProtocol(client_config, "ncr-protocol"); @@ -1186,9 +1212,9 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) { if (client_config->contains("qualifying-suffix")) { qualifying_suffix = getString(client_config, "qualifying-suffix"); found_qualifying_suffix = true; - } + } - IOAddress sender_ip(0); + IOAddress sender_ip(0U); if (sender_ip_str.empty()) { // The default sender IP depends on the server IP family sender_ip = (server_ip.isV4() ? IOAddress::IPV4_ZERO_ADDRESS() : diff --git a/src/lib/dhcpsrv/parsers/simple_parser4.cc b/src/lib/dhcpsrv/parsers/simple_parser4.cc index e766e96323..76286090fa 100644 --- a/src/lib/dhcpsrv/parsers/simple_parser4.cc +++ b/src/lib/dhcpsrv/parsers/simple_parser4.cc @@ -4,6 +4,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include + #include #include #include @@ -83,6 +85,8 @@ const SimpleDefaults SimpleParser4::SUBNET4_DEFAULTS = { { "4o6-interface", Element::string, "" }, { "4o6-interface-id", Element::string, "" }, { "4o6-subnet", Element::string, "" }, + { "v4-psid-offset", Element::integer, "0" }, + { "v4-psid-len", Element::integer, "0" }, }; /// @brief This table defines default values for each IPv4 subnet that is @@ -96,6 +100,8 @@ const SimpleDefaults SimpleParser4::SHARED_SUBNET4_DEFAULTS = { { "4o6-interface", Element::string, "" }, { "4o6-interface-id", Element::string, "" }, { "4o6-subnet", Element::string, "" }, + { "v4-psid-offset", Element::integer, "0" }, + { "v4-psid-len", Element::integer, "0" }, }; /// @brief This table defines default values for each IPv4 shared network. diff --git a/src/lib/dhcpsrv/parsers/simple_parser6.cc b/src/lib/dhcpsrv/parsers/simple_parser6.cc index f7ca2dba16..6384b8fb77 100644 --- a/src/lib/dhcpsrv/parsers/simple_parser6.cc +++ b/src/lib/dhcpsrv/parsers/simple_parser6.cc @@ -4,6 +4,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include + #include #include #include diff --git a/src/lib/dhcpsrv/pgsql_connection.cc b/src/lib/dhcpsrv/pgsql_connection.cc index 0e66d6e558..c706d60676 100644 --- a/src/lib/dhcpsrv/pgsql_connection.cc +++ b/src/lib/dhcpsrv/pgsql_connection.cc @@ -98,7 +98,10 @@ PgSqlTransaction::PgSqlTransaction(PgSqlConnection& conn) PgSqlTransaction::~PgSqlTransaction() { // If commit() wasn't explicitly called, rollback. if (!committed_) { - conn_.rollback(); + try { + conn_.rollback(); + } catch (...) { + } } } diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index 3d8c30cfdc..3bde83383e 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -68,7 +68,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_addr", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE address = $1"}, @@ -77,7 +78,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_clientid", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE client_id = $1"}, @@ -86,7 +88,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_clientid_subid", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE client_id = $1 AND subnet_id = $2"}, @@ -95,7 +98,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_hwaddr", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE hwaddr = $1"}, @@ -104,7 +108,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_hwaddr_subid", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE hwaddr = $1 AND subnet_id = $2"}, @@ -121,12 +126,13 @@ PgSqlTaggedStatement tagged_statements[] = { { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 }, "get_lease4_expire", "SELECT address, hwaddr, client_id, " - "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " - "FROM lease4 " - "WHERE state != $1 AND expire < $2 " - "ORDER BY expire " - "LIMIT $3"}, + "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " + "fqdn_fwd, fqdn_rev, hostname, " + "state " + "FROM lease4 " + "WHERE state != $1 AND expire < $2 " + "ORDER BY expire " + "LIMIT $3"}, // GET_LEASE6_ADDR { 2, { OID_VARCHAR, OID_INT2 }, @@ -163,14 +169,14 @@ PgSqlTaggedStatement tagged_statements[] = { { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 }, "get_lease6_expire", "SELECT address, duid, valid_lifetime, " - "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len, " - "fqdn_fwd, fqdn_rev, hostname, state " - "state " - "FROM lease6 " - "WHERE state != $1 AND expire < $2 " - "ORDER BY expire " - "LIMIT $3"}, + "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, " + "fqdn_fwd, fqdn_rev, hostname, " + "state " + "FROM lease6 " + "WHERE state != $1 AND expire < $2 " + "ORDER BY expire " + "LIMIT $3"}, // GET_VERSION { 0, { OID_NONE }, @@ -193,7 +199,8 @@ PgSqlTaggedStatement tagged_statements[] = { "insert_lease6", "INSERT INTO lease6(address, duid, valid_lifetime, " "expire, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, state) " + "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, " + "state) " "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)"}, // UPDATE_LEASE4 @@ -275,7 +282,6 @@ class PgSqlLeaseExchange : public PgSqlExchange { }; - /// @brief Supports exchanging IPv4 leases with PostgreSQL. class PgSqlLease4Exchange : public PgSqlLeaseExchange { private: @@ -344,7 +350,7 @@ class PgSqlLease4Exchange : public PgSqlLeaseExchange { try { addr_str_ = boost::lexical_cast - (lease->addr_.toUint32()); + (lease->addr_.addressPlusPortToUint64()); bind_array.add(addr_str_); if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) { @@ -437,7 +443,9 @@ class PgSqlLease4Exchange : public PgSqlLeaseExchange { valid_lifetime_, 0, 0, cltt_, subnet_id_, fqdn_fwd_, fqdn_rev_, hostname_)); + result->state_ = state; + return (result); } catch (const std::exception& ex) { isc_throw(DbOperationError, @@ -453,7 +461,7 @@ class PgSqlLease4Exchange : public PgSqlLeaseExchange { Lease4Ptr lease_; /// @Brief Lease4 specific members used for binding and conversion. - uint32_t addr4_; + uint64_t addr4_; size_t hwaddr_length_; std::vector hwaddr_; uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; @@ -646,7 +654,9 @@ class PgSqlLease6Exchange : public PgSqlLeaseExchange { subnet_id_, fqdn_fwd_, fqdn_rev_, hostname_, hwaddr, prefix_len_)); result->cltt_ = cltt_; + result->state_ = state; + return (result); } catch (const std::exception& ex) { isc_throw(DbOperationError, @@ -929,7 +939,6 @@ void PgSqlLeaseMgr::getLeaseCollection(StatementIndex stindex, } } - void PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array, Lease4Ptr& result) const { @@ -949,7 +958,6 @@ PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array, } } - void PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array, Lease6Ptr& result) const { @@ -979,7 +987,7 @@ PgSqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const { // LEASE ADDRESS std::string addr_str = boost::lexical_cast - (addr.toUint32()); + (addr.addressPlusPortToUint64()); bind_array.add(addr_str); // Get the data @@ -1247,7 +1255,6 @@ PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases, getLeaseCollection(statement_index, bind_array, expired_leases); } - template void PgSqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, @@ -1283,7 +1290,6 @@ PgSqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, "that had the address " << lease->addr_.toText()); } - void PgSqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { const StatementIndex stindex = UPDATE_LEASE4; @@ -1296,9 +1302,9 @@ PgSqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { exchange4_->createBindForSend(lease, bind_array); // Set up the WHERE clause and append it to the SQL_BIND array - std::string addr4_ = boost::lexical_cast - (lease->addr_.toUint32()); - bind_array.add(addr4_); + std::string addr4_str = boost::lexical_cast + (lease->addr_.addressPlusPortToUint64()); + bind_array.add(addr4_str); // Drop to common update code updateLeaseCommon(stindex, bind_array, lease); @@ -1348,7 +1354,7 @@ PgSqlLeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) { if (addr.isV4()) { std::string addr4_str = boost::lexical_cast - (addr.toUint32()); + (addr.addressPlusPortToUint64()); bind_array.add(addr4_str); return (deleteLeaseCommon(DELETE_LEASE4, bind_array) > 0); } diff --git a/src/lib/dhcpsrv/sql_common.h b/src/lib/dhcpsrv/sql_common.h index 610abd62e1..a8795e91df 100644 --- a/src/lib/dhcpsrv/sql_common.h +++ b/src/lib/dhcpsrv/sql_common.h @@ -32,9 +32,7 @@ enum ExchangeDataType { EXCHANGE_DATA_TYPE_TIMESTAMP, EXCHANGE_DATA_TYPE_STRING, EXCHANGE_DATA_TYPE_BYTES, - EXCHANGE_DATA_TYPE_UUID, - EXCHANGE_DATA_TYPE_UDT, ///< User-Defined Type (used in Cassandra) - EXCHANGE_DATA_TYPE_COLLECTION ///< Collection (used in Cassandra) + EXCHANGE_DATA_TYPE_UUID }; /// @brief Base class for backend exchanges. diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc index 86b05f1609..e93b12d23b 100644 --- a/src/lib/dhcpsrv/subnet.cc +++ b/src/lib/dhcpsrv/subnet.cc @@ -278,6 +278,13 @@ isc::asiolink::IOAddress Subnet4::getSiaddr() const { return (siaddr_); } +bool Subnet4::isExcludedAddress(const asiolink::IOAddress& address) { + if (address.getPsidLen()) { + return excludedPSIDs.find(address.getPsid()) != excludedPSIDs.end(); + } + return false; +} + void Subnet4::setSname(const std::string& sname) { sname_ = sname; } diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h index 52b059a8e1..18e3852a7a 100644 --- a/src/lib/dhcpsrv/subnet.h +++ b/src/lib/dhcpsrv/subnet.h @@ -28,6 +28,8 @@ namespace isc { namespace dhcp { +typedef std::set PSIDContainer; + class Subnet : public virtual UserContext, public data::CfgToElement { // Assignable network is our friend to allow it to call @@ -519,6 +521,18 @@ class Subnet4 : public Subnet, public Network4 { return (dhcp4o6_); } + /// @brief Returns container with excluded PSIDs. + /// + /// @return container with excluded PSIDs + PSIDContainer& getExcludedPSIDs() { + return (excludedPSIDs); + } + + /// @brief Returns if address contains excluded PSID. + /// + /// @return true if address contains excluded PSID, false otherwise + bool isExcludedAddress(const asiolink::IOAddress& address); + /// @brief Unparse a subnet object. /// /// @return A pointer to unparsed subnet configuration. @@ -551,6 +565,9 @@ class Subnet4 : public Subnet, public Network4 { /// @brief All the information related to DHCP4o6 Cfg4o6 dhcp4o6_; + + /// @brief container with excluded PSIDs + PSIDContainer excludedPSIDs; }; class Subnet6; diff --git a/src/lib/dhcpsrv/subnet_selector.h b/src/lib/dhcpsrv/subnet_selector.h index 559fac5633..e9561c6385 100644 --- a/src/lib/dhcpsrv/subnet_selector.h +++ b/src/lib/dhcpsrv/subnet_selector.h @@ -51,6 +51,15 @@ struct SubnetSelector { /// @brief Specifies if the packet is DHCP4o6 bool dhcp4o6_; + /// @brief Specifies if the packet contains address plus port information + bool address_plus_port_; + + /// @brief Specifies the packet offset for address plus port + uint8_t psid_offset_; + + /// @brief Specifies the packet psid-len for address plus port + uint8_t psid_len_; + /// @brief Default constructor. /// /// Sets the default values for the @c Selector. @@ -63,7 +72,8 @@ struct SubnetSelector { local_address_(asiolink::IOAddress("0.0.0.0")), remote_address_(asiolink::IOAddress("0.0.0.0")), client_classes_(), iface_name_(std::string()), - dhcp4o6_(false) { + dhcp4o6_(false), address_plus_port_(false), + psid_offset_(0), psid_len_(0) { } }; diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index 4696247e1d..9b1cc36f3a 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -85,6 +85,24 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { initializeTest(); } + /// @brief Destroys the LM and the schema. + void destroyTest() { + try { + lmptr_->rollback(); + } catch (...) { + // Rollback may fail if backend is in read only mode. That's ok. + } + LeaseMgrFactory::destroy(); + destroyCqlSchema(false, true); + } + + /// @brief Constructor + /// + /// Deletes everything from the database and opens it. + CqlLeaseMgrTest() { + initializeTest(); + } + /// @brief Destructor /// /// Rolls back all pending transactions. The deletion of lmptr_ will close diff --git a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc index 63a81b4539..6c6b1048fe 100644 --- a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc @@ -35,11 +35,8 @@ namespace { class MySqlHostDataSourceTest : public GenericHostDataSourceTest { public: - /// @brief Constructor - /// - /// Deletes everything from the database and opens it. - MySqlHostDataSourceTest() { - + /// @brief Clears the database and opens connection to it. + void initializeTest() { // Ensure schema is the correct one. destroyMySQLSchema(); createMySQLSchema(); @@ -59,21 +56,32 @@ class MySqlHostDataSourceTest : public GenericHostDataSourceTest { hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr(); } - /// @brief Destructor - /// - /// Rolls back all pending transactions. The deletion of myhdsptr_ will close - /// the database. Then reopen it and delete everything created by the test. - virtual ~MySqlHostDataSourceTest() { + /// @brief Destroys the HDS and the schema. + void destroyTest() { try { hdsptr_->rollback(); } catch (...) { // Rollback may fail if backend is in read only mode. That's ok. } HostDataSourceFactory::destroy(); - hdsptr_.reset(); destroyMySQLSchema(); } + /// @brief Constructor + /// + /// Deletes everything from the database and opens it. + MySqlHostDataSourceTest() { + initializeTest(); + } + + /// @brief Destructor + /// + /// Rolls back all pending transactions. The deletion of myhdsptr_ will close + /// the database. Then reopen it and delete everything created by the test. + virtual ~MySqlHostDataSourceTest() { + destroyTest(); + } + /// @brief Reopen the database /// /// Closes the database and re-open it. Anything committed should be diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc index 609ddabe6e..bf0ec54536 100644 --- a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc @@ -39,11 +39,8 @@ namespace { class MySqlLeaseMgrTest : public GenericLeaseMgrTest { public: - /// @brief Constructor - /// - /// Deletes everything from the database and opens it. - MySqlLeaseMgrTest() { - + /// @brief Clears the database and opens connection to it. + void initializeTest() { // Ensure schema is the correct one. destroyMySQLSchema(); createMySQLSchema(); @@ -59,17 +56,34 @@ class MySqlLeaseMgrTest : public GenericLeaseMgrTest { "*** accompanying exception output.\n"; throw; } + lmptr_ = &(LeaseMgrFactory::instance()); } + /// @brief Destroys the LM and the schema. + void destroyTest() { + try { + lmptr_->rollback(); + } catch (...) { + // Rollback may fail if backend is in read only mode. That's ok. + } + LeaseMgrFactory::destroy(); + destroyMySQLSchema(); + } + + /// @brief Constructor + /// + /// Deletes everything from the database and opens it. + MySqlLeaseMgrTest() { + initializeTest(); + } + /// @brief Destructor /// /// Rolls back all pending transactions. The deletion of lmptr_ will close /// the database. Then reopen it and delete everything created by the test. virtual ~MySqlLeaseMgrTest() { - lmptr_->rollback(); - LeaseMgrFactory::destroy(); - destroyMySQLSchema(); + destroyTest(); } /// @brief Reopen the database diff --git a/src/lib/dhcpsrv/tests/pgsql_exchange_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_exchange_unittest.cc index 6f6ba77dc5..01674d7bb9 100644 --- a/src/lib/dhcpsrv/tests/pgsql_exchange_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_exchange_unittest.cc @@ -598,7 +598,7 @@ TEST_F(PgSqlBasicsTest, smallIntTest) { ints.push_back(-1); ints.push_back(0); ints.push_back(0x7fff); - ints.push_back(0xffff); + ints.push_back(static_cast(0xffff)); // Insert a row for each reference value PsqlBindArrayPtr bind_array; diff --git a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc index 269fe77e95..792e66a231 100644 --- a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc @@ -35,11 +35,8 @@ namespace { class PgSqlHostDataSourceTest : public GenericHostDataSourceTest { public: - /// @brief Constructor - /// - /// Deletes everything from the database and opens it. - PgSqlHostDataSourceTest() { - + /// @brief Clears the database and opens connection to it. + void initializeTest() { // Ensure schema is the correct one. destroyPgSQLSchema(); createPgSQLSchema(); @@ -59,22 +56,33 @@ class PgSqlHostDataSourceTest : public GenericHostDataSourceTest { hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr(); } - /// @brief Destructor - /// - /// Rolls back all pending transactions. The deletion of myhdsptr_ will - /// close the database. Then reopen it and delete everything created by - /// the test. - virtual ~PgSqlHostDataSourceTest() { + /// @brief Destroys the HDS and the schema. + void destroyTest() { try { hdsptr_->rollback(); } catch (...) { // Rollback may fail if backend is in read only mode. That's ok. } HostDataSourceFactory::destroy(); - hdsptr_.reset(); destroyPgSQLSchema(); } + /// @brief Constructor + /// + /// Deletes everything from the database and opens it. + PgSqlHostDataSourceTest() { + initializeTest(); + } + + /// @brief Destructor + /// + /// Rolls back all pending transactions. The deletion of myhdsptr_ will + /// close the database. Then reopen it and delete everything created by + /// the test. + virtual ~PgSqlHostDataSourceTest() { + destroyTest(); + } + /// @brief Reopen the database /// /// Closes the database and re-open it. Anything committed should be diff --git a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc index fa84bbb99b..0862e335ed 100644 --- a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc @@ -31,11 +31,8 @@ namespace { class PgSqlLeaseMgrTest : public GenericLeaseMgrTest { public: - /// @brief Constructor - /// - /// Deletes everything from the database and opens it. - PgSqlLeaseMgrTest() { - + /// @brief Clears the database and opens connection to it. + void initializeTest() { // Ensure schema is the correct one. destroyPgSQLSchema(); createPgSQLSchema(); @@ -51,17 +48,34 @@ class PgSqlLeaseMgrTest : public GenericLeaseMgrTest { "*** accompanying exception output.\n"; throw; } + lmptr_ = &(LeaseMgrFactory::instance()); } + /// @brief Destroys the LM and the schema. + void destroyTest() { + try { + lmptr_->rollback(); + } catch (...) { + // Rollback may fail if backend is in read only mode. That's ok. + } + LeaseMgrFactory::destroy(); + destroyPgSQLSchema(); + } + + /// @brief Constructor + /// + /// Deletes everything from the database and opens it. + PgSqlLeaseMgrTest() { + initializeTest(); + } + /// @brief Destructor /// /// Rolls back all pending transactions. The deletion of lmptr_ will close /// the database. Then reopen it and delete everything created by the test. virtual ~PgSqlLeaseMgrTest() { - lmptr_->rollback(); - LeaseMgrFactory::destroy(); - destroyPgSQLSchema(); + destroyTest(); } /// @brief Reopen the database @@ -76,7 +90,6 @@ class PgSqlLeaseMgrTest : public GenericLeaseMgrTest { LeaseMgrFactory::create(validPgSQLConnectionString()); lmptr_ = &(LeaseMgrFactory::instance()); } - }; /// @brief Check that database can be opened @@ -96,7 +109,7 @@ TEST(PgSqlOpenTest, OpenDatabase) { // If it fails, print the error message. try { LeaseMgrFactory::create(validPgSQLConnectionString()); - EXPECT_NO_THROW((void) LeaseMgrFactory::instance()); + EXPECT_NO_THROW((void)LeaseMgrFactory::instance()); LeaseMgrFactory::destroy(); } catch (const isc::Exception& ex) { FAIL() << "*** ERROR: unable to open database, reason:\n" @@ -108,10 +121,10 @@ TEST(PgSqlOpenTest, OpenDatabase) { // Check that lease manager open the database opens correctly with a longer // timeout. If it fails, print the error message. try { - string connection_string = validPgSQLConnectionString() + string(" ") + - string(VALID_TIMEOUT); + string connection_string = + validPgSQLConnectionString() + string(" ") + string(VALID_TIMEOUT); LeaseMgrFactory::create(connection_string); - EXPECT_NO_THROW((void) LeaseMgrFactory::instance()); + EXPECT_NO_THROW((void)LeaseMgrFactory::instance()); LeaseMgrFactory::destroy(); } catch (const isc::Exception& ex) { FAIL() << "*** ERROR: unable to open database, reason:\n" @@ -127,45 +140,56 @@ TEST(PgSqlOpenTest, OpenDatabase) { // Check that wrong specification of backend throws an exception. // (This is really a check on LeaseMgrFactory, but is convenient to // perform here.) - EXPECT_THROW(LeaseMgrFactory::create(connectionString( - NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)), + EXPECT_THROW( + LeaseMgrFactory::create(connectionString(NULL, VALID_NAME, VALID_HOST, + INVALID_USER, VALID_PASSWORD)), InvalidParameter); - EXPECT_THROW(LeaseMgrFactory::create(connectionString( - INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)), + EXPECT_THROW( + LeaseMgrFactory::create(connectionString( + INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)), InvalidType); // Check that invalid login data causes an exception. - EXPECT_THROW(LeaseMgrFactory::create(connectionString( - PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)), - DbOpenError); + EXPECT_THROW(LeaseMgrFactory::create( + connectionString(PGSQL_VALID_TYPE, INVALID_NAME, + VALID_HOST, VALID_USER, VALID_PASSWORD)), + DbOpenError); EXPECT_THROW(LeaseMgrFactory::create(connectionString( - PGSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)), - DbOpenError); + PGSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, + VALID_PASSWORD)), + DbOpenError); - EXPECT_THROW(LeaseMgrFactory::create(connectionString( - PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)), - DbOpenError); + EXPECT_THROW(LeaseMgrFactory::create( + connectionString(PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, + INVALID_USER, VALID_PASSWORD)), + DbOpenError); - // This test might fail if 'auth-method' in PostgresSQL host-based authentication + // This test might fail if 'auth-method' in PostgresSQL host-based + // authentication // file (/var/lib/pgsql/9.4/data/pg_hba.conf) is set to 'trust', - // which allows logging without password. 'Auth-method' should be changed to 'password'. - EXPECT_THROW(LeaseMgrFactory::create(connectionString( - PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)), - DbOpenError); + // which allows logging without password. 'Auth-method' should be changed to + // 'password'. + EXPECT_THROW(LeaseMgrFactory::create( + connectionString(PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, + VALID_USER, INVALID_PASSWORD)), + DbOpenError); // Check for invalid timeouts EXPECT_THROW(LeaseMgrFactory::create(connectionString( - PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)), - DbInvalidTimeout); + PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, + VALID_PASSWORD, INVALID_TIMEOUT_1)), + DbInvalidTimeout); EXPECT_THROW(LeaseMgrFactory::create(connectionString( - PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)), - DbInvalidTimeout); + PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, + VALID_PASSWORD, INVALID_TIMEOUT_2)), + DbInvalidTimeout); // Check for missing parameters - EXPECT_THROW(LeaseMgrFactory::create(connectionString( - PGSQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)), + EXPECT_THROW( + LeaseMgrFactory::create(connectionString( + PGSQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)), NoDatabaseName); // Tidy up after the test @@ -292,8 +316,9 @@ TEST_F(PgSqlLeaseMgrTest, getLeases4) { /// @brief Basic Lease4 Checks /// -/// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id), -/// updateLease4() and deleteLease (IPv4 address) can handle NULL client-id. +/// Checks that the addLease, getLease4(by address), +/// getLease4(hwaddr,subnet_id), +/// updateLease4() and deleteLease can handle NULL client-id. /// (client-id is optional and may not be present) TEST_F(PgSqlLeaseMgrTest, lease4NullClientId) { testLease4NullClientId(); @@ -412,6 +437,11 @@ TEST_F(PgSqlLeaseMgrTest, getExpiredLeases6) { testGetExpiredLeases6(); } +/// @brief Check that expired reclaimed DHCPv6 leases are removed. +TEST_F(PgSqlLeaseMgrTest, deleteExpiredReclaimedLeases6) { + testDeleteExpiredReclaimedLeases6(); +} + // Verifies that IPv4 lease statistics can be recalculated. TEST_F(PgSqlLeaseMgrTest, recountLeaseStats4) { testRecountLeaseStats4(); diff --git a/src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc b/src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc index 9644fc95e4..9b0f96e406 100644 --- a/src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc +++ b/src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc @@ -58,6 +58,8 @@ class SharedNetwork4ParserTest : public ::testing::Test { " \"4o6-interface-id\": \"\"," " \"4o6-subnet\": \"\"," " \"dhcp4o6-port\": 0," + " \"v4-psid-offset\": 0," + " \"v4-psid-len\": 0," " \"decline-probation-period\": 86400," " \"reservation-mode\": \"all\"" " }," @@ -78,6 +80,8 @@ class SharedNetwork4ParserTest : public ::testing::Test { " \"4o6-interface-id\": \"\"," " \"4o6-subnet\": \"\"," " \"dhcp4o6-port\": 0," + " \"v4-psid-offset\": 0," + " \"v4-psid-len\": 0," " \"decline-probation-period\": 86400," " \"reservation-mode\": \"all\"" " }" diff --git a/src/lib/dhcpsrv/testutils/cql_schema.cc b/src/lib/dhcpsrv/testutils/cql_schema.cc index 8a4468e39e..115c3f176e 100644 --- a/src/lib/dhcpsrv/testutils/cql_schema.cc +++ b/src/lib/dhcpsrv/testutils/cql_schema.cc @@ -79,8 +79,10 @@ runCqlScript(const std::string& path, cmd << script_name; - int retval = ::system(cmd.str().c_str()); - ASSERT_EQ(0, retval) << "runCqlSchema failed:" << cmd.str(); + int32_t retval = ::system(cmd.str().c_str()); + if (retval) { + std::cerr << "runCqlSchema failed:" << cmd.str() << std::endl; + } } } // namespace test diff --git a/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc b/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc index 36a37efb48..41be4192a0 100644 --- a/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc +++ b/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc @@ -31,6 +31,12 @@ Dhcp4o6TestIpc::open() { } } +void +Dhcp4o6TestIpc::close() { + // Use the base IPC to close the socket + Dhcp4o6IpcBase::close(); +} + void Dhcp4o6TestIpc::receiveHandler() { pkt_received_ = receive(); diff --git a/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h b/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h index 5109de06c3..6af2295395 100644 --- a/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h +++ b/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h @@ -43,6 +43,9 @@ class Dhcp4o6TestIpc : public Dhcp4o6IpcBase { /// over the socket. virtual void open(); + /// @brief Close the IPC socket. + virtual void close(); + /// @brief Retrieve port which socket is bound to. uint16_t getPort() const { return (port_); diff --git a/src/lib/dhcpsrv/testutils/mysql_schema.cc b/src/lib/dhcpsrv/testutils/mysql_schema.cc index a216e4f49e..3b79d975b0 100644 --- a/src/lib/dhcpsrv/testutils/mysql_schema.cc +++ b/src/lib/dhcpsrv/testutils/mysql_schema.cc @@ -53,10 +53,11 @@ void runMySQLScript(const std::string& path, const std::string& script_name, cmd << script_name; int retval = ::system(cmd.str().c_str()); - ASSERT_EQ(0, retval) << "runMySQLSchema failed:" << cmd.str(); + if (retval) { + std::cerr << "runMySQLSchema failed:" << cmd.str() << std::endl; + } } - }; }; }; diff --git a/src/lib/dhcpsrv/testutils/pgsql_schema.cc b/src/lib/dhcpsrv/testutils/pgsql_schema.cc index 319fafd5ba..57729e1747 100644 --- a/src/lib/dhcpsrv/testutils/pgsql_schema.cc +++ b/src/lib/dhcpsrv/testutils/pgsql_schema.cc @@ -56,7 +56,9 @@ void runPgSQLScript(const std::string& path, const std::string& script_name, } int retval = ::system(cmd.str().c_str()); - ASSERT_EQ(0, retval) << "runPgSQLSchema failed:" << cmd.str(); + if (retval) { + std::cerr << "runPgSQLSchema failed:" << cmd.str() << std::endl; + } } }; diff --git a/src/share/database/scripts/cql/.gitignore b/src/share/database/scripts/cql/.gitignore index d184e0fe31..9976ce894b 100644 --- a/src/share/database/scripts/cql/.gitignore +++ b/src/share/database/scripts/cql/.gitignore @@ -1,2 +1 @@ upgrade_1.0_to_2.0.sh - diff --git a/src/share/database/scripts/cql/Makefile.am b/src/share/database/scripts/cql/Makefile.am index 46f8e26f8e..68e7be4c3e 100644 --- a/src/share/database/scripts/cql/Makefile.am +++ b/src/share/database/scripts/cql/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = . sqlscriptsdir = ${datarootdir}/${PACKAGE_NAME}/scripts/cql -sqlscripts_DATA = dhcpdb_create.cql +sqlscripts_DATA = dhcpdb_create.cql sqlscripts_DATA += dhcpdb_drop.cql sqlscripts_DATA += upgrade_1.0_to_2.0.sh sqlscripts_DATA += soft_wipe.cql diff --git a/src/share/database/scripts/cql/dhcpdb_create.cql b/src/share/database/scripts/cql/dhcpdb_create.cql index 2d6ab7d86f..1ee2bd652c 100644 --- a/src/share/database/scripts/cql/dhcpdb_create.cql +++ b/src/share/database/scripts/cql/dhcpdb_create.cql @@ -45,7 +45,7 @@ -- Table `lease4` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS lease4 ( - address int, + address bigint, hwaddr blob, client_id blob, valid_lifetime bigint, @@ -226,7 +226,7 @@ CREATE INDEX IF NOT EXISTS host_reservationsindex5 ON host_reservations (host_ip CREATE INDEX IF NOT EXISTS host_reservationsindex6 ON host_reservations (reserved_ipv6_prefix_address); CREATE INDEX IF NOT EXISTS host_reservationsindex7 ON host_reservations (reserved_ipv6_prefix_length); -TRUNCATE SCHEMA_VERSION; +DELETE FROM schema_version WHERE version=1; INSERT INTO schema_version (version, minor) VALUES(2, 0); -- This line concludes database upgrade to version 2.0 diff --git a/src/share/database/scripts/mysql/.gitignore b/src/share/database/scripts/mysql/.gitignore index b5670c1823..0ec9579b3a 100644 --- a/src/share/database/scripts/mysql/.gitignore +++ b/src/share/database/scripts/mysql/.gitignore @@ -1,7 +1,8 @@ -/upgrade_1.0_to_2.0.sh -/upgrade_2.0_to_3.0.sh -/upgrade_3.0_to_4.0.sh -/upgrade_4.0_to_4.1.sh -/upgrade_4.1_to_5.0.sh -/upgrade_5.0_to_5.1.sh -/upgrade_5.1_to_6.0.sh +upgrade_1.0_to_2.0.sh +upgrade_2.0_to_3.0.sh +upgrade_3.0_to_4.0.sh +upgrade_4.0_to_4.1.sh +upgrade_4.1_to_5.0.sh +upgrade_5.0_to_5.1.sh +upgrade_5.1_to_6.0.sh +upgrade_6.0_to_7.0.sh diff --git a/src/share/database/scripts/mysql/Makefile.am b/src/share/database/scripts/mysql/Makefile.am index cfc8134d96..68bb708341 100644 --- a/src/share/database/scripts/mysql/Makefile.am +++ b/src/share/database/scripts/mysql/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = . sqlscriptsdir = ${datarootdir}/${PACKAGE_NAME}/scripts/mysql -sqlscripts_DATA = dhcpdb_create.mysql +sqlscripts_DATA = dhcpdb_create.mysql sqlscripts_DATA += dhcpdb_drop.mysql sqlscripts_DATA += upgrade_1.0_to_2.0.sh sqlscripts_DATA += upgrade_2.0_to_3.0.sh @@ -10,6 +10,7 @@ sqlscripts_DATA += upgrade_4.0_to_4.1.sh sqlscripts_DATA += upgrade_4.1_to_5.0.sh sqlscripts_DATA += upgrade_5.0_to_5.1.sh sqlscripts_DATA += upgrade_5.1_to_6.0.sh +sqlscripts_DATA += upgrade_6.0_to_7.0.sh DISTCLEANFILES = upgrade_1.0_to_2.0.sh DISTCLEANFILES += upgrade_2.0_to_3.0.sh @@ -18,5 +19,6 @@ DISTCLEANFILES += upgrade_4.0_to_4.1.sh DISTCLEANFILES += upgrade_4.1_to_5.0.sh DISTCLEANFILES += upgrade_5.0_to_5.1.sh DISTCLEANFILES += upgrade_5.1_to_6.0.sh +DISTCLEANFILES += upgrade_6.0_to_7.0.sh EXTRA_DIST = ${sqlscripts_DATA} diff --git a/src/share/database/scripts/mysql/dhcpdb_create.mysql b/src/share/database/scripts/mysql/dhcpdb_create.mysql index b1cdd1d058..3aa0e05346 100644 --- a/src/share/database/scripts/mysql/dhcpdb_create.mysql +++ b/src/share/database/scripts/mysql/dhcpdb_create.mysql @@ -43,7 +43,6 @@ CREATE TABLE lease4 ( hostname VARCHAR(255) # The FQDN of the client ) ENGINE = INNODB; - # Create search indexes for lease4 table # index by hwaddr and subnet_id CREATE INDEX lease4_by_hwaddr_subnet_id ON lease4 (hwaddr, subnet_id); @@ -521,6 +520,13 @@ UPDATE schema_version SET version = '6', minor = '0'; # This line concludes database upgrade to version 6.0. +ALTER TABLE lease4 MODIFY address BIGINT UNSIGNED NOT NULL; + +# Update the schema version number +UPDATE schema_version +SET version = '7', minor = '0'; +# This line concludes database upgrade to version 7.0. + # Notes: # # Indexes diff --git a/src/share/database/scripts/mysql/upgrade_6.0_to_7.0.sh.in b/src/share/database/scripts/mysql/upgrade_6.0_to_7.0.sh.in new file mode 100644 index 0000000000..4fac437706 --- /dev/null +++ b/src/share/database/scripts/mysql/upgrade_6.0_to_7.0.sh.in @@ -0,0 +1,31 @@ +#!/bin/sh + +# Include utilities. Use installed version if available and +# use build version if it isn't. +if [ -e @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh ]; then + . @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh +else + . @abs_top_builddir@/src/bin/admin/admin-utils.sh +fi + +VERSION=`mysql_version "$@"` + +if [ "$VERSION" != "6.0" ]; then + printf "This script upgrades 6.0 to 7.0. Reported version is $VERSION. Skipping upgrade.\n" + exit 0 +fi + +mysql "$@" < Date: Thu, 1 Feb 2018 18:44:03 +0200 Subject: [PATCH 02/34] fixed merge --- src/lib/dhcpsrv/alloc_engine.h | 4 +++- src/lib/dhcpsrv/cql_lease_mgr.cc | 2 +- .../dhcpsrv/tests/cql_lease_mgr_unittest.cc | 18 ------------------ 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index 020f2f5a10..654223e689 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -143,6 +143,7 @@ class AllocEngine : public boost::noncopyable { virtual isc::asiolink::IOAddress pickAddressInternal(const SubnetPtr& subnet, + const ClientClasses& client_classes, const DuidPtr& duid, const isc::asiolink::IOAddress& hint, uint8_t psid_offset, @@ -174,7 +175,8 @@ class AllocEngine : public boost::noncopyable { /// @return result address or prefix static isc::asiolink::IOAddress increaseAddress(const isc::asiolink::IOAddress& address, - bool prefix, const uint8_t prefix_len); + bool prefix, const uint8_t prefix_len, + uint8_t psid_offset = 0, uint8_t psid_len = 0); }; diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index 24fde3f76d..1805d5256a 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -537,7 +537,7 @@ CqlLease4Exchange::createBindForDelete(const IOAddress &address, AnyArray &data, try { // address: bigint - address_ = lease_->addr_.addressPlusPortToUint64(); + address_ = address.addressPlusPortToUint64(); // Start with a fresh array. data.clear(); diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index 9b1cc36f3a..4696247e1d 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -85,24 +85,6 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { initializeTest(); } - /// @brief Destroys the LM and the schema. - void destroyTest() { - try { - lmptr_->rollback(); - } catch (...) { - // Rollback may fail if backend is in read only mode. That's ok. - } - LeaseMgrFactory::destroy(); - destroyCqlSchema(false, true); - } - - /// @brief Constructor - /// - /// Deletes everything from the database and opens it. - CqlLeaseMgrTest() { - initializeTest(); - } - /// @brief Destructor /// /// Rolls back all pending transactions. The deletion of lmptr_ will close From a238b7c7bb4232c6a4ea63f2867fe37d32e570bb Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Feb 2018 19:07:33 +0200 Subject: [PATCH 03/34] add static casts --- src/lib/dhcpsrv/cql_lease_mgr.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index 1805d5256a..c8297c4a70 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -358,7 +358,7 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) { // address: bigint // The address in the Lease structure is an IOAddress object. // Convert this to an integer for storage. - address_ = lease_->addr_.addressPlusPortToUint64(); + address_ = static_cast(lease_->addr_.addressPlusPortToUint64()); // hwaddr: blob if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { @@ -451,7 +451,7 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, // address: bigint // The address in the Lease structure is an IOAddress object. // Convert this to an integer for storage. - address_ = lease_->addr_.addressPlusPortToUint64(); + address_ = static_cast(lease_->addr_.addressPlusPortToUint64()); // hwaddr: blob if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { @@ -537,7 +537,7 @@ CqlLease4Exchange::createBindForDelete(const IOAddress &address, AnyArray &data, try { // address: bigint - address_ = address.addressPlusPortToUint64(); + address_ = static_cast(address.addressPlusPortToUint64()); // Start with a fresh array. data.clear(); From 67483dc93fc909116e1db5acbef30f880acc98fb Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Feb 2018 19:31:49 +0200 Subject: [PATCH 04/34] minor changes --- src/lib/dhcpsrv/cql_lease_mgr.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index c8297c4a70..c8b186f23b 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -1500,8 +1500,8 @@ CqlLeaseMgr::getLease4(const IOAddress &addr) const { // Set up the WHERE clause value AnyArray data; - cass_int64_t address = static_cast(addr.addressPlusPortToUint64()); - data.add(&address); + cass_int64_t addr4 = static_cast(addr.addressPlusPortToUint64()); + data.add(&addr4); // Get the data. Lease4Ptr result; From 08688233cc15e3254dc1a75287e05bf9f4d73ddd Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Feb 2018 19:47:59 +0200 Subject: [PATCH 05/34] minor changes --- src/lib/dhcpsrv/cql_lease_mgr.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index c8b186f23b..771cedc507 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -361,7 +361,7 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) { address_ = static_cast(lease_->addr_.addressPlusPortToUint64()); // hwaddr: blob - if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { + if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) { if (lease_->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) { isc_throw(DbOperationError, "hardware address " @@ -376,7 +376,7 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) { } // client_id: blob - if (lease_->client_id_ && lease->client_id_->getClientId().size() > 0) { + if (lease_->client_id_ && lease_->client_id_->getClientId().size() > 0) { client_id_ = lease_->client_id_->getClientId(); } else { client_id_.clear(); @@ -454,7 +454,7 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, address_ = static_cast(lease_->addr_.addressPlusPortToUint64()); // hwaddr: blob - if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { + if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) { if (lease_->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) { isc_throw(DbOperationError, "hardware address " @@ -469,7 +469,7 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, } // client_id: blob - if (lease_->client_id_ && lease->client_id_->getClientId().size() > 0) { + if (lease_->client_id_ && lease_->client_id_->getClientId().size() > 0) { client_id_ = lease_->client_id_->getClientId(); } else { client_id_.clear(); @@ -1022,7 +1022,7 @@ CqlLease6Exchange::createBindForInsert(const Lease6Ptr &lease, AnyArray &data) { hostname_ = lease_->hostname_; // hwaddr: blob - if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { + if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) { if (lease_->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) { isc_throw(DbOperationError, "hardware address " << lease_->hwaddr_->toText() << " of length " << lease_->hwaddr_->hwaddr_.size() @@ -1152,7 +1152,7 @@ CqlLease6Exchange::createBindForUpdate(const Lease6Ptr &lease, AnyArray &data, hostname_ = lease_->hostname_; // hwaddr: blob - if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { + if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) { if (lease_->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) { isc_throw(DbOperationError, "hardware address " From 6012b295b302b871ac6e855d182afac537d8c696 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Fri, 2 Feb 2018 11:29:31 +0200 Subject: [PATCH 06/34] fixed unit tests --- src/lib/dhcpsrv/mysql_connection.h | 2 +- src/lib/dhcpsrv/parsers/dbaccess_parser.cc | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/lib/dhcpsrv/mysql_connection.h b/src/lib/dhcpsrv/mysql_connection.h index cf2a64f95b..6cc8061589 100644 --- a/src/lib/dhcpsrv/mysql_connection.h +++ b/src/lib/dhcpsrv/mysql_connection.h @@ -40,7 +40,7 @@ extern const int MLM_MYSQL_FETCH_FAILURE; /// @name Current database schema version values. //@{ -const uint32_t MYSQL_SCHEMA_VERSION_MAJOR = 6; +const uint32_t MYSQL_SCHEMA_VERSION_MAJOR = 7; const uint32_t MYSQL_SCHEMA_VERSION_MINOR = 0; //@} diff --git a/src/lib/dhcpsrv/parsers/dbaccess_parser.cc b/src/lib/dhcpsrv/parsers/dbaccess_parser.cc index 5fb6434c0e..f8d73ae97a 100644 --- a/src/lib/dhcpsrv/parsers/dbaccess_parser.cc +++ b/src/lib/dhcpsrv/parsers/dbaccess_parser.cc @@ -59,8 +59,9 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db, // 2. Update the copy with the passed keywords. BOOST_FOREACH(ConfigPair param, database_config->mapValue()) { try { - if ((param.first == "persist") || (param.first == "readonly") || - (param.first == "tcp-nodelay")) { + if ((param.first == "persist") || + (param.first == "tcp-nodelay") || + (param.first == "readonly")) { values_copy[param.first] = (param.second->boolValue() ? "true" : "false"); @@ -95,6 +96,16 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db, boost::lexical_cast(port); } else { + // all remaining string parameters + // type + // user + // password + // host + // name + // contact-points + // keyspace + // ssl-cert + // protocol values_copy[param.first] = param.second->stringValue(); } } catch (const isc::data::TypeError& ex) { From 62ce579d1de6a16e7d740c56f58df74202f68bea Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Fri, 2 Feb 2018 12:45:55 +0200 Subject: [PATCH 07/34] updated unit tests --- src/bin/admin/tests/cql_tests.sh.in | 12 ++++++------ .../tests/data/cql.lease4_dump_test.reference.csv | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bin/admin/tests/cql_tests.sh.in b/src/bin/admin/tests/cql_tests.sh.in index 0478fd87f8..a9bd14d115 100644 --- a/src/bin/admin/tests/cql_tests.sh.in +++ b/src/bin/admin/tests/cql_tests.sh.in @@ -144,23 +144,23 @@ cql_lease4_dump_test() { assert_eq 0 $? "kea-admin lease-init cql failed, expected exit code: %d, actual: %d" # Insert the reference record. - # -1073741302 corresponds to 192.0.2.10 - # -1073741301 corresponds to 192.0.2.11 - # -1073741300 corresponds to 192.0.2.12 + # 3221225994 corresponds to 192.0.2.10 + # 3221225995 corresponds to 192.0.2.11 + # 3221225996 corresponds to 192.0.2.12 # 1430694930 corresponds to 2015-04-04 01:15:30 # 1433464245 corresponds to 2015-05-05 02:30:45 # 1436173267 corresponds to 2015-06-06 11:01:07 insert_cql="\ INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\ fqdn_fwd, fqdn_rev, hostname, state)\ - VALUES(-1073741302,textAsBlob('20'),textAsBlob('30'),40,1430694930,50,true,true,\ + VALUES(3221225994,textAsBlob('20'),textAsBlob('30'),40,1430694930,50,true,true,\ 'one.example.com', 0);\ INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\ fqdn_fwd, fqdn_rev, hostname, state)\ - VALUES(-1073741301,NULL,textAsBlob('123'),40,1433464245,50,true,true,'', 1);\ + VALUES(3221225995,NULL,textAsBlob('123'),40,1433464245,50,true,true,'', 1);\ INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\ fqdn_fwd, fqdn_rev, hostname, state)\ - VALUES(-1073741300,textAsBlob('22'),NULL,40,1436173267,50,true,true,\ + VALUES(3221225996,textAsBlob('22'),NULL,40,1436173267,50,true,true,\ 'three.example.com', 2);" cql_execute "$insert_cql" diff --git a/src/bin/admin/tests/data/cql.lease4_dump_test.reference.csv b/src/bin/admin/tests/data/cql.lease4_dump_test.reference.csv index 5316f1e734..95dc3c3bc4 100644 --- a/src/bin/admin/tests/data/cql.lease4_dump_test.reference.csv +++ b/src/bin/admin/tests/data/cql.lease4_dump_test.reference.csv @@ -1,4 +1,4 @@ address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state --1073741302,0x3230,0x3330,40,1430694930,50,True,True,one.example.com,0 --1073741301,null,0x313233,40,1433464245,50,True,True,,1 --1073741300,0x3232,null,40,1436173267,50,True,True,three.example.com,2 +3221225996,0x3232,null,40,1436173267,50,True,True,three.example.com,2 +3221225995,null,0x313233,40,1433464245,50,True,True,,1 +3221225994,0x3230,0x3330,40,1430694930,50,True,True,one.example.com,0 From 26e8bf451239754dd3e46ca039c83cd7665c0c9b Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Sat, 3 Feb 2018 13:10:42 +0200 Subject: [PATCH 08/34] removed unsupported options --- src/lib/dhcpsrv/parsers/dbaccess_parser.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/dhcpsrv/parsers/dbaccess_parser.cc b/src/lib/dhcpsrv/parsers/dbaccess_parser.cc index f8d73ae97a..caac267731 100644 --- a/src/lib/dhcpsrv/parsers/dbaccess_parser.cc +++ b/src/lib/dhcpsrv/parsers/dbaccess_parser.cc @@ -104,8 +104,6 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db, // name // contact-points // keyspace - // ssl-cert - // protocol values_copy[param.first] = param.second->stringValue(); } } catch (const isc::data::TypeError& ex) { From a875ea1ec5bf6e14877e223bfc05d6dc0cea64ea Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 7 Feb 2018 18:18:18 +0200 Subject: [PATCH 09/34] updated cql schema and added minor changes (including spelling mistakes and spacing) --- configure.ac | 81 ++-- src/bin/admin/tests/cql_tests.sh.in | 12 +- .../data/cql.lease4_dump_test.reference.csv | 6 +- src/bin/admin/tests/dhcpdb_create_1.0.cql | 2 +- src/bin/admin/tests/dhcpdb_create_1.0.mysql | 2 +- src/bin/admin/tests/mysql_tests.sh.in | 2 +- src/bin/dhcp4/ctrl_dhcp4_srv.h | 2 +- src/bin/dhcp4/dhcp4_lexer.ll | 45 +- src/bin/dhcp4/dhcp4_messages.mes | 2 +- src/bin/dhcp4/dhcp4_parser.yy | 32 +- .../dhcp4/tests/ctrl_dhcp4_srv_unittest.cc | 2 +- src/bin/dhcp6/ctrl_dhcp6_srv.cc | 8 +- src/bin/dhcp6/dhcp6_hooks.dox | 4 +- src/bin/dhcp6/dhcp6_lexer.ll | 43 +- src/bin/dhcp6/dhcp6_parser.yy | 31 +- .../dhcp6/tests/shared_network_unittest.cc | 2 +- src/lib/dhcp/option_custom.cc | 2 +- src/lib/dhcpsrv/cfg_db_access.cc | 6 +- src/lib/dhcpsrv/cql_connection.cc | 20 + src/lib/dhcpsrv/cql_exchange.cc | 418 +----------------- src/lib/dhcpsrv/cql_exchange.h | 54 --- src/lib/dhcpsrv/cql_lease_mgr.cc | 45 +- src/lib/dhcpsrv/mysql_connection.cc | 7 +- src/lib/dhcpsrv/mysql_lease_mgr.cc | 41 +- src/lib/dhcpsrv/parsers/dbaccess_parser.cc | 13 +- src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 10 +- src/lib/dhcpsrv/pgsql_connection.cc | 5 +- src/lib/dhcpsrv/pgsql_lease_mgr.cc | 60 +-- src/lib/dhcpsrv/sql_common.h | 4 +- src/lib/dhcpsrv/testutils/cql_schema.cc | 6 +- src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc | 6 + src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h | 3 + src/lib/dhcpsrv/testutils/mysql_schema.cc | 5 +- src/lib/dhcpsrv/testutils/pgsql_schema.cc | 4 +- src/share/database/scripts/cql/.gitignore | 1 - .../database/scripts/cql/dhcpdb_create.cql | 4 +- .../scripts/pgsql/dhcpdb_create.pgsql | 1 - 37 files changed, 367 insertions(+), 624 deletions(-) diff --git a/configure.ac b/configure.ac index 40dd9a2301..df7488378d 100644 --- a/configure.ac +++ b/configure.ac @@ -133,15 +133,15 @@ AX_ISC_CPP11 # Check for std::is_base_of support AC_MSG_CHECKING([for std::is_base_of]) AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [#include - class A {}; - class B : A {};] - [static_assert(std::is_base_of::value, "");])], - [AC_MSG_RESULT(yes) - AC_DEFINE([HAVE_IS_BASE_OF], [1], - [Define to 1 if std::is_base_of is available])], - [AC_MSG_RESULT(no)]) + [AC_LANG_PROGRAM( + [#include + class A {}; + class B : A {};] + [static_assert(std::is_base_of::value, "");])], + [AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_IS_BASE_OF], [1], + [Define to 1 if std::is_base_of is available])], + [AC_MSG_RESULT(no)]) dnl Determine if we are using GNU sed GNU_SED=no @@ -408,7 +408,6 @@ case "$host" in ;; esac - # Kea-shell is written in python. It can work with python 2.7 or any 3.x. # It may likely work with earlier versions, but 2.7 was the oldest one we tested # it with. We require python only if kea-shell was enabled. It is disabled @@ -893,9 +892,9 @@ if test "x$enable_gtest" = "xyes" ; then AC_MSG_ERROR([no gtest source but it was selected]) fi else - if test ! -d $GTEST_SOURCE/src -a -d $GTEST_SOURCE/googletest; then - GTEST_SOURCE=$GTEST_SOURCE/googletest - fi + if test ! -d $GTEST_SOURCE/src -a -d $GTEST_SOURCE/googletest; then + GTEST_SOURCE=$GTEST_SOURCE/googletest + fi AC_CHECK_FILES([$GTEST_SOURCE/src/gtest-all.cc] [$GTEST_SOURCE/src/gtest_main.cc], [have_gtest_source=yes], @@ -905,7 +904,7 @@ if test "x$enable_gtest" = "xyes" ; then GTEST_LDADD="\$(top_builddir)/ext/gtest/libgtest.a" DISTCHECK_GTEST_CONFIGURE_FLAG="--with-gtest-source=$GTEST_SOURCE" GTEST_INCLUDES="-I$GTEST_SOURCE -I$GTEST_SOURCE/include" - GTEST_VERSION="`basename $GTEST_SOURCE`" + GTEST_VERSION="`basename $GTEST_SOURCE`" fi if test "$gtest_path" != "no" ; then @@ -970,15 +969,15 @@ if test $enable_gtest != "no"; then CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES $GTEST_INCLUDES" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( - [#include - #include - void foo() { - boost::shared_ptr bar; - ASSERT_TRUE(bar); + [#include + #include + void foo() { + boost::shared_ptr bar; + ASSERT_TRUE(bar); }], - [return 0;])], - [AC_MSG_RESULT(yes)], - [AC_MSG_ERROR([XXX_TRUE() Google Test macros won't compile; the most likely reason is that a later version of Google Test is required])]) + [return 0;])], + [AC_MSG_RESULT(yes)], + [AC_MSG_ERROR([XXX_TRUE() Google Test macros won't compile; the most likely reason is that a later version of Google Test is required])]) CPPFLAGS=$CPPFLAGS_SAVED fi @@ -989,21 +988,21 @@ if test $enable_gtest != "no"; then CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES $GTEST_INCLUDES" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( - [#include - #include - #include - #include - std::string nodiff(std::string text) { - std::vector lines; - boost::split(lines, text, boost::is_any_of("\n")); - using namespace testing::internal; - return (edit_distance::CreateUnifiedDiff(lines, lines)); - }], - [return 0;])], - [AC_MSG_RESULT(yes) - AC_DEFINE([HAVE_CREATE_UNIFIED_DIFF], [1], - [Define to 1 if gtest defines edit_distance::CreateUnifiedDiff])], - [AC_MSG_RESULT(no)]) + [#include + #include + #include + #include + std::string nodiff(std::string text) { + std::vector lines; + boost::split(lines, text, boost::is_any_of("\n")); + using namespace testing::internal; + return (edit_distance::CreateUnifiedDiff(lines, lines)); + }], + [return 0;])], + [AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_CREATE_UNIFIED_DIFF], [1], + [Define to 1 if gtest defines edit_distance::CreateUnifiedDiff])], + [AC_MSG_RESULT(no)]) CPPFLAGS=$CPPFLAGS_SAVED fi @@ -1039,7 +1038,7 @@ AC_CHECK_FUNCS([pselect]) # code will be updated by the time we really need it. AC_CHECK_HEADERS(sys/devpoll.h, ac_cv_have_devpoll=yes, ac_cv_have_devpoll=no) if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GXX" = "Xyes"; then - CPPFLAGS="$CPPFLAGS -DBOOST_ASIO_DISABLE_DEV_POLL=1" + CPPFLAGS="$CPPFLAGS -DBOOST_ASIO_DISABLE_DEV_POLL=1" fi # @@ -1503,9 +1502,9 @@ if test "$CQL_CPPFLAGS" != "" ; then cat >> config.report << END Cassandra CQL: - CQL_VERSION: ${CQL_VERSION} - CQL_CPPFLAGS: ${CQL_CPPFLAGS} - CQL_LIBS: ${CQL_LIBS} + CQL_VERSION: ${CQL_VERSION} + CQL_CPPFLAGS: ${CQL_CPPFLAGS} + CQL_LIBS: ${CQL_LIBS} END else cat >> config.report << END diff --git a/src/bin/admin/tests/cql_tests.sh.in b/src/bin/admin/tests/cql_tests.sh.in index 0478fd87f8..a9bd14d115 100644 --- a/src/bin/admin/tests/cql_tests.sh.in +++ b/src/bin/admin/tests/cql_tests.sh.in @@ -144,23 +144,23 @@ cql_lease4_dump_test() { assert_eq 0 $? "kea-admin lease-init cql failed, expected exit code: %d, actual: %d" # Insert the reference record. - # -1073741302 corresponds to 192.0.2.10 - # -1073741301 corresponds to 192.0.2.11 - # -1073741300 corresponds to 192.0.2.12 + # 3221225994 corresponds to 192.0.2.10 + # 3221225995 corresponds to 192.0.2.11 + # 3221225996 corresponds to 192.0.2.12 # 1430694930 corresponds to 2015-04-04 01:15:30 # 1433464245 corresponds to 2015-05-05 02:30:45 # 1436173267 corresponds to 2015-06-06 11:01:07 insert_cql="\ INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\ fqdn_fwd, fqdn_rev, hostname, state)\ - VALUES(-1073741302,textAsBlob('20'),textAsBlob('30'),40,1430694930,50,true,true,\ + VALUES(3221225994,textAsBlob('20'),textAsBlob('30'),40,1430694930,50,true,true,\ 'one.example.com', 0);\ INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\ fqdn_fwd, fqdn_rev, hostname, state)\ - VALUES(-1073741301,NULL,textAsBlob('123'),40,1433464245,50,true,true,'', 1);\ + VALUES(3221225995,NULL,textAsBlob('123'),40,1433464245,50,true,true,'', 1);\ INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\ fqdn_fwd, fqdn_rev, hostname, state)\ - VALUES(-1073741300,textAsBlob('22'),NULL,40,1436173267,50,true,true,\ + VALUES(3221225996,textAsBlob('22'),NULL,40,1436173267,50,true,true,\ 'three.example.com', 2);" cql_execute "$insert_cql" diff --git a/src/bin/admin/tests/data/cql.lease4_dump_test.reference.csv b/src/bin/admin/tests/data/cql.lease4_dump_test.reference.csv index 5316f1e734..95dc3c3bc4 100644 --- a/src/bin/admin/tests/data/cql.lease4_dump_test.reference.csv +++ b/src/bin/admin/tests/data/cql.lease4_dump_test.reference.csv @@ -1,4 +1,4 @@ address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state --1073741302,0x3230,0x3330,40,1430694930,50,True,True,one.example.com,0 --1073741301,null,0x313233,40,1433464245,50,True,True,,1 --1073741300,0x3232,null,40,1436173267,50,True,True,three.example.com,2 +3221225996,0x3232,null,40,1436173267,50,True,True,three.example.com,2 +3221225995,null,0x313233,40,1433464245,50,True,True,,1 +3221225994,0x3230,0x3330,40,1430694930,50,True,True,one.example.com,0 diff --git a/src/bin/admin/tests/dhcpdb_create_1.0.cql b/src/bin/admin/tests/dhcpdb_create_1.0.cql index 577f2ae277..b6cf064ffd 100644 --- a/src/bin/admin/tests/dhcpdb_create_1.0.cql +++ b/src/bin/admin/tests/dhcpdb_create_1.0.cql @@ -47,7 +47,7 @@ -- Table `lease4` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS lease4 ( - address int, + address bigint, hwaddr blob, client_id blob, valid_lifetime bigint, diff --git a/src/bin/admin/tests/dhcpdb_create_1.0.mysql b/src/bin/admin/tests/dhcpdb_create_1.0.mysql index b4823afbff..9f68439ffe 100644 --- a/src/bin/admin/tests/dhcpdb_create_1.0.mysql +++ b/src/bin/admin/tests/dhcpdb_create_1.0.mysql @@ -123,7 +123,7 @@ COMMIT; # # Portability # =========== -# The "ENGINE = INNODB" on some tables is not portablea to another database +# The "ENGINE = INNODB" on some tables is not portable to another database # and will need to be removed. # # Some columns contain binary data so are stored as VARBINARY instead of diff --git a/src/bin/admin/tests/mysql_tests.sh.in b/src/bin/admin/tests/mysql_tests.sh.in index e5233c338d..fd0ea325f7 100644 --- a/src/bin/admin/tests/mysql_tests.sh.in +++ b/src/bin/admin/tests/mysql_tests.sh.in @@ -189,7 +189,7 @@ mysql_upgrade_test() { mysql -u$db_user -p$db_password $db_name < @abs_top_srcdir@/src/bin/admin/tests/dhcpdb_create_1.0.mysql # Sanity check - verify that it reports version 1.0. - version=$(${keaadmin} lease-version mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir) + version=$(${keaadmin} lease-version mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir) assert_str_eq "1.0" ${version} "Expected kea-admin to return %s, returned value was %s" diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h index f9598041d1..2c124dac04 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.h +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h @@ -123,7 +123,7 @@ class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv { /// @brief Callback that will be called from iface_mgr when data /// is received over control socket. /// - /// This static callback method is called from IfaceMgr::receive6() method, + /// This static callback method is called from IfaceMgr::receive4() method, /// when there is a new command or configuration sent over control socket /// (that was sent from some yet unspecified sender). static void sessionReader(void); diff --git a/src/bin/dhcp4/dhcp4_lexer.ll b/src/bin/dhcp4/dhcp4_lexer.ll index d5d88ff41a..f71a0e26fd 100644 --- a/src/bin/dhcp4/dhcp4_lexer.ll +++ b/src/bin/dhcp4/dhcp4_lexer.ll @@ -36,7 +36,7 @@ unsigned int comment_start_line = 0; using namespace isc::dhcp; -}; +} /* To avoid the call to exit... oops! */ #define YY_FATAL_ERROR(msg) isc::dhcp::Parser4Context::fatal(msg) @@ -410,6 +410,46 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } +\"tcp-nodelay\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::LEASE_DATABASE: + case isc::dhcp::Parser4Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp4Parser::make_TCP_NODELAY(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("tcp-nodelay", driver.loc_); + } +} + +\"reconnect-wait-time\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::LEASE_DATABASE: + case isc::dhcp::Parser4Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp4Parser::make_RECONNECT_WAIT_TIME(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("reconnect-wait-time", driver.loc_); + } +} + +\"request-timeout\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::LEASE_DATABASE: + case isc::dhcp::Parser4Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp4Parser::make_REQUEST_TIMEOUT(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("request-timeout", driver.loc_); + } +} + +\"tcp-keepalive\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::LEASE_DATABASE: + case isc::dhcp::Parser4Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp4Parser::make_TCP_KEEPALIVE(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("tcp-keepalive", driver.loc_); + } +} + \"connect-timeout\" { switch(driver.ctx_) { case isc::dhcp::Parser4Context::LEASE_DATABASE: @@ -985,7 +1025,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } - \"parameters\" { switch(driver.ctx_) { case isc::dhcp::Parser4Context::HOOKS_LIBRARIES: @@ -1441,8 +1480,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } - - {JSONString} { /* A string has been matched. It contains the actual string and single quotes. We need to get those quotes out of the way and just use its content, e.g. diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index fef6ef62dc..6486fac74a 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -198,7 +198,7 @@ the message. % DHCP4_DHCP4O6_RECEIVING receiving DHCPv4o6 packet from DHCPv6 server This debug message is printed when the server is receiving a DHCPv4o6 -from the DHCPv6 server over inter-process communication socket. +from the DHCPv4 server over inter-process communication socket. % DHCP4_DHCP4O6_RESPONSE_DATA %1: responding with packet %2 (type %3), packet details: %4 A debug message including the detailed data about the packet being diff --git a/src/bin/dhcp4/dhcp4_parser.yy b/src/bin/dhcp4/dhcp4_parser.yy index 9c5f94262a..d4a03c5f31 100644 --- a/src/bin/dhcp4/dhcp4_parser.yy +++ b/src/bin/dhcp4/dhcp4_parser.yy @@ -81,6 +81,10 @@ using namespace std; LFC_INTERVAL "lfc-interval" READONLY "readonly" CONNECT_TIMEOUT "connect-timeout" + TCP_NODELAY "tcp-nodelay" + RECONNECT_WAIT_TIME "reconnect-wait-time" + REQUEST_TIMEOUT "request-timeout" + TCP_KEEPALIVE "tcp-keepalive" CONTACT_POINTS "contact-points" KEYSPACE "keyspace" @@ -470,7 +474,6 @@ match_client_id: MATCH_CLIENT_ID COLON BOOLEAN { ctx.stack_.back()->set("match-client-id", match); }; - interfaces_config: INTERFACES_CONFIG { ElementPtr i(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("interfaces-config", i); @@ -582,6 +585,10 @@ database_map_param: database_type | lfc_interval | readonly | connect_timeout + | tcp_nodelay + | reconnect_wait_time + | request_timeout + | tcp_keepalive | contact_points | keyspace | unknown_map_entry @@ -657,6 +664,26 @@ connect_timeout: CONNECT_TIMEOUT COLON INTEGER { ctx.stack_.back()->set("connect-timeout", n); }; +tcp_nodelay: TCP_NODELAY COLON BOOLEAN { + ElementPtr n(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("tcp-nodelay", n); +}; + +reconnect_wait_time: RECONNECT_WAIT_TIME COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("reconnect-wait-time", n); +}; + +request_timeout: REQUEST_TIMEOUT COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("request-timeout", n); +}; + +tcp_keepalive: TCP_KEEPALIVE COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("tcp-keepalive", n); +}; + contact_points: CONTACT_POINTS { ctx.enter(ctx.NO_KEYWORD); } COLON STRING { @@ -673,7 +700,6 @@ keyspace: KEYSPACE { ctx.leave(); }; - host_reservation_identifiers: HOST_RESERVATION_IDENTIFIERS { ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("host-reservation-identifiers", l); @@ -1826,7 +1852,7 @@ replace_client_name: REPLACE_CLIENT_NAME { replace_client_name_value: WHEN_PRESENT { - $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); + $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); } | NEVER { $$ = ElementPtr(new StringElement("never", ctx.loc2pos(@1))); diff --git a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc index 1ac0981a51..bae5d2c60a 100644 --- a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc @@ -92,7 +92,7 @@ class NakedControlledDhcpv4Srv: public ControlledDhcpv4Srv { /// @brief Default control connection timeout. const size_t DEFAULT_CONNECTION_TIMEOUT = 10; -/// @brief Fixture class intended for testin control channel in the DHCPv4Srv +/// @brief Fixture class intended for testing control channel in the DHCPv4Srv class CtrlChannelDhcpv4SrvTest : public ::testing::Test { public: diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc index dceb6367fb..6b5aed2055 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc @@ -571,8 +571,8 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) { return (answer); } } catch (const std::exception& ex) { - return (isc::config::createAnswer(1, "Failed to process configuration:" - + string(ex.what()))); + return (isc::config::createAnswer(1, "Failed to process configuration:" + + string(ex.what()))); } // Re-open lease and host database with new parameters. @@ -582,8 +582,8 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) { cfg_db->createManagers(); } catch (const std::exception& ex) { - return (isc::config::createAnswer(1, "Unable to open database: " - + std::string(ex.what()))); + return (isc::config::createAnswer(1, "Unable to open database: " + + std::string(ex.what()))); } // Regenerate server identifier if needed. diff --git a/src/bin/dhcp6/dhcp6_hooks.dox b/src/bin/dhcp6/dhcp6_hooks.dox index 45afd6cb38..ec8cb952eb 100644 --- a/src/bin/dhcp6/dhcp6_hooks.dox +++ b/src/bin/dhcp6/dhcp6_hooks.dox @@ -273,7 +273,7 @@ to the end of this list. - name: @b response6, type: isc::dhcp::Pkt6Ptr, direction: in/out - @b Description: This callout is executed when server's response - is about to be send back to the client. The sole argument "response6" + is about to be sent back to the client. The sole argument "response6" contains a pointer to an @c isc::dhcp::Pkt6 object that contains the packet, with set source and destination addresses, interface over which it will be send, list of all options and relay information. All fields @@ -296,7 +296,7 @@ to the end of this list. - name: @b response6, type: isc::dhcp::Pkt6Ptr, direction: in/out - @b Description: This callout is executed when server's response is - assembled into binary form and is about to be send back to the + assembled into binary form and is about to be sent back to the client. The sole argument "response6" contains a pointer to an @c isc::dhcp::Pkt6 object that contains the packet, with set source and destination addresses, interface over which it will be sent, list of diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index 58808613ea..af3c7ae773 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -36,7 +36,7 @@ unsigned int comment_start_line = 0; using namespace isc::dhcp; -}; +} /* To avoid the call to exit... oops! */ #define YY_FATAL_ERROR(msg) isc::dhcp::Parser6Context::fatal(msg) @@ -575,6 +575,46 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } +\"tcp-nodelay\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp6Parser::make_TCP_NODELAY(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("tcp-nodelay", driver.loc_); + } +} + +\"reconnect-wait-time\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp6Parser::make_RECONNECT_WAIT_TIME(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("reconnect-wait-time", driver.loc_); + } +} + +\"request-timeout\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp6Parser::make_REQUEST_TIMEOUT(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("request-timeout", driver.loc_); + } +} + +\"tcp-keepalive\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + return isc::dhcp::Dhcp6Parser::make_TCP_KEEPALIVE(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("tcp-keepalive", driver.loc_); + } +} + \"connect-timeout\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::LEASE_DATABASE: @@ -1239,7 +1279,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } - \"parameters\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::HOOKS_LIBRARIES: diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index 5fd8df6db6..b70f402669 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -69,6 +69,10 @@ using namespace std; LFC_INTERVAL "lfc-interval" READONLY "readonly" CONNECT_TIMEOUT "connect-timeout" + TCP_NODELAY "tcp-nodelay" + RECONNECT_WAIT_TIME "reconnect-wait-time" + REQUEST_TIMEOUT "request-timeout" + TCP_KEEPALIVE "tcp-keepalive" CONTACT_POINTS "contact-points" KEYSPACE "keyspace" @@ -513,7 +517,6 @@ re_detect: RE_DETECT COLON BOOLEAN { ctx.stack_.back()->set("re-detect", b); }; - lease_database: LEASE_DATABASE { ElementPtr i(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("lease-database", i); @@ -552,6 +555,10 @@ database_map_param: database_type | lfc_interval | readonly | connect_timeout + | tcp_nodelay + | reconnect_wait_time + | request_timeout + | tcp_keepalive | contact_points | keyspace | unknown_map_entry @@ -627,6 +634,26 @@ connect_timeout: CONNECT_TIMEOUT COLON INTEGER { ctx.stack_.back()->set("connect-timeout", n); }; +tcp_nodelay: TCP_NODELAY COLON BOOLEAN { + ElementPtr n(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("tcp-nodelay", n); +}; + +reconnect_wait_time: RECONNECT_WAIT_TIME COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("reconnect-wait-time", n); +}; + +request_timeout: REQUEST_TIMEOUT COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("request-timeout", n); +}; + +tcp_keepalive: TCP_KEEPALIVE COLON INTEGER { + ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("tcp-keepalive", n); +}; + contact_points: CONTACT_POINTS { ctx.enter(ctx.NO_KEYWORD); } COLON STRING { @@ -1910,7 +1937,7 @@ replace_client_name: REPLACE_CLIENT_NAME { replace_client_name_value: WHEN_PRESENT { - $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); + $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); } | NEVER { $$ = ElementPtr(new StringElement("never", ctx.loc2pos(@1))); diff --git a/src/bin/dhcp6/tests/shared_network_unittest.cc b/src/bin/dhcp6/tests/shared_network_unittest.cc index 32fa5d53ec..e521451bdc 100644 --- a/src/bin/dhcp6/tests/shared_network_unittest.cc +++ b/src/bin/dhcp6/tests/shared_network_unittest.cc @@ -426,7 +426,7 @@ const char* NETWORKS_CONFIG[] = { " }" " ]," " \"subnet6\": [" - " \{" + " {" " \"subnet\": \"3000::/96\"," " \"id\": 1000," " \"interface\": \"eth0\"," diff --git a/src/lib/dhcp/option_custom.cc b/src/lib/dhcp/option_custom.cc index 68f4d23d8b..02e6fa0b47 100644 --- a/src/lib/dhcp/option_custom.cc +++ b/src/lib/dhcp/option_custom.cc @@ -113,7 +113,7 @@ OptionCustom::addArrayDataField(const PSIDLen& psid_len, const PSID& psid) { checkArrayType(); if (definition_.getType() != OPT_PSID_TYPE) { - isc_throw(BadDataTypeCast, "PSID value can be specified onlu for" + isc_throw(BadDataTypeCast, "PSID value can be specified only for" " an option comprising an array of PSID length / value" " tuples"); } diff --git a/src/lib/dhcpsrv/cfg_db_access.cc b/src/lib/dhcpsrv/cfg_db_access.cc index 366cdf4be2..26d6917207 100644 --- a/src/lib/dhcpsrv/cfg_db_access.cc +++ b/src/lib/dhcpsrv/cfg_db_access.cc @@ -50,7 +50,7 @@ CfgDbAccess::createManagers() const { } } -std::string +std::string CfgDbAccess::getAccessString(const std::string& access_string) const { std::ostringstream s; s << access_string; @@ -81,6 +81,9 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) { std::string value = token.substr(pos + 1); if ((keyword == "lfc-interval") || (keyword == "connect-timeout") || + (keyword == "reconnect-wait-time") || + (keyword == "request-timeout") || + (keyword == "tcp-keepalive") || (keyword == "port")) { // integer parameters int64_t int_value; @@ -93,6 +96,7 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) { << keyword << "=" << value); } } else if ((keyword == "persist") || + (keyword == "tcp-nodelay") || (keyword == "readonly")) { if (value == "true") { result->set(keyword, Element::create(true)); diff --git a/src/lib/dhcpsrv/cql_connection.cc b/src/lib/dhcpsrv/cql_connection.cc index 0e88de7824..3211a08bbe 100644 --- a/src/lib/dhcpsrv/cql_connection.cc +++ b/src/lib/dhcpsrv/cql_connection.cc @@ -177,6 +177,8 @@ CqlConnection::openDatabase() { try { port_number = boost::lexical_cast(port); if (port_number < 1 || port_number > 65535) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "port outside of range, expected " @@ -184,6 +186,8 @@ CqlConnection::openDatabase() { << port); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid " "port, expected castable to int, instead got " @@ -199,12 +203,16 @@ CqlConnection::openDatabase() { reconnect_wait_time_number = boost::lexical_cast(reconnect_wait_time); if (reconnect_wait_time_number < 0) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid reconnect " "wait time, expected positive number, instead got " << reconnect_wait_time); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "invalid reconnect wait time, expected " @@ -221,6 +229,8 @@ CqlConnection::openDatabase() { connect_timeout_number = boost::lexical_cast(connect_timeout); if (connect_timeout_number < 0) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "invalid connect timeout, expected " @@ -228,6 +238,8 @@ CqlConnection::openDatabase() { << connect_timeout); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid connect timeout, " "expected castable to int, instead got \"" @@ -242,6 +254,8 @@ CqlConnection::openDatabase() { request_timeout_number = boost::lexical_cast(request_timeout); if (request_timeout_number < 0) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "invalid request timeout, expected " @@ -249,6 +263,8 @@ CqlConnection::openDatabase() { << request_timeout); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid request timeout, " "expected castable to int, instead got \"" @@ -262,6 +278,8 @@ CqlConnection::openDatabase() { try { tcp_keepalive_number = boost::lexical_cast(tcp_keepalive); if (tcp_keepalive_number < 0) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): " "invalid TCP keepalive, expected " @@ -269,6 +287,8 @@ CqlConnection::openDatabase() { << tcp_keepalive); } } catch (const boost::bad_lexical_cast& ex) { + cass_cluster_free(cluster_); + cluster_ = NULL; isc_throw(DbOperationError, "CqlConnection::openDatabase(): invalid TCP keepalive, " "expected castable to int, instead got \"" diff --git a/src/lib/dhcpsrv/cql_exchange.cc b/src/lib/dhcpsrv/cql_exchange.cc index c84d7b72f4..c22feb9529 100644 --- a/src/lib/dhcpsrv/cql_exchange.cc +++ b/src/lib/dhcpsrv/cql_exchange.cc @@ -94,68 +94,7 @@ static AnyTypeMap ANY_TYPE_MAP = { {typeid(cass_int64_t*), EXCHANGE_DATA_TYPE_INT64}, {typeid(std::string*), EXCHANGE_DATA_TYPE_STRING}, {typeid(CassBlob*), EXCHANGE_DATA_TYPE_BYTES}, - {typeid(CassUuid*), EXCHANGE_DATA_TYPE_UUID}, - {typeid(Udt*), EXCHANGE_DATA_TYPE_UDT}, // user data type - {typeid(AnyCollection*), EXCHANGE_DATA_TYPE_COLLECTION}}; - -/// @brief Maps Cassandra type to exchange type -static CassTypeMap CASS_TYPE_MAP = { - {CASS_VALUE_TYPE_CUSTOM, EXCHANGE_DATA_TYPE_UDT}, - {CASS_VALUE_TYPE_ASCII, EXCHANGE_DATA_TYPE_STRING}, - {CASS_VALUE_TYPE_BIGINT, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_BLOB, EXCHANGE_DATA_TYPE_BYTES}, - {CASS_VALUE_TYPE_BOOLEAN, EXCHANGE_DATA_TYPE_BOOL}, - {CASS_VALUE_TYPE_COUNTER, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_DECIMAL, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_DOUBLE, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_FLOAT, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_INT, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_TEXT, EXCHANGE_DATA_TYPE_STRING}, - {CASS_VALUE_TYPE_TIMESTAMP, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_UUID, EXCHANGE_DATA_TYPE_UUID}, - {CASS_VALUE_TYPE_VARCHAR, EXCHANGE_DATA_TYPE_STRING}, - {CASS_VALUE_TYPE_VARINT, EXCHANGE_DATA_TYPE_INT32}, - {CASS_VALUE_TYPE_TIMEUUID, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_INET, EXCHANGE_DATA_TYPE_NONE}, - {CASS_VALUE_TYPE_DATE, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_TIME, EXCHANGE_DATA_TYPE_INT64}, - {CASS_VALUE_TYPE_SMALL_INT, EXCHANGE_DATA_TYPE_INT16}, - {CASS_VALUE_TYPE_TINY_INT, EXCHANGE_DATA_TYPE_INT8}, - {CASS_VALUE_TYPE_LIST, EXCHANGE_DATA_TYPE_COLLECTION}, - {CASS_VALUE_TYPE_MAP, EXCHANGE_DATA_TYPE_COLLECTION}, - {CASS_VALUE_TYPE_SET, EXCHANGE_DATA_TYPE_COLLECTION}, - {CASS_VALUE_TYPE_UDT, EXCHANGE_DATA_TYPE_UDT}, - {CASS_VALUE_TYPE_TUPLE, EXCHANGE_DATA_TYPE_UDT}}; - -/// @brief Udt (user data type) method implementations -/// @{ -Udt::Udt(const CqlConnection& connection, const std::string& name) - : AnyArray(), connection_(connection), name_(name) { - // Create type. - cass_data_type_ = cass_keyspace_meta_user_type_by_name( - connection_.keyspace_meta_, name_.c_str()); - if (!cass_data_type_) { - isc_throw(DbOperationError, - "Udt::Udt(): UDT " << name_ << " does not exist "); - } - // Create container. - cass_user_type_ = cass_user_type_new_from_data_type(cass_data_type_); - if (!cass_user_type_) { - isc_throw(DbOperationError, - "Udt::Udt(): Type " << name_ - << " is not a UDT as expected. "); - } -} - -Udt::~Udt() { - /// @todo: Need to get back to this issue. This is likely a memory leak. - // - // Bug: it seems that if there is no call to - // cass_user_type_set_*(cass_user_type_), then - // cass_user_type_free(cass_user_type_) might SIGSEGV, so we never - // free. Udt objects should have application scope though. - // cass_user_type_free(cass_user_type_); -} + {typeid(CassUuid*), EXCHANGE_DATA_TYPE_UUID}}; /// @} /// @brief AnyArray method implementations @@ -251,238 +190,8 @@ CqlBindUuid(const boost::any& value, return cass_statement_bind_uuid(statement, index, *boost::any_cast(value)); } - -static CassError -CqlBindUdt(const boost::any& value, - const size_t& index, - CassStatement* statement) { - Udt* udt = boost::any_cast(value); - - if (!udt) { - isc_throw(BadValue, "Invalid value specified, not an Udt object"); - } - - size_t i = 0u; - - // Let's iterate over all elements in udt and check that we indeed - // can assign the set function for each specified type. - for (boost::any& element : *udt) { - try { - KEA_CASS_CHECK( - CQL_FUNCTIONS[exchangeType(element)].cqlUdtSetFunction_( - element, i, udt->cass_user_type_)); - } catch (const boost::bad_any_cast& exception) { - isc_throw(DbOperationError, - "CqlCommon::udtSetData(): " - << exception.what() << " when binding parameter " - << " of type " << element.type().name() - << "in UDT with function CQL_FUNCTIONS[" - << exchangeType(element) << "].cqlUdtSetFunction_"); - } - ++i; - } - - return cass_statement_bind_user_type(statement, index, - udt->cass_user_type_); -} - -static CassError -CqlBindCollection(const boost::any& value, - const size_t& index, - CassStatement* statement) { - AnyCollection* elements = boost::any_cast(value); - - CassCollection* collection = - cass_collection_new(CASS_COLLECTION_TYPE_SET, elements->size()); - - // Iterate over all elements and assign appropriate append function - // for each. - for (boost::any& element : *elements) { - ExchangeDataType type = exchangeType(element); - KEA_CASS_CHECK(CQL_FUNCTIONS[type].cqlCollectionAppendFunction_( - element, collection)); - } - - const CassError cass_error = - cass_statement_bind_collection(statement, index, collection); - cass_collection_free(collection); - - return cass_error; -} -/// @} - -/// @name CqlUdtSet functions for binding data into Cassandra format for -/// insertion of a UDT: -/// @{ -static CassError -CqlUdtSetNone(const boost::any& /* udt_member */, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_null(cass_user_type, position); -} - -static CassError -CqlUdtSetBool(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_bool(cass_user_type, position, - *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetInt8(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_int8(cass_user_type, position, - *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetInt16(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_int16( - cass_user_type, position, *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetInt32(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_int32( - cass_user_type, position, *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetInt64(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_int64( - cass_user_type, position, *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetString(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_string( - cass_user_type, position, - boost::any_cast(udt_member)->c_str()); -} - -static CassError -CqlUdtSetBytes(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - CassBlob* blob_value = boost::any_cast(udt_member); - return cass_user_type_set_bytes(cass_user_type, position, - blob_value->data(), blob_value->size()); -} - -static CassError -CqlUdtSetUuid(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_uuid(cass_user_type, position, - *boost::any_cast(udt_member)); -} - -static CassError -CqlUdtSetUdt(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_user_type( - cass_user_type, position, - boost::any_cast(udt_member)->cass_user_type_); -} - -static CassError -CqlUdtSetCollection(const boost::any& udt_member, - const size_t& position, - CassUserType* cass_user_type) { - return cass_user_type_set_collection( - cass_user_type, position, boost::any_cast(udt_member)); -} /// @} -/// @name CqlCollectionAppend functions for binding data into Cassandra format -/// for insertion of a collection: -/// @{ -static CassError -CqlCollectionAppendNone(const boost::any& /* value */, - CassCollection* /* collection */) { - return CASS_OK; -} - -static CassError -CqlCollectionAppendBool(const boost::any& value, CassCollection* collection) { - return cass_collection_append_bool(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendInt8(const boost::any& value, CassCollection* collection) { - return cass_collection_append_int8(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendInt16(const boost::any& value, CassCollection* collection) { - return cass_collection_append_int16(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendInt32(const boost::any& value, CassCollection* collection) { - return cass_collection_append_int32(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendInt64(const boost::any& value, CassCollection* collection) { - return cass_collection_append_int64(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendString(const boost::any& value, CassCollection* collection) { - return cass_collection_append_string( - collection, boost::any_cast(value)->c_str()); -} - -static CassError -CqlCollectionAppendBytes(const boost::any& value, CassCollection* collection) { - CassBlob* blob_value = boost::any_cast(value); - return cass_collection_append_bytes(collection, blob_value->data(), - blob_value->size()); -} - -static CassError -CqlCollectionAppendUuid(const boost::any& value, CassCollection* collection) { - return cass_collection_append_uuid(collection, - *boost::any_cast(value)); -} - -static CassError -CqlCollectionAppendUdt(const boost::any& value, CassCollection* collection) { - Udt* udt = boost::any_cast(value); - size_t i = 0u; - for (boost::any& element : *udt) { - KEA_CASS_CHECK(CQL_FUNCTIONS[exchangeType(element)].cqlUdtSetFunction_( - element, i, udt->cass_user_type_)); - ++i; - } - return cass_collection_append_user_type(collection, udt->cass_user_type_); -} - -static CassError -CqlCollectionAppendCollection(const boost::any& value, - CassCollection* collection) { - return cass_collection_append_collection( - collection, boost::any_cast(value)); -} -// @} - /// @name CqlGet functions for retrieving data of the proper Cassandra format: /// @{ static CassError @@ -541,101 +250,30 @@ static CassError CqlGetUuid(const boost::any& data, const CassValue* value) { return cass_value_get_uuid(value, boost::any_cast(data)); } - -static CassError -CqlGetUdt(const boost::any& data, const CassValue* value) { - Udt* udt = boost::any_cast(data); - - CassIterator* fields = cass_iterator_fields_from_user_type(value); - if (!fields) { - isc_throw(DbOperationError, "CqlGetUdt(): column is not a UDT"); - } - Udt::const_iterator it = udt->begin(); - while (cass_iterator_next(fields)) { - const CassValue* field_value = - cass_iterator_get_user_type_field_value(fields); - if (cass_value_is_null(field_value)) { - isc_throw(DbOperationError, - "CqlGetUdt(): null value returned in UDT"); - } - const CassValueType& type = cass_value_type(field_value); - KEA_CASS_CHECK(CQL_FUNCTIONS[exchangeType(type)].cqlGetFunction_( - *it, field_value)); - ++it; - // If cqlGetFunction_() returns != CASS_OK, don't - // cass_iterator_free(items_iterator) because we're returning from this - // function and throwing from the callee. - } - cass_iterator_free(fields); - return CASS_OK; -} - -static CassError -CqlGetCollection(const boost::any& data, const CassValue* value) { - AnyCollection* collection = boost::any_cast(data); - if (!collection) { - isc_throw(DbOperationError, "CqlGetCollection(): column is not a collection"); - } - - BOOST_ASSERT(collection->size() == 1); - - /// @todo: Create a copy of the underlying object rather than referencing to - /// it. - boost::any underlying_object = *collection->begin(); - - collection->clear(); - - CassIterator* items = cass_iterator_from_collection(value); - if (!items) { - isc_throw(DbOperationError, - "CqlGetCollection(): column is not a collection"); - } - while (cass_iterator_next(items)) { - const CassValue* item_value = cass_iterator_get_value(items); - if (cass_value_is_null(item_value)) { - isc_throw(DbOperationError, - "CqlGetCollection(): null value returned in collection"); - } - const CassValueType& type = cass_value_type(item_value); - - collection->push_back(underlying_object); - KEA_CASS_CHECK(CQL_FUNCTIONS[exchangeType(type)].cqlGetFunction_( - *collection->rbegin(), item_value)); - // If cqlGetFunction_() returns != CASS_OK, don't call - // cass_iterator_free(items_iterator) because we're returning from this - // function and throwing from the callee. - } - cass_iterator_free(items); - return CASS_OK; -} /// @} /// @brief Functions used to interface with the Cassandra C++ driver CqlFunctionMap CQL_FUNCTIONS = // {{EXCHANGE_DATA_TYPE_NONE, - {CqlBindNone, CqlUdtSetNone, CqlCollectionAppendNone, CqlGetNone}}, + {CqlBindNone, CqlGetNone}}, {EXCHANGE_DATA_TYPE_BOOL, - {CqlBindBool, CqlUdtSetBool, CqlCollectionAppendBool, CqlGetBool}}, + {CqlBindBool, CqlGetBool}}, {EXCHANGE_DATA_TYPE_INT8, - {CqlBindInt8, CqlUdtSetInt8, CqlCollectionAppendInt8, CqlGetInt8}}, + {CqlBindInt8, CqlGetInt8}}, {EXCHANGE_DATA_TYPE_INT16, - {CqlBindInt16, CqlUdtSetInt16, CqlCollectionAppendInt16, CqlGetInt16}}, + {CqlBindInt16, CqlGetInt16}}, {EXCHANGE_DATA_TYPE_INT32, - {CqlBindInt32, CqlUdtSetInt32, CqlCollectionAppendInt32, CqlGetInt32}}, + {CqlBindInt32, CqlGetInt32}}, {EXCHANGE_DATA_TYPE_INT64, - {CqlBindInt64, CqlUdtSetInt64, CqlCollectionAppendInt64, CqlGetInt64}}, + {CqlBindInt64, CqlGetInt64}}, + {EXCHANGE_DATA_TYPE_TIMESTAMP, + {CqlBindInt64, CqlGetInt64}}, {EXCHANGE_DATA_TYPE_STRING, - {CqlBindString, CqlUdtSetString, CqlCollectionAppendString, - CqlGetString}}, + {CqlBindString, CqlGetString}}, {EXCHANGE_DATA_TYPE_BYTES, - {CqlBindBytes, CqlUdtSetBytes, CqlCollectionAppendBytes, CqlGetBytes}}, + {CqlBindBytes, CqlGetBytes}}, {EXCHANGE_DATA_TYPE_UUID, - {CqlBindUuid, CqlUdtSetUuid, CqlCollectionAppendUuid, CqlGetUuid}}, - {EXCHANGE_DATA_TYPE_UDT, - {CqlBindUdt, CqlUdtSetUdt, CqlCollectionAppendUdt, CqlGetUdt}}, - {EXCHANGE_DATA_TYPE_COLLECTION, - {CqlBindCollection, CqlUdtSetCollection, CqlCollectionAppendCollection, - CqlGetCollection}}}; + {CqlBindUuid, CqlGetUuid}}}; ExchangeDataType exchangeType(const boost::any& object) { @@ -656,24 +294,6 @@ exchangeType(const boost::any& object) { return exchange_type; } -ExchangeDataType -exchangeType(const CassValueType& type) { - CassTypeMap::const_iterator exchange_type_it = CASS_TYPE_MAP.find(type); - if (exchange_type_it == CASS_TYPE_MAP.end()) { - isc_throw(DbOperationError, - "exchangeType(): Cassandra value type " - << type << " does not map to any exchange type"); - } - const ExchangeDataType exchange_type = exchange_type_it->second; - if (exchange_type >= CQL_FUNCTIONS.size()) { - isc_throw(BadValue, - "exchangeType(): index " << exchange_type << " out of bounds " - << 0 << " - " - << CQL_FUNCTIONS.size() - 1); - } - return exchange_type; -} - void CqlCommon::bindData(const AnyArray& data, CassStatement* statement) { size_t i = 0u; @@ -812,7 +432,12 @@ CqlExchange::executeSelect(const CqlConnection& connection, const AnyArray& data } } - CqlCommon::bindData(local_data, statement); + try { + CqlCommon::bindData(local_data, statement); + } catch (const std::exception& ex) { + cass_statement_free(statement); + isc_throw(DbOperationError, ex.what()); + } // Everything's ready. Call the actual statement. future = cass_session_execute(connection.session_, statement); @@ -902,7 +527,12 @@ CqlExchange::executeMutation(const CqlConnection& connection, const AnyArray& da } } - CqlCommon::bindData(data, statement); + try { + CqlCommon::bindData(data, statement); + } catch (const std::exception& ex) { + cass_statement_free(statement); + isc_throw(DbOperationError, ex.what()); + } future = cass_session_execute(connection.session_, statement); if (!future) { diff --git a/src/lib/dhcpsrv/cql_exchange.h b/src/lib/dhcpsrv/cql_exchange.h index c99f762e41..5f17399ffa 100644 --- a/src/lib/dhcpsrv/cql_exchange.h +++ b/src/lib/dhcpsrv/cql_exchange.h @@ -56,38 +56,6 @@ class AnyArray : public std::vector { void remove(const size_t& index); }; -// @brief Representation of a Cassandra User Defined Type -class Udt : public AnyArray { -public: - /// @brief Parameterized constructor - Udt(const CqlConnection& connection, const std::string& name); - - /// @brief Destructor - ~Udt(); - - /// @brief Frees the underlying container. - void freeUserType(); - - /// @brief Creates the underlying container. - void newUserType(); - - /// @brief Connection to the Cassandra database - const CqlConnection& connection_; - - /// @brief Name of the UDT in the schema: CREATE TYPE ___ { ... } - const std::string name_; - - /// @brief Internal Cassandra driver object representing a Cassandra data - /// type - const CassDataType* cass_data_type_; - - /// @brief Internal Cassandra driver object representing a user defined type - CassUserType* cass_user_type_; -}; - -/// @brief Defines an array of arbitrary objects (used by Cassandra backend) -typedef AnyArray AnyCollection; - /// @brief Binds a C++ object to a Cassandra statement's parameter. Used in all /// statements. /// @param value the value to be set or retreived @@ -97,20 +65,6 @@ typedef CassError (*CqlBindFunction)(const boost::any& value, const size_t& index, CassStatement* statement); -/// @brief Sets a member in a UDT. Used in INSERT & UPDATE statements. -/// @param value the value to be set or retreived -/// @param index offset of the value being processed -/// @param cass_user_type pointer to the user type that uses this member -typedef CassError (*CqlUdtSetFunction)(const boost::any& value, - const size_t& index, - CassUserType* cass_user_type); - -/// @brief Sets an item in a collection. Used in INSERT & UPDATE statements. -/// @param value pointer to a value to be inserted or updated -/// @param collection pointer to collection to be inserted or updated -typedef CassError (*CqlCollectionAppendFunction)(const boost::any& value, - CassCollection* collection); - /// @brief Converts a single Cassandra column value to a C++ object. Used in /// SELECT statements. /// @@ -124,10 +78,6 @@ struct CqlFunction { /// @brief Binds a C++ object to a Cassandra statement's parameter. Used in /// all statements. CqlBindFunction cqlBindFunction_; - /// @brief Sets a member in a UDT. Used in INSERT & UPDATE statements. - CqlUdtSetFunction cqlUdtSetFunction_; - /// @brief Sets an item in a collection. Used in INSERT & UPDATE statements. - CqlCollectionAppendFunction cqlCollectionAppendFunction_; /// @brief Converts a single Cassandra column value to a C++ object. Used in /// SELECT statements. CqlGetFunction cqlGetFunction_; @@ -314,10 +264,6 @@ class CqlCommon { ExchangeDataType exchangeType(const boost::any& object); -/// @brief Determine exchange type based on CassValueType. -ExchangeDataType -exchangeType(const CassValueType& type); - } // namespace dhcp } // namespace isc diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index 8f3c351b7f..199294bab9 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -223,7 +223,7 @@ class CqlLease4Exchange : public CqlLeaseExchange { // Pointer to lease object Lease4Ptr lease_; // IPv4 address - cass_int32_t address_; + cass_int64_t address_; // Client identification CassBlob client_id_; }; // CqlLease4Exchange @@ -355,13 +355,13 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) { // structure. try { - // address: int + // address: bigint // The address in the Lease structure is an IOAddress object. // Convert this to an integer for storage. - address_ = static_cast(lease->addr_.toUint32()); + address_ = static_cast(lease_->addr_.toUint32()); // hwaddr: blob - if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { + if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) { if (lease_->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) { isc_throw(DbOperationError, "hardware address " @@ -376,7 +376,7 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) { } // client_id: blob - if (lease_->client_id_ && lease->client_id_->getClientId().size() > 0) { + if (lease_->client_id_ && lease_->client_id_->getClientId().size() > 0) { client_id_ = lease_->client_id_->getClientId(); } else { client_id_.clear(); @@ -391,8 +391,7 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) { // For convenience for external tools, this is converted to lease // expiry time (expire). The relationship is given by: // expire = cltt_ + valid_lft_ - CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, - expire_); + CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, expire_); // subnet_id: int subnet_id_ = static_cast(lease_->subnet_id_); @@ -449,13 +448,13 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, // structure. try { - // address: int + // address: bigint // The address in the Lease structure is an IOAddress object. // Convert this to an integer for storage. - address_ = static_cast(lease->addr_.toUint32()); + address_ = static_cast(lease_->addr_.toUint32()); // hwaddr: blob - if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { + if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) { if (lease_->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) { isc_throw(DbOperationError, "hardware address " @@ -470,7 +469,7 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, } // client_id: blob - if (lease_->client_id_ && lease->client_id_->getClientId().size() > 0) { + if (lease_->client_id_ && lease_->client_id_->getClientId().size() > 0) { client_id_ = lease_->client_id_->getClientId(); } else { client_id_.clear(); @@ -485,8 +484,7 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, // For convenience for external tools, this is converted to lease // expiry time (expire). The relationship is given by: // expire = cltt_ + valid_lft_ - CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, - expire_); + CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, expire_); // subnet_id: int subnet_id_ = static_cast(lease_->subnet_id_); @@ -538,8 +536,8 @@ CqlLease4Exchange::createBindForDelete(const IOAddress &address, AnyArray &data, // structure. try { - // address: int - address_ = static_cast(address.toUint32()); + // address: bigint + address_ = static_cast(address.toUint32()); // Start with a fresh array. data.clear(); @@ -1024,7 +1022,7 @@ CqlLease6Exchange::createBindForInsert(const Lease6Ptr &lease, AnyArray &data) { hostname_ = lease_->hostname_; // hwaddr: blob - if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { + if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) { if (lease_->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) { isc_throw(DbOperationError, "hardware address " << lease_->hwaddr_->toText() << " of length " << lease_->hwaddr_->hwaddr_.size() @@ -1112,8 +1110,7 @@ CqlLease6Exchange::createBindForUpdate(const Lease6Ptr &lease, AnyArray &data, // For convenience for external tools, this is converted to lease // expiry time (expire). The relationship is given by: // expire = cltt_ + valid_lft_ - CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, - expire_); + CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, expire_); // subnet_id: int subnet_id_ = static_cast(lease_->subnet_id_); @@ -1155,7 +1152,7 @@ CqlLease6Exchange::createBindForUpdate(const Lease6Ptr &lease, AnyArray &data, hostname_ = lease_->hostname_; // hwaddr: blob - if (lease_->hwaddr_ && lease->hwaddr_->hwaddr_.size() > 0) { + if (lease_->hwaddr_ && lease_->hwaddr_->hwaddr_.size() > 0) { if (lease_->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) { isc_throw(DbOperationError, "hardware address " @@ -1503,8 +1500,8 @@ CqlLeaseMgr::getLease4(const IOAddress &addr) const { // Set up the WHERE clause value AnyArray data; - cass_int32_t address = static_cast(addr.toUint32()); - data.add(&address); + cass_int64_t addr4 = static_cast(addr.toUint32()); + data.add(&addr4); // Get the data. Lease4Ptr result; @@ -1833,7 +1830,7 @@ CqlLeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) { DHCPSRV_CQL_DELETE_EXPIRED_RECLAIMED6) .arg(secs); AnyArray data; - uint64_t n_of_deleted_leases = 0u; + uint64_t deleted = 0u; cass_int32_t limit = 1024; // State is reclaimed. @@ -1852,10 +1849,10 @@ CqlLeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) { exchange6->getLeaseCollection(CqlLease6Exchange::GET_LEASE6_EXPIRE, data, leases); for (Lease6Ptr &lease : leases) { if (deleteLease(lease->addr_)) { - ++n_of_deleted_leases; + ++deleted; } } - return n_of_deleted_leases; + return (deleted); } size_t diff --git a/src/lib/dhcpsrv/mysql_connection.cc b/src/lib/dhcpsrv/mysql_connection.cc index fdb6859359..13dbcc57a8 100644 --- a/src/lib/dhcpsrv/mysql_connection.cc +++ b/src/lib/dhcpsrv/mysql_connection.cc @@ -42,7 +42,10 @@ MySqlTransaction::~MySqlTransaction() { // Rollback if the MySqlTransaction::commit wasn't explicitly // called. if (!committed_) { - conn_.rollback(); + try { + conn_.rollback(); + } catch (...) { + } } } @@ -131,10 +134,8 @@ MySqlConnection::openDatabase() { // No timeout parameter, we are going to use the default timeout. stimeout = ""; } - if (stimeout.size() > 0) { // Timeout was given, so try to convert it to an integer. - try { connect_timeout = boost::lexical_cast(stimeout); } catch (...) { diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index 8c70a60afa..88cf5a1458 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -197,7 +197,8 @@ tagged_statements = { { {MySqlLeaseMgr::INSERT_LEASE4, "INSERT INTO lease4(address, hwaddr, client_id, " "valid_lifetime, expire, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state) " + "fqdn_fwd, fqdn_rev, hostname, " + "state) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"}, {MySqlLeaseMgr::INSERT_LEASE6, "INSERT INTO lease6(address, duid, valid_lifetime, " @@ -211,7 +212,8 @@ tagged_statements = { { "UPDATE lease4 SET address = ?, hwaddr = ?, " "client_id = ?, valid_lifetime = ?, expire = ?, " "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, " - "hostname = ?, state = ? " + "hostname = ?, " + "state = ? " "WHERE address = ?"}, {MySqlLeaseMgr::UPDATE_LEASE6, "UPDATE lease6 SET address = ?, duid = ?, " @@ -471,6 +473,7 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { bind_[9].is_unsigned = MLM_TRUE; // bind_[9].is_null = &MLM_FALSE; // commented out for performance // reasons, see memset() above + // Add the error flags setErrorIndicators(bind_, error_, LEASE_COLUMNS); @@ -623,7 +626,10 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { client_id_buffer_, client_id_length_, valid_lifetime_, 0, 0, cltt, subnet_id_, fqdn_fwd_, fqdn_rev_, hostname)); + + // Set state. lease->state_ = state_; + return (lease); } @@ -648,8 +654,8 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { // Note: Arrays are declared fixed length for speed of creation uint32_t addr4_; ///< IPv4 address MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array - std::string columns_[LEASE_COLUMNS];///< Column names - my_bool error_[LEASE_COLUMNS]; ///< Error array + std::string columns_[LEASE_COLUMNS]; ///< Column names + my_bool error_[LEASE_COLUMNS]; ///< Error array std::vector hwaddr_; ///< Hardware address uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Hardware address buffer @@ -673,11 +679,9 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { ///< Client hostname unsigned long hostname_length_; ///< Client hostname length uint32_t state_; ///< Lease state - }; - /// @brief Exchange MySQL and Lease6 Data /// /// On any MySQL operation, arrays of MYSQL_BIND structures must be built to @@ -698,7 +702,7 @@ class MySqlLease6Exchange : public MySqlLeaseExchange { public: /// @brief Constructor /// - /// The initialization of the variables here is nonly to satisfy cppcheck - + /// The initialization of the variables here is only to satisfy cppcheck - /// all variables are initialized/set in the methods before they are used. MySqlLease6Exchange() : addr6_length_(0), duid_length_(0), iaid_(0), lease_type_(0), prefixlen_(0), @@ -981,7 +985,7 @@ class MySqlLease6Exchange : public MySqlLeaseExchange { // code that explicitly sets is_null is there, but is commented out. memset(bind_, 0, sizeof(bind_)); - // address: varchar(39) + // address: varchar(39) // A Lease6_ address has a maximum of 39 characters. The array is // one byte longer than this to guarantee that we can always null // terminate it whatever is returned. @@ -1100,6 +1104,7 @@ class MySqlLease6Exchange : public MySqlLeaseExchange { bind_[15].is_unsigned = MLM_TRUE; // bind_[15].is_null = &MLM_FALSE; // commented out for performance // reasons, see memset() above + // Add the error flags setErrorIndicators(bind_, error_, LEASE_COLUMNS); @@ -1202,11 +1207,11 @@ class MySqlLease6Exchange : public MySqlLeaseExchange { // schema. // Note: arrays are declared fixed length for speed of creation std::string addr6_; ///< String form of address - char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character + char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character ///< array form of V6 address unsigned long addr6_length_; ///< Length of the address MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array - std::string columns_[LEASE_COLUMNS];///< Column names + std::string columns_[LEASE_COLUMNS]; ///< Column names std::vector duid_; ///< Client identification uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID unsigned long duid_length_; ///< Length of the DUID @@ -1323,7 +1328,6 @@ class MySqlLeaseStatsQuery : public LeaseStatsQuery { conn_.checkError(status, statement_index_, "results storage failed"); } - /// @brief Fetches the next row in the result set /// /// Once the internal result set has been populated by invoking the @@ -1404,7 +1408,6 @@ MySqlLeaseMgr::MySqlLeaseMgr(const MySqlConnection::ParameterMap& parameters) exchange6_.reset(new MySqlLease6Exchange()); } - MySqlLeaseMgr::~MySqlLeaseMgr() { // There is no need to close the database in this destructor: it is // closed in the destructor of the mysql_ member variable. @@ -1562,7 +1565,6 @@ void MySqlLeaseMgr::getLeaseCollection(StatementIndex stindex, } } - void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind, Lease4Ptr& result) const { // Create appropriate collection object and get all leases matching @@ -1581,7 +1583,6 @@ void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind, } } - void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind, Lease6Ptr& result) const { // Create appropriate collection object and get all leases matching @@ -1600,7 +1601,6 @@ void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind, } } - // Basic lease access methods. Obtain leases from the database using various // criteria. @@ -1625,7 +1625,6 @@ MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const { return (result); } - Lease4Collection MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, @@ -1655,7 +1654,6 @@ MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const { return (result); } - Lease4Ptr MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, @@ -1690,7 +1688,6 @@ MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const { return (result); } - Lease4Collection MySqlLeaseMgr::getLease4(const ClientId& clientid) const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, @@ -1815,7 +1812,6 @@ MySqlLeaseMgr::getLease6(Lease::Type lease_type, return (result); } - Lease6Collection MySqlLeaseMgr::getLeases6(Lease::Type lease_type, const DUID& duid, uint32_t iaid) const { @@ -1959,8 +1955,6 @@ MySqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases, getLeaseCollection(statement_index, inbind, expired_leases); } - - // Update lease methods. These comprise common code that handles the actual // update, and type-specific methods that set up the parameters for the prepared // statement depending on the type of lease. @@ -1992,7 +1986,6 @@ MySqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, MYSQL_BIND* bind, } } - void MySqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { const StatementIndex stindex = UPDATE_LEASE4; @@ -2017,7 +2010,6 @@ MySqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { updateLeaseCommon(stindex, &bind[0], lease); } - void MySqlLeaseMgr::updateLease6(const Lease6Ptr& lease) { const StatementIndex stindex = UPDATE_LEASE6; @@ -2170,13 +2162,11 @@ MySqlLeaseMgr::getName() const { return (name); } - std::string MySqlLeaseMgr::getDescription() const { return (std::string("MySQL Database")); } - std::pair MySqlLeaseMgr::getVersion() const { const StatementIndex stindex = GET_VERSION; @@ -2253,7 +2243,6 @@ MySqlLeaseMgr::commit() { } } - void MySqlLeaseMgr::rollback() { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_ROLLBACK); diff --git a/src/lib/dhcpsrv/parsers/dbaccess_parser.cc b/src/lib/dhcpsrv/parsers/dbaccess_parser.cc index 5fb6434c0e..caac267731 100644 --- a/src/lib/dhcpsrv/parsers/dbaccess_parser.cc +++ b/src/lib/dhcpsrv/parsers/dbaccess_parser.cc @@ -59,8 +59,9 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db, // 2. Update the copy with the passed keywords. BOOST_FOREACH(ConfigPair param, database_config->mapValue()) { try { - if ((param.first == "persist") || (param.first == "readonly") || - (param.first == "tcp-nodelay")) { + if ((param.first == "persist") || + (param.first == "tcp-nodelay") || + (param.first == "readonly")) { values_copy[param.first] = (param.second->boolValue() ? "true" : "false"); @@ -95,6 +96,14 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db, boost::lexical_cast(port); } else { + // all remaining string parameters + // type + // user + // password + // host + // name + // contact-points + // keyspace values_copy[param.first] = param.second->stringValue(); } } catch (const isc::data::TypeError& ex) { diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index b10d7e7eda..c3f694395b 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -849,7 +849,7 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) { OptionDataListParser opts_parser(AF_INET6); opts_parser.parse(options_, option_data); } - + ConstElementPtr user_context = pd_pool_->get("user-context"); if (user_context) { user_context_ = user_context; @@ -1000,7 +1000,7 @@ Subnet6ConfigParser::initSubnet(data::ConstElementPtr params, << ", rapid-commit is " << (rapid_commit ? "enabled" : "disabled"); - LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET4).arg(output.str()); + LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET6).arg(output.str()); // Create a new subnet. Subnet6* subnet6 = new Subnet6(addr, len, t1, t2, pref, valid, @@ -1155,9 +1155,9 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) { std::string sender_ip_str = getString(client_config, "sender-ip"); - uint32_t sender_port = getUint32(client_config, "sender-port"); + uint32_t sender_port = getUint32(client_config, "sender-port"); - uint32_t max_queue_size = getUint32(client_config, "max-queue-size"); + uint32_t max_queue_size = getUint32(client_config, "max-queue-size"); dhcp_ddns::NameChangeProtocol ncr_protocol = getProtocol(client_config, "ncr-protocol"); @@ -1186,7 +1186,7 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) { if (client_config->contains("qualifying-suffix")) { qualifying_suffix = getString(client_config, "qualifying-suffix"); found_qualifying_suffix = true; - } + } IOAddress sender_ip(0); if (sender_ip_str.empty()) { diff --git a/src/lib/dhcpsrv/pgsql_connection.cc b/src/lib/dhcpsrv/pgsql_connection.cc index 0e66d6e558..c706d60676 100644 --- a/src/lib/dhcpsrv/pgsql_connection.cc +++ b/src/lib/dhcpsrv/pgsql_connection.cc @@ -98,7 +98,10 @@ PgSqlTransaction::PgSqlTransaction(PgSqlConnection& conn) PgSqlTransaction::~PgSqlTransaction() { // If commit() wasn't explicitly called, rollback. if (!committed_) { - conn_.rollback(); + try { + conn_.rollback(); + } catch (...) { + } } } diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index 3d8c30cfdc..242e4f8bed 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -68,7 +68,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_addr", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE address = $1"}, @@ -77,7 +78,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_clientid", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE client_id = $1"}, @@ -86,7 +88,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_clientid_subid", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE client_id = $1 AND subnet_id = $2"}, @@ -95,7 +98,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_hwaddr", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE hwaddr = $1"}, @@ -104,7 +108,8 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_hwaddr_subid", "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " + "fqdn_fwd, fqdn_rev, hostname, " + "state " "FROM lease4 " "WHERE hwaddr = $1 AND subnet_id = $2"}, @@ -121,12 +126,13 @@ PgSqlTaggedStatement tagged_statements[] = { { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 }, "get_lease4_expire", "SELECT address, hwaddr, client_id, " - "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname, state " - "FROM lease4 " - "WHERE state != $1 AND expire < $2 " - "ORDER BY expire " - "LIMIT $3"}, + "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " + "fqdn_fwd, fqdn_rev, hostname, " + "state " + "FROM lease4 " + "WHERE state != $1 AND expire < $2 " + "ORDER BY expire " + "LIMIT $3"}, // GET_LEASE6_ADDR { 2, { OID_VARCHAR, OID_INT2 }, @@ -163,14 +169,14 @@ PgSqlTaggedStatement tagged_statements[] = { { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 }, "get_lease6_expire", "SELECT address, duid, valid_lifetime, " - "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len, " - "fqdn_fwd, fqdn_rev, hostname, state " - "state " - "FROM lease6 " - "WHERE state != $1 AND expire < $2 " - "ORDER BY expire " - "LIMIT $3"}, + "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, " + "fqdn_fwd, fqdn_rev, hostname, " + "state " + "FROM lease6 " + "WHERE state != $1 AND expire < $2 " + "ORDER BY expire " + "LIMIT $3"}, // GET_VERSION { 0, { OID_NONE }, @@ -193,7 +199,8 @@ PgSqlTaggedStatement tagged_statements[] = { "insert_lease6", "INSERT INTO lease6(address, duid, valid_lifetime, " "expire, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, state) " + "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, " + "state) " "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)"}, // UPDATE_LEASE4 @@ -275,7 +282,6 @@ class PgSqlLeaseExchange : public PgSqlExchange { }; - /// @brief Supports exchanging IPv4 leases with PostgreSQL. class PgSqlLease4Exchange : public PgSqlLeaseExchange { private: @@ -437,7 +443,9 @@ class PgSqlLease4Exchange : public PgSqlLeaseExchange { valid_lifetime_, 0, 0, cltt_, subnet_id_, fqdn_fwd_, fqdn_rev_, hostname_)); + result->state_ = state; + return (result); } catch (const std::exception& ex) { isc_throw(DbOperationError, @@ -646,7 +654,9 @@ class PgSqlLease6Exchange : public PgSqlLeaseExchange { subnet_id_, fqdn_fwd_, fqdn_rev_, hostname_, hwaddr, prefix_len_)); result->cltt_ = cltt_; + result->state_ = state; + return (result); } catch (const std::exception& ex) { isc_throw(DbOperationError, @@ -929,7 +939,6 @@ void PgSqlLeaseMgr::getLeaseCollection(StatementIndex stindex, } } - void PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array, Lease4Ptr& result) const { @@ -949,7 +958,6 @@ PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array, } } - void PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array, Lease6Ptr& result) const { @@ -1247,7 +1255,6 @@ PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases, getLeaseCollection(statement_index, bind_array, expired_leases); } - template void PgSqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, @@ -1283,7 +1290,6 @@ PgSqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, "that had the address " << lease->addr_.toText()); } - void PgSqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { const StatementIndex stindex = UPDATE_LEASE4; @@ -1296,9 +1302,9 @@ PgSqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { exchange4_->createBindForSend(lease, bind_array); // Set up the WHERE clause and append it to the SQL_BIND array - std::string addr4_ = boost::lexical_cast + std::string addr4_str = boost::lexical_cast (lease->addr_.toUint32()); - bind_array.add(addr4_); + bind_array.add(addr4_str); // Drop to common update code updateLeaseCommon(stindex, bind_array, lease); diff --git a/src/lib/dhcpsrv/sql_common.h b/src/lib/dhcpsrv/sql_common.h index 610abd62e1..a8795e91df 100644 --- a/src/lib/dhcpsrv/sql_common.h +++ b/src/lib/dhcpsrv/sql_common.h @@ -32,9 +32,7 @@ enum ExchangeDataType { EXCHANGE_DATA_TYPE_TIMESTAMP, EXCHANGE_DATA_TYPE_STRING, EXCHANGE_DATA_TYPE_BYTES, - EXCHANGE_DATA_TYPE_UUID, - EXCHANGE_DATA_TYPE_UDT, ///< User-Defined Type (used in Cassandra) - EXCHANGE_DATA_TYPE_COLLECTION ///< Collection (used in Cassandra) + EXCHANGE_DATA_TYPE_UUID }; /// @brief Base class for backend exchanges. diff --git a/src/lib/dhcpsrv/testutils/cql_schema.cc b/src/lib/dhcpsrv/testutils/cql_schema.cc index 8a4468e39e..115c3f176e 100644 --- a/src/lib/dhcpsrv/testutils/cql_schema.cc +++ b/src/lib/dhcpsrv/testutils/cql_schema.cc @@ -79,8 +79,10 @@ runCqlScript(const std::string& path, cmd << script_name; - int retval = ::system(cmd.str().c_str()); - ASSERT_EQ(0, retval) << "runCqlSchema failed:" << cmd.str(); + int32_t retval = ::system(cmd.str().c_str()); + if (retval) { + std::cerr << "runCqlSchema failed:" << cmd.str() << std::endl; + } } } // namespace test diff --git a/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc b/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc index 36a37efb48..41be4192a0 100644 --- a/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc +++ b/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.cc @@ -31,6 +31,12 @@ Dhcp4o6TestIpc::open() { } } +void +Dhcp4o6TestIpc::close() { + // Use the base IPC to close the socket + Dhcp4o6IpcBase::close(); +} + void Dhcp4o6TestIpc::receiveHandler() { pkt_received_ = receive(); diff --git a/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h b/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h index 5109de06c3..6af2295395 100644 --- a/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h +++ b/src/lib/dhcpsrv/testutils/dhcp4o6_test_ipc.h @@ -43,6 +43,9 @@ class Dhcp4o6TestIpc : public Dhcp4o6IpcBase { /// over the socket. virtual void open(); + /// @brief Close the IPC socket. + virtual void close(); + /// @brief Retrieve port which socket is bound to. uint16_t getPort() const { return (port_); diff --git a/src/lib/dhcpsrv/testutils/mysql_schema.cc b/src/lib/dhcpsrv/testutils/mysql_schema.cc index a216e4f49e..3b79d975b0 100644 --- a/src/lib/dhcpsrv/testutils/mysql_schema.cc +++ b/src/lib/dhcpsrv/testutils/mysql_schema.cc @@ -53,10 +53,11 @@ void runMySQLScript(const std::string& path, const std::string& script_name, cmd << script_name; int retval = ::system(cmd.str().c_str()); - ASSERT_EQ(0, retval) << "runMySQLSchema failed:" << cmd.str(); + if (retval) { + std::cerr << "runMySQLSchema failed:" << cmd.str() << std::endl; + } } - }; }; }; diff --git a/src/lib/dhcpsrv/testutils/pgsql_schema.cc b/src/lib/dhcpsrv/testutils/pgsql_schema.cc index 319fafd5ba..57729e1747 100644 --- a/src/lib/dhcpsrv/testutils/pgsql_schema.cc +++ b/src/lib/dhcpsrv/testutils/pgsql_schema.cc @@ -56,7 +56,9 @@ void runPgSQLScript(const std::string& path, const std::string& script_name, } int retval = ::system(cmd.str().c_str()); - ASSERT_EQ(0, retval) << "runPgSQLSchema failed:" << cmd.str(); + if (retval) { + std::cerr << "runPgSQLSchema failed:" << cmd.str() << std::endl; + } } }; diff --git a/src/share/database/scripts/cql/.gitignore b/src/share/database/scripts/cql/.gitignore index d184e0fe31..9976ce894b 100644 --- a/src/share/database/scripts/cql/.gitignore +++ b/src/share/database/scripts/cql/.gitignore @@ -1,2 +1 @@ upgrade_1.0_to_2.0.sh - diff --git a/src/share/database/scripts/cql/dhcpdb_create.cql b/src/share/database/scripts/cql/dhcpdb_create.cql index 2d6ab7d86f..1ee2bd652c 100644 --- a/src/share/database/scripts/cql/dhcpdb_create.cql +++ b/src/share/database/scripts/cql/dhcpdb_create.cql @@ -45,7 +45,7 @@ -- Table `lease4` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS lease4 ( - address int, + address bigint, hwaddr blob, client_id blob, valid_lifetime bigint, @@ -226,7 +226,7 @@ CREATE INDEX IF NOT EXISTS host_reservationsindex5 ON host_reservations (host_ip CREATE INDEX IF NOT EXISTS host_reservationsindex6 ON host_reservations (reserved_ipv6_prefix_address); CREATE INDEX IF NOT EXISTS host_reservationsindex7 ON host_reservations (reserved_ipv6_prefix_length); -TRUNCATE SCHEMA_VERSION; +DELETE FROM schema_version WHERE version=1; INSERT INTO schema_version (version, minor) VALUES(2, 0); -- This line concludes database upgrade to version 2.0 diff --git a/src/share/database/scripts/pgsql/dhcpdb_create.pgsql b/src/share/database/scripts/pgsql/dhcpdb_create.pgsql index 90d1aed7da..70e97bb461 100644 --- a/src/share/database/scripts/pgsql/dhcpdb_create.pgsql +++ b/src/share/database/scripts/pgsql/dhcpdb_create.pgsql @@ -35,7 +35,6 @@ CREATE TABLE lease4 ( hostname VARCHAR(255) -- The FQDN of the client ); - -- Create search indexes for lease4 table -- index by hwaddr and subnet_id CREATE INDEX lease4_by_hwaddr_subnet_id ON lease4 (hwaddr, subnet_id); From f804d7eebe49f1297bc142294773ae3c675582d7 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Fri, 9 Feb 2018 13:41:25 +0200 Subject: [PATCH 10/34] minor chnages --- src/lib/dhcpsrv/lease.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/dhcpsrv/lease.cc b/src/lib/dhcpsrv/lease.cc index 5fefaf1b3c..3802a26c18 100644 --- a/src/lib/dhcpsrv/lease.cc +++ b/src/lib/dhcpsrv/lease.cc @@ -26,9 +26,9 @@ Lease::Lease(const isc::asiolink::IOAddress& addr, uint32_t t1, uint32_t t2, uint32_t valid_lft, SubnetID subnet_id, time_t cltt, const bool fqdn_fwd, const bool fqdn_rev, const std::string& hostname, const HWAddrPtr& hwaddr) - :addr_(addr), t1_(t1), t2_(t2), valid_lft_(valid_lft), cltt_(cltt), - subnet_id_(subnet_id), hostname_(hostname), fqdn_fwd_(fqdn_fwd), - fqdn_rev_(fqdn_rev), hwaddr_(hwaddr), state_(STATE_DEFAULT) { + : addr_(addr), t1_(t1), t2_(t2), valid_lft_(valid_lft), cltt_(cltt), + subnet_id_(subnet_id), hostname_(hostname), fqdn_fwd_(fqdn_fwd), + fqdn_rev_(fqdn_rev), hwaddr_(hwaddr), state_(STATE_DEFAULT) { } From 14c3a5564c6f33ec1a9de158fe9938a180fc1ce3 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Mar 2018 11:51:31 +0200 Subject: [PATCH 11/34] minor changes - fixed eventual memory leak --- src/lib/dhcpsrv/cql_host_data_source.cc | 6 +- src/lib/dhcpsrv/cql_lease_mgr.cc | 203 +++++++----------------- src/lib/dhcpsrv/lease_mgr.h | 5 +- 3 files changed, 61 insertions(+), 153 deletions(-) diff --git a/src/lib/dhcpsrv/cql_host_data_source.cc b/src/lib/dhcpsrv/cql_host_data_source.cc index 6fab69ab02..898550c720 100644 --- a/src/lib/dhcpsrv/cql_host_data_source.cc +++ b/src/lib/dhcpsrv/cql_host_data_source.cc @@ -1162,12 +1162,12 @@ CqlHostExchange::retrieve() { asiolink::IOAddress ipv4_reservation = asiolink::IOAddress(static_cast(host_ipv4_address_)); - Host* host = new Host(host_identifier.data(), host_identifier.size(), + HostPtr host(new Host(host_identifier.data(), host_identifier.size(), host_identifier_type, ipv4_subnet_id, ipv6_subnet_id, ipv4_reservation, hostname_, host_ipv4_client_classes_, host_ipv6_client_classes_, static_cast(host_ipv4_next_server_), - host_ipv4_server_hostname_, host_ipv4_boot_file_name_); + host_ipv4_server_hostname_, host_ipv4_boot_file_name_)); // Set the user context if there is one. if (!user_context_.empty()) { @@ -2043,7 +2043,7 @@ CqlHostDataSourceImpl::getHostCollection(StatementTag statement_tag, // Form HostPtr objects. HostCollection host_collection; for (boost::any& host : collection) { - host_collection.push_back(HostPtr(boost::any_cast(host))); + host_collection.push_back(boost::any_cast(host)); } // Merge the denormalized table entries that belong to the same host diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index cca6696250..c7e40a835f 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -1459,7 +1459,7 @@ CqlLease6Exchange::getExpiredLeases(const size_t &max_leases, /// This class provides the functionality such as results storage and row /// fetching common to fulfilling the statistical lease data query. /// -class CqlLeaseStatsQuery : public LeaseStatsQuery { +class CqlLeaseStatsQuery : public LeaseStatsQuery, public CqlExchange { public: /// @brief Constructor /// @@ -1467,11 +1467,11 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { /// @param statement The lease data SQL prepared statement tag to execute /// @param fetch_type Indicates whether or not lease_type should be /// fetched from the result set (should be true for v6) - CqlLeaseStatsQuery(CqlConnection& conn, StatementTag& statement, - const bool fetch_type) - : conn_(conn), statement_(statement), fetch_type_(fetch_type), + CqlLeaseStatsQuery(CqlConnection& connection, StatementTag& statement, + const bool fetch_type) + : connection_(connection), statement_(statement), fetch_type_(fetch_type), cummulative_rows_(), next_row_(cummulative_rows_.begin()), - subnet_id_(0), lease_type_(0), lease_state_(0) { + subnet_id_(0), lease_type_(0), state_(0) { } /// @brief Destructor @@ -1485,35 +1485,6 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { /// first row of the aggregate results. void start(); - /// @brief Executes protocol specific lease query SELECT statement - /// - /// Currently we do not have a good way for Cassandra to roll up the - /// lease counts per subnet, type, and state as we do the other back - /// ends. This method executes the select statement which returns - /// a result set containing a row of data for every lease: - /// -v4 - subnet-id, lease-state - /// -v6 - subnet-id, lease-type, lease-state - /// - /// It then iterates over this result set, aggregating the data into a - /// a map of LeaseStatRows. - /// - /// If we didn't have to roll up the raw lease data first, we could - /// have derived this class from CqlExchange and used it's executeSelect - /// (from which this method borrows heavily). However, that would mean - /// copying all the raw lease data into a collection returned by - /// executeSelect and then aggregating that into cummulative rows. - /// The way we are now we go turn the raw lease data directly into the - /// cummulative row map. - /// - /// @param connection connection used to communicate with the Cassandra - /// database - /// @param where_values array of bound objects used to filter the results - /// @param statement_tag prepared statement being executed - /// - /// @throw DbOperationError - void executeSelect(const CqlConnection& connection, const AnyArray& data, - StatementTag statement_tag); - /// @brief Fetches the next row in the result set /// /// Once the internal result set has been populated by invoking the @@ -1537,6 +1508,15 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { virtual void createBindForSelect(AnyArray& data, StatementTag statement_tag = NULL); + /// @brief Copy received data into the derived class' object. + /// + /// Copies information about the entity to be retrieved into a holistic + /// object. Called in @ref executeSelect(). Not implemented for base class + /// CqlExchange. To be implemented in derived classes. + /// + /// @return a pointer to the object retrieved. + virtual boost::any retrieve(); + /// @brief Statement tags definitions /// @{ // Return recalculated lease4 lease statistics @@ -1549,8 +1529,8 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { static StatementMap tagged_statements_; private: - /// @brief Database connection to use to execute the query - CqlConnection& conn_; + /// @brief Database connection + const CqlConnection &connection_; /// @brief The query's prepared statement tag StatementTag statement_; @@ -1558,19 +1538,20 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { /// @brief Indicates if query supplies lease type bool fetch_type_; - /// @brief map containing the aggregated lease counts std::map cummulative_rows_; /// @brief cursor pointing to the next row to read in aggregate map std::map::iterator next_row_; - /// @brief bind variable for retrieving subnet-id from a result set row - int subnet_id_; - /// @brief bind variable for retrieving lease-type from a result set row - int lease_type_; - /// @brief bind variable for retrieving lease-state from a result set row - int lease_state_; + /// @brief Subnet identifier + cass_int32_t subnet_id_; + + /// @brief Lease type (NA, TA or PD) + cass_int32_t lease_type_; + + /// @brief Lease state + cass_int32_t state_; }; constexpr StatementTag CqlLeaseStatsQuery::RECOUNT_LEASE4_STATS; @@ -1600,7 +1581,20 @@ CqlLeaseStatsQuery::start() { // This gets a collection of data for ALL leases, and // then rolls them up into cummulative_rows_ - executeSelect(conn_, data, statement_); + AnyArray collection = executeSelect(connection_, data, statement_); + + // Form LeaseStatsRowPtr objects. + LeaseStatsCollection stats_collection; + for (boost::any& stats : collection) { + LeaseStatsRowPtr data(boost::any_cast(stats)); + stats_collection.push_back(data); + auto cum_row = cummulative_rows_.find(*data); + if (cum_row != cummulative_rows_.end()) { + cummulative_rows_[*data] = cum_row->second + 1; + } else { + cummulative_rows_.insert(std::make_pair(*data, 1)); + } + } // Set our row iterator to the beginning next_row_ = cummulative_rows_.begin(); @@ -1627,118 +1621,29 @@ CqlLeaseStatsQuery::getNextRow(LeaseStatsRow& row) { } void -CqlLeaseStatsQuery::createBindForSelect(AnyArray& data, StatementTag) { - data.clear(); - data.add(&subnet_id_); - if (fetch_type_) { - data.add(&lease_type_); - } +CqlLeaseStatsQuery::createBindForSelect(AnyArray& data, StatementTag statement_tag) { - data.add(&lease_state_); -} + // Start with a fresh array. + data.clear(); -void -CqlLeaseStatsQuery::executeSelect(const CqlConnection& connection, const AnyArray& data, - StatementTag statement_tag) { - CassError rc; - CassStatement* statement = NULL; - CassFuture* future = NULL; - AnyArray local_data = data; - - // Find the query statement first. - StatementMap::const_iterator it = connection.statements_.find(statement_tag); - if (it == connection.statements_.end()) { - isc_throw(DbOperationError, - "CqlLeastStatsQuery::executeSelect(): Statement " - << statement_tag << "has not been prepared."); - } + // subnet_id: int + data.add(&subnet_id_); - // Bind the data before the query is executed. - CqlTaggedStatement tagged_statement = it->second; - if (tagged_statement.is_raw_) { - // The entire query is the first element in data. - std::string* query = boost::any_cast(local_data.back()); - local_data.pop_back(); - statement = cass_statement_new(query->c_str(), local_data.size()); + // lease_type: int + if (statement_tag == CqlLeaseStatsQuery::RECOUNT_LEASE6_STATS) { + data.add(&lease_type_); } else { - statement = cass_prepared_bind(tagged_statement.prepared_statement_); - if (!statement) { - isc_throw(DbOperationError, - "CqlLeaseStatsQuery::executeSelect(): unable to bind statement " - << tagged_statement.name_); - } - } - - // Set specific level of consistency if we're told to do so. - if (connection.force_consistency_) { - rc = cass_statement_set_consistency(statement, connection.consistency_); - if (rc != CASS_OK) { - cass_statement_free(statement); - isc_throw(DbOperationError, - "CqlLeaseStatsQuery::executeSelect(): unable to set statement " - "consistency for statement " - << tagged_statement.name_ - << ", Cassandra error code: " << cass_error_desc(rc)); - } - } - - CqlCommon::bindData(local_data, statement); - - // Everything's ready. Call the actual statement. - future = cass_session_execute(connection.session_, statement); - if (!future) { - cass_statement_free(statement); - isc_throw(DbOperationError, - "CqlLeaseStatsQuery::executeSelect(): no CassFuture for statement " - << tagged_statement.name_); + lease_type_ = Lease::TYPE_NA; // lease type is always NA for v4 } - // Wait for the statement execution to complete. - cass_future_wait(future); - const std::string error = connection.checkFutureError( - "CqlLeaseStatsQuery::executeSelect(): cass_session_execute() != CASS_OK", - future, statement_tag); - rc = cass_future_error_code(future); - if (rc != CASS_OK) { - cass_future_free(future); - cass_statement_free(statement); - isc_throw(DbOperationError, error); - } - - // Get column values. - const CassResult* result_collection = cass_future_get_result(future); - - // lease type is always NA for v4 - if (!fetch_type_) { - lease_type_ = Lease::TYPE_NA; - } - - // Since we're currently forced to pull data for all leases, we - // iterate over them, aggregating them into cummulative LeaseStatsRows - AnyArray return_values; - CassIterator* rows = cass_iterator_from_result(result_collection); - while (cass_iterator_next(rows)) { - const CassRow* row = cass_iterator_get_row(rows); - createBindForSelect(return_values, statement_tag); - CqlCommon::getData(row, return_values); - - LeaseStatsRow raw_row(subnet_id_, static_cast(lease_type_), - lease_state_, 1); - - auto cum_row = cummulative_rows_.find(raw_row); - if (cum_row != cummulative_rows_.end()) { - cummulative_rows_[raw_row] = cum_row->second + 1; - } else { - cummulative_rows_.insert(std::make_pair(raw_row, 1)); - } - } + // state: int + data.add(&state_); +} - // Free resources. - cass_iterator_free(rows); - cass_result_free(result_collection); - cass_future_free(future); - cass_statement_free(statement); - return; +boost::any +CqlLeaseStatsQuery::retrieve() { + return (LeaseStatsRowPtr(new LeaseStatsRow(subnet_id_, + static_cast(lease_type_), state_, 1))); } CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap ¶meters) diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h index 56507195f7..db1d7e5e33 100644 --- a/src/lib/dhcpsrv/lease_mgr.h +++ b/src/lib/dhcpsrv/lease_mgr.h @@ -114,7 +114,7 @@ struct LeaseStatsRow { if (subnet_id_ == rhs.subnet_id_ && lease_type_ == rhs.lease_type_ && - lease_state_ < rhs.lease_state_) { + lease_state_ < rhs.lease_state_) { return (true); } @@ -166,6 +166,9 @@ typedef boost::shared_ptr LeaseStatsQueryPtr; /// @brief Defines a pointer to a LeaseStatsRow. typedef boost::shared_ptr LeaseStatsRowPtr; +/// @brief Collection of the @c LeaseStatsRow objects. +typedef std::vector LeaseStatsCollection; + /// @brief Abstract Lease Manager /// /// This is an abstract API for lease database backends. It provides unified From 45464c577d5ce8f5f4c1a1eec389d0915b8bbf8d Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Mar 2018 14:15:08 +0200 Subject: [PATCH 12/34] minor changes --- src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc | 7 ++++--- src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc | 11 +++-------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index a93a96d6a1..84eaeca08e 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -221,7 +221,7 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { } // This is the CQL implementation for - // GenericLeaseMgrTest::testGetExpiredLeases4(). + // GenericLeaseMgrTest::testGetExpiredLeases6(). // The GenericLeaseMgrTest implementation checks for the order of expired // leases to be from the most expired to the least expired. Cassandra // doesn't support ORDER BY without imposing a EQ / IN restriction on the @@ -283,8 +283,7 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { } // Retrieve expired leases again. The limit of 0 means return all - // expired - // leases. + // expired leases. ASSERT_NO_THROW(lmptr_->getExpiredLeases6(expired_leases, 0)); // The same leases should be returned. @@ -317,6 +316,8 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { // This the returned leases should exclude reclaimed ones. So the number // of returned leases should be roughly half of the expired leases. ASSERT_NO_THROW(lmptr_->getExpiredLeases6(expired_leases, 0)); + ASSERT_EQ(static_cast(saved_expired_leases.size() / 2u), + expired_leases.size()); // Make sure that returned leases are those that are not reclaimed, i.e. // those that have even index. diff --git a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc index 037172f2b1..fe99c87a60 100644 --- a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc @@ -779,7 +779,6 @@ GenericLeaseMgrTest::testBasicLease4() { detailCompareLease(leases[3], l_returned); } - void GenericLeaseMgrTest::testBasicLease6() { // Get the leases to be used for the test. @@ -1081,7 +1080,6 @@ GenericLeaseMgrTest::testGetLease4HWAddrSubnetId() { EXPECT_THROW(returned = lmptr_->getLease4(*leases[1]->hwaddr_, leases[1]->subnet_id_), isc::dhcp::MultipleRecords); - } void @@ -1315,7 +1313,6 @@ GenericLeaseMgrTest::testGetLeases6DuidSize() { // Don't bother to check DUIDs longer than the maximum - these cannot be // constructed, and that limitation is tested in the DUID/Client ID unit // tests. - } void @@ -1841,6 +1838,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() { int index = static_cast(std::distance(expired_leases.rbegin(), lease)); // Multiple current index by two, because only leases with even indexes // should have been returned. + ASSERT_LE(2 * index, leases.size()); EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_); } @@ -1855,7 +1853,6 @@ GenericLeaseMgrTest::testGetExpiredLeases6() { // Update the time of expired leases with even indexes. if (i % 2 == 0) { leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - 1000 + i; - } else { // Make sure remaining leases remain unexpired. leases[i]->cltt_ = current_time + 100; @@ -1873,6 +1870,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() { for (Lease6Collection::iterator lease = expired_leases.begin(); lease != expired_leases.end(); ++lease) { int index = static_cast(std::distance(expired_leases.begin(), lease)); + ASSERT_LE(2 * index, leases.size()); EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_); } @@ -1892,6 +1890,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() { for (Lease6Collection::iterator lease = expired_leases.begin(); lease != expired_leases.end(); ++lease) { int index = static_cast(std::distance(expired_leases.begin(), lease)); + ASSERT_LE(2 * index, leases.size()); EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_); } @@ -2516,7 +2515,6 @@ GenericLeaseMgrTest::testRecountLeaseStats4() { subnet->addPool(pool); cfg->add(subnet); - ASSERT_NO_THROW(CfgMgr::instance().commit()); // Create the expected stats list. At this point, the only stat @@ -2587,7 +2585,6 @@ GenericLeaseMgrTest::testRecountLeaseStats4() { ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats)); } - void GenericLeaseMgrTest::testRecountLeaseStats6() { using namespace stats; @@ -2624,7 +2621,6 @@ GenericLeaseMgrTest::testRecountLeaseStats6() { ASSERT_NO_THROW(CfgMgr::instance().commit()); - // Create the expected stats list. At this point, the only stat // that should be non-zero is total-nas/total-pds. for (int i = 0; i < num_subnets; ++i) { @@ -2638,7 +2634,6 @@ GenericLeaseMgrTest::testRecountLeaseStats6() { // Make sure stats are as expected. ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats)); - // Recount stats. We should have the same results. ASSERT_NO_THROW(lmptr_->recountLeaseStats4()); From 16c80de1e2b293a28ccd3519f9a7da6fd7b0f47d Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Mar 2018 14:20:50 +0200 Subject: [PATCH 13/34] minor changes --- src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc | 4 ++-- src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc | 4 ++-- src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index 84eaeca08e..423ef8ade7 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -752,14 +752,14 @@ TEST_F(CqlLeaseMgrTest, recountLeaseStats6) { testRecountLeaseStats6(); } -// @brief Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. /// @todo: uncomment this once lease wipe is implemented /// for Cassandra (see #5485) TEST_F(CqlLeaseMgrTest, DISABLED_wipeLeases4) { testWipeLeases4(); } -// @brief Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. /// @todo: uncomment this once lease wipe is implemented /// for Cassandra (see #5485) TEST_F(CqlLeaseMgrTest, DISABLED_wipeLeases6) { diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc index 64fae4c95d..4bccd73ec4 100644 --- a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc @@ -516,12 +516,12 @@ TEST_F(MySqlLeaseMgrTest, recountLeaseStats6) { testRecountLeaseStats6(); } -// @brief Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. TEST_F(MySqlLeaseMgrTest, DISABLED_wipeLeases4) { testWipeLeases4(); } -// @brief Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. TEST_F(MySqlLeaseMgrTest, DISABLED_wipeLeases6) { testWipeLeases6(); } diff --git a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc index 67c34553cf..3a9de30ee6 100644 --- a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc @@ -478,12 +478,12 @@ TEST_F(PgSqlLeaseMgrTest, recountLeaseStats6) { testRecountLeaseStats6(); } -// @brief Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. TEST_F(PgSqlLeaseMgrTest, DISABLED_wipeLeases4) { testWipeLeases4(); } -// @brief Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. TEST_F(PgSqlLeaseMgrTest, DISABLED_wipeLeases6) { testWipeLeases6(); } From 5637d018a133a101a8ca63775d49b82dbdb717b4 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Mar 2018 15:17:58 +0200 Subject: [PATCH 14/34] minor changes --- src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc index fe99c87a60..2d2c88fb20 100644 --- a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc @@ -1970,6 +1970,7 @@ GenericLeaseMgrTest::testDeleteExpiredReclaimedLeases4() { EXPECT_FALSE(lease) << "The following lease should have been" " deleted: " << leases[i]->toText(); ++should_delete_num; + } else { // If the lease is not reclaimed or it has expired less than // 15 seconds ago, the lease should still be there. @@ -1977,9 +1978,8 @@ GenericLeaseMgrTest::testDeleteExpiredReclaimedLeases4() { " deleted: " << leases[i]->toText(); } } - - // Check that the number of leases deleted is correct. - EXPECT_EQ(deleted_num, should_delete_num); + // Check that the number of deleted leases is correct. + EXPECT_EQ(should_delete_num, deleted_num); // Make sure we can make another attempt, when there are no more leases // to be deleted. From 4637a2308494af08168284bf6a983508941c7b4e Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Mar 2018 15:24:41 +0200 Subject: [PATCH 15/34] refactored cql recount leases plus minor changes --- src/bin/perfdhcp/command_options.cc | 5 +- src/lib/config/base_command_mgr.cc | 2 +- src/lib/dhcpsrv/benchmarks/benchmarks.dox | 2 +- src/lib/dhcpsrv/cql_host_data_source.cc | 6 +- src/lib/dhcpsrv/cql_lease_mgr.cc | 203 +++++------------- src/lib/dhcpsrv/lease_mgr.h | 5 +- .../dhcpsrv/tests/cql_lease_mgr_unittest.cc | 12 +- .../tests/generic_lease_mgr_unittest.cc | 15 +- .../dhcpsrv/tests/mysql_lease_mgr_unittest.cc | 8 +- .../dhcpsrv/tests/pgsql_lease_mgr_unittest.cc | 8 +- 10 files changed, 85 insertions(+), 181 deletions(-) diff --git a/src/bin/perfdhcp/command_options.cc b/src/bin/perfdhcp/command_options.cc index 7d6babffc8..3a12cc247c 100644 --- a/src/bin/perfdhcp/command_options.cc +++ b/src/bin/perfdhcp/command_options.cc @@ -370,9 +370,8 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) { break; case 'W': - // 'm' for moratorium exit_wait_time_ = nonNegativeInteger("value of exist wait time: " - "-m must not be a " + "-W must not be a " "negative integer"); break; @@ -989,7 +988,7 @@ CommandOptions::usage() const { " [-n] [-p] [-d]\n" " [-D] [-l] [-P]\n" " [-a] [-L] [-s] [-i] [-B]\n" - " [-m]\n" + " [-W]\n" " [-c] [-1] [-M] [-T]\n" " [-X] [-O]\n" " [-S] [-I] [-x]\n" diff --git a/src/lib/config/base_command_mgr.cc b/src/lib/config/base_command_mgr.cc index d76bde71f5..eaa1700f48 100644 --- a/src/lib/config/base_command_mgr.cc +++ b/src/lib/config/base_command_mgr.cc @@ -172,7 +172,7 @@ BaseCommandMgr::handleCommand(const std::string& cmd_name, } isc::data::ConstElementPtr -BaseCommandMgr::listCommandsHandler(const std::string& name, +BaseCommandMgr::listCommandsHandler(const std::string& /* name */, const isc::data::ConstElementPtr& ) { using namespace isc::data; ElementPtr commands = Element::createList(); diff --git a/src/lib/dhcpsrv/benchmarks/benchmarks.dox b/src/lib/dhcpsrv/benchmarks/benchmarks.dox index 8e5327b3ce..98dc88a448 100644 --- a/src/lib/dhcpsrv/benchmarks/benchmarks.dox +++ b/src/lib/dhcpsrv/benchmarks/benchmarks.dox @@ -23,7 +23,7 @@ $ make The benchmarks are built in @b src/lib/dhcpsrv/benchmarks directory. Note that the benchmarks are backend-specific, so please make sure you enable the backends you want to measure (See --with-mysql, ---with-pgsql --with-cql parameters for configure). Once the +--with-pgsql, --with-cql parameters for configure). Once the benchmark is built, you can run specific benchmarks. Make sure you have the environment ready for use, i.e. the actual database backend is set up, the DB or keyspace is created. The setup is the same as for diff --git a/src/lib/dhcpsrv/cql_host_data_source.cc b/src/lib/dhcpsrv/cql_host_data_source.cc index e9073848b1..7410e5debc 100644 --- a/src/lib/dhcpsrv/cql_host_data_source.cc +++ b/src/lib/dhcpsrv/cql_host_data_source.cc @@ -898,10 +898,10 @@ CqlHostExchange::retrieve() { asiolink::IOAddress ipv4_reservation = asiolink::IOAddress(static_cast(host_ipv4_address_)); - Host* host = new Host(host_identifier.data(), host_identifier.size(), + HostPtr host(new Host(host_identifier.data(), host_identifier.size(), host_identifier_type, ipv4_subnet_id, ipv6_subnet_id, ipv4_reservation, hostname_, - host_ipv4_client_classes_, host_ipv6_client_classes_); + host_ipv4_client_classes_, host_ipv6_client_classes_)); host->setHostId(id); const IPv6Resrv reservation = retrieveReservation(); @@ -1702,7 +1702,7 @@ CqlHostDataSourceImpl::getHostCollection(StatementTag statement_tag, // Form HostPtr objects. HostCollection host_collection; for (boost::any& host : collection) { - host_collection.push_back(HostPtr(boost::any_cast(host))); + host_collection.push_back(boost::any_cast(host)); } // Merge the denormalized table entries that belong to the same host diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index 0527b43753..4a951f8504 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -1437,7 +1437,7 @@ CqlLease6Exchange::getExpiredLeases(const size_t &max_leases, /// This class provides the functionality such as results storage and row /// fetching common to fulfilling the statistical lease data query. /// -class CqlLeaseStatsQuery : public LeaseStatsQuery { +class CqlLeaseStatsQuery : public LeaseStatsQuery, public CqlExchange { public: /// @brief Constructor /// @@ -1445,11 +1445,11 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { /// @param statement The lease data SQL prepared statement tag to execute /// @param fetch_type Indicates whether or not lease_type should be /// fetched from the result set (should be true for v6) - CqlLeaseStatsQuery(CqlConnection& conn, StatementTag& statement, - const bool fetch_type) - : conn_(conn), statement_(statement), fetch_type_(fetch_type), + CqlLeaseStatsQuery(CqlConnection& connection, StatementTag& statement, + const bool fetch_type) + : connection_(connection), statement_(statement), fetch_type_(fetch_type), cummulative_rows_(), next_row_(cummulative_rows_.begin()), - subnet_id_(0), lease_type_(0), lease_state_(0) { + subnet_id_(0), lease_type_(0), state_(0) { } /// @brief Destructor @@ -1463,35 +1463,6 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { /// first row of the aggregate results. void start(); - /// @brief Executes protocol specific lease query SELECT statement - /// - /// Currently we do not have a good way for Cassandra to roll up the - /// lease counts per subnet, type, and state as we do the other back - /// ends. This method executes the select statement which returns - /// a result set containing a row of data for every lease: - /// -v4 - subnet-id, lease-state - /// -v6 - subnet-id, lease-type, lease-state - /// - /// It then iterates over this result set, aggregating the data into a - /// a map of LeaseStatRows. - /// - /// If we didn't have to roll up the raw lease data first, we could - /// have derived this class from CqlExchange and used it's executeSelect - /// (from which this method borrows heavily). However, that would mean - /// copying all the raw lease data into a collection returned by - /// executeSelect and then aggregating that into cummulative rows. - /// The way we are now we go turn the raw lease data directly into the - /// cummulative row map. - /// - /// @param connection connection used to communicate with the Cassandra - /// database - /// @param where_values array of bound objects used to filter the results - /// @param statement_tag prepared statement being executed - /// - /// @throw DbOperationError - void executeSelect(const CqlConnection& connection, const AnyArray& data, - StatementTag statement_tag); - /// @brief Fetches the next row in the result set /// /// Once the internal result set has been populated by invoking the @@ -1515,6 +1486,15 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { virtual void createBindForSelect(AnyArray& data, StatementTag statement_tag = NULL); + /// @brief Copy received data into the derived class' object. + /// + /// Copies information about the entity to be retrieved into a holistic + /// object. Called in @ref executeSelect(). Not implemented for base class + /// CqlExchange. To be implemented in derived classes. + /// + /// @return a pointer to the object retrieved. + virtual boost::any retrieve(); + /// @brief Statement tags definitions /// @{ // Return recalculated lease4 lease statistics @@ -1527,8 +1507,8 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { static StatementMap tagged_statements_; private: - /// @brief Database connection to use to execute the query - CqlConnection& conn_; + /// @brief Database connection + const CqlConnection &connection_; /// @brief The query's prepared statement tag StatementTag statement_; @@ -1536,19 +1516,20 @@ class CqlLeaseStatsQuery : public LeaseStatsQuery { /// @brief Indicates if query supplies lease type bool fetch_type_; - /// @brief map containing the aggregated lease counts std::map cummulative_rows_; /// @brief cursor pointing to the next row to read in aggregate map std::map::iterator next_row_; - /// @brief bind variable for retrieving subnet-id from a result set row - int subnet_id_; - /// @brief bind variable for retrieving lease-type from a result set row - int lease_type_; - /// @brief bind variable for retrieving lease-state from a result set row - int lease_state_; + /// @brief Subnet identifier + cass_int32_t subnet_id_; + + /// @brief Lease type (NA, TA or PD) + cass_int32_t lease_type_; + + /// @brief Lease state + cass_int32_t state_; }; constexpr StatementTag CqlLeaseStatsQuery::RECOUNT_LEASE4_STATS; @@ -1578,7 +1559,20 @@ CqlLeaseStatsQuery::start() { // This gets a collection of data for ALL leases, and // then rolls them up into cummulative_rows_ - executeSelect(conn_, data, statement_); + AnyArray collection = executeSelect(connection_, data, statement_); + + // Form LeaseStatsRowPtr objects. + LeaseStatsCollection stats_collection; + for (boost::any& stats : collection) { + LeaseStatsRowPtr data(boost::any_cast(stats)); + stats_collection.push_back(data); + auto cum_row = cummulative_rows_.find(*data); + if (cum_row != cummulative_rows_.end()) { + cummulative_rows_[*data] = cum_row->second + 1; + } else { + cummulative_rows_.insert(std::make_pair(*data, 1)); + } + } // Set our row iterator to the beginning next_row_ = cummulative_rows_.begin(); @@ -1605,118 +1599,29 @@ CqlLeaseStatsQuery::getNextRow(LeaseStatsRow& row) { } void -CqlLeaseStatsQuery::createBindForSelect(AnyArray& data, StatementTag) { - data.clear(); - data.add(&subnet_id_); - if (fetch_type_) { - data.add(&lease_type_); - } +CqlLeaseStatsQuery::createBindForSelect(AnyArray& data, StatementTag statement_tag) { - data.add(&lease_state_); -} + // Start with a fresh array. + data.clear(); -void -CqlLeaseStatsQuery::executeSelect(const CqlConnection& connection, const AnyArray& data, - StatementTag statement_tag) { - CassError rc; - CassStatement* statement = NULL; - CassFuture* future = NULL; - AnyArray local_data = data; - - // Find the query statement first. - StatementMap::const_iterator it = connection.statements_.find(statement_tag); - if (it == connection.statements_.end()) { - isc_throw(DbOperationError, - "CqlLeastStatsQuery::executeSelect(): Statement " - << statement_tag << "has not been prepared."); - } + // subnet_id: int + data.add(&subnet_id_); - // Bind the data before the query is executed. - CqlTaggedStatement tagged_statement = it->second; - if (tagged_statement.is_raw_) { - // The entire query is the first element in data. - std::string* query = boost::any_cast(local_data.back()); - local_data.pop_back(); - statement = cass_statement_new(query->c_str(), local_data.size()); + // lease_type: int + if (statement_tag == CqlLeaseStatsQuery::RECOUNT_LEASE6_STATS) { + data.add(&lease_type_); } else { - statement = cass_prepared_bind(tagged_statement.prepared_statement_); - if (!statement) { - isc_throw(DbOperationError, - "CqlLeaseStatsQuery::executeSelect(): unable to bind statement " - << tagged_statement.name_); - } - } - - // Set specific level of consistency if we're told to do so. - if (connection.force_consistency_) { - rc = cass_statement_set_consistency(statement, connection.consistency_); - if (rc != CASS_OK) { - cass_statement_free(statement); - isc_throw(DbOperationError, - "CqlLeaseStatsQuery::executeSelect(): unable to set statement " - "consistency for statement " - << tagged_statement.name_ - << ", Cassandra error code: " << cass_error_desc(rc)); - } - } - - CqlCommon::bindData(local_data, statement); - - // Everything's ready. Call the actual statement. - future = cass_session_execute(connection.session_, statement); - if (!future) { - cass_statement_free(statement); - isc_throw(DbOperationError, - "CqlLeaseStatsQuery::executeSelect(): no CassFuture for statement " - << tagged_statement.name_); + lease_type_ = Lease::TYPE_NA; // lease type is always NA for v4 } - // Wait for the statement execution to complete. - cass_future_wait(future); - const std::string error = connection.checkFutureError( - "CqlLeaseStatsQuery::executeSelect(): cass_session_execute() != CASS_OK", - future, statement_tag); - rc = cass_future_error_code(future); - if (rc != CASS_OK) { - cass_future_free(future); - cass_statement_free(statement); - isc_throw(DbOperationError, error); - } - - // Get column values. - const CassResult* result_collection = cass_future_get_result(future); - - // lease type is always NA for v4 - if (!fetch_type_) { - lease_type_ = Lease::TYPE_NA; - } - - // Since we're currently forced to pull data for all leases, we - // iterate over them, aggregating them into cummulative LeaseStatsRows - AnyArray return_values; - CassIterator* rows = cass_iterator_from_result(result_collection); - while (cass_iterator_next(rows)) { - const CassRow* row = cass_iterator_get_row(rows); - createBindForSelect(return_values, statement_tag); - CqlCommon::getData(row, return_values); - - LeaseStatsRow raw_row(subnet_id_, static_cast(lease_type_), - lease_state_, 1); - - auto cum_row = cummulative_rows_.find(raw_row); - if (cum_row != cummulative_rows_.end()) { - cummulative_rows_[raw_row] = cum_row->second + 1; - } else { - cummulative_rows_.insert(std::make_pair(raw_row, 1)); - } - } + // state: int + data.add(&state_); +} - // Free resources. - cass_iterator_free(rows); - cass_result_free(result_collection); - cass_future_free(future); - cass_statement_free(statement); - return; +boost::any +CqlLeaseStatsQuery::retrieve() { + return (LeaseStatsRowPtr(new LeaseStatsRow(subnet_id_, + static_cast(lease_type_), state_, 1))); } CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap ¶meters) diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h index 3c60e09a22..11321766b9 100644 --- a/src/lib/dhcpsrv/lease_mgr.h +++ b/src/lib/dhcpsrv/lease_mgr.h @@ -114,7 +114,7 @@ struct LeaseStatsRow { if (subnet_id_ == rhs.subnet_id_ && lease_type_ == rhs.lease_type_ && - lease_state_ < rhs.lease_state_) { + lease_state_ < rhs.lease_state_) { return (true); } @@ -166,6 +166,9 @@ typedef boost::shared_ptr LeaseStatsQueryPtr; /// @brief Defines a pointer to a LeaseStatsRow. typedef boost::shared_ptr LeaseStatsRowPtr; +/// @brief Collection of the @c LeaseStatsRow objects. +typedef std::vector LeaseStatsCollection; + /// @brief Abstract Lease Manager /// /// This is an abstract API for lease database backends. It provides unified diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index 4e559c75cc..db1f83e2fa 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -216,7 +216,7 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { } // This is the CQL implementation for - // GenericLeaseMgrTest::testGetExpiredLeases4(). + // GenericLeaseMgrTest::testGetExpiredLeases6(). // The GenericLeaseMgrTest implementation checks for the order of expired // leases to be from the most expired to the least expired. Cassandra // doesn't support ORDER BY without imposing a EQ / IN restriction on the @@ -278,8 +278,7 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { } // Retrieve expired leases again. The limit of 0 means return all - // expired - // leases. + // expired leases. ASSERT_NO_THROW(lmptr_->getExpiredLeases6(expired_leases, 0)); // The same leases should be returned. @@ -312,6 +311,8 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { // This the returned leases should exclude reclaimed ones. So the number // of returned leases should be roughly half of the expired leases. ASSERT_NO_THROW(lmptr_->getExpiredLeases6(expired_leases, 0)); + ASSERT_EQ(static_cast(saved_expired_leases.size() / 2u), + expired_leases.size()); // Make sure that returned leases are those that are not reclaimed, i.e. // those that have even index. @@ -366,7 +367,6 @@ TEST(CqlOpenTest, OpenDatabase) { << "*** before the CQL tests will run correctly.\n"; } - // Check that attempting to get an instance of the lease manager when // none is set throws an exception. EXPECT_THROW(LeaseMgrFactory::instance(), NoLeaseManager); @@ -735,14 +735,14 @@ TEST_F(CqlLeaseMgrTest, recountLeaseStats6) { testRecountLeaseStats6(); } -// Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. /// @todo: uncomment this once lease wipe is implemented /// for Cassandra (see #5485) TEST_F(CqlLeaseMgrTest, DISABLED_wipeLeases4) { testWipeLeases4(); } -// Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. /// @todo: uncomment this once lease wipe is implemented /// for Cassandra (see #5485) TEST_F(CqlLeaseMgrTest, DISABLED_wipeLeases6) { diff --git a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc index e9cdcbf942..8152fe5163 100644 --- a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc @@ -64,7 +64,6 @@ GenericLeaseMgrTest::GenericLeaseMgrTest() /// a template leasetype6_.push_back(LEASETYPE6[i]); } - } GenericLeaseMgrTest::~GenericLeaseMgrTest() { @@ -780,7 +779,6 @@ GenericLeaseMgrTest::testBasicLease4() { detailCompareLease(leases[3], l_returned); } - void GenericLeaseMgrTest::testBasicLease6() { // Get the leases to be used for the test. @@ -1082,8 +1080,6 @@ GenericLeaseMgrTest::testGetLease4HWAddrSubnetId() { EXPECT_THROW(returned = lmptr_->getLease4(*leases[1]->hwaddr_, leases[1]->subnet_id_), isc::dhcp::MultipleRecords); - - } void @@ -1175,7 +1171,7 @@ GenericLeaseMgrTest::testGetLease4ClientIdSize() { leases[1]->client_id_.reset(new ClientId(clientid_vec)); EXPECT_TRUE(lmptr_->addLease(leases[1])); Lease4Collection returned = lmptr_->getLease4(*leases[1]->client_id_); - ASSERT_TRUE(returned.size() == 1); + ASSERT_EQ(returned.size(), 1u); detailCompareLease(leases[1], *returned.begin()); (void) lmptr_->deleteLease(leases[1]->addr_); } @@ -1317,7 +1313,6 @@ GenericLeaseMgrTest::testGetLeases6DuidSize() { // Don't bother to check DUIDs longer than the maximum - these cannot be // constructed, and that limitation is tested in the DUID/Client ID unit // tests. - } void @@ -1843,6 +1838,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() { int index = static_cast(std::distance(expired_leases.rbegin(), lease)); // Multiple current index by two, because only leases with even indexes // should have been returned. + ASSERT_LE(2 * index, leases.size()); EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_); } @@ -1857,7 +1853,6 @@ GenericLeaseMgrTest::testGetExpiredLeases6() { // Update the time of expired leases with even indexes. if (i % 2 == 0) { leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - 1000 + i; - } else { // Make sure remaining leases remain unexpired. leases[i]->cltt_ = current_time + 100; @@ -1875,6 +1870,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() { for (Lease6Collection::iterator lease = expired_leases.begin(); lease != expired_leases.end(); ++lease) { int index = static_cast(std::distance(expired_leases.begin(), lease)); + ASSERT_LE(2 * index, leases.size()); EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_); } @@ -1894,6 +1890,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() { for (Lease6Collection::iterator lease = expired_leases.begin(); lease != expired_leases.end(); ++lease) { int index = static_cast(std::distance(expired_leases.begin(), lease)); + ASSERT_LE(2 * index, leases.size()); EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_); } @@ -1981,8 +1978,8 @@ GenericLeaseMgrTest::testDeleteExpiredReclaimedLeases4() { " deleted: " << leases[i]->toText(); } } - // Check that the number of leases deleted is correct. - EXPECT_EQ(deleted_num, should_delete_num); + // Check that the number of deleted leases is correct. + EXPECT_EQ(should_delete_num, deleted_num); // Make sure we can make another attempt, when there are no more leases // to be deleted. diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc index 609ddabe6e..843ead24d4 100644 --- a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc @@ -487,22 +487,22 @@ TEST_F(MySqlLeaseMgrTest, deleteExpiredReclaimedLeases4) { testDeleteExpiredReclaimedLeases4(); } -// Verifies that IPv4 lease statistics can be recalculated. +/// @brief Verifies that IPv4 lease statistics can be recalculated. TEST_F(MySqlLeaseMgrTest, recountLeaseStats4) { testRecountLeaseStats4(); } -// Verifies that IPv6 lease statistics can be recalculated. +/// @brief Verifies that IPv6 lease statistics can be recalculated. TEST_F(MySqlLeaseMgrTest, recountLeaseStats6) { testRecountLeaseStats6(); } -// Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. TEST_F(MySqlLeaseMgrTest, DISABLED_wipeLeases4) { testWipeLeases4(); } -// Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. TEST_F(MySqlLeaseMgrTest, DISABLED_wipeLeases6) { testWipeLeases6(); } diff --git a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc index fa84bbb99b..3e1ad2c6a8 100644 --- a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc @@ -412,22 +412,22 @@ TEST_F(PgSqlLeaseMgrTest, getExpiredLeases6) { testGetExpiredLeases6(); } -// Verifies that IPv4 lease statistics can be recalculated. +/// @brief Verifies that IPv4 lease statistics can be recalculated. TEST_F(PgSqlLeaseMgrTest, recountLeaseStats4) { testRecountLeaseStats4(); } -// Verifies that IPv6 lease statistics can be recalculated. +/// @brief Verifies that IPv6 lease statistics can be recalculated. TEST_F(PgSqlLeaseMgrTest, recountLeaseStats6) { testRecountLeaseStats6(); } -// Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. TEST_F(PgSqlLeaseMgrTest, DISABLED_wipeLeases4) { testWipeLeases4(); } -// Tests that leases from specific subnet can be removed. +/// @brief Tests that leases from specific subnet can be removed. TEST_F(PgSqlLeaseMgrTest, DISABLED_wipeLeases6) { testWipeLeases6(); } From d3f82819584e4a3935043866149cbe1212d16e24 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Mar 2018 15:46:05 +0200 Subject: [PATCH 16/34] minor changes --- src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index 423ef8ade7..cda6000f8f 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -315,7 +315,7 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { // This the returned leases should exclude reclaimed ones. So the number // of returned leases should be roughly half of the expired leases. - ASSERT_NO_THROW(lmptr_->getExpiredLeases6(expired_leases, 0)); + ASSERT_NO_THROW(lmptr_->getExpiredLeases6(expired_leases, 0u)); ASSERT_EQ(static_cast(saved_expired_leases.size() / 2u), expired_leases.size()); From b2d80eb043494d45796da26f919c5ef244eb9cc2 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 1 Mar 2018 15:47:28 +0200 Subject: [PATCH 17/34] minor changes --- src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index db1f83e2fa..b9216f5cb4 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -310,7 +310,7 @@ class CqlLeaseMgrTest : public GenericLeaseMgrTest { // This the returned leases should exclude reclaimed ones. So the number // of returned leases should be roughly half of the expired leases. - ASSERT_NO_THROW(lmptr_->getExpiredLeases6(expired_leases, 0)); + ASSERT_NO_THROW(lmptr_->getExpiredLeases6(expired_leases, 0u)); ASSERT_EQ(static_cast(saved_expired_leases.size() / 2u), expired_leases.size()); From c3e4fe2a02c3e1d058deb0adfa0bc444220e8230 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 7 Mar 2018 11:07:27 +0200 Subject: [PATCH 18/34] enabled tests for cql --- .../dhcpsrv/tests/cql_host_data_source_unittest.cc | 12 ++++++++++++ .../tests/generic_host_data_source_unittest.cc | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc index 65275506a0..2efa9228fc 100644 --- a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc @@ -291,6 +291,18 @@ TEST_F(CqlHostDataSourceTest, basic4HWAddr) { testBasic4(Host::IDENT_HWADDR); } +// Verifies that IPv4 host reservation with options can have a max value +// for dhcp4_subnet id +TEST_F(MySqlHostDataSourceTest, maxSubnetId4) { + testMaxSubnetId4(); +} + +// Verifies that IPv6 host reservation with options can have a max value +// for dhcp6_subnet id +TEST_F(MySqlHostDataSourceTest, maxSubnetId6) { + testMaxSubnetId6(); +} + // Test verifies if a host reservation can be added and later retrieved by IPv4 // address. Host uses client-id (DUID) as identifier. TEST_F(CqlHostDataSourceTest, basic4ClientId) { diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc index c84633895a..50d0deb911 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc @@ -288,7 +288,8 @@ GenericHostDataSourceTest::testMaxSubnetId4() { EXPECT_FALSE(host_by_id); } -void GenericHostDataSourceTest::testMaxSubnetId6() { +void +GenericHostDataSourceTest::testMaxSubnetId6() { std::vector ident; ident = HostDataSourceUtils::generateIdentifier(); From 8b1f21a45db0c6700726510a777ad39c214619b1 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 7 Mar 2018 11:35:07 +0200 Subject: [PATCH 19/34] src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc --- src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc index c84633895a..50d0deb911 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc @@ -288,7 +288,8 @@ GenericHostDataSourceTest::testMaxSubnetId4() { EXPECT_FALSE(host_by_id); } -void GenericHostDataSourceTest::testMaxSubnetId6() { +void +GenericHostDataSourceTest::testMaxSubnetId6() { std::vector ident; ident = HostDataSourceUtils::generateIdentifier(); From 55a57d49dd3c60813b1f3c521180ab5c7b57c6a4 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 7 Mar 2018 15:45:27 +0200 Subject: [PATCH 20/34] enabled tests for cql --- .../dhcpsrv/tests/cql_host_data_source_unittest.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc index a3462a5421..7aa627f545 100644 --- a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc @@ -221,6 +221,18 @@ TEST_F(CqlHostDataSourceTest, basic4HWAddr) { testBasic4(Host::IDENT_HWADDR); } +// Verifies that IPv4 host reservation with options can have a max value +// for dhcp4_subnet id +TEST_F(MySqlHostDataSourceTest, maxSubnetId4) { + testMaxSubnetId4(); +} + +// Verifies that IPv6 host reservation with options can have a max value +// for dhcp6_subnet id +TEST_F(MySqlHostDataSourceTest, maxSubnetId6) { + testMaxSubnetId6(); +} + // Test verifies if a host reservation can be added and later retrieved by IPv4 // address. Host uses client-id (DUID) as identifier. TEST_F(CqlHostDataSourceTest, basic4ClientId) { From 38b5430af056e6c1d6a256caafb7d7cba142deb6 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 7 Mar 2018 16:42:37 +0200 Subject: [PATCH 21/34] fixed unit tests --- src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc index 7aa627f545..365ac93663 100644 --- a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc @@ -223,13 +223,13 @@ TEST_F(CqlHostDataSourceTest, basic4HWAddr) { // Verifies that IPv4 host reservation with options can have a max value // for dhcp4_subnet id -TEST_F(MySqlHostDataSourceTest, maxSubnetId4) { +TEST_F(CqlHostDataSourceTest, maxSubnetId4) { testMaxSubnetId4(); } // Verifies that IPv6 host reservation with options can have a max value // for dhcp6_subnet id -TEST_F(MySqlHostDataSourceTest, maxSubnetId6) { +TEST_F(CqlHostDataSourceTest, maxSubnetId6) { testMaxSubnetId6(); } From 42d8ad3ad92541c54e513ba8c3b9a481f134278b Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Tue, 13 Mar 2018 12:23:27 +0200 Subject: [PATCH 22/34] minor changes --- src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc index f348e0f1c5..821b8b012d 100644 --- a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc @@ -294,13 +294,13 @@ TEST_F(CqlHostDataSourceTest, basic4HWAddr) { // Verifies that IPv4 host reservation with options can have a max value // for dhcp4_subnet id -TEST_F(MySqlHostDataSourceTest, maxSubnetId4) { +TEST_F(CqlHostDataSourceTest, maxSubnetId4) { testMaxSubnetId4(); } // Verifies that IPv6 host reservation with options can have a max value // for dhcp6_subnet id -TEST_F(MySqlHostDataSourceTest, maxSubnetId6) { +TEST_F(CqlHostDataSourceTest, maxSubnetId6) { testMaxSubnetId6(); } From 39bc0b765534f4a6ed2997134366d38a0e345671 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Tue, 13 Mar 2018 13:48:40 +0200 Subject: [PATCH 23/34] fixed merge --- src/bin/dhcp6/dhcp6_parser.yy | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index 464f31f609..6f611010a4 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -75,7 +75,6 @@ using namespace std; TCP_KEEPALIVE "tcp-keepalive" CONTACT_POINTS "contact-points" MAX_RECONNECT_TRIES "max-reconnect-tries" - RECONNECT_WAIT_TIME "reconnect-wait-time" KEYSPACE "keyspace" PREFERRED_LIFETIME "preferred-lifetime" @@ -670,11 +669,6 @@ max_reconnect_tries: MAX_RECONNECT_TRIES COLON INTEGER { ctx.stack_.back()->set("max-reconnect-tries", n); }; -reconnect_wait_time: RECONNECT_WAIT_TIME COLON INTEGER { - ElementPtr n(new IntElement($3, ctx.loc2pos(@3))); - ctx.stack_.back()->set("reconnect-wait-time", n); -}; - keyspace: KEYSPACE { ctx.enter(ctx.NO_KEYWORD); } COLON STRING { From b65cd1f0a8c8c908e8d57a84024327f8f35b4644 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Tue, 13 Mar 2018 14:53:32 +0200 Subject: [PATCH 24/34] fixed merge --- src/bin/dhcp4/dhcp4_lexer.ll | 10 ---------- src/bin/dhcp6/dhcp6_lexer.ll | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/src/bin/dhcp4/dhcp4_lexer.ll b/src/bin/dhcp4/dhcp4_lexer.ll index 81d79f700c..1c4db05812 100644 --- a/src/bin/dhcp4/dhcp4_lexer.ll +++ b/src/bin/dhcp4/dhcp4_lexer.ll @@ -490,16 +490,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } -\"reconnect-wait-time\" { - switch(driver.ctx_) { - case isc::dhcp::Parser4Context::LEASE_DATABASE: - case isc::dhcp::Parser4Context::HOSTS_DATABASE: - return isc::dhcp::Dhcp4Parser::make_RECONNECT_WAIT_TIME(driver.loc_); - default: - return isc::dhcp::Dhcp4Parser::make_STRING("reconnect-wait-time", driver.loc_); - } -} - \"valid-lifetime\" { switch(driver.ctx_) { case isc::dhcp::Parser4Context::DHCP4: diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index 1f70795899..1654fdd083 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -655,16 +655,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } -\"reconnect-wait-time\" { - switch(driver.ctx_) { - case isc::dhcp::Parser6Context::LEASE_DATABASE: - case isc::dhcp::Parser6Context::HOSTS_DATABASE: - return isc::dhcp::Dhcp6Parser::make_RECONNECT_WAIT_TIME(driver.loc_); - default: - return isc::dhcp::Dhcp6Parser::make_STRING("reconnect-wait-time", driver.loc_); - } -} - \"preferred-lifetime\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::DHCP6: From a1ab75150630fdbc981623ff45e85f4257f3dfee Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Tue, 13 Mar 2018 14:58:33 +0200 Subject: [PATCH 25/34] fixed comments --- src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc | 4 ++-- src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc | 4 ++-- src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index b538dc27ad..75e879aa12 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -716,12 +716,12 @@ TEST_F(CqlLeaseMgrTest, nullDuid) { testNullDuid(); } -/// @brief Tests whether memfile can store and retrieve hardware addresses +/// @brief Tests whether CQL can store and retrieve hardware addresses TEST_F(CqlLeaseMgrTest, testLease6Mac) { testLease6MAC(); } -/// @brief Tests whether memfile can store and retrieve hardware addresses +/// @brief Tests whether CQL can store and retrieve hardware addresses TEST_F(CqlLeaseMgrTest, testLease6HWTypeAndSource) { testLease6HWTypeAndSource(); } diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc index 4bccd73ec4..6ce2c5b972 100644 --- a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc @@ -480,12 +480,12 @@ TEST_F(MySqlLeaseMgrTest, nullDuid) { testNullDuid(); } -/// @brief Tests whether memfile can store and retrieve hardware addresses +/// @brief Tests whether MySQL can store and retrieve hardware addresses TEST_F(MySqlLeaseMgrTest, testLease6Mac) { testLease6MAC(); } -/// @brief Tests whether memfile can store and retrieve hardware addresses +/// @brief Tests whether MySQL can store and retrieve hardware addresses TEST_F(MySqlLeaseMgrTest, testLease6HWTypeAndSource) { testLease6HWTypeAndSource(); } diff --git a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc index a2cdac7c3b..a8116c0c73 100644 --- a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc @@ -473,12 +473,12 @@ TEST_F(PgSqlLeaseMgrTest, nullDuid) { testNullDuid(); } -/// @brief Tests whether Postgres can store and retrieve hardware addresses +/// @brief Tests whether PostgreSQL can store and retrieve hardware addresses TEST_F(PgSqlLeaseMgrTest, testLease6Mac) { testLease6MAC(); } -/// @brief Tests whether Postgres can store and retrieve hardware addresses +/// @brief Tests whether PostgreSQL can store and retrieve hardware addresses TEST_F(PgSqlLeaseMgrTest, testLease6HWTypeAndSource) { testLease6HWTypeAndSource(); } From 387ffa495327dc8e3e2f7db43119c1f4990e40d5 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Tue, 13 Mar 2018 15:11:46 +0200 Subject: [PATCH 26/34] minor changes --- configure.ac | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index b6e8cc8529..51f0b2a78c 100644 --- a/configure.ac +++ b/configure.ac @@ -62,15 +62,15 @@ AC_SUBST(SEP) # If cross compiling assume the message compiler executable was # magically already in place... if test "$cross_compiling" = "yes"; then - AC_MSG_CHECKING("build (vs. host) compiled message compiler") - if test -x "${srcdir}/src/lib/log/compiler/message"; then - AC_MSG_RESULT(yes) - else - AC_MSG_RESULT(no) - AC_MSG_WARN("you must install a message compiler in:") - AC_MSG_WARN(" ${srcdir}/src/lib/log/compiler/message") - AC_MSG_WARN("compiled for build ($build).") - fi + AC_MSG_CHECKING("build (vs. host) compiled message compiler") + if test -x "${srcdir}/src/lib/log/compiler/message"; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + AC_MSG_WARN("you must install a message compiler in:") + AC_MSG_WARN(" ${srcdir}/src/lib/log/compiler/message") + AC_MSG_WARN("compiled for build ($build).") + fi fi AM_CONDITIONAL([CROSS_COMPILING], [test "$cross_compiling" = "yes"]) From 746acc82bdc157f15432fded5ce978fe9d7af77e Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Tue, 13 Mar 2018 15:15:41 +0200 Subject: [PATCH 27/34] minor changes --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index cfdcb815a2..76bfd78fee 100644 --- a/AUTHORS +++ b/AUTHORS @@ -5,7 +5,7 @@ Primary developers: - Tomek Mrugalski (lead developer: DHCPv4, DHCPv6 components, prefix delegation, memfile, database interface, core libdhcp++, - host reservation, MAC extraction in DHCPv6, statistics manager, + host reservation, MAC extraction in DHCPv6, statistics manager, kea-shell) - Stephen Morris (Hooks, MySQL) - Marcin Siodelski (DHCPv4, DHCPv6 components, options handling, perfdhcp, From 38a837f3b4373d75b4ec2bf0baff17b09fc4a8fa Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 14 Mar 2018 11:08:17 +0200 Subject: [PATCH 28/34] minor changes --- Makefile.am | 4 ++-- src/bin/dhcp6/dhcp6_lexer.ll | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2c0733c29c..c23fe48402 100644 --- a/Makefile.am +++ b/Makefile.am @@ -110,8 +110,8 @@ endif --output report.info; \ sed --in-place --expression "s|$(abs_top_srcdir)|$(abs_top_builddir)|g" report.info; \ "$(GENHTML)" --frames --show-details --title 'Kea code coverage report' --legend \ - --function-coverage --ignore-errors source --demangle-cpp \ - --output "$(OVERALL_COVERAGE_DIR)" report.info; \ + --function-coverage --ignore-errors source --demangle-cpp \ + --output "$(OVERALL_COVERAGE_DIR)" report.info; \ printf "Generated C++ code coverage report in HTML at %s.\n" "$(OVERALL_COVERAGE_DIR)"; \ else \ echo "C++ code coverage not enabled at configuration time." ; \ diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index 1654fdd083..c9e9da856d 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -1096,7 +1096,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } - \"debuglevel\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::LOGGERS: @@ -1514,7 +1513,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } - {JSONString} { /* A string has been matched. It contains the actual string and single quotes. We need to get those quotes out of the way and just use its content, e.g. From 9ed1f3d36c4e6bbb61200454db71e81d71057356 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 14 Mar 2018 11:26:40 +0200 Subject: [PATCH 29/34] minor changes --- doc/guide/intro.xml | 8 ++++---- doc/guide/lfc.xml | 2 +- src/share/database/scripts/mysql/.gitignore | 16 ++++++++-------- .../database/scripts/mysql/dhcpdb_create.mysql | 1 - 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/doc/guide/intro.xml b/doc/guide/intro.xml index b857c72845..b189bf9bb7 100644 --- a/doc/guide/intro.xml +++ b/doc/guide/intro.xml @@ -79,7 +79,7 @@ - In order to store lease information in a MySQL database, Kea requires MySQL + In order to store lease information in a MySQL database, Kea requires MySQL headers and libraries. This is an optional dependency in that Kea can be built without MySQL support. @@ -87,7 +87,7 @@ - In order to store lease information in a PostgreSQL database, Kea requires PostgreSQL + In order to store lease information in a PostgreSQL database, Kea requires PostgreSQL headers and libraries. This is an optional dependency in that Kea can be built without PostgreSQL support. @@ -95,7 +95,7 @@ - In order to store lease information in a Cassandra database (CQL), Kea + In order to store lease information in a Cassandra database (CQL), Kea requires Cassandra headers and libraries. This is an optional dependency in that Kea can be built without Cassandra support. @@ -163,7 +163,7 @@ kea-lfc — This process removes redundant information from the files used to provide persistent storage for the memfile data base backend. - While it can be run standalone, it is normally run as and when + While it can be run standalone, it is normally run as and when required by the Kea DHCP servers. diff --git a/doc/guide/lfc.xml b/doc/guide/lfc.xml index e689bde5aa..b90fe696bc 100644 --- a/doc/guide/lfc.xml +++ b/doc/guide/lfc.xml @@ -15,7 +15,7 @@ kea-lfc is a service process that removes redundant information from the files used to provide persistent storage for the memfile data base backend. This service is written to run as a - stand alone process. + stand alone process. While kea-lfc can be started externally, there is usually no need to do this. kea-lfc is run on a periodic diff --git a/src/share/database/scripts/mysql/.gitignore b/src/share/database/scripts/mysql/.gitignore index 8f9f1ce2bc..0884fd0277 100644 --- a/src/share/database/scripts/mysql/.gitignore +++ b/src/share/database/scripts/mysql/.gitignore @@ -1,8 +1,8 @@ -/upgrade_1.0_to_2.0.sh -/upgrade_2.0_to_3.0.sh -/upgrade_3.0_to_4.0.sh -/upgrade_4.0_to_4.1.sh -/upgrade_4.1_to_5.0.sh -/upgrade_5.0_to_5.1.sh -/upgrade_5.1_to_5.2.sh -/upgrade_5.2_to_6.0.sh +upgrade_1.0_to_2.0.sh +upgrade_2.0_to_3.0.sh +upgrade_3.0_to_4.0.sh +upgrade_4.0_to_4.1.sh +upgrade_4.1_to_5.0.sh +upgrade_5.0_to_5.1.sh +upgrade_5.1_to_5.2.sh +upgrade_5.2_to_6.0.sh diff --git a/src/share/database/scripts/mysql/dhcpdb_create.mysql b/src/share/database/scripts/mysql/dhcpdb_create.mysql index 47f02d308e..436be28ca4 100644 --- a/src/share/database/scripts/mysql/dhcpdb_create.mysql +++ b/src/share/database/scripts/mysql/dhcpdb_create.mysql @@ -43,7 +43,6 @@ CREATE TABLE lease4 ( hostname VARCHAR(255) # The FQDN of the client ) ENGINE = INNODB; - # Create search indexes for lease4 table # index by hwaddr and subnet_id CREATE INDEX lease4_by_hwaddr_subnet_id ON lease4 (hwaddr, subnet_id); From d61a05b0a3ba4c7c6cd8bff612d3684cba8e8e78 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 14 Mar 2018 14:47:01 +0200 Subject: [PATCH 30/34] minor changes --- src/bin/admin/tests/dhcpdb_create_1.0.cql | 4 ++++ src/bin/perfdhcp/test_control.cc | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bin/admin/tests/dhcpdb_create_1.0.cql b/src/bin/admin/tests/dhcpdb_create_1.0.cql index b6cf064ffd..9c5c8dac7c 100644 --- a/src/bin/admin/tests/dhcpdb_create_1.0.cql +++ b/src/bin/admin/tests/dhcpdb_create_1.0.cql @@ -133,6 +133,8 @@ CREATE TABLE IF NOT EXISTS lease_hwaddr_source ( PRIMARY KEY ((hwaddr_source)) ); +INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (0, 'HWADDR_SOURCE_UNKNOWN'); + -- Hardware address obtained from raw sockets INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (1, 'HWADDR_SOURCE_RAW'); @@ -154,6 +156,8 @@ INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (32, 'HWADDR_SOURCE -- Hardware address extracted from docsis options INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (64, 'HWADDR_SOURCE_DOCSIS_CMTS'); +INSERT INTO lease_hwaddr_source (hwaddr_source, name) VALUES (128, 'HWADDR_SOURCE_DOCSIS_MODEM'); + -- Create table holding mapping of the lease states to their names. -- This is not used in queries from the DHCP server but rather in -- direct queries from the lease database management tools. diff --git a/src/bin/perfdhcp/test_control.cc b/src/bin/perfdhcp/test_control.cc index 011894b6f9..9038e3ac43 100644 --- a/src/bin/perfdhcp/test_control.cc +++ b/src/bin/perfdhcp/test_control.cc @@ -61,7 +61,6 @@ TestControl::waitToExit() const { // Init the end time if it hasn't started yet if (exit_time.is_not_a_date_time()) { - CommandOptions& options = CommandOptions::instance(); exit_time = now + time_duration(microseconds(wait_time)); } From cc59e9a48094ba3a2f6b07e1a6b7def5f1820939 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 14 Mar 2018 16:45:35 +0200 Subject: [PATCH 31/34] minor changes --- src/lib/dhcpsrv/mysql_host_data_source.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc index 1c72afd741..dfd210a9c2 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.cc +++ b/src/lib/dhcpsrv/mysql_host_data_source.cc @@ -2218,7 +2218,6 @@ TaggedStatementArray tagged_statements = { { "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, " "o.option_id, o.code, o.value, o.formatted_value, o.space, " "o.persistent, o.user_context, " @@ -2269,11 +2268,11 @@ TaggedStatementArray tagged_statements = { { "DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND ipv4_address = ?"}, {MySqlHostDataSourceImpl::DEL_HOST_SUBID4_ID, - "DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND dhcp_identifier_type=? " + "DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND dhcp_identifier_type = ? " "AND dhcp_identifier = ?"}, {MySqlHostDataSourceImpl::DEL_HOST_SUBID6_ID, - "DELETE FROM hosts WHERE dhcp6_subnet_id = ? AND dhcp_identifier_type=? " + "DELETE FROM hosts WHERE dhcp6_subnet_id = ? AND dhcp_identifier_type = ? " "AND dhcp_identifier = ?"} } From 365e64f333acaa445a65abad136f65bfca637a0a Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 14 Mar 2018 17:14:59 +0200 Subject: [PATCH 32/34] minor changes --- src/bin/dhcp4/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am index cc19d70882..26e3d6f93b 100644 --- a/src/bin/dhcp4/Makefile.am +++ b/src/bin/dhcp4/Makefile.am @@ -31,7 +31,7 @@ EXTRA_DIST += dhcp4_parser.yy if GENERATE_DOCS kea-dhcp4.8: kea-dhcp4.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ \ - http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \ + http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \ $(srcdir)/kea-dhcp4.xml else From 8670f46dc5538793447ed9128b94c25cd76c4d21 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 24 May 2018 17:02:31 +0300 Subject: [PATCH 33/34] minor changes --- src/bin/dhcp6/dhcp6_srv.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 30066b1b0e..56efd71cc3 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -1415,6 +1415,7 @@ Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer, if (answer_opt) { answer->addOption(answer_opt); } + break; } default: break; From 3d23cef9d359526abe17e19de6b8d6650dab04a3 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 14 Jun 2018 15:37:46 +0300 Subject: [PATCH 34/34] minor changes --- src/bin/dhcp4/dhcp4_srv.cc | 2 +- src/lib/dhcp/dhcp4.h | 2 +- src/lib/dhcp/option_definition.cc | 74 +++++++++++++++---------------- src/lib/dhcp/std_option_defs.h | 9 ++-- src/lib/dhcpsrv/cql_exchange.cc | 8 ---- 5 files changed, 45 insertions(+), 50 deletions(-) diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 390e4193da..05a3252a8a 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -169,7 +169,7 @@ Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine, .arg(query_->getLabel()) .arg(classes.toText()); } -}; +} void Dhcpv4Exchange::initResponse() { diff --git a/src/lib/dhcp/dhcp4.h b/src/lib/dhcp/dhcp4.h index b72af11bac..af62ef93ed 100644 --- a/src/lib/dhcp/dhcp4.h +++ b/src/lib/dhcp/dhcp4.h @@ -210,7 +210,7 @@ enum DHCPOptionType { DHO_V4_CAPTIVE_PORTAL = 160, // 161-209 are removed/unassigned // DHO_PATH_PREFIX = 210, -// DHO_REBOOT_TIME = 211, +// DHO_REBOOT_TIME = 211, DHO_6RD = 212, DHO_V4_ACCESS_DOMAIN = 213, // 214-219 are removed/unassigned diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc index 4f77621a33..9bb6d9c7a0 100644 --- a/src/lib/dhcp/option_definition.cc +++ b/src/lib/dhcp/option_definition.cc @@ -662,46 +662,46 @@ OptionDefinition::writeToBuffer(Option::Universe u, OptionDataTypeUtil::writePrefix(PrefixLen(len), address, buf); return; - } + } case OPT_PSID_TYPE: - { - std::string txt = value; + { + std::string txt = value; - // first let's remove any whitespaces - boost::erase_all(txt, " "); // space - boost::erase_all(txt, "\t"); // tabulation + // first let's remove any whitespaces + boost::erase_all(txt, " "); // space + boost::erase_all(txt, "\t"); // tabulation - // Is this prefix/len notation? - size_t pos = txt.find("/"); + // Is this prefix/len notation? + size_t pos = txt.find("/"); - if (pos == string::npos) { - isc_throw(BadDataTypeCast, "provided PSID value " - << value << " is not valid"); - } + if (pos == string::npos) { + isc_throw(BadDataTypeCast, "provided PSID value " + << value << " is not valid"); + } - const std::string txt_psid = txt.substr(0, pos); - const std::string txt_psid_len = txt.substr(pos + 1); + const std::string txt_psid = txt.substr(0, pos); + const std::string txt_psid_len = txt.substr(pos + 1); - uint16_t psid = 0; - uint8_t psid_len = 0; + uint16_t psid = 0; + uint8_t psid_len = 0; - try { - psid = lexicalCastWithRangeCheck(txt_psid); - } catch (...) { - isc_throw(BadDataTypeCast, "provided PSID " - << txt_psid << " is not valid"); - } + try { + psid = lexicalCastWithRangeCheck(txt_psid); + } catch (...) { + isc_throw(BadDataTypeCast, "provided PSID " + << txt_psid << " is not valid"); + } - try { - psid_len = lexicalCastWithRangeCheck(txt_psid_len); - } catch (...) { - isc_throw(BadDataTypeCast, "provided PSID length " - << txt_psid_len << " is not valid"); - } + try { + psid_len = lexicalCastWithRangeCheck(txt_psid_len); + } catch (...) { + isc_throw(BadDataTypeCast, "provided PSID length " + << txt_psid_len << " is not valid"); + } - OptionDataTypeUtil::writePsid(PSIDLen(psid_len), PSID(psid), buf); - return; - } + OptionDataTypeUtil::writePsid(PSIDLen(psid_len), PSID(psid), buf); + return; + } case OPT_STRING_TYPE: OptionDataTypeUtil::writeString(value, buf); return; @@ -709,12 +709,12 @@ OptionDefinition::writeToBuffer(Option::Universe u, OptionDataTypeUtil::writeFqdn(value, buf); return; case OPT_TUPLE_TYPE: - { - OpaqueDataTuple::LengthFieldType lft = u == Option::V4 ? - OpaqueDataTuple::LENGTH_1_BYTE : OpaqueDataTuple::LENGTH_2_BYTES; - OptionDataTypeUtil::writeTuple(value, lft, buf); - return; - } + { + OpaqueDataTuple::LengthFieldType lft = u == Option::V4 ? + OpaqueDataTuple::LENGTH_1_BYTE : OpaqueDataTuple::LENGTH_2_BYTES; + OptionDataTypeUtil::writeTuple(value, lft, buf); + return; + } default: // We hit this point because invalid option data type has been specified // This may be the case because 'empty' or 'record' data type has been diff --git a/src/lib/dhcp/std_option_defs.h b/src/lib/dhcp/std_option_defs.h index 4e9d82923b..5800496edb 100644 --- a/src/lib/dhcp/std_option_defs.h +++ b/src/lib/dhcp/std_option_defs.h @@ -268,7 +268,8 @@ const OptionDefParams STANDARD_V4_OPTION_DEFINITIONS[] = { /// Number of option definitions defined. const int STANDARD_V4_OPTION_DEFINITIONS_SIZE = - sizeof(STANDARD_V4_OPTION_DEFINITIONS) / sizeof(STANDARD_V4_OPTION_DEFINITIONS[0]); + sizeof(STANDARD_V4_OPTION_DEFINITIONS) / + sizeof(STANDARD_V4_OPTION_DEFINITIONS[0]); /// Last resort definitions (only option 43 for now, these definitions /// are applied in deferred unpacking when none is found). @@ -277,7 +278,9 @@ const OptionDefParams LAST_RESORT_V4_OPTION_DEFINITIONS[] = { OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "vendor-encapsulated-options-space" } }; -const int LAST_RESORT_V4_OPTION_DEFINITIONS_SIZE = 1; +const int LAST_RESORT_V4_OPTION_DEFINITIONS_SIZE = + sizeof(LAST_RESORT_V4_OPTION_DEFINITIONS) / + sizeof(LAST_RESORT_V4_OPTION_DEFINITIONS[0]); /// Start Definition of DHCPv6 options @@ -421,7 +424,7 @@ const OptionDefParams STANDARD_V6_OPTION_DEFINITIONS[] = { { "v6-access-domain", D6O_V6_ACCESS_DOMAIN, OPT_FQDN_TYPE, false, NO_RECORD_DEF, "" }, { "sip-ua-cs-list", D6O_SIP_UA_CS_LIST, OPT_FQDN_TYPE, true, - NO_RECORD_DEF, "" }, + NO_RECORD_DEF, "" }, { "bootfile-url", D6O_BOOTFILE_URL, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" }, { "bootfile-param", D6O_BOOTFILE_PARAM, OPT_TUPLE_TYPE, true, NO_RECORD_DEF, "" }, { "client-arch-type", D6O_CLIENT_ARCH_TYPE, OPT_UINT16_TYPE, true, NO_RECORD_DEF, "" }, diff --git a/src/lib/dhcpsrv/cql_exchange.cc b/src/lib/dhcpsrv/cql_exchange.cc index c22feb9529..40ad9f9b23 100644 --- a/src/lib/dhcpsrv/cql_exchange.cc +++ b/src/lib/dhcpsrv/cql_exchange.cc @@ -39,14 +39,6 @@ namespace isc { namespace dhcp { -/// @brief Macro to return directly from caller function -#define KEA_CASS_CHECK(cass_error) \ - { \ - if (cass_error != CASS_OK) { \ - return cass_error; \ - } \ - } - /// @brief a helper structure with a function call operator that returns /// key value in a format expected by std::hash. struct ExchangeDataTypeHash {