<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Firewall locks up - root cause analysis + solutions (pfSense Plus 26.03.1 on Supermicro Xeon D-1521)]]></title><description><![CDATA[<p dir="auto">Included in analysis:</p>
<ul>
<li><a href="https://forum.netgate.com/topic/178438/firewall-locks-up-possibly-unbound-config?_=1784622186870">Firewall locks up, possibly unbound config</a></li>
</ul>
<p dir="auto"><strong>Hopefully this report will help others.</strong></p>
<ul>
<li>With the help of AI I tracked down various issues and hard lock ups on my pfSense node (experiencing it on and off for months now).</li>
<li>Divided over two posts. First post: problem setting + fixes. Second post: extended report + source code of files.</li>
</ul>
<h2><a class="anchor-offset" name="the-problem"></a>The problem</h2>
<p dir="auto">My pfSense box was suffering from gradual internet speed degradation over<br />
several days, always ending in a complete system lockup requiring a physical<br />
reset. The daily scheduled reboot (cron) didn't always fire -- the system was<br />
already too far gone. No crash dumps, no kernel panic messages in logs, just<br />
a multi-hour silent gap followed by a clean boot after pressing the reset<br />
button.</p>
<p dir="auto"><strong>Platform</strong>: Supermicro Xeon D-1521, 32 GB RAM, pfSense Plus 26.03.1-snapshots<br />
(FreeBSD 16.0-CURRENT #12, build date May 20 2026).</p>
<h2><a class="anchor-offset" name="diagnosis"></a>Diagnosis</h2>
<p dir="auto">WAN: FTTH 8 Gbps via PPPoE.</p>
<p dir="auto">Three root causes were identified, one primary and two contributing.</p>
<h3><a class="anchor-offset" name="root-cause-1-primary-cpu-stuck-at-half-speed"></a>Root cause 1 (primary): CPU stuck at half speed</h3>
<p dir="auto">The smoking gun was checking CPU frequency:</p>
<pre><code class="language-sh">sysctl dev.cpu.0.freq
# Result: 1100 MHz (rated: 2401 MHz)
</code></pre>
<p dir="auto">All 8 cores were running at <strong>1.1 GHz</strong> -- less than half the rated <strong>2.4 GHz</strong>.<br />
During the diagnosis, the frequency bounced between 800 and 1700 MHz, dropping<br />
within <strong>one second</strong> of being manually set back to max.</p>
<p dir="auto">The dmesg boot log had the clue:</p>
<pre><code>sysctl_register_oid: can't re-use a leaf (machdep.hwpstate_pkg_ctrl)!
</code></pre>
<p dir="auto">Two FreeBSD drivers are conflicting on this kernel:</p>
<ul>
<li><strong><code>est</code> (Enhanced SpeedStep)</strong> -- driver module, loads and registers first</li>
<li><strong><code>hwpstate_intel</code> (Hardware P-State)</strong> -- tries to register the same sysctl, fails</li>
</ul>
<p dir="auto">The EST driver aggressively downclocks for power saving and does not ramp back<br />
up fast enough under network interrupt load. With <strong>15 million NIC interrupts</strong><br />
in 50 minutes (4,843/sec) and an interrupt queue already dropping packets<br />
(<code>intr_queue_drops: 453</code>), the system drowns.</p>
<p dir="auto">The degradation cycle:</p>
<pre><code>Boot &gt; CPU at 1100 MHz &gt; NIC interrupts pile up &gt; 
Latency increases &gt; Retransmits add more interrupts &gt; 
CPU can't catch up &gt; Interrupts overflow &gt; 
Speed drops &gt; Eventually unresponsive
</code></pre>
<h3><a class="anchor-offset" name="root-cause-2-swap-overcommit"></a>Root cause 2: Swap overcommit</h3>
<pre><code>vm.swap_total:   1.0 GB
vm.swap_reserved: 3.6 GB   (335% overcommit)
</code></pre>
<p dir="auto">The kernel was reserving 3.6x more swap than actually existed. Under the<br />
pfBlockerNG update cycle, this could trigger page allocation failures.</p>
<h3><a class="anchor-offset" name="root-cause-3-unbound-memory-baseline"></a>Root cause 3: unbound memory baseline</h3>
<p dir="auto">unbound RSS was <strong>1,071 MB</strong> after 50 minutes. The pfBlockerNG python module<br />
loads its DNSBL data structures entirely inside unbound's process space<br />
(85 MB zone file + 16 MB data file parsed into memory). Cache tuning only<br />
constrains runtime growth, not this baseline.</p>
<h2><a class="anchor-offset" name="fixes-applied"></a>Fixes applied</h2>
<h3><a class="anchor-offset" name="cpu-frequency-primary-fix"></a>CPU frequency (primary fix)</h3>
<p dir="auto">Three-layer approach:</p>
<p dir="auto"><strong>1. Continuous watchdog script</strong> (immediate, running now)</p>
<p dir="auto">A background script resets all cores to 2401 MHz every 5 seconds:</p>
<pre><code class="language-sh">#!/bin/sh
while :; do
  for c in 0 1 2 3 4 5 6 7; do
    sysctl dev.cpu.${c}.freq=2401 &gt; /dev/null 2&gt;&amp;1
  done
  sleep 5
done
</code></pre>
<p dir="auto">Started from <code>/etc/rc.local</code> with <code>&amp;</code> (must background or boot hangs).</p>
<p dir="auto"><strong>2. Boot-level disable</strong> (will take effect after next reboot)</p>
<p dir="auto">In <code>/boot/loader.conf.local</code> (survives pfSense updates):</p>
<pre><code>hint.est.0.disabled=1
hint.acpi_throttle.0.disabled="1"
</code></pre>
<p dir="auto"><strong>3. Per-minute cron fallback</strong></p>
<p dir="auto">Added to crontab as secondary safety net. Note: EST's interval is sub-second,<br />
so a per-minute cron alone is insufficient -- the 5-second watchdog is<br />
essential.</p>
<p dir="auto"><strong>Result</strong>: CPU now stable at 2400-2401 MHz.</p>
<h3><a class="anchor-offset" name="swap"></a>Swap</h3>
<p dir="auto">Added an 8 GB swap file via mdconfig, bringing total swap to 9 GB (1 GB<br />
partition + 8 GB file). <code>swap_reserved</code> (3.5 GB) now fits comfortably within<br />
<code>swap_total</code> (9.3 GB).</p>
<h3><a class="anchor-offset" name="unbound-tuning"></a>Unbound tuning</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Parameter</th>
<th>Default</th>
<th>Tuned</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>outgoing-range</code></td>
<td>4096</td>
<td>2048</td>
</tr>
<tr>
<td><code>msg-cache-size</code></td>
<td>10m</td>
<td>5m</td>
</tr>
<tr>
<td><code>rrset-cache-size</code></td>
<td>20m</td>
<td>10m</td>
</tr>
<tr>
<td><code>cache-min-ttl</code></td>
<td>0</td>
<td>300</td>
</tr>
<tr>
<td><code>prefetch</code></td>
<td>yes</td>
<td>no</td>
</tr>
<tr>
<td><code>prefetch-key</code></td>
<td>yes</td>
<td>no</td>
</tr>
<tr>
<td><code>serve-expired</code></td>
<td>no</td>
<td>yes</td>
</tr>
</tbody>
</table>
<h3><a class="anchor-offset" name="pfblockerng-cron-priority"></a>pfBlockerNG cron priority</h3>
<p dir="auto">Main update cron lowered to <code>nice -n 19</code>.</p>
<h2><a class="anchor-offset" name="key-lessons-for-pfsense-on-freebsd-current"></a>Key lessons for pfSense on FreeBSD-CURRENT</h2>
<ol>
<li>
<p dir="auto"><strong>Always check <code>sysctl dev.cpu.0.freq</code></strong> if you see unexplained slowdowns.<br />
It should match the rated clock speed under load.</p>
</li>
<li>
<p dir="auto"><strong><code>sysctl_register_oid: can't re-use a leaf (machdep.hwpstate_pkg_ctrl)</code></strong><br />
in dmesg = EST and hwpstate_intel are conflicting. The EST driver wins but<br />
scales too aggressively.</p>
</li>
<li>
<p dir="auto"><strong><code>intr_queue_drops</code></strong> is a direct indicator of CPU starvation on packet<br />
processing. Non-zero at idle means the CPU is already overwhelmed.</p>
</li>
<li>
<p dir="auto"><strong><code>loader.conf.local</code></strong> survives pfSense package updates and config<br />
regeneration. Use it for boot-time tunables.</p>
</li>
<li>
<p dir="auto"><strong><code>vm.swap_reserved &gt;&gt; vm.swap_total</code></strong> is an OOM precursor that shows up<br />
long before <code>swapinfo</code> reports any usage. Watch this metric.</p>
</li>
<li>
<p dir="auto"><strong>A per-minute cron is NOT fast enough</strong> to counteract EST's sub-second<br />
frequency scaling. You need a watchdog loop with <code>sleep 5</code> or shorter.</p>
</li>
</ol>
]]></description><link>https://forum.netgate.com/topic/200987/firewall-locks-up-root-cause-analysis-solutions-pfsense-plus-26.03.1-on-supermicro-xeon-d-1521</link><generator>RSS for Node</generator><lastBuildDate>Fri, 16 Oct 2026 17:07:04 GMT</lastBuildDate><atom:link href="https://forum.netgate.com/topic/200987.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 21 Jul 2026 08:32:04 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Firewall locks up - root cause analysis + solutions (pfSense Plus 26.03.1 on Supermicro Xeon D-1521) on Tue, 21 Jul 2026 23:00:43 GMT]]></title><description><![CDATA[<p dir="auto">Well if you enable powerd (the daemon that drives speedstep) you do have options for it's behaviour. The default setting of high-adaptive is usually pretty good.</p>
<p dir="auto">But simply disabling that should run the CPU at full speed all the time.</p>
]]></description><link>https://forum.netgate.com/post/1245463</link><guid isPermaLink="true">https://forum.netgate.com/post/1245463</guid><dc:creator><![CDATA[stephenw10]]></dc:creator><pubDate>Tue, 21 Jul 2026 23:00:43 GMT</pubDate></item><item><title><![CDATA[Reply to Firewall locks up - root cause analysis + solutions (pfSense Plus 26.03.1 on Supermicro Xeon D-1521) on Tue, 21 Jul 2026 20:19:50 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/stephenw10">@<bdi>stephenw10</bdi></a></p>
<p dir="auto">I really appreciate your feedback. And you are right.</p>
<p dir="auto">The problem was a suspected and annoying OOM and/or failing hardware or even a configuration mistake.<br />
For the life of me, I could not find a cause or find any other solution whatsoever by myself (reinstalled, used a backup, removed packages, reinstalled packages clean, etc.).</p>
<p dir="auto">SpeedShift (HWP) is indeed far faster than SpeedStep (EST). HWP runs in CPU microcode, EST is a software driver. The Xeon D-1521 does not support HWP.</p>
]]></description><link>https://forum.netgate.com/post/1245454</link><guid isPermaLink="true">https://forum.netgate.com/post/1245454</guid><dc:creator><![CDATA[rle]]></dc:creator><pubDate>Tue, 21 Jul 2026 20:19:50 GMT</pubDate></item><item><title><![CDATA[Reply to Firewall locks up - root cause analysis + solutions (pfSense Plus 26.03.1 on Supermicro Xeon D-1521) on Tue, 21 Jul 2026 15:55:44 GMT]]></title><description><![CDATA[<p dir="auto">You shouldn't need anything custom for CPU frequency control like that.</p>
<p dir="auto">You should only ever use one frequency control method. If your CPU supports both SpeedStep and SpeedShift you should use SpeedShift. It's far far faster reacting. It runs in the CPU directly rather than relying on a software daemon. The controls in pfSense only configure it. It varies with CPU but if you set SpeedShift towards the performance end of the scale it should have no problems. Say at 30%.</p>
<p dir="auto">If you really want maximum performance and are not worried about heat or power then just disable both. Running multiple custom scripts is almost never a good idea.</p>
]]></description><link>https://forum.netgate.com/post/1245440</link><guid isPermaLink="true">https://forum.netgate.com/post/1245440</guid><dc:creator><![CDATA[stephenw10]]></dc:creator><pubDate>Tue, 21 Jul 2026 15:55:44 GMT</pubDate></item><item><title><![CDATA[Reply to Firewall locks up - root cause analysis + solutions (pfSense Plus 26.03.1 on Supermicro Xeon D-1521) on Tue, 21 Jul 2026 08:58:08 GMT]]></title><description><![CDATA[<h1><a class="anchor-offset" name="pfsense-plus-stability-report"></a>pfSense Plus Stability Report</h1>
<p dir="auto"><strong>Host</strong>: pfSense Plus 26.03.1 on Supermicro Xeon D-1521<br />
<strong>Date</strong>: July 21, 2026<br />
<strong>Author</strong>: Diagnosis and remediation session</p>
<hr />
<h2><a class="anchor-offset" name="1.-platform-specifications"></a>1. Platform Specifications</h2>
<h3><a class="anchor-offset" name="hardware"></a>Hardware</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Component</th>
<th>Detail</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Motherboard</strong></td>
<td>Supermicro Super Server</td>
</tr>
<tr>
<td><strong>CPU</strong></td>
<td>Intel Xeon D-1521, 4C/8T @ 2.4 GHz (Broadwell-DE)</td>
</tr>
<tr>
<td><strong>RAM</strong></td>
<td>32 GB (4 x 8 GB DDR4)</td>
</tr>
<tr>
<td><strong>Storage</strong></td>
<td>Samsung MZVLB256HAHQ-000H1, 256 GB NVMe (51,325 POH, 15% wear)</td>
</tr>
<tr>
<td><strong>LAN/NIC 1</strong></td>
<td>Intel X552/X557-AT 10GBASE-T (ix0)</td>
</tr>
<tr>
<td><strong>WAN/NIC 2</strong></td>
<td>Intel X552/X557-AT 10GBASE-T (ix1) - FTTH 8 Gbps PPPoE (pppoe0)</td>
</tr>
<tr>
<td><strong>NIC 3</strong></td>
<td>Intel X710 for 10GbE SFP+ (ixl0) -- VLAN trunk</td>
</tr>
<tr>
<td><strong>NIC 4</strong></td>
<td>Intel X710 for 10GbE SFP+ (ixl1) -- VLAN trunk</td>
</tr>
</tbody>
</table>
<h3><a class="anchor-offset" name="software"></a>Software</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Component</th>
<th>Version</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>pfSense</strong></td>
<td>Plus 26.03.1-snapshots</td>
</tr>
<tr>
<td><strong>Kernel</strong></td>
<td>FreeBSD 16.0-CURRENT #12</td>
</tr>
<tr>
<td><strong>ZFS</strong></td>
<td>2.4.99-292-FreeBSD</td>
</tr>
<tr>
<td><strong>Build date</strong></td>
<td>Wed May 20 15:20:10 UTC 2026</td>
</tr>
<tr>
<td><strong>BIOS</strong></td>
<td>Supermicro Super Server (Supermicro)</td>
</tr>
</tbody>
</table>
<h3><a class="anchor-offset" name="installed-pfsense-packages"></a>Installed pfSense Packages</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Package</th>
<th>Version</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>pfBlockerNG</strong></td>
<td>3.2.16_1</td>
<td>ACTIVE (DNSBL python module in unbound + filterlog daemon)</td>
</tr>
<tr>
<td><strong>HAProxy</strong></td>
<td>0.65.7</td>
<td>ACTIVE (PID 11192, 33 MB RSS)</td>
</tr>
<tr>
<td><strong>FreeRADIUS</strong></td>
<td>0.16.4</td>
<td>ACTIVE (PID running, 71 MB RSS)</td>
</tr>
<tr>
<td><strong>Kea DHCP</strong></td>
<td>3.0.2_1</td>
<td>ACTIVE (PID running)</td>
</tr>
<tr>
<td><strong>WireGuard</strong></td>
<td>0.2.13_4</td>
<td>ACTIVE (php_wg daemon running)</td>
</tr>
<tr>
<td><strong>node_exporter</strong></td>
<td>0.18.1_8</td>
<td>ACTIVE (PID 89711, 22 MB RSS)</td>
</tr>
<tr>
<td><strong>Suricata</strong></td>
<td>7.0.8_16</td>
<td>INSTALLED (rules update failing, process may be idle)</td>
</tr>
<tr>
<td><strong>FRR</strong></td>
<td>2.1.2_1</td>
<td>INSTALLED (no active routing sessions)</td>
</tr>
<tr>
<td><strong>OpenVPN</strong></td>
<td>2.6.20</td>
<td>INSTALLED (auth-script plugin loaded)</td>
</tr>
<tr>
<td><strong>NUT (UPS)</strong></td>
<td>2.8.2_9</td>
<td>INSTALLED (driver shows connection issues to UPS_White)</td>
</tr>
<tr>
<td><strong>strongSwan/IPsec</strong></td>
<td>6.0.7</td>
<td>INSTALLED (not running on this boot)</td>
</tr>
<tr>
<td><strong>Zeek</strong></td>
<td>3.0.4</td>
<td>INSTALLED (no process detected)</td>
</tr>
<tr>
<td><strong>ACME</strong></td>
<td>1.2</td>
<td>INSTALLED (cert renewal, cron-triggered)</td>
</tr>
<tr>
<td><strong>Backup</strong></td>
<td>0.7</td>
<td>INSTALLED (cron/event-triggered)</td>
</tr>
<tr>
<td><strong>Cron</strong></td>
<td>0.3.8_8</td>
<td>ACTIVE (system cron daemon)</td>
</tr>
<tr>
<td><strong>Service Watchdog</strong></td>
<td>1.8.7_7</td>
<td>INSTALLED</td>
</tr>
<tr>
<td><strong>System Patches</strong></td>
<td>2.3.3</td>
<td>INSTALLED</td>
</tr>
<tr>
<td><strong>REST API</strong></td>
<td>2.8_2</td>
<td>INSTALLED</td>
</tr>
<tr>
<td><strong>Netgate Nexus</strong></td>
<td>26.03.1</td>
<td>INSTALLED</td>
</tr>
<tr>
<td><strong>Traffic Totals</strong></td>
<td>2.3.5_2</td>
<td>INSTALLED (vnStat backend active)</td>
</tr>
<tr>
<td><strong>UDP Broadcast Relay</strong></td>
<td>1.2.8</td>
<td>INSTALLED</td>
</tr>
<tr>
<td><strong>TFTP Server</strong></td>
<td>0.1.3_10</td>
<td>INSTALLED</td>
</tr>
<tr>
<td><strong>iperf</strong></td>
<td>3.0.6</td>
<td>INSTALLED</td>
</tr>
<tr>
<td><strong>Status Monitoring</strong></td>
<td>1.8_9</td>
<td>INSTALLED</td>
</tr>
</tbody>
</table>
<hr />
<h2><a class="anchor-offset" name="2.-symptoms"></a>2. Symptoms</h2>
<ul>
<li>Internet speed is <strong>fast immediately after reboot</strong>, then <strong>gradually degrades over days</strong></li>
<li>System eventually becomes <strong>completely unresponsive</strong> -- requires <strong>physical reset button</strong></li>
<li>Daily scheduled reboot (<code>/etc/rc.reboot</code> at 02:03) often fails to fire</li>
<li>No crash dumps written, no kernel panic messages in logs -- system simply <strong>stops</strong> with a multi-hour silent gap in the log</li>
</ul>
<hr />
<h2><a class="anchor-offset" name="3.-root-cause-1-cpu-throttled-to-half-speed-primary"></a>3. Root Cause 1: CPU Throttled to Half Speed (PRIMARY)</h2>
<h3><a class="anchor-offset" name="discovery"></a>Discovery</h3>
<p dir="auto">The CPU was running at <strong>800-1700 MHz</strong> instead of the rated <strong>2401 MHz</strong> -- between 33% and 71% of intended speed. After the most recent boot, observed frequencies were:</p>
<ul>
<li>09:37: 1500 MHz (after 50 min uptime)</li>
<li>09:43: 1100 MHz (dropped while idle)</li>
<li>09:46: 2401 MHz (manually forced)</li>
<li>09:46+01s: 1700 MHz (EST driver dropped it back within 1 second)</li>
<li>09:48: 2400 MHz (watchdog active, stable)</li>
</ul>
<h3><a class="anchor-offset" name="why"></a>Why</h3>
<pre><code>dmesg: sysctl_register_oid: can't re-use a leaf (machdep.hwpstate_pkg_ctrl)!
</code></pre>
<p dir="auto">Two FreeBSD CPU frequency drivers conflict on this FreeBSD 16.0-CURRENT kernel:</p>
<ul>
<li><strong><code>est</code> (Enhanced SpeedStep)</strong> -- driver module, registers first during boot</li>
<li><strong><code>hwpstate_intel</code> (Hardware P-State)</strong> -- tries to register the same <code>machdep.hwpstate_pkg_ctrl</code> sysctl second, fails</li>
</ul>
<p dir="auto">The EST driver then aggressively downclocks the CPU for power saving, dropping to <strong>1.1 GHz at idle</strong> (46% of rated speed). Under network or interrupt load, it fails to ramp up fast enough.</p>
<h3><a class="anchor-offset" name="the-degradation-cycle"></a>The degradation cycle</h3>
<pre><code>Boot (fast) --&gt; CPU at 1100-1500 MHz --&gt; NIC interrupts pile up at 31K/sec per queue --&gt;
Network latency increases --&gt; Retransmits generate more interrupts --&gt;
CPU can't catch up at half speed --&gt; Interrupt queue overflows (intr_queue_drops &gt; 0) --&gt;
Packet loss --&gt; Perceived speed degradation --&gt;
System enters feedback loop of more retransmits/less CPU --&gt; Eventually locks up
</code></pre>
<h3><a class="anchor-offset" name="evidence"></a>Evidence</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Metric</th>
<th>Value</th>
<th>Significance</th>
</tr>
</thead>
<tbody>
<tr>
<td>CPU frequency</td>
<td>800-1500 MHz vs 2401 MHz rated</td>
<td>33-62% of intended speed</td>
</tr>
<tr>
<td>NIC interrupt rate</td>
<td>31,250/sec per queue (locked)</td>
<td>Driver does not adapt to load</td>
</tr>
<tr>
<td>Total interrupts</td>
<td>15,325,450 in 50 min (4,843/sec)</td>
<td>High for idle system</td>
</tr>
<tr>
<td><code>intr_queue_drops</code></td>
<td>453 in 50 min at idle</td>
<td>CPU already losing packets</td>
</tr>
<tr>
<td><code>vm.pfault_oom_attempts</code></td>
<td>3 in 50 min</td>
<td>Kernel hitting allocation failures</td>
</tr>
<tr>
<td>CPU temperature</td>
<td>62C</td>
<td>Normal for Xeon D-1521</td>
</tr>
</tbody>
</table>
<h3><a class="anchor-offset" name="fix-three-layer-approach"></a>Fix: Three-layer approach</h3>
<h4><a class="anchor-offset" name="layer-1-continuous-watchdog-immediate"></a>Layer 1: Continuous watchdog (IMMEDIATE)</h4>
<p dir="auto">A background script at <code>/usr/local/bin/cpu_freq_watchdog.sh</code> runs every 5 seconds<br />
and forces all cores to 2401 MHz:</p>
<pre><code class="language-sh">while :; do
  for c in 0 1 2 3 4 5 6 7; do
    sysctl dev.cpu.${c}.freq=2401 &gt; /dev/null 2&gt;&amp;1
  done
  sleep 5
