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