diff --git a/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc index 31d8cd28e5..92792d26a6 100644 --- a/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc @@ -42,16 +42,42 @@ public: virtual ~PerfMonLibLoadTest() { unloadLibraries(); } + + /// @brief Creates a valid set configuration parameters valid for the library. + virtual isc::data::ElementPtr validConfigParams() { + std::string valid_config = + R"({ + "enable-monitoring" : true, + "interval-width-secs" : 5, + "stats-mgr-reporting" : true, + "alarm-report-secs" : 600, + "alarms": [{ + "duration-key": { + "query-type" : "*", + "response-type" : "*", + "start-event" : "socket-received", + "stop-event" : "buffer-read", + "subnet-id" : 70 + }, + "enable-alarm" : true, + "high-water-ms" : 500, + "low-water-ms" : 25 + }] + })"; + + // Convert JSON texts to Element map. + return (Element::fromJSON(valid_config)); + } }; // Simple V4 test that checks the library can be loaded and unloaded several times. TEST_F(PerfMonLibLoadTest, validLoad4) { - validDaemonTest("kea-dhcp4"); + validDaemonTest("kea-dhcp4", AF_INET, valid_params_); } // Simple V6 test that checks the library can be loaded and unloaded several times. TEST_F(PerfMonLibLoadTest, validLoad6) { - validDaemonTest("kea-dhcp6", AF_INET6); + validDaemonTest("kea-dhcp6", AF_INET6, valid_params_); } // Simple test that checks the library cannot by loaded by invalid daemons. diff --git a/src/hooks/dhcp/perfmon/monitored_duration.cc b/src/hooks/dhcp/perfmon/monitored_duration.cc index 2305310309..d010db106d 100644 --- a/src/hooks/dhcp/perfmon/monitored_duration.cc +++ b/src/hooks/dhcp/perfmon/monitored_duration.cc @@ -157,17 +157,21 @@ DurationKey::validateMessagePair(uint16_t family, uint8_t query_type, uint8_t re } std::string -DurationKey::getLabel() const { - std::ostringstream oss; - if (family_ == AF_INET) { - oss << (query_type_ == DHCP_NOTYPE ? "NONE" : Pkt4::getName(query_type_)) << "-" - << (response_type_ == DHCP_NOTYPE ? "NONE" : Pkt4::getName(response_type_)); - } else { - oss << (query_type_ == DHCPV6_NOTYPE ? "NONE" : Pkt6::getName(query_type_)) << "-" - << (response_type_ == DHCPV6_NOTYPE ? "NONE" : Pkt6::getName(response_type_)); +DurationKey::getMessageTypeLabel(uint16_t family, uint16_t msg_type) { + if (family == AF_INET) { + return (msg_type == DHCP_NOTYPE ? "*" : Pkt4::getName(msg_type)); } - oss << "." << start_event_label_ << "-" << stop_event_label_ + return (msg_type == DHCPV6_NOTYPE ? "*" : Pkt6::getName(msg_type)); +} + +std::string +DurationKey::getLabel() const { + std::ostringstream oss; + oss << getMessageTypeLabel(family_, query_type_) + << "-" + << getMessageTypeLabel(family_, response_type_) + << "." << start_event_label_ << "-" << stop_event_label_ << "." << subnet_id_; return (oss.str()); diff --git a/src/hooks/dhcp/perfmon/monitored_duration.h b/src/hooks/dhcp/perfmon/monitored_duration.h index 59cc304683..1ab40bef63 100644 --- a/src/hooks/dhcp/perfmon/monitored_duration.h +++ b/src/hooks/dhcp/perfmon/monitored_duration.h @@ -188,6 +188,15 @@ public: return (subnet_id_); } + /// @brief Get a label for a family-specific message type (e.g. + /// "DHCPDISCOVER", "SOLICIT") + /// + /// @param family Protocol family of the key (AF_INET or AF_INET6) + /// @param msg_type numeric message type to translate + /// + /// @return Text label, for values of DHCP_NOTYPE or DHCPV6_NOTYPE: "*" + static std::string getMessageTypeLabel(uint16_t family, uint16_t msg_type); + /// @brief Get a composite label of the member values with text message types. /// /// The format of the string: @@ -201,7 +210,7 @@ public: /// /// or /// - /// "DHCPV6_SOLICIT-DHCPV6_ADVERTISE.socket_received.buffer_read.12" + /// "SOLICIT-ADVERTISE.socket_received.buffer_read.12" /// /// @endcode /// diff --git a/src/hooks/dhcp/perfmon/perfmon_callouts.cc b/src/hooks/dhcp/perfmon/perfmon_callouts.cc index 959fd3de2a..49c2452d4e 100644 --- a/src/hooks/dhcp/perfmon/perfmon_callouts.cc +++ b/src/hooks/dhcp/perfmon/perfmon_callouts.cc @@ -11,11 +11,22 @@ #include #include +#include #include #include #include #include +namespace isc { +namespace perfmon { + +/// @brief PerfMonMgr singleton +PerfMonMgrPtr mgr; + +} // end of namespace perfmon +} + +using namespace isc::data; using namespace isc::dhcp; using namespace isc::hooks; using namespace isc::log; @@ -88,24 +99,34 @@ int pkt6_send(CalloutHandle& handle) { /// /// @param handle library handle /// @return 0 when initialization is successful, 1 otherwise -int load(LibraryHandle& /* handle */) { - // Make the hook library not loadable by d2 or ca. - uint16_t family = CfgMgr::instance().getFamily(); - const std::string& proc_name = Daemon::getProcName(); - if (family == AF_INET) { - if (proc_name != "kea-dhcp4") { - isc_throw(isc::Unexpected, "Bad process name: " << proc_name - << ", expected kea-dhcp4"); - } - } else { - if (proc_name != "kea-dhcp6") { +int load(LibraryHandle& handle) { + try { + // Make the hook library only loadable for kea-dhcpX. + uint16_t family = CfgMgr::instance().getFamily(); + const std::string& proc_name = Daemon::getProcName(); + if (family == AF_INET) { + if (proc_name != "kea-dhcp4") { + isc_throw(isc::Unexpected, "Bad process name: " << proc_name + << ", expected kea-dhcp4"); + } + } else if (proc_name != "kea-dhcp6") { isc_throw(isc::Unexpected, "Bad process name: " << proc_name << ", expected kea-dhcp6"); } - } - /// @todo register commands - /// handle.registerCommandCallout("command-here", handler_here); + // Instantiate the manager singleton. + mgr.reset(new PerfMonMgr(family)); + + // Configure the manager using the hook library's parameters. + ConstElementPtr json = handle.getParameters(); + mgr->configure(json); + + /// @todo register commands + /// handle.registerCommandCallout("command-here", handler_here); + } catch (const std::exception& ex) { + LOG_ERROR(perfmon_logger, PERFMON_INIT_FAILED).arg(ex.what()); + return (1); + } LOG_INFO(perfmon_logger, PERFMON_INIT_OK); return (0); diff --git a/src/hooks/dhcp/perfmon/perfmon_config.cc b/src/hooks/dhcp/perfmon/perfmon_config.cc index 93778abc59..04b9755979 100644 --- a/src/hooks/dhcp/perfmon/perfmon_config.cc +++ b/src/hooks/dhcp/perfmon/perfmon_config.cc @@ -33,6 +33,7 @@ uint16_t DurationKeyParser::getMessageNameType4(const std::string& name) { static std::map name_type_map = { {"", DHCP_NOTYPE}, + {"*", DHCP_NOTYPE}, {"DHCPDISCOVER", DHCPDISCOVER}, {"DHCPOFFER", DHCPOFFER}, {"DHCPREQUEST", DHCPREQUEST}, @@ -63,6 +64,7 @@ uint16_t DurationKeyParser::getMessageNameType6(const std::string& name) { static std::map name_type_map = { {"", DHCPV6_NOTYPE}, + {"*", DHCPV6_NOTYPE}, {"SOLICIT", DHCPV6_SOLICIT}, {"ADVERTISE", DHCPV6_ADVERTISE}, {"REQUEST", DHCPV6_REQUEST}, diff --git a/src/hooks/dhcp/perfmon/perfmon_config.h b/src/hooks/dhcp/perfmon/perfmon_config.h index 1f65c57681..c004d3d92c 100644 --- a/src/hooks/dhcp/perfmon/perfmon_config.h +++ b/src/hooks/dhcp/perfmon/perfmon_config.h @@ -37,7 +37,7 @@ namespace perfmon { /// }, /// "enable-alarm" : true, /// "high-water-ms" : 500, -/// "low-water-ms" : 25, +/// "low-water-ms" : 25 /// }, /// .. /// }] diff --git a/src/hooks/dhcp/perfmon/tests/duration_key_parser_unittests.cc b/src/hooks/dhcp/perfmon/tests/duration_key_parser_unittests.cc index fb83d53a1c..9abe417dab 100644 --- a/src/hooks/dhcp/perfmon/tests/duration_key_parser_unittests.cc +++ b/src/hooks/dhcp/perfmon/tests/duration_key_parser_unittests.cc @@ -165,6 +165,32 @@ TEST_F(DurationKeyParserTest, validScenarios4) { })", DHCPDISCOVER, DHCPOFFER, "start_here", "stop_there", SUBNET_ID_GLOBAL }, + { + // Empty message types should map to DHCP_NOTYPE + __LINE__, + R"( + { + "query-type": "", + "response-type": "", + "start-event": "start_here", + "stop-event": "stop_there", + "subnet-id": 701 + })", + DHCP_NOTYPE, DHCP_NOTYPE, "start_here", "stop_there", 701 + }, + { + // "*" message types should map to DHCP_NOTYPE + __LINE__, + R"( + { + "query-type": "*", + "response-type": "*", + "start-event": "start_here", + "stop-event": "stop_there", + "subnet-id": 701 + })", + DHCP_NOTYPE, DHCP_NOTYPE, "start_here", "stop_there", 701 + }, }; testValidScenarios(scenarios, AF_INET); @@ -386,6 +412,32 @@ TEST_F(DurationKeyParserTest, parseValidScenarios6) { })", DHCPV6_SOLICIT, DHCPV6_ADVERTISE, "start_here", "stop_there", SUBNET_ID_GLOBAL }, + { + // Empty message types should map to DHCPV6_NOTYPE + __LINE__, + R"( + { + "query-type": "", + "response-type": "", + "start-event": "start_here", + "stop-event": "stop_there", + "subnet-id": 701 + })", + DHCPV6_NOTYPE, DHCPV6_NOTYPE, "start_here", "stop_there", 701 + }, + { + // "*" message types should map to DHCPV6_NOTYPE + __LINE__, + R"( + { + "query-type": "*", + "response-type": "*", + "start-event": "start_here", + "stop-event": "stop_there", + "subnet-id": 701 + })", + DHCPV6_NOTYPE, DHCPV6_NOTYPE, "start_here", "stop_there", 701 + }, }; testValidScenarios(scenarios, AF_INET6); diff --git a/src/hooks/dhcp/perfmon/tests/perfmon_mgr_unittests.cc b/src/hooks/dhcp/perfmon/tests/perfmon_mgr_unittests.cc index 95167e0172..443fe7ab4a 100644 --- a/src/hooks/dhcp/perfmon/tests/perfmon_mgr_unittests.cc +++ b/src/hooks/dhcp/perfmon/tests/perfmon_mgr_unittests.cc @@ -117,7 +117,8 @@ public: EXPECT_EQ(mgr->getAlarmStore()->getFamily(), family_); AlarmCollectionPtr alarms = mgr->getAlarmStore()->getAll(); ASSERT_EQ(alarms->size(), 1); - DurationKeyPtr key(new DurationKey(family_, 0, 0, "process-started", "process-completed", 70)); + DurationKeyPtr key(new DurationKey(family_, 0, 0, "process-started", + "process-completed", 70)); AlarmPtr alarm = (*alarms)[0]; ASSERT_TRUE(alarm); EXPECT_EQ(*alarm, *key) << "alarm:" << alarm->getLabel();