<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>
    perfsonar on ForwardingPlane.net
    
    </title>
    <link>https://forwardingplane.net/tags/perfsonar/</link>
    <description>Recent content 
    
    in perfsonar on ForwardingPlane.net
    </description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    
    
    <copyright>Copyright (c) 2025, all rights reserved.</copyright>
    <lastBuildDate>Sun, 02 Aug 2026 00:00:00 +0000</lastBuildDate>
    
    
        <atom:link href="https://forwardingplane.net/tags/perfsonar/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>piccolo-perf - a perfSONAR-lite for routers and SBCs</title>
      <link>https://forwardingplane.net/post/2026-08-02-piccolo-perf/</link>
      <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate>
      
      <guid>https://forwardingplane.net/post/2026-08-02-piccolo-perf/</guid>
      <description>&lt;p&gt;I have a soft spot for &lt;a href=&#34;https://www.perfsonar.net&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;perfSONAR&lt;/a&gt; . It&amp;rsquo;s the gold standard for research and education network performance measurement, and if you run a network that touches ESnet, Internet2, or any of the big R&amp;amp;E backbones, you&amp;rsquo;ve probably got a perfSONAR node (or ten) somewhere. The problem is that perfSONAR is heavy. It wants a full OS, a stack of services, and real resources. That&amp;rsquo;s fine for a dedicated measurement box and that has served perfSonar well for 20 years, but it&amp;rsquo;s a non-starter for a router, a Raspberry Pi at a remote site, or anything else you&amp;rsquo;d call &amp;ldquo;constrained.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;That gap is exactly what &lt;a href=&#34;https://github.com/retecolo/piccolo-perf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;piccolo-perf&lt;/a&gt;  is going after. It&amp;rsquo;s a single static Go binary, no runtime dependencies, that gives you TWAMP-Light, TCP bandwidth, traceroute, MTU discovery, and DNS latency measurements, plus an agent mode that turns a fleet of these into a lightweight distributed mesh - InfluxDB and Prometheus included. Dual stack throughout, which matters to me more than it probably should. Honestly, I have been working on this for 15+ years, from trying to run OWAMP on a rpi1, to helping distribute mac minis for perfSonar tools into campuses, to even running lightweight versions of the toolkit on actual L3 switchines in the early days of virtualized NOSs&#39;. This project has been a labor of love and with my recent endeavor to teach myself golang, I thought &amp;ldquo;why not give it a try with this&amp;rdquo;? The results are surprisingly useful.&lt;/p&gt;
