Files
klaster/ansible/roles/openwrt/tasks/network.yml
T
Lumpiasty 2d69cc6569
ci/woodpecker/push/flux-reconcile-source Pipeline was successful
ci/woodpecker/cron/renovate Pipeline was successful
fix(ansible): resolve LTE failover data-plane bug on BroadMobi BM806C
The embedded BroadMobi BM806C modem (Qualcomm MDM9225, firmware
M1.2.0_E1.0.1_A1.1.8) in the D-Link DWR-921 C1 has two independent
firmware bugs that together break the QMI data plane:

1.  Modem accepts 802.3 framing but its 802.3 path is buggy — downlink
    frames never reach the host kernel. raw-ip framing works.

2.  qmish calls uqmi --start-network --apn <foo>, which triggers
    FS#1363: the modem establishes a phantom bearer that gets IP
    addresses but has no working data path. Using --start-network
    --profile <N> (referencing a pre-configured NVRAM profile with
    the same APN) works correctly.

Fixes applied:

- qmish patches (3x community.openwrt.lineinfile):
  * Replace --set-data-format 802.3 with raw-ip
  * Replace --wda-set-data-format 802.3 with raw-ip
  * Bracket raw_ip sysfs write with ip link down/up (kernel rejects
    write with -EBUSY when wwan0 is already up)
- Modem NVRAM: create/modify profile 2 (internetipv6, ipv6) for the
  IPv6 APN — profile 1 is already managed by qmish's --modify-profile
- UCI wwan: add profile=1 and v6profile=2 so qmish uses --start-network
  --profile instead of --apn on both the v4 and v6 legs
- Firewall: add wwan zone (input REJECT, output ACCEPT, forward REJECT)
  and Allow-ICMPv6-wwan rule
- main.yml: reorder — packages (including usb-modeswitch) now run
  before wwan setup, so the modem is out of EDL mode when wwan.yml
  queries it for profile creation

See docs/wwan-bm806c-qmi-workaround.md for the full diagnosis
(what we ruled out, how we confirmed, manual setup steps, component
versions, future upstreaming).
2026-05-16 21:20:26 +02:00

178 lines
6.7 KiB
YAML

