]> git.ipfire.org Git - thirdparty/mtr.git/commitdiff
options: add cache mode for known hops 623/head
authoryvs <VSYakovetsky@gmail.com>
Fri, 8 May 2026 12:59:36 +0000 (16:59 +0400)
committerDarafei Praliaskouski <me@komzpa.net>
Fri, 8 May 2026 12:59:36 +0000 (16:59 +0400)
Port the mtr085 cache mode as a long-only option for current upstream.  Upstream already uses -x for XML output, so this keeps the user-facing short-option namespace unchanged and exposes only --cache SECONDS.

Ported-from: yvs2014/mtr085@0700269ce0f3f501fc33ec98176101f2f4f733eb

Ported-from: yvs2014/mtr085@0cab98cf8d2e0648f8e1bdd52da5d3122d3c091d

Original-author: yvs <VSYakovetsky@gmail.com>

man/mtr.8.in
ui/mtr.c
ui/mtr.h
ui/net.c

index 35bc545e5ae360d429dec5149b0946131ed7a39f..d94421cf2930e93bff60ad0c6a448c5e667a6e11 100644 (file)
@@ -486,6 +486,12 @@ The number of seconds to keep probe sockets open before giving up on
 the connection.  Using large values for this, especially combined with
 a short interval, will use up a lot of file descriptors.
 .TP
+.B \-\-cache \fISECONDS
+Skip probes to hops that have replied within the last
+.IR SECONDS .
+This reduces probe traffic on stable paths, but cached hops keep their
+previous statistics until they are probed again.
+.TP
 .B \-M \fIMARK\fR, \fB\-\-mark \fIMARK
 Set the mark for each packet sent through this socket similar to the
 netfilter MARK target but socket-based.
index 32fbc751ad260423ea25991c9fb24fdc62950091..4bf9190e23a47c9b13638742a685354b1fa43db6 100644 (file)
--- a/ui/mtr.c
+++ b/ui/mtr.c
@@ -121,6 +121,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out)
     fputs(" -Q, --tos NUMBER                 type of service field in IP header\n", out);       
     fputs(" -e, --mpls                       display information from ICMP extensions\n", out);       
     fputs(" -Z, --timeout SECONDS            seconds to keep probe sockets open\n", out);       
+    fputs("     --cache SECONDS              skip recently seen hops for SECONDS\n", out);
 #ifdef SO_MARK       
     fputs(" -M, --mark MARK                  mark each sent packet\n", out);
 #endif       
@@ -363,6 +364,9 @@ static void parse_arg(
         OPT_IPINFO4 = CHAR_MAX + 2,
 #ifdef ENABLE_IPV6
         OPT_IPINFO6 = CHAR_MAX + 3,
+        OPT_CACHE = CHAR_MAX + 4,
+#else
+        OPT_CACHE = CHAR_MAX + 3,
 #endif /* ifdef ENABLE_IPV6 */
     };
     static const struct option long_options[] = {
@@ -428,6 +432,7 @@ static void parse_arg(
         {"localport", 1, NULL, 'L'},    /* source port number for UDP */
         {"timeout", 1, NULL, 'Z'},      /* timeout for probe sockets */
         {"gracetime", 1, NULL, 'G'},    /* gracetime for replies after last probe */
+        {"cache", 1, NULL, OPT_CACHE},  /* skip probes to recently seen hops */
 #ifdef SO_MARK
         {"mark", 1, NULL, 'M'}, /* use SO_MARK */
 #endif
@@ -608,6 +613,14 @@ static void parse_arg(
                 error(EXIT_FAILURE, 0, "wait time must be positive");
             }
             break;
+        case OPT_CACHE:
+            ctl->cache_timeout =
+                strtoint_or_err(optarg, "invalid argument");
+            if (ctl->cache_timeout <= 0) {
+                error(EXIT_FAILURE, 0, "cache timeout must be positive");
+            }
+            ctl->cache = 1;
+            break;
         case 'Q':
             ctl->tos =
                 strtoint_or_err(optarg, "invalid argument");
@@ -929,6 +942,7 @@ int main(
     ctl.MaxPing = 10;
     ctl.WaitTime = 1.0;
     ctl.GraceTime = 5.0;
+    ctl.cache_timeout = 60;
     ctl.dns = 1;
     ctl.use_dns = 1;
     ctl.cpacketsize = 64;
index b71b43a2f370dff6685fa3778b35b3ccafb9b77d..7af3dcc89ae3be2dd9349fd4a0655fa6c2ce1336 100644 (file)
--- a/ui/mtr.h
+++ b/ui/mtr.h
@@ -108,6 +108,7 @@ struct mtr_ctl {
     int remoteport;             /* target port for TCP tracing */
     int localport;              /* source port for UDP tracing */
     int probe_timeout;          /* timeout for probe sockets */
+    int cache_timeout;          /* seconds to skip probes for recently seen hops */
     unsigned char fld_active[2 * MAXFLD];       /* SO_MARK to set for ping packet */
     int display_mode;           /* display mode selector */
     int fld_index[FLD_INDEX_SZ];        /* default display field (defined by key in net.h) and order */
@@ -117,7 +118,7 @@ struct mtr_ctl {
     void *gtk_data;             /* pointer to hold arbitrary gtk data */
     unsigned int                /* bit field to hold named booleans */
      ForceMaxPing:1,
-        use_dns:1,
+        use_dns:1, cache:1,
         show_ips:1,
         enablempls:1, dns:1, reportwide:1, Interactive:1, DisplayMode:5, CompactLayout:1;
 #ifdef HAVE_IPINFO
index ed71a5623ce048ee1c33fdd34964c819f7cef92b..3c82cd3a7b747d21f9a4e02a82bc24a96c03f1a7 100644 (file)
--- a/ui/net.c
+++ b/ui/net.c
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/select.h>
+#include <time.h>
 #include <unistd.h>
 
 #ifdef HAVE_ERROR_H
@@ -65,6 +66,7 @@ struct nethost {
     int jworst;                 /* max jitter */
     int jinta;                  /* estimated variance,? rfc1889's "Interarrival Jitter" */
     int transit;
+    time_t seen;
     int saved[SAVED_PINGS];
     int saved_seq_offset;
     struct mplslen mpls;
@@ -325,6 +327,9 @@ static void net_process_ping(
     nh->sent = 0;
     nh->up = 1;
     nh->transit = 0;
+    if (ctl->cache) {
+        nh->seen = time(NULL);
+    }
 
     net_save_return(index, sequence[seq].saved_seq, totusec);
     display_rawping(ctl, index, totusec, seq);
@@ -588,7 +593,11 @@ int net_send_batch(
         }
     }
 
-    net_send_query(ctl, batch_at, abs(packetsize));
+    if (!ctl->cache || !host[batch_at].up ||
+        host[batch_at].seen == 0 ||
+        time(NULL) - host[batch_at].seen > ctl->cache_timeout) {
+        net_send_query(ctl, batch_at, abs(packetsize));
+    }
 
     for (i = ctl->fstTTL - 1; i < batch_at; i++) {
         if (host_addr_cmp(i, &ctl->unspec_addr, ctl->af) == 0)