done
</code></pre>
<p dir="auto">Started from <code>/etc/rc.local</code> with <code>&amp;</code> (must background).</p>
<p dir="auto"><strong>Result</strong>: CPU stable at <strong>2400-2401 MHz</strong> with watchdog running.</p>
<h4><a class="anchor-offset" name="layer-2-boot-level-disable-permanent-after-reboot"></a>Layer 2: Boot-level disable (PERMANENT AFTER REBOOT)</h4>
<p dir="auto"><code>/boot/loader.conf.local</code>:</p>
<pre><code>hint.est.0.disabled=1
hint.acpi_throttle.0.disabled="1"
</code></pre>
<p dir="auto">This prevents the EST driver from loading entirely. <code>loader.conf.local</code> survives<br />
pfSense package updates and config regeneration -- it is NOT overwritten like<br />
<code>/etc/crontab</code> or <code>/var/unbound/unbound.conf</code>.</p>
<h4><a class="anchor-offset" name="layer-3-per-minute-cron-fallback"></a>Layer 3: Per-minute cron (FALLBACK)</h4>
<pre><code>* * * * * root for c in 0 1 2 3 4 5 6 7; do sysctl dev.cpu.${c}.freq=2401 &gt; /dev/null 2&gt;&amp;1; done
</code></pre>
<p dir="auto">Added to <code>/etc/crontab</code> as secondary safety net. Note: EST's scaling interval is<br />
sub-second, so per-minute cron alone is NOT sufficient -- the 5-second watchdog<br />
is the critical layer.</p>
<hr />
<h2><a class="anchor-offset" name="4.-root-cause-2-swap-overcommit-secondary"></a>4. Root Cause 2: Swap Overcommit (SECONDARY)</h2>
<h3><a class="anchor-offset" name="discovery"></a>Discovery</h3>
<pre><code>vm.swap_total:   1,073,741,824 (1.0 GB)
vm.swap_reserved: 3,594,932,224 (3.6 GB)  --&gt;  335% overcommit
</code></pre>
<p dir="auto">The kernel reserves swap space for every memory allocation. When reserved exceeds<br />
total, the kernel has <strong>zero headroom</strong> to page out under pressure.</p>
<h3><a class="anchor-offset" name="fix"></a>Fix</h3>
<p dir="auto">8 GB swap file created via <code>mdconfig</code>:</p>
<pre><code class="language-sh">dd if=/dev/zero of=/swap bs=1m count=8192
chmod 0600 /swap
mdconfig -a -t vnode -f /swap -u 0
swapon /dev/md0
</code></pre>
<p dir="auto">Persisted in <code>/etc/rc.local</code>.</p>
<p dir="auto"><strong>Result</strong>: <code>swap_reserved: 3.5 GB</code> well within <code>swap_total: 9.3 GB</code> (38% utilization).</p>
<hr />
<h2><a class="anchor-offset" name="5.-root-cause-3-unbound-memory-pressure-contributing"></a>5. Root Cause 3: Unbound Memory Pressure (CONTRIBUTING)</h2>
<h3><a class="anchor-offset" name="discovery"></a>Discovery</h3>
<p dir="auto">unbound RSS: <strong>1,071 MB</strong> after only 50 minutes uptime. The pfBlockerNG<br />
python module (<code>pfb_unbound.py</code>) loads entirely inside unbound's process space.<br />
The <code>pfb_py_zone.txt</code> (85 MB) and <code>pfb_py_data.txt</code> (16 MB) DNSBL data files<br />
are parsed into in-memory data structures. Cache tuning does not reduce this<br />
baseline -- it only constrains runtime growth.</p>
<h3><a class="anchor-offset" name="fix"></a>Fix</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Parameter</th>
<th>Default</th>
<th>Tuned</th>
<th>Effect</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>outgoing-range</code></td>
<td>4096</td>
<td>2048</td>
<td>Reduces socket/epoll memory</td>
</tr>
<tr>
<td><code>msg-cache-size</code></td>
<td>10m</td>
<td>5m</td>
<td>Smaller message cache</td>
</tr>
<tr>
<td><code>rrset-cache-size</code></td>
<td>20m</td>
<td>10m</td>
<td>Smaller RRset cache</td>
</tr>
<tr>
<td><code>cache-min-ttl</code></td>
<td>0</td>
<td>300</td>
<td>Prevents cache thrash</td>
</tr>
<tr>
<td><code>prefetch</code></td>
<td>yes</td>
<td>no</td>
<td>Stops proactive re-querying</td>
</tr>
<tr>
<td><code>prefetch-key</code></td>
<td>yes</td>
<td>no</td>
<td>Stops proactive DNSSEC</td>
</tr>
<tr>
<td><code>serve-expired</code></td>
<td>no</td>
<td>yes</td>
<td>Serves stale data while refreshing</td>
</tr>
</tbody>
</table>
<hr />
<h2><a class="anchor-offset" name="6.-persistence-mechanism"></a>6. Persistence Mechanism</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Layer</th>
<th>What</th>
<th>When</th>
<th>Reliability</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/etc/rc.local</code></td>
<td>Swap mdconfig, watchdog start, best-effort sed patching</td>
<td>Early boot</td>
<td>Swap: reliable. Seds: unreliable (before pfSense writes configs)</td>
</tr>
<tr>
<td><code>/etc/cron.d/pfsense_tweaks</code></td>
<td><a class="plugin-mentions-user plugin-mentions-a" href="/user/reboot">@<bdi>reboot</bdi></a>: CPU freq lock (10s delay) + unbound restart (30s)</td>
<td>After boot</td>
<td>Reliable -- runs after pfSense configs are finalized</td>
</tr>
<tr>
<td><code>/boot/loader.conf.local</code></td>
<td>Disable EST + ACPI throttle at boot loader</td>
<td>Pre-boot</td>
<td>Permanent -- survives pfSense updates</td>
</tr>
<tr>
<td>Per-minute cron</td>
<td>CPU max frequency</td>
<td>Every minute</td>
<td>Fallback only (too slow alone)</td>
</tr>
<tr>
<td><code>loader.conf.local</code></td>
<td><code>hint.est.0.disabled=1</code>, <code>hint.acpi_throttle.0.disabled="1"</code></td>
<td>Boot</td>
<td>Survives pfSense updates</td>
</tr>
</tbody>
</table>
<hr />
<h2><a class="anchor-offset" name="7.-files-deployed"></a>7. Files Deployed</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>File</th>
<th>pfSense Path</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>rc.local</code></td>
<td><code>/etc/rc.local</code></td>
<td>Swap, watchdog start, unbound patching</td>
</tr>
<tr>
<td><code>pfsense_tweaks.cron</code></td>
<td><code>/etc/cron.d/pfsense_tweaks</code></td>
<td><a class="plugin-mentions-user plugin-mentions-a" href="/user/reboot">@<bdi>reboot</bdi></a>: CPU freq + unbound restart + crontab fix</td>
</tr>
<tr>
<td><code>cpu_freq_watchdog.sh</code></td>
<td><code>/usr/local/bin/cpu_freq_watchdog.sh</code></td>
<td>CPU frequency watchdog (5-second loop)</td>
</tr>
<tr>
<td><code>loader.conf.local</code></td>
<td><code>/boot/loader.conf.local</code></td>
<td>Disable EST and ACPI throttle at boot</td>
</tr>
</tbody>
</table>
<hr />
<h2><a class="anchor-offset" name="8.-verification"></a>8. Verification</h2>
<pre><code class="language-sh"># CPU frequency
sysctl dev.cpu.0.freq        # Expected: 2400-2401

