]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master] Add support for pool thresholds
authorShawn Routhier <sar@isc.org>
Thu, 5 Jun 2014 21:55:01 +0000 (14:55 -0700)
committerShawn Routhier <sar@isc.org>
Thu, 5 Jun 2014 21:55:01 +0000 (14:55 -0700)
Add support to set high and low thresholds for pools for
v4 and v6.  A message will be emitted when the usage of
the pool first exceeds the high threshold.  More messages
will be skipped until the usage has gone below the low
threshold and then back above the high threshold.

12 files changed:
RELNOTES
common/options.c
common/tests/Makefile.am
common/tests/Makefile.in
common/tests/misc_unittest.c [new file with mode: 0644]
includes/dhcpd.h
server/confpars.c
server/dhcp.c
server/dhcpd.conf.5
server/dhcpv6.c
server/mdb6.c
server/stables.c

index d4a16317951e3403dc03c3b074b81f4268f6683c..7a35d346b1659c79ad43ebfef4834e6f62f3a433 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -164,6 +164,12 @@ by Eric Young (eay@cryptsoft.com).
   process to start up even if the resolv.conf file has problems.
   [ISC-Bugs #35989]
 
+- Add theshold logging functionality.  Two new options,
+  log-threshold-low and log-threshold-high, indicate to the
+  server if and when it should log an error message as addresses
+  in a pool are used.
+  [ISC-Bugs #34487]
+
                        Changes since 4.3.0rc1
 
 - None
index a15c51fa68ca32b38ce16adfe784e03027f58a12..374cb573954fc30f323e1ebb0f5143d2d4ca4a13 100644 (file)
@@ -2126,6 +2126,57 @@ int get_option (result, universe, packet, lease, client_state,
        return 1;
 }
 
+/*
+ * Look for the option and dig out the value assoicated with it.
+ * Currently this is used for 1 byte integers, it maybe expanded
+ * in the future to handle other integers at which point it will
+ * need a size argument.
+ */
+int get_option_int (result, universe, packet, lease, client_state,
+                   in_options, cfg_options, options, scope, code, file, line)
+       int *result;
+       struct universe *universe;
+       struct packet *packet;
+       struct lease *lease;
+       struct client_state *client_state;
+       struct option_state *in_options;
+       struct option_state *cfg_options;
+       struct option_state *options;
+       struct binding_scope **scope;
+       unsigned code;
+       const char *file;
+       int line;
+{
+       struct option_cache *oc;
+       struct data_string d1;
+       int rcode = 0;
+
+       /* basic sanity checks */
+       if ((options == NULL) || (universe->lookup_func == NULL))
+               return (0);
+
+       /* find the option cache */
+       oc = ((*universe->lookup_func)(universe, options, code));
+       if (!oc)
+               return (0);
+
+       /* if there is a value get it into the string */
+       memset(&d1, 0, sizeof(d1));     
+       if (!evaluate_option_cache(&d1, packet, lease, client_state,
+                                  in_options, cfg_options, scope, oc,
+                                  file, line))
+               return (0);
+
+       /* If the length matches extract the value for the return */
+       if (d1.len == 1) {
+               *result = d1.data[0];
+               rcode = 1;
+       }
+       data_string_forget(&d1, MDL);
+
+       return (rcode);
+}
+
 void set_option (universe, options, option, op)
        struct universe *universe;
        struct option_state *options;
index 18456be85db8adcea604982ed94a63a28f8caa37..08d76fc371b35283f0a797ac4e291edd35a5de75 100644 (file)
@@ -8,7 +8,7 @@ ATF_TESTS =
 
 if HAVE_ATF
 
-ATF_TESTS += alloc_unittest dns_unittest
+ATF_TESTS += alloc_unittest dns_unittest misc_unittest
 
 alloc_unittest_SOURCES = test_alloc.c $(top_srcdir)/tests/t_api_dhcp.c
 alloc_unittest_LDADD = $(ATF_LDFLAGS)
@@ -22,6 +22,12 @@ dns_unittest_LDADD += ../libdhcp.a  \
        ../../omapip/libomapi.a ../../bind/lib/libirs.a \
        ../../bind/lib/libdns.a ../../bind/lib/libisccfg.a  ../../bind/lib/libisc.a
 
+misc_unittest_SOURCES = misc_unittest.c $(top_srcdir)/tests/t_api_dhcp.c
+misc_unittest_LDADD = $(ATF_LDFLAGS)
+misc_unittest_LDADD += ../libdhcp.a  \
+       ../../omapip/libomapi.a ../../bind/lib/libirs.a \
+       ../../bind/lib/libdns.a ../../bind/lib/libisccfg.a  ../../bind/lib/libisc.a
+
 check: $(ATF_TESTS)
        atf-run | atf-report
 
index 76b0ac8afe3ae510ff7939059c91a5cc6d054071..8a5d3f1eaf34be855e486dba6fa8720cc0d97c75 100644 (file)
@@ -77,7 +77,7 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-@HAVE_ATF_TRUE@am__append_1 = alloc_unittest dns_unittest
+@HAVE_ATF_TRUE@am__append_1 = alloc_unittest dns_unittest misc_unittest
 check_PROGRAMS = $(am__EXEEXT_2)
 subdir = common/tests
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
@@ -91,7 +91,7 @@ CONFIG_HEADER = $(top_builddir)/includes/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 @HAVE_ATF_TRUE@am__EXEEXT_1 = alloc_unittest$(EXEEXT) \
-@HAVE_ATF_TRUE@        dns_unittest$(EXEEXT)
+@HAVE_ATF_TRUE@        dns_unittest$(EXEEXT) misc_unittest$(EXEEXT)
 am__EXEEXT_2 = $(am__EXEEXT_1)
 am__alloc_unittest_SOURCES_DIST = test_alloc.c \
        $(top_srcdir)/tests/t_api_dhcp.c
@@ -114,6 +114,16 @@ dns_unittest_OBJECTS = $(am_dns_unittest_OBJECTS)
 @HAVE_ATF_TRUE@        ../../bind/lib/libirs.a ../../bind/lib/libdns.a \
 @HAVE_ATF_TRUE@        ../../bind/lib/libisccfg.a \
 @HAVE_ATF_TRUE@        ../../bind/lib/libisc.a
+am__misc_unittest_SOURCES_DIST = misc_unittest.c \
+       $(top_srcdir)/tests/t_api_dhcp.c
+@HAVE_ATF_TRUE@am_misc_unittest_OBJECTS = misc_unittest.$(OBJEXT) \
+@HAVE_ATF_TRUE@        t_api_dhcp.$(OBJEXT)
+misc_unittest_OBJECTS = $(am_misc_unittest_OBJECTS)
+@HAVE_ATF_TRUE@misc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@HAVE_ATF_TRUE@        ../libdhcp.a ../../omapip/libomapi.a \
+@HAVE_ATF_TRUE@        ../../bind/lib/libirs.a ../../bind/lib/libdns.a \
+@HAVE_ATF_TRUE@        ../../bind/lib/libisccfg.a \
+@HAVE_ATF_TRUE@        ../../bind/lib/libisc.a
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -146,9 +156,11 @@ 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 = $(alloc_unittest_SOURCES) $(dns_unittest_SOURCES)
+SOURCES = $(alloc_unittest_SOURCES) $(dns_unittest_SOURCES) \
+       $(misc_unittest_SOURCES)
 DIST_SOURCES = $(am__alloc_unittest_SOURCES_DIST) \
-       $(am__dns_unittest_SOURCES_DIST)
+       $(am__dns_unittest_SOURCES_DIST) \
+       $(am__misc_unittest_SOURCES_DIST)
 RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
        ctags-recursive dvi-recursive html-recursive info-recursive \
        install-data-recursive install-dvi-recursive \
@@ -334,6 +346,12 @@ ATF_TESTS = $(am__append_1)
 @HAVE_ATF_TRUE@        ../../bind/lib/libdns.a \
 @HAVE_ATF_TRUE@        ../../bind/lib/libisccfg.a \
 @HAVE_ATF_TRUE@        ../../bind/lib/libisc.a
+@HAVE_ATF_TRUE@misc_unittest_SOURCES = misc_unittest.c $(top_srcdir)/tests/t_api_dhcp.c
+@HAVE_ATF_TRUE@misc_unittest_LDADD = $(ATF_LDFLAGS) ../libdhcp.a \
+@HAVE_ATF_TRUE@        ../../omapip/libomapi.a ../../bind/lib/libirs.a \
+@HAVE_ATF_TRUE@        ../../bind/lib/libdns.a \
+@HAVE_ATF_TRUE@        ../../bind/lib/libisccfg.a \
+@HAVE_ATF_TRUE@        ../../bind/lib/libisc.a
 all: all-recursive
 
 .SUFFIXES:
@@ -380,6 +398,10 @@ dns_unittest$(EXEEXT): $(dns_unittest_OBJECTS) $(dns_unittest_DEPENDENCIES) $(EX
        @rm -f dns_unittest$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(dns_unittest_OBJECTS) $(dns_unittest_LDADD) $(LIBS)
 
+misc_unittest$(EXEEXT): $(misc_unittest_OBJECTS) $(misc_unittest_DEPENDENCIES) $(EXTRA_misc_unittest_DEPENDENCIES) 
+       @rm -f misc_unittest$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(misc_unittest_OBJECTS) $(misc_unittest_LDADD) $(LIBS)
+
 mostlyclean-compile:
        -rm -f *.$(OBJEXT)
 
@@ -387,6 +409,7 @@ distclean-compile:
        -rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc_unittest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_api_dhcp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_alloc.Po@am__quote@
 
diff --git a/common/tests/misc_unittest.c b/common/tests/misc_unittest.c
new file mode 100644 (file)
index 0000000..6cefa6e
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <atf-c.h>
+#include "dhcpd.h"
+
+struct basic_test {
+       int count;
+       int used_0;
+       int used_25;
+       int used_50;
+       int used_75;
+       int used_100;
+};
+
+struct basic_test basic_values[] =
+       {{         0, 0,         0,          0,          0,          0},
+        {        10, 0,         2,          5,          7,         10},
+        {        20, 0,         5,         10,         15,         20},
+        {        50, 0,        12,         25,         37,         50},
+        {       100, 0,        25,         50,         75,        100},
+        {      1000, 0,       250,        500,        750,       1000},
+        {     10000, 0,      2500,       5000,       7500,      10000},
+        {    100000, 0,     25000,      50000,      75000,     100000},
+        {   1000000, 0,    250000,     500000,     750000,    1000000},
+        {  10000000, 0,   2500000,    5000000,    7500000,   10000000},
+        { 100000000, 0,  25000000,   50000000,   75000000,  100000000},
+        {1000000000, 0, 250000000,  500000000,  750000000, 1000000000},
+        {2000000000, 0, 500000000, 1000000000, 1500000000, 2000000000},
+        {-1, 0, 0, 0, 0, 0}};
+
+ATF_TC(find_percent_basic);
+
+ATF_TC_HEAD(find_percent_basic, tc)
+{
+    atf_tc_set_md_var(tc, "descr", "Verify basic percent calculation.");
+}
+
+/* This test does a simple check to see if we get the right value
+ * given a count and a percnetage of that count
+ */
+ATF_TC_BODY(find_percent_basic, tc)
+{
+    struct basic_test *basic_value;
+    int used;
+
+    for (basic_value = &basic_values[0];
+        basic_value->count != -1;
+        basic_value++) {
+       used = FIND_PERCENT(basic_value->count, 0);
+       if (used != basic_value->used_0) {
+           atf_tc_fail("Wrong value for 0 - count: %d, used %d",
+                       basic_value->count, used);
+       }
+
+       used = FIND_PERCENT(basic_value->count, 25);
+       if (used != basic_value->used_25) {
+           atf_tc_fail("Wrong value for 25 - count: %d, used %d",
+                       basic_value->count, used);
+       }
+
+       used = FIND_PERCENT(basic_value->count, 50);
+       if (used != basic_value->used_50) {
+           atf_tc_fail("Wrong value for 50 - count: %d, used %d",
+                       basic_value->count, used);
+       }
+
+       used = FIND_PERCENT(basic_value->count, 75);
+       if (used != basic_value->used_75) {
+           atf_tc_fail("Wrong value for 75 - count: %d, used %d",
+                       basic_value->count, used);
+       }
+
+       used = FIND_PERCENT(basic_value->count, 100);
+       if (used != basic_value->used_100) {
+           atf_tc_fail("Wrong value for 100 - count: %d, used %d",
+                       basic_value->count, used);
+       }
+    }
+    return;
+}
+
+ATF_TC(find_percent_adv);
+
+ATF_TC_HEAD(find_percent_adv, tc)
+{
+    atf_tc_set_md_var(tc, "descr", "Verify advanced percent calculation.");
+}
+
+/* This test tries some more complicated items, such as using the macro
+ * in a function or passing expressions into macro
+ */
+ATF_TC_BODY(find_percent_adv, tc)
+{
+    if (FIND_PERCENT(10*10, 10) != 10) {
+       atf_tc_fail("Wrong value for adv 1");
+    }
+
+    if (FIND_PERCENT(20*20, 80) != 320) {
+       atf_tc_fail("Wrong value for adv 2");
+    }
+
+    if (FIND_PERCENT(1000000*1000, 50) != 500000000) {
+       atf_tc_fail("Wrong value for adv 3");
+    }
+
+    if (FIND_PERCENT(100+100, 10) != 20) {
+       atf_tc_fail("Wrong value for adv 4");
+    }
+
+    if (FIND_PERCENT(1000+2000, 90) != 2700) {
+       atf_tc_fail("Wrong value for adv 5");
+    }
+
+    if (FIND_PERCENT(10000 - 8000, 70) != 1400) {
+       atf_tc_fail("Wrong value for adv 6");
+    }
+
+    if (FIND_PERCENT(2000000000 / 1000, 25) != 500000) {
+       atf_tc_fail("Wrong value for adv 7");
+    }
+
+    if (FIND_PERCENT(10*10, 10)/2 != 5) {
+       atf_tc_fail("Wrong value for adv 8");
+    }
+
+    if (FIND_PERCENT(100*10, 50) * 2 != 1000) {
+       atf_tc_fail("Wrong value for adv 9");
+    }
+
+    if (FIND_PERCENT(100*10, 50) * 2 > 1000) {
+       atf_tc_fail("Wrong value for adv 10");
+    }
+
+    if (FIND_PERCENT(100+100, 20) * 2 < 60) {
+       atf_tc_fail("Wrong value for adv 11");
+    }
+
+    return;
+}
+
+       
+/* This macro defines main() method that will call specified
+   test cases. tp and simple_test_case names can be whatever you want
+   as long as it is a valid variable identifier. */
+ATF_TP_ADD_TCS(tp)
+{
+    ATF_TP_ADD_TC(tp, find_percent_basic);
+    ATF_TP_ADD_TC(tp, find_percent_adv);
+
+    return (atf_no_error());
+}
index 45bdd6ab802fef6b62b58e04fda507c3fb33223b..6692026c889f6b2f5633e7ff1122d872829f2f43 100644 (file)
@@ -730,6 +730,8 @@ struct lease_state {
 #define SV_DDNS_LOCAL_ADDRESS4         80
 #define SV_DDNS_LOCAL_ADDRESS6         81
 #define SV_IGNORE_CLIENT_UIDS          82
+#define SV_LOG_THRESHOLD_LOW           83
+#define SV_LOG_THRESHOLD_HIGH          84
 
 #if !defined (DEFAULT_PING_TIMEOUT)
 # define DEFAULT_PING_TIMEOUT 1
@@ -925,6 +927,8 @@ struct pool {
 #if defined (FAILOVER_PROTOCOL)
        dhcp_failover_state_t *failover_peer;
 #endif
+       int logged;             /* already logged a message */
+       int low_threshold;      /* low threshold to restart logging */
 };
 
 struct shared_network {
@@ -1606,6 +1610,10 @@ struct ipv6_pond {
        struct ipv6_pool **ipv6_pools;  /* NULL-terminated array */
        int last_ipv6_pool;             /* offset of last IPv6 pool
                                           used to issue a lease */
+       int num_total;                  /* Total number of elements in the pond */
+       int num_active;                 /* Number of elements in the pond in use */
+       int logged;                     /* already logged a message */
+       int low_threshold;              /* low threshold to restart logging */
 };
 
 /* Flags and state for dhcp_ddns_cb_t */
@@ -1774,6 +1782,11 @@ int get_option (struct data_string *, struct universe *,
                struct option_state *, struct option_state *,
                struct option_state *, struct binding_scope **, unsigned,
                const char *, int);
+int get_option_int (int *, struct universe *,
+                   struct packet *, struct lease *, struct client_state *,
+                   struct option_state *, struct option_state *,
+                   struct option_state *, struct binding_scope **, unsigned,
+                   const char *, int);
 void set_option (struct universe *, struct option_state *,
                 struct option_cache *, enum statement_op);
 struct option_cache *lookup_option (struct universe *,
@@ -3617,3 +3630,12 @@ void mark_interfaces_unavailable(void);
 
 #define MAX_ADDRESS_STRING_LEN \
    (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"))
+
+/* Find the percentage of count.  We need to try two different
+ * ways to avoid rounding mistakes.
+ */
+#define FIND_PERCENT(count, percent)   \
+       ((count) > (INT_MAX / 100) ?    \
+        ((count) / 100) * (percent) : ((count) * (percent)) / 100)
+
+       
index a8fe1fb4ee57fd2ff08ad9ea74089593a76dd1b0..8a5a4b33dab3ea32ccca0200b4dba4d08ba716ef 100644 (file)
@@ -3837,6 +3837,12 @@ add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
         */
        ipv6_pool_reference(&pond->ipv6_pools[num_pools], pool, MDL);
        pond->ipv6_pools[num_pools+1] = NULL;
+       /* Update the number of elements in the pond.  Conveniently
+        * we have the total size of the block in bits and the amount
+        * we would allocate per element in units.  For an address units
+        * will always be 128, for a prefix it will be something else.
+        */
+       pond->num_total += 1 << (units - bits);
 }
 
 /*!
index 80398176b1e5da6546807ed7f3275b41df137b0b..dbc2d5666c56db9dc75973e6bca11768c131bb72 100644 (file)
@@ -1745,6 +1745,98 @@ void nak_lease (packet, cip)
 
 }
 
+void check_pool_threshold (packet, lease, state)
+     struct packet *packet;
+     struct lease *lease;
+     struct lease_state *state;
+
+{
+
+       struct pool *pool = lease->pool;
+       int used, count, high_threshold, poolhigh = 0, poollow = 0;
+       char *shared_name = "no name";
+
+       if (pool == NULL)
+               return;
+
+       /* get a pointer to the name if we have one */
+       if ((pool->shared_network != NULL) &&
+           (pool->shared_network->name != NULL)) {
+               shared_name = pool->shared_network->name;
+       }
+
+       count = pool->lease_count;
+       used = count - (pool->free_leases + pool->backup_leases);
+
+       /* The logged flag indicates if we have already crossed the high
+        * threshold and emitted a log message.  If it is set we check to
+        * see if we have re-crossed the low threshold and need to reset
+        * things.  When we cross the high threshold we determine what
+        * the low threshold is and save it into the low_threshold value.
+        * When we cross that threshold we reset the logged flag and
+        * the low_threshold to 0 which allows the high threshold message
+        * to be emitted once again.
+        * if we haven't recrossed the boundry we don't need to do anything.
+        */
+       if (pool->logged !=0) {
+               if (used <= pool->low_threshold) {
+                       pool->low_threshold = 0;
+                       pool->logged = 0;
+                       log_error("Pool threshold reset - shared subnet: %s; "
+                                 "address: %s; low threshold %d/%d.",
+                                 shared_name, piaddr(lease->ip_addr),
+                                 used, count);
+               }
+               return;
+       }
+
+       /* find the high threshold */
+       if (get_option_int(&poolhigh, &server_universe, packet, lease,  NULL,
+                          packet->options, state->options, state->options,
+                          &lease->scope, SV_LOG_THRESHOLD_HIGH, MDL) == 0) {
+               /* no threshold bail out */
+               return;
+       }
+
+       /* We do have a threshold for this pool, see if its valid */
+       if ((poolhigh <= 0) || (poolhigh > 100)) {
+               /* not valid */
+               return;
+       }
+
+       /* we have a valid value, have we exceeded it */
+       high_threshold = FIND_PERCENT(count, poolhigh);
+       if (used < high_threshold) {
+               /* nope, no more to do */
+               return;
+       }
+
+       /* we've exceeded it, output a message */
+       log_error("Pool threshold exceeded - shared subnet: %s; "
+                 "address: %s; high threshold %d%% %d/%d.",
+                 shared_name, piaddr(lease->ip_addr),
+                 poolhigh, used, count);
+
+       /* handle the low threshold now, if we don't
+        * have a valid one we default to 0. */
+       if ((get_option_int(&poollow, &server_universe, packet, lease,  NULL,
+                           packet->options, state->options, state->options,
+                           &lease->scope, SV_LOG_THRESHOLD_LOW, MDL) == 0) ||
+           (poollow > 100)) {
+               poollow = 0;
+       }
+
+       /*
+        * If the low theshold is higher than the high threshold we continue to log
+        * If it isn't then we set the flag saying we already logged and determine
+        * what the reset threshold is.
+        */
+       if (poollow < poolhigh) {
+               pool->logged = 1;
+               pool->low_threshold = FIND_PERCENT(count, poollow);
+       }
+}
+
 void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
        struct packet *packet;
        struct lease *lease;
@@ -2390,6 +2482,14 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
                        data_string_forget(&d1, MDL);
                }
 
+
+               /*
+                * If this is an ack check to see if we have used enough of
+                * the pool to want to log a message
+                */
+               if (offer == DHCPACK)
+                       check_pool_threshold(packet, lease, state);
+
                /* a client requests an address which is not yet active*/
                if (lease->pool && lease->pool->valid_from && 
                     cur_time < lease->pool->valid_from) {
@@ -2410,7 +2510,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
                b) extend lease only up to the expiration date, but not
                below min-lease-time
                Setting min-lease-time is essential for this to work!
-               The value of min-lease-time determines the lenght
+               The value of min-lease-time determines the length
                of the transition window:
                A client renewing a second before the deadline will
                get a min-lease-time lease. Since the current ip might not
index ea34edc2d9fc5c5122a8a2124dc9fef393677132..be624792d6835e4381da35217d23ed8dd062b03e 100644 (file)
@@ -2476,6 +2476,31 @@ possible.
 .RE
 .PP
 The
+.I log-threshold-high
+and 
+.I log-threshold-low
+statements
+.RS 0.25i
+.PP
+.B log-threshold-high \fIpercentage\fB;\fR
+.PP
+.B log-threshold-low \fIpercentage\fB;\fR
+.PP
+The \fIlog-threshold-low\fR and \fIlog-threshold-high\fR statements
+are used to control when a message is output about pool usage.  The
+value for both of them is the percentage of the pool in use.  If the
+high threshold is 0 or has not been specified, no messages will be
+produced.  If a high threshold is given, a message is output once the
+pool usage passes that level.  After that, no more messages will be
+output until the pool usage falls below the low threshold.  If the low
+threshold is not given, it default to a value of zero.
+.PP
+A special case occurs when the low threshold is set to be higer than
+the high threshold.  In this case, a message will be generated each time
+a lease is acknowledged when the pool usage is above the high threshold.
+.RE
+.PP
+The
 .I max-lease-time
 statement
 .RS 0.25i
index d1a425530629ab30d794482f441556bc805c63f8..112d1e1c6540a6efbed2ba40eb400bbac6368ad9 100644 (file)
@@ -796,6 +796,99 @@ set_status_code(u_int16_t status_code, const char *status_message,
        return ret_val;
 }
 
+void check_pool6_threshold(struct reply_state *reply,
+                          struct iasubopt *lease)
+{
+       struct ipv6_pond *pond;
+       int used, count, high_threshold, poolhigh = 0, poollow = 0;
+       char *shared_name = "no name";
+       char tmp_addr[INET6_ADDRSTRLEN];
+
+       if ((lease->ipv6_pool == NULL) || (lease->ipv6_pool->ipv6_pond == NULL))
+               return;
+       pond = lease->ipv6_pool->ipv6_pond;
+
+       count = pond->num_total;
+       used = pond->num_active;
+
+       /* The logged flag indicates if we have already crossed the high
+        * threshold and emitted a log message.  If it is set we check to
+        * see if we have re-crossed the low threshold and need to reset
+        * things.  When we cross the high threshold we determine what
+        * the low threshold is and save it into the low_threshold value.
+        * When we cross that threshold we reset the logged flag and
+        * the low_threshold to 0 which allows the high threshold message
+        * to be emitted once again.
+        * if we haven't recrossed the boundry we don't need to do anything.
+        */
+       if (pond->logged !=0) {
+               if (used <= pond->low_threshold) {
+                       pond->low_threshold = 0;
+                       pond->logged = 0;
+                       log_error("Pool threshold reset - shared subnet: %s; "
+                                 "address: %s; low threshold %d/%d.",
+                                 shared_name,
+                                 inet_ntop(AF_INET6, &lease->addr,
+                                           tmp_addr, sizeof(tmp_addr)),
+                                 used, count);
+               }
+               return;
+       }
+
+       /* find the high threshold */
+       if (get_option_int(&poolhigh, &server_universe, reply->packet, NULL,
+                          NULL, reply->packet->options, reply->opt_state,
+                          reply->opt_state, &lease->scope,
+                          SV_LOG_THRESHOLD_HIGH, MDL) == 0) {
+               /* no threshold bail out */
+               return;
+       }
+
+       /* We do have a threshold for this pool, see if its valid */
+       if ((poolhigh <= 0) || (poolhigh > 100)) {
+               /* not valid */
+               return;
+       }
+
+       /* we have a valid value, have we exceeded it */
+       high_threshold = FIND_PERCENT(count, poolhigh);
+       if (used < high_threshold) {
+               /* nope, no more to do */
+               return;
+       }
+
+       /* we've exceeded it, output a message */
+       if ((pond->shared_network != NULL) &&
+           (pond->shared_network->name != NULL)) {
+               shared_name = pond->shared_network->name;
+       }
+       log_error("Pool threshold exceeded - shared subnet: %s; "
+                 "address: %s; high threshold %d%% %d/%d.",
+                 shared_name,
+                 inet_ntop(AF_INET6, &lease->addr, tmp_addr, sizeof(tmp_addr)),
+                 poolhigh, used, count);
+
+       /* handle the low threshold now, if we don't
+        * have one we default to 0. */
+       if ((get_option_int(&poollow, &server_universe, reply->packet, NULL,
+                           NULL, reply->packet->options, reply->opt_state,
+                           reply->opt_state, &lease->scope,
+                           SV_LOG_THRESHOLD_LOW, MDL) == 0) ||
+           (poollow > 100)) {
+               poollow = 0;
+       }
+
+       /*
+        * If the low theshold is higher than the high threshold we continue to log
+        * If it isn't then we set the flag saying we already logged and determine
+        * what the reset threshold is.
+        */
+       if (poollow < poolhigh) {
+               pond->logged = 1;
+               pond->low_threshold = FIND_PERCENT(count, poollow);
+       }
+}
+
 /*
  * We have a set of operations we do to set up the reply packet, which
  * is the same for many message types.
@@ -1939,6 +2032,8 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) {
                                             tmp, NULL, reply->opt_state);
                        }
 #endif
+                       /* Do our threshold check. */
+                       check_pool6_threshold(reply, tmp);
                }
 
                /* Remove any old ia from the hash. */
@@ -2655,6 +2750,8 @@ reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) {
                                             tmp, NULL, reply->opt_state);
                        }
 #endif
+                       /* Do our threshold check. */
+                       check_pool6_threshold(reply, tmp);
                }
 
                /* Remove any old ia from the hash. */
