xref: /linux/tools/testing/selftests/net/netfilter/br_netfilter.sh (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Test for legacy br_netfilter module combined with connection tracking,
5# a combination that doesn't really work.
6# Multicast/broadcast packets race for hash table insertion.
7
8#           eth0    br0     eth0
9# setup is: ns1 <->,ns0 <-> ns3
10#           ns2 <-'    `'-> ns4
11
12source lib.sh
13
14checktool "nft --version" "run test without nft tool"
15
16read t < /proc/sys/kernel/tainted
17if [ "$t" -ne 0 ];then
18	echo SKIP: kernel is tainted
19	exit $ksft_skip
20fi
21
22cleanup() {
23	cleanup_all_ns
24}
25
26trap cleanup EXIT
27
28setup_ns ns0 ns1 ns2 ns3 ns4
29
30ret=0
31
32do_ping()
33{
34	fromns="$1"
35	dstip="$2"
36
37	if ! ip netns exec "$fromns" ping -c 1 -q "$dstip" > /dev/null; then
38		echo "ERROR: ping from $fromns to $dstip"
39		ip netns exec "$ns0" nft list ruleset
40		ret=1
41	fi
42}
43
44bcast_ping()
45{
46	fromns="$1"
47	dstip="$2"
48
49	local packets=500
50
51	[ "$KSFT_MACHINE_SLOW" = yes ] && packets=100
52
53	for i in $(seq 1 $packets); do
54		if ! ip netns exec "$fromns" ping -q -f -b -c 1 -q "$dstip" > /dev/null 2>&1; then
55			echo "ERROR: ping -b from $fromns to $dstip"
56			ip netns exec "$ns0" nft list ruleset
57			ret=1
58			break
59		fi
60	done
61}
62
63if ! ip link add veth1 netns "$ns0" type veth peer name eth0 netns "$ns1"; then
64	echo "SKIP: Can't create veth device"
65	exit $ksft_skip
66fi
67
68ip link add veth2 netns "$ns0" type veth peer name eth0 netns "$ns2"
69ip link add veth3 netns "$ns0" type veth peer name eth0 netns "$ns3"
70ip link add veth4 netns "$ns0" type veth peer name eth0 netns "$ns4"
71
72for i in $(seq 1 4); do
73  ip -net "$ns0" link set "veth$i" up
74done
75
76if ! 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
77	echo "SKIP: Can't create bridge br0"
78	exit $ksft_skip
79fi
80
81# make veth0,1,2 part of bridge.
82for i in $(seq 1 3); do
83  ip -net "$ns0" link set "veth$i" master br0
84done
85
86# add a macvlan on top of the bridge.
87MACVLAN_ADDR=ba:f3:13:37:42:23
88ip -net "$ns0" link add link br0 name macvlan0 type macvlan mode private
89ip -net "$ns0" link set macvlan0 address ${MACVLAN_ADDR}
90ip -net "$ns0" link set macvlan0 up
91ip -net "$ns0" addr add 10.23.0.1/24 dev macvlan0
92
93# add a macvlan on top of veth4.
94MACVLAN_ADDR=ba:f3:13:37:42:24
95ip -net "$ns0" link add link veth4 name macvlan4 type macvlan mode passthru
96ip -net "$ns0" link set macvlan4 address ${MACVLAN_ADDR}
97ip -net "$ns0" link set macvlan4 up
98
99# make the macvlan part of the bridge.
100# veth4 is not a bridge port, only the macvlan on top of it.
101ip -net "$ns0" link set macvlan4 master br0
102
103ip -net "$ns0" link set br0 up
104ip -net "$ns0" addr add 10.0.0.1/24 dev br0
105
106modprobe -q br_netfilter
107if ! ip netns exec "$ns0" sysctl -q net.bridge.bridge-nf-call-iptables=1; then
108	echo "SKIP: bridge netfilter not available"
109	ret=$ksft_skip
110fi
111
112# for testing, so namespaces will reply to ping -b probes.
113ip netns exec "$ns0" sysctl -q net.ipv4.icmp_echo_ignore_broadcasts=0
114
115# enable conntrack in ns0 and drop broadcast packets in forward to
116# avoid them from getting confirmed in the postrouting hook before
117# the cloned skb is passed up the stack.
118ip netns exec "$ns0" nft -f - <<EOF
119table ip filter {
120	chain input {
121		type filter hook input priority 1; policy accept
122		iifname br0 counter
123		ct state new accept
124	}
125}
126
127table bridge filter {
128	chain forward {
129		type filter hook forward priority 0; policy accept
130		meta pkttype broadcast ip protocol icmp counter drop
131	}
132}
133EOF
134if [ "$?" -ne 0 ];then
135	echo "SKIP: could not add nftables ruleset"
136	exit $ksft_skip
137fi
138
139# place 1, 2 & 3 in same subnet, connected via ns0:br0.
140# ns4 is placed in same subnet as well, but its not
141# part of the bridge: the corresponding veth4 is not
142# part of the bridge, only its macvlan interface.
143for i in $(seq 1 4); do
144  eval ip -net \$ns"$i" link set eth0 up
145done
146for i in $(seq 1 2); do
147  eval ip -net \$ns"$i" addr add "10.0.0.1$i/24" dev eth0
148done
149
150ip -net "$ns3" addr add 10.23.0.13/24 dev eth0
151ip -net "$ns4" addr add 10.23.0.14/24 dev eth0
152
153# test basic connectivity
154do_ping "$ns1" 10.0.0.12
155do_ping "$ns3" 10.23.0.1
156do_ping "$ns4" 10.23.0.1
157
158bcast_ping "$ns1" 10.0.0.255
159
160# This should deliver broadcast to macvlan0, which is on top of ns0:br0.
161bcast_ping "$ns3" 10.23.0.255
162
163# same, this time via veth4:macvlan4.
164bcast_ping "$ns4" 10.23.0.255
165
166read t < /proc/sys/kernel/tainted
167if [ "$t" -eq 0 ];then
168	echo PASS: kernel not tainted
169else
170	echo ERROR: kernel is tainted
171	dmesg
172	ret=1
173fi
174
175exit $ret
176