]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
conf: add percent support to 'dnssec-jitter' and 'refresh-jitter'
authorDaniel Salzman <daniel.salzman@nic.cz>
Mon, 27 Jul 2026 10:43:06 +0000 (12:43 +0200)
committerLibor Peltan <libor.peltan@nic.cz>
Fri, 7 Aug 2026 12:32:12 +0000 (14:32 +0200)
doc/reference.rst
src/knot/conf/conf.c
src/knot/conf/conf.h
src/knot/conf/schema.c
src/knot/dnssec/context.c
src/knot/events/handlers/refresh.c

index eaef49cbd963ce5f5eebe407f846c2fdb3d01277..59a21ca97aaa4862a25a3a857bf1c956877161b6 100644 (file)
@@ -2119,7 +2119,7 @@ DNSSEC policy configuration.
      dnskey-ttl: TIME
      zone-max-ttl: TIME
      keytag-modulo: INT/INT
-     dnssec-jitter: TIME
+     dnssec-jitter: TIME | INT%
      ksk-lifetime: TIME
      zsk-lifetime: TIME
      deleg-adt: BOOL
@@ -2305,8 +2305,9 @@ dnssec-jitter
 A pseudo-random jitter added to :ref:`policy_rrsig-refresh` and subtracted from
 :ref:`policy_zsk-lifetime`.
 
-The jitter value is selected from the interval between 0 and the configured value
-and is deterministic based on the zone name.
+The jitter value (in seconds or as a percentage of the adjusted value) is selected
+from the interval between 0 and the configured value and is deterministic
+based on the zone name.
 
 The goal is to prevent DNSSEC maintenance events for a large number of configured
 zones from interfering with other regular zone events.
@@ -2828,7 +2829,7 @@ Definition of zones served by the server.
      serial-modulo: INT/INT | +INT | -INT | INT/INT+INT | INT/INT-INT
      reverse-generate: DNAME ...
      include-from: DNAME ...
-     refresh-jitter: TIME
+     refresh-jitter: TIME | INT%
      refresh-min-interval: TIME
      refresh-max-interval: TIME
      retry-min-interval: TIME
@@ -3546,8 +3547,9 @@ refresh-jitter
 
 A pseudo-random jitter that shortens the SOA refresh timer.
 
-The jitter value is selected from the interval between 0 and the configured value
-and is deterministic based on the zone name.
+The jitter value (in seconds or as a percentage of the adjusted value) is selected
+from the interval between 0 and the configured value and is deterministic
+based on the zone name.
 
 The goal is to prevent zone refreshes for a large number of configured zones
 from interfering with NOTIFY-initiated zone refreshes.
