Skip to content

Commit 4807d92

Browse files
committed
Adding ffhl-gluon-mesh-batman-adv-brmldproxy
This is a copy of #2995 for the main Gluon repository: -> freifunk-gluon/gluon#2995
1 parent 37e175e commit 4807d92

File tree

11 files changed

+406
-0
lines changed

11 files changed

+406
-0
lines changed

ffhl-brmldproxy/Makefile

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# SPDX-License-Identifier: MIT
2+
# Copyright (C) 2023 Linus Lüssing <[email protected]>
3+
4+
include $(TOPDIR)/rules.mk
5+
6+
PKG_NAME:=ffhl-brmldproxy
7+
PKG_RELEASE:=1
8+
9+
PKG_SOURCE_PROTO:=git
10+
PKG_SOURCE_DATE:=2025-01-06
11+
PKG_SOURCE_URL=https://github.com/T-X/brmldproxy.git
12+
PKG_SOURCE_VERSION:=2b9ec1b64f7bffbbe01271894d53f1b371f48dfa
13+
PKG_MIRROR_HASH:=3db998649cc99ec0e64d39f7b06319a1b6e2b0f50e68e3cbb8f48023c31f0e3d
14+
15+
PKG_MAINTAINER:=Linus Lüssing <[email protected]>
16+
PKG_LICENSE:=GPL-2.0-or-later
17+
PKG_LICENSE_FILES:=LICENSE
18+
19+
include $(INCLUDE_DIR)/package.mk
20+
21+
define Package/$(PKG_NAME)
22+
SECTION:=net
23+
CATEGORY:=Network
24+
TITLE:=Bridge MLD Proxy
25+
DEPENDS:=+tc
26+
endef
27+
28+
define Package/$(PKG_NAME)/description
29+
A userspace controlled MLD proxy implementation for a Linux bridge.
30+
The bridge itself will appear as a single multicast listening host
31+
to any MLD querier on a configured proxy port, acting in deputy
32+
for any other multicast listener behind adjacent bridge ports.
33+
This potentially reduces MLD report overhead.
34+
brmldproxy further allows to filter out specific multicast groups
35+
and bridge ports from its combined MLD report.
36+
endef
37+
38+
define Package/$(PKG_NAME)/install
39+
$(INSTALL_DIR) $(1)/usr/sbin
40+
$(INSTALL_BIN) $(PKG_BUILD_DIR)/brmldproxy $(1)/usr/sbin/
41+
$(CP) ./files/* $(1)/
42+
endef
43+
44+
$(eval $(call BuildPackage,$(PKG_NAME)))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#config brmldproxy 'lan'
2+
# option disabled '1'
3+
# # The bridge to apply brmldproxy to. Either the
4+
# # bridge interface name or the UCI network interface
5+
# # section name.
6+
# option bridge 'lan'
7+
# # Currently only "ipv6" is supported, optional.
8+
# option family 'ipv6'
9+
# # bridge port to proxy to
10+
# list proxiedport 'wan0'
11+
# # bridge port to proxy from
12+
# list includedport 'lan0'
13+
# # bridge port to exclude from proxying
14+
# list excludedport 'lan1'
15+
# # multicast IP address (range) to exclude from proxying
16+
# list excludefilter 'ff00::/ff0e::'
17+
# list excludefilter 'ff0e::/64'
18+
# # multicast IP address (range) to include in proxying
19+
# # (includes ff0e::123 even though ff0e::/64 was excluded above)
20+
# list includefilter 'ff0e::123'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# SPDX-License-Identifier: MIT
2+
# Copyright (C) 2023 Linus Lüssing <[email protected]>
3+
4+
. /lib/functions.sh
5+
6+
[ -z "$INTERFACE" ] && exit 0
7+
[ "$ACTION" != "ifup" ] && [ "$ACTION" != "ifdown" ] && exit 0
8+
9+
/etc/init.d/brmldproxy enabled || exit 0
10+
11+
12+
brmldproxy_handle() {
13+
local cfg="$1"
14+
local disabled
15+
local bridge
16+
17+
config_get_bool disabled "$cfg" disabled 0
18+
[ "$disabled" -gt 0 ] && return 0
19+
20+
config_get bridge "$cfg" bridge
21+
22+
[ -z "$bridge" ] && return 0
23+
[ "$bridge" != "$INTERFACE" ] && return 0
24+
25+
if [ "$ACTION" = "ifup" ]; then
26+
/etc/init.d/brmldproxy start "$cfg" || return 0
27+
else
28+
/etc/init.d/brmldproxy stop "brmldproxy.$cfg" || return 0
29+
fi
30+
31+
# success, stop
32+
return 1
33+
}
34+
35+
config_load brmldproxy
36+
37+
config_foreach brmldproxy_handle brmldproxy
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/bin/sh /etc/rc.common
2+
# SPDX-License-Identifier: MIT
3+
# Copyright (C) 2023 Linus Lüssing <[email protected]>
4+
5+
USE_PROCD=1
6+
7+
START=19
8+
STOP=90
9+
10+
brmldproxy_start() {
11+
local cfg="$1"
12+
local namespace="$2"
13+
local disabled
14+
15+
local ifname
16+
local family
17+
local bridge
18+
local includedports
19+
local excludedports
20+
local proxiedports
21+
local includefilters
22+
local excludefilters
23+
24+
config_get_bool disabled "$cfg" disabled 0
25+
[ "$disabled" -gt 0 ] && return 0
26+
27+
config_get bridge "$cfg" "bridge"
28+
config_get family "$cfg" "family"
29+
config_get includedports "$cfg" "includedport"
30+
config_get excludedports "$cfg" "excludedport"
31+
config_get proxiedports "$cfg" "proxiedport"
32+
config_get includefilters "$cfg" "includefilter"
33+
config_get excludefilters "$cfg" "excludefilter"
34+
35+
[ -z "$bridge" ] && {
36+
echo "Error: no bridge specified for $cfg" >&2
37+
return 0
38+
}
39+
40+
. /lib/functions/network.sh
41+
42+
if network_get_device ifname "$bridge" && [ -n "$ifname" ]; then
43+
bridge="$ifname"
44+
fi
45+
46+
[ -n "$excludedports" ] && excludedports=$(echo "$excludedports" | sed 's/[^ ]* */-e &/g')
47+
[ -n "$includedports" ] && includedports=$(echo "$includedports" | sed 's/[^ ]* */-i &/g')
48+
[ -n "$proxiedports" ] && proxiedports=$(echo "$proxiedports" | sed 's/[^ ]* */-p &/g')
49+
[ -n "$includefilters" ] && includefilters=$(echo "$includefilters" | sed 's/[^ ]* */-I &/g')
50+
[ -n "$excludefilters" ] && excludefilters=$(echo "$excludefilters" | sed 's/[^ ]* */-E &/g')
51+
52+
[ -z "$namespace" ] && namespace="brmldproxy"
53+
54+
procd_open_instance "$namespace.$cfg"
55+
56+
procd_set_param command /usr/sbin/brmldproxy
57+
[ "${family}" = "ipv4" ] && procd_append_param command -4
58+
[ "${family}" = "ipv6" ] && procd_append_param command -6
59+
procd_append_param command -b "$bridge"
60+
[ -n "$excludedports" ] && procd_append_param command $excludedports
61+
[ -n "$includedports" ] && procd_append_param command $includedports
62+
[ -n "$proxiedports" ] && procd_append_param command $proxiedports
63+
[ -n "$includefilters" ] && procd_append_param command $includefilters
64+
[ -n "$excludefilters" ] && procd_append_param command $excludefilters
65+
66+
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
67+
68+
procd_set_param stderr 1
69+
procd_close_instance
70+
}
71+
72+
start_service() {
73+
local cfg="$1"
74+
local namespace="$2"
75+
local instance_found=0
76+
77+
. /lib/functions/network.sh
78+
79+
# no procd boot startup, via hotplug or manual only
80+
[ $PPID -eq 1 ] && return 0
81+
82+
config_cb() {
83+
local type="$1"
84+
local name="$2"
85+
if [ "$type" = "brmldproxy" ]; then
86+
if [ -n "$cfg" -a "$cfg" = "$name" ]; then
87+
instance_found=1
88+
fi
89+
fi
90+
}
91+
92+
config_load brmldproxy
93+
94+
if [ -n "$cfg" ]; then
95+
[ "$instance_found" -gt 0 ] || return
96+
brmldproxy_start "$cfg" "$namespace"
97+
else
98+
config_foreach brmldproxy_start brmldproxy "$namespace"
99+
fi
100+
}
101+
102+
stop_service() {
103+
local cfg="$1"
104+
local namespace="$2"
105+
106+
[ -z "$namespace" ] && namespace="brmldproxy"
107+
}
108+
109+
service_triggers() {
110+
procd_add_reload_trigger brmldproxy
111+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
include $(TOPDIR)/rules.mk
2+
3+
PKG_NAME:=ffhl-gluon-mesh-batman-adv-brmldproxy
4+
5+
include $(TOPDIR)/../package/gluon.mk
6+
7+
define Package/$(PKG_NAME)
8+
TITLE:=Bridge MLD Proxy for Gluon
9+
DEPENDS:=+tc +kmod-sched +ffhl-brmldproxy +ip-bridge gluon-mesh-batman-adv
10+
endef
11+
12+
define Package/$(PKG_NAME)/description
13+
Gluon community wifi mesh firmware framework: Configuration to
14+
enable brmldproxy in Gluon with batman-adv.
15+
16+
If filter_membership_reports is false in the site.conf
17+
then no multicast listener is filtered, but the node will
18+
respond on behalf of any of its local listeners, potentially
19+
reducing duplicate MLD report overhead.
20+
21+
If filter_membership_reports is true in the site.conf
22+
or absent then brmldproxy is additionally configured to
23+
only send MLD reports for routeable IPv6 multicast addresses
24+
and only to detected IPv6 multicast routers. If no such
25+
router is detected or no local listeners for routeable
26+
IPv6 multicast addresses exists then no MLD report is send
27+
into the mesh. Which greatly reduces MLD overhead while
28+
still allowing the usage of layer 3 IPv6 multicast routers.
29+
This is the recommended setting especially in larger meshes.
30+
endef
31+
32+
define Package/$(PKG_NAME)/conffiles
33+
/etc/config/brmldproxy
34+
endef
35+
36+
$(eval $(call BuildPackageGluon,$(PKG_NAME)))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
need_boolean({'mesh', 'filter_membership_reports'}, false)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/bin/sh
2+
set -e
3+
4+
if [ "$INTERFACE" != "client" ] || [ "$ACTION" != "ifup" ]; then exit 0; fi
5+
6+
lookup_site() {
7+
local path="$1" default="$2"
8+
lua -e "print(require('gluon.site').$path('$default'))"
9+
}
10+
11+
get_gluon_all_mc_routers_mac() {
12+
local group_id="$(lua -e 'print(require("gluon.util").domain_seed_bytes("gluon-mesh-batman-adv-brmldproxy.gluon-all-mc-routers-group", 4))')"
13+
group_id="$(echo "${group_id}" | sed 's/\(..\)/\1:/g;s/:$//')"
14+
15+
echo "33:33:${group_id}"
16+
}
17+
18+
wait_for_qdisc() {
19+
for i in $(seq 1 15); do
20+
tc qdisc show dev bat0 handle "$1" | grep -q qdisc && break
21+
sleep 1
22+
done
23+
}
24+
25+
add_filter() {
26+
local parent="$1"
27+
local prio="$2"
28+
local handle="$3"
29+
local rule="$4"
30+
31+
# shellcheck disable=SC2086 # Intended splitting of $rule
32+
tc filter add dev bat0 \
33+
parent "$parent" prio "$prio" handle "$handle" protocol ipv6 \
34+
u32 $rule
35+
}
36+
37+
if [ "$(lookup_site 'mesh.filter_membership_reports' 'true')" = "false" ]; then exit 0; fi
38+
39+
wait_for_qdisc "fffe:"
40+
wait_for_qdisc "ffff:"
41+
42+
# MLD reports, mesh outgoing:
43+
# 1) DNAT to 33:33:42:4e:f3:14
44+
# 2) Change ICMPv6 type to 100, keep original type in code field
45+
# => only send report to IPv6 multicast routers
46+
MC_MAC="$(get_gluon_all_mc_routers_mac)"
47+
add_filter fffe: 4221 11: "divisor 1"
48+
add_filter fffe: 4221 11::800 "ht 11: match u8 131 0xff at 48 match u8 0 0xff at 49 action pedit ex munge eth dst set ${MC_MAC} munge offset 0x30 u16 set 0x6483 action pipe classid 1:1"
49+
add_filter fffe: 4221 11::801 "ht 11: match u8 132 0xff at 48 match u8 0 0xff at 49 action pedit ex munge eth dst set ${MC_MAC} munge offset 0x30 u16 set 0x6484 action pipe classid 1:1"
50+
add_filter fffe: 4221 11::802 "ht 11: match u8 143 0xff at 48 match u8 0 0xff at 49 action pedit ex munge eth dst set ${MC_MAC} munge offset 0x30 u16 set 0x648f action pipe classid 1:1"
51+
add_filter fffe: 4221 801::800 "match mark 0x0800000 0x0800000 link 11:"
52+
53+
# MLD reports, mesh incoming:
54+
# 1) undo DNAT
55+
# 2) Change ICMPv6 type back to MLD report
56+
add_filter ffff: 4223 2::231 "ht 2: match u8 100 0xff at 48 match u8 131 0xff at 49 action pedit ex munge eth dst set 33:33:00:00:00:01 munge offset 0x30 u16 set 0x8300 reclassify"
57+
add_filter ffff: 4223 2::232 "ht 2: match u8 100 0xff at 48 match u8 132 0xff at 49 action pedit ex munge eth dst set 33:33:00:00:00:01 munge offset 0x30 u16 set 0x8400 reclassify"
58+
add_filter ffff: 4223 2::243 "ht 2: match u8 100 0xff at 48 match u8 143 0xff at 49 action pedit ex munge eth dst set 33:33:00:00:00:16 munge offset 0x30 u16 set 0x8f00 reclassify"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 131 -j RETURN', 'nat') -- MLDv1 Report
2+
rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 132 -j RETURN', 'nat') -- MLDv1 Done
3+
rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 143 -j RETURN', 'nat') -- MLDv2 Report
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* * * * * /usr/sbin/gluon-brmldproxy-router-check
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/bin/sh
2+
3+
lookup_site() {
4+
local path="$1" default="$2"
5+
lua -e "print(require('gluon.site').$path('$default'))"
6+
}
7+
8+
lookup_prefix6() {
9+
local prefix="$(lookup_site 'prefix6')"
10+
echo "${prefix%/*}"
11+
}
12+
13+
lookup_prefix6_len() {
14+
local prefix="$(lookup_site 'prefix6')"
15+
echo "${prefix#*/}"
16+
}
17+
18+
# Generates and prints an RFC3306, section 4 style network prefix based
19+
# multicast address from the site prefix6 with a pseudo-random group-id
20+
# from the domain seed.
21+
get_gluon_all_mc_routers_ip6() {
22+
local prefix6="$(lookup_prefix6)"
23+
local prefix6_len="$(lookup_prefix6_len)"
24+
local group_id="$(lua -e 'print(require("gluon.util").domain_seed_bytes("gluon-mesh-batman-adv-brmldproxy.gluon-all-mc-routers-group", 4))')"
25+
group_id="$(echo "${group_id}" | sed 's/\(....\)/\1:/g;s/:$//')"
26+
27+
echo "ff32:$(printf "%x" "${prefix6_len}"):${prefix6}${group_id}"
28+
}
29+
30+
update_router_recv() {
31+
local action="$1"
32+
local mc_ip6="$(get_gluon_all_mc_routers_ip6)"
33+
34+
bridge mdb "$action" dev br-client port local-port grp "${mc_ip6}" permanent 2> /dev/null
35+
}
36+
37+
if [ "$(batctl mj | jsonfilter -e "@.mcast_flags.want_no_rtr_ipv6")" = "false" ]; then
38+
update_router_recv add
39+
echo 1 > /sys/class/net/brmldpb0/bridge/multicast_querier
40+
else
41+
update_router_recv del
42+
echo 0 > /sys/class/net/brmldpb0/bridge/multicast_querier
43+
fi

0 commit comments

Comments
 (0)