# Watchdog running
ps aux | grep cpu_freq_watchdog

# Swap
swapinfo -h                  # Expected: 9 GB total, 0 used

# Unbound config
grep -E "(outgoing-range|msg-cache-size|cache-min-ttl|prefetch|serve-expired)" /var/unbound/unbound.conf

# pfBlockerNG cron priority
grep pfblockerng /etc/crontab | grep nice

# @reboot entries
cat /etc/cron.d/pfsense_tweaks

# Boot-level EST disable
cat /boot/loader.conf.local

# Link health
ifconfig ix0 | grep media
sysctl dev.ix.0.mac_stats.crc_errs  # Expected: 0
</code></pre>
<hr />
<h2><a class="anchor-offset" name="9.-source-code-of-files-deployed"></a>9. Source code of files deployed</h2>
<h3><a class="anchor-offset" name="rc.local"></a>rc.local</h3>
<pre><code class="language-sh">#!/bin/sh

# Swap file - added Wed Jul  1 14:40:05 CEST 2026
mdconfig -a -t vnode -f /swap -u 0 &amp;&amp; swapon /dev/md0

# Unbound memory tunings - re-apply after pfSense regenerates config
sleep 3
sed -i "" "s/^outgoing-range: 4096/outgoing-range: 2048/" /var/unbound/unbound.conf
sed -i "" "s/^msg-cache-size: 10m/msg-cache-size: 5m/" /var/unbound/unbound.conf
sed -i "" "s/^rrset-cache-size: 20m/rrset-cache-size: 10m/" /var/unbound/unbound.conf
sed -i "" "s/^cache-min-ttl: 0/cache-min-ttl: 300/" /var/unbound/unbound.conf
sed -i "" "s/^prefetch: yes/prefetch: no/" /var/unbound/unbound.conf
sed -i "" "s/^prefetch-key: yes/prefetch-key: no/" /var/unbound/unbound.conf
sed -i "" "s/^serve-expired: no/serve-expired: yes/" /var/unbound/unbound.conf