@@ -3713,6 +3810,9 @@ reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) {
                                executable_statement_dereference
                                        (&tmp->on_star.on_commit, MDL);
                        }
+
+                       /* Do our threshold check. */
+                       check_pool6_threshold(reply, tmp);
                }
 
                /* Remove any old ia from the hash. */
index 58fec01caae6e7b44c12059b1faeff7b6811f353..6eac7fca3f2e253fde1b862f8e9a56ec6f17a900 100644 (file)
@@ -1188,6 +1188,8 @@ cleanup_lease6(ia_hash_t *ia_table,
         */
        isc_heap_delete(pool->active_timeouts, test_iasubopt->heap_index);
        pool->num_active--;
+       if (pool->ipv6_pond)
+               pool->ipv6_pond->num_active--;
 
        iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
                             sizeof(test_iasubopt->addr), MDL);
@@ -1253,6 +1255,8 @@ add_lease6(struct ipv6_pool *pool, struct iasubopt *lease,
                        isc_heap_delete(pool->active_timeouts,
                                        test_iasubopt->heap_index);
                        pool->num_active--;
+                       if (pool->ipv6_pond)
+                               pool->ipv6_pond->num_active--;
                } else {
                        isc_heap_delete(pool->inactive_timeouts,
                                        test_iasubopt->heap_index);
@@ -1287,8 +1291,12 @@ add_lease6(struct ipv6_pool *pool, struct iasubopt *lease,
                                  sizeof(tmp_iasubopt->addr), lease, MDL);
                insert_result = isc_heap_insert(pool->active_timeouts,
                                                tmp_iasubopt);
-               if (insert_result == ISC_R_SUCCESS)
+               if (insert_result == ISC_R_SUCCESS) {
                        pool->num_active++;
+                       if (pool->ipv6_pond)
+                               pool->ipv6_pond->num_active++;
+               }
+
        } else {
                tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time;
                insert_result = isc_heap_insert(pool->inactive_timeouts,
@@ -1377,6 +1385,8 @@ move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
                pool->num_active++;
                pool->num_inactive--;
                lease->state = FTS_ACTIVE;
+               if (pool->ipv6_pond)
+                       pool->ipv6_pond->num_active++;
        }
        return insert_result;
 }
@@ -1503,6 +1513,8 @@ move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease,
                lease->state = state;
                pool->num_active--;
                pool->num_inactive++;
+               if (pool->ipv6_pond)
+                       pool->ipv6_pond->num_active--;
        }
        return insert_result;
 }
index 4a5a13b1a89c213615c0c2e7267fb1b29249935e..f9b3a511cdb9c6549526f3058a297fad6c7f936d 100644 (file)
@@ -265,6 +265,8 @@ static struct option server_options[] = {
        { "ddns-local-address4", "I",           &server_universe,  80, 1 },
        { "ddns-local-address6", "6",           &server_universe,  81, 1 },
        { "ignore-client-uids", "f",            &server_universe,  82, 1 },
+       { "log-threshold-low", "B",             &server_universe,  83, 1 },
+       { "log-threshold-high", "B",            &server_universe,  84, 1 },
        { NULL, NULL, NULL, 0, 0 }
 };