Skip to content

Commit dcdf181

Browse files
committed
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
1 parent 04e5650 commit dcdf181

File tree

5 files changed

+61
-27
lines changed

5 files changed

+61
-27
lines changed

packages/lime-proto-anygw/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ define Package/$(PKG_NAME)
1414
DEPENDS:=+dnsmasq-dhcpv6 +kmod-nft-bridge +libuci-lua \
1515
+lime-system +lua +kmod-macvlan \
1616
+shared-state +shared-state-dnsmasq_leases \
17-
+luci-lib-nixio +firewall4
17+
+luci-lib-nixio +firewall4 +ip-bridge
1818
PKGARCH:=all
1919
endef
2020

packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,41 @@ function anygw.configure(args)
126126
fs.writefile("/etc/dnsmasq.d/lime-proto-anygw-20-ipv6.conf", table.concat(content, "\n").."\n")
127127

128128
utils.unsafe_shell("/etc/init.d/dnsmasq enable || true")
129+
130+
if utils.is_dsa then
131+
local nftDsaGuardFileName = includeDir.."lime-proto-anygw_dsa-mac-rules.nft"
132+
local nftDsaGuard = "#!/usr/sbin/nft -f\
133+
define dsa_user_ports = {}\
134+
add table inet filter_anygw_ingress\
135+
add chain inet filter_anygw_ingress ingress_dsa\
136+
delete chain inet filter_anygw_ingress ingress_dsa\
137+
\
138+
table inet filter_anygw_ingress {\
139+
chain ingress_dsa {\
140+
type filter hook ingress devices = $dsa_user_ports priority 0; policy accept\
141+
ether saddr $anygw_macs counter drop\
142+
}\
143+
}\n"
144+
fs.writefile(nftDsaGuardFileName, nftDsaGuard)
145+
146+
local br_lan_cfgid = utils.find_br_lan()
147+
local dsaPortsList = "#!/bin/sh\
148+
ports=$(uci get network."..br_lan_cfgid..".ports)\
149+
dsa_ports={\
150+
for i in $ports; do\
151+
echo $i | grep -qv bat && dsa_ports=$dsa_ports$i,\
152+
done\
153+
dsa_ports=${dsa_ports::-1}}\
154+
sed -i \"s|\\(define dsa_user_ports = \\).*|\\1$dsa_ports|\" "..nftDsaGuardFileName.."\
155+
nft flush ruleset; fw4 reload\n"
156+
fs.writefile("/etc/hotplug.d/lime-config/10-anygw-mac-dsa", dsaPortsList)
157+
utils.unsafe_shell("chmod +x /etc/hotplug.d/lime-config/10-anygw-mac-dsa")
158+
159+
local bridgeFdbFixes = "#!/bin/sh\
160+
bridge fdb flush dev br-lan\
161+
bridge fdb add " .. anygw_mac .. " dev br-lan\n"
162+
fs.writefile("/etc/hotplug.d/net/10-anygw-mac-dsa", bridgeFdbFixes)
163+
end
129164
end
130165

131166
function anygw.setup_interface(ifname, args) end

packages/lime-system/files/usr/lib/lua/lime/network.lua

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -387,12 +387,6 @@ function network.configure()
387387
if protoName == "manual" then break end -- If manual is specified do not configure interface
388388
local protoModule = "lime.proto."..protoName
389389
local needsConfig = utils.isModuleAvailable(protoModule)
390-
if protoName ~= 'lan' and not flags["specific"] then
391-
--! Work around issue 1121. Do not configure any other
392-
--! protocols than lime.proto.lan on dsa devices unless there
393-
--! is a config net section for the device.
394-
needsConfig = needsConfig and not utils.is_dsa(device)
395-
end
396390
if needsConfig then
397391
for k,v in pairs(flags) do args[k] = v end
398392
local proto = require(protoModule)

packages/lime-system/files/usr/lib/lua/lime/proto/lan.lua

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,6 @@ local utils = require("lime.utils")
88

99
lan.configured = false
1010

11-
--! Find a device section in network with
12-
--! option name 'br-lan'
13-
--! option type 'bridge'
14-
local function find_br_lan(uci)
15-
local br_lan_section = nil
16-
uci:foreach("network", "device",
17-
function(s)
18-
if br_lan_section then return end
19-
local dev_type = uci:get("network", s[".name"], "type")
20-
local dev_name = uci:get("network", s[".name"], "name")
21-
if not (dev_type == 'bridge') then return end
22-
if not (dev_name == 'br-lan') then return end
23-
br_lan_section = s[".name"]
24-
end
25-
)
26-
return br_lan_section
27-
end
28-
2911
function lan.configure(args)
3012
if lan.configured then return end
3113
lan.configured = true
@@ -38,7 +20,7 @@ function lan.configure(args)
3820
uci:set("network", "lan", "netmask", ipv4:mask():string())
3921
uci:set("network", "lan", "proto", "static")
4022
uci:set("network", "lan", "mtu", "1500")
41-
local br_lan_section = find_br_lan(uci)
23+
local br_lan_section = utils.find_br_lan()
4224
if br_lan_section then uci:delete("network", br_lan_section, "ports") end
4325
uci:save("network")
4426

@@ -66,7 +48,7 @@ function lan.setup_interface(ifname, args)
6648

6749
local uci = config.get_uci_cursor()
6850
local bridgedIfs = {}
69-
local br_lan_section = find_br_lan(uci)
51+
local br_lan_section = utils.find_br_lan()
7052
if not br_lan_section then return end
7153
local oldIfs = uci:get("network", br_lan_section, "ports") or {}
7254
-- it should be a table, it was a string in old OpenWrt releases

packages/lime-system/files/usr/lib/lua/lime/utils.lua

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,4 +615,27 @@ function utils.dumptable(table, nesting)
615615
end
616616
end
617617

618+
--! Find a device section in network with i.e.
619+
--! option name 'br-lan'
620+
--! option type 'bridge'
621+
function utils.find_bridge_cfgid(bridge_name)
622+
local uci = config.get_uci_cursor()
623+
local br_section = nil
624+
uci:foreach("network", "device",
625+
function(s)
626+
if br_section then return end
627+
local dev_type = uci:get("network", s[".name"], "type")
628+
local dev_name = uci:get("network", s[".name"], "name")
629+
if not (dev_type == 'bridge') then return end
630+
if not (dev_name == bridge_name) then return end
631+
br_section = s[".name"]
632+
end
633+
)
634+
return br_section
635+
end
636+
637+
function utils.find_br_lan()
638+
return utils.find_bridge_cfgid("br-lan")
639+
end
640+
618641
return utils

0 commit comments

Comments
 (0)