# Restart unbound with tuned config
/bin/kill -9 $(/bin/pgrep unbound) 2&gt;/dev/null
sleep 1
/usr/local/sbin/unbound -c /var/unbound/unbound.conf

# pfBlockerNG cron with low CPU priority
sed -i "" "s|/usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php cron|/usr/bin/nice -n 19 /usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php cron|" /etc/crontab

# Start CPU frequency watchdog (est/hwpstate conflict workaround)
/usr/local/bin/cpu_freq_watchdog.sh # Lock all CPUs

# Lock all CPUs to max frequency - est/hwpstate conflict on FreeBSD 16-CURRENT
for c in 0 1 2 3 4 5 6 7; do sysctl dev.cpu.${c}.freq=2401 &gt; /dev/null 2&gt;&amp;1; done
</code></pre>
<h3><a class="anchor-offset" name="pfsense_tweaks.cron"></a>pfsense_tweaks.cron</h3>
<pre><code class="language-txt"># pfSense post-boot tweaks
# Runs 30s after boot to re-apply settings that pfSense overwrites on boot
@reboot root sleep 10 &amp;&amp; for c in 0 1 2 3 4 5 6 7; do /usr/sbin/sysctl dev.cpu.${c}.freq=2401 &gt; /dev/null 2&gt;&amp;1; done &amp;&amp; sleep 20 &amp;&amp; /bin/sed -i "" "s/^outgoing-range: 4096/outgoing-range: 2048/" /var/unbound/unbound.conf &amp;&amp; /bin/sed -i "" "s/^msg-cache-size: 10m/msg-cache-size: 5m/" /var/unbound/unbound.conf &amp;&amp; /bin/sed -i "" "s/^rrset-cache-size: 20m/rrset-cache-size: 10m/" /var/unbound/unbound.conf &amp;&amp; /bin/sed -i "" "s/^cache-min-ttl: 0/cache-min-ttl: 300/" /var/unbound/unbound.conf &amp;&amp; /bin/sed -i "" "s/^prefetch: yes/prefetch: no/" /var/unbound/unbound.conf &amp;&amp; /bin/sed -i "" "s/^prefetch-key: yes/prefetch-key: no/" /var/unbound/unbound.conf &amp;&amp; /bin/sed -i "" "s/^serve-expired: no/serve-expired: yes/" /var/unbound/unbound.conf &amp;&amp; /bin/kill -9 $(/bin/pgrep unbound) 2&gt;/dev/null; sleep 1; /usr/local/sbin/unbound -c /var/unbound/unbound.conf &amp;&amp; /bin/sed -i "" "s|/usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php cron|/usr/bin/nice -n 19 /usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php cron|" /etc/crontab
</code></pre>
<h3><a class="anchor-offset" name="loader.conf.local"></a>loader.conf.local</h3>
<pre><code class="language-conf">if_ixl_load="YES"
hint.est.0.disabled=1
hint.acpi_throttle.0.disabled="1"
</code></pre>
<h3><a class="anchor-offset" name="cpu_freq_watchdog.sh"></a>cpu_freq_watchdog.sh</h3>
<pre><code class="language-sh">#!/bin/sh
# CPU frequency watchdog - EST/hwpstate conflict workaround
# Forces all CPUs to max frequency every 5 seconds
while :; do
  for c in 0 1 2 3 4 5 6 7; do
    /usr/sbin/sysctl dev.cpu.${c}.freq=2401 &gt; /dev/null 2&gt;&amp;1
  done
  sleep 5
done
</code></pre>
]]></description><link>https://forum.netgate.com/post/1245428</link><guid isPermaLink="true">https://forum.netgate.com/post/1245428</guid><dc:creator><![CDATA[rle]]></dc:creator><pubDate>Tue, 21 Jul 2026 08:58:08 GMT</pubDate></item></channel></rss>