Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gluon-mesh-batman-adv-brmldproxy: add package #2995

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Several Freifunk communities in Germany use Gluon as the foundation of their Fre
package/gluon-hoodselector
package/gluon-logging
package/gluon-mesh-batman-adv
package/gluon-mesh-batman-adv-brmldproxy
package/gluon-mesh-wireless-sae
package/gluon-radv-filterd
package/gluon-scheduled-domain-switch
Expand Down
29 changes: 29 additions & 0 deletions docs/package/gluon-mesh-batman-adv-brmldproxy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
gluon-mesh-batman-adv-brmldproxy
================================

The *gluon-mesh-batman-adv-brmldproxy* package adds configuration
to enable `brmldproxy`_ in Gluon with batman-adv.

If `filter_membership_reports` :ref:`site.conf <user-site-mesh>` is false in the site.conf
then no multicast listener is filtered, but the node will
respond on behalf of any of its local listeners, potentially
reducing duplicate MLD report overhead.

If `filter_membership_reports` :ref:`site.conf <user-site-mesh>` is true in the site.conf
or absent then brmldproxy is additionally configured to
only send MLD reports for routeable IPv6 multicast addresses
and only to detected IPv6 multicast routers. If no such
router is detected or no local listeners for routeable
IPv6 multicast addresses exists then no MLD report is send
into the mesh. Which greatly reduces MLD overhead while
still allowing the usage of layer 3 IPv6 multicast routers.
This is the recommended setting especially in larger meshes.

----

Notable layer 3 IPv6 multicast router implementations:

* pim6sd: https://github.com/troglobit/pim6sd
* HowTo at DN42: https://dn42.dev/howto/IPv6-Multicast

.. _brmldproxy: https://github.com/T-X/brmldproxy
19 changes: 16 additions & 3 deletions docs/package/gluon-mesh-batman-adv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,16 @@ batman-adv. Which even with IGMP/MLD filtered, will have full multicast
membership knowledge through its own propagation through the batman-adv
translation table.

Advantages are:
**Advantages:**

* Reduced overhead through reactive batman-adv multicast TT vs.
periodic IGMP/MLD messages in the mesh
* Increased IGMP/MLD snooping robustness via local, per node
IGMP/MLD queriers
* DDoS vector mitigation

**Limitations:**

**Note:** For nodes running an operating system other than Gluon, but a bridge
interface on top of the batman-adv interface, you will need to set the
multicast router flag there manually:
Expand All @@ -159,12 +161,23 @@ assume that there is no multicast router behind this port, meaning
to only forward multicast to this port if an according multicast
listener on this link was detected.

Further limitations: IGMP/MLD snooping switches (e.g. "enterprise switches")
IGMP/MLD snooping switches (e.g. "enterprise switches")
behind the client network of a node (LAN ports) are unsupported. It is
advised to disable IGMP/MLD snooping on those enterprise switches for now
or to at least manually mark the port to the Gluon router as a
"multicast router port".

Alternatively, the filtering of IGMP/MLD reports can be disabled via
Also IPv4/IPv6 multicast routers are unsupported, unless the
:doc:`gluon-mesh-batman-adv-brmldproxy` package is installed.

**Configuration options:**

The filtering of IGMP/MLD reports can be disabled via
the site.conf (which is not recommended in large meshes though).
See :ref:`site.conf mesh section <user-site-mesh>` for details.

Another alternative is to install the :doc:`gluon-mesh-batman-adv-brmldproxy`
package. Which allows proxied MLD reports for listeners of
routable IPv6 multicast addresses, while keeping link-local
IPv6 multicast addresses filtered. This allows using IPv6
multicast routers.
36 changes: 36 additions & 0 deletions package/gluon-mesh-batman-adv-brmldproxy/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=gluon-mesh-batman-adv-brmldproxy

include ../gluon.mk

define Package/gluon-mesh-batman-adv-brmldproxy
TITLE:=Bridge MLD Proxy for Gluon
DEPENDS:=+tc +kmod-sched +brmldproxy +ip-bridge gluon-mesh-batman-adv
endef

define Package/gluon-mesh-batman-adv-brmldproxy/description
Gluon community wifi mesh firmware framework: Configuration to
enable brmldproxy in Gluon with batman-adv.

If filter_membership_reports is false in the site.conf
then no multicast listener is filtered, but the node will
respond on behalf of any of its local listeners, potentially
reducing duplicate MLD report overhead.

If filter_membership_reports is true in the site.conf
or absent then brmldproxy is additionally configured to
only send MLD reports for routeable IPv6 multicast addresses
and only to detected IPv6 multicast routers. If no such
router is detected or no local listeners for routeable
IPv6 multicast addresses exists then no MLD report is send
into the mesh. Which greatly reduces MLD overhead while
still allowing the usage of layer 3 IPv6 multicast routers.
This is the recommended setting especially in larger meshes.
endef

define Package/gluon-mesh-batman-adv-brmldproxy/conffiles
/etc/config/brmldproxy
endef

$(eval $(call BuildPackageGluon,gluon-mesh-batman-adv-brmldproxy))
1 change: 1 addition & 0 deletions package/gluon-mesh-batman-adv-brmldproxy/check_site.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
need_boolean({'mesh', 'filter_membership_reports'}, false)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
set -e

{ [ "$INTERFACE" != "client" ] || [ "$ACTION" != "ifup" ]; } && exit 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{ [ "$INTERFACE" != "client" ] || [ "$ACTION" != "ifup" ]; } && exit 0
if [ "$INTERFACE" != "client" ] || [ "$ACTION" != "ifup" ]; then exit 0; fi


