My Comcast/Arris SB8200 Disaster

Not that this is an unpopular take or anything, but this story reinforces reinforces my opinion that cable modems are the single worst piece of network equipment out there.

Several years ago, I had Xfinity’s 40Mbit downstream package. This just wasn’t cutting it, so I upgraded to the 400m down plan – the fastest they had at the time. I even got a promo rate on the upgrade. One minor problem – a rep told me that my current modem, a Cisco, would be sufficient, but this turned out to not be true – it could only do 300-some down. So I did some research, and bought the Arris SB8200. It was on Xfinity’s list of supported modems, and could do 2Gb/s down – plenty of headroom for future upgrades. Of course, since it only has gigabit Ethernet ports, you’d need to use link aggregation to actually get the full 2Gbps. OpenWRT didn’t have great support for bonding back then (it was doable, but not through UCI), but I figured that by the time it became an issue, that would change anyway.

Fast-forward a bit. The fastest speed they offer is now a gigabit. And they’re offering a promotional rate on it! On top of that, my current setup is good for 1g down, so no need to change out any hardware. Seems like a win-win!

Then, a bit later, my speed gets bumped up to 1.2Gb/s down, for free! Unfortunately, while it might have been doable, this meant it was probably time for the Omnia to be demoted to AP duty, and a new primary router would take its place (TODO put link). It’s easy – just set up the new router (which would be a breeze now that UCI supports bonding), enable link aggregation on the modem, and bam, 1200Mb/s down.

And it worked!

Since the router, desktop, and home server all have 10GbE interfaces, I was, for the first time, able to get >1Gbps downstream speeds.

For about 24 hours, that is. Stick around for the clownshow!

Read the rest of this entry »

Mini-Review: Emulex OpenConnect OCE11102SN (IBM Version) – BAD

I found a pair of these dual-port 10GbE NICs for $25, and had no idea what to expect.

The good:

  • Excellent secondhand value
  • Supports SR-IOV, VM switching, and the other usual stuff
  • No SFP lock
  • Can be cross-flashed
  • Appears to use the same driver (be2net) for both PFs and VFs, unlike Intel cards which have a separate VF driver

The bad:

  • There’s a known issue with these where you have to do trickery to bring the ports back up after a power cycle. It doesn’t seem to be OS/driver-specific, because even the BIOS shows “Link Down”. This is the deal breaker. On Linux, you can do it with ethtool -t but on Windows it requires a proprietary program.
  • SR-IOV support is toggled on and off in the BIOS. However, the IBM firmware doesn’t seem to expose this. I had to use an HPE or Lenovo image instead.
  • Would it kill Broadcom to just let you download the firmware from them, rather than having to peruse every 3rd party vendor site to figure out who has the latest firmware?
  • The card is x8 but seems to have some extra pins on the end of the PCIe connector. It seems to work fine in a x16 slot, but does not physically fit in a closed-ended x8 slot.

In short: they’re cheap for a reason. Don’t buy them.


You may have to flash twice if the card is running older firmware. There’s also this oddity where the interface has to be up (ip link set up, not physically plugged in) in order to flash – you’d think it would be the other way around.

Goodisory SR01: Almost-Perfect Router Case

Back with another niche case. This time, the Goodisory SR01, which I think is almost a perfect case for a high powered router. The use case I’m covering looks something like this:

  • Mini-ITX board
  • A small amount of active cooling needed (e.g. 25-50W SoC range), but the CPU socket doesn’t support mounting a fan.
  • Effectively silent (i.e. shouldn’t be able to hear it at 6ft+)
  • External PSU (PicoPSU or motherboard with support for DC-in)
  • PCIe slot (ideally 2+ for motherboards with bifurcation support, but 1 is fine)
  • No drive bay needed (it will use M.2 or other onboard storage)

Does such a case exist? Read on and find out. Short version since I hate cliffhanger clickbait: it almost does.

Read the rest of this entry »

