diff --git a/doc/guide/dhcp4-srv.xml b/doc/guide/dhcp4-srv.xml index 7c802d3841..896adb7fa0 100644 --- a/doc/guide/dhcp4-srv.xml +++ b/doc/guide/dhcp4-srv.xml @@ -2583,6 +2583,41 @@ temporarily override a list of interface names and listen on all interfaces. + + + +
+ MERGE ME + + + + subnet[id].total-addresses (integer) - + this statistic shows the total number of addresses available for the + DHCPv4 management. In other words, this is the sum of all addresses in + all configured pools. This statistic changes only during configuration + changes. Note it does not take into account any addresses that may be + reserved due to host reservation. The id is the + subnet-id of a given subnet. This statistic is exposed for each subnet + separately. This statistic is reset during reconfiguration event. + + + + subnet[id].assigned-addresses (integer) - + this statistic shows the number of assigned addresses in a given subnet. + This statistic increases every time a new lease is allocated (as a result + of receiving a REQUEST message) and is decreased every time a lease is + released (a RELEASE message is received). When proper lease expiration + is implemented (planned for Kea 1.0), it will also decrease when a lease + is expired. The id is the subnet-id of a given + subnet. This statistic is exposed for each subnet separately. This + statistic is reset during reconfiguration event. + + + + +
+
Supported DHCP Standards The following standards are currently supported: diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am index 2f8f6097e0..e68df12a6b 100644 --- a/src/lib/dhcpsrv/Makefile.am +++ b/src/lib/dhcpsrv/Makefile.am @@ -141,6 +141,7 @@ libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la +libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc index 8d3147e6b8..20c3ab108f 100644 --- a/src/lib/dhcpsrv/cfgmgr.cc +++ b/src/lib/dhcpsrv/cfgmgr.cc @@ -19,10 +19,13 @@ #include #include #include +#include +#include #include using namespace isc::asiolink; using namespace isc::util; +using namespace isc::stats; namespace isc { namespace dhcp { @@ -116,6 +119,12 @@ CfgMgr::clear() { void CfgMgr::commit() { + + // First we need to remove statistics. The new configuration can have fewer + // subnets. Also, it may change subnet-ids. So we need to remove them all + // and add it back. + removeStatistics(); + ensureCurrentAllocated(); if (!configs_.back()->sequenceEquals(*configuration_)) { configuration_ = configs_.back(); @@ -127,6 +136,9 @@ CfgMgr::commit() { configs_.erase(configs_.begin(), it); } } + + // Now we need to set the statistics back. + updateStatistics(); } void @@ -186,6 +198,40 @@ CfgMgr::getStagingCfg() { return (configs_.back()); } +void +CfgMgr::removeStatistics() { + const Subnet4Collection* subnets = getCurrentCfg()->getCfgSubnets4()->getAll(); + + // For each subnet currently configured, remove the statistic + for (Subnet4Collection::const_iterator subnet = subnets->begin(); + subnet != subnets->end(); ++subnet) { + + /// @todo: Once stat contexts are implemented, we'll need to remove all + /// statistics from the subnet[subnet-id] context. + std::stringstream stat1; + stat1 << "subnet[" << (*subnet)->getID() << "].total-addresses"; + StatsMgr::instance().del(stat1.str()); + + std::stringstream stat2; + stat2 << "subnet[" << (*subnet)->getID() << "].assigned-addresses"; + isc::stats::StatsMgr::instance().del(stat2.str()); + } +} + +void +CfgMgr::updateStatistics() { + const Subnet4Collection* subnets = getCurrentCfg()->getCfgSubnets4()->getAll(); + + for (Subnet4Collection::const_iterator subnet = subnets->begin(); + subnet != subnets->end(); ++subnet) { + std::stringstream name; + name << "subnet[" << (*subnet)->getID() << "].total-addresses"; + + StatsMgr::instance().setValue(name.str(), + (*subnet)->getPoolCapacity(Lease::TYPE_V4)); + } +} + CfgMgr::CfgMgr() : datadir_(DHCP_DATA_DIR), echo_v4_client_id_(true), d2_client_mgr_(), verbose_mode_(false) { diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h index 77d8fd996a..4d84976af8 100644 --- a/src/lib/dhcpsrv/cfgmgr.h +++ b/src/lib/dhcpsrv/cfgmgr.h @@ -339,6 +339,23 @@ private: /// @return true if the duplicate subnet exists. bool isDuplicate(const Subnet6& subnet) const; + /// @brief Updates statistics. + /// + /// This method updates statistics that are affected by the newly committed + /// configuration. In particular, it updates the number of available addresses + /// in each subnet. Other statistics may be added in the future. In general, + /// these are statistics that are dependant only on configuration, so they are + /// not expected to change until the next reconfiguration event. + void updateStatistics(); + + /// @brief Removes statistics. + /// + /// During commitment of a new configuration, we need to get rid of the old + /// statistics for the old configuration. In particular, we need to remove + /// anything related to subnets, as there may be fewer subnets in the new + /// configuration and also subnet-ids may change. + void removeStatistics(); + /// @brief Container for defined DHCPv6 option spaces. OptionSpaceCollection spaces6_; diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am index 36334dd1bd..a4c9f2217f 100644 --- a/src/lib/dhcpsrv/tests/Makefile.am +++ b/src/lib/dhcpsrv/tests/Makefile.am @@ -139,6 +139,7 @@ libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la libdhcpsrv_unittests_LDADD += $(GTEST_LDADD) endif diff --git a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc index bf007b91b2..6aec2abf49 100644 --- a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -34,6 +35,7 @@ using namespace isc::data; using namespace isc::dhcp; using namespace isc::dhcp::test; using namespace isc::util; +using namespace isc::stats; using namespace isc; // don't import the entire boost namespace. It will unexpectedly hide uint8_t @@ -574,6 +576,46 @@ TEST_F(CfgMgrTest, verbosity) { EXPECT_FALSE(CfgMgr::instance().isVerbose()); } +// This test verifies that once the configuration is committed, statistics +// are updated appropriately. +TEST_F(CfgMgrTest, commitStats) { + CfgMgr& cfg_mgr = CfgMgr::instance(); + StatsMgr& stats_mgr = StatsMgr::instance(); + + // Let's prepare the "old" configuration: a subnet with id 123 + // and pretent there ware addresses assigned, so statistics are non-zero. + Subnet4Ptr subnet1(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3, 123)); + CfgSubnets4Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4(); + subnets->add(subnet1); + cfg_mgr.commit(); + stats_mgr.addValue("subnet[123].total-addresses", static_cast(256)); + stats_mgr.setValue("subnet[123].assigned-addresses", static_cast(150)); + + // Now, let's change the configuration to something new. + + // There's a subnet 192.1.2.0/24 with ID=42 + Subnet4Ptr subnet2(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3, 42)); + + // Let's make a pool with 128 addresses available. + PoolPtr pool(new Pool4(IOAddress("192.1.2.0"), 25)); // 128 addrs + subnet2->addPool(pool); + + subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4(); + subnets->add(subnet2); + + // Let's commit it + cfg_mgr.commit(); + + EXPECT_FALSE(stats_mgr.getObservation("subnet[123].total-addresses")); + EXPECT_FALSE(stats_mgr.getObservation("subnet[123].assigned-addresses")); + + ObservationPtr total_addrs; + EXPECT_NO_THROW(total_addrs = stats_mgr.getObservation("subnet[42].total-addresses")); + ASSERT_TRUE(total_addrs); + EXPECT_EQ(128, total_addrs->getInteger().first); +} + + /// @todo Add unit-tests for testing: /// - addActiveIface() with invalid interface name /// - addActiveIface() with the same interface twice