Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167145967
D58747.id183733.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D58747.id183733.diff
View Options
diff --git a/share/man/man4/bridge.4 b/share/man/man4/bridge.4
--- a/share/man/man4/bridge.4
+++ b/share/man/man4/bridge.4
@@ -615,6 +615,19 @@
listener state is known, for non-IP multicast, and for exempt link-local
control traffic.
.Pp
+The link-local
+.Li 224.0.0.0/24
+block is never snooped and never pruned, as required by RFC 4541.
+Membership reports naming a group in that block are parsed but create no
+listener state, and traffic addressed to it is always forwarded to every
+port.
+Without this exemption a single reporting host could cause link-local
+control protocols, such as mDNS on
+.Li 224.0.0.251
+or OSPF on
+.Li 224.0.0.5 ,
+to be pruned away from ports whose own membership reports were suppressed.
+.Pp
IGMPv3 group records are reduced conservatively to any-source
.Pq (*,G)
listener state.
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1409,6 +1409,25 @@
return (IN_MULTICAST(ntohl(group.s_addr)));
}
+/*
+ * Whether listener state may be learned for a group. RFC 4541 section
+ * 2.1.1 requires that traffic addressed to the link-local 224.0.0.0/24
+ * block always be forwarded on all ports, so membership in those groups is
+ * never recorded. Learning them would let one reporting host cause the
+ * bridge to prune link-local control protocols -- mDNS on 224.0.0.251, OSPF
+ * on 224.0.0.5 and 224.0.0.6 -- away from ports whose own reports were
+ * suppressed by IGMP report suppression. This is reachable in practice:
+ * FreeBSD reports these groups by default (net.inet.igmp.sendlocal=1).
+ *
+ * A report for such a group is well-formed, just not actionable, so callers
+ * treat it as accepted-with-no-effect rather than as a parse rejection.
+ */
+static bool
+bridge_mdb_igmp_group_snoopable(struct in_addr group)
+{
+ return (!IN_LOCAL_GROUP(ntohl(group.s_addr)));
+}
+
static void
bridge_mdb_input(struct bridge_softc *sc, struct bridge_iflist *bif,
struct mbuf *m)
@@ -1499,6 +1518,8 @@
!bridge_mdb_igmp_group_valid(igmp.igmp_group) ||
!in_hosteq(igmp.igmp_group, ip.ip_dst))
return (EINVAL);
+ if (!bridge_mdb_igmp_group_snoopable(igmp.igmp_group))
+ return (0);
return (bridge_mdb_add_member(sc, AF_INET, &igmp.igmp_group,
vlan, bif, BRIDGE_MDB_IGMP_MAXAGE));
case IGMP_HOST_LEAVE_MESSAGE:
@@ -1549,7 +1570,8 @@
return (EINVAL);
if (pass == 1 &&
- bridge_mdb_igmp_group_valid(rec.ig_group)) {
+ bridge_mdb_igmp_group_valid(rec.ig_group) &&
+ bridge_mdb_igmp_group_snoopable(rec.ig_group)) {
/*
* Reduce each record conservatively to ASM
* (*,G) listener state. Any record that
@@ -1740,6 +1762,16 @@
if (!IN_MULTICAST(ntohl(ip.ip_dst.s_addr)))
return (false);
+ /*
+ * Never prune the link-local 224.0.0.0/24 block (RFC 4541 2.1.1):
+ * flood it exactly as the bridge did before snooping existed.
+ * Learning already refuses these groups, but checking on the
+ * forwarding side too means listener state recorded by an earlier
+ * kernel cannot prune control traffic after an upgrade.
+ */
+ if (IN_LOCAL_GROUP(ntohl(ip.ip_dst.s_addr)))
+ return (false);
+
if (bridge_mdb_key_init(&key, AF_INET, &ip.ip_dst, vlan) != 0)
return (false);
diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh
--- a/tests/sys/net/if_bridge_test.sh
+++ b/tests/sys/net/if_bridge_test.sh
@@ -1386,6 +1386,67 @@
vnet_cleanup
}
+atf_test_case "mdb_link_local_exempt" "cleanup"
+mdb_link_local_exempt_head()
+{
+ atf_set descr 'bridge never snoops or prunes the link-local 224.0.0.0/24 block'
+ atf_set require.user root
+ atf_set require.progs "cc tcpdump timeout"
+}
+
+mdb_link_local_exempt_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ bridge_mdb_vnet_topology_create
+
+ atf_check -s exit:0 -o ignore \
+ sysctl net.link.bridge.igmp_snooping=1
+
+ bridge_mdb_compile_join_helper
+
+ # 224.0.0.251 (mDNS) is inside the link-local block. FreeBSD reports
+ # it by default (net.inet.igmp.sendlocal=1), so the bridge does see a
+ # membership report for it -- but RFC 4541 2.1.1 requires that this
+ # traffic still reach every port, so no listener state may be created.
+ jexec mdbl /tmp/mcast_join_bridge_test 224.0.0.251 192.0.2.2 30 &
+ joiner_pid=$!
+ sleep 2
+
+ atf_check -o match:'^0$' \
+ sysctl -n net.link.bridge.mdb_entries
+
+ jexec mdbs route add -net 224.0.0.0/4 \
+ -interface ${mdb_sender_epair}b >/dev/null 2>&1 || true
+
+ capture="${PWD}/mdb_link_local.tcpdump"
+ rm -f "${capture}"
+
+ # The uninterested port must still receive it.
+ jexec mdbi sh -c "timeout 4 tcpdump --immediate-mode -n \
+ -i ${mdb_idle_epair}b -c 1 \
+ 'icmp and dst host 224.0.0.251' > ${capture} 2>&1" &
+ tcpdump_pid=$!
+ sleep 1
+
+ jexec mdbs ping -c 3 -t 1 224.0.0.251 >/dev/null 2>&1 || true
+ wait ${tcpdump_pid}
+ idle_status=$?
+
+ kill ${joiner_pid} 2>/dev/null || true
+
+ if [ ${idle_status} -ne 0 ]; then
+ atf_fail "link-local 224.0.0.251 was pruned from an uninterested port"
+ fi
+}
+
+mdb_link_local_exempt_cleanup()
+{
+ rm -f /tmp/mcast_join_bridge_test /tmp/mcast_join_bridge_test.c
+ vnet_cleanup
+}
+
atf_test_case "member_ifaddrs_enabled" "cleanup"
member_ifaddrs_enabled_head()
{
@@ -2075,6 +2136,7 @@
atf_add_test_case "mdb_counters"
atf_add_test_case "mdb_router_forward"
atf_add_test_case "mdb_igmpv3_source_join"
+ atf_add_test_case "mdb_link_local_exempt"
atf_add_test_case "member_ifaddrs_enabled"
atf_add_test_case "member_ifaddrs_disabled"
atf_add_test_case "member_ifaddrs_vlan"
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Aug 20, 11:44 AM (4 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36945646
Default Alt Text
D58747.id183733.diff (5 KB)
Attached To
Mode
D58747: if_bridge: exempt 224.0.0.0/24 from IGMP snooping
Attached
Detach File
Event Timeline
Log In to Comment