---
# Network layout:
# MikroTik ether3 ↔ dlink WAN port (switch0 port4)
# MikroTik sends MGMT traffic untagged, vlan2/vlan5/vlan6 tagged.
#
# switch0 VLAN table:
# VLAN 1 (MGMT): CPU(6) tagged, WAN(4) untagged → eth0.1 → mgmt
# VLAN 2 (LAN): CPU(6) tagged, WAN(4) tagged, LAN1-4(0-3) untagged → eth0.2 → br-lan → lan
# VLAN 5 (IOT): CPU(6) tagged, WAN(4) tagged → eth0.5 → br-iot → iot
# VLAN 6 (UPLINK): CPU(6) tagged, WAN(4) tagged → eth0.6 → uplink
#
# Interfaces:
# mgmt — static 192.168.255.11/24 on eth0.1, management
# lan — bridge (br-lan) on eth0.2, LAN clients via LAN ports
# iot — bridge (br-iot) on eth0.5, IoT clients via wifi only
# uplink — static 192.168.6.2/24 + 2001:470:61a3:600::2/64 on eth0.6, internet access for opkg
# wwan — QMI LTE modem (/dev/cdc-wdm0), Orange PL dual-stack failover (APNs: internet + internetipv6)
# Manual ifup only (option auto '0'); modem-specific quirks handled in wwan.yml.
- name: Configure network
community.openwrt.uci:
command: import
merge: false
config: network
value: |
package network
config interface 'loopback'
option device 'lo'
option proto 'static'
list ipaddr '127.0.0.1/8'
config globals 'globals'
option ula_prefix 'fd4d:508e:899a::/48'
config switch
option name 'switch0'
option reset '1'
option enable_vlan '1'
config switch_vlan
option device 'switch0'
option vlan '1'
option vid '1'
option description 'mgmt'
option ports '4 6t'
config switch_vlan
option device 'switch0'
option vlan '2'
option vid '2'
option description 'lan'
option ports '0 1 2 3 4t 6t'
config switch_vlan
option device 'switch0'
option vlan '5'
option vid '5'
option description 'iot'
option ports '4t 6t'
config switch_vlan
option device 'switch0'
option vlan '6'
option vid '6'
option description 'uplink'
option ports '4t 6t'
config device
option name 'br-lan'
option type 'bridge'
list ports 'eth0.2'
config interface 'mgmt'
option device 'eth0.1'
option proto 'static'
option ipaddr '{{ openwrt_mgmt_ip }}/{{ openwrt_mgmt_prefix }}'
option dns '{{ openwrt_dns_servers | join(" ") }}'
# Policy routing for mgmt interface.
#
# Without this, replies to traffic destined for 192.168.255.11 (mgmt IP)
# would be sent via the default route (eth0.6/uplink, src 192.168.6.2)
# instead of back through eth0.1. This is because mgmt clients (e.g. PCs
# on 192.168.0.0/24) are not on the directly connected 192.168.255.0/24
# subnet — they reach 192.168.255.11 via MikroTik routing, so the kernel
# has no connected route matching the reply destination and falls back to
# the default route, causing asymmetric routing.
#
# ip4table cannot be used here — it generates rules matching only the
# interface IP (from 192.168.255.11) and destination (to 192.168.255.11/24),
# not the source subnet needed for return traffic from arbitrary clients.
# Instead we manually add a rule matching any traffic sourced from the mgmt
# subnet and a default route in table 100 via the MikroTik mgmt gateway.
# Same-subnet traffic (src and dst both in 192.168.255.0/24) must stay in
# main table so replies go directly out eth0.1 without being redirected.
# Priority 500 ensures this fires before the catch-all rule below (1000).
config rule
option src '192.168.255.0/24'
option dest '192.168.255.0/24'
option lookup 'main'
option priority '500'
# All other traffic sourced from 192.168.255.0/24 (i.e. replies to clients
# outside this subnet, routed via MikroTik) uses table 100 which has a
# default route back via eth0.1 to prevent asymmetric routing.
config rule
option src '192.168.255.0/24'
option lookup '100'
option priority '1000'
config route
option table '100'
option interface 'mgmt'
option target '0.0.0.0/0'
option gateway '{{ openwrt_mgmt_gateway }}'
config interface 'lan'
option device 'br-lan'
option proto 'none'
config device
option name 'br-iot'
option type 'bridge'
list ports 'eth0.5'
config interface 'iot'
option device 'br-iot'
option proto 'none'
# LTE failover via embedded BroadMobi BM806C (Qualcomm MDM9225, fw M1.2.0_E1.0.1_A1.1.8).
# This modem has a firmware bug: when QMI --start-network is invoked with --apn
# (a WDS TLV), the modem establishes a phantom bearer that gets assigned IP
# addresses but cannot pass downlink data — TX packets egress, zero replies arrive.
# See https://forum.openwrt.org/t/problem-with-bm806u-e1-dwr-921-c3/130094 and
# https://github.com/openwrt/openwrt/issues/6295 (FS#1363). Workaround: configure
# the APN via NVRAM profile (uqmi --modify-profile, done by qmi.sh) and reference
# the profile via --start-network --profile, NOT --apn. qmi.sh already supports
# passing --profile when UCI option 'profile' is set — and 'apn' is kept because
# qmi.sh's --modify-profile call (line 314) still needs it to write the profile.
# qmi.sh only writes profile 1; profile 2 (used for the IPv6 v6apn) is created by
# the wwan role task.
#
# The BM806C also requires raw-ip framing (kernel qmi_wwan driver mode) to
# work properly. qmi.sh defaults to 802.3 mode; a patch in the wwan role task
# changes this to raw-ip for our setup.
config interface 'wwan'
option device '/dev/cdc-wdm0'
option proto 'qmi'
option apn 'internet'
option v6apn 'internetipv6'
option profile '1'
option v6profile '2'
option auth 'pap'
option username 'internet'
option password 'internet'
option pdptype 'ipv4v6'
option dhcp '0'
option dhcpv6 '0'
option metric '100'
option auto '0'
config interface 'uplink'
option device 'eth0.6'
option proto 'static'
option ipaddr '192.168.6.2/24'
option gateway '192.168.6.1'
option dns '192.168.6.1'
option ip6addr '2001:470:61a3:600::2/64'
option ip6gw '2001:470:61a3:600::1'
notify: Reload network
- name: Commit network config
community.openwrt.uci:
command: commit
key: network