Skip to content

Commit 25fe483

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 19fc2d3 commit 25fe483

File tree

11 files changed

+425
-0
lines changed

11 files changed

+425
-0
lines changed

ffhl-brmldproxy/Makefile

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# SPDX-License-Identifier: MIT
2+
# Copyright (C) 2023 Linus Lüssing <linus.luessing@c0d3.blue>
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 <linus.luessing@c0d3.blue>
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)))
Lines changed: 20 additions & 0 deletions
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'
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# SPDX-License-Identifier: MIT
2+
# Copyright (C) 2023 Linus Lüssing <linus.luessing@c0d3.blue>
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
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#!/bin/sh /etc/rc.common
2+
# SPDX-License-Identifier: MIT
3+
# Copyright (C) 2023 Linus Lüssing <linus.luessing@c0d3.blue>
4+
5+
# SC1091: /lib/functions/network.sh
6+
# SC2034: /etc/rc.common imports this script and uses variables defined here
7+
# shellcheck disable=SC1091,SC2034
8+
9+
USE_PROCD=1
10+
11+
START=19
12+
STOP=90
13+
14+
brmldproxy_start() {
15+
local cfg="$1"
16+
local namespace="$2"
17+
local disabled
18+
19+
local ifname
20+
local family
21+
local bridge
22+
local includedports
23+
local excludedports
24+
local proxiedports
25+
local includefilters
26+
local excludefilters
27+
28+
config_get_bool disabled "$cfg" disabled 0
29+
[ "$disabled" -gt 0 ] && return 0
30+
31+
config_get bridge "$cfg" "bridge"
32+
config_get family "$cfg" "family"
33+
config_get includedports "$cfg" "includedport"
34+
config_get excludedports "$cfg" "excludedport"
35+
config_get proxiedports "$cfg" "proxiedport"
36+
config_get includefilters "$cfg" "includefilter"
37+
config_get excludefilters "$cfg" "excludefilter"
38+
39+
[ -z "$bridge" ] && {
40+
echo "Error: no bridge specified for $cfg" >&2
41+
return 0
42+
}
43+
44+
. /lib/functions/network.sh
45+
46+
if network_get_device ifname "$bridge" && [ -n "$ifname" ]; then
47+
bridge="$ifname"
48+
fi
49+
50+
[ -n "$excludedports" ] && excludedports=$(echo "$excludedports" | sed 's/[^ ]* */-e &/g')
51+
[ -n "$includedports" ] && includedports=$(echo "$includedports" | sed 's/[^ ]* */-i &/g')
52+
[ -n "$proxiedports" ] && proxiedports=$(echo "$proxiedports" | sed 's/[^ ]* */-p &/g')
53+
[ -n "$includefilters" ] && includefilters=$(echo "$includefilters" | sed 's/[^ ]* */-I &/g')
54+
[ -n "$excludefilters" ] && excludefilters=$(echo "$excludefilters" | sed 's/[^ ]* */-E &/g')
55+
56+
[ -z "$namespace" ] && namespace="brmldproxy"
57+
58+
procd_open_instance "$namespace.$cfg"
59+
60+
procd_set_param command /usr/sbin/brmldproxy
61+
[ "${family}" = "ipv4" ] && procd_append_param command -4
62+
[ "${family}" = "ipv6" ] && procd_append_param command -6
63+
procd_append_param command -b "$bridge"
64+
# shellcheck disable=SC2086
65+
[ -n "$excludedports" ] && procd_append_param command $excludedports
66+
# shellcheck disable=SC2086
67+
[ -n "$includedports" ] && procd_append_param command $includedports
68+
# shellcheck disable=SC2086
69+
[ -n "$proxiedports" ] && procd_append_param command $proxiedports
70+
# shellcheck disable=SC2086
71+
[ -n "$includefilters" ] && procd_append_param command $includefilters
72+
# shellcheck disable=SC2086
73+
[ -n "$excludefilters" ] && procd_append_param command $excludefilters
74+
75+
procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}"
76+
77+
procd_set_param stderr 1
78+
procd_close_instance
79+
}
80+
81+
start_service() {
82+
local cfg="$1"
83+
local namespace="$2"
84+
local instance_found=0
85+
86+
. /lib/functions/network.sh
87+
88+
# no procd boot startup, via hotplug or manual only
89+
[ $PPID -eq 1 ] && return 0
90+
91+
# shellcheck disable=SC2317
92+
config_cb() {
93+
local type="$1"
94+
local name="$2"
95+
if [ "$type" = "brmldproxy" ]; then
96+
if [ -n "$cfg" ] && [ "$cfg" = "$name" ]; then
97+
instance_found=1
98+
fi
99+
fi
100+
}
101+
102+
config_load brmldproxy
103+
104+
if [ -n "$cfg" ]; then
105+
[ "$instance_found" -gt 0 ] || return
106+
brmldproxy_start "$cfg" "$namespace"
107+
else
108+
config_foreach brmldproxy_start brmldproxy "$namespace"
109+
fi
110+
}
111+
112+
stop_service() {
113+
local cfg="$1"
114+
local namespace="$2"
115+
116+
[ -z "$namespace" ] && namespace="brmldproxy"
117+
}
118+
119+
service_triggers() {
120+
procd_add_reload_trigger brmldproxy
121+
}
Lines changed: 36 additions & 0 deletions
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)))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
need_boolean({'mesh', 'filter_membership_reports'}, false)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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
13+
14+
group_id="$(lua -e 'print(require("gluon.util").domain_seed_bytes("gluon-mesh-batman-adv-brmldproxy.gluon-all-mc-routers-group", 4))')"
15+
group_id="$(echo "${group_id}" | sed 's/\(..\)/\1:/g;s/:$//')"
16+
17+
echo "33:33:${group_id}"
18+
}
19+
20+
wait_for_qdisc() {
21+
for _ in $(seq 1 15); do
22+
tc qdisc show dev bat0 handle "$1" | grep -q qdisc && break
23+
sleep 1
24+
done
25+
}
26+
27+
add_filter() {
28+
local parent="$1"
29+
local prio="$2"
30+
local handle="$3"
31+
local rule="$4"
32+
33+
# shellcheck disable=SC2086 # Intended splitting of $rule
34+
tc filter add dev bat0 \
35+
parent "$parent" prio "$prio" handle "$handle" protocol ipv6 \
36+
u32 $rule
37+
}
38+
39+
if [ "$(lookup_site 'mesh.filter_membership_reports' 'true')" = "false" ]; then exit 0; fi
40+
41+
wait_for_qdisc "fffe:"
42+
wait_for_qdisc "ffff:"
43+
44+
# MLD reports, mesh outgoing:
45+
# 1) DNAT to 33:33:42:4e:f3:14
46+
# 2) Change ICMPv6 type to 100, keep original type in code field
47+
# => only send report to IPv6 multicast routers
48+
MC_MAC="$(get_gluon_all_mc_routers_mac)"
49+
add_filter fffe: 4221 11: "divisor 1"
50+
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"
51+
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"
52+
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"
53+
add_filter fffe: 4221 801::800 "match mark 0x0800000 0x0800000 link 11:"
54+
55+
# MLD reports, mesh incoming:
56+
# 1) undo DNAT
57+
# 2) Change ICMPv6 type back to MLD report
58+
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"
59+
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"
60+
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"
Lines changed: 3 additions & 0 deletions
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
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* * * * * /usr/sbin/gluon-brmldproxy-router-check
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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
10+
11+
prefix="$(lookup_site 'prefix6')"
12+
echo "${prefix%/*}"
13+
}
14+
15+
lookup_prefix6_len() {
16+
local prefix
17+
18+
prefix="$(lookup_site 'prefix6')"
19+
echo "${prefix#*/}"
20+
}
21+
22+
# Generates and prints an RFC3306, section 4 style network prefix based
23+
# multicast address from the site prefix6 with a pseudo-random group-id
24+
# from the domain seed.
25+
get_gluon_all_mc_routers_ip6() {
26+
local prefix6 prefix6_len group_id
27+
28+
prefix6="$(lookup_prefix6)"
29+
prefix6_len="$(lookup_prefix6_len)"
30+
group_id="$(lua -e 'print(require("gluon.util").domain_seed_bytes("gluon-mesh-batman-adv-brmldproxy.gluon-all-mc-routers-group", 4))')"
31+
group_id="$(echo "${group_id}" | sed 's/\(....\)/\1:/g;s/:$//')"
32+
33+
echo "ff32:$(printf "%x" "${prefix6_len}"):${prefix6}${group_id}"
34+
}
35+
36+
update_router_recv() {
37+
local action="$1"
38+
local mc_ip6
39+
40+
mc_ip6="$(get_gluon_all_mc_routers_ip6)"
41+
bridge mdb "$action" dev br-client port local-port grp "${mc_ip6}" permanent 2> /dev/null
42+
}
43+
44+
if [ "$(batctl mj | jsonfilter -e "@.mcast_flags.want_no_rtr_ipv6")" = "false" ]; then
45+
update_router_recv add
46+
echo 1 > /sys/class/net/brmldpb0/bridge/multicast_querier
47+
else
48+
update_router_recv del
49+
echo 0 > /sys/class/net/brmldpb0/bridge/multicast_querier
50+
fi

0 commit comments

Comments
 (0)