]> git.gsnw.org Git - fping.git/commitdiff
new option --seqmap-timeout=MSEC
authorErik Auerswald <auerswal@unix-ag.uni-kl.de>
Mon, 21 Apr 2025 18:02:17 +0000 (20:02 +0200)
committerErik Auerswald <auerswal@unix-ag.uni-kl.de>
Thu, 19 Jun 2025 14:00:47 +0000 (16:00 +0200)
This allows to control the time after which sequence numbers
can be reused for new probe packets.  This is intended to
help using count or loop modes with tens of thousands of
target hosts.

See GH issue #385 for more information.

CHANGELOG.md
ci/test-03-forbidden.pl
ci/test-09-option-r-t.pl
ci/test-12-option-type.pl
doc/fping.pod
src/fping.c
src/options.h
src/seqmap.c
src/seqmap.h

index ca1955249939da0b92c48b46a2532dc9680e24c0..ad2e9af0281bc9e43c60b2fa0cdbc0fc043e5cfa 100644 (file)
@@ -6,6 +6,9 @@ Next
 - The -g, --generate option now also supports IPv6 addresses (#376,
   thanks @auerswal)
 
+- New option --seqmap-timeout to control the time after which sequence numbers
+  can be used again (#388, thanks @auerswal)
+
 ## Bugfixes and other changes
 
 - Fix OpenBSD warning sprintf() is often misused, please use snprintf() (#394, thanks @gsnw-sebast)
index d2db1331621d9fd7246da964b03190fd40dd81bd..84a305ffb64e6af81229a08a903fd89912dac81d 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 
-use Test::Command tests => 36;
+use Test::Command tests => 39;
 
 # fping -i 0
 my $cmd1 = Test::Command->new(cmd => "fping -i 0 -T10 -g 127.0.0.1/29");
@@ -57,7 +57,7 @@ $cmd10->stdout_is_eq("");
 $cmd10->stderr_is_eq("fping: backoff factor 5.1 not valid, must be between 1.0 and 5.0\n");
 
 # non-negative only
-for my $arg (qw(i p Q t)) {
+for my $arg (qw(i p Q t -seqmap-timeout)) {
     my $cmd = Test::Command->new(cmd => "fping -$arg -1");
     $cmd->exit_is_num(1);
     $cmd->stdout_is_eq("");
index 2c26d248d38b0ea1c013e2cd5689e9c7fc18ab66..aace972c6dbe31dd9bdb854c69af7ee59a32e99e 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 
-use Test::Command tests => 30;
+use Test::Command tests => 36;
 use Test::More;
 
 #  -R         random bytes
@@ -146,4 +146,20 @@ $cmd->stdout_is_eq("");
 $cmd->stderr_is_eq("fping: can't parse source address: bla\n");
 }
 
+# fping --seqmap-timeout N
+{
+my $cmd = Test::Command->new(cmd => "fping --seqmap-timeout 20000 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_is_eq("127.0.0.1 is alive\n");
+$cmd->stderr_is_eq("");
+}
+
+# fping --seqmap-timeout N
+{
+my $cmd = Test::Command->new(cmd => "fping --seqmap-timeout 0 127.0.0.1");
+$cmd->exit_is_num(1);
+$cmd->stdout_is_eq("127.0.0.1 is unreachable\n");
+$cmd->stderr_is_eq("");
+}
+
 # (note: fping -t also tested in test-4-options-a-b.pl)
index 6514425af01a8dc1c0c3daa42c7562a2d9e25d04..5b6dac41d56bf10c36487d4f0e215cd45ddc7ba1 100755 (executable)
@@ -1,10 +1,10 @@
 #!/usr/bin/perl -w
 
-use Test::Command tests => 84;
+use Test::Command tests => 90;
 use Test::More;
 
 # some options require a numeric argument
-for my $arg (qw(b B c C H i O p Q r t x X)) {
+for my $arg (qw(b B c C H i O p Q r t x X -seqmap-timeout)) {
     for my $test_input (qw(xxx '')) {
         my $cmd = Test::Command->new(cmd => "fping -$arg $test_input");
         $cmd->exit_is_num(1);
index d10014f4cd301eccb4c345604288610202c018d5..b466c309029a181a638c066ca0d9a04b7c8172c1 100644 (file)
@@ -241,6 +241,11 @@ Print cumulative statistics upon exit.
 
 Set source address.
 
+=item B<--seqmap-timeout>=I<MSEC>
+
+Timeout for sequence number mappings in milliseconds. Sequence numbers can
+be reused after the timeout. The default value is 10000ms.
+
 =item B<-t>, B<--timeout>=I<MSEC>
 
 Initial target timeout in milliseconds. In the default, non-loop mode, the
index 86da559df661db65804ca865f7d2d2e3b71bafe7..ba21e746e1bb9369d9845b0683795f23491998ab 100644 (file)
@@ -317,6 +317,7 @@ unsigned int debugging = 0;
 /* all time-related values are int64_t nanoseconds */
 unsigned int retry = DEFAULT_RETRY;
 int64_t timeout = (int64_t)DEFAULT_TIMEOUT * 1000000;
+int64_t seqmap_timeout = (int64_t)DEFAULT_SEQMAP_TIMEOUT * 1000000;
 int64_t interval = (int64_t)DEFAULT_INTERVAL * 1000000;
 int64_t perhost_interval = (int64_t)DEFAULT_PERHOST_INTERVAL * 1000000;
 float backoff = DEFAULT_BACKOFF_FACTOR;
@@ -578,6 +579,7 @@ int main(int argc, char **argv)
         { "check-source", '0', OPTPARSE_NONE },
         { "print-tos", '0', OPTPARSE_NONE },
         { "print-ttl", '0', OPTPARSE_NONE },
+        { "seqmap-timeout", '0', OPTPARSE_REQUIRED },
 #if defined(DEBUG) || defined(_DEBUG)
         { NULL, 'z', OPTPARSE_REQUIRED },
 #endif
@@ -638,6 +640,12 @@ int main(int argc, char **argv)
                     }
                 }
 #endif
+            } else if (strstr(optparse_state.optlongname, "seqmap-timeout") != NULL) {
+                if (sscanf(optparse_state.optarg, "%f", &opt_value_float) != 1)
+                    usage(1);
+                if (opt_value_float < 0)
+                    usage(1);
+                seqmap_timeout = opt_value_float * 1000000;
             } else {
                 usage(1);
             }
@@ -1077,6 +1085,7 @@ int main(int argc, char **argv)
             prog, count, retry, interval / 1e6);
         fprintf(stderr, "  perhost_interval: %.0f ms, timeout: %.0f\n",
             perhost_interval / 1e6, timeout / 1e6);
+        fprintf(stderr, "  seqmap_timeout: %.0f\n", seqmap_timeout / 1e6);
         fprintf(stderr, "  ping_data_size = %u, trials = %u\n",
             ping_data_size, trials);
 
@@ -1355,7 +1364,7 @@ int main(int argc, char **argv)
 
     last_send_time = 0;
 
-    seqmap_init();
+    seqmap_init(seqmap_timeout);
 
     /* main loop */
     main_loop();
@@ -3446,6 +3455,7 @@ void usage(int is_error)
     fprintf(out, "   -r, --retry=N      number of retries (default: %d)\n", DEFAULT_RETRY);
     fprintf(out, "   -R, --random       random packet data (to foil link data compression)\n");
     fprintf(out, "   -S, --src=IP       set source address\n");
+    fprintf(out, "       --seqmap-timeout=MSEC sequence number mapping timeout (default: %.0f ms)\n", seqmap_timeout / 1e6);
     fprintf(out, "   -t, --timeout=MSEC individual target initial timeout (default: %.0f ms,\n", timeout / 1e6);
     fprintf(out, "                      except with -l/-c/-C, where it's the -p period up to 2000 ms)\n");
     fprintf(out, "       --check-source discard replies not from target address\n");
index 229975c38d66e66df871ddf5c41b36b0c913fd75..29bbd5316221df85553694fc871a64a2c9aba98d 100644 (file)
 #define AUTOTUNE_TIMEOUT_MAX  2000
 #endif
 
+/* default time in milliseconds before a sequence number can be used again */
+#ifndef DEFAULT_SEQMAP_TIMEOUT
+#define DEFAULT_SEQMAP_TIMEOUT 10000
+#endif
 
 #ifndef DEFAULT_RETRY 
 #define DEFAULT_RETRY 3            /* number of times to retry a host */
index 7675bc15e11cf2efe694fd4a1d04d7ea3930c450..7d1d6438ffd0b80fde7418e0bd0533d482c31360 100644 (file)
@@ -48,7 +48,7 @@
 /* description of the data structure used:
  *
  * - we assume that no more than SEQMAP_MAXSEQ (65535) pings are sent in
- *   the timeout interval (SEQMAP_TIMEOUT_IN_NS)
+ *   the timeout interval (seqmap_timeout_in_ns)
  * - we store the values in an array with SEQMAP_MAXSEQ elements
  * - current sequence number % SEQMAP_MAXSEQ gives the current index
  * - when entering a value, we check that the current entry is expired
 
 static SEQMAP_VALUE* seqmap_map = NULL;
 static unsigned int seqmap_next_id = 0;
+static int64_t seqmap_timeout_in_ns;
 
-#define SEQMAP_TIMEOUT_IN_NS INT64_C(10000000000)
 #define SEQMAP_UNASSIGNED_HOST_NR UINT_MAX
 
-void seqmap_init()
+void seqmap_init(int64_t timeout)
 {
+    seqmap_timeout_in_ns = timeout;
     seqmap_map = calloc(SEQMAP_MAXSEQ, sizeof(SEQMAP_VALUE));
     if (seqmap_map == NULL) {
         perror("malloc error (can't allocate seqmap_map)");
@@ -81,9 +82,9 @@ unsigned int seqmap_add(unsigned int host_nr, unsigned int ping_count, int64_t t
     /* check if expired (note that unused seqmap values will have fields set to
      * 0, so will be seen as expired */
     next_value = &seqmap_map[seqmap_next_id];
-    if (next_value->ping_ts != 0 && timestamp - next_value->ping_ts < SEQMAP_TIMEOUT_IN_NS) {
+    if (next_value->ping_ts != 0 && timestamp - next_value->ping_ts < seqmap_timeout_in_ns) {
         fprintf(stderr, "fping error: not enough sequence numbers available! (expire_timeout=%" PRId64 ", host_nr=%d, ping_count=%d, seqmap_next_id=%d)\n",
-            SEQMAP_TIMEOUT_IN_NS, host_nr, ping_count, seqmap_next_id);
+            seqmap_timeout_in_ns, host_nr, ping_count, seqmap_next_id);
         exit(4);
     }
 
@@ -112,7 +113,7 @@ SEQMAP_VALUE* seqmap_fetch(unsigned int id, int64_t now)
     value = &seqmap_map[id];
 
     /* verify that value is not expired */
-    if (now - value->ping_ts >= SEQMAP_TIMEOUT_IN_NS) {
+    if (now - value->ping_ts >= seqmap_timeout_in_ns) {
         dbg_printf("seqmap_fetch(%d) -> host: %d, index: %d -> DISCARDED %ld\n", id, value->host_nr, value->ping_count,
                 now - value->ping_ts);
         return NULL;
index a1780b0a18e6462d4da7c79b0c9c0a4e227c2e21..9dc14dc2316ef7a5a53ea0da18ee9c552f67776f 100644 (file)
@@ -14,7 +14,7 @@ typedef struct seqmap_value
 
 #define SEQMAP_MAXSEQ 65535
 
-void seqmap_init();
+void seqmap_init(int64_t timeout);
 unsigned int seqmap_add(unsigned int host_nr, unsigned int ping_count, int64_t now);
 SEQMAP_VALUE *seqmap_fetch(unsigned int id, int64_t now);