Thanks, I just learned there is more to these as the form factor ![]()
I'll get on ordering the m2 somebody else in this thread suggested
Just make sure that its technical specs explicitly state PCIe (ideally gen3 or newer) and/or NVMe. The product label typically states something like "PCIe gen3 x4 NVMe" or "PCIe gen4 x4 NVMe" (yes, the OO will one use one lane, but that's not the issue here). Any cheap name-brand one should be fine.
But, yes, the M.2 connector is used for a variety of different/ alternative purposes, which aren't necessarily compatible with each other (even if the keying matches).
Just started playing with an OpenWrt One; hope this is the right place for a query like this.
I tried fitting a 2242 M.2 SSD, but found that the standoff for a 2230 card stops the 2242 from lying flat. I couldn't see how to deal with this; the unused standoff didn't seem to be removable. The SSD in question was double-sided; perhaps the One only supports single-sided in 2242 size?
Double sided SSD’s are more generally used in higher capacity drives. They also generally generate more heat than a single sided drive which is much more important on a passively cooled device like the OO. (High capacity double sided SSD’s are more suited to devices that typically contain active cooling designs.)
The OO specs are designed as M.2 2230/2242for NVMe SSD (PCIe gen 2x1). No capacity restrictions are noted, but FWIW, in my opinion I personally don’t see a need for anything more than 64GB-256GB capacity. (I use a 128GB 2242 gen3 bought for ~$10USD delivered with a stated MTBF that will more than likely outlast the OO)
Thanks for that -- I was focussing on the mechanical problem of the standoff which is in the way, and not thinking about heat, and that it might be better to use a lower capacity singled-sided one just for that reason.
My One did not come with any standoffs at all, just threaded holes in the motherboard. I used an extra standoff from an Asus motherboard and it is a little bit too tall, but works fine with this 512GB single-sided m.2 2042 drive.
root@openwrt-one:~# mount | grep overlay
/dev/nvme0n1p2 on /overlay type ext4 (rw,relatime)
overlayfs:/overlay on / type overlay (rw,noatime,lowerdir=/,upperdir=/overlay/upper,workdir=/overlay/work,xino=off)
At idle:
root@openwrt-one:~# nvme smart-log /dev/nvme0n1
Smart Log for NVME device:nvme0n1 namespace-id:ffffffff
critical_warning : 0
temperature : 41 °C (314 K)
available_spare : 100%
available_spare_threshold : 1%
percentage_used : 0%
endurance group critical warning summary: 0
Data Units Read : 2309327 (1.18 TB)
Data Units Written : 302867 (155.07 GB)
host_read_commands : 13656368
host_write_commands : 10298167
controller_busy_time : 8
power_cycles : 70
power_on_hours : 242
unsafe_shutdowns : 3
media_errors : 0
num_err_log_entries : 1
Warning Temperature Time : 0
Critical Composite Temperature Time : 0
Temperature Sensor 1 : 41 °C (314 K)
Temperature Sensor 2 : 47 °C (320 K)
Thermal Management T1 Trans Count : 0
Thermal Management T2 Trans Count : 0
Thermal Management T1 Total Time : 0
Thermal Management T2 Total Time : 0
After 30 seconds of fio benchmarking:
root@openwrt-one:~# fio --name=./fio-test.dat --size=1GiB --ioengine=libaio --readwrite=randwrite --fsync=1 --direct=1 --blocksize=4K --runtime=3
0; nvme smart-log /dev/nvme0n1
./fio-test.dat: (g=0): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=1
fio-3.37
Starting 1 thread
Jobs: 1 (f=1): [w(1)][100.0%][w=2690KiB/s][w=672 IOPS][eta 00m:00s]
./fio-test.dat: (groupid=0, jobs=1): err= 0: pid=3818: Fri Jan 10 11:39:50 2025
write: IOPS=915, BW=3661KiB/s (3749kB/s)(107MiB/30001msec); 0 zone resets
slat (usec): min=17, max=1309, avg=56.32, stdev=37.70
clat (usec): min=5, max=4100, avg=55.09, stdev=69.84
lat (usec): min=49, max=4219, avg=111.41, stdev=88.42
clat percentiles (usec):
| 1.00th=[ 33], 5.00th=[ 34], 10.00th=[ 35], 20.00th=[ 36],
| 30.00th=[ 38], 40.00th=[ 40], 50.00th=[ 44], 60.00th=[ 49],
| 70.00th=[ 63], 80.00th=[ 70], 90.00th=[ 79], 95.00th=[ 90],
| 99.00th=[ 155], 99.50th=[ 210], 99.90th=[ 1106], 99.95th=[ 1336],
| 99.99th=[ 3458]
bw ( KiB/s): min= 2480, max= 4336, per=99.98%, avg=3660.65, stdev=780.33, samples=60
iops : min= 620, max= 1084, avg=915.15, stdev=195.07, samples=60
lat (usec) : 10=0.04%, 20=0.23%, 50=62.06%, 100=33.98%, 250=3.32%
lat (usec) : 500=0.16%, 750=0.04%, 1000=0.05%
lat (msec) : 2=0.10%, 4=0.02%, 10=0.01%
fsync/fdatasync/sync_file_range:
sync (usec): min=589, max=11786, avg=1018.32, stdev=297.61
sync percentiles (usec):
| 1.00th=[ 693], 5.00th=[ 783], 10.00th=[ 799], 20.00th=[ 816],
| 30.00th=[ 832], 40.00th=[ 832], 50.00th=[ 840], 60.00th=[ 898],
| 70.00th=[ 1270], 80.00th=[ 1352], 90.00th=[ 1401], 95.00th=[ 1434],
| 99.00th=[ 1549], 99.50th=[ 1680], 99.90th=[ 3064], 99.95th=[ 3785],
| 99.99th=[ 6194]
cpu : usr=3.86%, sys=6.65%, ctx=55512, majf=0, minf=1
IO depths : 1=200.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=0,27456,0,27456 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs):
WRITE: bw=3661KiB/s (3749kB/s), 3661KiB/s-3661KiB/s (3749kB/s-3749kB/s), io=107MiB (112MB), run=30001-30001msec
Smart Log for NVME device:nvme0n1 namespace-id:ffffffff
critical_warning : 0
temperature : 42 °C (315 K)
available_spare : 100%
available_spare_threshold : 1%
percentage_used : 0%
endurance group critical warning summary: 0
Data Units Read : 2309327 (1.18 TB)
Data Units Written : 304182 (155.74 GB)
host_read_commands : 13656368
host_write_commands : 10404347
controller_busy_time : 8
power_cycles : 70
power_on_hours : 242
unsafe_shutdowns : 3
media_errors : 0
num_err_log_entries : 1
Warning Temperature Time : 0
Critical Composite Temperature Time : 0
Temperature Sensor 1 : 42 °C (315 K)
Temperature Sensor 2 : 48 °C (321 K)
Thermal Management T1 Trans Count : 0
Thermal Management T2 Trans Count : 0
Thermal Management T1 Total Time : 0
Thermal Management T2 Total Time : 0
So for my light usage, the passive cooling seems fine with this HUADISK drive.
@dfstone is referring to this:
The 2230 securing screw standoff prevents the use of double sided 2242 form factor SSD’s. The spec calls for PCIe gen 2x1 SSD. Not generally fabricated as double sided in that generation SSD’s. While gen3/4 are backwardly compatible, you won’t achieve the faster data rates advertised. As previously stated, the OO only uses a single lane. Save your money. Any cheap name-brand will do.
I put my One into service as dumb AP, and it works pretty well. So far I used the PoE capability to my advantage, but did not yet have to use the USB console (knock on wood). My kids who mostly use that AP are considerably happier with the WiFi reliability, so IMHO as anecdotal data point, the One makes just as decent an AP as its specs lead to believe.
Ah, I see -- tightening down an SSD flush would interfere with a double-sided SSD. I'm used to m.2 standoffs being removable as well as having a shoulder so that the notch in the m.2 is positively located. I naively assumed that the shouldered standoff was missing so I sourced one. By lifting the end of the m.2 up a bit, I think it would clear a double-sided SSD although I don't actually have a double-sided 2042 to check.
I'm dumb but resourceful, so I didn't even realize the limitation.
Not meant as a criticism, more a clarification of the situation @dfstone encountered. ![]()
Thank you both. Yes @RuralRoots' photo shows exactly what I encountered.
Ah well, I've learned something. For the time being, I've fudged it by putting
some washers between the M.2 card and the standoff, to keep the card in place
though it's not parallel with the mobo. I'll no doubt discover whether that stays put, or whether I need to buy the single-sided card I should have bought in the first place.
Keep an eye occasionally for thermal state of the drive. If they heat too much, it will degrade the performance of your system.
Install nvme-cli.
nvme smart-log /dev/nvme0 | grep -i '^temperature'
Hello faced with the same issue, were you able to remove the middle standoff nut? or is the little foil enough to prevent electrical contact? my nvme is single sided luckily
I did not find any need to remove the 2230 securing standoff cover, nor the standoff itself. This was designed to accept either length form factor SSD interchangeably. Any 2242 single sided M2 SSD should not interfere with or contact the 2230 M2 standoff when properly installed. If you are concerned, the mylar standoff cover will prevent any electric contact in any case. A piece of electrical tape can be used as well.
ah in the end thats what i did , put the little plastic from the rear ontop of the middle oneand added one extra little tape bit
I would suggest manual pinning of smp-affinities, tasket for networking and dnsmasq, plus aligning napi threads to the originating cores. Should help a bunch.
Not 100% sure, looking at htop made it look like both CPUs were pretty much running pedal to the metal already... probably worth testing. My hunch is, your recommendations will mostly balance the CPUs more equitably, so I do not expect too much improvements, but that is a testable hypothesis I should put to the test.
Alas, since my One had to be rushed into service, I will not be getting around to that anytime soon
Although this is for my Flint2, it can be a good starting point.
logread -e smp_setup
#!/bin/sh
# OpenWrt SMP and AQL optimization script
# Logging function
log() {
# Default to user.notice if no priority specified
[ -z "$1" ] && priority="user.notice" || priority="$1"
[ -z "$2" ] && message="No message provided" || message="$2"
# Use standard OpenWrt logging
logger -p "$priority" -t "smp_setup" "$message"
}
# Test logging system
test_logging() {
if ! pidof logd >/dev/null; then
echo "Error: logd not running"
exit 1
fi
log "daemon.info" "SMP setup logging initialized"
return 0
}
# Configure AQL parameters
configure_aql() {
log "daemon.notice" "Starting AQL configuration"
find /sys/kernel/debug/ieee80211 -name 'phy[0-9]*' | while read -r phypath; do
log "daemon.info" "Configuring wireless device: $phypath"
for queue in 0 1 2 3; do
if ! echo "$queue 1500 5000" > "$phypath/aql_txq_limit"; then
log "daemon.err" "AQL: Failed setting queue $queue limits on $phypath"
continue 2
fi
done
if ! echo "12000" > "$phypath/aql_threshold"; then
log "daemon.err" "AQL: Failed setting threshold on $phypath"
continue
fi
log "daemon.info" "AQL: Successfully configured $phypath"
done
log "daemon.notice" "AQL configuration completed"
}
# Get number of CPUs
get_cpu_count() {
grep -c ^processor /proc/cpuinfo
}
# Optimize SMP settings
optimize_smp() {
cpu_count=$(get_cpu_count)
log "daemon.notice" "Starting SMP optimization for $cpu_count cores"
# Calculate CPU masks for 4-core system
eth_mask="3" # Cores 0,1
wifi_mask="c" # Cores 2,3
# Configure network interfaces
for iface in /sys/class/net/*; do
case "$iface" in
*virtual*) continue ;;
esac
if [ -e "$iface/queues/rx-0/rps_cpus" ]; then
iface_name="${iface##*/}"
case "$iface_name" in
eth*|lan*)
if ! echo "$eth_mask" > "$iface/queues/rx-0/rps_cpus"; then
log "daemon.err" "SMP: RPS configuration failed for $iface_name"
else
log "daemon.info" "SMP: Set RPS affinity $eth_mask for $iface_name"
fi
;;
phy*)
if ! echo "$wifi_mask" > "$iface/queues/rx-0/rps_cpus"; then
log "daemon.err" "SMP: RPS configuration failed for $iface_name"
else
log "daemon.info" "SMP: Set RPS affinity $wifi_mask for $iface_name"
fi
;;
esac
fi
done
# Configure IRQ affinity
irq_map="130:$eth_mask 131:$eth_mask 133:$wifi_mask"
for irq_set in $irq_map; do
irq="${irq_set%:*}"
aff="${irq_set#*:}"
if [ -d "/proc/irq/$irq" ]; then
if ! echo "$aff" > "/proc/irq/$irq/smp_affinity"; then
log "daemon.err" "SMP: Failed setting IRQ affinity for irq $irq"
else
log "daemon.info" "SMP: Set IRQ $irq affinity to $aff"
fi
fi
done
# Configure NAPI thread affinity
for pid in $(pgrep -f 'napi/mtk_eth'); do
if ! taskset -p "$eth_mask" "$pid" >/dev/null 2>&1; then
log "daemon.err" "SMP: Failed setting Ethernet NAPI affinity for pid $pid"
else
log "daemon.info" "SMP: Set Ethernet NAPI affinity $eth_mask for pid $pid"
fi
done
for pid in $(pgrep -f 'napi/phy0-'); do
if ! taskset -p "$wifi_mask" "$pid" >/dev/null 2>&1; then
log "daemon.err" "SMP: Failed setting WiFi NAPI affinity for pid $pid"
else
log "daemon.info" "SMP: Set WiFi NAPI affinity $wifi_mask for pid $pid"
fi
done
log "daemon.notice" "SMP optimization completed"
}
# Main function
main() {
# Verify logging is working
test_logging || exit 1
log "daemon.notice" "Starting system optimization"
# Allow system to settle
sleep 10
# Run configurations
configure_aql
optimize_smp
log "daemon.notice" "System optimization completed"
}
# Entry point
main
exit 0
Quick question, is it true that the One's ethernet ports do not support MDI/MDI-X autodetection, that is will not work with patch and cross-over cables, but only one variant? At least that is what ethtool makes me wonder, especially the MDI-X: Unknownpart...
root@OpenWrt_One:~# ethtool eth0
Settings for eth0:
Supported ports: [ TP MII ]
Supported link modes: 100baseT/Full
1000baseT/Full
2500baseT/Full
Supported pause frame use: Symmetric Receive-only
Supports auto-negotiation: Yes
Supported FEC modes: Not reported
Advertised link modes: 100baseT/Full
1000baseT/Full
2500baseT/Full
Advertised pause frame use: Symmetric Receive-only
Advertised auto-negotiation: Yes
Advertised FEC modes: Not reported
Link partner advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Link partner advertised pause frame use: No
Link partner advertised auto-negotiation: Yes
Link partner advertised FEC modes: Not reported
Speed: 1000Mb/s
Duplex: Full
Auto-negotiation: on
master-slave cfg: preferred slave
master-slave status: slave
Port: Twisted Pair
PHYAD: f
Transceiver: external
MDI-X: Unknown
Current message level: 0x000000ff (255)
drv probe link timer ifdown ifup rx_err tx_err
Link detected: yes
root@OpenWrt_One:~# ethtool eth1
Settings for eth1:
Supported ports: [ TP MII ]
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supported pause frame use: Symmetric Receive-only
Supports auto-negotiation: Yes
Supported FEC modes: Not reported
Advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Advertised pause frame use: Symmetric Receive-only
Advertised auto-negotiation: Yes
Advertised FEC modes: Not reported
Speed: Unknown!
Duplex: Unknown! (255)
Auto-negotiation: on
master-slave cfg: preferred slave
master-slave status: unknown
Port: Twisted Pair
PHYAD: 0
Transceiver: external
MDI-X: Unknown
Current message level: 0x000000ff (255)
drv probe link timer ifdown ifup rx_err tx_err
Link detected: no
I would simply test it, but I am unsure I have both known working straight and cross-over cables sitting around my cable box...
I just tested it here. I have 2 X-over cables so I substituted them for each of the straight through cables.
If you get this message you know it worked ![]()
