]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
clientlog: allow very short rate limiting intervals
authorMiroslav Lichvar <mlichvar@redhat.com>
Wed, 14 Dec 2016 17:00:49 +0000 (18:00 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 15 Dec 2016 12:47:41 +0000 (13:47 +0100)
Support negative token shift to allow coarse rate limiting with
intervals down to -19.

clientlog.c
doc/chrony.conf.adoc

index 9dca9f13f6178060467d837e0d67c558e15e9881..105732673198e00453d5c71a16ec190de69a8f97 100644 (file)
@@ -95,7 +95,7 @@ static unsigned int max_slots;
    number of tokens spent on response are determined from configured
    minimum inverval between responses (in log2) and burst length. */
 
-#define MIN_LIMIT_INTERVAL (-TS_FRAC)
+#define MIN_LIMIT_INTERVAL (-15 - TS_FRAC)
 #define MAX_LIMIT_INTERVAL 12
 #define MIN_LIMIT_BURST 1
 #define MAX_LIMIT_BURST 255
@@ -105,7 +105,8 @@ static uint16_t max_cmd_tokens;
 static uint16_t ntp_tokens_per_packet;
 static uint16_t cmd_tokens_per_packet;
 
-/* Reduction of token rates to avoid overflow of 16-bit counters */
+/* Reduction of token rates to avoid overflow of 16-bit counters.  Negative
+   shift is used for coarse limiting with intervals shorter than -TS_FRAC. */
 static int ntp_token_shift;
 static int cmd_token_shift;
 
@@ -271,10 +272,17 @@ set_bucket_params(int interval, int burst, uint16_t *max_tokens,
   interval = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
   burst = CLAMP(MIN_LIMIT_BURST, burst, MAX_LIMIT_BURST);
 
-  /* Find smallest shift with which the maximum number fits in 16 bits */
-  for (*token_shift = 0; *token_shift < interval + TS_FRAC; (*token_shift)++) {
-    if (burst << (TS_FRAC + interval - *token_shift) < 1U << 16)
-      break;
+  if (interval >= -TS_FRAC) {
+    /* Find the smallest shift with which the maximum number fits in 16 bits */
+    for (*token_shift = 0; *token_shift < interval + TS_FRAC; (*token_shift)++) {
+      if (burst << (TS_FRAC + interval - *token_shift) < 1U << 16)
+        break;
+    }
+  } else {
+    /* Coarse rate limiting */
+    *token_shift = interval + TS_FRAC;
+    *tokens_per_packet = 1;
+    burst = MAX(1U << -*token_shift, burst);
   }
 
   *tokens_per_packet = 1U << (TS_FRAC + interval - *token_shift);
@@ -369,7 +377,12 @@ update_record(struct timespec *now, uint32_t *last_hit, uint32_t *hits,
   if (prev_hit == INVALID_TS || (int32_t)interval < 0)
     return;
 
-  new_tokens = (now_ts >> token_shift) - (prev_hit >> token_shift);
+  if (token_shift >= 0)
+    new_tokens = (now_ts >> token_shift) - (prev_hit >> token_shift);
+  else if (now_ts - prev_hit > max_tokens)
+    new_tokens = max_tokens;
+  else
+    new_tokens = (now_ts - prev_hit) << -token_shift;
   *tokens = MIN(*tokens + new_tokens, max_tokens);
 
   /* Convert the interval to scaled and rounded log2 */
index 4aea902ec950c17079d383f59ffddc37172aa7dc..d7710ad031431a376d51d9e568f1c5ef55c03e09 100644 (file)
@@ -1238,7 +1238,9 @@ in any order):
 *interval*:::
 This option sets the minimum interval between responses. It is defined as a
 power of 2 in seconds. The default value is 3 (8 seconds). The minimum value
-is -4 and the maximum value is 12.
+is -19 and the maximum value is 12. Note that with values below -4 the rate
+limiting is coarse (responses are allowed in bursts, even if the interval
+between them is shorter than the specified interval).
 *burst*:::
 This option sets the maximum number of responses that can be sent in a burst,
 temporarily exceeding the limit specified by the *interval* option. This is