Review: Mystery 8-Bay NAS Case

Overall Rating

8/10, pretty good. Great price and no extreme flaws.


This case is the ??? manufactured by ??? in…..probably China? There’s no branding other than “NAS-8” on the backplane PCB.

Here is the eBay listing that I bought it from:

It also appears to be available on AliExpress, along with the 2- and 4-bay versions: This link has more pictures available.

I actually plan to use it as a DAS rather than a NAS via an external SAS connection, but it is easier to just put a motherboard in there anyway for power + fan control. There are JBOD “motherboards” available that tell the power supply to turn on and control the fans, but it would cost more money to get one of those than to just throw in a mini-ITX Atom motherboard that I already own.

Read the rest of this entry »

Script to Read I2C Data From Supermicro PSU

I have a Supermicro Chassis that has the I2C/SMBus connector for the power supply. Unfortunately, the motherboard I am using doesn’t have LOM, so I can’t grab PSU data using the normal methods, and the PMBus support seems to not be working either. Fortunately, the PSU exposes an I2C device which exposes temperature and fan speed. These values might not be correct for every PSU – I had to use a combination of spec sheets for similar PSUs and some reverse engineering to get these values.



function getValue () {
        local rawVal=$(i2cget -y 0 $address $1 | cut -c3- | tr a-f A-F)
        local decVal=$(echo "obase=10; ibase=16; $rawVal" | bc -l)
        echo $decVal

TEMPERATURE=$(getValue 0x09)
FAN1RAW=$(getValue 0x0a)
FAN2RAW=$(getValue 0x0b)
DCSTATUS=$(getValue 0x0c)
ALARMTEMP=$(getValue 0x0d)
FAN1MIN=$(getValue 0x0e)
FAN2MIN=$(getValue 0x0f)

FAN1=$(echo $FAN1RAW '* 60 / 2 / .262' | bc)
FAN2=$(echo $FAN2RAW '* 60 / 2 / .262' | bc)

echo Temperature: $TEMPERATURE
echo Temp Max: $ALARMTEMP
echo Fan1 RPM: $FAN1
echo Fan2 RPM: $FAN2
echo Fan1 Raw: $FAN1RAW
echo Fan2 Raw: $FAN2RAW
echo Fan1 Min: $FAN1MIN
echo Fan2 Min: $FAN2MIN
echo DC Status Raw: $DCSTATUS


# ./ 0x38
Temperature: 33
Temp Max: 75
Fan1 RPM: 4122
Fan2 RPM: 5038
Fan1 Raw: 36
Fan2 Raw: 44
Fan1 Min: 0
Fan2 Min: 35
DC Status Raw: 1

The single argument is the i2c address of the PSU you want to read from. They seem to usually be in the 0x30-0x3f or 0x70-0x7e range. Systems with redundant power supplies will have two separate addresses. In addition, you may need to edit it if your system has multiple i2c buses (change i2cget -y 0 to i2cget -y 1 for example).

Disclaimer: reading/writing random i2c devices can hang your system or cause other issues.

Homegrown ZFS-based Cloud Backup

I started using ZFS a few years ago, and it’s been nothing short of amazing. However, one area that I wanted to take advantage of is the fact that zfs send/recv act as a very convenient incremental backup system. After some research, I found that very few providers natively supported this, and the ones that did didn’t seem to have competitive pricing for a home-tier usage (i.e. enterprise grade redundancy and reliability not required). With a pool of about 7TB and growing, most of the options just ended up being too pricy. After looking at my options, I decided to apply a bit of DIY.

Read the rest of this entry »

Mox Part 2

After having my Mox for over a month now, I’ve made a few changes, and have a few more complaints.

I ended up salvaging an internal antenna from another device, and using the original WLE900VX card instead of the SDIO WiFi for 2.4GHz. It only has two antennas for the time being, but that’s still no worse than SDIO card (and, you know, it doesn’t have bug-riddled firmware).

I’ve also slowed down the fan a little bit more, so that the card still stays under 70C under most ambient temperatures. It is a tiny bit hotter with the extra card running in it.

So, what are the problems?

The first is a bit of instability. There is a known issue with soft rebooting some Moxes, and mine seems to be one of them. However, since the Mox has the same auto-updates as the Omnia (including kernel updates, which require a reboot), it’s hard to tell what really happened when you come home and the Mox is unresponsive.

The main problem I have is the case design. It certainly looks fine, but there are some functional issues I have with it:

  • Thermal management, or utter lack thereof
  • Have to disassemble large parts of the case to access one module
  • Limited places to put antennas, and high risk of accidentally pulling a cable

Read on for the details.

Read the rest of this entry »

Turris Mox Thoughts/Review/Mods

I finally got my Turris Mox. I’ll start with an “as-is” review, then head into the improvements that I made.

Read the rest of this entry »

Lessons in Multihreaded Programming: Don’t Assume Anything will Run in a Timely Manner

I recently ran into an issue, where I had a loop that was to be run concurrently in multiple threads, that looked something like this:

    only the last thread to get here in every wakeup cycle should perform this:

In other words, the goal was to have every thread run main_stuff(), but have additional_stuff() run after every thread has had a chance to run main_stuff().

The first solution I came up with was this (pseudocode):

AtomicInt totalThreads;
AtomicInt waitingThreads;
Object notifier;
        if waitingThreads.incrementAndGet() == totalThreads.get()
        synchronized (notifier) {

At first glance, this would seem to work. Some testing indicated that it did. However, if an OS has exceptionally poor scheduling, or only has one CPU core to work with, then what would happen is:

  1. Let’s say two threads are at the wait() part
  2. They both get the signal to proceed
  3. One thread gets all the way back to the check before additional_stuff() before the other thread gets to the decrement()
  4. Because the number of waiting threads is still equal to the total number of threads in the loop, it runs additional_stuff() when it shouldn’t have.

In this particular case, additional_stuff() running an additional time wasn’t harmful to the operation of the program, merely a performance issue. But the issue didn’t even manifest until testing it on multiple different platforms.

The fully-working solution that I came up with after seeing the problem was this:

AtomicInt totalThreads;
AtomicInt waitingThreads;
AtomicInt counter;
Object notifier;
    int lastCounter = counter.get();
        if waitingThreads.incrementAndGet() == totalThreads.get()
        synchronized (notifier) {
            while counter.get() == lastCounter():

void notify():
    synchronized (notifier) {

Notice this version correctly handles this, by having the notification operation reset the variable, then waiting for every thread to catch back up. It also accounts for multiple notifications happening while one or more threads are still processing main_stuff().

Script to Fix Broken RRDs

OpenWRT seems to have issues with inserting bad data into RRDs, especially after reboots. I made the below script to fix affected files:


TIMESTAMP=`date +%s`

if [ -f $FILE ]
 rrdtool dump $1 > $1.xml
 sed -i "s/<lastupdate>.*<\/lastupdate>/<lastupdate> $TIMESTAMP <\/lastupdate>/" $1.xml
 rm $1
 rrdtool restore $1.xml $1
 rm $1.xml
 echo "File does not exist: $1"

Save it somewhere in your $PATH, and chmod +x it. You may also wish to change /bin/bash to a different compatible shell, as you may not have bash installed.

To use it, simply stop luci_statistics (and anything associated with it – check ps to see if any collectd processes are still running). Then, run something like this:

find /srv/rrd/ -name '*.rrd' | xargs -n 1 rrdfixer

where /srv/rrd/ is the path to your RRDs that you want fixed, and rrdfixer is the name of the script.

What happens to the RRDs is that instead of proper timestamps, “NaN” gets inserted instead. Simply replacing these with the current time won’t fix the bad data, but it will at least allow new data to be written to the file.