PBR 1.1.1-7 cannot use the dynamic modem interface created by the GL.iNet M2 5G Development Board on Flint 3 firmware 4.8.4
Hi GL.iNet Team,
I found an integration issue between the GL.iNet modem subsystem and the Policy-Based Routing (PBR) package when using the GL.iNet M2 5G Development Board with a GL-BE9300 Flint 3.
Environment
Device: GL.iNet GL-BE9300 / Flint 3
Firmware: 4.8.4
OpenWrt: 23.05-SNAPSHOT
PBR package: 1.1.1-7
Firewall: fw4 / nftables
Cellular hardware: GL.iNet M2 5G Development Board connected through USB
Modem protocol: qcm
Parent modem interface: modem_1_1
Dynamic IPv4 interface: modem_1_1_4
Linux network device: wwan0
Problem
The GL.iNet modem subsystem creates the IPv4 cellular interface dynamically as:
modem_1_1_4
The interface is fully operational and visible through ubus:
ubus call network.interface.modem_1_1_4 status
The output shows:
"up": true
"dynamic": true
"l3_device": "wwan0"
IPv4 address: 10.196.1.131/29
Default gateway: 10.196.1.132
DNS servers: 8.8.8.8 and 8.8.4.4
However, the dynamic interface is not present in the UCI network configuration.
The following command returns no output:
uci show network | grep modem_1_1_4
Initial PBR configuration
I enabled PBR and explicitly added the dynamic interface as a supported interface:
config pbr 'config'
option enabled '1'
list supported_interface 'modem_1_1_4'
Despite this, PBR initially only created routing tables for:
wan
wwan
secondwan
The service output showed that modem_1_1_4 was being monitored:
pbr 1.1.1-7 monitoring interfaces: wan wwan secondwan modem_1_1_4
However, no pbr_modem_1_1_4 routing table was created.
Root cause 1: dynamic interfaces are not processed during startup
PBR creates its routing tables using:
config_foreach interface_process 'interface' 'create'
This only processes interface sections defined in /etc/config/network.
Because modem_1_1_4 is dynamically created through ubus/netifd and is not a UCI interface section, interface_process() is never called for it.
The dynamic interface is included in ifacesSupported and monitored by PBR, but it is not included in routing-table creation.
Root cause 2: policy validation rejects the dynamic interface
A policy using:
option interface 'modem_1_1_4'
was initially rejected with:
ERROR: Policy 'ZTB-FRA' has no assigned interface!
The validator only accepts interfaces defined as UCI network interfaces.
Exact tested patch
The following are the only two PBR code changes required on my router.
File:
/etc/init.d/pbr
Change 1: Process supported dynamic interfaces during startup
Original code:
interface_process 'all' 'prepare'
config_foreach interface_process 'interface' 'create'
interface_process_tor 'tor' 'destroy'
Working code:
interface_process 'all' 'prepare'
config_foreach interface_process 'interface' 'create'
for n in $ifacesSupported; do
uci -q get "network.${n}" >/dev/null 2>&1 || interface_process "$n" "create"
done
interface_process_tor 'tor' 'destroy'
This preserves processing for all normal UCI interfaces.
It then processes interfaces from ifacesSupported that do not exist as UCI interface sections. This allows the dynamically created modem_1_1_4 interface to receive a routing table and fwmark.
Change 2: Allow a dynamic interface name in policy validation
Original validator:
'interface:or("ignore", "tor", uci("network", "@interface")):wan'
Working validator:
'interface:or("ignore", "tor", uci("network", "@interface"), string):wan'
Unified diff representation
--- a/etc/init.d/pbr
+++ b/etc/init.d/pbr
@@
output 1 'Processing interfaces '
json_add_array 'gateways'
interface_process 'all' 'prepare'
config_foreach interface_process 'interface' 'create'
+ for n in $ifacesSupported; do
+ uci -q get "network.${n}" >/dev/null 2>&1 || interface_process "$n" "create"
+ done
interface_process_tor 'tor' 'destroy'
is_tor_running && interface_process_tor 'tor' 'create'
json_close_array
@@
- 'interface:or("ignore", "tor", uci("network", "@interface")):wan' \
+ 'interface:or("ignore", "tor", uci("network", "@interface"), string):wan' \
Test policy
After applying the two changes, I configured the following policy:
config policy
option name 'ZTB-FRA'
option src_addr '172.16.1.5'
option interface 'modem_1_1_4'
Successful result
PBR now processes the interface correctly:
Setting up routing for 'modem_1_1_4/wwan0/10.196.1.132' [✓]
The following routing table is created:
ip route show table pbr_modem_1_1_4
default via 10.196.1.132 dev wwan0
10.1.199.0/24 dev br-lan proto kernel scope link src 10.1.199.1
100.64.0.0/10 dev tailscale0 scope link
172.16.1.0/24 dev br-lan proto kernel scope link src 172.16.1.1
PBR also creates the correct fwmark rule:
30003: from all fwmark 0x40000/0xff0000 lookup pbr_modem_1_1_4
The policy loads successfully:
Routing 'ZTB-FRA' via modem_1_1_4 [✓]
The generated nftables policy is:
ip saddr @pbr_modem_1_1_4_4_src_ip_cfg066ff5 goto pbr_mark_0x040000 comment "ZTB-FRA"
Traffic from 172.16.1.5 is successfully routed through wwan0 and the M2 5G Development Board.
An nftables counter was temporarily added for verification and confirmed that packets from 172.16.1.5 matched the policy. The counter itself is not required for the permanent solution.
Important clarification
No modification to pbr_get_gateway() was required.
Once modem_1_1_4 was actually processed by interface_process(), the existing PBR code correctly detected the gateway as 10.196.1.132 and created the proper default route.
Suggested permanent fix
PBR currently uses ifacesSupported for monitoring dynamic interfaces, but routing-table creation only loops through UCI-defined network interfaces.
A permanent fix could process non-UCI interfaces from ifacesSupported during startup, similar to the tested patch above.
The policy validator should also allow an interface explicitly configured through supported_interface, even when that interface exists only dynamically through ubus/netifd.
Alternatively, GL.iNet could expose the M2 cellular connection through a persistent UCI network interface that third-party OpenWrt packages can reference.
Impact
This may affect other GL.iNet products and modem configurations that create dynamic IPv4 child interfaces such as modem_x_x_4.
The issue is therefore likely not limited to the GL-BE9300 or my specific M2 5G Development Board.
I have successfully tested the above patch on a GL-BE9300 running firmware 4.8.4 with the GL.iNet M2 5G Development Board.
I would be happy to test an official firmware or package fix and provide any additional diagnostics required.
Thank you.