lookup_site() {
local path="$1" default="$2"
lua -e "print(require('gluon.site').$path('$default'))"
}

[ "$(lookup_site 'mesh.filter_membership_reports' 'true')" = "false" ] && exit 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[ "$(lookup_site 'mesh.filter_membership_reports' 'true')" = "false" ] && exit 0
if [ "$(lookup_site 'mesh.filter_membership_reports' 'true')" = "false" ]; then exit 0; fi


wait_for_qdisc() {
for i in $(seq 1 15); do
tc qdisc show dev bat0 handle "$1" | grep -q qdisc && break
sleep 1
done
}

wait_for_qdisc "fffe:"
wait_for_qdisc "ffff:"

# MLD reports, mesh outgoing:
# 1) DNAT to 33:33:42:4e:f3:14
# 2) Change ICMPv6 type to 100, keep original type in code field
# => only send report to IPv6 multicast routers
tc filter add dev bat0 parent fffe: protocol ipv6 prio 4221 handle 11: u32 divisor 1
tc filter add dev bat0 parent fffe: protocol ipv6 prio 4221 u32 ht 11: match u8 131 0xff at 48 match u8 0 0xff at 49 action pedit ex munge eth dst set 33:33:42:4e:f3:14 munge offset 0x30 u16 set 0x6483 action pipe classid 1:1
tc filter add dev bat0 parent fffe: protocol ipv6 prio 4221 u32 ht 11: match u8 132 0xff at 48 match u8 0 0xff at 49 action pedit ex munge eth dst set 33:33:42:4e:f3:14 munge offset 0x30 u16 set 0x6484 action pipe classid 1:1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe some helpers could be added for the repetitive parts of these commands?

tc filter add dev bat0 parent fffe: protocol ipv6 prio 4221 u32 ht 11: match u8 143 0xff at 48 match u8 0 0xff at 49 action pedit ex munge eth dst set 33:33:42:4e:f3:14 munge offset 0x30 u16 set 0x648f action pipe classid 1:1
tc filter add dev bat0 parent fffe: protocol ipv6 prio 4221 u32 match mark 0x0800000 0x0800000 link 11:

# MLD reports, mesh incoming:
# 1) undo DNAT
# 2) Change ICMPv6 type back to MLD report
tc filter add dev bat0 parent ffff: handle 2::231 protocol ipv6 prio 4223 u32 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
tc filter add dev bat0 parent ffff: handle 2::232 protocol ipv6 prio 4223 u32 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
tc filter add dev bat0 parent ffff: handle 2::243 protocol ipv6 prio 4223 u32 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 number Diff line number Diff line change
@@ -0,0 +1,3 @@
rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 131 -j RETURN', 'nat') -- MLDv1 Report
rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 132 -j RETURN', 'nat') -- MLDv1 Done
rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 143 -j RETURN', 'nat') -- MLDv2 Report
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* * * * * /usr/sbin/gluon-brmldproxy-router-check
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh

BRMLDPROXY_RTR_GROUP="ff12::424e:f314"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment regarding the source of this group address?

Using a group prefix derived from prefix6 (as specified in some RFC) might also be a an alternative.


update_router_recv() {
bridge mdb "$1" dev br-client port local-port grp "$BRMLDPROXY_RTR_GROUP" permanent 2> /dev/null
}

if batctl mcast_flags | grep -q "^Multicast flags (own flags: \[.*R6\.*\]"; then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if batctl mcast_flags | grep -q "^Multicast flags (own flags: \[.*R6\.*\]"; then
if batctl mcast_flags | grep -q '^Multicast flags (own flags: \[.*R6\.*\]'; then

Also, maybe the JSON output should be used here?

update_router_recv add
else
update_router_recv del
fi
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/lua

local site = require 'gluon.site'
local uci = require('simple-uci').cursor()

local excludefilters = { 'ff00::/ff0e::' }
if site.mesh.filter_membership_reports(true) then
table.insert(excludefilters, 'ff02::/ff0f::')
table.insert(excludefilters, 'ff05::2:1001')
end

uci:delete('brmldproxy', 'client')
uci:section('brmldproxy', 'brmldproxy', 'client', {
disabled = 0,
bridge = 'client',
family = 'ipv6',
proxiedport = { 'bat0' },
excludedport = { 'local-port' },
excludefilter = excludefilters,
})
uci:save('brmldproxy')

-- Allow incoming MLD on brmldp0/1/... devices
uci:section('firewall', 'rule', 'brmldproxy_mld_in', {
name = 'brmldproxy_mld_in',
device = 'brmldp+',
direction = 'in',
src = '*',
src_ip = 'fe80::/10',
target = 'ACCEPT',
family = 'ipv6',
proto = 'icmp',
icmp_type = { '130/0', '131/0', '132/0', '143/0', },
})

-- Fix default mark of MLDv2 reports (bug in the Linux IPv6 stack)
-- See: https://marc.info/?l=netfilter&m=168959399302909
-- Subject: skb->mark not cleared for MLDv2 Reports? (skb->mark == 212 / 0xd4)
uci:section('firewall', 'rule', 'brmldproxy_mldv2_mark_fixup', {
name = 'brmldproxy_mldv2_mark_fixup',
device = 'brmldp+',
direction = 'out',
dest = '*',
src_ip = 'fe80::/10',
target = 'MARK',
set_mark = '0x0',
family = 'ipv6',
proto = 'icmp',
icmp_type = { '143/0', },
})

uci:save('firewall')