index 5c5ca330fc0b8fe0be4f865a1f949450ed7e58e9..5f0e2f1eb6c015259e5f0f833622b0fdb891bcff 100644 (file)
@@ -616,7 +616,8 @@ void conf_mix_iter_next(
 
 int64_t conf_int_alt(
        conf_val_t *val,
-       bool alternative)
+       bool alternative,
+       bool *percent)
 {
        assert(val != NULL && val->item != NULL);
        assert(val->item->type == YP_TINT ||
@@ -627,19 +628,27 @@ int64_t conf_int_alt(
 
        if (val->code == KNOT_EOK) {
                conf_val(val);
-               return yp_int(val->data);
+               return (percent == NULL) ? yp_int(val->data) : yp_int_pct(val->data, percent);
        } else {
+               if (percent != NULL) {
+                       *percent = false;
+               }
                return alternative ? val->item->var.i.dflt_alt : val->item->var.i.dflt;
        }
 }
 
 int64_t conf_jitter(
        conf_val_t *jitter_val,
+       int64_t base_value,
+       int64_t max_value,
        const knot_dname_t *zone)
 {
-       int64_t intval = conf_int(jitter_val);
+       bool percent;
+       int64_t intval = conf_int_alt(jitter_val, false, &percent);
        if (intval < 1) {
                return intval;
+       } else if (percent) {
+               intval = intval * base_value / 100;
        }
 
        SIPHASH_KEY zero_key = { 0, 0 };
@@ -649,7 +658,8 @@ int64_t conf_jitter(
        uint64_t random64 = SipHash24_End(&ctx);
        uint64_t granularity = (1 << 16);
 
-       return (1 + intval) * (random64 & (granularity - 1)) / granularity;
+       int64_t out = (1 + intval) * (random64 & (granularity - 1)) / granularity;
+       return MIN(out, max_value);
 }
 
 bool conf_bool(
index adb8f28e645df080082852b58c32291a331bfe3d..bb5da9738d23e9fa19f56e85868567ae6c1e5c85 100644 (file)
@@ -469,18 +469,20 @@ void conf_mix_iter_next(
  * Gets the numeric value of the item.
  *
  * \param[in] val          Item value.
+ * \param[out] percent     Percentual value indication.
  * \param[in] alternative  Use alternative default value.
  *
  * \return Integer.
  */
 int64_t conf_int_alt(
        conf_val_t *val,
-       bool alternative
+       bool alternative,
+       bool *percent
 );
 inline static int64_t conf_int(
        conf_val_t *val)
 {
-       return conf_int_alt(val, false);
+       return conf_int_alt(val, false, NULL);
 }
 
 /*!
@@ -490,13 +492,18 @@ inline static int64_t conf_int(
  * ...pseudo-random, deterministic based on zone name.
  *
  * \param[in] jitter_val    Jitter value item.
+ * \param[in] base_value    Base value for percentual computation.
+ * \param[in] max_value     Maximum allowed output value.
  * \param[in] zone          Zone name.
  *
  * \return Integer.
  */
 int64_t conf_jitter(
        conf_val_t *jitter_val,
-       const knot_dname_t *zone);
+       int64_t base_value,
+       int64_t max_value,
+       const knot_dname_t *zone
+);
 
 /*!
  * Gets the boolean value of the item.
index 75e7e7e522afbd70b4c022c19a7169ec01e9eaa3..d966cb23c775770dbed582deca634f9a82f98c26 100644 (file)
@@ -444,7 +444,7 @@ static const yp_item_t desc_policy[] = {
        { C_ZONE_MAX_TTL,        YP_TINT,  YP_VINT = { 0, INT32_MAX, YP_NIL, YP_STIME },
                                           CONF_IO_FRLD_ZONES },
        { C_KEYTAG_MODULO,       YP_TSTR,  YP_VSTR = { "0/1" }, YP_FNONE, { check_modulo } },
-       { C_DNSSEC_JITTER,       YP_TINT,  YP_VINT = { 0, UINT32_MAX, 0, YP_STIME } },
+       { C_DNSSEC_JITTER,       YP_TINT,  YP_VINT = { 0, UINT32_MAX, 0, YP_STIME | YP_SPERCENT } },
        { C_KSK_LIFETIME,        YP_TINT,  YP_VINT = { 0, UINT32_MAX, 0, YP_STIME },
                                           CONF_IO_FRLD_ZONES },
        { C_ZSK_LIFETIME,        YP_TINT,  YP_VINT = { 0, UINT32_MAX, DAYS(30), YP_STIME },
@@ -537,7 +537,7 @@ static const yp_item_t desc_external[] = {
        { C_SERIAL_MODULO,       YP_TSTR,  YP_VSTR = { "0/1" }, YP_FNONE, { check_modulo_shift } }, \
        { C_ZONEMD_GENERATE,     YP_TOPT,  YP_VOPT = { zone_digest, ZONE_DIGEST_NONE }, FLAGS }, \
        { C_ZONEMD_VERIFY,       YP_TBOOL, YP_VNONE, FLAGS }, \
-       { C_REFRESH_JITTER,      YP_TINT,  YP_VINT = { 0, UINT32_MAX, 0, YP_STIME } }, \
+       { C_REFRESH_JITTER,      YP_TINT,  YP_VINT = { 0, UINT32_MAX, 0, YP_STIME | YP_SPERCENT } }, \
        { C_REFRESH_MIN_INTERVAL,YP_TINT,  YP_VINT = { 2, UINT32_MAX, 2, YP_STIME } }, \
        { C_REFRESH_MAX_INTERVAL,YP_TINT,  YP_VINT = { 2, UINT32_MAX, UINT32_MAX, YP_STIME } }, \
        { C_RETRY_MIN_INTERVAL,  YP_TINT,  YP_VINT = { 1, UINT32_MAX, 1, YP_STIME } }, \
index a1a7bda4d8112809f8cc0403b01c962b65bab1ff..2759885e112db85a7468d74dc58774389f5f89ab 100644 (file)
@@ -177,9 +177,10 @@ static void policy_load(knot_kasp_policy_t *policy, conf_t *conf, conf_val_t *id
        }
 
        val = conf_id_get(conf, C_POLICY, C_DNSSEC_JITTER, id);
-       int64_t jitter = conf_jitter(&val, zone_name);
-       policy->rrsig_refresh_before += jitter;
-       policy->zsk_lifetime -= jitter;
+       policy->rrsig_refresh_before += conf_jitter(&val, policy->rrsig_refresh_before, policy->rrsig_lifetime - 1, zone_name);
+       if (policy->zsk_lifetime != 0) { // 0 ~ infinity!
+               policy->zsk_lifetime -= conf_jitter(&val, policy->zsk_lifetime, policy->zsk_lifetime - 1, zone_name);
+       }
 }
 
 static void policy_unload(knot_kasp_policy_t *policy)
@@ -390,7 +391,7 @@ int kdnssec_validation_ctx(conf_t *conf, kdnssec_ctx_t *ctx, const zone_contents
                conf_val_t val = conf_id_get(conf, C_POLICY, C_SIGNING_THREADS, &policy_id);
                ctx->policy->signing_threads = conf_int(&val);
                val = conf_id_get(conf, C_POLICY, C_RRSIG_REFRESH, &policy_id);
-               ctx->policy->rrsig_refresh_before = conf_int_alt(&val, true);
+               ctx->policy->rrsig_refresh_before = conf_int_alt(&val, true, NULL);
        } else if (threads > 0) {
                ctx->policy->signing_threads = threads;
        } else {
index e0f50410731d74d6cf22178c06dc166cad7d9991..37244cae8e47dc591ca8e9a640603c2feb0e7318 100644 (file)
@@ -204,7 +204,8 @@ static void finalize_timers_base(struct refresh_data *data, bool also_expire)
        limit_timer(conf, zone->name, &soa_refresh, "refresh",
                    C_REFRESH_MIN_INTERVAL, C_REFRESH_MAX_INTERVAL);
        conf_val_t refresh_jitter = conf_zone_get(conf, C_REFRESH_JITTER, zone->name);
-       zone->timers->next_refresh = now + soa_refresh - conf_jitter(&refresh_jitter, zone->name);
+       zone->timers->next_refresh = now + soa_refresh;
+       zone->timers->next_refresh -= conf_jitter(&refresh_jitter, soa_refresh, soa_refresh - 1, zone->name);
        zone->timers->flags |= LAST_REFRESH_OK | TIMERS_MODIFIED;
 
        if (zone->is_catalog_flag) {