mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
fix(openwrt): ship mesh transports commented, uncomment on setup
The default-on mesh0/mesh1 transport entries logged a per-boot "interface missing" bind warning on installs that never create fips-mesh* (PR #123 review). Ship them commented out instead, and have fips-mesh-setup uncomment the matching meshN block in fips.yaml when it creates the interface (re-commenting it on remove) — a stock install stays quiet while the flash-and-drop-in flow still needs no manual config edit. Also note in the how-to that both the create and remove paths run `wifi reload`, which briefly drops client APs on all radios. The shipped-config regression test now checks both states parse: as shipped (mesh inactive) and after the uncomment the helper performs.
This commit is contained in:
@@ -70,9 +70,16 @@ fips-mesh-setup radio1
|
||||
|
||||
This creates an open 802.11s interface with mesh ID `fips-mesh` and
|
||||
HWMP forwarding off, attaches it to an unmanaged netifd interface (no
|
||||
IP configuration — none is needed), and reloads the radio. Interfaces
|
||||
are named by radio index: `radio0` → `fips-mesh0`, `radio1` →
|
||||
`fips-mesh1`. Pass a second argument to use a different mesh ID.
|
||||
IP configuration — none is needed), uncomments the matching `meshN`
|
||||
transport entry in `/etc/fips/fips.yaml` (see Step 2), and reloads the
|
||||
radio. Interfaces are named by radio index: `radio0` → `fips-mesh0`,
|
||||
`radio1` → `fips-mesh1`. Pass a second argument to use a different
|
||||
mesh ID.
|
||||
|
||||
Note: the helper runs `wifi reload`, which re-applies the whole
|
||||
wireless config and so briefly drops every client AP on all radios for
|
||||
a few seconds. `fips-mesh-setup remove` reloads the same way. Expect
|
||||
the blip if clients are connected.
|
||||
|
||||
On dual-band routers, meshing **both** bands is worth it: 2.4 GHz
|
||||
reaches further at lower rates, 5 GHz carries more over shorter
|
||||
@@ -123,10 +130,13 @@ wifi reload
|
||||
|
||||
## Step 2 — check the FIPS transport binding
|
||||
|
||||
The `fips.yaml` shipped in the OpenWrt package already carries one
|
||||
transport entry per radio, enabled by default — each is inert until
|
||||
its interface exists. If you maintain your own config, make sure they
|
||||
are present:
|
||||
The `fips.yaml` shipped in the OpenWrt package carries one transport
|
||||
entry per radio, but **commented out** — so a stock install that never
|
||||
runs this helper logs no per-boot "interface missing" warning.
|
||||
`fips-mesh-setup` uncommented the matching `meshN` entry in Step 1, so
|
||||
there is normally nothing to do here. If you maintain your own config
|
||||
(or ran the manual UCI above instead of the helper), make sure the
|
||||
entries are present and uncommented:
|
||||
|
||||
```yaml
|
||||
transports:
|
||||
|
||||
@@ -100,28 +100,31 @@ transports:
|
||||
auto_connect: true
|
||||
accept_connections: true
|
||||
|
||||
# 802.11s mesh backhaul between FIPS routers. Each entry is inert until
|
||||
# its radio interface exists — create them with 'fips-mesh-setup <radio>'
|
||||
# (once per radio; radio0 -> fips-mesh0, radio1 -> fips-mesh1), then
|
||||
# restart fips (a transport whose interface is missing at startup is
|
||||
# skipped, not retried). Dual-band routers can mesh on both bands at
|
||||
# once — failover, not multipath: FIPS keeps one active link per peer,
|
||||
# the other band stands by. The mesh runs OPEN (no SAE) with 802.11s
|
||||
# 802.11s mesh backhaul between FIPS routers. These entries ship
|
||||
# commented out so a stock install that never creates fips-mesh*
|
||||
# logs no per-boot "interface missing" bind warning. Running
|
||||
# 'fips-mesh-setup <radio>' creates the interface AND uncomments the
|
||||
# matching block here (once per radio; radio0 -> fips-mesh0, radio1 ->
|
||||
# fips-mesh1); 'fips-mesh-setup remove' re-comments it. Restart fips
|
||||
# after — a transport whose interface is missing at startup is skipped,
|
||||
# not retried. Dual-band routers can mesh on both bands at once —
|
||||
# failover, not multipath: FIPS keeps one active link per peer, the
|
||||
# other band stands by. The mesh runs OPEN (no SAE) with 802.11s
|
||||
# forwarding off: FIPS's Noise handshake is the encryption and
|
||||
# authentication, and FIPS is the routing layer. See
|
||||
# docs/how-to/set-up-80211s-mesh-backhaul.md.
|
||||
mesh0:
|
||||
interface: "fips-mesh0"
|
||||
discovery: true
|
||||
announce: true
|
||||
auto_connect: true
|
||||
accept_connections: true
|
||||
mesh1:
|
||||
interface: "fips-mesh1"
|
||||
discovery: true
|
||||
announce: true
|
||||
auto_connect: true
|
||||
accept_connections: true
|
||||
# mesh0:
|
||||
# interface: "fips-mesh0"
|
||||
# discovery: true
|
||||
# announce: true
|
||||
# auto_connect: true
|
||||
# accept_connections: true
|
||||
# mesh1:
|
||||
# interface: "fips-mesh1"
|
||||
# discovery: true
|
||||
# announce: true
|
||||
# auto_connect: true
|
||||
# accept_connections: true
|
||||
|
||||
# Bluetooth Low Energy transport — requires BlueZ and the 'ble' feature.
|
||||
# ble:
|
||||
|
||||
@@ -24,12 +24,51 @@
|
||||
# fips-mesh1) and are intentionally NOT bridged into br-lan: the FIPS
|
||||
# Ethernet transport binds each directly and runs discovery beacons over it.
|
||||
#
|
||||
# The shipped /etc/fips/fips.yaml already carries 'mesh0' and 'mesh1'
|
||||
# entries under 'transports.ethernet' bound to these names — each is inert
|
||||
# until its interface exists. After an interface is up, restart fips.
|
||||
# The shipped /etc/fips/fips.yaml carries 'mesh0' and 'mesh1' entries under
|
||||
# 'transports.ethernet' bound to these names, but commented out — a stock
|
||||
# install that never creates fips-mesh* then logs no bind warning. This
|
||||
# helper uncomments the matching entry when it creates an interface and
|
||||
# re-comments it on remove, so the daemon binds the transport without a
|
||||
# manual config edit. After an interface is up, restart fips.
|
||||
# See docs/how-to/set-up-80211s-mesh-backhaul.md for the full guide.
|
||||
|
||||
DEFAULT_MESH_ID="fips-mesh"
|
||||
CONFIG="/etc/fips/fips.yaml"
|
||||
|
||||
# Replace $CONFIG with the rewritten $CONFIG.tmp. Force mode 0600 first: the
|
||||
# package installs fips.yaml 0600 (it may hold an inline 'nsec' private key),
|
||||
# and a fresh tmp file would otherwise land world-readable after the move.
|
||||
mesh_config_write() {
|
||||
chmod 600 "$CONFIG.tmp" && mv "$CONFIG.tmp" "$CONFIG"
|
||||
}
|
||||
|
||||
# Uncomment the 'mesh<idx>' transports.ethernet block in $CONFIG (created by
|
||||
# 'fips-mesh-setup'). Reversible with mesh_config_disable. Returns:
|
||||
# 0 enabled (or already active) 1 no config file 2 no such block
|
||||
mesh_config_enable() {
|
||||
idx="$1"
|
||||
[ -f "$CONFIG" ] || return 1
|
||||
grep -q "^ mesh$idx:" "$CONFIG" && return 0
|
||||
grep -q "^ # mesh$idx:" "$CONFIG" || return 2
|
||||
awk -v idx="$idx" '
|
||||
$0 ~ ("^ # mesh" idx ":[ \t]*$") { blk = 1; sub(/^ # /, " "); print; next }
|
||||
blk && /^ # / { sub(/^ # /, " "); print; next }
|
||||
{ blk = 0; print }
|
||||
' "$CONFIG" > "$CONFIG.tmp" && mesh_config_write
|
||||
}
|
||||
|
||||
# Re-comment the 'mesh<idx>' block so the daemon stops binding it (and stops
|
||||
# warning about the now-missing interface). Inverse of mesh_config_enable.
|
||||
mesh_config_disable() {
|
||||
idx="$1"
|
||||
[ -f "$CONFIG" ] || return 1
|
||||
grep -q "^ mesh$idx:" "$CONFIG" || return 0
|
||||
awk -v idx="$idx" '
|
||||
$0 ~ ("^ mesh" idx ":[ \t]*$") { blk = 1; sub(/^ /, " # "); print; next }
|
||||
blk && /^ / { sub(/^ /, " # "); print; next }
|
||||
{ blk = 0; print }
|
||||
' "$CONFIG" > "$CONFIG.tmp" && mesh_config_write
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: fips-mesh-setup <radio> [mesh-id]" >&2
|
||||
@@ -62,15 +101,18 @@ if [ "$1" = "remove" ]; then
|
||||
ifname="$(uci -q get "wireless.$section.ifname")"
|
||||
uci -q delete "wireless.$section"
|
||||
uci -q delete "network.$section"
|
||||
# Re-comment the matching mesh<N> transport in fips.yaml so the
|
||||
# daemon stops warning about the interface we just removed.
|
||||
idx="$(printf '%s' "$ifname" | sed -n 's/.*[^0-9]\([0-9]\{1,\}\)$/\1/p')"
|
||||
[ -n "$idx" ] && mesh_config_disable "$idx"
|
||||
echo "Removed ${ifname:-$section}."
|
||||
done
|
||||
uci commit wireless
|
||||
uci commit network
|
||||
# 'wifi reload' re-applies the whole wireless config, so it briefly drops
|
||||
# every client AP on all radios (a few seconds) — expected on remove.
|
||||
wifi reload
|
||||
echo "Restart fips: /etc/init.d/fips restart"
|
||||
echo "(The 'mesh*' entries in /etc/fips/fips.yaml are harmless without"
|
||||
echo "their interfaces, but you may comment them out to silence the"
|
||||
echo "startup warnings.)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -178,8 +220,22 @@ uci set "network.$SECTION.proto=none"
|
||||
|
||||
uci commit wireless
|
||||
uci commit network
|
||||
# 'wifi reload' re-applies the whole wireless config, so it briefly drops
|
||||
# every client AP on all radios (a few seconds) — expected when adding a mesh.
|
||||
wifi reload
|
||||
|
||||
# Enable the matching mesh<N> transport in the shipped fips.yaml (it ships
|
||||
# commented out). Tailor the restart hint to what we could do.
|
||||
mesh_config_enable "$IDX"
|
||||
case $? in
|
||||
0) TRANSPORT_NOTE="The mesh$IDX transport in $CONFIG that binds '$MESH_IFNAME' is
|
||||
now uncommented and enabled." ;;
|
||||
1) TRANSPORT_NOTE="No $CONFIG found — add a transports.ethernet entry binding
|
||||
interface '$MESH_IFNAME' by hand." ;;
|
||||
*) TRANSPORT_NOTE="No 'mesh$IDX' entry in $CONFIG — add a transports.ethernet
|
||||
entry binding interface '$MESH_IFNAME' by hand (copy the mesh0 block)." ;;
|
||||
esac
|
||||
|
||||
cat <<EOF
|
||||
Created open 802.11s mesh '$MESH_ID' as $MESH_IFNAME on $RADIO \
|
||||
(band ${BAND:-?}, channel ${CHANNEL:-auto}).
|
||||
@@ -189,10 +245,9 @@ ALL routers in this backhaul must share this mesh ID AND channel
|
||||
radio too — second band is a standby path (failover, not multipath).
|
||||
|
||||
Next steps:
|
||||
1. Restart the daemon (the shipped /etc/fips/fips.yaml already binds
|
||||
mesh transports to fips-mesh0/fips-mesh1). Restart AFTER the
|
||||
interface is up — a transport whose interface is missing at
|
||||
startup is skipped, not retried:
|
||||
1. $TRANSPORT_NOTE
|
||||
Restart the daemon AFTER the interface is up — a transport whose
|
||||
interface is missing at startup is skipped, not retried:
|
||||
/etc/init.d/fips restart
|
||||
2. Verify L2 peering with a second FIPS router in range:
|
||||
iw dev $MESH_IFNAME station dump
|
||||
|
||||
@@ -771,13 +771,35 @@ node:
|
||||
}
|
||||
|
||||
/// The fips.yaml shipped in the OpenWrt package must keep parsing as the
|
||||
/// config schema evolves, including the default-enabled 802.11s mesh
|
||||
/// backhaul transport entries — one per radio, so dual-band routers can
|
||||
/// mesh on both bands (docs/how-to/set-up-80211s-mesh-backhaul.md).
|
||||
/// config schema evolves. The 802.11s mesh backhaul entries (one per
|
||||
/// radio, so dual-band routers can mesh on both bands) ship commented
|
||||
/// out — a stock install that never creates fips-mesh* logs no per-boot
|
||||
/// bind warning; `fips-mesh-setup` uncomments the matching block when it
|
||||
/// creates the interface (docs/how-to/set-up-80211s-mesh-backhaul.md).
|
||||
/// Verify both states parse: as shipped (mesh inactive), and after the
|
||||
/// uncomment `fips-mesh-setup` performs.
|
||||
#[test]
|
||||
fn shipped_openwrt_config_parses() {
|
||||
let yaml = include_str!("../../packaging/openwrt-ipk/files/etc/fips/fips.yaml");
|
||||
|
||||
// As shipped: parses, and the mesh entries are commented out (a
|
||||
// running daemon binds no fips-mesh* transport, so no bind warning).
|
||||
let config: Config = serde_yaml::from_str(yaml).expect("shipped OpenWrt fips.yaml");
|
||||
for name in ["mesh0", "mesh1"] {
|
||||
assert!(
|
||||
!config
|
||||
.transports
|
||||
.ethernet
|
||||
.iter()
|
||||
.any(|(n, _)| n == Some(name)),
|
||||
"{name} must ship commented out, not active, in fips.yaml"
|
||||
);
|
||||
}
|
||||
|
||||
// What `fips-mesh-setup` produces: uncomment each mesh block, which
|
||||
// must still parse into a transport entry bound to the right netdev.
|
||||
let config: Config = serde_yaml::from_str(&uncomment_mesh_blocks(yaml))
|
||||
.expect("fips.yaml with mesh transports uncommented");
|
||||
for (name, interface) in [("mesh0", "fips-mesh0"), ("mesh1", "fips-mesh1")] {
|
||||
assert!(
|
||||
config
|
||||
@@ -785,11 +807,36 @@ node:
|
||||
.ethernet
|
||||
.iter()
|
||||
.any(|(n, eth)| n == Some(name) && eth.interface == interface),
|
||||
"{name} backhaul entry missing from shipped OpenWrt fips.yaml"
|
||||
"{name} backhaul entry missing after uncommenting shipped fips.yaml"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Mirror `fips-mesh-setup`'s block uncomment: strip the ` # ` prefix
|
||||
/// from each `# mesh<N>:` header and its ` # ` continuation lines,
|
||||
/// leaving every other comment untouched.
|
||||
fn uncomment_mesh_blocks(yaml: &str) -> String {
|
||||
let mut out = String::new();
|
||||
let mut in_block = false;
|
||||
for line in yaml.lines() {
|
||||
let is_header = line
|
||||
.strip_prefix(" # mesh")
|
||||
.and_then(|r| r.strip_suffix(':'))
|
||||
.is_some_and(|n| !n.is_empty() && n.bytes().all(|b| b.is_ascii_digit()));
|
||||
if is_header {
|
||||
in_block = true;
|
||||
out.push_str(&line.replacen(" # ", " ", 1));
|
||||
} else if in_block && line.starts_with(" # ") {
|
||||
out.push_str(&line.replacen(" # ", " ", 1));
|
||||
} else {
|
||||
in_block = false;
|
||||
out.push_str(line);
|
||||
}
|
||||
out.push('\n');
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_yaml_with_hex() {
|
||||
let yaml = r#"
|
||||
|
||||
Reference in New Issue
Block a user