diff options
Diffstat (limited to 'src/hooks/dhcp/perfmon')
29 files changed, 7619 insertions, 0 deletions
diff --git a/src/hooks/dhcp/perfmon/Makefile.am b/src/hooks/dhcp/perfmon/Makefile.am new file mode 100644 index 0000000..36302b8 --- /dev/null +++ b/src/hooks/dhcp/perfmon/Makefile.am @@ -0,0 +1,90 @@ +SUBDIRS = . libloadtests tests + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +# Ensure that the message file and doxygen file is included in the distribution +EXTRA_DIST = perfmon_messages.mes +EXTRA_DIST += perfmon.dox + +CLEANFILES = *.gcno *.gcda + +# convenience archive + +noinst_LTLIBRARIES = libperfmon.la + +libperfmon_la_SOURCES = perfmon_callouts.cc +libperfmon_la_SOURCES += perfmon_log.cc perfmon_log.h +libperfmon_la_SOURCES += perfmon_messages.cc perfmon_messages.h +libperfmon_la_SOURCES += monitored_duration.cc monitored_duration.h +libperfmon_la_SOURCES += alarm.cc alarm.h +libperfmon_la_SOURCES += monitored_duration_store.cc monitored_duration_store.h +libperfmon_la_SOURCES += alarm_store.cc alarm_store.h +libperfmon_la_SOURCES += version.cc + +libperfmon_la_CXXFLAGS = $(AM_CXXFLAGS) +libperfmon_la_CPPFLAGS = $(AM_CPPFLAGS) + +# install the shared object into $(libdir)/kea/hooks +lib_hooksdir = $(libdir)/kea/hooks +lib_hooks_LTLIBRARIES = libdhcp_perfmon.la + +libdhcp_perfmon_la_SOURCES = +libdhcp_perfmon_la_LDFLAGS = $(AM_LDFLAGS) +libdhcp_perfmon_la_LDFLAGS += -avoid-version -export-dynamic -module +libdhcp_perfmon_la_LIBADD = libperfmon.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/process/libkea-process.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/eval/libkea-eval.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/http/libkea-http.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/database/libkea-database.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la +libdhcp_perfmon_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +libdhcp_perfmon_la_LIBADD += $(LOG4CPLUS_LIBS) +libdhcp_perfmon_la_LIBADD += $(CRYPTO_LIBS) +libdhcp_perfmon_la_LIBADD += $(BOOST_LIBS) + +# If we want to get rid of all generated messages files, we need to use +# make maintainer-clean. The proper way to introduce custom commands for +# that operation is to define maintainer-clean-local target. However, +# make maintainer-clean also removes Makefile, so running configure script +# is required. To make it easy to rebuild messages without going through +# reconfigure, a new target messages-clean has been added. +maintainer-clean-local: + rm -f perfmon_messages.h perfmon_messages.cc + +# To regenerate messages files, one can do: +# +# make messages-clean +# make messages +# +# This is needed only when a .mes file is modified. +messages-clean: maintainer-clean-local + +if GENERATE_MESSAGES + +# Define rule to build logging source files from message file +messages: perfmon_messages.h perfmon_messages.cc + @echo Message files regenerated + +perfmon_messages.h perfmon_messages.cc: perfmon_messages.mes + $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/hooks/dhcp/perfmon/perfmon_messages.mes + +else + +messages perfmon_messages.h perfmon_messages.cc: + @echo Messages generation disabled. Configure with --enable-generate-messages to enable it. + +endif + diff --git a/src/hooks/dhcp/perfmon/Makefile.in b/src/hooks/dhcp/perfmon/Makefile.in new file mode 100644 index 0000000..e14df7d --- /dev/null +++ b/src/hooks/dhcp/perfmon/Makefile.in @@ -0,0 +1,1101 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/hooks/dhcp/perfmon +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ + $(top_srcdir)/m4macros/ax_cpp14.m4 \ + $(top_srcdir)/m4macros/ax_cpp20.m4 \ + $(top_srcdir)/m4macros/ax_crypto.m4 \ + $(top_srcdir)/m4macros/ax_find_library.m4 \ + $(top_srcdir)/m4macros/ax_gssapi.m4 \ + $(top_srcdir)/m4macros/ax_gtest.m4 \ + $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ + $(top_srcdir)/m4macros/ax_netconf.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(lib_hooksdir)" +LTLIBRARIES = $(lib_hooks_LTLIBRARIES) $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +libdhcp_perfmon_la_DEPENDENCIES = libperfmon.la \ + $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ + $(top_builddir)/src/lib/process/libkea-process.la \ + $(top_builddir)/src/lib/eval/libkea-eval.la \ + $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ + $(top_builddir)/src/lib/stats/libkea-stats.la \ + $(top_builddir)/src/lib/config/libkea-cfgclient.la \ + $(top_builddir)/src/lib/http/libkea-http.la \ + $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ + $(top_builddir)/src/lib/hooks/libkea-hooks.la \ + $(top_builddir)/src/lib/database/libkea-database.la \ + $(top_builddir)/src/lib/cc/libkea-cc.la \ + $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ + $(top_builddir)/src/lib/dns/libkea-dns++.la \ + $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ + $(top_builddir)/src/lib/log/libkea-log.la \ + $(top_builddir)/src/lib/util/libkea-util.la \ + $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_libdhcp_perfmon_la_OBJECTS = +libdhcp_perfmon_la_OBJECTS = $(am_libdhcp_perfmon_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libdhcp_perfmon_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libdhcp_perfmon_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +libperfmon_la_LIBADD = +am_libperfmon_la_OBJECTS = libperfmon_la-perfmon_callouts.lo \ + libperfmon_la-perfmon_log.lo libperfmon_la-perfmon_messages.lo \ + libperfmon_la-monitored_duration.lo libperfmon_la-alarm.lo \ + libperfmon_la-monitored_duration_store.lo \ + libperfmon_la-alarm_store.lo libperfmon_la-version.lo +libperfmon_la_OBJECTS = $(am_libperfmon_la_OBJECTS) +libperfmon_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/libperfmon_la-alarm.Plo \ + ./$(DEPDIR)/libperfmon_la-alarm_store.Plo \ + ./$(DEPDIR)/libperfmon_la-monitored_duration.Plo \ + ./$(DEPDIR)/libperfmon_la-monitored_duration_store.Plo \ + ./$(DEPDIR)/libperfmon_la-perfmon_callouts.Plo \ + ./$(DEPDIR)/libperfmon_la-perfmon_log.Plo \ + ./$(DEPDIR)/libperfmon_la-perfmon_messages.Plo \ + ./$(DEPDIR)/libperfmon_la-version.Plo +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libdhcp_perfmon_la_SOURCES) $(libperfmon_la_SOURCES) +DIST_SOURCES = $(libdhcp_perfmon_la_SOURCES) $(libperfmon_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASCIIDOC = @ASCIIDOC@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_INCLUDES = @BOOST_INCLUDES@ +BOOST_LIBS = @BOOST_LIBS@ +BOTAN_TOOL = @BOTAN_TOOL@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONTRIB_DIR = @CONTRIB_DIR@ +CPPFLAGS = @CPPFLAGS@ +CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ +CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ +CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ +CRYPTO_LIBS = @CRYPTO_LIBS@ +CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ +CRYPTO_RPATH = @CRYPTO_RPATH@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ +DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@ +DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ +DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@ +DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ +DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@ +DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@ +DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@ +DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@ +DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@ +DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@ +DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@ +DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@ +DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@ +DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@ +DLLTOOL = @DLLTOOL@ +DPKG = @DPKG@ +DPKGQUERY = @DPKGQUERY@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GENHTML = @GENHTML@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_INCLUDES = @GTEST_INCLUDES@ +GTEST_LDADD = @GTEST_LDADD@ +GTEST_LDFLAGS = @GTEST_LDFLAGS@ +GTEST_SOURCE = @GTEST_SOURCE@ +HAVE_NETCONF = @HAVE_NETCONF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KEA_CXXFLAGS = @KEA_CXXFLAGS@ +KEA_SRCID = @KEA_SRCID@ +KRB5_CONFIG = @KRB5_CONFIG@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@ +LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@ +LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@ +LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@ +LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@ +LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@ +LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@ +LIBYANG_LIBS = @LIBYANG_LIBS@ +LIBYANG_PREFIX = @LIBYANG_PREFIX@ +LIBYANG_VERSION = @LIBYANG_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ +LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LIBS = @MYSQL_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ +PERL = @PERL@ +PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PKGPYTHONDIR = @PKGPYTHONDIR@ +PKG_CONFIG = @PKG_CONFIG@ +PLANTUML = @PLANTUML@ +PREMIUM_DIR = @PREMIUM_DIR@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SEP = @SEP@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPHINXBUILD = @SPHINXBUILD@ +SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@ +SR_PLUGINS_PATH = @SR_PLUGINS_PATH@ +SR_REPO_PATH = @SR_REPO_PATH@ +STRIP = @STRIP@ +SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@ +SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@ +SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@ +SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@ +SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@ +SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@ +SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@ +SYSREPO_LIBS = @SYSREPO_LIBS@ +SYSREPO_PREFIX = @SYSREPO_PREFIX@ +SYSREPO_VERSION = @SYSREPO_VERSION@ +USE_LCOV = @USE_LCOV@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ +XMLLINT = @XMLLINT@ +YACC = @YACC@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . libloadtests tests +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \ + $(BOOST_INCLUDES) +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +# Ensure that the message file and doxygen file is included in the distribution +EXTRA_DIST = perfmon_messages.mes perfmon.dox +CLEANFILES = *.gcno *.gcda + +# convenience archive +noinst_LTLIBRARIES = libperfmon.la +libperfmon_la_SOURCES = perfmon_callouts.cc perfmon_log.cc \ + perfmon_log.h perfmon_messages.cc perfmon_messages.h \ + monitored_duration.cc monitored_duration.h alarm.cc alarm.h \ + monitored_duration_store.cc monitored_duration_store.h \ + alarm_store.cc alarm_store.h version.cc +libperfmon_la_CXXFLAGS = $(AM_CXXFLAGS) +libperfmon_la_CPPFLAGS = $(AM_CPPFLAGS) + +# install the shared object into $(libdir)/kea/hooks +lib_hooksdir = $(libdir)/kea/hooks +lib_hooks_LTLIBRARIES = libdhcp_perfmon.la +libdhcp_perfmon_la_SOURCES = +libdhcp_perfmon_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version \ + -export-dynamic -module +libdhcp_perfmon_la_LIBADD = libperfmon.la \ + $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ + $(top_builddir)/src/lib/process/libkea-process.la \ + $(top_builddir)/src/lib/eval/libkea-eval.la \ + $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ + $(top_builddir)/src/lib/stats/libkea-stats.la \ + $(top_builddir)/src/lib/config/libkea-cfgclient.la \ + $(top_builddir)/src/lib/http/libkea-http.la \ + $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ + $(top_builddir)/src/lib/hooks/libkea-hooks.la \ + $(top_builddir)/src/lib/database/libkea-database.la \ + $(top_builddir)/src/lib/cc/libkea-cc.la \ + $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ + $(top_builddir)/src/lib/dns/libkea-dns++.la \ + $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ + $(top_builddir)/src/lib/log/libkea-log.la \ + $(top_builddir)/src/lib/util/libkea-util.la \ + $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ + $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) $(BOOST_LIBS) +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/hooks/dhcp/perfmon/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hooks/dhcp/perfmon/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-lib_hooksLTLIBRARIES: $(lib_hooks_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_hooks_LTLIBRARIES)'; test -n "$(lib_hooksdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(lib_hooksdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(lib_hooksdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(lib_hooksdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(lib_hooksdir)"; \ + } + +uninstall-lib_hooksLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_hooks_LTLIBRARIES)'; test -n "$(lib_hooksdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(lib_hooksdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(lib_hooksdir)/$$f"; \ + done + +clean-lib_hooksLTLIBRARIES: + -test -z "$(lib_hooks_LTLIBRARIES)" || rm -f $(lib_hooks_LTLIBRARIES) + @list='$(lib_hooks_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libdhcp_perfmon.la: $(libdhcp_perfmon_la_OBJECTS) $(libdhcp_perfmon_la_DEPENDENCIES) $(EXTRA_libdhcp_perfmon_la_DEPENDENCIES) + $(AM_V_CCLD)$(libdhcp_perfmon_la_LINK) -rpath $(lib_hooksdir) $(libdhcp_perfmon_la_OBJECTS) $(libdhcp_perfmon_la_LIBADD) $(LIBS) + +libperfmon.la: $(libperfmon_la_OBJECTS) $(libperfmon_la_DEPENDENCIES) $(EXTRA_libperfmon_la_DEPENDENCIES) + $(AM_V_CXXLD)$(libperfmon_la_LINK) $(libperfmon_la_OBJECTS) $(libperfmon_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libperfmon_la-alarm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libperfmon_la-alarm_store.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libperfmon_la-monitored_duration.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libperfmon_la-monitored_duration_store.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libperfmon_la-perfmon_callouts.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libperfmon_la-perfmon_log.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libperfmon_la-perfmon_messages.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libperfmon_la-version.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +libperfmon_la-perfmon_callouts.lo: perfmon_callouts.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -MT libperfmon_la-perfmon_callouts.lo -MD -MP -MF $(DEPDIR)/libperfmon_la-perfmon_callouts.Tpo -c -o libperfmon_la-perfmon_callouts.lo `test -f 'perfmon_callouts.cc' || echo '$(srcdir)/'`perfmon_callouts.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libperfmon_la-perfmon_callouts.Tpo $(DEPDIR)/libperfmon_la-perfmon_callouts.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='perfmon_callouts.cc' object='libperfmon_la-perfmon_callouts.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -c -o libperfmon_la-perfmon_callouts.lo `test -f 'perfmon_callouts.cc' || echo '$(srcdir)/'`perfmon_callouts.cc + +libperfmon_la-perfmon_log.lo: perfmon_log.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -MT libperfmon_la-perfmon_log.lo -MD -MP -MF $(DEPDIR)/libperfmon_la-perfmon_log.Tpo -c -o libperfmon_la-perfmon_log.lo `test -f 'perfmon_log.cc' || echo '$(srcdir)/'`perfmon_log.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libperfmon_la-perfmon_log.Tpo $(DEPDIR)/libperfmon_la-perfmon_log.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='perfmon_log.cc' object='libperfmon_la-perfmon_log.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -c -o libperfmon_la-perfmon_log.lo `test -f 'perfmon_log.cc' || echo '$(srcdir)/'`perfmon_log.cc + +libperfmon_la-perfmon_messages.lo: perfmon_messages.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -MT libperfmon_la-perfmon_messages.lo -MD -MP -MF $(DEPDIR)/libperfmon_la-perfmon_messages.Tpo -c -o libperfmon_la-perfmon_messages.lo `test -f 'perfmon_messages.cc' || echo '$(srcdir)/'`perfmon_messages.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libperfmon_la-perfmon_messages.Tpo $(DEPDIR)/libperfmon_la-perfmon_messages.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='perfmon_messages.cc' object='libperfmon_la-perfmon_messages.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -c -o libperfmon_la-perfmon_messages.lo `test -f 'perfmon_messages.cc' || echo '$(srcdir)/'`perfmon_messages.cc + +libperfmon_la-monitored_duration.lo: monitored_duration.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -MT libperfmon_la-monitored_duration.lo -MD -MP -MF $(DEPDIR)/libperfmon_la-monitored_duration.Tpo -c -o libperfmon_la-monitored_duration.lo `test -f 'monitored_duration.cc' || echo '$(srcdir)/'`monitored_duration.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libperfmon_la-monitored_duration.Tpo $(DEPDIR)/libperfmon_la-monitored_duration.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='monitored_duration.cc' object='libperfmon_la-monitored_duration.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -c -o libperfmon_la-monitored_duration.lo `test -f 'monitored_duration.cc' || echo '$(srcdir)/'`monitored_duration.cc + +libperfmon_la-alarm.lo: alarm.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -MT libperfmon_la-alarm.lo -MD -MP -MF $(DEPDIR)/libperfmon_la-alarm.Tpo -c -o libperfmon_la-alarm.lo `test -f 'alarm.cc' || echo '$(srcdir)/'`alarm.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libperfmon_la-alarm.Tpo $(DEPDIR)/libperfmon_la-alarm.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='alarm.cc' object='libperfmon_la-alarm.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -c -o libperfmon_la-alarm.lo `test -f 'alarm.cc' || echo '$(srcdir)/'`alarm.cc + +libperfmon_la-monitored_duration_store.lo: monitored_duration_store.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -MT libperfmon_la-monitored_duration_store.lo -MD -MP -MF $(DEPDIR)/libperfmon_la-monitored_duration_store.Tpo -c -o libperfmon_la-monitored_duration_store.lo `test -f 'monitored_duration_store.cc' || echo '$(srcdir)/'`monitored_duration_store.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libperfmon_la-monitored_duration_store.Tpo $(DEPDIR)/libperfmon_la-monitored_duration_store.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='monitored_duration_store.cc' object='libperfmon_la-monitored_duration_store.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -c -o libperfmon_la-monitored_duration_store.lo `test -f 'monitored_duration_store.cc' || echo '$(srcdir)/'`monitored_duration_store.cc + +libperfmon_la-alarm_store.lo: alarm_store.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -MT libperfmon_la-alarm_store.lo -MD -MP -MF $(DEPDIR)/libperfmon_la-alarm_store.Tpo -c -o libperfmon_la-alarm_store.lo `test -f 'alarm_store.cc' || echo '$(srcdir)/'`alarm_store.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libperfmon_la-alarm_store.Tpo $(DEPDIR)/libperfmon_la-alarm_store.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='alarm_store.cc' object='libperfmon_la-alarm_store.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -c -o libperfmon_la-alarm_store.lo `test -f 'alarm_store.cc' || echo '$(srcdir)/'`alarm_store.cc + +libperfmon_la-version.lo: version.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -MT libperfmon_la-version.lo -MD -MP -MF $(DEPDIR)/libperfmon_la-version.Tpo -c -o libperfmon_la-version.lo `test -f 'version.cc' || echo '$(srcdir)/'`version.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libperfmon_la-version.Tpo $(DEPDIR)/libperfmon_la-version.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='version.cc' object='libperfmon_la-version.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libperfmon_la_CPPFLAGS) $(CPPFLAGS) $(libperfmon_la_CXXFLAGS) $(CXXFLAGS) -c -o libperfmon_la-version.lo `test -f 'version.cc' || echo '$(srcdir)/'`version.cc + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(lib_hooksdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-lib_hooksLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/libperfmon_la-alarm.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-alarm_store.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-monitored_duration.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-monitored_duration_store.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-perfmon_callouts.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-perfmon_log.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-perfmon_messages.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-version.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-lib_hooksLTLIBRARIES + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/libperfmon_la-alarm.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-alarm_store.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-monitored_duration.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-monitored_duration_store.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-perfmon_callouts.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-perfmon_log.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-perfmon_messages.Plo + -rm -f ./$(DEPDIR)/libperfmon_la-version.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic \ + maintainer-clean-local + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-lib_hooksLTLIBRARIES + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-generic \ + clean-lib_hooksLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-lib_hooksLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-local mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am \ + uninstall-lib_hooksLTLIBRARIES + +.PRECIOUS: Makefile + + +# If we want to get rid of all generated messages files, we need to use +# make maintainer-clean. The proper way to introduce custom commands for +# that operation is to define maintainer-clean-local target. However, +# make maintainer-clean also removes Makefile, so running configure script +# is required. To make it easy to rebuild messages without going through +# reconfigure, a new target messages-clean has been added. +maintainer-clean-local: + rm -f perfmon_messages.h perfmon_messages.cc + +# To regenerate messages files, one can do: +# +# make messages-clean +# make messages +# +# This is needed only when a .mes file is modified. +messages-clean: maintainer-clean-local + +# Define rule to build logging source files from message file +@GENERATE_MESSAGES_TRUE@messages: perfmon_messages.h perfmon_messages.cc +@GENERATE_MESSAGES_TRUE@ @echo Message files regenerated + +@GENERATE_MESSAGES_TRUE@perfmon_messages.h perfmon_messages.cc: perfmon_messages.mes +@GENERATE_MESSAGES_TRUE@ $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/hooks/dhcp/perfmon/perfmon_messages.mes + +@GENERATE_MESSAGES_FALSE@messages perfmon_messages.h perfmon_messages.cc: +@GENERATE_MESSAGES_FALSE@ @echo Messages generation disabled. Configure with --enable-generate-messages to enable it. + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/hooks/dhcp/perfmon/alarm.cc b/src/hooks/dhcp/perfmon/alarm.cc new file mode 100644 index 0000000..1ba8fc2 --- /dev/null +++ b/src/hooks/dhcp/perfmon/alarm.cc @@ -0,0 +1,139 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 <config.h> + +#include <dhcp/pkt4.h> +#include <dhcp/pkt6.h> +#include <dhcp/dhcp6.h> +#include <exceptions/exceptions.h> +#include <alarm.h> + +using namespace isc::dhcp; +using namespace boost::posix_time; + +namespace isc { +namespace perfmon { + +Alarm::Alarm(uint16_t family, + uint8_t query_type, + uint8_t response_type, + const std::string& start_event_label, + const std::string& stop_event_label, + dhcp::SubnetID subnet_id, + const Duration& low_water, + const Duration& high_water, + bool enabled /* = true */) + : DurationKey(family, query_type, response_type, start_event_label, stop_event_label, subnet_id), + low_water_(low_water), + high_water_(high_water), + state_(enabled ? CLEAR : DISABLED), + stos_time_(PktEvent::now()), + last_high_water_report_(PktEvent::EMPTY_TIME()) { + if (low_water >= high_water_) { + isc_throw(BadValue, "low water: " << low_water_ + << ", must be less than high water: " << high_water_); + } +} + +Alarm::Alarm(const DurationKey& key, + const Duration& low_water, + const Duration& high_water, + bool enabled /* = true */) + : DurationKey(key), + low_water_(low_water), + high_water_(high_water), + state_(enabled ? CLEAR : DISABLED), + stos_time_(PktEvent::now()), + last_high_water_report_(PktEvent::EMPTY_TIME()) { + if (low_water >= high_water_) { + isc_throw(BadValue, "low water: " << low_water_ + << ", must be less than high water: " << high_water_); + } +} + +void +Alarm::setLowWater(const Duration& low_water) { + if (low_water >= high_water_) { + isc_throw(BadValue, "low water: " << low_water + << ", must be less than high water: " << high_water_); + } + + low_water_ = low_water; +} + +void +Alarm::setHighWater(const Duration& high_water) { + if (high_water <= low_water_) { + isc_throw(BadValue, "high water: " << high_water + << ", must be greater than low water: " << low_water_); + } + + high_water_ = high_water; +} + +void +Alarm::setState(State state) { + state_ = state; + stos_time_ = PktEvent::now(); + last_high_water_report_ = PktEvent::EMPTY_TIME(); +} + +void +Alarm::clear() { + setState(CLEAR); +} + +void +Alarm::disable() { + setState(DISABLED); +} + +bool +Alarm::checkSample(const Duration& sample, const Duration& report_interval) { + if (state_ == DISABLED) { + isc_throw(InvalidOperation, "Alarm::checkSample() " + "- should not be called when alarm is DISABLED"); + } + + // Low water subceeded? + if (sample < low_water_) { + // If the alarm is currently triggered, transition to CLEAR + // state and return true to signal reportable condition. + if (state_ == TRIGGERED) { + setState(CLEAR); + return (true); + } + + // Nothing to report. + return (false); + } + + // High water exceeded? + if (sample > high_water_) { + // If the alarm isn't yet triggered, transition to the TRIGGERED state. + if (state_ != TRIGGERED) { + setState(TRIGGERED); + } + } + + // If we're triggered and have not yet reported it or it is time to report again, + // update the report time and return true. + if (state_ == TRIGGERED) { + auto now = PktEvent::now(); + if ((last_high_water_report_ == PktEvent::EMPTY_TIME()) || + ((now - last_high_water_report_) > report_interval)) { + last_high_water_report_ = now; + return (true); + } + } + + // Nothing to report. + return (false); +} + +} // end of namespace perfmon +} // end of namespace isc diff --git a/src/hooks/dhcp/perfmon/alarm.h b/src/hooks/dhcp/perfmon/alarm.h new file mode 100644 index 0000000..0000557 --- /dev/null +++ b/src/hooks/dhcp/perfmon/alarm.h @@ -0,0 +1,173 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +#ifndef _ALARM_H +#define _ALARM_H + +#include <dhcp/pkt.h> +#include <dhcpsrv/subnet_id.h> +#include <monitored_duration.h> + +#include <boost/date_time/posix_time/posix_time.hpp> + +namespace isc { +namespace perfmon { + +/// @brief Defines an alarm for a duration. +class Alarm : public DurationKey { +public: + /// @brief Defines Alarm states + enum State { + CLEAR, // Enabled and not currently triggered + TRIGGERED, // High water has been exceeded + DISABLED // Disabled + }; + + /// @brief Constructor + /// + /// @param family protocol family AF_INET or AF_INET6 + /// @param query_type message type of the query packet + /// @param response_type message type of the response packet + /// @param start_event_label label of the start event + /// @param stop_event_label label of the end event + /// @param subnet_id SubnetID of the selected subnet + /// @param low_water threshold below which the average duration must fall to clear the alarm + /// @param high_water threshold above which the average duration must rise to trigger the alarm. + /// @param enabled true sets state to CLEAR, otherwise DISABLED, defaults to true. + Alarm(uint16_t family, uint8_t query_type, uint8_t response_type, + const std::string& start_event_label, const std::string& stop_event_label, + dhcp::SubnetID subnet_id, + const Duration& low_water, const Duration& high_water, bool enabled = true); + + /// @brief Constructor + /// + /// @param key composite key that identifies the alarm + /// @param low_water threshold below which the average duration must fall to clear the alarm + /// @param high_water threshold above which the average duration must rise to trigger the alarm. + /// @param enabled true sets state to CLEAR, otherwise DISABLED, defaults to true. + Alarm(const DurationKey& key, const Duration& low_water, const Duration& high_water, bool enabled = true); + + /// @brief Destructor + virtual ~Alarm() = default; + + /// @brief Get the low water threshold. + /// + /// @return Duration containing the low water threshold. + Duration getLowWater() const { + return (low_water_); + } + + /// @brief Set the low water threshold. + /// + /// @param low_water new value for the low water threshold. + /// @throw BadValue if new value is greater than the current value + /// of high water. + void setLowWater(const Duration& low_water); + + /// @brief Get the high water threshold. + /// + /// @return Duration containing the high water threshold. + Duration getHighWater() const { + return (high_water_); + } + + /// @brief Set the high water threshold. + /// + /// @param high_water new value for the high water threshold. + /// @throw BadValue if new value is less than the current value + /// of low water. + void setHighWater(const Duration& high_water); + + /// @brief Get the alarm's state. + State getState() { + return (state_); + } + + /// @brief Sets the alarm state. + /// + /// Sets the alarm's state to the given value, + /// sets the start of state time to the current time, + /// and resets the last high water report. + /// + /// @param state new state to which to transition. + void setState(State state); + + /// @brief Get the time the current state began. + /// + /// @return Timestamp the alarm entered it's current state. + Timestamp getStosTime() { + return (stos_time_); + } + + /// @brief Get the timestamp of the last high water report. + /// + /// @return Timestamp containing the last high water report time. + Timestamp getLastHighWaterReport() { + return (last_high_water_report_); + } + + /// @brief Set the timestamp of the last high water report. + /// + /// This function is provided for test purposes only. + /// + /// @param timestamp new value of the last high water report, defaults to + /// the current time. + void setLastHighWaterReport(const Timestamp& timestamp = dhcp::PktEvent::now()) { + last_high_water_report_ = timestamp; + } + + /// @brief Sets the alarm back to the CLEAR state. + void clear(); + + /// @brief Disables the alarm by setting the state to DISABLED. + void disable(); + + /// @brief Checks a duration against the high and low water thresholds + /// and calls the appropriate event handler. + /// + /// -# If the sample is less than the low water threshold: + /// If the state is TRIGGERED, transition to CLEAR and return true otherwise + /// return false. + /// -# If the sample is greater than high water threshold: + /// If the state is not TRIGGERED, transition to TRIGGERED + /// -# If the state is TRIGGERED and the last report time either not set or + /// is more than report interval old, update the last report time to current + /// time and return true. + /// -# Otherwise return false. + /// + /// @param sample duration to test against the thresholds. + /// @param report_interval amount of time that must elapse between high + /// water reports. + /// + /// @return True if alarm state should be reported. + /// + /// @throw InvalidOperation if called when the state is DISABLED. + bool checkSample(const Duration& sample, const Duration& report_interval); + +private: + /// @brief Threshold below which the average duration must fall to clear the alarm. + Duration low_water_; + + /// @brief Threshold above which the average duration must rise to trigger the alarm. + Duration high_water_; + + /// @brief Current alarm state. + State state_; + + /// @brief Timestamp of the beginning of the current state. + Timestamp stos_time_; + + /// @brief Last time the high water breach was reported. + Timestamp last_high_water_report_; +}; + +/// @brief Defines a pointer to an Alarm instance. +typedef boost::shared_ptr<Alarm> AlarmPtr; + +} // end of namespace isc::perfmon +} // end of namespace isc + +#endif diff --git a/src/hooks/dhcp/perfmon/alarm_store.cc b/src/hooks/dhcp/perfmon/alarm_store.cc new file mode 100644 index 0000000..cf9a0d0 --- /dev/null +++ b/src/hooks/dhcp/perfmon/alarm_store.cc @@ -0,0 +1,167 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 <config.h> + +#include <exceptions/exceptions.h> +#include <alarm_store.h> +#include <util/multi_threading_mgr.h> + +using namespace isc; +using namespace isc::util; + +namespace isc { +namespace perfmon { + +AlarmStore::AlarmStore(uint16_t family) + : family_(family), + alarms_(), + mutex_(new std::mutex) { + if (family_ != AF_INET && family_ != AF_INET6) { + isc_throw(BadValue, "AlarmStore - invalid family " + << family_ << ", must be AF_INET or AF_INET6"); + } +} + +void +AlarmStore::validateKey(const std::string& label, DurationKeyPtr key) const { + if (!key) { + isc_throw(BadValue, "AlarmStore::" << label << " - key is empty"); + } + + if (key->getFamily() != family_) { + isc_throw(BadValue, "AlarmStore::" << label + << " - family mismatch, key is " << (family_ == AF_INET ? + "v6, store is v4" : "v4, store is v6")); + } +} + +AlarmPtr +AlarmStore::checkDurationSample(DurationKeyPtr key, const Duration& sample, + const Duration& report_interval) { + validateKey("checkDurationSample", key); + + MultiThreadingLock lock(*mutex_); + auto& index = alarms_.get<AlarmPrimaryKeyTag>(); + auto alarm_iter = index.find(*key); + + // If we find an alarm then we check the sample. Alarm::checkSample() + // does not alter the key so it can be done in-place. + if (alarm_iter != index.end()) { + bool should_report = false; + bool modified = index.modify(alarm_iter, + [sample, report_interval, &should_report](AlarmPtr alarm) { + should_report = alarm->checkSample(sample, report_interval); + }); + + if (!modified) { + // Possible but unlikely. + isc_throw(Unexpected, "AlarmStore::checkDurationSample - modify failed for: " << key->getLabel()); + } + + if (should_report) { + // Alarm state needs to be reported, return a copy of the alarm. + return (AlarmPtr(new Alarm(**alarm_iter))); + } + } + + // Nothing to alarm. + return (AlarmPtr()); +} + +AlarmPtr +AlarmStore::addAlarm(AlarmPtr alarm) { + MultiThreadingLock lock(*mutex_); + auto ret = alarms_.insert(alarm); + if (ret.second == false) { + isc_throw(DuplicateAlarm, "AlarmStore::addAlarm: alarm already exists for: " + << alarm->getLabel()); + } + + // Return a copy of what we inserted. + return (AlarmPtr(new Alarm(*alarm))); +} + +AlarmPtr +AlarmStore::addAlarm(DurationKeyPtr key, const Duration& low_water, + const Duration& high_water, bool enabled /* = true */) { + validateKey("addAlarm", key); + + // Create the alarm instance. + AlarmPtr alarm; + try { + alarm.reset(new Alarm(*key, low_water, high_water, enabled)); + } catch (const std::exception& ex) { + isc_throw(BadValue, "AlarmStore::addAlarm failed: " << ex.what()); + } + + return (addAlarm(alarm)); +} + +AlarmPtr +AlarmStore::getAlarm(DurationKeyPtr key) { + validateKey("getAlarm", key); + + MultiThreadingLock lock(*mutex_); + const auto& index = alarms_.get<AlarmPrimaryKeyTag>(); + auto alarm_iter = index.find(*key); + return (alarm_iter == index.end() ? AlarmPtr() + : AlarmPtr(new Alarm(**alarm_iter))); +} + +void +AlarmStore::updateAlarm(AlarmPtr& alarm) { + validateKey("updateAlarm", alarm); + + MultiThreadingLock lock(*mutex_); + auto& index = alarms_.get<AlarmPrimaryKeyTag>(); + auto alarm_iter = index.find(*alarm); + if (alarm_iter == index.end()) { + isc_throw(InvalidOperation, "AlarmStore::updateAlarm alarm not found: " + << alarm->getLabel()); + } + + // Use replace() which only re-indexes if keys change. + index.replace(alarm_iter, AlarmPtr(new Alarm(*alarm))); +} + +void +AlarmStore::deleteAlarm(DurationKeyPtr key) { + validateKey("deleteAlarm", key); + + MultiThreadingLock lock(*mutex_); + auto& index = alarms_.get<AlarmPrimaryKeyTag>(); + auto alarm_iter = index.find(*key); + if (alarm_iter == index.end()) { + // Not there, just return. + return; + } + + // Remove the alarm from the store. + alarms_.erase(alarm_iter); +} + +AlarmCollectionPtr +AlarmStore::getAll() { + MultiThreadingLock lock(*mutex_); + const auto& index = alarms_.get<AlarmPrimaryKeyTag>(); + AlarmCollectionPtr collection(new AlarmCollection()); + for (auto const& alarm : index) { + collection->push_back(AlarmPtr(new Alarm(*alarm))); + } + + return (collection); +} + +void +AlarmStore::clear() { + MultiThreadingLock lock(*mutex_); + alarms_.clear(); +} + +} // end of namespace perfmon +} // end of namespace isc + diff --git a/src/hooks/dhcp/perfmon/alarm_store.h b/src/hooks/dhcp/perfmon/alarm_store.h new file mode 100644 index 0000000..dfaacce --- /dev/null +++ b/src/hooks/dhcp/perfmon/alarm_store.h @@ -0,0 +1,186 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +#ifndef ALARM_STORE_H +#define ALARM_STORE_H + +#include <exceptions/exceptions.h> +#include <alarm.h> + +#include <boost/multi_index/indexed_by.hpp> +#include <boost/multi_index/member.hpp> +#include <boost/multi_index/mem_fun.hpp> +#include <boost/multi_index/ordered_index.hpp> +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/composite_key.hpp> +#include <boost/multi_index/sequenced_index.hpp> +#include <boost/multi_index/identity.hpp> +#include <boost/scoped_ptr.hpp> + +#include <string> + +namespace isc { +namespace perfmon { + +/// @brief Exception thrown when an attempt was made to add a duplicate key +/// to either the duration or alarm stores. +class DuplicateAlarm : public Exception { +public: + DuplicateAlarm(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +/// @brief Tag for index by primary key (DurationKey). +struct AlarmPrimaryKeyTag { }; + +/// @brief A multi index container holding pointers to alarms. +/// +/// The alarms in the container may be accessed using different indexes: +/// - using the index on DurationKey members, AlarmPrimaryKeyTag +/// - others to follow based on API +/// +/// Indexes can be accessed using the index number (from 0 to n) or a +/// name tag. It is recommended to use the tags to access indexes as +/// they do not depend on the order of indexes in the container. +typedef boost::multi_index_container< + // It holds pointers to Lease6 objects. + AlarmPtr, + boost::multi_index::indexed_by< + // Specification of the first index starts here. + // This index sorts using DurationKey::operators + boost::multi_index::ordered_unique< + boost::multi_index::tag<AlarmPrimaryKeyTag>, + boost::multi_index::identity<DurationKey> + > + > +> AlarmContainer; + +/// @brief Type for a collection of AlarmPtrs. +typedef std::vector<AlarmPtr> AlarmCollection; + +/// @brief Type for a pointer to a collection of AlarmPtrs. +typedef boost::shared_ptr<AlarmCollection> AlarmCollectionPtr; + +/// @brief Maintains an in-memory store of alarms +/// +/// Provides essential CRUD functions for managing a collection of +/// alarms. Additionally there are finders that can return +/// durations by DurationKey (others are TBD). +/// All finders return copies of the durations found, rather than the +/// stored duration itself. +class AlarmStore { +public: + /// @brief Constructor + /// + /// @param family protocol family AF_INET or AF_INET6 + explicit AlarmStore(uint16_t family); + + /// @brief Destructor + ~AlarmStore() = default; + + /// @brief Checks a sample against an alarm. + /// + /// If the alarm exists in the store for the duration key, then Alarm::checkSample() + /// is invoked on the in-store alarm. If this returns true, indicating an alarm + /// state change, then a copy of the in-store alarm is returned, otherwise an empty + /// pointer is returned. + /// + /// If no alarm exists in the store, then it simply returns an empty pointer. + /// + /// This function does not/must not modify any index keys. + /// + /// @param key key value of the alarm to check. + /// @param sample duration value to check. + /// @param report_interval amount of time that must elapse between high + /// water reports. + /// + /// @return A copy of the updated alarm if it should be reported, an empty + /// pointer otherwise. + AlarmPtr checkDurationSample(DurationKeyPtr key, const Duration& sample, + const Duration& report_interval); + + /// @brief Creates a new alarm and adds it to the store + /// + /// @param key key value of the alarm to create. + /// @param low_water threshold below which the average duration must fall to clear the alarm + /// @param high_water threshold above which the average duration must rise to trigger the alarm. + /// @param enabled true sets state to CLEAR, otherwise DISABLED, defaults to true. + /// + /// @return pointer to the newly created alarm. + /// @throw DuplicateAlarm if a duration for the given key already exists in + /// the store. + AlarmPtr addAlarm(DurationKeyPtr key, const Duration& low_water, + const Duration& high_water, bool enabled = true); + + /// @brief Adds an alarm to the store. + /// + /// @return pointer to a copy of the alarm added. + AlarmPtr addAlarm(AlarmPtr alarm); + + /// @brief Fetches a duration from the store for a given key. + /// + /// @param key key value of the alarm to fetch. + /// + /// @return Pointer the desired alarm or an empty pointer. + AlarmPtr getAlarm(DurationKeyPtr key); + + /// @brief Updates an alarm in the store. + /// + /// The alarm is assumed to already exist in the store. + /// + /// @param alarm alarm to update. + /// + /// @throw InvalidOperation if the alarm does not exist in the store. + void updateAlarm(AlarmPtr& alarm); + + /// @brief Removes the alarm from the store. + /// + /// If the alarm does not exist in the store, it simply returns. + /// + /// @param key key value of the alarm to delete. + void deleteAlarm(DurationKeyPtr key); + + /// @brief Fetches all of the alarms (in order by target) + /// + /// @return a collection of all alarms in the store. + AlarmCollectionPtr getAll(); + + /// @brief Removes all alarms from the store. + void clear(); + + /// @brief Get protocol family + /// + /// @return uint16_t containing the family (AF_INET or AF_INET6) + uint16_t getFamily() { + return (family_); + } + +private: + /// @brief Convenience method to verify a key is valid for an operation. + /// + /// @param label description of where the check is being made, appears in exception text. + /// @param key key to validate. + /// + /// @throw BadValue if the key is either empty or its family does not + /// match the store. + void validateKey(const std::string& label, DurationKeyPtr key) const; + + /// @brief Protocol family AF_INET or AF_INET6. + uint16_t family_; + + /// @brief Container instance. + AlarmContainer alarms_; + + /// @brief The mutex used to protect internal state. + const boost::scoped_ptr<std::mutex> mutex_; +}; + +typedef boost::shared_ptr<AlarmStore> AlarmStorePtr; + +} // end of namespace perfmon +} // end of namespace isc + +#endif diff --git a/src/hooks/dhcp/perfmon/libloadtests/Makefile.am b/src/hooks/dhcp/perfmon/libloadtests/Makefile.am new file mode 100644 index 0000000..2f12610 --- /dev/null +++ b/src/hooks/dhcp/perfmon/libloadtests/Makefile.am @@ -0,0 +1,55 @@ +SUBDIRS = . + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/perfmon -I$(top_srcdir)/src/hooks/dhcp/perfmon +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CPPFLAGS += -DLIBDHCP_PERFMON_SO=\"$(abs_top_builddir)/src/hooks/dhcp/perfmon/.libs/libdhcp_perfmon.so\" +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +EXTRA_DIST = + +CLEANFILES = *.gcno *.gcda + +TESTS_ENVIRONMENT = \ + $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) + +if HAVE_GTEST + +TESTS = hook_load_unittests + +hook_load_unittests_SOURCES = +hook_load_unittests_SOURCES += load_unload_unittests.cc +hook_load_unittests_SOURCES += run_unittests.cc +hook_load_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) +hook_load_unittests_CXXFLAGS = $(AM_CXXFLAGS) +hook_load_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) + +hook_load_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la +hook_load_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +hook_load_unittests_LDADD += $(LOG4CPLUS_LIBS) +hook_load_unittests_LDADD += $(CRYPTO_LIBS) +hook_load_unittests_LDADD += $(BOOST_LIBS) +hook_load_unittests_LDADD += $(GTEST_LDADD) + +noinst_PROGRAMS = $(TESTS) + +endif diff --git a/src/hooks/dhcp/perfmon/libloadtests/Makefile.in b/src/hooks/dhcp/perfmon/libloadtests/Makefile.in new file mode 100644 index 0000000..85a0f74 --- /dev/null +++ b/src/hooks/dhcp/perfmon/libloadtests/Makefile.in @@ -0,0 +1,1033 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@HAVE_GTEST_TRUE@TESTS = hook_load_unittests$(EXEEXT) +@HAVE_GTEST_TRUE@noinst_PROGRAMS = $(am__EXEEXT_1) +subdir = src/hooks/dhcp/perfmon/libloadtests +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ + $(top_srcdir)/m4macros/ax_cpp14.m4 \ + $(top_srcdir)/m4macros/ax_cpp20.m4 \ + $(top_srcdir)/m4macros/ax_crypto.m4 \ + $(top_srcdir)/m4macros/ax_find_library.m4 \ + $(top_srcdir)/m4macros/ax_gssapi.m4 \ + $(top_srcdir)/m4macros/ax_gtest.m4 \ + $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ + $(top_srcdir)/m4macros/ax_netconf.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@HAVE_GTEST_TRUE@am__EXEEXT_1 = hook_load_unittests$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +am__hook_load_unittests_SOURCES_DIST = load_unload_unittests.cc \ + run_unittests.cc +@HAVE_GTEST_TRUE@am_hook_load_unittests_OBJECTS = hook_load_unittests-load_unload_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ hook_load_unittests-run_unittests.$(OBJEXT) +hook_load_unittests_OBJECTS = $(am_hook_load_unittests_OBJECTS) +am__DEPENDENCIES_1 = +@HAVE_GTEST_TRUE@hook_load_unittests_DEPENDENCIES = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +hook_load_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) \ + $(hook_load_unittests_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = \ + ./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po \ + ./$(DEPDIR)/hook_load_unittests-run_unittests.Po +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(hook_load_unittests_SOURCES) +DIST_SOURCES = $(am__hook_load_unittests_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + fi; \ +} +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASCIIDOC = @ASCIIDOC@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_INCLUDES = @BOOST_INCLUDES@ +BOOST_LIBS = @BOOST_LIBS@ +BOTAN_TOOL = @BOTAN_TOOL@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONTRIB_DIR = @CONTRIB_DIR@ +CPPFLAGS = @CPPFLAGS@ +CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ +CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ +CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ +CRYPTO_LIBS = @CRYPTO_LIBS@ +CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ +CRYPTO_RPATH = @CRYPTO_RPATH@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ +DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@ +DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ +DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@ +DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ +DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@ +DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@ +DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@ +DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@ +DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@ +DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@ +DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@ +DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@ +DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@ +DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@ +DLLTOOL = @DLLTOOL@ +DPKG = @DPKG@ +DPKGQUERY = @DPKGQUERY@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GENHTML = @GENHTML@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_INCLUDES = @GTEST_INCLUDES@ +GTEST_LDADD = @GTEST_LDADD@ +GTEST_LDFLAGS = @GTEST_LDFLAGS@ +GTEST_SOURCE = @GTEST_SOURCE@ +HAVE_NETCONF = @HAVE_NETCONF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KEA_CXXFLAGS = @KEA_CXXFLAGS@ +KEA_SRCID = @KEA_SRCID@ +KRB5_CONFIG = @KRB5_CONFIG@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@ +LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@ +LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@ +LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@ +LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@ +LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@ +LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@ +LIBYANG_LIBS = @LIBYANG_LIBS@ +LIBYANG_PREFIX = @LIBYANG_PREFIX@ +LIBYANG_VERSION = @LIBYANG_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ +LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LIBS = @MYSQL_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ +PERL = @PERL@ +PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PKGPYTHONDIR = @PKGPYTHONDIR@ +PKG_CONFIG = @PKG_CONFIG@ +PLANTUML = @PLANTUML@ +PREMIUM_DIR = @PREMIUM_DIR@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SEP = @SEP@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPHINXBUILD = @SPHINXBUILD@ +SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@ +SR_PLUGINS_PATH = @SR_PLUGINS_PATH@ +SR_REPO_PATH = @SR_REPO_PATH@ +STRIP = @STRIP@ +SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@ +SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@ +SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@ +SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@ +SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@ +SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@ +SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@ +SYSREPO_LIBS = @SYSREPO_LIBS@ +SYSREPO_PREFIX = @SYSREPO_PREFIX@ +SYSREPO_VERSION = @SYSREPO_VERSION@ +USE_LCOV = @USE_LCOV@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ +XMLLINT = @XMLLINT@ +YACC = @YACC@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \ + -I$(top_builddir)/src/hooks/dhcp/perfmon \ + -I$(top_srcdir)/src/hooks/dhcp/perfmon $(BOOST_INCLUDES) \ + -DLIBDHCP_PERFMON_SO=\"$(abs_top_builddir)/src/hooks/dhcp/perfmon/.libs/libdhcp_perfmon.so\" +AM_CXXFLAGS = $(KEA_CXXFLAGS) +@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static +EXTRA_DIST = +CLEANFILES = *.gcno *.gcda +TESTS_ENVIRONMENT = \ + $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) + +@HAVE_GTEST_TRUE@hook_load_unittests_SOURCES = \ +@HAVE_GTEST_TRUE@ load_unload_unittests.cc run_unittests.cc +@HAVE_GTEST_TRUE@hook_load_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) +@HAVE_GTEST_TRUE@hook_load_unittests_CXXFLAGS = $(AM_CXXFLAGS) +@HAVE_GTEST_TRUE@hook_load_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) +@HAVE_GTEST_TRUE@hook_load_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) \ +@HAVE_GTEST_TRUE@ $(BOOST_LIBS) $(GTEST_LDADD) +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/hooks/dhcp/perfmon/libloadtests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hooks/dhcp/perfmon/libloadtests/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +hook_load_unittests$(EXEEXT): $(hook_load_unittests_OBJECTS) $(hook_load_unittests_DEPENDENCIES) $(EXTRA_hook_load_unittests_DEPENDENCIES) + @rm -f hook_load_unittests$(EXEEXT) + $(AM_V_CXXLD)$(hook_load_unittests_LINK) $(hook_load_unittests_OBJECTS) $(hook_load_unittests_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hook_load_unittests-run_unittests.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +hook_load_unittests-load_unload_unittests.o: load_unload_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-load_unload_unittests.o -MD -MP -MF $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo -c -o hook_load_unittests-load_unload_unittests.o `test -f 'load_unload_unittests.cc' || echo '$(srcdir)/'`load_unload_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo $(DEPDIR)/hook_load_unittests-load_unload_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='load_unload_unittests.cc' object='hook_load_unittests-load_unload_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-load_unload_unittests.o `test -f 'load_unload_unittests.cc' || echo '$(srcdir)/'`load_unload_unittests.cc + +hook_load_unittests-load_unload_unittests.obj: load_unload_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-load_unload_unittests.obj -MD -MP -MF $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo -c -o hook_load_unittests-load_unload_unittests.obj `if test -f 'load_unload_unittests.cc'; then $(CYGPATH_W) 'load_unload_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/load_unload_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo $(DEPDIR)/hook_load_unittests-load_unload_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='load_unload_unittests.cc' object='hook_load_unittests-load_unload_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-load_unload_unittests.obj `if test -f 'load_unload_unittests.cc'; then $(CYGPATH_W) 'load_unload_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/load_unload_unittests.cc'; fi` + +hook_load_unittests-run_unittests.o: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/hook_load_unittests-run_unittests.Tpo -c -o hook_load_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-run_unittests.Tpo $(DEPDIR)/hook_load_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='hook_load_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc + +hook_load_unittests-run_unittests.obj: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/hook_load_unittests-run_unittests.Tpo -c -o hook_load_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-run_unittests.Tpo $(DEPDIR)/hook_load_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='hook_load_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po + -rm -f ./$(DEPDIR)/hook_load_unittests-run_unittests.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po + -rm -f ./$(DEPDIR)/hook_load_unittests-run_unittests.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) check-am install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-TESTS check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc new file mode 100644 index 0000000..31d8cd2 --- /dev/null +++ b/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc @@ -0,0 +1,64 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +/// @file This file contains tests which exercise the load and unload +/// functions in the perfmon hook library. In order to test the load +/// function, one must be able to pass it hook library parameters. The +/// the only way to populate these parameters is by actually loading the +/// library via HooksManager::loadLibraries(). + +#include <config.h> + +#include <cc/data.h> +#include <dhcpsrv/cfgmgr.h> +#include <hooks/hooks_manager.h> +#include <process/daemon.h> +#include <testutils/gtest_utils.h> +#include <testutils/lib_load_test_fixture.h> + +#include <gtest/gtest.h> +#include <errno.h> + +using namespace std; +using namespace isc; +using namespace isc::hooks; +using namespace isc::data; +using namespace isc::dhcp; +using namespace isc::process; + +namespace { + +/// @brief Test fixture for testing loading and unloading the perfmon library +class PerfMonLibLoadTest : public isc::test::LibLoadTest { +public: + /// @brief Constructor + PerfMonLibLoadTest() : LibLoadTest(LIBDHCP_PERFMON_SO) { + } + + /// @brief Destructor + virtual ~PerfMonLibLoadTest() { + unloadLibraries(); + } +}; + +// Simple V4 test that checks the library can be loaded and unloaded several times. +TEST_F(PerfMonLibLoadTest, validLoad4) { + validDaemonTest("kea-dhcp4"); +} + +// Simple V6 test that checks the library can be loaded and unloaded several times. +TEST_F(PerfMonLibLoadTest, validLoad6) { + validDaemonTest("kea-dhcp6", AF_INET6); +} + +// Simple test that checks the library cannot by loaded by invalid daemons. +TEST_F(PerfMonLibLoadTest, invalidDaemonLoad) { + invalidDaemonTest("kea-ctrl-agent"); + invalidDaemonTest("kea-dhcp-ddns"); + invalidDaemonTest("bogus"); +} + +} // end of anonymous namespace diff --git a/src/hooks/dhcp/perfmon/libloadtests/run_unittests.cc b/src/hooks/dhcp/perfmon/libloadtests/run_unittests.cc new file mode 100644 index 0000000..0500503 --- /dev/null +++ b/src/hooks/dhcp/perfmon/libloadtests/run_unittests.cc @@ -0,0 +1,20 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the End User License +// Agreement. See COPYING file in the premium/ directory. + +#include <config.h> + +#include <log/logger_support.h> + +#include <gtest/gtest.h> + +int +main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + isc::log::initLogger(); + + int result = RUN_ALL_TESTS(); + + return (result); +} diff --git a/src/hooks/dhcp/perfmon/monitored_duration.cc b/src/hooks/dhcp/perfmon/monitored_duration.cc new file mode 100644 index 0000000..ec6bb9d --- /dev/null +++ b/src/hooks/dhcp/perfmon/monitored_duration.cc @@ -0,0 +1,287 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 <config.h> + +#include <dhcp/pkt4.h> +#include <dhcp/pkt6.h> +#include <dhcp/dhcp6.h> +#include <exceptions/exceptions.h> +#include <monitored_duration.h> + +using namespace isc::dhcp; +using namespace boost::posix_time; + +namespace isc { +namespace perfmon { + +// DurationDataInterval methods + +DurationDataInterval::DurationDataInterval(const Timestamp& start_time /* = PktEvent::now()*/) + : start_time_(start_time), occurrences_(0), + min_duration_(pos_infin), max_duration_(neg_infin), + total_duration_(microseconds(0)) { +} + +void +DurationDataInterval::addDuration(const Duration& duration) { + ++occurrences_; + if (duration < min_duration_) { + min_duration_ = duration; + } + + if (duration > max_duration_) { + max_duration_ = duration; + } + + total_duration_ += duration; +} + +Duration +DurationDataInterval::getAverageDuration() const { + if (!occurrences_) { + return (ZERO_DURATION()); + } + + return (total_duration_ / occurrences_); +} + +bool +DurationDataInterval::operator==(const DurationDataInterval& other) const { + return ((start_time_ == other.start_time_) && + (occurrences_ == other.occurrences_) && + (min_duration_ == other.min_duration_) && + (max_duration_ == other.max_duration_) && + (total_duration_ == other.total_duration_)); +} + +// DurationKey methods + +DurationKey::DurationKey(uint16_t family, + uint8_t query_type, + uint8_t response_type, + const std::string& start_event_label, + const std::string& stop_event_label, + dhcp::SubnetID subnet_id) + : family_(family), + query_type_(query_type), + response_type_(response_type), + start_event_label_(start_event_label), + stop_event_label_(stop_event_label), + subnet_id_(subnet_id) { + if (family != AF_INET && family != AF_INET6) { + isc_throw (BadValue, "DurationKey: family must be AF_INET or AF_INET6"); + } + + validateMessagePair(family, query_type, response_type); +} + +void +DurationKey::validateMessagePair(uint16_t family, uint8_t query_type, uint8_t response_type) { + if (family == AF_INET) { + switch(query_type) { + case DHCP_NOTYPE: + if (response_type == DHCP_NOTYPE || + response_type == DHCPOFFER || + response_type == DHCPACK || + response_type == DHCPNAK) { + return; + } + break; + + case DHCPDISCOVER: + if (response_type == DHCP_NOTYPE || + response_type == DHCPOFFER || + response_type == DHCPNAK) { + return; + } + break; + + case DHCPREQUEST: + if (response_type == DHCP_NOTYPE || + response_type == DHCPACK || + response_type == DHCPNAK) { + return; + } + break; + + case DHCPINFORM: + if (response_type == DHCP_NOTYPE || + response_type == DHCPACK) { + return; + } + break; + + default: + isc_throw(BadValue, "Query type not supported by monitoring: " + << Pkt4::getName(query_type)); + break; + } + + isc_throw(BadValue, "Response type: " << Pkt4::getName(response_type) + << " not valid for query type: " << Pkt4::getName(query_type)); + + } else { + switch(query_type) { + case DHCPV6_NOTYPE: + case DHCPV6_SOLICIT: + if (response_type == DHCPV6_NOTYPE || + response_type == DHCPV6_ADVERTISE || + response_type == DHCPV6_REPLY) { + return; + } + break; + + case DHCPV6_REQUEST: + case DHCPV6_RENEW: + case DHCPV6_REBIND: + case DHCPV6_CONFIRM: + if (response_type == DHCPV6_NOTYPE || + response_type == DHCPV6_REPLY) { + return; + } + break; + + default: + isc_throw(BadValue, "Query type not supported by monitoring: " + << Pkt6::getName(query_type)); + break; + } + + isc_throw(BadValue, "Response type: " << Pkt6::getName(response_type) + << " not valid for query type: " << Pkt6::getName(query_type)); + } +} + +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_)); + } + + oss << "." << start_event_label_ << "-" << stop_event_label_ + << "." << subnet_id_; + + return (oss.str()); +}; + +bool +DurationKey::operator==(const DurationKey& other) const { + return ( + (query_type_ == other.query_type_) && + (response_type_ == other.response_type_) && + (start_event_label_ == other.start_event_label_) && + (stop_event_label_ == other.stop_event_label_) && + (subnet_id_ == other.subnet_id_) + ); +} + +bool +DurationKey::operator!=(const DurationKey& other) const { + return (!(*this == other)); +} + +bool +DurationKey::operator<(const DurationKey& other) const { + return ((query_type_ < other.query_type_) || + (response_type_ < other.response_type_) || + (start_event_label_ < other.start_event_label_) || + (stop_event_label_ < other.stop_event_label_) || + (subnet_id_ < other.subnet_id_)); +} + + +// MonitoredDuration methods + +MonitoredDuration::MonitoredDuration(uint16_t family, + uint8_t query_type, + uint8_t response_type, + const std::string& start_event_label, + const std::string& stop_event_label, + dhcp::SubnetID subnet_id, + const Duration& interval_duration) + : DurationKey(family, query_type, response_type, start_event_label, stop_event_label, subnet_id), + interval_duration_(interval_duration), + current_interval_(0), + previous_interval_(0) { + if (interval_duration_ <= DurationDataInterval::ZERO_DURATION()) { + isc_throw(BadValue, "MonitoredDuration - interval_duration " << interval_duration_ + << ", is invalid, it must be greater than 0"); + } +} + +MonitoredDuration::MonitoredDuration(const DurationKey& key, + const Duration& interval_duration) + : DurationKey(key), + interval_duration_(interval_duration), + current_interval_(0), + previous_interval_(0) { + if (interval_duration_ <= DurationDataInterval::ZERO_DURATION()) { + isc_throw(BadValue, "MonitoredDuration - interval_duration " << interval_duration_ + << ", is invalid, it must be greater than 0"); + } +} + +MonitoredDuration::MonitoredDuration(const MonitoredDuration& rhs) + : DurationKey(rhs), + interval_duration_(rhs.interval_duration_), + current_interval_(0), + previous_interval_(0) { + if (rhs.current_interval_) { + current_interval_.reset(new DurationDataInterval(*rhs.current_interval_)); + } + + if (rhs.previous_interval_) { + previous_interval_.reset(new DurationDataInterval(*rhs.previous_interval_)); + } +} + +Timestamp +MonitoredDuration::getCurrentIntervalStart() const { + return (current_interval_ ? current_interval_->getStartTime() + : dhcp::PktEvent::MIN_TIME()); +} + +bool +MonitoredDuration::addSample(const Duration& sample) { + auto now = PktEvent::now(); + bool do_report = false; + if (!current_interval_) { + current_interval_.reset(new DurationDataInterval(now)); + } else if ((now - current_interval_->getStartTime()) > interval_duration_) { + previous_interval_ = current_interval_; + do_report = true; + current_interval_.reset(new DurationDataInterval(now)); + } + + current_interval_->addDuration(sample); + return (do_report); +} + +void +MonitoredDuration::expireCurrentInterval() { + if (!current_interval_) { + isc_throw(InvalidOperation, "MonitoredDuration::expireInterval" + " - no current interval for: " << getLabel()); + } + + previous_interval_ = current_interval_; + current_interval_.reset(); +} + +void +MonitoredDuration::clear() { + current_interval_.reset(); + previous_interval_.reset(); +} + +} // end of namespace perfmon +} // end of namespace isc diff --git a/src/hooks/dhcp/perfmon/monitored_duration.h b/src/hooks/dhcp/perfmon/monitored_duration.h new file mode 100644 index 0000000..6efa261 --- /dev/null +++ b/src/hooks/dhcp/perfmon/monitored_duration.h @@ -0,0 +1,360 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +#ifndef _MONITORED_DURATION_H +#define _MONITORED_DURATION_H + +#include <dhcp/pkt.h> +#include <dhcpsrv/subnet_id.h> + +#include <boost/date_time/posix_time/posix_time.hpp> + +namespace isc { +namespace perfmon { + +typedef boost::posix_time::ptime Timestamp; +typedef boost::posix_time::time_duration Duration; + +/// @brief Embodies a span of time (i.e. an interval) over which duration data +/// is accumulated. +class DurationDataInterval { +public: + /// @brief Get a duration of zero. + /// + /// @return Duration of zero microseconds. + static const Duration& ZERO_DURATION() { + static Duration duration(boost::posix_time::microseconds(0)); + return (duration); + } + + /// @brief Constructor + explicit DurationDataInterval(const Timestamp& start_time = dhcp::PktEvent::now()); + + /// @brief Destructor + ~DurationDataInterval() = default; + + /// @brief Add a duration to the interval. + /// + /// Given a duration value: + /// -# Increment the number of occurrences + /// -# Add the duration to the total duration + /// -# Update the minimum and/or maxium duration accordingly + /// + /// @param duration Duration to add. + void addDuration(const Duration& duration); + + /// @brief Get the start time of the interval. + /// + /// @return Timestamp containing the start time. + const Timestamp& getStartTime() const { + return (start_time_); + } + + /// @brief Set the interval start time. + /// + /// @param start_time new value for the interval start time. + void setStartTime(const Timestamp& start_time) { + start_time_ = start_time; + } + + /// @brief Get the number of occurrences that have contributed to the + /// interval. + /// + /// @return the number of occurrences. + uint64_t getOccurrences() const { + return (occurrences_); + }; + + /// @brief Get the minimum duration that has occurred in the interval. + /// + /// @return Duration containing the minimum duration. + Duration getMinDuration() const { + return (min_duration_); + } + + /// @brief Get the maximum duration that has occurred in the interval. + /// + /// @return Duration containing the maximum duration. + Duration getMaxDuration() const { + return (max_duration_); + } + + /// @brief Get the total duration in the interval. + /// + /// @return Duration containing the total duration. + Duration getTotalDuration() const { + return (total_duration_); + } + + /// @brief Get the average duration for the interval. + /// + /// @return Duration containing the average. + Duration getAverageDuration() const; + + /// @brief Equality operator. + /// + /// Primarily used for testing. + /// + /// equality operator to compare two DurationDataInterval objects. + /// @param other DurationDataInterval to be compared against. + /// @return True the keys are equal + bool operator==(const DurationDataInterval& other) const; + +private: + /// @brief Timestamp at which this interval began. + Timestamp start_time_; + + /// @brief Number of event-pairs that occurred during the interval. + uint64_t occurrences_; + + /// @brief Minimum duration that occurred during this interval. + Duration min_duration_; + + /// @brief Maximum duration that occurred during this interval. + Duration max_duration_; + + /// @brief Total duration of all the occurrences included in this interval. + Duration total_duration_; +}; + +/// @brief Defines a pointer to a DurationDataInterval instance. +typedef boost::shared_ptr<DurationDataInterval> DurationDataIntervalPtr; + +/// @brief Houses the composite key that uniquely identifies a duration: +/// -# Query Packet Type +/// -# Response Packet Type +/// -# Start Event +/// -# Stop Event +/// -# Subnet ID can be GLOBAL_SUBNET_ID for aggregate durations +class DurationKey { +public: + /// @brief Constructor + /// + /// @param family protocol family AF_INET or AF_INET6 + /// @param query_type message type of the query packet + /// @param response_type message type of the response packet + /// @param start_event_label label of the start event + /// @param stop_event_label label of the end event + /// @param subnet_id id of the selected subnet + DurationKey(uint16_t family, uint8_t query_type, uint8_t response_type, + const std::string& start_event_label, const std::string& stop_event_label, + dhcp::SubnetID subnet_id); + + /// @brief Destructor + virtual ~DurationKey() = default; + + /// @brief Get protocol family + /// + /// @return uint16_t containing the family (AF_INET or AF_INET6) + uint16_t getFamily() { + return (family_); + } + + /// @brief Get the query packet type. + /// + /// @return the query packet type. + uint8_t getQueryType() const { + return (query_type_); + } + + /// @brief Get the response packet type. + /// + /// @return the response packet type. + uint8_t getResponseType() const { + return (response_type_); + }; + + /// @brief Get the start event label. + /// + /// @return the start event label. + std::string getStartEventLabel() const { + return (start_event_label_); + } + + /// @brief Get the end event label. + /// + /// @return the end event label. + std::string getStopEventLabel() const { + return (stop_event_label_); + } + + /// @brief Get the subnet id. + /// + /// @return SubnetID of the selected subnet. + dhcp::SubnetID getSubnetId() const { + return (subnet_id_); + } + + /// @brief Get a composite label of the member values with text message types. + /// + /// @param family Protocol family of the key (AF_INET or AF_INET6) + /// The format of the string: + /// + /// @code + /// <query type>-<response type>.<start_event>-<stop_event>.<subnet id> + /// + /// Example: + /// + /// "DHCPDISCOVER-DHCPOFFER.socket_received.buffer_read.12" + /// + /// or + /// + /// "DHCPV6_SOLICIT-DHCPV6_ADVERTISE.socket_received.buffer_read.12" + /// + /// @endcode + /// + /// @return the composite label. + std::string getLabel() const; + + /// @brief Validates that a query and response message type pair is sane. + /// + /// @param family Protocol family of the key (AF_INET or AF_INET6) + /// The format of the string: + /// @param query_type message type of the query packet + /// @param response_type message type of the response packet + /// + /// @throw BadValue is the pairing does not make sense. + static void validateMessagePair(uint16_t family, uint8_t query_type, uint8_t response_type); + + /// @brief Equality operator. + /// + /// equality operator to compare two DurationKey objects. + /// @param other DurationKey to be compared against. + /// @return True the keys are equal + bool operator==(const DurationKey& other) const; + + /// @brief Inequality operator. + /// + /// Inequality operator to compare two DurationKey objects. + /// @param other DurationKey to be compared against. + /// @return True the keys are not equal + bool operator!=(const DurationKey& other) const; + + /// @brief Less than operator. + /// + /// less than operator to compare two DurationKey objects. + /// @param other DurationKey to be compared against. + /// @return True key is less than the other key + bool operator<(const DurationKey& other) const; + +protected: + /// @brief Protocol family AF_INET or AF_INET6. + uint16_t family_; + + /// @brief Query message type (e.g. DHCPDISCOVER, DHCP6_SOLICIT). + uint8_t query_type_; + + /// @brief Response message type (e.g. DHCPOFFER, DHCP6_ADVERTISE). + uint8_t response_type_; + + /// @brief Label of the start event which begins the duration. + std::string start_event_label_; + + /// @brief Label of the end event which ends the duration. + std::string stop_event_label_; + + /// @brief Subnet ID of the subnet selected during query fulfillment. + isc::dhcp::SubnetID subnet_id_; +}; + +/// @brief Defines a pointer to a DurationKey instance. +typedef boost::shared_ptr<DurationKey> DurationKeyPtr; + +class MonitoredDuration : public DurationKey { +public: + /// @brief Constructor + /// + /// @param family protocol family AF_INET or AF_INET6 + /// @param query_type message type of the query packet + /// @param response_type message type of the response packet + /// @param start_event_label label of the start event + /// @param stop_event_label label of the end event + /// @param subnet_id id of the selected subnet + /// @param interval_duration the interval duration + MonitoredDuration(uint16_t family, uint8_t query_type, uint8_t response_type, + const std::string& start_event_label, const std::string& stop_event_label, + dhcp::SubnetID subnet_id, const Duration& interval_duration); + + /// @brief Constructor + /// + /// @param key composite key that identifies the alarm + /// @param interval_duration the interval duration + MonitoredDuration(const DurationKey& key, const Duration& interval_duration); + + /// @brief Copy Constructor + /// + /// @param rhs duration to copy + MonitoredDuration(const MonitoredDuration& rhs); + + /// @brief Destructor + virtual ~MonitoredDuration() = default; + + /// @brief Get the interval duration. + /// + /// @return Duration containing the interval duration. + Duration getIntervalDuration() const { + return (interval_duration_); + } + + /// @brief Get the previous interval. + /// + /// @return Pointer to the previous interval if it exists or an empty pointer. + DurationDataIntervalPtr getPreviousInterval() const { + return (previous_interval_); + } + + /// @brief Get the current interval. + /// + /// @return Pointer to the current interval if it exists or an empty pointer. + DurationDataIntervalPtr getCurrentInterval() const { + return (current_interval_); + } + + /// @brief Get the current interval start time. + /// + /// @return Current interval's start time or MIN_TIME if there's no + /// current interval. + Timestamp getCurrentIntervalStart() const; + + /// @brief Add a sample to the duration's current interval. + /// + /// If there is no current interval start a new one otherwise if the current + /// interval has expired move it to the previous interval, set the return flag + /// to true, then start a new interval. + /// Add the sample to the current interval. + /// + /// @param sample duration value to add + /// + /// @return True if there is a newly completed (i.e. previous) interval to report. + bool addSample(const Duration& sample); + + /// @brief Concludes the current interval + /// + /// Rotates current interval to previous and resets curent interval to empty. + /// + /// @throw InvalidOperation if there is no current interval. + void expireCurrentInterval(); + + /// @brief Deletes the current and previous intervals. + void clear(); + +private: + /// @brief Length of the time of a single data interval. + Duration interval_duration_; + + /// @brief Data interval into which samples are currently accumulating. + DurationDataIntervalPtr current_interval_; + + /// @brief Closed data interval immediately prior to the current interval. + DurationDataIntervalPtr previous_interval_; +}; + +typedef boost::shared_ptr<MonitoredDuration> MonitoredDurationPtr; + +} // end of namespace isc::perfmon +} // end of namespace isc + +#endif diff --git a/src/hooks/dhcp/perfmon/monitored_duration_store.cc b/src/hooks/dhcp/perfmon/monitored_duration_store.cc new file mode 100644 index 0000000..6c0e550 --- /dev/null +++ b/src/hooks/dhcp/perfmon/monitored_duration_store.cc @@ -0,0 +1,214 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 <config.h> + +#include <exceptions/exceptions.h> +#include <monitored_duration_store.h> +#include <util/multi_threading_mgr.h> + +using namespace isc; +using namespace isc::dhcp; +using namespace isc::util; +using namespace boost::posix_time; + +namespace isc { +namespace perfmon { + +MonitoredDurationStore::MonitoredDurationStore(uint16_t family, + const Duration& interval_duration) + : family_(family), + interval_duration_(interval_duration), + durations_(), + mutex_(new std::mutex) { + if (family != AF_INET && family_ != AF_INET6) { + isc_throw(BadValue, "MonitoredDurationStore - invalid family " + << family_ << ", must be AF_INET or AF_INET6"); + } + + if (interval_duration_ <= DurationDataInterval::ZERO_DURATION()) { + isc_throw(BadValue, "MonitoredDurationStore - invalid interval_duration " + << interval_duration_ << ", must be greater than zero"); + } +} + +void +MonitoredDurationStore::validateKey(const std::string& label, DurationKeyPtr key) const { + if (!key) { + isc_throw(BadValue, "MonitoredDurationStore::" << label << " - key is empty"); + } + + if (key->getFamily() != family_) { + isc_throw(BadValue, "MonitoredDurationStore::" << label + << " - family mismatch, key is " << (family_ == AF_INET ? + "v6, store is v4" : "v4, store is v6")); + } +} + +MonitoredDurationPtr +MonitoredDurationStore::addDurationSample(DurationKeyPtr key, const Duration& sample) { + validateKey("addDurationSample", key); + + MultiThreadingLock lock(*mutex_); + auto& index = durations_.get<DurationKeyTag>(); + auto duration_iter = index.find(*key); + if (duration_iter != index.end()) { + bool should_report = false; + // Modify updates in place and only re-indexes if keys change. + bool modified = index.modify(duration_iter, + [sample, &should_report](MonitoredDurationPtr mond) { + should_report = mond->addSample(sample); + }); + + if (!modified) { + // Possible but unlikely. + isc_throw(Unexpected, + "MonitoredDurationStore::addDurationSample - modify failed for: " + << key->getLabel()); + } + + // If it's time to report return a copy otherwise an empty pointer. + return (should_report ? MonitoredDurationPtr(new MonitoredDuration(**duration_iter)) + : MonitoredDurationPtr()); + } + + // It doesn't exist, add it. + MonitoredDurationPtr mond(new MonitoredDuration(*key, interval_duration_)); + static_cast<void>(mond->addSample(sample)); + auto ret = durations_.insert(mond); + if (ret.second == false) { + // Shouldn't be possible. + isc_throw(DuplicateDurationKey, + "MonitoredDurationStore::addDurationSample: duration already exists for: " + << key->getLabel()); + } + + // Nothing to report. + return (MonitoredDurationPtr()); +} + +MonitoredDurationPtr +MonitoredDurationStore::addDuration(DurationKeyPtr key) { + validateKey("addDuration", key); + + // Create the duration instance. + MonitoredDurationPtr mond; + try { + mond.reset(new MonitoredDuration(*key, interval_duration_)); + } catch (const std::exception& ex) { + isc_throw(BadValue, "MonitoredDurationStore::addDuration failed: " << ex.what()); + } + + // Now lock and insert the new duration. + { + MultiThreadingLock lock(*mutex_); + auto ret = durations_.insert(mond); + if (ret.second == false) { + isc_throw(DuplicateDurationKey, + "MonitoredDurationStore::addDuration: duration already exists for: " + << key->getLabel()); + } + } + + // Return a copy of what we inserted. + return (MonitoredDurationPtr(new MonitoredDuration(*mond))); +} + + +MonitoredDurationPtr +MonitoredDurationStore::getDuration(DurationKeyPtr key) { + validateKey("getDuration", key); + + MultiThreadingLock lock(*mutex_); + const auto& index = durations_.get<DurationKeyTag>(); + auto duration_iter = index.find(*key); + return (duration_iter == index.end() ? MonitoredDurationPtr() + : MonitoredDurationPtr(new MonitoredDuration(**duration_iter))); +} + +void +MonitoredDurationStore::updateDuration(MonitoredDurationPtr& duration) { + validateKey("updateDuration", duration); + + MultiThreadingLock lock(*mutex_); + auto& index = durations_.get<DurationKeyTag>(); + auto duration_iter = index.find(*duration); + if (duration_iter == index.end()) { + isc_throw(InvalidOperation, "MonitoredDurationStore::updateDuration duration not found: " + << duration->getLabel()); + } + + // Use replace() which only re-indexes if keys change. + index.replace(duration_iter, MonitoredDurationPtr(new MonitoredDuration(*duration))); +} + +void +MonitoredDurationStore::deleteDuration(DurationKeyPtr key) { + validateKey("deleteDuration", key); + + MultiThreadingLock lock(*mutex_); + auto& index = durations_.get<DurationKeyTag>(); + auto duration_iter = index.find(*key); + if (duration_iter == index.end()) { + // Not there, just return. + return; + } + + // Remove the duration from the store. + durations_.erase(duration_iter); +} + +MonitoredDurationCollectionPtr +MonitoredDurationStore::getAll() { + MultiThreadingLock lock(*mutex_); + const auto& index = durations_.get<DurationKeyTag>(); + MonitoredDurationCollectionPtr collection(new MonitoredDurationCollection()); + for (auto const& mond : index) { + collection->push_back(MonitoredDurationPtr(new MonitoredDuration(*mond))); + } + + return (collection); +} + +void +MonitoredDurationStore::clear() { + MultiThreadingLock lock(*mutex_); + durations_.clear(); +} + +MonitoredDurationPtr +MonitoredDurationStore::getReportsNext() { + MultiThreadingLock lock(*mutex_); + const auto& index = durations_.get<IntervalStartTag>(); + // We want to find the oldest interval that is less than interval_duration in the past. + auto duration_iter = index.lower_bound(dhcp::PktEvent::now() - interval_duration_); + return (duration_iter == index.end() ? MonitoredDurationPtr() + : MonitoredDurationPtr(new MonitoredDuration(**duration_iter))); +} + +MonitoredDurationCollectionPtr +MonitoredDurationStore::getOverdueReports(const Timestamp& since /* = PktEvent::now() */) { + MultiThreadingLock lock(*mutex_); + // We use a lower bound of MIN + 1us to avoid dormant durations + static Timestamp lower_limit_time(PktEvent::MIN_TIME() + microseconds(1)); + + // We want to find anything since the start of time who's start time + // is more than interval_duration_ in the past. + const auto& index = durations_.get<IntervalStartTag>(); + auto lower_limit = index.lower_bound(lower_limit_time); + auto upper_limit = index.upper_bound(since - interval_duration_); + + MonitoredDurationCollectionPtr collection(new MonitoredDurationCollection()); + for (auto duration_iter = lower_limit; duration_iter != upper_limit; ++duration_iter) { + collection->push_back(MonitoredDurationPtr(new MonitoredDuration(**duration_iter))); + } + + return (collection); +} + +} // end of namespace perfmon +} // end of namespace isc + diff --git a/src/hooks/dhcp/perfmon/monitored_duration_store.h b/src/hooks/dhcp/perfmon/monitored_duration_store.h new file mode 100644 index 0000000..292782e --- /dev/null +++ b/src/hooks/dhcp/perfmon/monitored_duration_store.h @@ -0,0 +1,205 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +#ifndef MONITORED_DURATION_STORE_H +#define MONITORED_DURATION_STORE_H + +#include <exceptions/exceptions.h> +#include <monitored_duration.h> + +#include <boost/multi_index/indexed_by.hpp> +#include <boost/multi_index/member.hpp> +#include <boost/multi_index/mem_fun.hpp> +#include <boost/multi_index/ordered_index.hpp> +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/composite_key.hpp> +#include <boost/multi_index/sequenced_index.hpp> +#include <boost/multi_index/identity.hpp> +#include <boost/scoped_ptr.hpp> + +#include <string> + +namespace isc { +namespace perfmon { + +/// @brief Exception thrown when an attempt was made to add a duplicate duration +/// to the store. +class DuplicateDurationKey : public Exception { +public: + DuplicateDurationKey(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +/// @brief Tag for index by primary key (DurationKey). +struct DurationKeyTag { }; + +/// @brief Tag for index by interval start time. +struct IntervalStartTag { }; + +/// @brief A multi index container holding pointers to durations. +/// +/// The durations in the container may be accessed using different indexes: +/// - using the index on DurationKey members, DurationKeyTag +/// - others to follow based on API +/// +/// Indexes can be accessed using the index number (from 0 to n) or a +/// name tag. It is recommended to use the tags to access indexes as +/// they do not depend on the order of indexes in the container. +typedef boost::multi_index_container< + // It holds pointers to Lease6 objects. + MonitoredDurationPtr, + boost::multi_index::indexed_by< + // Specification of the first index starts here. + // This index sorts using DurationKey::operators + boost::multi_index::ordered_unique< + boost::multi_index::tag<DurationKeyTag>, + boost::multi_index::identity<DurationKey> + >, + + // Specification of the second index starts here. + // This index sorts durations by current interval start time. + boost::multi_index::ordered_non_unique< + boost::multi_index::tag<IntervalStartTag>, + boost::multi_index::const_mem_fun<MonitoredDuration, Timestamp, + &MonitoredDuration::getCurrentIntervalStart> + > + > +> MonitoredDurationContainer; + +/// @brief Type for a collection of MonitoredDurationPtrs. +typedef std::vector<MonitoredDurationPtr> MonitoredDurationCollection; + +/// @brief Type for a pointer to a collection of MonitoredDurationPtrs. +typedef boost::shared_ptr<MonitoredDurationCollection> MonitoredDurationCollectionPtr; + +/// @brief Maintains an in-memory store of durations +/// +/// Provides essential CRUD functions for managing a collection of +/// durations. Additionally there are finders that can return +/// durations by DurationKey (others are TBD) +/// All finders return copies of the durations found, rather than the +/// stored duration itself. +class MonitoredDurationStore { +public: + /// @brief Constructor + /// + /// @param family protocol family AF_INET or AF_INET6 + /// @param interval_duration the interval duration + explicit MonitoredDurationStore(uint16_t family, const Duration& interval_duration); + + /// @brief Destructor + ~MonitoredDurationStore() = default; + + /// @brief Adds a sample to a duration in-place. + /// + /// If the duration exists in the store then the MonitoredDuration::addSample() + /// is invoked on the in-store duration. If this returns true, indicating a reportable + /// condition, then a copy of the in-store duration is returned, otherwise an empty + /// pointer is returned. + /// + /// If the duration does not exist in the store, then one is created and inserted + /// into the store after adding the sample. An empty pointer is returned. + /// + /// This function does not/must not modify any index keys. + /// + /// @param key key value of the duration to which to add. + /// @param sample duration value to add + /// + /// @return A copy of the updated duration if it should be reported, an empty + /// pointer otherwise. + MonitoredDurationPtr addDurationSample(DurationKeyPtr key, const Duration& sample); + + /// @brief Creates a new duration and adds it to the store + /// + /// @param key key value of the duration to create. + /// + /// @return pointer to the newly created duration. + /// @throw DuplicateDuration if a duration for the given key already exists in + /// the store. + MonitoredDurationPtr addDuration(DurationKeyPtr key); + + /// @brief Fetches a duration from the store for a given key. + /// + /// @param key key value of the duration to fetch. + /// + /// @return Pointer the desired duration or an empty pointer. + MonitoredDurationPtr getDuration(DurationKeyPtr key); + + /// @brief Updates a duration in the store. + /// + /// The duration is assumed to already exist in the store. + /// + /// @param duration duration to update. + /// + /// @throw InvalidOperation if duration does not exist in the store. + void updateDuration(MonitoredDurationPtr& duration); + + /// @brief Removes the duration from the store. + /// + /// If the duration does not exist in the store, it simply returns. + /// + /// @param key key value of the duration to delete. + void deleteDuration(DurationKeyPtr key); + + /// @brief Fetches all of the durations (in order by target) + /// + /// @return a collection of all durations in the store. + MonitoredDurationCollectionPtr getAll(); + + /// @brief Fetches the duration which is due to report next. + /// + /// @return pointer to the matching duration or an empty pointer if + /// not found. + MonitoredDurationPtr getReportsNext(); + + /// @brief Fetches all durations that are overdue to report. + /// + /// @param since timestamp to search by. Defaults to current time. + /// + /// @return a collection of the matching durations, ordered by current interval + /// start time. + MonitoredDurationCollectionPtr getOverdueReports(const Timestamp& since = dhcp::PktEvent::now()); + + /// @brief Removes all durations from the store. + void clear(); + + /// @brief Get protocol family + /// + /// @return uint16_t containing the family (AF_INET or AF_INET6) + uint16_t getFamily() { + return (family_); + } + +private: + /// @brief Convenience method to verify a key is valid for an operation. + /// + /// @param label description of where the check is being made, appears in exception text. + /// @param key key to validate. + /// + /// @throw BadValue if the key is either empty or its family does not + /// match the store. + void validateKey(const std::string& label, DurationKeyPtr key) const; + + /// @brief Protocol family AF_INET or AF_INET6. + uint16_t family_; + + /// @brief The length of time over data for a single duration is + /// accumulated before reporting. + Duration interval_duration_; + + /// @brief Container instance. + MonitoredDurationContainer durations_; + + /// @brief The mutex used to protect internal state. + const boost::scoped_ptr<std::mutex> mutex_; +}; + +typedef boost::shared_ptr<MonitoredDurationStore> MonitoredDurationStorePtr; + +} // end of namespace perfmon +} // end of namespace isc + +#endif diff --git a/src/hooks/dhcp/perfmon/perfmon.dox b/src/hooks/dhcp/perfmon/perfmon.dox new file mode 100644 index 0000000..ca4f2e2 --- /dev/null +++ b/src/hooks/dhcp/perfmon/perfmon.dox @@ -0,0 +1,43 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +/** + +@page libdhcp_perfmon Kea PerfMon Hooks Library + +@section libdhcp_perfmonIntro Introduction + +Welcome to Kea PerfMon Hooks Library. This documentation is addressed to +developers who are interested in the internal operation of the PerfMon +library. This file provides information needed to understand and perhaps extend +this library. + +This documentation is stand-alone: you should have read and understood the <a +href="https://reports.kea.isc.org/dev_guide/">Kea Developer's Guide</a> and in +particular its section about hooks. + +@section perfmon PerfMon Overview + +PerfMon (or perfmon) is a Hook library that can be loaded by +either kea-dhcp4 and kea-dhcp6 servers to extend them with the +ability to track and report performance related data. + +The initial purpose of this library is to provide supplemental data and +commands for monitoring the performance of kea-dhcp4 and kea-dhcp6 +servers in real time. + + + + THIS LIBRARY IS CURRENTLY UNDER DEVELOPMENT + + + + +@section perfmonMTCompatibility Multi-Threading Compatibility + +The PerfMon Hook library is compatible with multi-threading. + +*/ diff --git a/src/hooks/dhcp/perfmon/perfmon_callouts.cc b/src/hooks/dhcp/perfmon/perfmon_callouts.cc new file mode 100644 index 0000000..853ba1c --- /dev/null +++ b/src/hooks/dhcp/perfmon/perfmon_callouts.cc @@ -0,0 +1,129 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +// Functions accessed by the hooks framework use C linkage to avoid the name +// mangling that accompanies use of the C++ compiler as well as to avoid +// issues related to namespaces. + +#include <config.h> + +#include <perfmon_log.h> +#include <cc/command_interpreter.h> +#include <dhcpsrv/cfgmgr.h> +#include <hooks/hooks.h> +#include <process/daemon.h> + +using namespace isc::dhcp; +using namespace isc::hooks; +using namespace isc::log; +using namespace isc::process; +using namespace isc::perfmon; + +extern "C" { + +int dhcp4_srv_configured(CalloutHandle& /* handle */) { + // We do this here rather than in load() to ensure we check after the + // filter has been determined. + LOG_DEBUG(perfmon_logger, DBGLVL_TRACE_BASIC, + PERFMON_DHCP4_SOCKET_RECEIVED_TIME_SUPPORT) + .arg(IfaceMgr::instance().isSocketReceivedTimeSupported() ? "Yes" : "No"); + return (0); +} + +int dhcp6_srv_configured(CalloutHandle& /* handle */) { + // We do this here rather than in load() to ensure we check after the + // filter has been determined. + LOG_DEBUG(perfmon_logger, DBGLVL_TRACE_BASIC, + PERFMON_DHCP6_SOCKET_RECEIVED_TIME_SUPPORT) + .arg(IfaceMgr::instance().isSocketReceivedTimeSupported() ? "Yes" : "No"); + return (0); +} + +/// @brief This callout is called at the "pkt4_send" hook. +/// +/// @param handle CalloutHandle which provides access to context. +/// +/// @return 0 upon success, non-zero otherwise. +int pkt4_send(CalloutHandle& handle) { + CalloutHandle::CalloutNextStep status = handle.getStatus(); + if (status == CalloutHandle::NEXT_STEP_DROP || + status == CalloutHandle::NEXT_STEP_SKIP) { + return (0); + } + + Pkt4Ptr query; + handle.getArgument("query4", query); + LOG_DEBUG(perfmon_logger, DBGLVL_TRACE_DETAIL, PERFMON_DHCP4_PKT_EVENTS) + .arg(query->getLabel()) + .arg(query->dumpPktEvents()); + + return (0); +} + +/// @brief This callout is called at the "pkt6_send" hook. +/// +/// @param handle CalloutHandle which provides access to context. +/// +/// @return 0 upon success, non-zero otherwise. +int pkt6_send(CalloutHandle& handle) { + CalloutHandle::CalloutNextStep status = handle.getStatus(); + if (status == CalloutHandle::NEXT_STEP_DROP || + status == CalloutHandle::NEXT_STEP_SKIP) { + return (0); + } + + Pkt6Ptr query; + handle.getArgument("query6", query); + LOG_DEBUG(perfmon_logger, DBGLVL_TRACE_DETAIL, PERFMON_DHCP6_PKT_EVENTS) + .arg(query->getLabel()) + .arg(query->dumpPktEvents()); + + return (0); +} + +/// @brief This function is called when the library is loaded. +/// +/// @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") { + isc_throw(isc::Unexpected, "Bad process name: " << proc_name + << ", expected kea-dhcp6"); + } + } + + /// @todo register commands + /// handle.registerCommandCallout("command-here", handler_here); + + LOG_INFO(perfmon_logger, PERFMON_INIT_OK); + return (0); +} + +/// @brief This function is called when the library is unloaded. +/// +/// @return 0 if deregistration was successful, 1 otherwise +int unload() { + LOG_INFO(perfmon_logger, PERFMON_DEINIT_OK); + return (0); +} + +/// @brief This function is called to retrieve the multi-threading compatibility. +/// +/// @return 1 which means compatible with multi-threading. +int multi_threading_compatible() { + return (1); +} + +} // end extern "C" diff --git a/src/hooks/dhcp/perfmon/perfmon_log.cc b/src/hooks/dhcp/perfmon/perfmon_log.cc new file mode 100644 index 0000000..29d49c9 --- /dev/null +++ b/src/hooks/dhcp/perfmon/perfmon_log.cc @@ -0,0 +1,18 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 <config.h> + +#include <perfmon_log.h> + +namespace isc { +namespace perfmon { + +isc::log::Logger perfmon_logger("perfmon-hooks"); + +} +} + diff --git a/src/hooks/dhcp/perfmon/perfmon_log.h b/src/hooks/dhcp/perfmon/perfmon_log.h new file mode 100644 index 0000000..2f7f10c --- /dev/null +++ b/src/hooks/dhcp/perfmon/perfmon_log.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +#ifndef PERFMON_LOG_H +#define PERFMON_LOG_H + +#include <log/logger_support.h> +#include <log/macros.h> +#include <perfmon_messages.h> + +namespace isc { +namespace perfmon { + +extern isc::log::Logger perfmon_logger; + +} // end of isc::perfmon namespace +} // end of isc namespace + + +#endif diff --git a/src/hooks/dhcp/perfmon/perfmon_messages.cc b/src/hooks/dhcp/perfmon/perfmon_messages.cc new file mode 100644 index 0000000..1bb01f9 --- /dev/null +++ b/src/hooks/dhcp/perfmon/perfmon_messages.cc @@ -0,0 +1,33 @@ +// File created from ../../../../src/hooks/dhcp/perfmon/perfmon_messages.mes + +#include <cstddef> +#include <log/message_types.h> +#include <log/message_initializer.h> + +extern const isc::log::MessageID PERFMON_DEINIT_FAILED = "PERFMON_DEINIT_FAILED"; +extern const isc::log::MessageID PERFMON_DEINIT_OK = "PERFMON_DEINIT_OK"; +extern const isc::log::MessageID PERFMON_DHCP4_PKT_EVENTS = "PERFMON_DHCP4_PKT_EVENTS"; +extern const isc::log::MessageID PERFMON_DHCP4_SOCKET_RECEIVED_TIME_SUPPORT = "PERFMON_DHCP4_SOCKET_RECEIVED_TIME_SUPPORT"; +extern const isc::log::MessageID PERFMON_DHCP6_PKT_EVENTS = "PERFMON_DHCP6_PKT_EVENTS"; +extern const isc::log::MessageID PERFMON_DHCP6_SOCKET_RECEIVED_TIME_SUPPORT = "PERFMON_DHCP6_SOCKET_RECEIVED_TIME_SUPPORT"; +extern const isc::log::MessageID PERFMON_INIT_FAILED = "PERFMON_INIT_FAILED"; +extern const isc::log::MessageID PERFMON_INIT_OK = "PERFMON_INIT_OK"; + +namespace { + +const char* values[] = { + "PERFMON_DEINIT_FAILED", "unloading PerfMon hooks library failed: %1", + "PERFMON_DEINIT_OK", "unloading PerfMon hooks library successful", + "PERFMON_DHCP4_PKT_EVENTS", "query: %1 events=[%2]", + "PERFMON_DHCP4_SOCKET_RECEIVED_TIME_SUPPORT", "Kernel supports socket received time? %1", + "PERFMON_DHCP6_PKT_EVENTS", "query: %1 events=[%2]", + "PERFMON_DHCP6_SOCKET_RECEIVED_TIME_SUPPORT", "Kernel supports socket received time? %1", + "PERFMON_INIT_FAILED", "loading PerfMon hooks library failed: %1", + "PERFMON_INIT_OK", "loading PerfMon hooks library successful", + NULL +}; + +const isc::log::MessageInitializer initializer(values); + +} // Anonymous namespace + diff --git a/src/hooks/dhcp/perfmon/perfmon_messages.h b/src/hooks/dhcp/perfmon/perfmon_messages.h new file mode 100644 index 0000000..3fcb213 --- /dev/null +++ b/src/hooks/dhcp/perfmon/perfmon_messages.h @@ -0,0 +1,17 @@ +// File created from ../../../../src/hooks/dhcp/perfmon/perfmon_messages.mes + +#ifndef PERFMON_MESSAGES_H +#define PERFMON_MESSAGES_H + +#include <log/message_types.h> + +extern const isc::log::MessageID PERFMON_DEINIT_FAILED; +extern const isc::log::MessageID PERFMON_DEINIT_OK; +extern const isc::log::MessageID PERFMON_DHCP4_PKT_EVENTS; +extern const isc::log::MessageID PERFMON_DHCP4_SOCKET_RECEIVED_TIME_SUPPORT; +extern const isc::log::MessageID PERFMON_DHCP6_PKT_EVENTS; +extern const isc::log::MessageID PERFMON_DHCP6_SOCKET_RECEIVED_TIME_SUPPORT; +extern const isc::log::MessageID PERFMON_INIT_FAILED; +extern const isc::log::MessageID PERFMON_INIT_OK; + +#endif // PERFMON_MESSAGES_H diff --git a/src/hooks/dhcp/perfmon/perfmon_messages.mes b/src/hooks/dhcp/perfmon/perfmon_messages.mes new file mode 100644 index 0000000..053eab1 --- /dev/null +++ b/src/hooks/dhcp/perfmon/perfmon_messages.mes @@ -0,0 +1,43 @@ +# Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") + +% PERFMON_DEINIT_FAILED unloading PerfMon hooks library failed: %1 +This error message indicates an error unloading the PerfMon hooks +library. The details of the error are provided as argument of +the log message. + +% PERFMON_DEINIT_OK unloading PerfMon hooks library successful +This info message indicates that the PerfMon hooks library has been +removed successfully. + +% PERFMON_DHCP4_PKT_EVENTS query: %1 events=[%2] +This debug message is emitted after an inbound DHCPv4 query has been +processed, the arguments are the query label and the dump of the +query's packet event stack. + +% PERFMON_DHCP4_SOCKET_RECEIVED_TIME_SUPPORT Kernel supports socket received time? %1 +This debug message is emitted after a (re)configuration and indicates +whether or not the packet filter being used by kea-dhcp4 can supply +the timestamp a packet was received by the kernel for recording +SOCKET_RECEIVED events. If it does not, perfmon will still function but +will not have data available to determine kernel buffer wait times. + +% PERFMON_DHCP6_PKT_EVENTS query: %1 events=[%2] +The debug message is emitted after an inbound DHCPv6 query has been +processed, the arguments are the query label and the dump of the +query's packet event stack. + +% PERFMON_DHCP6_SOCKET_RECEIVED_TIME_SUPPORT Kernel supports socket received time? %1 +This debug message is emitted after a (re)configuration and indicates +whether or not the packet filter being used by kea-dhcp6 can supply +the timestamp a packet was received by the kernel for recording +SOCKET_RECEIVED events. If it does not, perfmon will still function but +will not have data available to determine kernel buffer wait times. + +% PERFMON_INIT_FAILED loading PerfMon hooks library failed: %1 +This error message indicates an error during loading the PerfMon +hooks library. The details of the error are provided as argument of +the log message. + +% PERFMON_INIT_OK loading PerfMon hooks library successful +This info message indicates that the PerfMon hooks library has been +loaded successfully. Enjoy! diff --git a/src/hooks/dhcp/perfmon/tests/Makefile.am b/src/hooks/dhcp/perfmon/tests/Makefile.am new file mode 100644 index 0000000..e74c1d8 --- /dev/null +++ b/src/hooks/dhcp/perfmon/tests/Makefile.am @@ -0,0 +1,59 @@ +SUBDIRS = . + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/perfmon -I$(top_srcdir)/src/hooks/dhcp/perfmon +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CPPFLAGS += -DPERFMON_LIB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/perfmon/.libs/libdhcp_perfmon.so\" +AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\" + +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +# Unit test data files need to get installed. +EXTRA_DIST = + +CLEANFILES = *.gcno *.gcda + +TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) + +LOG_COMPILER = $(LIBTOOL) +AM_LOG_FLAGS = --mode=execute + +TESTS = +if HAVE_GTEST +TESTS += perfmon_unittests + +perfmon_unittests_SOURCES = run_unittests.cc +perfmon_unittests_SOURCES += monitored_duration_unittests.cc +perfmon_unittests_SOURCES += alarm_unittests.cc +perfmon_unittests_SOURCES += monitored_duration_store_unittests.cc +perfmon_unittests_SOURCES += alarm_store_unittests.cc + +perfmon_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) + +perfmon_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) + +perfmon_unittests_CXXFLAGS = $(AM_CXXFLAGS) + +perfmon_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/perfmon/libperfmon.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la +perfmon_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +perfmon_unittests_LDADD += $(LOG4CPLUS_LIBS) +perfmon_unittests_LDADD += $(CRYPTO_LIBS) +perfmon_unittests_LDADD += $(BOOST_LIBS) +perfmon_unittests_LDADD += $(GTEST_LDADD) +endif +noinst_PROGRAMS = $(TESTS) diff --git a/src/hooks/dhcp/perfmon/tests/Makefile.in b/src/hooks/dhcp/perfmon/tests/Makefile.in new file mode 100644 index 0000000..49040f2 --- /dev/null +++ b/src/hooks/dhcp/perfmon/tests/Makefile.in @@ -0,0 +1,1092 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +TESTS = $(am__EXEEXT_1) +@HAVE_GTEST_TRUE@am__append_1 = perfmon_unittests +noinst_PROGRAMS = $(am__EXEEXT_2) +subdir = src/hooks/dhcp/perfmon/tests +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ + $(top_srcdir)/m4macros/ax_cpp14.m4 \ + $(top_srcdir)/m4macros/ax_cpp20.m4 \ + $(top_srcdir)/m4macros/ax_crypto.m4 \ + $(top_srcdir)/m4macros/ax_find_library.m4 \ + $(top_srcdir)/m4macros/ax_gssapi.m4 \ + $(top_srcdir)/m4macros/ax_gtest.m4 \ + $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ + $(top_srcdir)/m4macros/ax_netconf.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@HAVE_GTEST_TRUE@am__EXEEXT_1 = perfmon_unittests$(EXEEXT) +am__EXEEXT_2 = $(am__EXEEXT_1) +PROGRAMS = $(noinst_PROGRAMS) +am__perfmon_unittests_SOURCES_DIST = run_unittests.cc \ + monitored_duration_unittests.cc alarm_unittests.cc \ + monitored_duration_store_unittests.cc alarm_store_unittests.cc +@HAVE_GTEST_TRUE@am_perfmon_unittests_OBJECTS = \ +@HAVE_GTEST_TRUE@ perfmon_unittests-run_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ perfmon_unittests-monitored_duration_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ perfmon_unittests-alarm_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ perfmon_unittests-monitored_duration_store_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ perfmon_unittests-alarm_store_unittests.$(OBJEXT) +perfmon_unittests_OBJECTS = $(am_perfmon_unittests_OBJECTS) +am__DEPENDENCIES_1 = +@HAVE_GTEST_TRUE@perfmon_unittests_DEPENDENCIES = $(top_builddir)/src/hooks/dhcp/perfmon/libperfmon.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +perfmon_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) \ + $(perfmon_unittests_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = \ + ./$(DEPDIR)/perfmon_unittests-alarm_store_unittests.Po \ + ./$(DEPDIR)/perfmon_unittests-alarm_unittests.Po \ + ./$(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Po \ + ./$(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Po \ + ./$(DEPDIR)/perfmon_unittests-run_unittests.Po +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(perfmon_unittests_SOURCES) +DIST_SOURCES = $(am__perfmon_unittests_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + fi; \ +} +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASCIIDOC = @ASCIIDOC@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_INCLUDES = @BOOST_INCLUDES@ +BOOST_LIBS = @BOOST_LIBS@ +BOTAN_TOOL = @BOTAN_TOOL@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONTRIB_DIR = @CONTRIB_DIR@ +CPPFLAGS = @CPPFLAGS@ +CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ +CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ +CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ +CRYPTO_LIBS = @CRYPTO_LIBS@ +CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ +CRYPTO_RPATH = @CRYPTO_RPATH@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ +DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@ +DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ +DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@ +DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ +DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@ +DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@ +DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@ +DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@ +DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@ +DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@ +DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@ +DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@ +DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@ +DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@ +DLLTOOL = @DLLTOOL@ +DPKG = @DPKG@ +DPKGQUERY = @DPKGQUERY@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GENHTML = @GENHTML@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_INCLUDES = @GTEST_INCLUDES@ +GTEST_LDADD = @GTEST_LDADD@ +GTEST_LDFLAGS = @GTEST_LDFLAGS@ +GTEST_SOURCE = @GTEST_SOURCE@ +HAVE_NETCONF = @HAVE_NETCONF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KEA_CXXFLAGS = @KEA_CXXFLAGS@ +KEA_SRCID = @KEA_SRCID@ +KRB5_CONFIG = @KRB5_CONFIG@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@ +LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@ +LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@ +LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@ +LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@ +LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@ +LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@ +LIBYANG_LIBS = @LIBYANG_LIBS@ +LIBYANG_PREFIX = @LIBYANG_PREFIX@ +LIBYANG_VERSION = @LIBYANG_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ +LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LIBS = @MYSQL_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ +PERL = @PERL@ +PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PKGPYTHONDIR = @PKGPYTHONDIR@ +PKG_CONFIG = @PKG_CONFIG@ +PLANTUML = @PLANTUML@ +PREMIUM_DIR = @PREMIUM_DIR@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SEP = @SEP@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPHINXBUILD = @SPHINXBUILD@ +SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@ +SR_PLUGINS_PATH = @SR_PLUGINS_PATH@ +SR_REPO_PATH = @SR_REPO_PATH@ +STRIP = @STRIP@ +SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@ +SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@ +SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@ +SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@ +SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@ +SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@ +SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@ +SYSREPO_LIBS = @SYSREPO_LIBS@ +SYSREPO_PREFIX = @SYSREPO_PREFIX@ +SYSREPO_VERSION = @SYSREPO_VERSION@ +USE_LCOV = @USE_LCOV@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ +XMLLINT = @XMLLINT@ +YACC = @YACC@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \ + -I$(top_builddir)/src/hooks/dhcp/perfmon \ + -I$(top_srcdir)/src/hooks/dhcp/perfmon $(BOOST_INCLUDES) \ + -DPERFMON_LIB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/perfmon/.libs/libdhcp_perfmon.so\" \ + -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\" +AM_CXXFLAGS = $(KEA_CXXFLAGS) +@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static + +# Unit test data files need to get installed. +EXTRA_DIST = +CLEANFILES = *.gcno *.gcda +TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) +LOG_COMPILER = $(LIBTOOL) +AM_LOG_FLAGS = --mode=execute +@HAVE_GTEST_TRUE@perfmon_unittests_SOURCES = run_unittests.cc \ +@HAVE_GTEST_TRUE@ monitored_duration_unittests.cc \ +@HAVE_GTEST_TRUE@ alarm_unittests.cc \ +@HAVE_GTEST_TRUE@ monitored_duration_store_unittests.cc \ +@HAVE_GTEST_TRUE@ alarm_store_unittests.cc +@HAVE_GTEST_TRUE@perfmon_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) +@HAVE_GTEST_TRUE@perfmon_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) +@HAVE_GTEST_TRUE@perfmon_unittests_CXXFLAGS = $(AM_CXXFLAGS) +@HAVE_GTEST_TRUE@perfmon_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/perfmon/libperfmon.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) \ +@HAVE_GTEST_TRUE@ $(BOOST_LIBS) $(GTEST_LDADD) +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/hooks/dhcp/perfmon/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hooks/dhcp/perfmon/tests/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +perfmon_unittests$(EXEEXT): $(perfmon_unittests_OBJECTS) $(perfmon_unittests_DEPENDENCIES) $(EXTRA_perfmon_unittests_DEPENDENCIES) + @rm -f perfmon_unittests$(EXEEXT) + $(AM_V_CXXLD)$(perfmon_unittests_LINK) $(perfmon_unittests_OBJECTS) $(perfmon_unittests_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perfmon_unittests-alarm_store_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perfmon_unittests-alarm_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perfmon_unittests-run_unittests.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +perfmon_unittests-run_unittests.o: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/perfmon_unittests-run_unittests.Tpo -c -o perfmon_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-run_unittests.Tpo $(DEPDIR)/perfmon_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='perfmon_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc + +perfmon_unittests-run_unittests.obj: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/perfmon_unittests-run_unittests.Tpo -c -o perfmon_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-run_unittests.Tpo $(DEPDIR)/perfmon_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='perfmon_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` + +perfmon_unittests-monitored_duration_unittests.o: monitored_duration_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-monitored_duration_unittests.o -MD -MP -MF $(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Tpo -c -o perfmon_unittests-monitored_duration_unittests.o `test -f 'monitored_duration_unittests.cc' || echo '$(srcdir)/'`monitored_duration_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Tpo $(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='monitored_duration_unittests.cc' object='perfmon_unittests-monitored_duration_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-monitored_duration_unittests.o `test -f 'monitored_duration_unittests.cc' || echo '$(srcdir)/'`monitored_duration_unittests.cc + +perfmon_unittests-monitored_duration_unittests.obj: monitored_duration_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-monitored_duration_unittests.obj -MD -MP -MF $(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Tpo -c -o perfmon_unittests-monitored_duration_unittests.obj `if test -f 'monitored_duration_unittests.cc'; then $(CYGPATH_W) 'monitored_duration_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/monitored_duration_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Tpo $(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='monitored_duration_unittests.cc' object='perfmon_unittests-monitored_duration_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-monitored_duration_unittests.obj `if test -f 'monitored_duration_unittests.cc'; then $(CYGPATH_W) 'monitored_duration_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/monitored_duration_unittests.cc'; fi` + +perfmon_unittests-alarm_unittests.o: alarm_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-alarm_unittests.o -MD -MP -MF $(DEPDIR)/perfmon_unittests-alarm_unittests.Tpo -c -o perfmon_unittests-alarm_unittests.o `test -f 'alarm_unittests.cc' || echo '$(srcdir)/'`alarm_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-alarm_unittests.Tpo $(DEPDIR)/perfmon_unittests-alarm_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='alarm_unittests.cc' object='perfmon_unittests-alarm_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-alarm_unittests.o `test -f 'alarm_unittests.cc' || echo '$(srcdir)/'`alarm_unittests.cc + +perfmon_unittests-alarm_unittests.obj: alarm_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-alarm_unittests.obj -MD -MP -MF $(DEPDIR)/perfmon_unittests-alarm_unittests.Tpo -c -o perfmon_unittests-alarm_unittests.obj `if test -f 'alarm_unittests.cc'; then $(CYGPATH_W) 'alarm_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/alarm_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-alarm_unittests.Tpo $(DEPDIR)/perfmon_unittests-alarm_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='alarm_unittests.cc' object='perfmon_unittests-alarm_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-alarm_unittests.obj `if test -f 'alarm_unittests.cc'; then $(CYGPATH_W) 'alarm_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/alarm_unittests.cc'; fi` + +perfmon_unittests-monitored_duration_store_unittests.o: monitored_duration_store_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-monitored_duration_store_unittests.o -MD -MP -MF $(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Tpo -c -o perfmon_unittests-monitored_duration_store_unittests.o `test -f 'monitored_duration_store_unittests.cc' || echo '$(srcdir)/'`monitored_duration_store_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Tpo $(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='monitored_duration_store_unittests.cc' object='perfmon_unittests-monitored_duration_store_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-monitored_duration_store_unittests.o `test -f 'monitored_duration_store_unittests.cc' || echo '$(srcdir)/'`monitored_duration_store_unittests.cc + +perfmon_unittests-monitored_duration_store_unittests.obj: monitored_duration_store_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-monitored_duration_store_unittests.obj -MD -MP -MF $(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Tpo -c -o perfmon_unittests-monitored_duration_store_unittests.obj `if test -f 'monitored_duration_store_unittests.cc'; then $(CYGPATH_W) 'monitored_duration_store_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/monitored_duration_store_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Tpo $(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='monitored_duration_store_unittests.cc' object='perfmon_unittests-monitored_duration_store_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-monitored_duration_store_unittests.obj `if test -f 'monitored_duration_store_unittests.cc'; then $(CYGPATH_W) 'monitored_duration_store_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/monitored_duration_store_unittests.cc'; fi` + +perfmon_unittests-alarm_store_unittests.o: alarm_store_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-alarm_store_unittests.o -MD -MP -MF $(DEPDIR)/perfmon_unittests-alarm_store_unittests.Tpo -c -o perfmon_unittests-alarm_store_unittests.o `test -f 'alarm_store_unittests.cc' || echo '$(srcdir)/'`alarm_store_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-alarm_store_unittests.Tpo $(DEPDIR)/perfmon_unittests-alarm_store_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='alarm_store_unittests.cc' object='perfmon_unittests-alarm_store_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-alarm_store_unittests.o `test -f 'alarm_store_unittests.cc' || echo '$(srcdir)/'`alarm_store_unittests.cc + +perfmon_unittests-alarm_store_unittests.obj: alarm_store_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -MT perfmon_unittests-alarm_store_unittests.obj -MD -MP -MF $(DEPDIR)/perfmon_unittests-alarm_store_unittests.Tpo -c -o perfmon_unittests-alarm_store_unittests.obj `if test -f 'alarm_store_unittests.cc'; then $(CYGPATH_W) 'alarm_store_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/alarm_store_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/perfmon_unittests-alarm_store_unittests.Tpo $(DEPDIR)/perfmon_unittests-alarm_store_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='alarm_store_unittests.cc' object='perfmon_unittests-alarm_store_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(perfmon_unittests_CPPFLAGS) $(CPPFLAGS) $(perfmon_unittests_CXXFLAGS) $(CXXFLAGS) -c -o perfmon_unittests-alarm_store_unittests.obj `if test -f 'alarm_store_unittests.cc'; then $(CYGPATH_W) 'alarm_store_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/alarm_store_unittests.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/perfmon_unittests-alarm_store_unittests.Po + -rm -f ./$(DEPDIR)/perfmon_unittests-alarm_unittests.Po + -rm -f ./$(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Po + -rm -f ./$(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Po + -rm -f ./$(DEPDIR)/perfmon_unittests-run_unittests.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/perfmon_unittests-alarm_store_unittests.Po + -rm -f ./$(DEPDIR)/perfmon_unittests-alarm_unittests.Po + -rm -f ./$(DEPDIR)/perfmon_unittests-monitored_duration_store_unittests.Po + -rm -f ./$(DEPDIR)/perfmon_unittests-monitored_duration_unittests.Po + -rm -f ./$(DEPDIR)/perfmon_unittests-run_unittests.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) check-am install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-TESTS check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/hooks/dhcp/perfmon/tests/alarm_store_unittests.cc b/src/hooks/dhcp/perfmon/tests/alarm_store_unittests.cc new file mode 100644 index 0000000..270f0a9 --- /dev/null +++ b/src/hooks/dhcp/perfmon/tests/alarm_store_unittests.cc @@ -0,0 +1,511 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +/// @file This file contains tests which exercise the AlarmStore class. +#include <config.h> +#include <alarm_store.h> +#include <dhcp/dhcp6.h> +#include <testutils/gtest_utils.h> +#include <testutils/multi_threading_utils.h> + +#include <gtest/gtest.h> +#include <sstream> + +using namespace std; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfmon; +using namespace isc::test; +using namespace boost::posix_time; + +namespace { + +// Verifies AlarmStore valid construction. +TEST(AlarmStore, validConstructors) { + AlarmStorePtr store; + + // Construct and verify v4 store. + EXPECT_NO_THROW_LOG(store.reset(new AlarmStore(AF_INET))); + ASSERT_TRUE(store); + EXPECT_EQ(store->getFamily(), AF_INET); + + AlarmCollectionPtr alarms; + ASSERT_NO_THROW_LOG(alarms = store->getAll()); + ASSERT_TRUE(alarms); + EXPECT_TRUE(alarms->empty()); + + // Construct and verify v6 store. + EXPECT_NO_THROW_LOG(store.reset(new AlarmStore(AF_INET6))); + ASSERT_TRUE(store); + EXPECT_EQ(store->getFamily(), AF_INET6); + + ASSERT_NO_THROW_LOG(alarms = store->getAll()); + ASSERT_TRUE(alarms); + EXPECT_TRUE(alarms->empty()); +} + +// Verifies AlarmStore invalid construction. +TEST(AlarmStore, invalidConstructors) { + AlarmStorePtr store; + + // Invalid family should throw. + EXPECT_THROW_MSG(AlarmStore(777), + BadValue, + "AlarmStore - invalid family 777, must be AF_INET or AF_INET6"); +} + +/// @brief Text fixture class for @c AlarmStore +/// +/// In order to facilitate single and multi threaded testing, +/// individual tests are implemented as methods that are called +/// from within TEST_F bodies rather than in TEST_F bodies. +class AlarmStoreTest : public ::testing::Test { +public: + + /// @brief Constructor + AlarmStoreTest() = default; + + /// @brief Destructor + virtual ~AlarmStoreTest() = default; + + /// @brief Creates a protocol-specific DurationKey for a given subnet + /// + /// The message-pair and socket-event pairs are fixed. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + /// @param subnet SubnetID of the duration + DurationKeyPtr makeKey(uint16_t family, SubnetID subnet = 1) { + DurationKeyPtr key; + if (family == AF_INET) { + return (DurationKeyPtr(new DurationKey(AF_INET, DHCPDISCOVER, DHCPOFFER, + "socket_received", "buffer_read", subnet))); + } + + return (DurationKeyPtr(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_REPLY, + "socket_received", "buffer_read", subnet))); + } + + /// @brief Verifies that alarms can be added to the store and fetched + /// by DurationKey. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void addAlarmTest(uint16_t family) { + Duration low_water(milliseconds(10)); + Duration high_water(milliseconds(250)); + AlarmStore store(family); + + // Add four alarms with decreaing subnet ids. + std::vector<AlarmPtr> orig_alarms; + for (int subnet = 4; subnet > 0; --subnet) { + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm = store.addAlarm(makeKey(family, subnet), + low_water, high_water)); + ASSERT_TRUE(alarm); + orig_alarms.push_back(alarm); + } + + // Get all should retrieve all four in ascending order. + AlarmCollectionPtr alarms = store.getAll(); + ASSERT_EQ(alarms->size(), orig_alarms.size()); + + int idx = orig_alarms.size() - 1; + for (auto const& d : *alarms) { + EXPECT_EQ(*d, *orig_alarms[idx]) << "failed on pass :" << idx; + --idx; + } + + // Make sure we can fetch them all individually. + for (auto const& alarm : orig_alarms) { + AlarmPtr found; + ASSERT_NO_THROW_LOG(found = store.getAlarm(alarm)); + ASSERT_TRUE(found); + EXPECT_EQ(*alarm, *found); + } + + // Verify that clear() discards store contents. + store.clear(); + alarms = store.getAll(); + ASSERT_TRUE(alarms->empty()); + } + + /// @brief Verifies that duplicate alarms cannot be added to the store. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void addAlarmDuplicateTest(uint16_t family) { + AlarmStore store(family); + + // Add an alarm. + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm = store.addAlarm(makeKey(family), milliseconds(10), + milliseconds(250))); + ASSERT_TRUE(alarm); + + // Attempting to add it again should evoke a duplicate key exception. + ASSERT_THROW(store.addAlarm(alarm), DuplicateAlarm); + } + + /// @brief Verifies that duration key must be valid to add an alarm to the store. + /// + /// Tests both v4 and v6. + void addAlarmInvalidTest() { + // Create a v4 store. + AlarmStorePtr store(new AlarmStore(AF_INET)); + + // Attempting to add with an empty key should throw. + ASSERT_THROW_MSG(store->addAlarm(DurationKeyPtr(), + milliseconds(10), milliseconds(250)), + BadValue, + "AlarmStore::addAlarm - key is empty"); + + // Attempting to add a v6 key should fail. + ASSERT_THROW_MSG(store->addAlarm(makeKey(AF_INET6), + milliseconds(10), milliseconds(250)), + BadValue, + "AlarmStore::addAlarm" + " - family mismatch, key is v6, store is v4"); + + // Create a v6 store. + store.reset(new AlarmStore(AF_INET6)); + + // Attempting to add a v4 key should fail. + ASSERT_THROW_MSG(store->addAlarm(makeKey(AF_INET), + milliseconds(10), milliseconds(250)), + BadValue, + "AlarmStore::addAlarm" + " - family mismatch, key is v4, store is v6"); + } + + /// @brief Verify that alarms can be deleted from the store. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void deleteAlarmTest(uint16_t family) { + AlarmStore store(family); + + std::vector<DurationKeyPtr> keys; + for (int subnet = 0; subnet < 3; ++subnet) { + AlarmPtr alarm; + DurationKeyPtr key = makeKey(family, subnet); + ASSERT_NO_THROW_LOG(alarm = store.addAlarm(key, milliseconds(10), milliseconds(250))); + ASSERT_TRUE(alarm); + keys.push_back(key); + } + + // Verify we added three of them. + auto alarms = store.getAll(); + ASSERT_EQ(alarms->size(), 3); + + // Fetch the second alarm. + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm = store.getAlarm(keys[1])); + ASSERT_TRUE(alarm); + EXPECT_EQ(*alarm, *(keys[1])); + + // Delete it. + ASSERT_NO_THROW_LOG(store.deleteAlarm(alarm)); + + // Try to fetch it, shouldn't find it. + AlarmPtr alarm2; + ASSERT_NO_THROW_LOG(alarm2 = store.getAlarm(alarm)); + ASSERT_FALSE(alarm2); + + // Deleting it again should do no harm. + ASSERT_NO_THROW_LOG(store.deleteAlarm(alarm)); + + // Verify there are two left. + alarms = store.getAll(); + ASSERT_EQ(alarms->size(), 2); + } + + /// @brief Verify an invalid alarm key on delete is detected. + /// + /// Tests both v4 and v6. + void deleteAlarmInvalidTest() { + // Create a v4 store. + AlarmStorePtr store(new AlarmStore(AF_INET)); + + // Attempting to delete an empty key should throw. + DurationKeyPtr key; + ASSERT_THROW_MSG(store->deleteAlarm(key), + BadValue, + "AlarmStore::deleteAlarm - key is empty"); + + // Attempting to delete a v6 key should fail. + ASSERT_THROW_MSG(store->deleteAlarm(makeKey(AF_INET6)), + BadValue, + "AlarmStore::deleteAlarm" + " - family mismatch, key is v6, store is v4"); + + // Create a v6 store. + store.reset(new AlarmStore(AF_INET6)); + + // Attempting to delete a v4 key should fail. + ASSERT_THROW_MSG(store->deleteAlarm(makeKey(AF_INET)), + BadValue, + "AlarmStore::deleteAlarm" + " - family mismatch, key is v4, store is v6"); + } + + /// @brief Verify that alarms in the store can be updated. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void updateAlarmTest(uint16_t family) { + AlarmStore store(family); + + // Add the alarm to the store. + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(*makeKey(family), milliseconds(10), + milliseconds(250)))); + ASSERT_NO_THROW_LOG(store.addAlarm(alarm)); + + // Fetch it. + AlarmPtr found; + ASSERT_NO_THROW_LOG(found = store.getAlarm(alarm)); + ASSERT_TRUE(found); + + // Verify the fetched object is a copy. + ASSERT_NE(found, alarm); + ASSERT_EQ(*found, *alarm); + + // Now change the thresholds and update it. + alarm->setLowWater(milliseconds(125)); + alarm->setHighWater(milliseconds(500)); + ASSERT_NO_THROW_LOG(store.updateAlarm(alarm)); + + // Fetch it again. + ASSERT_NO_THROW_LOG(found = store.getAlarm(alarm)); + + // Verify it has the expected thresholds. + EXPECT_EQ(found->getLowWater(), milliseconds(125)); + EXPECT_EQ(found->getHighWater(), milliseconds(500)); + } + + /// @brief Verify an invalid alarm key on update is detected. + /// + /// Tests both v4 and v6. + void updateAlarmInvalidTest() { + AlarmPtr alarm; + + // Create a v4 store. + AlarmStorePtr store(new AlarmStore(AF_INET)); + + // Attempting to update an empty key should throw. + ASSERT_THROW_MSG(store->updateAlarm(alarm), + BadValue, + "AlarmStore::updateAlarm - key is empty"); + + // Create a v6 alarm. + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(*makeKey(AF_INET6), milliseconds(10), + milliseconds(250)))); + + // Attempting to update v6 alarm to a v4 store should fail. + ASSERT_THROW_MSG(store->updateAlarm(alarm), + BadValue, + "AlarmStore::updateAlarm" + " - family mismatch, key is v6, store is v4"); + + // Create a v6 store. + store.reset(new AlarmStore(AF_INET6)); + + // Updating a non-existent alarm should fail. + ASSERT_THROW_MSG(store->updateAlarm(alarm), + InvalidOperation, + "AlarmStore::updateAlarm alarm not found:" + " SOLICIT-REPLY.socket_received-buffer_read.1"); + + // Create a v4 alarm. + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(*makeKey(AF_INET), milliseconds(10), + milliseconds(250)))); + + // Attempting to update v4 alarm to a v6 store fail. + ASSERT_THROW_MSG(store->updateAlarm(alarm), + BadValue, + "AlarmStore::updateAlarm" + " - family mismatch, key is v4, store is v6"); + } + + /// @brief Verify checkDurationSample() valid behavior. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void checkDurationSampleTest(uint16_t family) { + AlarmStore store(family); + + Duration under_low_water(milliseconds(50)); + Duration low_water(milliseconds(100)); + Duration mid_range(milliseconds(175)); + Duration high_water(milliseconds(250)); + Duration over_high_water(milliseconds(300)); + Duration report_interval(milliseconds(10)); + + DurationKeyPtr key(makeKey(family)); + AlarmPtr reportable; + ASSERT_NO_THROW_LOG(reportable = store.checkDurationSample(key, over_high_water, + report_interval)); + ASSERT_FALSE(reportable); + + // Add an alarm for the key to the store. + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(*key, low_water, high_water))); + ASSERT_NO_THROW_LOG(store.addAlarm(alarm)); + + // Fetch it. + AlarmPtr found; + ASSERT_NO_THROW_LOG(found = store.getAlarm(alarm)); + ASSERT_TRUE(found); + + // Check a sample at mid range. Should not return the alarm. + ASSERT_NO_THROW_LOG(reportable = store.checkDurationSample(key, mid_range, + report_interval)); + ASSERT_FALSE(reportable); + + // Check a sample over high water. Should return the alarm. + ASSERT_NO_THROW_LOG(reportable = store.checkDurationSample(key, over_high_water, + report_interval)); + ASSERT_TRUE(reportable); + EXPECT_EQ(reportable->getState(), Alarm::TRIGGERED); + + // Check a sample over high water but before report interval elapses. + // Should not return the alarm. + ASSERT_NO_THROW_LOG(reportable = store.checkDurationSample(key, over_high_water, + report_interval)); + ASSERT_FALSE(reportable); + + // Sleep beyond the report interval. + usleep(15 * 1000); + + // Check a sample over high water after report interval elapses. + // Should return the alarm. + ASSERT_NO_THROW_LOG(reportable = store.checkDurationSample(key, over_high_water, + report_interval)); + ASSERT_TRUE(reportable); + EXPECT_EQ(reportable->getState(), Alarm::TRIGGERED); + + // Check a sample below low water. + // Should return the alarm. + ASSERT_NO_THROW_LOG(reportable = store.checkDurationSample(key, under_low_water, + report_interval)); + ASSERT_TRUE(reportable); + EXPECT_EQ(reportable->getState(), Alarm::CLEAR); + } +}; + +TEST_F(AlarmStoreTest, addAlarm) { + addAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, addAlarmMultiThreading) { + MultiThreadingTest mt; + addAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, addAlarm6) { + addAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, addAlarm6MultiThreading) { + MultiThreadingTest mt; + addAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, addAlarmDuplicate) { + addAlarmDuplicateTest(AF_INET); +} + +TEST_F(AlarmStoreTest, addAlarmDuplicateMultiThreading) { + MultiThreadingTest mt; + addAlarmDuplicateTest(AF_INET); +} + +TEST_F(AlarmStoreTest, addAlarm6Duplicate) { + addAlarmDuplicateTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, addAlarm6DuplicateMultiThreading) { + MultiThreadingTest mt; + addAlarmDuplicateTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, addAlarmInvalid) { + addAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, addAlarmInvalidMultiThreading) { + MultiThreadingTest mt; + addAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, deleteAlarm) { + deleteAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, deleteAlarmMultiThreading) { + MultiThreadingTest mt; + deleteAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, deleteAlarm6) { + deleteAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, deleteAlarm6MultiThreading) { + MultiThreadingTest mt; + deleteAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, deleteAlarmInvalid) { + deleteAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, deleteAlarmInvalidMultiThreading) { + MultiThreadingTest mt; + deleteAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, updateAlarm) { + updateAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, updateAlarmMultiThreading) { + MultiThreadingTest mt; + updateAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, updateAlarm6) { + updateAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, updateAlarm6MultiThreading) { + MultiThreadingTest mt; + updateAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, updateAlarmInvalid) { + updateAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, updateAlarmInvalidMultiThreading) { + MultiThreadingTest mt; + updateAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, checkDurationSample) { + checkDurationSampleTest(AF_INET); +} + +TEST_F(AlarmStoreTest, checkDurationSampleMultiThreading) { + MultiThreadingTest mt; + checkDurationSampleTest(AF_INET); +} + +TEST_F(AlarmStoreTest, checkDurationSample6) { + checkDurationSampleTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, checkDurationSample6MultiThreading) { + MultiThreadingTest mt; + checkDurationSampleTest(AF_INET6); +} + +} // end of anonymous namespace diff --git a/src/hooks/dhcp/perfmon/tests/alarm_unittests.cc b/src/hooks/dhcp/perfmon/tests/alarm_unittests.cc new file mode 100644 index 0000000..0814dc4 --- /dev/null +++ b/src/hooks/dhcp/perfmon/tests/alarm_unittests.cc @@ -0,0 +1,328 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 <config.h> +#include <alarm.h> +#include <dhcp/dhcp6.h> +#include <testutils/gtest_utils.h> + +#include <gtest/gtest.h> +#include <sstream> +#include <unordered_set> + +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfmon; +using namespace boost::posix_time; + +namespace { + +// Verifies Alarm construction. +TEST(Alarm, validConstructors) { + AlarmPtr alarm; + + auto start_time = PktEvent::now(); + + // Create valid v4 alarm, verify contents and label. + Duration low_water(milliseconds(50)); + Duration high_water(milliseconds(250)); + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, + low_water, high_water))); + ASSERT_TRUE(alarm); + EXPECT_EQ(alarm->getFamily(), AF_INET); + EXPECT_EQ(alarm->getQueryType(), DHCPDISCOVER); + EXPECT_EQ(alarm->getResponseType(), DHCPOFFER); + EXPECT_EQ(alarm->getStartEventLabel(), "process_started"); + EXPECT_EQ(alarm->getStopEventLabel(), "process_completed"); + EXPECT_EQ(alarm->getSubnetId(), SUBNET_ID_GLOBAL); + EXPECT_EQ("DHCPDISCOVER-DHCPOFFER.process_started-process_completed.0", alarm->getLabel()); + EXPECT_EQ(alarm->getSubnetId(), SUBNET_ID_GLOBAL); + EXPECT_EQ(alarm->getLowWater(), low_water); + EXPECT_EQ(alarm->getHighWater(), high_water); + EXPECT_EQ(alarm->getState(), Alarm::CLEAR); + EXPECT_GE(alarm->getStosTime(), start_time); + + start_time = PktEvent::now(); + + // Create valid v6 key and use that to create an alarm. Verify contents and label. + DurationKeyPtr key; + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(*key, low_water, high_water, false))); + ASSERT_TRUE(alarm); + EXPECT_EQ(alarm->getFamily(), AF_INET6); + EXPECT_EQ(alarm->getQueryType(), DHCPV6_SOLICIT); + EXPECT_EQ(alarm->getResponseType(), DHCPV6_ADVERTISE); + EXPECT_EQ(alarm->getStartEventLabel(), "mt_queued"); + EXPECT_EQ(alarm->getStopEventLabel(), "process_started"); + EXPECT_EQ(alarm->getSubnetId(), 77); + EXPECT_EQ("SOLICIT-ADVERTISE.mt_queued-process_started.77", alarm->getLabel()); + EXPECT_EQ(alarm->getLowWater(), low_water); + EXPECT_EQ(alarm->getHighWater(), high_water); + EXPECT_EQ(alarm->getState(), Alarm::DISABLED); + EXPECT_GE(alarm->getStosTime(), start_time); +} + +// Verifies Alarm invalid construction. +TEST(Alarm, invalidConstructors) { + AlarmPtr alarm; + + // Make sure we catch an invalid message pairing. + Duration low_water(milliseconds(50)); + Duration high_water(milliseconds(250)); + ASSERT_THROW_MSG(alarm.reset(new Alarm(AF_INET, DHCPDISCOVER, DHCPDISCOVER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, low_water, high_water)), + BadValue, + "Response type: DHCPDISCOVER not valid for query type: DHCPDISCOVER"); + + // Low water too high, should throw. + ASSERT_THROW_MSG(alarm.reset(new Alarm(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, high_water, low_water)), + BadValue, + "low water: 00:00:00.250000, must be less than high water:" + " 00:00:00.050000"); + + // Create valid v6 key. + DurationKeyPtr key; + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + + // Low water too high, should throw. + ASSERT_THROW_MSG(alarm.reset(new Alarm(*key, high_water, low_water)), + BadValue, + "low water: 00:00:00.250000, must be less than high water:" + " 00:00:00.050000"); +} + +TEST(Alarm, lowWaterHighWaterSetters) { + // Create valid v4 alarm. + Duration low_water(milliseconds(50)); + Duration high_water(milliseconds(250)); + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, + low_water, high_water))); + + // Should be able to set thresholds to new, valid values. + low_water += milliseconds(50); + high_water -= milliseconds(100); + ASSERT_NO_THROW(alarm->setLowWater(low_water)); + EXPECT_EQ(alarm->getLowWater(), low_water); + ASSERT_NO_THROW(alarm->setHighWater(high_water)); + EXPECT_EQ(alarm->getHighWater(), high_water); + + // Setting low too high should fail and leave Alarm intact. + ASSERT_THROW_MSG(alarm->setLowWater(high_water), BadValue, + "low water: 00:00:00.150000, must be less than high water: 00:00:00.150000"); + EXPECT_EQ(alarm->getLowWater(), low_water); + + // Setting high too low should fail and leave Alarm intact. + ASSERT_THROW_MSG(alarm->setHighWater(low_water), BadValue, + "high water: 00:00:00.100000, must be greater than low water: 00:00:00.100000"); + EXPECT_EQ(alarm->getHighWater(), high_water); +} + +TEST(Alarm, clearAndDisable) { + auto start_time = PktEvent::now(); + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, milliseconds(100), milliseconds(200)))); + + // Initial state should be CLEAR, stos_time_ should be close to now, no report time. + EXPECT_EQ(alarm->getState(), Alarm::CLEAR); + EXPECT_GE(alarm->getStosTime(), start_time); + EXPECT_EQ(alarm->getLastHighWaterReport(), PktEvent::EMPTY_TIME()); + + // Save stos then nap. + auto prev_time = alarm->getStosTime(); + usleep(100); + + // Change the state to DISABLED. Should have a later stos_time_. + ASSERT_NO_THROW(alarm->disable()); + EXPECT_EQ(alarm->getState(), Alarm::DISABLED); + EXPECT_GE(alarm->getStosTime(), prev_time); + EXPECT_EQ(alarm->getLastHighWaterReport(), PktEvent::EMPTY_TIME()); + + // While we're disabled verify operations that are not allowed. + ASSERT_THROW_MSG(alarm->checkSample(milliseconds(75), seconds(60)), InvalidOperation, + "Alarm::checkSample() - should not be called when alarm is DISABLED"); + + // Save stos then nap. + prev_time = alarm->getStosTime(); + usleep(100); + + // Restore the alarm to CLEAR. + ASSERT_NO_THROW(alarm->clear()); + EXPECT_EQ(alarm->getState(), Alarm::CLEAR); + EXPECT_GE(alarm->getStosTime(), prev_time); + EXPECT_EQ(alarm->getLastHighWaterReport(), PktEvent::EMPTY_TIME()); +} + +// Verifies the result of Alarm::checkSample() over the range of scenarios. +// The alarm is created in either the CLEAR or TRIGGERED state and then checkSample() +// is invoked. The scenarios tested are described by the table below: +// +// ``` +// INPUT | OUTPUT +// Test sample relationship Input Report Int.| +// to the thresholds State Elapsed | Report State Stos Last Report +// -------------------------------------------------|---------------------------------- +// sample < low_water C false | false C - - +// sample < low_water C true | false C - - +// sample < low_water T false | true C updated reset +// sample < low_water T true | true C updated reset +// | +// sample == low_water C false | false C - - +// sample == low_water C true | false C - - +// sample == low_water T false | false T - - +// sample == low_water T true | true T updated +// | +// low_water < sample < high_water C false | false C - - +// low_water < sample < high_water C true | false C - - +// low_water < sample < high_water T false | false T - - +// low_water < sample < high_water T true | true T - updated +// | +// sample == high water C false | false C - - +// sample == high water C true | false C - - +// sample == high water T false | false T - - +// sample == high water T true | true T - updated +// | +// sample > high water C false | true T updated set +// sample > high water C true | true T updated set +// sample > high water T false | false T - - +// sample > high water T true | true T - updated +// ``` +TEST(Alarm, checkSample) { + // Create mnemonic constants. + Duration low_water(milliseconds(100)); + Duration high_water(milliseconds(200)); + Duration lt_low_water(milliseconds(50)); + Duration eq_low_water = low_water; + Duration mid_range(milliseconds(150)); + Duration eq_high_water = high_water; + Duration gt_high_water(milliseconds(250)); + Duration report_interval(milliseconds(25)); + + bool report_elapsed = true; + bool should_report = true; + + // Enumerates possible outcomes for last_high_water_report. + enum TimeChange { + none, // no change + set, // from empty time to time + updated, // updated to a more recent time + reset // reset to empty time + }; + + // Embodies a test scenario based on the table in the commentary. It does not + // include a column for stos_time_ changes as they are easily inferred. + struct Scenario { + Duration sample_; // duration to test the alarm with + Alarm::State input_state_; // Starting state of the Alarm (CLEAR or TRIGGERED) + bool report_interval_elapsed_; // True if report interval has elapsed + bool should_report_; // True if checkSample() should return true + Alarm::State output_state_; // Alarm state after calling checkSample() + TimeChange last_report_chg_; // Expected change to last_high_water_report_ + }; + + // Scenarios as described in the commentary. + std::list<Scenario> scenarios = { + { lt_low_water, Alarm::CLEAR, !report_elapsed, !should_report, Alarm::CLEAR, TimeChange::none }, + { lt_low_water, Alarm::CLEAR, report_elapsed, !should_report, Alarm::CLEAR, TimeChange::none }, + { lt_low_water, Alarm::TRIGGERED, !report_elapsed, should_report, Alarm::CLEAR, TimeChange::reset }, + { lt_low_water, Alarm::TRIGGERED, report_elapsed, should_report, Alarm::CLEAR, TimeChange::reset }, + + { eq_low_water, Alarm::CLEAR, !report_elapsed, !should_report, Alarm::CLEAR, TimeChange::none }, + { eq_low_water, Alarm::CLEAR, report_elapsed, !should_report, Alarm::CLEAR, TimeChange::none }, + { eq_low_water, Alarm::TRIGGERED, !report_elapsed, !should_report, Alarm::TRIGGERED, TimeChange::none }, + { eq_low_water, Alarm::TRIGGERED, report_elapsed, should_report, Alarm::TRIGGERED, TimeChange::updated }, + + { mid_range, Alarm::CLEAR, !report_elapsed, !should_report, Alarm::CLEAR, TimeChange::none }, + { mid_range, Alarm::CLEAR, report_elapsed, !should_report, Alarm::CLEAR, TimeChange::none }, + { mid_range, Alarm::TRIGGERED, !report_elapsed, !should_report, Alarm::TRIGGERED, TimeChange::none }, + { mid_range, Alarm::TRIGGERED, report_elapsed, should_report, Alarm::TRIGGERED, TimeChange::updated }, + + { eq_high_water, Alarm::CLEAR, !report_elapsed, !should_report, Alarm::CLEAR, TimeChange::none }, + { eq_high_water, Alarm::CLEAR, report_elapsed, !should_report, Alarm::CLEAR, TimeChange::none }, + { eq_high_water, Alarm::TRIGGERED, !report_elapsed, !should_report, Alarm::TRIGGERED, TimeChange::none }, + { eq_high_water, Alarm::TRIGGERED, report_elapsed, should_report, Alarm::TRIGGERED, TimeChange::updated }, + + { gt_high_water, Alarm::CLEAR, !report_elapsed, should_report, Alarm::TRIGGERED, TimeChange::set }, + { gt_high_water, Alarm::CLEAR, report_elapsed, should_report, Alarm::TRIGGERED, TimeChange::set }, + { gt_high_water, Alarm::TRIGGERED, !report_elapsed, !should_report, Alarm::TRIGGERED, TimeChange::none }, + { gt_high_water, Alarm::TRIGGERED, report_elapsed, should_report, Alarm::TRIGGERED, TimeChange::updated }, + }; + + AlarmPtr alarm; + DurationKey key(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", SUBNET_ID_GLOBAL); + size_t pass = 0; + for (auto const& scenario : scenarios) { + std::ostringstream oss; + oss << "scenario: " << pass++; + SCOPED_TRACE(oss.str()); + + auto start_time = PktEvent::now(); + + // Create an Alarm with the scenario starting characteristics. + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(key, low_water, high_water))); + if (scenario.input_state_ == Alarm::TRIGGERED) { + alarm->setState(Alarm::TRIGGERED); + alarm->setLastHighWaterReport(!scenario.report_interval_elapsed_ ? + PktEvent::now() : start_time - (report_interval * 2)); + } + + // Save the current timestamps. + auto prev_stos_time = alarm->getStosTime(); + auto prev_report_time = alarm->getLastHighWaterReport(); + + // Take a little nap. + usleep(50); + + // Invoke checkSample() with the scenario sample duration. It should not throw. + bool should_report; + ASSERT_NO_THROW_LOG(should_report = alarm->checkSample(scenario.sample_, report_interval)); + + // Verify that we returned the expected value for a reportable event (or not). + EXPECT_EQ(should_report, scenario.should_report_); + + // Verify we ended up in the expected state. + ASSERT_EQ(alarm->getState(), scenario.output_state_); + + // If the state changed, stos_time_ should have been updated. + if (scenario.input_state_ != scenario.output_state_) { + EXPECT_GT(alarm->getStosTime(), prev_stos_time); + } else { + EXPECT_EQ(alarm->getStosTime(), prev_stos_time); + } + + // Verify the last_high_water_report_ outcome. + switch(scenario.last_report_chg_) { + case TimeChange::none: + EXPECT_EQ(alarm->getLastHighWaterReport(), prev_report_time); + break; + case TimeChange::set: + EXPECT_EQ(prev_report_time, PktEvent::EMPTY_TIME()); + EXPECT_GE(alarm->getLastHighWaterReport(), alarm->getStosTime()); + break; + case TimeChange::updated: + EXPECT_GT(alarm->getLastHighWaterReport(), prev_report_time); + break; + case TimeChange::reset: + EXPECT_EQ(alarm->getLastHighWaterReport(), PktEvent::EMPTY_TIME()); + break; + } + } +} + +} // end of anonymous namespace diff --git a/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc b/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc new file mode 100644 index 0000000..ae79933 --- /dev/null +++ b/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc @@ -0,0 +1,671 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +/// @file This file contains tests which exercise the MonitoredDurationStore class. +#include <config.h> +#include <monitored_duration_store.h> +#include <dhcp/dhcp6.h> +#include <testutils/gtest_utils.h> +#include <testutils/multi_threading_utils.h> + +#include <boost/range/adaptor/reversed.hpp> +#include <gtest/gtest.h> +#include <sstream> + +using namespace std; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfmon; +using namespace isc::test; +using namespace boost::posix_time; + +namespace { + +// Verifies MonitoredDurationStore valid construction. +TEST(MonitoredDurationStore, validConstructors) { + MonitoredDurationStorePtr store; + + EXPECT_NO_THROW_LOG(store.reset(new MonitoredDurationStore(AF_INET, milliseconds(5)))); + ASSERT_TRUE(store); + + MonitoredDurationCollectionPtr durations; + ASSERT_NO_THROW_LOG(durations = store->getAll()); + ASSERT_TRUE(durations); + EXPECT_TRUE(durations->empty()); +} + +// Verifies MonitoredDurationStore invalid construction. +TEST(MonitoredDurationStore, invalidConstructors) { + MonitoredDurationStorePtr store; + + EXPECT_THROW_MSG(MonitoredDurationStore(777, seconds(60)), + BadValue, + "MonitoredDurationStore - invalid family 777, must be AF_INET or AF_INET6"); + + EXPECT_THROW_MSG(MonitoredDurationStore(AF_INET, milliseconds(0)), + BadValue, + "MonitoredDurationStore - invalid interval_duration" + " 00:00:00, must be greater than zero"); + + EXPECT_THROW_MSG(MonitoredDurationStore(AF_INET, milliseconds(-5)), + BadValue, + "MonitoredDurationStore - invalid interval_duration" + " -00:00:00.005000, must be greater than zero"); +} + +/// @brief Text fixture class for @c MonitoredDurationStore +/// +/// In order to facilitate single and multi threaded testing, +/// individual tests are implemented as methods that are called +/// from within TEST_F bodies rather than in TEST_F bodies. +class MonitoredDurationStoreTest : public ::testing::Test { +public: + + /// @brief Constructor + MonitoredDurationStoreTest() = default; + + /// @brief Destructor + virtual ~MonitoredDurationStoreTest() = default; + + /// @brief Creates a protocol-specific DurationKey for a given subnet + /// + /// The message-pair and socket-event pairs are fixed. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + /// @param subnet SubnetID of the duration + DurationKeyPtr makeKey(uint16_t family, SubnetID subnet = 1) { + DurationKeyPtr key; + if (family == AF_INET) { + return (DurationKeyPtr(new DurationKey(AF_INET, DHCPDISCOVER, DHCPOFFER, + "socket_received", "buffer_read", subnet))); + } + + return (DurationKeyPtr(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_REPLY, + "socket_received", "buffer_read", subnet))); + } + + /// @brief Verifies that durations can be added to the store and fetched + /// by DurationKey. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void addDurationTest(uint16_t family) { + Duration interval_duration(milliseconds(10)); + MonitoredDurationStore store(family, interval_duration); + + std::vector<MonitoredDurationPtr> monds; + // Add four durations with decreaing subnet ids. + for (int subnet = 4; subnet > 0; --subnet) { + MonitoredDurationPtr mond; + ASSERT_NO_THROW_LOG(mond = store.addDuration(makeKey(family, subnet))); + ASSERT_TRUE(mond); + monds.push_back(mond); + } + + // Get all should retrieve all four in ascending order. + MonitoredDurationCollectionPtr durations = store.getAll(); + ASSERT_EQ(durations->size(), monds.size()); + + int idx = monds.size() - 1; + for (auto const& d : *durations) { + EXPECT_EQ(*d, *monds[idx]) << "failed on pass :" << idx; + --idx; + } + + // Make sure we can fetch them all individually. + for (auto const& mond : monds) { + MonitoredDurationPtr found; + ASSERT_NO_THROW_LOG(found = store.getDuration(mond)); + ASSERT_TRUE(found); + EXPECT_EQ(*mond, *found); + } + + // Verify that clear() discards store contents. + store.clear(); + durations = store.getAll(); + ASSERT_TRUE(durations->empty()); + } + + /// @brief Verifies that duplicate durations cannot be added to the store. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void addDurationDuplicateTest(uint16_t family) { + Duration interval_duration(milliseconds(10)); + MonitoredDurationStore store(family, interval_duration); + + // Add a duration. + MonitoredDurationPtr mond; + ASSERT_NO_THROW_LOG(mond = store.addDuration(makeKey(family))); + ASSERT_TRUE(mond); + + // Attempting to add it again should evoke a duplicate key exception. + ASSERT_THROW(store.addDuration(mond), DuplicateDurationKey); + } + + /// @brief Verifies that duration key must be valid to add a duration to the store. + /// + /// Tests both v4 and v6. + void addDurationInvalidTest() { + // Create a v4 store. + Duration interval_duration(milliseconds(10)); + MonitoredDurationStorePtr store(new MonitoredDurationStore(AF_INET, interval_duration)); + + // Attempting to add with an empty key should throw. + ASSERT_THROW_MSG(store->addDuration(DurationKeyPtr()), + BadValue, + "MonitoredDurationStore::addDuration - key is empty"); + + // Attempting to add a v6 key should fail. + ASSERT_THROW_MSG(store->addDuration(makeKey(AF_INET6)), + BadValue, + "MonitoredDurationStore::addDuration" + " - family mismatch, key is v6, store is v4"); + + // Create a v6 store. + store.reset(new MonitoredDurationStore(AF_INET6, interval_duration)); + + // Attempting to add a v4 key should fail. + ASSERT_THROW_MSG(store->addDuration(makeKey(AF_INET)), + BadValue, + "MonitoredDurationStore::addDuration" + " - family mismatch, key is v4, store is v6"); + } + + /// @brief Verify that durations can be deleted from the store. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void deleteDurationTest(uint16_t family) { + MonitoredDurationStore store(family, milliseconds(5)); + + std::vector<DurationKeyPtr> keys; + for (int subnet = 0; subnet < 3; ++subnet) { + MonitoredDurationPtr mond; + DurationKeyPtr key = makeKey(family, subnet); + ASSERT_NO_THROW_LOG(mond = store.addDuration(key)); + ASSERT_TRUE(mond); + keys.push_back(key); + } + + // Verify we added three of them. + auto durations = store.getAll(); + ASSERT_EQ(durations->size(), 3); + + // Fetch the second duration. + MonitoredDurationPtr mond; + ASSERT_NO_THROW_LOG(mond = store.getDuration(keys[1])); + ASSERT_TRUE(mond); + EXPECT_EQ(*mond, *(keys[1])); + + // Delete it. + ASSERT_NO_THROW_LOG(store.deleteDuration(mond)); + + // Try to fetch it, shouldn't find it. + MonitoredDurationPtr mond2; + ASSERT_NO_THROW_LOG(mond2 = store.getDuration(mond)); + ASSERT_FALSE(mond2); + + // Deleting it again should do no harm. + ASSERT_NO_THROW_LOG(store.deleteDuration(mond)); + + // Verify there are two left. + durations = store.getAll(); + ASSERT_EQ(durations->size(), 2); + } + + /// @brief Verify an invalid duration key on delete is detected. + /// + /// Tests both v4 and v6. + void deleteDurationInvalidTest() { + // Create a v4 store. + Duration interval_duration(milliseconds(10)); + MonitoredDurationStorePtr store(new MonitoredDurationStore(AF_INET, interval_duration)); + + // Attempting to delete an empty key should throw. + DurationKeyPtr key; + ASSERT_THROW_MSG(store->deleteDuration(key), + BadValue, + "MonitoredDurationStore::deleteDuration - key is empty"); + + // Attempting to delete a v6 key should fail. + ASSERT_THROW_MSG(store->deleteDuration(makeKey(AF_INET6)), + BadValue, + "MonitoredDurationStore::deleteDuration" + " - family mismatch, key is v6, store is v4"); + + // Create a v6 store. + store.reset(new MonitoredDurationStore(AF_INET6, interval_duration)); + + // Attempting to delete a v4 key should fail. + ASSERT_THROW_MSG(store->deleteDuration(makeKey(AF_INET)), + BadValue, + "MonitoredDurationStore::deleteDuration" + " - family mismatch, key is v4, store is v6"); + } + + /// @brief Verify that durations in the store can be updated. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void updateDurationTest(uint16_t family) { + Duration interval_duration(seconds(60)); + MonitoredDurationStore store(family, interval_duration); + + // Add the duration to the store. + MonitoredDurationPtr mond; + ASSERT_NO_THROW(mond.reset(new MonitoredDuration(*makeKey(family), interval_duration))); + ASSERT_NO_THROW(store.addDuration(mond)); + + // Fetch it. + MonitoredDurationPtr found; + ASSERT_NO_THROW_LOG(found = store.getDuration(mond)); + ASSERT_TRUE(found); + + // Verify the fetched object is a copy. + ASSERT_NE(found, mond); + ASSERT_EQ(*found, *mond); + + // Verify that it has no intervals. + ASSERT_FALSE(found->getPreviousInterval()); + ASSERT_FALSE(found->getCurrentInterval()); + + // Now add a sample to the duration and update it. + mond->addSample(milliseconds(75)); + ASSERT_NO_THROW(store.updateDuration(mond)); + + // Fetch it again. + ASSERT_NO_THROW_LOG(found = store.getDuration(mond)); + ASSERT_FALSE(found->getPreviousInterval()); + + // Verify it has the expected current interval. + DurationDataIntervalPtr current; + ASSERT_TRUE(current = found->getCurrentInterval()); + ASSERT_NE(current, mond->getCurrentInterval()); + EXPECT_EQ(current->getOccurrences(), 1); + EXPECT_EQ(current->getTotalDuration(), milliseconds(75)); + } + + /// @brief Verify an invalid duration key on update is detected. + /// + /// Tests both v4 and v6. + void updateDurationInvalidTest() { + Duration interval_duration(seconds(60)); + MonitoredDurationPtr mond; + + // Create a v4 store. + MonitoredDurationStorePtr store(new MonitoredDurationStore(AF_INET, interval_duration)); + + // Attempting to update an empty key should throw. + ASSERT_THROW_MSG(store->updateDuration(mond), + BadValue, + "MonitoredDurationStore::updateDuration - key is empty"); + + // Create a v6 duration. + ASSERT_NO_THROW_LOG(mond.reset(new MonitoredDuration(*makeKey(AF_INET6), interval_duration))); + + // Attempting to update v6 duration in a v4 store should fail. + ASSERT_THROW_MSG(store->updateDuration(mond), + BadValue, + "MonitoredDurationStore::updateDuration" + " - family mismatch, key is v6, store is v4"); + + // Create a v6 store. + store.reset(new MonitoredDurationStore(AF_INET6, interval_duration)); + + // Updating a non-existent duration should fail. + ASSERT_THROW_MSG(store->updateDuration(mond), + InvalidOperation, + "MonitoredDurationStore::updateDuration duration not found:" + " SOLICIT-REPLY.socket_received-buffer_read.1"); + + // Create a v4 duration. + ASSERT_NO_THROW_LOG(mond.reset(new MonitoredDuration(*makeKey(AF_INET), interval_duration))); + + // Attempting to update v4 duration in a v6 store fail. + ASSERT_THROW_MSG(store->updateDuration(mond), + BadValue, + "MonitoredDurationStore::updateDuration" + " - family mismatch, key is v4, store is v6"); + } + + /// @brief Exercises addDurationSample() valid behavior. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void addDurationSampleTest(uint16_t family) { + // Create a store. + Duration interval_duration(milliseconds(50)); + MonitoredDurationStore store(family, interval_duration); + + // Create valid key. + DurationKeyPtr key = makeKey(family); + + // Add a 5 ms sample for the key. + MonitoredDurationPtr mond; + Duration five_ms(milliseconds(5)); + ASSERT_NO_THROW_LOG(mond = store.addDurationSample(key, five_ms)); + + // Should return an empty pointer as nothing to report yet. + EXPECT_FALSE(mond); + + // Make sure the duration was created and stored, and has only + // the current interval with 1 occurrence and a total of 5 ms. + ASSERT_NO_THROW_LOG(mond = store.getDuration(key)); + ASSERT_TRUE(mond); + auto current_interval = mond->getCurrentInterval(); + ASSERT_TRUE(current_interval); + EXPECT_EQ(current_interval->getOccurrences(), 1); + EXPECT_EQ(current_interval->getTotalDuration(), (five_ms)); + auto previous_interval = mond->getPreviousInterval(); + ASSERT_FALSE(previous_interval); + + // Now lets add a second sample. We should still be inside the + // interval, so it still should return an empty pointer. + ASSERT_NO_THROW_LOG(mond = store.addDurationSample(key, five_ms)); + EXPECT_FALSE(mond); + + // Make sure the duration's current interval (only) was updated + ASSERT_NO_THROW_LOG(mond = store.getDuration(key)); + ASSERT_TRUE(mond); + current_interval = mond->getCurrentInterval(); + ASSERT_TRUE(current_interval); + EXPECT_EQ(current_interval->getOccurrences(), 2); + EXPECT_EQ(current_interval->getTotalDuration(), (five_ms * 2)); + previous_interval = mond->getPreviousInterval(); + ASSERT_FALSE(previous_interval); + + // Sleep til past the end of interval + usleep(60 * 1000); + + // Now lets add a third sample. We are past the end of the + // interval, so it should return the duration. + ASSERT_NO_THROW_LOG(mond = store.addDurationSample(key, five_ms)); + ASSERT_TRUE(mond); + + // Make sure the duration's current interval and prevous intervals correct. + current_interval = mond->getCurrentInterval(); + ASSERT_TRUE(current_interval); + EXPECT_EQ(current_interval->getOccurrences(), 1); + EXPECT_EQ(current_interval->getTotalDuration(), (five_ms)); + + previous_interval = mond->getPreviousInterval(); + ASSERT_TRUE(previous_interval); + EXPECT_EQ(previous_interval->getOccurrences(), 2); + EXPECT_EQ(previous_interval->getTotalDuration(), (five_ms) * 2); + } + + /// @brief Veriries getReportsNext and getOverdueReports + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void reportDueTest(uint16_t family) { + // Create a store. + Duration interval_duration(milliseconds(100)); + MonitoredDurationStore store(family, interval_duration); + + // Create durations in the store, none of them will have intervals. + size_t num_subnets = 4; + std::vector<DurationKeyPtr> keys; + for (int s = 0; s < num_subnets; ++s) { + auto key = makeKey(family, s); + store.addDuration(key); + keys.push_back(key); + } + + // No duration should be due to report. + MonitoredDurationPtr mond; + ASSERT_NO_THROW_LOG(mond = store.getReportsNext()); + ASSERT_FALSE(mond); + + // No durations should be over due to report. + MonitoredDurationCollectionPtr durations; + ASSERT_NO_THROW_LOG(durations = store.getOverdueReports()); + ASSERT_TRUE(durations); + EXPECT_TRUE(durations->empty()); + + // Now add a 5ms sample to all four durations in reverse order + // This should give us a list of durations (by key) as follows: + // + // key[0] - interval start = now + 54ms + // key[1] - interval start = now + 52ms + // key[2] - interval start = now + 2ms + // key[3] - interval start = now + auto five_ms(milliseconds(5)); + for (auto const& k : boost::adaptors::reverse(keys)) { + ASSERT_NO_THROW_LOG(store.addDurationSample(k, five_ms)); + if (k->getSubnetId() != 2) { + usleep(2 * 1000); // put 2ms gap between them + } else { + usleep(50 * 1000); // put 50ms gap between them. + } + } + + // Key[3] should be returned by getReportsNext(). + ASSERT_NO_THROW_LOG(mond = store.getReportsNext()); + ASSERT_TRUE(mond); + EXPECT_EQ(*mond, *keys[3]) << "mond: " << mond->getLabel(); + + // None should be returned by getOverdueReports(). + ASSERT_NO_THROW_LOG(durations = store.getOverdueReports()); + ASSERT_TRUE(durations); + EXPECT_TRUE(durations->empty()); + + // Sleep for 50 ms. + usleep(50 * 1000); + + // Key[1] should be returned by getReportsNext(). + ASSERT_NO_THROW_LOG(mond = store.getReportsNext()); + ASSERT_TRUE(mond); + EXPECT_EQ(*mond, *keys[1]) << "mond: " << mond->getLabel(); + + // Key[3] and key[2] should be returned by getOverdueReports(). + ASSERT_NO_THROW_LOG(durations = store.getOverdueReports()); + ASSERT_TRUE(durations); + EXPECT_EQ(durations->size(), 2); + EXPECT_EQ(*(*durations)[0], *keys[3]); + EXPECT_EQ(*(*durations)[1], *keys[2]); + + // Sleep for 50 ms. + usleep(50 * 1000); + + // None should report as reports next. + ASSERT_NO_THROW_LOG(mond = store.getReportsNext()); + ASSERT_FALSE(mond); + + // All should be found overdue. + ASSERT_NO_THROW_LOG(durations = store.getOverdueReports()); + ASSERT_TRUE(durations); + EXPECT_EQ(durations->size(), keys.size()); + EXPECT_EQ(*(*durations)[0], *keys[3]); + EXPECT_EQ(*(*durations)[1], *keys[2]); + EXPECT_EQ(*(*durations)[2], *keys[1]); + EXPECT_EQ(*(*durations)[3], *keys[0]); + } + + /// @brief Test tool for gauging speed. + /// + /// This test is really just a development tool for gauging performance. + /// of adding duration samples. It does not pass or fail and thus is not + /// included in explicit UTs. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void speedCheck(uint16_t family) { + // Create a store. + Duration interval_duration(microseconds(100)); + MonitoredDurationStore store(family, interval_duration); + + // Create keys. + size_t num_subnets = 100; + std::vector<DurationKeyPtr> keys; + + for (int s = 0; s < num_subnets; ++s) { + keys.push_back(makeKey(family, s)); + } + + auto start_time = PktEvent::now(); + + for (auto k : keys) { + store.addDuration(k); + } + + auto add_keys_time = PktEvent::now(); + + size_t num_passes = 100; + size_t report_count = 0; + Duration two_us(microseconds(2)); + for (int p = 0; p < num_passes; ++p) { + for (auto k : keys) { + if (store.addDurationSample(k, two_us)) { + ++report_count; + } + } + } + + auto add_samples_time = PktEvent::now(); + + EXPECT_GT(report_count, 0); + auto durations = store.getAll(); + EXPECT_EQ(durations->size(), num_subnets); + + std::cout << "report count: " << report_count << std::endl + << "add keys time: " << (add_keys_time - start_time) << std::endl + << "add samples time: " << (add_samples_time - add_keys_time) << std::endl + << "time per sample: " + << (add_samples_time - add_keys_time) / (num_subnets * num_passes) << std::endl; + } +}; + +TEST_F(MonitoredDurationStoreTest, addDuration) { + addDurationTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, addDurationMultiThreading) { + MultiThreadingTest mt; + addDurationTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, addDuration6) { + addDurationTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, addDuration6MultiThreading) { + MultiThreadingTest mt; + addDurationTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, addDurationDuplicate) { + addDurationDuplicateTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, addDurationDuplicateMultiThreading) { + MultiThreadingTest mt; + addDurationDuplicateTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, addDuration6Duplicate) { + addDurationDuplicateTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, addDuration6DuplicateMultiThreading) { + MultiThreadingTest mt; + addDurationDuplicateTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, addDurationInvalid) { + addDurationInvalidTest(); +} + +TEST_F(MonitoredDurationStoreTest, addDurationInvalidMultiThreading) { + MultiThreadingTest mt; + addDurationInvalidTest(); +} + +TEST_F(MonitoredDurationStoreTest, deleteDuration) { + deleteDurationTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, deleteDurationMultiThreading) { + MultiThreadingTest mt; + deleteDurationTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, deleteDuration6) { + deleteDurationTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, deleteDuration6MultiThreading) { + MultiThreadingTest mt; + deleteDurationTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, deleteDurationInvalid) { + deleteDurationInvalidTest(); +} + +TEST_F(MonitoredDurationStoreTest, deleteDurationInvalidMultiThreading) { + MultiThreadingTest mt; + deleteDurationInvalidTest(); +} + +TEST_F(MonitoredDurationStoreTest, updateDuration) { + updateDurationTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, updateDurationMultiThreading) { + MultiThreadingTest mt; + updateDurationTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, updateDuration6) { + updateDurationTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, updateDuration6MultiThreading) { + MultiThreadingTest mt; + updateDurationTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, updateDurationInvalid) { + updateDurationInvalidTest(); +} + +TEST_F(MonitoredDurationStoreTest, updateDurationInvalidMultiThreading) { + MultiThreadingTest mt; + updateDurationInvalidTest(); +} + +TEST_F(MonitoredDurationStoreTest, addDurationSample) { + addDurationSampleTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, addDurationSampleMultiThreading) { + MultiThreadingTest mt; + addDurationSampleTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, addDurationSample6) { + addDurationSampleTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, addDurationSample6MultiThreading) { + MultiThreadingTest mt; + addDurationSampleTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, reportDue) { + reportDueTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, reportDueMultiThreading) { + MultiThreadingTest mt; + reportDueTest(AF_INET); +} + +TEST_F(MonitoredDurationStoreTest, reportDue6) { + reportDueTest(AF_INET6); +} + +TEST_F(MonitoredDurationStoreTest, reportDue6MultiThreading) { + MultiThreadingTest mt; + reportDueTest(AF_INET6); +} + +} // end of anonymous namespace diff --git a/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc b/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc new file mode 100644 index 0000000..8aeea12 --- /dev/null +++ b/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc @@ -0,0 +1,522 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 <config.h> +#include <monitored_duration.h> +#include <dhcp/dhcp6.h> +#include <testutils/gtest_utils.h> + +#include <gtest/gtest.h> +#include <sstream> +#include <unordered_set> + +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfmon; +using namespace boost::posix_time; + +namespace { + +// Exercises the basic functions of DurationDataInterval. +TEST(DurationDataInterval, basics) { + auto start_time = PktEvent::now(); + + DurationDataIntervalPtr interval; + + // Default Construct a interval. + interval.reset(new DurationDataInterval()); + ASSERT_TRUE(interval); + + // Verify contents. + // Start time is set to current time by default. + EXPECT_GE(interval->getStartTime(), start_time); + EXPECT_EQ(interval->getOccurrences(), 0); + EXPECT_EQ(interval->getMinDuration(), pos_infin); + EXPECT_EQ(interval->getMaxDuration(), neg_infin); + EXPECT_EQ(interval->getTotalDuration(), DurationDataInterval::ZERO_DURATION()); + EXPECT_EQ(interval->getAverageDuration(), DurationDataInterval::ZERO_DURATION()); + + // Verify that start time can be specified. + interval.reset(new DurationDataInterval(start_time + milliseconds(5000))); + ASSERT_TRUE(interval); + EXPECT_EQ(interval->getStartTime() - start_time, milliseconds(5000)); + + // Add 100ms duration and check contents. + Duration d100(milliseconds(100)); + interval->addDuration(d100); + EXPECT_EQ(interval->getOccurrences(), 1); + EXPECT_EQ(interval->getMinDuration(), d100); + EXPECT_EQ(interval->getMaxDuration(), d100); + EXPECT_EQ(interval->getTotalDuration(), d100); + EXPECT_EQ(interval->getAverageDuration(), d100); + + // Add 300ms duration and check contents. + Duration d300(milliseconds(300)); + interval->addDuration(d300); + EXPECT_EQ(interval->getOccurrences(), 2); + EXPECT_EQ(interval->getMinDuration(), d100); + EXPECT_EQ(interval->getMaxDuration(), d300); + EXPECT_EQ(interval->getTotalDuration(), d100 + d300); + EXPECT_EQ(interval->getAverageDuration(), Duration(milliseconds(200))); + + // Add 50ms duration and check contents. + Duration d50(milliseconds(50)); + interval->addDuration(d50); + EXPECT_EQ(interval->getOccurrences(), 3); + EXPECT_EQ(interval->getMinDuration(), d50); + EXPECT_EQ(interval->getMaxDuration(), d300); + EXPECT_EQ(interval->getTotalDuration(), d100 + d300 + d50); + EXPECT_EQ(interval->getAverageDuration(), Duration(milliseconds(150))); + + // Add a zero duration and check contents. + interval->addDuration(DurationDataInterval::ZERO_DURATION()); + EXPECT_EQ(interval->getOccurrences(), 4); + EXPECT_EQ(interval->getMinDuration(), DurationDataInterval::ZERO_DURATION()); + EXPECT_EQ(interval->getMaxDuration(), d300); + EXPECT_EQ(interval->getTotalDuration(), d100 + d300 + d50); + EXPECT_EQ(interval->getAverageDuration(), Duration(microseconds(112500))); +} + +// Exercises the basic functions of DurationDataInterval. +TEST(DurationKey, basics) { + DurationKeyPtr key; + + // Create valid v4 key, verify contents and label. + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL))); + ASSERT_TRUE(key); + EXPECT_EQ(key->getFamily(), AF_INET); + EXPECT_EQ(key->getQueryType(), DHCPDISCOVER); + EXPECT_EQ(key->getResponseType(), DHCPOFFER); + EXPECT_EQ(key->getStartEventLabel(), "process_started"); + EXPECT_EQ(key->getStopEventLabel(), "process_completed"); + EXPECT_EQ(key->getSubnetId(), SUBNET_ID_GLOBAL); + EXPECT_EQ("DHCPDISCOVER-DHCPOFFER.process_started-process_completed.0", key->getLabel()); + + // Create valid v6 key, verify contents and label. + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + ASSERT_TRUE(key); + EXPECT_EQ(key->getFamily(), AF_INET6); + EXPECT_EQ(key->getQueryType(), DHCPV6_SOLICIT); + EXPECT_EQ(key->getResponseType(), DHCPV6_ADVERTISE); + EXPECT_EQ(key->getStartEventLabel(), "mt_queued"); + EXPECT_EQ(key->getStopEventLabel(), "process_started"); + EXPECT_EQ(key->getSubnetId(), 77); + EXPECT_EQ("SOLICIT-ADVERTISE.mt_queued-process_started.77", key->getLabel()); + + // Make sure constructor catches an insane message pairing. + ASSERT_THROW_MSG(key.reset(new DurationKey(AF_INET6, DHCPV6_ADVERTISE, DHCPV6_SOLICIT, + "mt_queued", "process_started", 77)), BadValue, + "Query type not supported by monitoring: ADVERTISE"); +} + +// Verify v4 message pair validation works. +TEST(DurationKey, validateMessagePairs4) { + // Defines a test scenario. + struct Scenario { + // Query type to use in the scenario. + uint8_t query_type_; + // Valid response types for query type (if any). + std::unordered_set<uint8_t> valid_responses_; + }; + + // List of scenarios to test, one per v4 message type. + std::list<Scenario> scenarios { + {DHCP_NOTYPE, {DHCP_NOTYPE, DHCPOFFER, DHCPACK, DHCPNAK}}, + {DHCPDISCOVER, {DHCP_NOTYPE, DHCPOFFER, DHCPNAK}}, + {DHCPOFFER, {}}, + {DHCPREQUEST, {DHCP_NOTYPE, DHCPACK, DHCPNAK}}, + {DHCPDECLINE, {}}, + {DHCPACK, {}}, + {DHCPNAK, {}}, + {DHCPRELEASE, {}}, + {DHCPINFORM, {DHCP_NOTYPE, DHCPACK}}, +// {DHCPFORCERENEW, {}}, commented out in dhcp4.h + {DHCPLEASEQUERY, {}}, + {DHCPLEASEUNASSIGNED, {}}, + {DHCPLEASEUNKNOWN, {}}, + {DHCPLEASEACTIVE, {}}, + {DHCPBULKLEASEQUERY, {}}, + {DHCPLEASEQUERYDONE, {}}, +// {DHCPACTIVELEASEQUERY, {}}, commented out in dhcp4.h + {DHCPLEASEQUERYSTATUS, {}}, + {DHCPTLS, {}}, + }; + + // Iterate over the scenarios. Attempt to pair each scenario query type with every v4 message + // type as a response type. If the response type is in the scenario's valid list, the pair + // should validate, otherwise it should throw. + for (auto const& scenario : scenarios) { + for (uint8_t response_type = DHCP_NOTYPE; response_type < DHCP_TYPES_EOF; ++response_type) { + if (scenario.valid_responses_.count(response_type)) { + ASSERT_NO_THROW_LOG( + DurationKey::validateMessagePair(AF_INET, scenario.query_type_, response_type)); + } else { + ASSERT_THROW( + DurationKey::validateMessagePair(AF_INET, scenario.query_type_, response_type), + BadValue); + } + } + } +} + +// Verify v6 message pair validation works. +TEST(DurationKey, validateMessagePairs6) { + // Defines a test scenario. + struct Scenario { + // Query type to use in the scenario. + uint8_t query_type_; + // Valid response types for query type (if any). + std::unordered_set<uint8_t> valid_responses_; + }; + + // List of scenarios to test, one per v6 message type. + std::list<Scenario> scenarios { + {DHCPV6_NOTYPE, {DHCPV6_NOTYPE, DHCPV6_ADVERTISE, DHCPV6_REPLY}}, + {DHCPV6_SOLICIT, {DHCPV6_NOTYPE, DHCPV6_ADVERTISE, DHCPV6_REPLY}}, + {DHCPV6_ADVERTISE, {}}, + {DHCPV6_REQUEST, {DHCPV6_NOTYPE, DHCPV6_REPLY}}, + {DHCPV6_CONFIRM, {DHCPV6_NOTYPE, DHCPV6_REPLY}}, + {DHCPV6_RENEW, {DHCPV6_NOTYPE, DHCPV6_REPLY}}, + {DHCPV6_REBIND, {DHCPV6_NOTYPE, DHCPV6_REPLY}}, + {DHCPV6_REPLY, {}}, + {DHCPV6_RELEASE, {}}, + {DHCPV6_DECLINE, {}}, + {DHCPV6_RECONFIGURE, {}}, + {DHCPV6_INFORMATION_REQUEST, {}}, + {DHCPV6_RELAY_FORW, {}}, + {DHCPV6_RELAY_REPL, {}}, + {DHCPV6_LEASEQUERY, {}}, + {DHCPV6_LEASEQUERY_REPLY, {}}, + {DHCPV6_LEASEQUERY_DONE, {}}, + {DHCPV6_LEASEQUERY_DATA, {}}, + {DHCPV6_RECONFIGURE_REQUEST, {}}, + {DHCPV6_RECONFIGURE_REPLY, {}}, + {DHCPV6_DHCPV4_QUERY, {}}, + {DHCPV6_DHCPV4_RESPONSE, {}}, + {DHCPV6_ACTIVELEASEQUERY, {}}, + {DHCPV6_STARTTLS, {}}, + {DHCPV6_BNDUPD, {}}, + {DHCPV6_BNDREPLY, {}}, + {DHCPV6_POOLREQ, {}}, + {DHCPV6_POOLRESP, {}}, + {DHCPV6_UPDREQ, {}}, + {DHCPV6_UPDREQALL, {}}, + {DHCPV6_UPDDONE, {}}, + {DHCPV6_CONNECT, {}}, + {DHCPV6_CONNECTREPLY, {}}, + {DHCPV6_DISCONNECT, {}}, + {DHCPV6_STATE, {}}, + {DHCPV6_CONTACT, {}} + }; + + // Iterate over the scenarios. Attempt to pair each scenario query type with every v6 message + // type as a response type. If the response type is in the scenario's valid list, the pair + // should validate, otherwise it should throw. + for (auto const& scenario : scenarios) { + for (uint8_t response_type = DHCPV6_NOTYPE; response_type < DHCPV6_TYPES_EOF; ++response_type) { + if (scenario.valid_responses_.count(response_type)) { + ASSERT_NO_THROW_LOG( + DurationKey::validateMessagePair(AF_INET6, scenario.query_type_, response_type)); + } else { + ASSERT_THROW( + DurationKey::validateMessagePair(AF_INET6, scenario.query_type_, response_type), + BadValue); + } + } + } +} + +/// @brief Verify DurationKey equality operator +TEST(DurationKey, equalityOperators) { + DurationKeyPtr refkey; + DurationKeyPtr compkey; + + ASSERT_NO_THROW_LOG(refkey.reset(new DurationKey(AF_INET6, DHCPV6_REQUEST, DHCPV6_REPLY, + "event_2", "event_3", 100))); + + ASSERT_NO_THROW_LOG(compkey.reset(new DurationKey(AF_INET6, DHCPV6_REQUEST, DHCPV6_REPLY, + "event_2", "event_3", 100))); + EXPECT_EQ(*compkey, *refkey); + + ASSERT_NO_THROW_LOG(compkey.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_REPLY, + "event_2", "event_3", 100))); + EXPECT_NE(*compkey, *refkey); +} + +// Verifies MonitoredDuration valid construction. +TEST(MonitoredDuration, validConstructors) { + MonitoredDurationPtr mond; + Duration interval_duration(seconds(60)); + + // Create valid v4 duration, verify contents and label. + ASSERT_NO_THROW_LOG(mond.reset(new MonitoredDuration(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, interval_duration))); + ASSERT_TRUE(mond); + EXPECT_EQ(mond->getFamily(), AF_INET); + EXPECT_EQ(mond->getQueryType(), DHCPDISCOVER); + EXPECT_EQ(mond->getResponseType(), DHCPOFFER); + EXPECT_EQ(mond->getStartEventLabel(), "process_started"); + EXPECT_EQ(mond->getStopEventLabel(), "process_completed"); + EXPECT_EQ(mond->getSubnetId(), SUBNET_ID_GLOBAL); + EXPECT_EQ("DHCPDISCOVER-DHCPOFFER.process_started-process_completed.0", mond->getLabel()); + EXPECT_EQ(mond->getIntervalDuration(), interval_duration); + EXPECT_FALSE(mond->getCurrentInterval()); + EXPECT_FALSE(mond->getPreviousInterval()); + + // Create valid v6 key and use that to create an alarm. Verify contents and label. + DurationKeyPtr key; + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + + ASSERT_NO_THROW_LOG(mond.reset(new MonitoredDuration(*key, interval_duration))); + ASSERT_TRUE(mond); + EXPECT_EQ(mond->getFamily(), AF_INET6); + EXPECT_EQ(mond->getQueryType(), DHCPV6_SOLICIT); + EXPECT_EQ(mond->getResponseType(), DHCPV6_ADVERTISE); + EXPECT_EQ(mond->getStartEventLabel(), "mt_queued"); + EXPECT_EQ(mond->getStopEventLabel(), "process_started"); + EXPECT_EQ(mond->getSubnetId(), 77); + EXPECT_EQ("SOLICIT-ADVERTISE.mt_queued-process_started.77", mond->getLabel()); + EXPECT_EQ(mond->getIntervalDuration(), interval_duration); + EXPECT_FALSE(mond->getCurrentInterval()); + EXPECT_FALSE(mond->getPreviousInterval()); +} + +// Verifies Copy construction. Since current and previous intervals are not +// exposed, this test relies on addSample() to alter them. +TEST(MonitoredDuration, copyConstructors) { + MonitoredDurationPtr mond; + Duration interval_duration(microseconds(10)); + + // Create valid v4 duration, verify contents and label. + ASSERT_NO_THROW_LOG(mond.reset(new MonitoredDuration(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, interval_duration))); + + // Make a copy. + MonitoredDurationPtr duplicate; + duplicate.reset(new MonitoredDuration(*mond)); + + // Should have different pointers. + EXPECT_NE(duplicate, mond); + + // Key values should be equal (DurationKey::operator==). + EXPECT_EQ(*duplicate, *mond); + + // Check non-key members. + EXPECT_EQ(duplicate->getIntervalDuration(), mond->getIntervalDuration()); + EXPECT_FALSE(duplicate->getCurrentInterval()); + EXPECT_FALSE(duplicate->getPreviousInterval()); + + // Add a sample to the original. + EXPECT_FALSE(mond->addSample(microseconds(2))); + + // Make a new copy. + duplicate.reset(new MonitoredDuration(*mond)); + + // Current intervals should exist. + ASSERT_TRUE(mond->getCurrentInterval()); + ASSERT_TRUE(duplicate->getCurrentInterval()); + // They should not be the same object but the content should be equal. + EXPECT_NE(duplicate->getCurrentInterval(), mond->getCurrentInterval()); + EXPECT_EQ(*duplicate->getCurrentInterval(), *mond->getCurrentInterval()); + // Previous interval should not exist. + ASSERT_FALSE(mond->getPreviousInterval()); + ASSERT_FALSE(duplicate->getPreviousInterval()); + + // Sleep past interval duration. + usleep(20); + + // Add anoter sample to the original. + EXPECT_TRUE(mond->addSample(microseconds(2))); + + // Make a new copy. + duplicate.reset(new MonitoredDuration(*mond)); + + // Current intervals should exist. + ASSERT_TRUE(mond->getCurrentInterval()); + ASSERT_TRUE(duplicate->getCurrentInterval()); + // They should not be the same object but the content should be equal. + EXPECT_NE(duplicate->getCurrentInterval(), mond->getCurrentInterval()); + EXPECT_EQ(*duplicate->getCurrentInterval(), *mond->getCurrentInterval()); + + // Current previous should exist. + ASSERT_TRUE(mond->getPreviousInterval()); + ASSERT_TRUE(duplicate->getPreviousInterval()); + // They should not be the same object but the content should be equal. + EXPECT_NE(duplicate->getPreviousInterval(), mond->getPreviousInterval()); + EXPECT_EQ(*duplicate->getPreviousInterval(), *mond->getPreviousInterval()); +} + +// Verifies MonitoredDuration invalid construction. +TEST(MonitoredDuration, invalidConstructors) { + MonitoredDurationPtr mond; + + // Make sure we catch an invalid message pairing. + Duration interval_duration = seconds(60); + ASSERT_THROW_MSG(mond.reset(new MonitoredDuration(AF_INET, DHCPDISCOVER, DHCPDISCOVER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, interval_duration)), + BadValue, + "Response type: DHCPDISCOVER not valid for query type: DHCPDISCOVER"); + + // Interval duration cannot be zero. + interval_duration = DurationDataInterval::ZERO_DURATION(); + ASSERT_THROW_MSG(mond.reset(new MonitoredDuration(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, interval_duration)), + BadValue, + "MonitoredDuration - interval_duration 00:00:00," + " is invalid, it must be greater than 0"); + + // Interval duration cannot be negative. + ASSERT_THROW_MSG(mond.reset(new MonitoredDuration(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, seconds(-5))), + BadValue, + "MonitoredDuration - interval_duration -00:00:05," + " is invalid, it must be greater than 0"); + + // Create valid v6 key. + DurationKeyPtr key; + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + + // Interval duration cannot be zero. + ASSERT_THROW_MSG(mond.reset(new MonitoredDuration(*key, interval_duration)), + BadValue, + "MonitoredDuration - interval_duration 00:00:00," + " is invalid, it must be greater than 0"); + + // Interval duration cannot be negative. + ASSERT_THROW_MSG(mond.reset(new MonitoredDuration(*key, seconds(-5))), + BadValue, + "MonitoredDuration - interval_duration -00:00:05," + " is invalid, it must be greater than 0"); +} + +// Exercises MonitoredDuration::addSample() and MonitoredDuration::clear(). +TEST(MonitoredDuration, addSampleAndClear) { + MonitoredDurationPtr mond; + Duration interval_duration(milliseconds(50)); + + // Create valid v4 duration with interval duration of 50ms. + ASSERT_NO_THROW_LOG(mond.reset(new MonitoredDuration(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, interval_duration))); + ASSERT_TRUE(mond); + + // Initially there are no intervals. + EXPECT_FALSE(mond->getCurrentInterval()); + EXPECT_FALSE(mond->getPreviousInterval()); + + auto two_ms = milliseconds(2); + bool should_report = false; + + // Add a sample and verify nothing to report and that it creates a + // current interval. + ASSERT_NO_THROW(should_report = mond->addSample(two_ms)); + EXPECT_FALSE(should_report); + DurationDataIntervalPtr current_interval = mond->getCurrentInterval(); + ASSERT_TRUE(current_interval); + + // First pass, we should only have a current interval, + // nothing to report, one occurrence and a total duration of 10ms. + EXPECT_FALSE(mond->getPreviousInterval()); + EXPECT_FALSE(should_report); + EXPECT_EQ(current_interval->getOccurrences(), 1); + EXPECT_EQ(current_interval->getTotalDuration(), two_ms); + + // Save a copy of the current interval pointer. + DurationDataIntervalPtr original_interval = current_interval; + + // Add 4 two ms samples during the current interval. + DurationDataIntervalPtr previous_interval; + for (int i = 1; i < 5; ++i) { + // Add a two ms sample, it should return false as its not + // time to report. + ASSERT_NO_THROW(should_report = mond->addSample(two_ms)); + EXPECT_FALSE(should_report); + current_interval = mond->getCurrentInterval(); + ASSERT_TRUE(current_interval); + + // Make sure the current interval hasn't been replaced and we + // have no previous interval. + EXPECT_EQ(current_interval, original_interval); + EXPECT_FALSE(mond->getPreviousInterval()); + // Verify the sample was added. + EXPECT_EQ(current_interval->getOccurrences(), (i + 1)); + EXPECT_EQ(current_interval->getTotalDuration(), (two_ms * (i + 1))); + } + + // Sleep til past the end of interval + usleep(60 * 1000); + + // Add another sample. + ASSERT_NO_THROW(should_report = mond->addSample(two_ms)); + current_interval = mond->getCurrentInterval(); + ASSERT_TRUE(current_interval); + + // We should have crossed the interval boundary. + // Previous interval should be equal to the original interval and + // should_report should be true. The new current interval should + // have 1 occurrence and a total of 10ms. + previous_interval = mond->getPreviousInterval(); + EXPECT_TRUE(previous_interval); + EXPECT_EQ(previous_interval, original_interval); + EXPECT_TRUE(should_report); + EXPECT_EQ(current_interval->getOccurrences(), 1); + EXPECT_EQ(current_interval->getTotalDuration(), two_ms); + + // Verify that clear wipes the intervals. + ASSERT_NO_THROW_LOG(mond->clear()); + EXPECT_FALSE(mond->getCurrentInterval()); + EXPECT_FALSE(mond->getPreviousInterval()); +} + +TEST(MonitoredDuration, expireInterval) { + MonitoredDurationPtr mond; + Duration interval_duration(milliseconds(50)); + auto start_time = PktEvent::now(); + auto ten_ms = milliseconds(10); + + // Create valid v4 duration with interval duration of 50ms. + ASSERT_NO_THROW_LOG(mond.reset(new MonitoredDuration(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, interval_duration))); + ASSERT_TRUE(mond); + + // Initially there are no intervals. + EXPECT_FALSE(mond->getCurrentInterval()); + EXPECT_FALSE(mond->getPreviousInterval()); + EXPECT_EQ(mond->getCurrentIntervalStart(), PktEvent::MIN_TIME()); + + ASSERT_THROW_MSG(mond->expireCurrentInterval(), InvalidOperation, + "MonitoredDuration::expireInterval - no current interval for:" + " DHCPDISCOVER-DHCPOFFER.process_started-process_completed.0"); + + ASSERT_NO_THROW(mond->addSample(ten_ms)); + auto current_interval = mond->getCurrentInterval(); + ASSERT_TRUE(current_interval); + EXPECT_EQ(current_interval->getOccurrences(), 1); + EXPECT_EQ(current_interval->getTotalDuration(), ten_ms); + EXPECT_FALSE(mond->getPreviousInterval()); + EXPECT_GE(mond->getCurrentIntervalStart(), start_time); + EXPECT_EQ(mond->getCurrentIntervalStart(), current_interval->getStartTime()); + + ASSERT_NO_THROW_LOG(mond->expireCurrentInterval()); + EXPECT_FALSE(mond->getCurrentInterval()); + + auto previous_interval = mond->getPreviousInterval(); + EXPECT_EQ(previous_interval, current_interval); + EXPECT_EQ(mond->getCurrentIntervalStart(), PktEvent::MIN_TIME()); +} + +} // end of anonymous namespace diff --git a/src/hooks/dhcp/perfmon/tests/run_unittests.cc b/src/hooks/dhcp/perfmon/tests/run_unittests.cc new file mode 100644 index 0000000..755b9e4 --- /dev/null +++ b/src/hooks/dhcp/perfmon/tests/run_unittests.cc @@ -0,0 +1,19 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 <config.h> + +#include <log/logger_support.h> +#include <gtest/gtest.h> + +int +main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + isc::log::initLogger(); + int result = RUN_ALL_TESTS(); + + return (result); +} diff --git a/src/hooks/dhcp/perfmon/version.cc b/src/hooks/dhcp/perfmon/version.cc new file mode 100644 index 0000000..53473eb --- /dev/null +++ b/src/hooks/dhcp/perfmon/version.cc @@ -0,0 +1,17 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 <config.h> +#include <hooks/hooks.h> + +extern "C" { + +/// @brief returns Kea hooks version. +int version() { + return (KEA_HOOKS_VERSION); +} + +} |