From 23563dea2de97e6d14d9439f0728be4e0b84e90e Mon Sep 17 00:00:00 2001 From: a-gave Date: Wed, 27 Aug 2025 19:24:02 +0200 Subject: [PATCH 1/4] fix: anygw not working via cable in dsa devices Fix #1192. In dsa devices if another libremesh node is connected via cable anygw starts working intermittently for hosts connected via cable Manually adjust the bridge fdb, as suggested here [0], with an /etc/hotplug.d/net trigger adding an entry that states that the anygw mac address can be found locally on device br-lan Then add a nftables guard rule that drop packets with ether source address equal to the anygw_mac on every dsa user ports that is member of br-lan to prevent icmp6 broadcast loops. To use the command bridge it is necessary to add the package ip-bridge ~30KB. This wouldn't be required in swconfig devices but an easy way to distinguish between dsa and swconfig devices at compile time doesn't exists at the moment. [0] https://www.kernel.org/doc/html/latest/networking/dsa/configuration.html#forwarding-database-fdb-management --- packages/lime-proto-anygw/Makefile | 2 +- .../files/usr/lib/lua/lime/proto/anygw.lua | 35 +++++++++++++++++++ .../files/usr/lib/lua/lime/network.lua | 6 ---- .../files/usr/lib/lua/lime/proto/lan.lua | 22 ++---------- .../files/usr/lib/lua/lime/utils.lua | 23 ++++++++++++ 5 files changed, 61 insertions(+), 27 deletions(-) diff --git a/packages/lime-proto-anygw/Makefile b/packages/lime-proto-anygw/Makefile index f6b094e53..077afe0e1 100644 --- a/packages/lime-proto-anygw/Makefile +++ b/packages/lime-proto-anygw/Makefile @@ -12,7 +12,7 @@ define Package/$(PKG_NAME) DEPENDS:=+dnsmasq-dhcpv6 +kmod-nft-bridge +libuci-lua \ +lime-system +lua +kmod-macvlan \ +shared-state +shared-state-dnsmasq_leases \ - +luci-lib-nixio +firewall4 + +luci-lib-nixio +firewall4 +ip-bridge PKGARCH:=all endef diff --git a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua index b3b73207c..941b45902 100644 --- a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua +++ b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua @@ -126,6 +126,41 @@ function anygw.configure(args) fs.writefile("/etc/dnsmasq.d/lime-proto-anygw-20-ipv6.conf", table.concat(content, "\n").."\n") utils.unsafe_shell("/etc/init.d/dnsmasq enable || true") + + if utils.is_dsa then + local nftDsaGuardFileName = includeDir.."lime-proto-anygw_dsa-mac-rules.nft" + local nftDsaGuard = "#!/usr/sbin/nft -f\ +define dsa_user_ports = {}\ +add table inet filter_anygw_ingress\ +add chain inet filter_anygw_ingress ingress_dsa\ +delete chain inet filter_anygw_ingress ingress_dsa\ +\ +table inet filter_anygw_ingress {\ + chain ingress_dsa {\ + type filter hook ingress devices = $dsa_user_ports priority 0; policy accept\ + ether saddr $anygw_macs counter drop\ + }\ +}\n" + fs.writefile(nftDsaGuardFileName, nftDsaGuard) + + local br_lan_cfgid = utils.find_br_lan() + local dsaPortsList = "#!/bin/sh\ +ports=$(uci get network."..br_lan_cfgid..".ports)\ +dsa_ports={\ +for i in $ports; do\ + echo $i | grep -qv bat && dsa_ports=$dsa_ports$i,\ +done\ +dsa_ports=${dsa_ports::-1}}\ +sed -i \"s|\\(define dsa_user_ports = \\).*|\\1$dsa_ports|\" "..nftDsaGuardFileName.."\ +nft flush ruleset; fw4 reload\n" + fs.writefile("/etc/hotplug.d/lime-config/10-anygw-mac-dsa", dsaPortsList) + utils.unsafe_shell("chmod +x /etc/hotplug.d/lime-config/10-anygw-mac-dsa") + + local bridgeFdbFixes = "#!/bin/sh\ +bridge fdb flush dev br-lan\ +bridge fdb add " .. anygw_mac .. " dev br-lan\n" + fs.writefile("/etc/hotplug.d/net/10-anygw-mac-dsa", bridgeFdbFixes) + end end function anygw.setup_interface(ifname, args) end diff --git a/packages/lime-system/files/usr/lib/lua/lime/network.lua b/packages/lime-system/files/usr/lib/lua/lime/network.lua index c70eca9af..798897a53 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/network.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/network.lua @@ -385,12 +385,6 @@ function network.configure() if protoName == "manual" then break end -- If manual is specified do not configure interface local protoModule = "lime.proto."..protoName local needsConfig = utils.isModuleAvailable(protoModule) - if protoName ~= 'lan' and not flags["specific"] then - --! Work around issue 1121. Do not configure any other - --! protocols than lime.proto.lan on dsa devices unless there - --! is a config net section for the device. - needsConfig = needsConfig and not utils.is_dsa(device) - end if needsConfig then for k,v in pairs(flags) do args[k] = v end local proto = require(protoModule) diff --git a/packages/lime-system/files/usr/lib/lua/lime/proto/lan.lua b/packages/lime-system/files/usr/lib/lua/lime/proto/lan.lua index 0db5e7b9b..a5e5e6f32 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/proto/lan.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/proto/lan.lua @@ -8,24 +8,6 @@ local utils = require("lime.utils") lan.configured = false ---! Find a device section in network with ---! option name 'br-lan' ---! option type 'bridge' -local function find_br_lan(uci) - local br_lan_section = nil - uci:foreach("network", "device", - function(s) - if br_lan_section then return end - local dev_type = uci:get("network", s[".name"], "type") - local dev_name = uci:get("network", s[".name"], "name") - if not (dev_type == 'bridge') then return end - if not (dev_name == 'br-lan') then return end - br_lan_section = s[".name"] - end - ) - return br_lan_section -end - function lan.configure(args) if lan.configured then return end lan.configured = true @@ -38,7 +20,7 @@ function lan.configure(args) uci:set("network", "lan", "netmask", ipv4:mask():string()) uci:set("network", "lan", "proto", "static") uci:set("network", "lan", "mtu", "1500") - local br_lan_section = find_br_lan(uci) + local br_lan_section = utils.find_br_lan() if br_lan_section then uci:delete("network", br_lan_section, "ports") end uci:save("network") @@ -66,7 +48,7 @@ function lan.setup_interface(ifname, args) local uci = config.get_uci_cursor() local bridgedIfs = {} - local br_lan_section = find_br_lan(uci) + local br_lan_section = utils.find_br_lan() if not br_lan_section then return end local oldIfs = uci:get("network", br_lan_section, "ports") or {} --! it should be a table, it was a string in old OpenWrt releases diff --git a/packages/lime-system/files/usr/lib/lua/lime/utils.lua b/packages/lime-system/files/usr/lib/lua/lime/utils.lua index 65179208a..8f0c1d843 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/utils.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/utils.lua @@ -616,4 +616,27 @@ function utils.dumptable(table, nesting) end end +--! Find a device section in network with i.e. +--! option name 'br-lan' +--! option type 'bridge' +function utils.find_bridge_cfgid(bridge_name) + local uci = config.get_uci_cursor() + local br_section = nil + uci:foreach("network", "device", + function(s) + if br_section then return end + local dev_type = uci:get("network", s[".name"], "type") + local dev_name = uci:get("network", s[".name"], "name") + if not (dev_type == 'bridge') then return end + if not (dev_name == bridge_name) then return end + br_section = s[".name"] + end + ) + return br_section +end + +function utils.find_br_lan() + return utils.find_bridge_cfgid("br-lan") +end + return utils From fc95088bbbc8ac4e6cd09a98b9492f13edd40659 Mon Sep 17 00:00:00 2001 From: a-gave Date: Fri, 20 Feb 2026 21:42:07 +0100 Subject: [PATCH 2/4] fix: anygw fails to configure on some dsa devices some devices using dsa, don't have an bridge called br-lan instead it is present a configuration like ``` config device 'switch' option name 'switch' option type 'bridge' config bridge-vlan 'lan_vlan' option device 'switch' option vlan '1' option ports 'lan1 lan2 lan3 lan4' config interface 'lan' option device 'switch.1' ... ``` utils.lua should then check lan_vlan's device first, or fallback to br-lan anygw.lua should configure it's macvlan on top of the device `switch.1` if present or using the most common 'br-lan' added then a dynamic retrieval of the right device from `network.lan.device` tested on: - dlink,dsl-2750b-b1 (bmips/bcm6328) dsa with switch.1 - tp-link,td-w8968-v3 (bmips/bcm6318) dsa with switch.1 - cudy,wr3000s-v1 (mediatek/filogic) dsa with br-lan --- .../lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua | 2 +- packages/lime-system/files/usr/lib/lua/lime/utils.lua | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua index 941b45902..94e0cdfe9 100644 --- a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua +++ b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua @@ -32,7 +32,7 @@ function anygw.configure(args) local anygw_ipv4 = ipv4:minhost() anygw_ipv6:prefix(64) -- SLAAC only works with a /64, per RFC anygw_ipv4:prefix(ipv4:prefix()) - local baseIfname = "br-lan" + local baseIfname = config.uci:get('network', 'lan', 'device') local argsDev = { macaddr = anygw_mac } local argsIf = { proto = "static", diff --git a/packages/lime-system/files/usr/lib/lua/lime/utils.lua b/packages/lime-system/files/usr/lib/lua/lime/utils.lua index 8f0c1d843..60da7de91 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/utils.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/utils.lua @@ -636,7 +636,9 @@ function utils.find_bridge_cfgid(bridge_name) end function utils.find_br_lan() - return utils.find_bridge_cfgid("br-lan") + local dev = config.uci:get('network', 'lan_vlan', 'device') + if dev == nil then dev = 'br-lan' end + return utils.find_bridge_cfgid(dev) end return utils From 02902d0cae6c167139e9e989cdfc4476b4ffefb4 Mon Sep 17 00:00:00 2001 From: a-gave Date: Wed, 4 Mar 2026 22:45:13 +0100 Subject: [PATCH 3/4] fix: run hotplug script anygw-mac-dsa only once Adapt the hotplug script anygw-mac-dsa to #1233. Run it only once at the end of the execution of lime-config. --- packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua index 94e0cdfe9..fa1cf0ae0 100644 --- a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua +++ b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua @@ -145,6 +145,7 @@ table inet filter_anygw_ingress {\ local br_lan_cfgid = utils.find_br_lan() local dsaPortsList = "#!/bin/sh\ +[ \"$ACTION\" = \"post\" ] || exit 0\ ports=$(uci get network."..br_lan_cfgid..".ports)\ dsa_ports={\ for i in $ports; do\ From fa127f5979119d97b34b3fece8e801563879f4de Mon Sep 17 00:00:00 2001 From: a-gave Date: Thu, 12 Mar 2026 09:49:32 +0100 Subject: [PATCH 4/4] fix: typo --- .../lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua index fa1cf0ae0..366e40ac9 100644 --- a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua +++ b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua @@ -127,7 +127,7 @@ function anygw.configure(args) utils.unsafe_shell("/etc/init.d/dnsmasq enable || true") - if utils.is_dsa then + if utils.is_dsa() then local nftDsaGuardFileName = includeDir.."lime-proto-anygw_dsa-mac-rules.nft" local nftDsaGuard = "#!/usr/sbin/nft -f\ define dsa_user_ports = {}\