1#!/bin/bash
2#
3# This test is for bridge 'brouting', i.e. make some packets being routed
4# rather than getting bridged even though they arrive on interface that is
5# part of a bridge.
6
7#           eth0    br0     eth0
8# setup is: ns1 <-> ns0 <-> ns2
9
10# Kselftest framework requirement - SKIP code is 4.
11ksft_skip=4
12ret=0
13
14ebtables -V > /dev/null 2>&1
15if [ $? -ne 0 ];then
16	echo "SKIP: Could not run test without ebtables"
17	exit $ksft_skip
18fi
19
20ip -Version > /dev/null 2>&1
21if [ $? -ne 0 ];then
22	echo "SKIP: Could not run test without ip tool"
23	exit $ksft_skip
24fi
25
26ip netns add ns0
27ip netns add ns1
28ip netns add ns2
29
30ip link add veth0 netns ns0 type veth peer name eth0 netns ns1
31if [ $? -ne 0 ]; then
32	echo "SKIP: Can't create veth device"
33	exit $ksft_skip
34fi
35ip link add veth1 netns ns0 type veth peer name eth0 netns ns2
36
37ip -net ns0 link set lo up
38ip -net ns0 link set veth0 up
39ip -net ns0 link set veth1 up
40
41ip -net ns0 link add br0 type bridge
42if [ $? -ne 0 ]; then
43	echo "SKIP: Can't create bridge br0"
44	exit $ksft_skip
45fi
46
47ip -net ns0 link set veth0 master br0
48ip -net ns0 link set veth1 master br0
49ip -net ns0 link set br0 up
50ip -net ns0 addr add 10.0.0.1/24 dev br0
51
52# place both in same subnet, ns1 and ns2 connected via ns0:br0
53for i in 1 2; do
54  ip -net ns$i link set lo up
55  ip -net ns$i link set eth0 up
56  ip -net ns$i addr add 10.0.0.1$i/24 dev eth0
57done
58
59test_ebtables_broute()
60{
61	local cipt
62
63	# redirect is needed so the dstmac is rewritten to the bridge itself,
64	# ip stack won't process OTHERHOST (foreign unicast mac) packets.
65	ip netns exec ns0 ebtables -t broute -A BROUTING -p ipv4 --ip-protocol icmp -j redirect --redirect-target=DROP
66	if [ $? -ne 0 ]; then
67		echo "SKIP: Could not add ebtables broute redirect rule"
68		return $ksft_skip
69	fi
70
71	# ping netns1, expected to not work (ip forwarding is off)
72	ip netns exec ns1 ping -q -c 1 10.0.0.12 > /dev/null 2>&1
73	if [ $? -eq 0 ]; then
74		echo "ERROR: ping works, should have failed" 1>&2
75		return 1
76	fi
77
78	# enable forwarding on both interfaces.
79	# neither needs an ip address, but at least the bridge needs
80	# an ip address in same network segment as ns1 and ns2 (ns0
81	# needs to be able to determine route for to-be-forwarded packet).
82	ip netns exec ns0 sysctl -q net.ipv4.conf.veth0.forwarding=1
83	ip netns exec ns0 sysctl -q net.ipv4.conf.veth1.forwarding=1
84
85	sleep 1
86
87	ip netns exec ns1 ping -q -c 1 10.0.0.12 > /dev/null
88	if [ $? -ne 0 ]; then
89		echo "ERROR: ping did not work, but it should (broute+forward)" 1>&2
90		return 1
91	fi
92
93	echo "PASS: ns1/ns2 connectivity with active broute rule"
94	ip netns exec ns0 ebtables -t broute -F
95
96	# ping netns1, expected to work (frames are bridged)
97	ip netns exec ns1 ping -q -c 1 10.0.0.12 > /dev/null
98	if [ $? -ne 0 ]; then
99		echo "ERROR: ping did not work, but it should (bridged)" 1>&2
100		return 1
101	fi
102
103	ip netns exec ns0 ebtables -t filter -A FORWARD -p ipv4 --ip-protocol icmp -j DROP
104
105	# ping netns1, expected to not work (DROP in bridge forward)
106	ip netns exec ns1 ping -q -c 1 10.0.0.12 > /dev/null 2>&1
107	if [ $? -eq 0 ]; then
108		echo "ERROR: ping works, should have failed (icmp forward drop)" 1>&2
109		return 1
110	fi
111
112	# re-activate brouter
113	ip netns exec ns0 ebtables -t broute -A BROUTING -p ipv4 --ip-protocol icmp -j redirect --redirect-target=DROP
114
115	ip netns exec ns2 ping -q -c 1 10.0.0.11 > /dev/null
116	if [ $? -ne 0 ]; then
117		echo "ERROR: ping did not work, but it should (broute+forward 2)" 1>&2
118		return 1
119	fi
120
121	echo "PASS: ns1/ns2 connectivity with active broute rule and bridge forward drop"
122	return 0
123}
124
125# test basic connectivity
126ip netns exec ns1 ping -c 1 -q 10.0.0.12 > /dev/null
127if [ $? -ne 0 ]; then
128    echo "ERROR: Could not reach ns2 from ns1" 1>&2
129    ret=1
130fi
131
132ip netns exec ns2 ping -c 1 -q 10.0.0.11 > /dev/null
133if [ $? -ne 0 ]; then
134    echo "ERROR: Could not reach ns1 from ns2" 1>&2
135    ret=1
136fi
137
138if [ $ret -eq 0 ];then
139    echo "PASS: netns connectivity: ns1 and ns2 can reach each other"
140fi
141
142test_ebtables_broute
143ret=$?
144for i in 0 1 2; do ip netns del ns$i;done
145
146exit $ret
147