&lt;p&gt;The measurement set:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;twamp&lt;/strong&gt; - RTT, jitter, and packet loss via TWAMP-Light (RFC 5357 §5). No TCP control session, pure UDP test packets, so it&amp;rsquo;s cheap to run and interoperable with other TWAMP-Light endpoints.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bw&lt;/strong&gt; - TCP throughput, either a native Go implementation or iperf3 if it&amp;rsquo;s present on the box.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;trace&lt;/strong&gt; - per-hop RTT and path topology via ICMP TTL/HopLimit probing, IPv4 and IPv6.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mtu&lt;/strong&gt; - effective path MTU via ICMP binary search (DF-bit on v4, Packet Too Big on v6). Useful for finding where a WireGuard tunnel or a double-encapsulated path quietly knocked your MTU down - very common in managed-service-paths.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dns&lt;/strong&gt; - A successor to &lt;a href=&#34;https://dns.qosbox.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;DNS test&lt;/a&gt;  resolver latency and success rate, independent of the system resolver.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;agent&lt;/strong&gt; - runs all of the above on a schedule, reflects TWAMP for peers, and ships results to InfluxDB and/or exposes them as Prometheus metrics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anything that needs raw sockets (mtu, trace) degrades gracefully without &lt;code&gt;CAP_NET_RAW&lt;/code&gt; rather than failing outright - it just reports &lt;code&gt;skipped=true&lt;/code&gt;. That&amp;rsquo;s a small detail, but it&amp;rsquo;s the kind of thing that tells you someone has actually run this on a box they don&amp;rsquo;t have root on. I&amp;rsquo;d be open to better ways to handle that.&lt;/p&gt;
&lt;p&gt;Getting it running is a one-liner:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;/bin/sh -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;curl -fsSL https://raw.githubusercontent.com/retecolo/piccolo-perf/main/install.sh&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and a one-shot test looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;piccolo-perf twamp -mode client -server 2001:db8::1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[TWAMP-Light-Client] Starting TWAMP-Light test to 2001:db8::1 (count=10 interval=1s timeout=5s padding=0)
[TWAMP-Light-Client] seq=1 RTT=0.823ms
...
[TWAMP-Light-Client] === TWAMP-Light Test Statistics ===
[TWAMP-Light-Client] Packets sent:     10
[TWAMP-Light-Client] Packets received: 10
[TWAMP-Light-Client] Packet loss:      0.0%
[TWAMP-Light-Client] RTT min/avg/max:  0.778 / 0.812 / 0.857 ms
[TWAMP-Light-Client] Mean jitter:      0.018 ms
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The part I find more interesting than the one-shot CLI use is agent mode, and this harkens back to the inspiration for this peoject, perfSonar. Point a handful of hosts at a config server serving a JSON topology file, and each host stands up a TWAMP reflector, a bandwidth sink, and per-measurement schedulers, then pushes results upstream:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌─────────────────────────────────────────┐
│            Each Probe Host              │
│  piccolo-perf agent                     │
│  ├── TWAMP-Light reflector (UDP)        │
│  ├── BwServer (TCP sink, port 5201)     │
│  ├── Per-measurement schedulers         │
│  ├── Config poller (HTTP, live-reload)  │
│  ├── InfluxDB writer                    │
│  ├── Prometheus /metrics                │
│  └── Local JSONL resilience store       │
└──────────┬──────────────────┬───────────┘
           │ pull config      │ push metrics
           ▼                  ▼
  ┌──────────────┐    ┌──────────────┐
  │ Config Server│    │   InfluxDB   │◀─── Grafana
  └──────────────┘    │  Prometheus  │
                       └──────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Topology can be full mesh (every host probes every other host) or hub-and-spoke, which is the more realistic shape for most of us - a handful of spokes reporting back to a hub instead of an N² mesh. There&amp;rsquo;s also a local JSONL ring buffer for intermittently-connected edge devices, so a probe that loses its uplink keeps measuring and replays results once connectivity comes back instead of just dropping data on the floor.&lt;/p&gt;
&lt;h2 id=&#34;where-this-actually-fits&#34;&gt;Where this actually fits&lt;/h2&gt; &lt;p&gt;A few use cases jump out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IPv6 test pods and lab networks.&lt;/strong&gt; If you listened to &lt;a href=&#34;https://packetpushers.net/podcasts/ipv6-buzz/ipb173-the-ipv6-test-pod-project/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;IPB173&lt;/a&gt;  or any of the recent IPv6 Buzz episodes on lab builds, this is a natural fit for exactly that kind of environment - dual-stack RTT, jitter, and MTU measurement without standing up a perfSONAR node for every pod. Hey James, lets test this out =)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPE and branch office monitoring.&lt;/strong&gt; Since it compiles to a static binary across amd64, arm64, arm, mips, ppc64le, and riscv64, it&amp;rsquo;ll run on the kind of small router or SBC that lives at a remote site where you have no business installing a full measurement stack.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VPN and tunnel path MTU troubleshooting.&lt;/strong&gt; The mtu subcommand&amp;rsquo;s binary search is a fast way to confirm whether a WireGuard or other tunnel is silently truncating your effective MTU, without reaching for tcpdump and doing the math by hand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A perfSONAR-adjacent mesh on a budget.&lt;/strong&gt; Agent mode with hub-and-spoke topology and Grafana on top gets you a reasonable approximation of a perfSONAR mesh dashboard for a fraction of the deployment overhead, which is appealing if you want visibility into a network that doesn&amp;rsquo;t justify (or fit) the full perfSONAR toolkit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s early days for the project, but the design choices - graceful degradation without root, IPv6 treated as a first-class citizen rather than an afterthought, and a resilience store for flaky links - suggest someone building this against real constraints rather than a whiteboard. Worth a look if smokeping and perfSONAR are two ends of a spectrum you&amp;rsquo;ve been missing the middle of.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
