1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-or-later
3# Copyright (c) 2018-2019 Petr Vorel <pvorel@suse.cz>
4# Copyright (c) 2014-2017 Oracle and/or its affiliates. All Rights Reserved.
5# Author: Alexey Kodanev <alexey.kodanev@oracle.com>
6#
7# VxLAN
8# -----
9# Virtual eXtensible Local Area Network (VxLAN) provides L2 networks
10# over existed L3 networks. It is using UDP (port 8472) to encapsulate
11# data packets. More information:
12# http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-08
13#
14# Warning: Test assumes that machines don't have any existed VxLANs.
15#          If machine has VxLANs, the test might fail or eventually delete
16#          them in cleanup function. See "start_vni" variable which can
17#          solve it.
18
19TST_SETUP="${TST_SETUP:-virt_lib_setup}"
20TST_CLEANUP="${TST_CLEANUP:-cleanup_vifaces}"
21
22virt_lib_usage()
23{
24	echo "i n     start ID to use"
25	echo "d x     VxLAN destination address, 'uni' or 'multi'"
26}
27
28virt_lib_parse_args()
29{
30	case "$1" in
31	i) start_id=$2 ;;
32	d) vxlan_dst_addr=$2 ;;
33	esac
34}
35
36virt_lib_setup()
37{
38	case "$virt_type" in
39	vxlan|geneve)
40		if tst_kvcmp -lt "3.8"; then
41			tst_brk TCONF "test must be run with kernel 3.8 or newer"
42		fi
43
44		if [ "$TST_IPV6" ] && tst_kvcmp -lt "3.12"; then
45			tst_brk TCONF "test must be run with kernels >= 3.12"
46		fi
47
48		# newer versions of 'ip' complain if this option not set
49		ip li add type vxlan help 2>&1 | grep -q dstport && vxlan_dstport=1
50	;;
51	esac
52
53	tst_require_cmds "ip"
54
55	virt_add ltp_v0 || \
56		tst_brk TCONF "iproute2 or kernel doesn't support $virt_type"
57
58	ROD_SILENT "ip link delete ltp_v0"
59}
60
61TST_NEEDS_ROOT=1
62. tst_net.sh
63
64ip_local=$(tst_ipaddr)
65ip_virt_local="$(TST_IPV6= tst_ipaddr_un)"
66ip6_virt_local="$(TST_IPV6=6 tst_ipaddr_un)"
67
68ip_remote=$(tst_ipaddr rhost)
69ip_virt_remote="$(TST_IPV6= tst_ipaddr_un rhost)"
70ip6_virt_remote="$(TST_IPV6=6 tst_ipaddr_un rhost)"
71
72vxlan_dstport=0
73
74# Max performance loss (%) for virtual devices during network load
75VIRT_PERF_THRESHOLD=${VIRT_PERF_THRESHOLD:-80}
76if [ -n "$VIRT_PERF_THRESHOLD_MIN" ] && [ "$VIRT_PERF_THRESHOLD" -lt $VIRT_PERF_THRESHOLD_MIN ]; then
77	 VIRT_PERF_THRESHOLD="$VIRT_PERF_THRESHOLD_MIN"
78fi
79
80cleanup_vifaces()
81{
82	tst_res TINFO "cleanup virtual interfaces..."
83	local viface=`ip li | sed -nE 's/^[0-9]+: (ltp_v[0-9]+)[@:].+/\1/p'`
84	for vx in $viface; do
85		ip link delete $vx
86	done
87}
88
89virt_cleanup_rmt()
90{
91	cleanup_vifaces
92	tst_rhost_run -c "ip link delete ltp_v0 2>/dev/null"
93	if [ "$virt_tcp_syn" ]; then
94		sysctl -q net.ipv4.tcp_syn_retries=$virt_tcp_syn
95		virt_tcp_syn=
96	fi
97}
98
99virt_cleanup()
100{
101	virt_cleanup_rmt
102}
103
104virt_add()
105{
106	local vname=$1
107	shift
108	local opt="$*"
109
110	case $virt_type in
111	vlan|vxlan)
112		[ -z "$opt" ] && opt="id 4094"
113		[ "$vxlan_dstport" -eq 1 ] && opt="dstport 0 $opt"
114		[ "$virt_type" = "vxlan" ] && opt="$opt dev $(tst_iface)"
115	;;
116	geneve)
117		[ -z "$opt" ] && opt="id 4094 remote $(tst_ipaddr rhost)"
118	;;
119	gre|ip6gre)
120		[ -z "$opt" ] && \
121			opt="remote $(tst_ipaddr rhost) dev $(tst_iface)"
122	;;
123	sit)
124		[ -z "$opt" ] && opt="remote $(tst_ipaddr rhost) local $(tst_ipaddr)"
125	;;
126	esac
127
128	case $virt_type in
129	vxlan|geneve|sit)
130		ip li add $vname type $virt_type $opt
131	;;
132	gre|ip6gre)
133		ip -f inet$TST_IPV6 tu add $vname mode $virt_type $opt
134	;;
135	*)
136		ip li add link $(tst_iface) $vname type $virt_type $opt
137	;;
138	esac
139}
140
141virt_add_rhost()
142{
143	local opt=""
144	case $virt_type in
145	vxlan|geneve)
146		[ "$virt_type" = "vxlan" ] && opt="dev $(tst_iface rhost)"
147		[ "$vxlan_dstport" -eq 1 ] && opt="$opt dstport 0"
148		tst_rhost_run -s -c "ip li add ltp_v0 type $virt_type $@ $opt"
149	;;
150	sit)
151		tst_rhost_run -s -c "ip link add ltp_v0 type $virt_type $@"
152	;;
153	gre|ip6gre)
154		tst_rhost_run -s -c "ip -f inet$TST_IPV6 tu add ltp_v0 \
155				     mode $virt_type $@"
156	;;
157	*)
158		tst_rhost_run -s -c "ip li add link $(tst_iface rhost) ltp_v0 \
159				     type $virt_type $@"
160	;;
161	esac
162}
163
164virt_multiple_add_test()
165{
166	local opt="$@"
167	local max=$(($start_id + $NS_TIMES - 1))
168	local i
169
170	tst_res TINFO "add $NS_TIMES $virt_type, then delete"
171
172	for i in $(seq $start_id $max); do
173		virt_add ltp_v$i id $i $opt || \
174			tst_brk TFAIL "failed to create 'ltp_v0 $opt'"
175		ROD_SILENT "ip link set ltp_v$i up"
176	done
177
178	for i in $(seq $start_id $max); do
179		ROD_SILENT "ip link set ltp_v$i down"
180		ROD_SILENT "ip link delete ltp_v$i"
181	done
182
183	tst_res TPASS "done"
184}
185
186virt_add_delete_test()
187{
188	local opt="$@"
189	local max=$(($NS_TIMES - 1))
190	local i
191
192	tst_res TINFO "add/del $virt_type $NS_TIMES times"
193
194	for i in $(seq 0 $max); do
195		virt_add ltp_v0 $opt || \
196			tst_brk TFAIL "failed to create 'ltp_v0 $opt'"
197		ROD_SILENT "ip link set ltp_v0 up"
198		ROD_SILENT "ip link delete ltp_v0"
199	done
200	tst_res TPASS "done"
201}
202
203virt_setup()
204{
205	local opt="$1"
206	local opt_r="${2:-$1}"
207
208	tst_res TINFO "setup local ${virt_type} with '$opt'"
209	virt_add ltp_v0 $opt || \
210		tst_brk TBROK "failed to create 'ltp_v0 $opt'"
211
212	tst_res TINFO "setup rhost ${virt_type} with '$opt_r'"
213	virt_add_rhost "$opt_r"
214
215	ROD_SILENT "ip addr add ${ip6_virt_local}/64 dev ltp_v0 nodad"
216	tst_rhost_run -s -c "ip ad add ${ip6_virt_remote}/64 dev ltp_v0 nodad"
217
218	ROD_SILENT "ip addr add ${ip_virt_local}/24 dev ltp_v0"
219	tst_rhost_run -s -c "ip addr add ${ip_virt_remote}/24 dev ltp_v0"
220
221	ROD_SILENT "sysctl -q net.ipv6.conf.ltp_v0.accept_dad=0"
222	tst_rhost_run -s -c "sysctl -q net.ipv6.conf.ltp_v0.accept_dad=0"
223
224	ROD_SILENT "ip li set up ltp_v0"
225	tst_rhost_run -s -c "ip li set up ltp_v0"
226}
227
228virt_tcp_syn=
229virt_minimize_timeout()
230{
231	local mac_loc="$(cat /sys/class/net/ltp_v0/address)"
232	local mac_rmt="$(tst_rhost_run -c 'cat /sys/class/net/ltp_v0/address')"
233
234	ROD_SILENT "ip ne replace $ip_virt_remote lladdr \
235		    $mac_rmt nud permanent dev ltp_v0"
236	tst_rhost_run -s -c "ip ne replace $ip_virt_local lladdr \
237			     $mac_loc nud permanent dev ltp_v0"
238	virt_tcp_syn=$(sysctl -n net.ipv4.tcp_syn_retries)
239	ROD sysctl -q net.ipv4.tcp_syn_retries=1
240}
241
242vxlan_setup_subnet_uni()
243{
244	if tst_kvcmp -lt "3.10"; then
245		tst_brk TCONF "test must be run with kernel 3.10 or newer"
246	fi
247
248	[ "$(ip li add type $virt_type help 2>&1 | grep remote)" ] || \
249		tst_brk TCONF "iproute doesn't support remote unicast address"
250
251	local opt="$1 remote $(tst_ipaddr rhost)"
252	local opt_r="$2 remote $(tst_ipaddr)"
253
254	virt_setup "$opt" "$opt_r"
255}
256
257vxlan_setup_subnet_multi()
258{
259	tst_require_cmds "od"
260	local b1=$(($(od -An -d -N1 /dev/urandom) % 254 + 1))
261	local b2=$(($(od -An -d -N1 /dev/urandom) % 254 + 1))
262	local b3=$(($(od -An -d -N1 /dev/urandom) % 254 + 1))
263
264	local grp=
265	if [ "$TST_IPV6" ]; then
266		grp="group ff05::$(printf '%x:%x%x' $b1 $b2 $b3)"
267	else
268		grp="group 239.$b1.$b2.$b3"
269	fi
270
271	local opt="$1 $grp"
272	local opt_r="$2 $grp"
273
274	virt_setup "$opt" "$opt_r"
275}
276
277virt_compare_netperf()
278{
279	local ret1="pass"
280	local ret2="pass"
281	local expect_res="${1:-pass}"
282	local opts="$2"
283
284	tst_netload -H $ip_virt_remote $opts -d res_ipv4 -e $expect_res \
285		-D ltp_v0 || ret1="fail"
286
287	tst_netload -H ${ip6_virt_remote} $opts -d res_ipv6 -e $expect_res \
288		-D ltp_v0 || ret2="fail"
289
290	[ "$ret1" = "fail" -o "$ret2" = "fail" ] && return
291
292	local vt="$(cat res_ipv4)"
293	local vt6="$(cat res_ipv6)"
294
295	tst_netload -H $ip_remote $opts -d res_ipv4
296
297	local lt="$(cat res_ipv4)"
298	tst_res TINFO "time lan($lt) $virt_type IPv4($vt) and IPv6($vt6) ms"
299
300	per=$(( $vt * 100 / $lt - 100 ))
301	per6=$(( $vt6 * 100 / $lt - 100 ))
302
303	case "$virt_type" in
304	vxlan|geneve)
305		tst_res TINFO "IP4 $virt_type over IP$TST_IPVER slower by $per %"
306		tst_res TINFO "IP6 $virt_type over IP$TST_IPVER slower by $per6 %"
307	;;
308	*)
309		tst_res TINFO "IP4 $virt_type slower by $per %"
310		tst_res TINFO "IP6 $virt_type slower by $per6 %"
311	esac
312
313	if [ "$per" -ge "$VIRT_PERF_THRESHOLD" -o \
314	     "$per6" -ge "$VIRT_PERF_THRESHOLD" ]; then
315		tst_res TFAIL "Test failed, threshold: $VIRT_PERF_THRESHOLD %"
316	else
317		tst_res TPASS "Test passed, threshold: $VIRT_PERF_THRESHOLD %"
318	fi
319}
320
321virt_check_cmd()
322{
323	$@ > /dev/null 2>&1
324	if [ $? -ne 0 ]; then
325		tst_res TCONF "'$@' option(s) not supported, skipping it"
326		return 1
327	fi
328	ROD_SILENT "ip li delete ltp_v0"
329	return 0
330}
331
332virt_netperf_msg_sizes()
333{
334	local sizes="100 1000 2000 $TST_NET_MAX_PKT"
335	local s
336
337	for s in $sizes; do
338		virt_compare_netperf pass "-n $s -N $s"
339	done
340}
341
342virt_netperf_rand_sizes()
343{
344	local max_pkt_size="$TST_NET_MAX_PKT"
345	local types="tcp udp udp_lite"
346
347	for t in $types; do
348		virt_compare_netperf pass "-A $max_pkt_size -T $t"
349	done
350}
351
352# Check if we can create then delete virtual interface.
353virt_test_01()
354{
355	start_id="${start_id:-1}"
356
357	tst_res TINFO "add $virt_type with '$2'"
358	virt_check_cmd virt_add ltp_v0 id 0 $2 || return
359	virt_multiple_add_test "$2"
360}
361
362# Check if we can create then delete virtual interface.
363virt_test_02()
364{
365	start_id="${start_id:-1}"
366
367	tst_res TINFO "add and then delete $virt_type with '$2'"
368	virt_check_cmd virt_add ltp_v0 $2 || return
369	virt_add_delete_test "$2"
370	start_id=$(($start_id + $NS_TIMES))
371}
372
373virt_gre_setup()
374{
375	virt_type="gre"
376	[ "$TST_IPV6" ] && virt_type="ip6gre"
377	virt_lib_setup
378
379	if [ -z $ip_local -o -z $ip_remote ]; then
380		tst_brk TBROK "you must specify IP address"
381	fi
382
383	tst_res TINFO "test $virt_type"
384	virt_setup "local $(tst_ipaddr) remote $(tst_ipaddr rhost) dev $(tst_iface)" \
385	"local $(tst_ipaddr rhost) remote $(tst_ipaddr) dev $(tst_iface rhost)"
386}
387