Files
github-actions[bot] c71da84035
Merge-upstream / merge (push) Canceled after 0s
💋 Sync 2026-10-11 00:16:14
2026-10-11 00:16:14 +08:00

87 lines
4.2 KiB
Markdown

# mwan3-autobalancer
Adaptive weight controller for [`mwan3-nft`](https://github.com/koshev-msk/mwan3-nft) (OpenWrt 25.12, nftables).
It adjusts load-balancing weights at runtime from link quality. It does **not** patch mwan3 and does **not** run any active probes.
Is ucode and shell implementation of https://github.com/AlexStarc/mwan3-autobalancer
## How it works
1. Reads the latency and packet loss that `mwan3track` already collects (via `ubus call mwan3 status`).
2. Smooths the samples (EWMA) and computes a quality factor per link, **relative to that link's own baseline latency**. A single lost ping barely changes anything.
3. Scales each member's configured uci `weight` by its quality factor and rounds the result to a small total (default 20, i.e. 5% steps).
4. If the result differs enough from the live chain (hysteresis), rewrites the `numgen ... vmap` rule of `mwan3_policy_<name>` in **one atomic nft transaction** (`flush` + `add` in a single batch). All other rules, including last-resort, are re-added unchanged. Both `numgen inc` and `numgen random` are supported.
## Safety
- **Observe mode is the default**: decisions are logged, nothing is changed.
- **Level-triggered**: if mwan3 rebuilds the chain (ifup/ifdown), the next pass or the hotplug poke restores the adjusted weights.
- Unrecognized chain shape, unknown member or missing data: the chain is left untouched.
- On stop (SIGTERM) the original uci weights are restored. procd respawns the daemon after a crash.
## Requirements
- `mwan3-nft`, `ucode` with the `fs`, `uci`, `ubus` and `uloop` modules (ucode from OpenWrt 25.12 or newer).
- `check_quality` enabled on the balanced interfaces. To keep mwan3's own up/down decisions unchanged, neutralize its thresholds:
```sh
for i in wan1 wan2; do # your interface names
uci set mwan3.$i.check_quality='1'
uci set mwan3.$i.failure_latency='100000'
uci set mwan3.$i.recovery_latency='99999'
uci set mwan3.$i.failure_loss='100'
uci set mwan3.$i.recovery_loss='99'
done
uci commit mwan3 && mwan3 restart
```
## Usage
```sh
/usr/sbin/mwan3-autobalancer once # one-shot calculation printout, changes nothing
/usr/sbin/mwan3-autobalancer restore # restore original uci weights
/etc/init.d/mwan3-autobalancer start # run the daemon (needs enabled=1)
```
Recommended rollout: `enabled=1`, keep `observe=1`, watch `logread | grep -i autobalancer`, then set `observe=0`.
## Configuration (`/etc/config/mwan3_autobalancer`)
| Option | Default | Meaning |
|------------|------------|--------------------------------------------------------------------|
| `enabled` | `0` | Start the daemon |
| `observe` | `1` | Log decisions only, do not touch the chain |
| `policy` | `balanced` | mwan3 policy name |
| `interval` | `30` | Seconds between passes (minimum 5) |
| `total` | `20` | Sum of integer weights in the chain (step = 100/total %) |
| `hyst` | `1.0` | Apply when a target is off by at least this many steps |
With `numgen random` finer steps are fine, e.g. `total=100`, `hyst=5`. With `numgen inc` keep `total` small, because connections are handed out in runs of up to `total`.
Model constants (baseline drift, loss threshold, smoothing) are at the top of `model.uc`.
## ubus
Object `mwan3_autobalancer`:
- `poke`: trigger an early pass (called from the hotplug script after mwan3 rebuilds the chain)
- `status`: current mode, policy and last decision
## ToDo
- LuCI page.
## Statistics collector (optional)
`ab-stats.sh` appends one CSV row per run: chain weights, per-link status/latency/loss, interface byte counters, connection counts per mark, daemon RSS and CPU ticks.
```sh
cp ab-stats.sh /root/ && chmod +x /root/ab-stats.sh
(crontab -l 2>/dev/null; echo '* * * * * /root/ab-stats.sh >/dev/null 2>&1') | crontab -
/etc/init.d/cron enable && /etc/init.d/cron restart
```
Data goes to `/tmp/ab-stats.csv` (RAM, trimmed to the last 8000 rows, lost on reboot).
## Thanks
To idea thakns https://github.com/AlexStarc