13f189349SFlorian Westphal#!/bin/bash
23f189349SFlorian Westphal# SPDX-License-Identifier: GPL-2.0
33f189349SFlorian Westphal#
41286e106SFlorian Westphal# Test for legacy br_netfilter module combined with connection tracking,
51286e106SFlorian Westphal# a combination that doesn't really work.
61286e106SFlorian Westphal# Multicast/broadcast packets race for hash table insertion.
73f189349SFlorian Westphal
83f189349SFlorian Westphal#           eth0    br0     eth0
93f189349SFlorian Westphal# setup is: ns1 <->,ns0 <-> ns3
103f189349SFlorian Westphal#           ns2 <-'    `'-> ns4
113f189349SFlorian Westphal
121286e106SFlorian Westphalsource lib.sh
133f189349SFlorian Westphal
1410e2ed3fSFlorian Westphalchecktool "nft --version" "run test without nft tool"
153f189349SFlorian Westphal
163f189349SFlorian Westphalcleanup() {
171286e106SFlorian Westphal	cleanup_all_ns
183f189349SFlorian Westphal}
193f189349SFlorian Westphal
203f189349SFlorian Westphaltrap cleanup EXIT
213f189349SFlorian Westphal
221286e106SFlorian Westphalsetup_ns ns0 ns1 ns2 ns3 ns4
231286e106SFlorian Westphal
241286e106SFlorian Westphalret=0
251286e106SFlorian Westphal
263f189349SFlorian Westphaldo_ping()
273f189349SFlorian Westphal{
283f189349SFlorian Westphal	fromns="$1"
293f189349SFlorian Westphal	dstip="$2"
303f189349SFlorian Westphal
311286e106SFlorian Westphal	if ! ip netns exec "$fromns" ping -c 1 -q "$dstip" > /dev/null; then
323f189349SFlorian Westphal		echo "ERROR: ping from $fromns to $dstip"
331286e106SFlorian Westphal		ip netns exec "$ns0" nft list ruleset
343f189349SFlorian Westphal		ret=1
353f189349SFlorian Westphal	fi
363f189349SFlorian Westphal}
373f189349SFlorian Westphal
383f189349SFlorian Westphalbcast_ping()
393f189349SFlorian Westphal{
403f189349SFlorian Westphal	fromns="$1"
413f189349SFlorian Westphal	dstip="$2"
423f189349SFlorian Westphal
43*f581bcf0SFlorian Westphal	local packets=500
44*f581bcf0SFlorian Westphal
45*f581bcf0SFlorian Westphal	[ "$KSFT_MACHINE_SLOW" = yes ] && packets=100
46*f581bcf0SFlorian Westphal
47*f581bcf0SFlorian Westphal	for i in $(seq 1 $packets); do
481286e106SFlorian Westphal		if ! ip netns exec "$fromns" ping -q -f -b -c 1 -q "$dstip" > /dev/null 2>&1; then
493f189349SFlorian Westphal			echo "ERROR: ping -b from $fromns to $dstip"
501286e106SFlorian Westphal			ip netns exec "$ns0" nft list ruleset
511286e106SFlorian Westphal			ret=1
521286e106SFlorian Westphal			break
533f189349SFlorian Westphal		fi
543f189349SFlorian Westphal	done
553f189349SFlorian Westphal}
563f189349SFlorian Westphal
571286e106SFlorian Westphalip netns exec "$ns0" sysctl -q net.ipv4.conf.all.rp_filter=0
581286e106SFlorian Westphalip netns exec "$ns0" sysctl -q net.ipv4.conf.default.rp_filter=0
591286e106SFlorian Westphal
601286e106SFlorian Westphalif ! ip link add veth1 netns "$ns0" type veth peer name eth0 netns "$ns1"; then
613f189349SFlorian Westphal	echo "SKIP: Can't create veth device"
623f189349SFlorian Westphal	exit $ksft_skip
633f189349SFlorian Westphalfi
643f189349SFlorian Westphal
651286e106SFlorian Westphalip link add veth2 netns "$ns0" type veth peer name eth0 netns "$ns2"
661286e106SFlorian Westphalip link add veth3 netns "$ns0" type veth peer name eth0 netns "$ns3"
671286e106SFlorian Westphalip link add veth4 netns "$ns0" type veth peer name eth0 netns "$ns4"
683f189349SFlorian Westphal
693f189349SFlorian Westphalfor i in $(seq 1 4); do
701286e106SFlorian Westphal  ip -net "$ns0" link set "veth$i" up
713f189349SFlorian Westphaldone
723f189349SFlorian Westphal
731286e106SFlorian Westphalif ! ip -net "$ns0" link add br0 type bridge stp_state 0 forward_delay 0 nf_call_iptables 1 nf_call_ip6tables 1 nf_call_arptables 1; then
743f189349SFlorian Westphal	echo "SKIP: Can't create bridge br0"
753f189349SFlorian Westphal	exit $ksft_skip
763f189349SFlorian Westphalfi
773f189349SFlorian Westphal
783f189349SFlorian Westphal# make veth0,1,2 part of bridge.
793f189349SFlorian Westphalfor i in $(seq 1 3); do
801286e106SFlorian Westphal  ip -net "$ns0" link set "veth$i" master br0
813f189349SFlorian Westphaldone
823f189349SFlorian Westphal
833f189349SFlorian Westphal# add a macvlan on top of the bridge.
843f189349SFlorian WestphalMACVLAN_ADDR=ba:f3:13:37:42:23
851286e106SFlorian Westphalip -net "$ns0" link add link br0 name macvlan0 type macvlan mode private
861286e106SFlorian Westphalip -net "$ns0" link set macvlan0 address ${MACVLAN_ADDR}
871286e106SFlorian Westphalip -net "$ns0" link set macvlan0 up
881286e106SFlorian Westphalip -net "$ns0" addr add 10.23.0.1/24 dev macvlan0
893f189349SFlorian Westphal
903f189349SFlorian Westphal# add a macvlan on top of veth4.
913f189349SFlorian WestphalMACVLAN_ADDR=ba:f3:13:37:42:24
921286e106SFlorian Westphalip -net "$ns0" link add link veth4 name macvlan4 type macvlan mode passthru
931286e106SFlorian Westphalip -net "$ns0" link set macvlan4 address ${MACVLAN_ADDR}
941286e106SFlorian Westphalip -net "$ns0" link set macvlan4 up
953f189349SFlorian Westphal
963f189349SFlorian Westphal# make the macvlan part of the bridge.
973f189349SFlorian Westphal# veth4 is not a bridge port, only the macvlan on top of it.
981286e106SFlorian Westphalip -net "$ns0" link set macvlan4 master br0
993f189349SFlorian Westphal
1001286e106SFlorian Westphalip -net "$ns0" link set br0 up
1011286e106SFlorian Westphalip -net "$ns0" addr add 10.0.0.1/24 dev br0
1021286e106SFlorian Westphal
1031286e106SFlorian Westphalmodprobe -q br_netfilter
1041286e106SFlorian Westphalif ! ip netns exec "$ns0" sysctl -q net.bridge.bridge-nf-call-iptables=1; then
1053f189349SFlorian Westphal	echo "SKIP: bridge netfilter not available"
1063f189349SFlorian Westphal	ret=$ksft_skip
1073f189349SFlorian Westphalfi
1083f189349SFlorian Westphal
1093f189349SFlorian Westphal# for testing, so namespaces will reply to ping -b probes.
1101286e106SFlorian Westphalip netns exec "$ns0" sysctl -q net.ipv4.icmp_echo_ignore_broadcasts=0
1113f189349SFlorian Westphal
1123f189349SFlorian Westphal# enable conntrack in ns0 and drop broadcast packets in forward to
1133f189349SFlorian Westphal# avoid them from getting confirmed in the postrouting hook before
1143f189349SFlorian Westphal# the cloned skb is passed up the stack.
1151286e106SFlorian Westphalip netns exec "$ns0" nft -f - <<EOF
1163f189349SFlorian Westphaltable ip filter {
1173f189349SFlorian Westphal	chain input {
1183f189349SFlorian Westphal		type filter hook input priority 1; policy accept
1193f189349SFlorian Westphal		iifname br0 counter
1203f189349SFlorian Westphal		ct state new accept
1213f189349SFlorian Westphal	}
1223f189349SFlorian Westphal}
1233f189349SFlorian Westphal
1243f189349SFlorian Westphaltable bridge filter {
1253f189349SFlorian Westphal	chain forward {
1263f189349SFlorian Westphal		type filter hook forward priority 0; policy accept
1273f189349SFlorian Westphal		meta pkttype broadcast ip protocol icmp counter drop
1283f189349SFlorian Westphal	}
1293f189349SFlorian Westphal}
1303f189349SFlorian WestphalEOF
131bb0ee78fSFlorian Westphalif [ "$?" -ne 0 ];then
132bb0ee78fSFlorian Westphal	echo "SKIP: could not add nftables ruleset"
133bb0ee78fSFlorian Westphal	exit $ksft_skip
134bb0ee78fSFlorian Westphalfi
1353f189349SFlorian Westphal
1363f189349SFlorian Westphal# place 1, 2 & 3 in same subnet, connected via ns0:br0.
1373f189349SFlorian Westphal# ns4 is placed in same subnet as well, but its not
1383f189349SFlorian Westphal# part of the bridge: the corresponding veth4 is not
1393f189349SFlorian Westphal# part of the bridge, only its macvlan interface.
1403f189349SFlorian Westphalfor i in $(seq 1 4); do
1411286e106SFlorian Westphal  eval ip -net \$ns"$i" link set eth0 up
1423f189349SFlorian Westphaldone
1433f189349SFlorian Westphalfor i in $(seq 1 2); do
1441286e106SFlorian Westphal  eval ip -net \$ns"$i" addr add "10.0.0.1$i/24" dev eth0
1453f189349SFlorian Westphaldone
1463f189349SFlorian Westphal
1471286e106SFlorian Westphalip -net "$ns3" addr add 10.23.0.13/24 dev eth0
1481286e106SFlorian Westphalip -net "$ns4" addr add 10.23.0.14/24 dev eth0
1493f189349SFlorian Westphal
1503f189349SFlorian Westphal# test basic connectivity
1511286e106SFlorian Westphaldo_ping "$ns1" 10.0.0.12
1521286e106SFlorian Westphaldo_ping "$ns3" 10.23.0.1
1531286e106SFlorian Westphaldo_ping "$ns4" 10.23.0.1
1543f189349SFlorian Westphal
1551286e106SFlorian Westphalbcast_ping "$ns1" 10.0.0.255
1563f189349SFlorian Westphal
1573f189349SFlorian Westphal# This should deliver broadcast to macvlan0, which is on top of ns0:br0.
1581286e106SFlorian Westphalbcast_ping "$ns3" 10.23.0.255
1593f189349SFlorian Westphal
1603f189349SFlorian Westphal# same, this time via veth4:macvlan4.
1611286e106SFlorian Westphalbcast_ping "$ns4" 10.23.0.255
1623f189349SFlorian Westphal
1633f189349SFlorian Westphalread t < /proc/sys/kernel/tainted
1641286e106SFlorian Westphalif [ "$t" -eq 0 ];then
1653f189349SFlorian Westphal	echo PASS: kernel not tainted
1663f189349SFlorian Westphalelse
1673f189349SFlorian Westphal	echo ERROR: kernel is tainted
1683f189349SFlorian Westphal	ret=1
1693f189349SFlorian Westphalfi
1703f189349SFlorian Westphal
1713f189349SFlorian Westphalexit $ret
172