• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-or-later
3# Copyright (c) 2014-2017 Oracle and/or its affiliates. All Rights Reserved.
4# Copyright (c) 2016-2019 Petr Vorel <pvorel@suse.cz>
5# Author: Alexey Kodanev <alexey.kodanev@oracle.com>
6
7[ -n "$TST_LIB_NET_LOADED" ] && return 0
8TST_LIB_NET_LOADED=1
9
10TST_OPTS="6$TST_OPTS"
11TST_PARSE_ARGS_CALLER="$TST_PARSE_ARGS"
12TST_PARSE_ARGS="tst_net_parse_args"
13TST_USAGE_CALLER="$TST_USAGE"
14TST_USAGE="tst_net_usage"
15TST_SETUP_CALLER="$TST_SETUP"
16TST_SETUP="tst_net_setup"
17
18# Blank for an IPV4 test; 6 for an IPV6 test.
19TST_IPV6=${TST_IPV6:-}
20TST_IPVER=${TST_IPV6:-4}
21# Blank for IPv4, '-6' for IPv6 test.
22TST_IPV6_FLAG=${TST_IPV6_FLAG:-}
23
24tst_net_parse_args()
25{
26	case $1 in
27	6) TST_IPV6=6 TST_IPVER=6 TST_IPV6_FLAG="-6";;
28	*) [ "$TST_PARSE_ARGS_CALLER" ] && $TST_PARSE_ARGS_CALLER "$1" "$2";;
29	esac
30}
31
32tst_net_read_opts()
33{
34	local OPTIND
35	while getopts ":$TST_OPTS" opt; do
36		$TST_PARSE_ARGS "$opt" "$OPTARG"
37	done
38}
39
40tst_net_usage()
41{
42	if [ -n "$TST_USAGE_CALLER" ]; then
43		$TST_USAGE_CALLER
44	else
45		echo "Usage: $0 [-6]"
46		echo "OPTIONS"
47	fi
48	echo "-6      IPv6 tests"
49}
50
51tst_net_remote_tmpdir()
52{
53	[ "$TST_NEEDS_TMPDIR" = 1 ] || return 0
54	[ -n "$TST_USE_LEGACY_API" ] && tst_tmpdir
55	tst_rhost_run -c "mkdir -p $TST_TMPDIR"
56	tst_rhost_run -c "chmod 777 $TST_TMPDIR"
57	export TST_TMPDIR_RHOST=1
58}
59
60tst_net_setup()
61{
62	tst_net_remote_tmpdir
63	[ -n "$TST_SETUP_CALLER" ] && $TST_SETUP_CALLER
64
65	if [ -z "$NS_ICMP_SENDER_DATA_MAXSIZE" ]; then
66		if [ "$TST_IPV6" ]; then
67			NS_ICMP_SENDER_DATA_MAXSIZE="$NS_ICMPV6_SENDER_DATA_MAXSIZE"
68		else
69			NS_ICMP_SENDER_DATA_MAXSIZE="$NS_ICMPV4_SENDER_DATA_MAXSIZE"
70		fi
71	fi
72}
73
74[ -n "$TST_USE_LEGACY_API" ] && . test.sh || . tst_test.sh
75
76if [ "$TST_PARSE_ARGS_CALLER" = "$TST_PARSE_ARGS" ]; then
77	tst_res TWARN "TST_PARSE_ARGS_CALLER same as TST_PARSE_ARGS, unset it ($TST_PARSE_ARGS)"
78	unset TST_PARSE_ARGS_CALLER
79fi
80if [ "$TST_SETUP_CALLER" = "$TST_SETUP" ]; then
81	tst_res TWARN "TST_SETUP_CALLER same as TST_SETUP, unset it ($TST_SETUP)"
82	unset TST_SETUP_CALLER
83fi
84if [ "$TST_USAGE_CALLER" = "$TST_USAGE" ]; then
85	tst_res TWARN "TST_USAGE_CALLER same as TST_USAGE, unset it ($TST_USAGE)"
86	unset TST_USAGE_CALLER
87fi
88
89if [ -n "$TST_USE_LEGACY_API" ]; then
90	tst_net_read_opts "$@"
91fi
92
93# old vs. new API compatibility layer
94tst_res_()
95{
96	[ -z "$TST_USE_LEGACY_API" ] && tst_res $@ || tst_resm $@
97}
98tst_brk_()
99{
100	[ -z "$TST_USE_LEGACY_API" ] && tst_brk $@ || tst_brkm $@
101}
102
103init_ltp_netspace()
104{
105	local pid
106
107	if [ ! -f /var/run/netns/ltp_ns -a -z "$LTP_NETNS" ]; then
108		tst_require_cmds ip
109		tst_require_root
110
111		tst_require_drivers veth
112		ROD ip li add name ltp_ns_veth1 type veth peer name ltp_ns_veth2
113		pid="$(ROD ns_create net,mnt)"
114		mkdir -p /var/run/netns
115		ROD ln -s /proc/$pid/ns/net /var/run/netns/ltp_ns
116		ROD ns_exec $pid net,mnt mount --make-rprivate /sys
117		ROD ns_exec $pid net,mnt mount -t sysfs none /sys
118		ROD ns_ifmove ltp_ns_veth1 $pid
119		ROD ns_exec $pid net,mnt ip li set lo up
120	elif [ -n "$LTP_NETNS" ]; then
121		tst_res_ TINFO "using not default LTP netns: '$LTP_NETNS'"
122	fi
123
124	LHOST_IFACES="${LHOST_IFACES:-ltp_ns_veth2}"
125	RHOST_IFACES="${RHOST_IFACES:-ltp_ns_veth1}"
126
127	export TST_INIT_NETNS="no"
128
129	pid="$(echo $(readlink /var/run/netns/ltp_ns) | cut -f3 -d'/')"
130	export LTP_NETNS="${LTP_NETNS:-ns_exec $pid net,mnt}"
131
132	tst_restore_ipaddr
133	tst_restore_ipaddr rhost
134}
135
136# return 0: use ssh, 1: use netns
137tst_net_use_netns()
138{
139	[ -n "$TST_USE_NETNS" ]
140}
141
142# Run command on remote host.
143# tst_rhost_run -c CMD [-b] [-s] [-u USER]
144# Options:
145# -b run in background
146# -c CMD specify command to run (this must be binary, not shell builtin/function)
147# -s safe option, if something goes wrong, will exit with TBROK
148# -u USER for ssh (default root)
149# RETURN: 0 on success, 1 on failure
150# TST_NET_RHOST_RUN_DEBUG=1 enables debugging
151tst_rhost_run()
152{
153	local post_cmd=' || echo RTERR'
154	local user="root"
155	local ret=0
156	local cmd out output pre_cmd rcmd sh_cmd safe use
157
158	local OPTIND
159	while getopts :bc:su: opt; do
160		case "$opt" in
161		b) [ "${TST_USE_NETNS:-}" ] && pre_cmd= || pre_cmd="nohup"
162		   post_cmd=" > /dev/null 2>&1 &"
163		   out="1> /dev/null"
164		;;
165		c) cmd="$OPTARG" ;;
166		s) safe=1 ;;
167		u) user="$OPTARG" ;;
168		*) tst_brk_ TBROK "tst_rhost_run: unknown option: $OPTARG" ;;
169		esac
170	done
171
172	if [ -z "$cmd" ]; then
173		[ "$safe" ] && \
174			tst_brk_ TBROK "tst_rhost_run: command not defined"
175		tst_res_ TWARN "tst_rhost_run: command not defined"
176		return 1
177	fi
178
179	sh_cmd="$pre_cmd $cmd $post_cmd"
180
181	if [ -n "${TST_USE_NETNS:-}" ]; then
182		use="NETNS"
183		rcmd="$LTP_NETNS sh -c"
184	else
185		tst_require_cmds ssh
186		use="SSH"
187		rcmd="ssh -nq $user@$RHOST"
188	fi
189
190	if [ "$TST_NET_RHOST_RUN_DEBUG" = 1 ]; then
191		tst_res_ TINFO "tst_rhost_run: cmd: $cmd"
192		tst_res_ TINFO "$use: $rcmd \"$sh_cmd\" $out 2>&1"
193	fi
194
195	output=$($rcmd "$sh_cmd" $out 2>&1 || echo 'RTERR')
196
197	echo "$output" | grep -q 'RTERR$' && ret=1
198	if [ $ret -eq 1 ]; then
199		output=$(echo "$output" | sed 's/RTERR//')
200		[ "$safe" ] && \
201			tst_brk_ TBROK "'$cmd' failed on '$RHOST': '$output'"
202	fi
203
204	[ -z "$out" -a -n "$output" ] && echo "$output"
205
206	return $ret
207}
208
209# Run command on both lhost and rhost.
210# tst_net_run [-s] [-l LPARAM] [-r RPARAM] [ -q ] CMD [ARG [ARG2]]
211# Options:
212# -l LPARAM: parameter passed to CMD in lhost
213# -r RPARAM: parameter passed to CMD in rhost
214# -q: quiet mode (suppress failure warnings)
215# CMD: command to run (this must be binary, not shell builtin/function due
216# tst_rhost_run() limitation)
217# RETURN: 0 on success, 1 on missing CMD or exit code on lhost or rhost
218tst_net_run()
219{
220	local cmd
221	local lparams
222	local rparams
223	local lsafe
224	local rsafe
225	local lret
226	local rret
227	local quiet
228
229	local OPTIND
230	while getopts l:qr:s opt; do
231		case "$opt" in
232		l) lparams="$OPTARG" ;;
233		q) quiet=1 ;;
234		r) rparams="$OPTARG" ;;
235		s) lsafe="ROD"; rsafe="-s" ;;
236		*) tst_brk_ TBROK "tst_net_run: unknown option: $OPTARG" ;;
237		esac
238	done
239	shift $((OPTIND - 1))
240	cmd="$1"
241	shift
242
243	if [ -z "$cmd" ]; then
244		[ -n "$lsafe" ] && \
245			tst_brk_ TBROK "tst_net_run: command not defined"
246		tst_res_ TWARN "tst_net_run: command not defined"
247		return 1
248	fi
249
250	$lsafe $cmd $lparams $@
251	lret=$?
252	tst_rhost_run $rsafe -c "$cmd $rparams $@"
253	rret=$?
254
255	if [ -z "$quiet" ]; then
256		[ $lret -ne 0 ] && tst_res_ TWARN "tst_net_run: lhost command failed: $lret"
257		[ $rret -ne 0 ] && tst_res_ TWARN "tst_net_run: rhost command failed: $rret"
258	fi
259
260	[ $lret -ne 0 ] && return $lret
261	return $rret
262}
263
264EXPECT_RHOST_PASS()
265{
266	local log="$TMPDIR/log.$$"
267
268	tst_rhost_run -c "$*" > $log
269	if [ $? -eq 0 ]; then
270		tst_res_ TPASS "$* passed as expected"
271	else
272		tst_res_ TFAIL "$* failed unexpectedly"
273		cat $log
274	fi
275
276	rm -f $log
277}
278
279EXPECT_RHOST_FAIL()
280{
281	local log="$TMPDIR/log.$$"
282
283	tst_rhost_run -c "$*" > $log
284	if [ $? -ne 0 ]; then
285		tst_res_ TPASS "$* failed as expected"
286	else
287		tst_res_ TFAIL "$* passed unexpectedly"
288		cat $log
289	fi
290
291	rm -f $log
292}
293
294# Get test interface names for local/remote host.
295# tst_get_ifaces [TYPE]
296# TYPE: { lhost | rhost }; Default value is 'lhost'.
297tst_get_ifaces()
298{
299	local type="${1:-lhost}"
300	if [ "$type" = "lhost" ]; then
301		echo "$LHOST_IFACES"
302	else
303		echo "$RHOST_IFACES"
304	fi
305}
306
307# Get count of test interfaces for local/remote host.
308tst_get_ifaces_cnt()
309{
310	tst_require_cmds awk
311	local type="${1:-lhost}"
312	echo "$(tst_get_ifaces $type)" | awk '{print NF}'
313}
314
315# Get HW addresses from defined test interface names.
316# tst_get_hwaddrs [TYPE]
317# TYPE: { lhost | rhost }; Default value is 'lhost'.
318tst_get_hwaddrs()
319{
320	local type="${1:-lhost}"
321	local addr=
322	local list=
323
324	for eth in $(tst_get_ifaces $type); do
325
326		local addr_path="/sys/class/net/${eth}/address"
327
328		case $type in
329		lhost) addr=$(cat $addr_path) ;;
330		rhost) addr=$(tst_rhost_run -s -c "cat $addr_path")
331		esac
332
333		[ -z "$list" ] && list="$addr" || list="$list $addr"
334	done
335	echo "$list"
336}
337
338# Get test HW address.
339# tst_hwaddr [TYPE] [LINK]
340# TYPE: { lhost | rhost }; Default value is 'lhost'.
341# LINK: link number starting from 0. Default value is '0'.
342tst_hwaddr()
343{
344	tst_require_cmds awk
345
346	local type="${1:-lhost}"
347	local link_num="${2:-0}"
348	local hwaddrs=
349	link_num=$(( $link_num + 1 ))
350	[ "$type" = "lhost" ] && hwaddrs=$LHOST_HWADDRS || hwaddrs=$RHOST_HWADDRS
351	echo "$hwaddrs" | awk '{ print $'"$link_num"' }'
352}
353
354# Get test interface name.
355# tst_iface [TYPE] [LINK]
356# TYPE: { lhost | rhost }; Default value is 'lhost'.
357# LINK: link number starting from 0. Default value is '0'.
358tst_iface()
359{
360	tst_require_cmds awk
361
362	local type="${1:-lhost}"
363	local link_num="${2:-0}"
364	link_num="$(( $link_num + 1 ))"
365	echo "$(tst_get_ifaces $type)" | awk '{ print $'"$link_num"' }'
366}
367
368# Get IP address
369# tst_ipaddr [TYPE]
370# TYPE: { lhost | rhost }; Default value is 'lhost'.
371tst_ipaddr()
372{
373	local type="${1:-lhost}"
374	if [ "$TST_IPV6" ]; then
375		[ "$type" = "lhost" ] && echo "$IPV6_LHOST" || echo "$IPV6_RHOST"
376	else
377		[ "$type" = "lhost" ] && echo "$IPV4_LHOST" || echo "$IPV4_RHOST"
378	fi
379}
380
381# Get IP address of unused network, specified either counter and type
382# or by net and host.
383# counter mode:
384# tst_ipaddr_un [-h MIN,MAX] [-n MIN,MAX] [-p] [-c COUNTER] [TYPE]
385# net & host mode:
386# tst_ipaddr_un [-h MIN,MAX] [-n MIN,MAX] [-p] NET_ID [HOST_ID]
387#
388# TYPE: { lhost | rhost } (default: 'lhost')
389# NET_ID: integer or hex value of net (IPv4: 3rd octet <0,255>, IPv6: 3rd
390# hextet <0,65535>)
391# HOST_ID: integer or hex value of host (IPv4: 4th octet <0,255>, IPv6: the
392# last hextet <0, 65535>, default: 0)
393#
394# OPTIONS
395# -c COUNTER: integer value for counting HOST_ID and NET_ID (default: 1)
396#
397# -h: specify *host* address range (HOST_ID)
398# -h MIN,MAX or -h MIN or -h ,MAX
399#
400# -n: specify *network* address range (NET_ID)
401# -n MIN,MAX or -n MIN or -n ,MAX
402#
403# -p: print also prefix
404tst_ipaddr_un()
405{
406	local default_max=255
407	[ "$TST_IPV6" ] && default_max=65535
408	local max_net_id=$default_max
409	local min_net_id=0
410
411	local counter host_id host_range is_counter max_host_id min_host_id net_id prefix tmp type
412
413	local OPTIND
414	while getopts "c:h:n:p" opt; do
415		case $opt in
416			c) counter="$OPTARG";;
417			h)
418				if echo $OPTARG | grep -q ','; then # 'min,max' or 'min,' or ',max'
419					min_host_id="$(echo $OPTARG | cut -d, -f1)"
420					max_host_id="$(echo $OPTARG | cut -d, -f2)"
421				else # min
422					min_host_id="$OPTARG"
423				fi
424				;;
425			n)
426				if echo $OPTARG | grep -q ','; then # 'min,max' or 'min,' or ',max'
427					min_net_id="$(echo $OPTARG | cut -d, -f1)"
428					max_net_id="$(echo $OPTARG | cut -d, -f2)"
429				else # min
430					min_net_id="$OPTARG"
431				fi
432				;;
433			m)
434				! tst_is_int "$OPTARG" || [ "$OPTARG" -lt 0 ]|| [ "$OPTARG" -gt $max_net_id ] && \
435					tst_brk TBROK "tst_ipaddr_un: -m must be integer <0,$max_net_id> ($OPTARG)"
436				[ "$OPTARG" -gt $max_net_id ] && \
437					tst_brk_ TBROK "tst_ipaddr_un: -m cannot be higher than $max_net_id ($OPTARG)"
438				max_host_id="$OPTARG"
439				;;
440			p) [ "$TST_IPV6" ] && prefix="/64" || prefix="/24";;
441		esac
442	done
443	shift $(($OPTIND - 1))
444	[ $# -eq 0 -o "$1" = "lhost" -o "$1" = "rhost" ] && is_counter=1
445
446	if [ -z "$min_host_id" ]; then
447		[ "$is_counter" ] && min_host_id=1 || min_host_id=0
448	fi
449	if [ -z "$max_host_id" ]; then
450		[ "$is_counter" ] && max_host_id=$((default_max - 1)) || max_host_id=$default_max
451	fi
452
453	! tst_is_int "$min_host_id" || ! tst_is_int "$max_host_id" || \
454		[ $min_host_id -lt 0 -o $min_host_id -gt $default_max ] || \
455		[ $max_host_id -lt 0 -o $max_host_id -gt $default_max ] && \
456		tst_brk TBROK "tst_ipaddr_un: HOST_ID must be int in range <0,$default_max> ($min_host_id,$max_host_id)"
457	! tst_is_int "$min_net_id" || ! tst_is_int "$max_net_id" || \
458		[ $min_net_id -lt 0 -o $min_net_id -gt $default_max ] || \
459		[ $max_net_id -lt 0 -o $max_net_id -gt $default_max ] && \
460		tst_brk TBROK "tst_ipaddr_un: NET_ID must be int in range <0,$default_max> ($min_net_id,$max_net_id)"
461
462	[ $min_host_id -gt $max_host_id ] && \
463		tst_brk TBROK "tst_ipaddr_un: max HOST_ID ($max_host_id) must be >= min HOST_ID ($min_host_id)"
464	[ $min_net_id -gt $max_net_id ] && \
465		tst_brk TBROK "tst_ipaddr_un: max NET_ID ($max_net_id) must be >= min NET_ID ($min_net_id)"
466
467	# counter
468	host_range=$((max_host_id - min_host_id + 1))
469	if [ "$is_counter" ]; then
470		[ -z "$counter" ] && counter=1
471		[ $counter -lt 1 ] && counter=1
472		type="${1:-lhost}"
473		tmp=$((counter * 2))
474		[ "$type" = "rhost" ] && tmp=$((tmp - 1))
475		net_id=$(((tmp - 1) / host_range))
476		host_id=$((tmp - net_id * host_range + min_host_id - 1))
477	else # net_id & host_id
478		net_id="$1"
479		host_id="${2:-0}"
480		if [ "$TST_IPV6" ]; then
481			net_id=$(printf %d $net_id)
482			host_id=$(printf %d $host_id)
483		fi
484		host_id=$((host_id % host_range + min_host_id))
485	fi
486
487	net_id=$((net_id % (max_net_id - min_net_id + 1) + min_net_id))
488
489	if [ -z "$TST_IPV6" ]; then
490		echo "${IPV4_NET16_UNUSED}.${net_id}.${host_id}${prefix}"
491		return
492	fi
493
494	[ $host_id -gt 0 ] && host_id="$(printf %x $host_id)" || host_id=
495	[ $net_id -gt 0 ] && net_id="$(printf %x $net_id)" || net_id=
496	[ "$net_id" ] && net_id=":$net_id"
497	echo "${IPV6_NET32_UNUSED}${net_id}::${host_id}${prefix}"
498}
499
500# tst_init_iface [TYPE] [LINK]
501# TYPE: { lhost | rhost }; Default value is 'lhost'.
502# LINK: link number starting from 0. Default value is '0'.
503tst_init_iface()
504{
505	local type="${1:-lhost}"
506	local link_num="${2:-0}"
507	local iface="$(tst_iface $type $link_num)"
508	tst_res_ TINFO "initialize '$type' '$iface' interface"
509
510	if [ "$type" = "lhost" ]; then
511		if ip xfrm state 1>/dev/null 2>&1; then
512			ip xfrm policy flush || return $?
513			ip xfrm state flush || return $?
514		fi
515		ip link set $iface down || return $?
516		ip route flush dev $iface || return $?
517		ip addr flush dev $iface || return $?
518		ip link set $iface up
519		return $?
520	fi
521
522	if tst_rhost_run -c "ip xfrm state 1>/dev/null 2>&1"; then
523		tst_rhost_run -c "ip xfrm policy flush" || return $?
524		tst_rhost_run -c "ip xfrm state flush" || return $?
525	fi
526	tst_rhost_run -c "ip link set $iface down" || return $?
527	tst_rhost_run -c "ip route flush dev $iface" || return $?
528	tst_rhost_run -c "ip addr flush dev $iface" || return $?
529	tst_rhost_run -c "ip link set $iface up"
530}
531
532# tst_add_ipaddr [TYPE] [LINK] [-a IP] [-d] [-q] [-s]
533# Options:
534# TYPE: { lhost | rhost }, default value is 'lhost'
535# LINK: link number starting from 0, default value is '0'
536# -a IP: IP address to be added, default value is
537# $(tst_ipaddr)/$IPV{4,6}_{L,R}PREFIX
538# -d: delete address instead of adding
539# -q: quiet mode (don't print info)
540# -s: safe option, if something goes wrong, will exit with TBROK
541tst_add_ipaddr()
542{
543	local action="add"
544	local addr dad lsafe mask quiet rsafe
545
546	local OPTIND
547	while getopts a:dqs opt; do
548		case "$opt" in
549		a) addr="$OPTARG" ;;
550		d) action="del" ;;
551		q) quiet=1 ;;
552		s) lsafe="ROD"; rsafe="-s" ;;
553		*) tst_brk TBROK "tst_add_ipaddr: unknown option: $OPTARG" ;;
554		esac
555	done
556	shift $((OPTIND - 1))
557
558	local type="${1:-lhost}"
559	local link_num="${2:-0}"
560	local iface=$(tst_iface $type $link_num)
561
562	if [ "$TST_IPV6" ]; then
563		dad="nodad"
564		[ "$type" = "lhost" ] && mask=$IPV6_LPREFIX || mask=$IPV6_RPREFIX
565	else
566		[ "$type" = "lhost" ] && mask=$IPV4_LPREFIX || mask=$IPV4_RPREFIX
567	fi
568	[ -n "$addr" ] || addr="$(tst_ipaddr $type)"
569	echo $addr | grep -q / || addr="$addr/$mask"
570
571	if [ $type = "lhost" ]; then
572		[ "$quiet" ] || tst_res_ TINFO "$action local addr $addr"
573		$lsafe ip addr $action $addr dev $iface $dad
574		return $?
575	fi
576
577	[ "$quiet" ] || tst_res_ TINFO "$action remote addr $addr"
578	tst_rhost_run $rsafe -c "ip addr $action $addr dev $iface $dad"
579}
580
581# tst_del_ipaddr [ tst_add_ipaddr options ]
582# Delete IP address
583tst_del_ipaddr()
584{
585	tst_add_ipaddr -d $@
586}
587
588# tst_restore_ipaddr [TYPE] [LINK]
589# Restore default ip addresses defined in network.sh
590# TYPE: { lhost | rhost }; Default value is 'lhost'.
591# LINK: link number starting from 0. Default value is '0'.
592tst_restore_ipaddr()
593{
594	tst_require_cmds ip
595	tst_require_root
596
597	local type="${1:-lhost}"
598	local link_num="${2:-0}"
599
600	tst_init_iface $type $link_num || return $?
601
602	local ret=0
603	local backup_tst_ipv6=$TST_IPV6
604	TST_IPV6= tst_add_ipaddr $type $link_num || ret=$?
605	TST_IPV6=6 tst_add_ipaddr $type $link_num || ret=$?
606	TST_IPV6=$backup_tst_ipv6
607
608	return $ret
609}
610
611# tst_wait_ipv6_dad [LHOST_IFACE] [RHOST_IFACE]
612# wait for IPv6 DAD completion
613tst_wait_ipv6_dad()
614{
615	local ret=
616	local i=
617	local iface_loc=${1:-$(tst_iface)}
618	local iface_rmt=${2:-$(tst_iface rhost)}
619
620	for i in $(seq 1 50); do
621		ip a sh $iface_loc | grep -q tentative
622		ret=$?
623
624		tst_rhost_run -c "ip a sh $iface_rmt | grep -q tentative"
625
626		[ $ret -ne 0 -a $? -ne 0 ] && return
627
628		[ $(($i % 10)) -eq 0 ] && \
629			tst_res_ TINFO "wait for IPv6 DAD completion $((i / 10))/5 sec"
630
631		tst_sleep 100ms
632	done
633}
634
635tst_netload_brk()
636{
637	tst_rhost_run -c "cat $TST_TMPDIR/netstress.log"
638	cat tst_netload.log
639	tst_brk_ $1 $2
640}
641
642# Run network load test, see 'netstress -h' for option description
643tst_netload()
644{
645	local rfile="tst_netload.res"
646	local expect_res="pass"
647	local ret=0
648	local type="tcp"
649	local hostopt=
650	local setup_srchost=0
651	# common options for client and server
652	local cs_opts=
653
654	local run_cnt="$TST_NETLOAD_RUN_COUNT"
655	local c_num="$TST_NETLOAD_CLN_NUMBER"
656	local c_requests="$TST_NETLOAD_CLN_REQUESTS"
657	local c_opts=
658
659	# number of server replies after which TCP connection is closed
660	local s_replies="${TST_NETLOAD_MAX_SRV_REPLIES:-500000}"
661	local s_opts=
662	local bind_to_device=1
663
664	if [ ! "$TST_NEEDS_TMPDIR" = 1 ]; then
665		tst_brk_ TBROK "Using tst_netload requires setting TST_NEEDS_TMPDIR=1"
666	fi
667
668	OPTIND=0
669	while getopts :a:H:d:n:N:r:R:S:b:t:T:fFe:m:A:D: opt; do
670		case "$opt" in
671		a) c_num="$OPTARG" ;;
672		H) c_opts="${c_opts}-H $OPTARG "
673		   hostopt="$OPTARG" ;;
674		d) rfile="$OPTARG" ;;
675		n) c_opts="${c_opts}-n $OPTARG " ;;
676		N) c_opts="${c_opts}-N $OPTARG " ;;
677		r) c_requests="$OPTARG" ;;
678		A) c_opts="${c_opts}-A $OPTARG " ;;
679		R) s_replies="$OPTARG" ;;
680		S) c_opts="${c_opts}-S $OPTARG "
681		   setup_srchost=1 ;;
682		b) cs_opts="${cs_opts}-b $OPTARG " ;;
683		t) cs_opts="${cs_opts}-t $OPTARG " ;;
684		T) cs_opts="${cs_opts}-T $OPTARG "
685		   type="$OPTARG" ;;
686		m) cs_opts="${cs_opts}-m $OPTARG " ;;
687		f) cs_opts="${cs_opts}-f " ;;
688		F) cs_opts="${cs_opts}-F " ;;
689		e) expect_res="$OPTARG" ;;
690		D) [ "$TST_NETLOAD_BINDTODEVICE" = 1 ] && cs_opts="${cs_opts}-D $OPTARG "
691		   bind_to_device=0 ;;
692		*) tst_brk_ TBROK "tst_netload: unknown option: $OPTARG" ;;
693		esac
694	done
695	OPTIND=0
696
697	[ "$setup_srchost" = 1 ] && s_opts="${s_opts}-S $hostopt "
698
699	if [ "$bind_to_device" = 1 -a "$TST_NETLOAD_BINDTODEVICE" = 1 ]; then
700		c_opts="${c_opts}-D $(tst_iface) "
701		s_opts="${s_opts}-D $(tst_iface rhost) "
702	fi
703
704	local expect_ret=0
705	[ "$expect_res" != "pass" ] && expect_ret=3
706
707	local was_failure=0
708	if [ "$run_cnt" -lt 2 ]; then
709		run_cnt=1
710		was_failure=1
711	fi
712
713	s_opts="${cs_opts}${s_opts}-R $s_replies -B $TST_TMPDIR"
714	c_opts="${cs_opts}${c_opts}-a $c_num -r $((c_requests / run_cnt)) -d $rfile"
715
716	tst_res_ TINFO "run server 'netstress $s_opts'"
717	tst_res_ TINFO "run client 'netstress -l $c_opts' $run_cnt times"
718
719	tst_rhost_run -c "pkill -9 netstress\$"
720	rm -f tst_netload.log
721
722	local results
723	local passed=0
724
725	for i in $(seq 1 $run_cnt); do
726		tst_rhost_run -c "netstress $s_opts" > tst_netload.log 2>&1
727		if [ $? -ne 0 ]; then
728			cat tst_netload.log
729			local ttype="TFAIL"
730			grep -e 'CONF:' tst_netload.log && ttype="TCONF"
731			tst_brk_ $ttype "server failed"
732		fi
733
734		local port=$(tst_rhost_run -s -c "cat $TST_TMPDIR/netstress_port")
735		netstress -l ${c_opts} -g $port > tst_netload.log 2>&1
736		ret=$?
737		tst_rhost_run -c "pkill -9 netstress\$"
738
739		if [ "$expect_ret" -ne 0 ]; then
740			if [ $((ret & expect_ret)) -ne 0 ]; then
741				tst_res_ TPASS "netstress failed as expected"
742			else
743				tst_res_ TFAIL "expected '$expect_res' but ret: '$ret'"
744			fi
745			return $ret
746		fi
747
748		if [ "$ret" -ne 0 ]; then
749			[ $((ret & 32)) -ne 0 ] && \
750				tst_netload_brk TCONF "not supported configuration"
751
752			[ $((ret & 3)) -ne 0 -a $was_failure -gt 0 ] && \
753				tst_netload_brk TFAIL "expected '$expect_res' but ret: '$ret'"
754
755			tst_res_ TWARN "netstress failed, ret: $ret"
756			was_failure=1
757			continue
758		fi
759
760		[ ! -f $rfile ] && \
761			tst_netload_brk TFAIL "can't read $rfile"
762
763		results="$results $(cat $rfile)"
764		passed=$((passed + 1))
765	done
766
767	if [ "$ret" -ne 0 ]; then
768		[ $((ret & 4)) -ne 0 ] && \
769			tst_res_ TWARN "netstress has warnings"
770		tst_netload_brk TFAIL "expected '$expect_res' but ret: '$ret'"
771	fi
772
773	local median=$(tst_get_median $results)
774	echo "$median" > $rfile
775
776	tst_res_ TPASS "netstress passed, median time $median ms, data:$results"
777
778	return $ret
779}
780
781# Compares results for netload runs.
782# tst_netload_compare TIME_BASE TIME THRESHOLD_LOW [THRESHOLD_HI]
783# TIME_BASE: time taken to run netstress load test - 100%
784# TIME: time that is compared to the base one
785# THRESHOD_LOW: lower limit for TFAIL
786# THRESHOD_HIGH: upper limit for TWARN
787tst_netload_compare()
788{
789	local base_time=$1
790	local new_time=$2
791	local threshold_low=$3
792	local threshold_hi=$4
793
794	if [ -z "$base_time" -o -z "$new_time" -o -z "$threshold_low" ]; then
795		tst_brk_ TBROK "tst_netload_compare: invalid argument(s)"
796	fi
797
798	local res=$(((base_time - new_time) * 100 / base_time))
799	local msg="performance result is ${res}%"
800
801	if [ "$res" -lt "$threshold_low" ]; then
802		tst_res_ TFAIL "$msg < threshold ${threshold_low}%"
803		return
804	fi
805
806	[ "$threshold_hi" ] && [ "$res" -gt "$threshold_hi" ] && \
807		tst_res_ TWARN "$msg > threshold ${threshold_hi}%"
808
809	tst_res_ TPASS "$msg, in range [${threshold_low}:${threshold_hi}]%"
810}
811
812tst_ping_opt_unsupported()
813{
814	ping $@ 2>&1 | grep -q "invalid option"
815}
816
817# tst_ping -c COUNT -s MESSAGE_SIZES -p PATTERN -I IFACE -H HOST
818# Check icmp connectivity
819# IFACE: source interface name or IP address
820# HOST: destination IPv4 or IPv6 address
821# MESSAGE_SIZES: message size array
822tst_ping()
823{
824	# The max number of ICMP echo request
825	local ping_count="${PING_MAX:-500}"
826	local flood_opt="-f"
827	local pattern_opt
828	local msg_sizes
829	local src_iface="$(tst_iface)"
830	local dst_addr="$(tst_ipaddr rhost)"
831	local cmd="ping"
832	local ret=0
833	local opts
834
835	local OPTIND
836	while getopts c:s:p:I:H: opt; do
837		case "$opt" in
838		c) ping_count="$OPTARG";;
839		s) msg_sizes="$OPTARG";;
840		p) pattern_opt="-p $OPTARG";;
841		I) src_iface="$OPTARG";;
842		H) dst_addr="$OPTARG";;
843		*) tst_brk_ TBROK "tst_ping: unknown option: $OPTARG";;
844		esac
845	done
846
847	echo "$dst_addr" | grep -q ':' && cmd="ping6"
848	tst_require_cmds $cmd
849
850	if tst_ping_opt_unsupported $flood_opt; then
851		flood_opt="-i 0.01"
852		[ "$pattern_opt" ] && pattern_opt="-p aa"
853
854		tst_ping_opt_unsupported -i $pattern_opt && \
855			tst_brk_ TCONF "unsupported ping version (old busybox?)"
856	fi
857
858	# ping cmd use 56 as default message size
859	for size in ${msg_sizes:-"56"}; do
860		EXPECT_PASS $cmd -I $src_iface -c $ping_count -s $size \
861			$flood_opt $pattern_opt $dst_addr \>/dev/null
862		ret=$?
863		[ "$ret" -ne 0 ] && break
864	done
865	return $ret
866}
867
868# tst_icmp -t TIMEOUT -s MESSAGE_SIZE_ARRAY OPTS
869# TIMEOUT: total time for the test in seconds
870# OPTS: additional options for ns-icmpv4|6-sender tool
871tst_icmp()
872{
873	local timeout=1
874	local msg_sizes=56
875	local opts=
876	local num=
877	local ret=0
878
879	OPTIND=0
880	while getopts :t:s: opt; do
881		case "$opt" in
882		t) timeout="$OPTARG" ;;
883		s) msg_sizes="$OPTARG" ;;
884		*) opts="-$OPTARG $opts" ;;
885		esac
886	done
887	OPTIND=0
888
889	local num=$(echo "$msg_sizes" | wc -w)
890	timeout="$(($timeout / $num))"
891	[ "$timeout" -eq 0 ] && timeout=1
892
893	opts="${opts}-I $(tst_iface) -S $(tst_ipaddr) -D $(tst_ipaddr rhost) "
894	opts="${opts}-M $(tst_hwaddr rhost) -t $timeout"
895
896	for size in $msg_sizes; do
897		ns-icmpv${TST_IPVER}_sender -s $size $opts
898		ret=$?
899		if [ $ret -eq 0 ]; then
900			tst_res_ TPASS "'ns-icmpv${TST_IPVER}_sender -s $size $opts' pass"
901		else
902			tst_res_ TFAIL "'ns-icmpv${TST_IPVER}_sender -s $size $opts' fail"
903			break
904		fi
905	done
906	return $ret
907}
908
909# tst_set_sysctl NAME VALUE [safe]
910# It can handle netns case when sysctl not namespaceified.
911tst_set_sysctl()
912{
913	local name="$1"
914	local value="$2"
915	local safe=
916	[ "$3" = "safe" ] && safe="-s"
917
918	local rparam=
919	[ "$TST_USE_NETNS" = "yes" ] && rparam="-r '-e'"
920
921	tst_net_run $safe $rparam "sysctl -q -w $name=$value"
922}
923
924tst_cleanup_rhost()
925{
926	tst_rhost_run -c "rm -rf $TST_TMPDIR"
927}
928
929tst_default_max_pkt()
930{
931	local mtu="$(cat /sys/class/net/$(tst_iface)/mtu)"
932
933	echo "$((mtu + mtu / 10))"
934}
935
936# Management Link
937[ -z "$RHOST" ] && TST_USE_NETNS="yes"
938export RHOST="$RHOST"
939export PASSWD="${PASSWD:-}"
940# Don't use it in new tests, use tst_rhost_run() from tst_net.sh instead.
941export LTP_RSH="${LTP_RSH:-ssh -nq}"
942
943# Test Links
944# IPV{4,6}_{L,R}HOST can be set with or without prefix (e.g. IP or IP/prefix),
945# but if you use IP/prefix form, /prefix will be removed by tst_net_vars.
946IPV4_LHOST="${IPV4_LHOST:-10.0.0.2/24}"
947IPV4_RHOST="${IPV4_RHOST:-10.0.0.1/24}"
948IPV6_LHOST="${IPV6_LHOST:-fd00:1:1:1::2/64}"
949IPV6_RHOST="${IPV6_RHOST:-fd00:1:1:1::1/64}"
950
951# tst_net_ip_prefix
952# Strip prefix from IP address and save both If no prefix found sets
953# default prefix.
954#
955# tst_net_iface_prefix reads prefix and interface from rtnetlink.
956# If nothing found sets default prefix value.
957#
958# tst_net_vars exports environment variables related to test links and
959# networks that aren't reachable through the test links.
960#
961# For full list of exported environment variables see:
962# tst_net_ip_prefix -h
963# tst_net_iface_prefix -h
964# tst_net_vars -h
965if [ -z "$_tst_net_parse_variables" ]; then
966	eval $(tst_net_ip_prefix $IPV4_LHOST || echo "exit $?")
967	eval $(tst_net_ip_prefix -r $IPV4_RHOST || echo "exit $?")
968	eval $(tst_net_ip_prefix $IPV6_LHOST || echo "exit $?")
969	eval $(tst_net_ip_prefix -r $IPV6_RHOST || echo "exit $?")
970fi
971
972[ -n "$TST_USE_NETNS" -a "$TST_INIT_NETNS" != "no" ] && init_ltp_netspace
973
974if [ -z "$_tst_net_parse_variables" ]; then
975	eval $(tst_net_iface_prefix $IPV4_LHOST || echo "exit $?")
976	eval $(tst_rhost_run -c 'tst_net_iface_prefix -r '$IPV4_RHOST \
977		|| echo "exit $?")
978	eval $(tst_net_iface_prefix $IPV6_LHOST || echo "exit $?")
979	eval $(tst_rhost_run -c 'tst_net_iface_prefix -r '$IPV6_RHOST \
980		|| echo "exit $?")
981
982	eval $(tst_net_vars $IPV4_LHOST/$IPV4_LPREFIX \
983		$IPV4_RHOST/$IPV4_RPREFIX || echo "exit $?")
984	eval $(tst_net_vars $IPV6_LHOST/$IPV6_LPREFIX \
985		$IPV6_RHOST/$IPV6_RPREFIX || echo "exit $?")
986
987	tst_res_ TINFO "Network config (local -- remote):"
988	tst_res_ TINFO "$LHOST_IFACES -- $RHOST_IFACES"
989	tst_res_ TINFO "$IPV4_LHOST/$IPV4_LPREFIX -- $IPV4_RHOST/$IPV4_RPREFIX"
990	tst_res_ TINFO "$IPV6_LHOST/$IPV6_LPREFIX -- $IPV6_RHOST/$IPV6_RPREFIX"
991	export _tst_net_parse_variables="yes"
992fi
993
994export TST_NET_DATAROOT="$LTPROOT/testcases/bin/datafiles"
995
996export TST_NETLOAD_CLN_REQUESTS="${TST_NETLOAD_CLN_REQUESTS:-10000}"
997export TST_NETLOAD_CLN_NUMBER="${TST_NETLOAD_CLN_NUMBER:-2}"
998export TST_NETLOAD_BINDTODEVICE="${TST_NETLOAD_BINDTODEVICE-1}"
999export TST_NETLOAD_RUN_COUNT="${TST_NETLOAD_RUN_COUNT:-5}"
1000export HTTP_DOWNLOAD_DIR="${HTTP_DOWNLOAD_DIR:-/var/www/html}"
1001export FTP_DOWNLOAD_DIR="${FTP_DOWNLOAD_DIR:-/var/ftp}"
1002export FTP_UPLOAD_DIR="${FTP_UPLOAD_DIR:-/var/ftp/pub}"
1003export FTP_UPLOAD_URLDIR="${FTP_UPLOAD_URLDIR:-pub}"
1004
1005# network/stress tests require additional parameters
1006export NS_DURATION="${NS_DURATION:-10}"
1007export NS_TIMES="${NS_TIMES:-10}"
1008export CONNECTION_TOTAL="${CONNECTION_TOTAL:-10}"
1009export IP_TOTAL="${IP_TOTAL:-100}"
1010export IP_TOTAL_FOR_TCPIP="${IP_TOTAL_FOR_TCPIP:-100}"
1011export ROUTE_TOTAL="${ROUTE_TOTAL:-100}"
1012export MTU_CHANGE_TIMES="${MTU_CHANGE_TIMES:-100}"
1013export IF_UPDOWN_TIMES="${IF_UPDOWN_TIMES:-100}"
1014export DOWNLOAD_BIGFILESIZE="${DOWNLOAD_BIGFILESIZE:-2147483647}"
1015export DOWNLOAD_REGFILESIZE="${DOWNLOAD_REGFILESIZE:-1048576}"
1016export UPLOAD_BIGFILESIZE="${UPLOAD_BIGFILESIZE:-2147483647}"
1017export UPLOAD_REGFILESIZE="${UPLOAD_REGFILESIZE:-1024}"
1018export MCASTNUM_NORMAL="${MCASTNUM_NORMAL:-20}"
1019export MCASTNUM_HEAVY="${MCASTNUM_HEAVY:-4000}"
1020export ROUTE_CHANGE_IP="${ROUTE_CHANGE_IP:-100}"
1021export ROUTE_CHANGE_NETLINK="${ROUTE_CHANGE_NETLINK:-10000}"
1022
1023# Warning: make sure to set valid interface names and IP addresses below.
1024# Set names for test interfaces, e.g. "eth0 eth1"
1025# This is fallback for LHOST_IFACES in case tst_net_vars finds nothing or we
1026# want to use more ifaces.
1027export LHOST_IFACES="${LHOST_IFACES:-eth0}"
1028export RHOST_IFACES="${RHOST_IFACES:-eth0}"
1029# Maximum payload size for 'virt' performance tests, by default eqauls to 1.1 * MTU
1030export TST_NET_MAX_PKT="${TST_NET_MAX_PKT:-$(tst_default_max_pkt)}"
1031# Set corresponding HW addresses, e.g. "00:00:00:00:00:01 00:00:00:00:00:02"
1032export LHOST_HWADDRS="${LHOST_HWADDRS:-$(tst_get_hwaddrs lhost)}"
1033export RHOST_HWADDRS="${RHOST_HWADDRS:-$(tst_get_hwaddrs rhost)}"
1034
1035export NS_ICMPV4_SENDER_DATA_MAXSIZE=1472
1036export NS_ICMPV6_SENDER_DATA_MAXSIZE=1452
1037
1038# More information about network parameters can be found
1039# in the following document: testcases/network/stress/README
1040
1041if [ -n "$TST_USE_LEGACY_API" ]; then
1042	tst_net_remote_tmpdir
1043fi
1044
1045if [ -z "$TST_USE_LEGACY_API" ] && ! tst_cmd_available ping6; then
1046	ping6()
1047	{
1048		ping -6 $@
1049	}
1050	if [ -z "$_tst_net_ping6_warn_printed" ]; then
1051		tst_res_ TINFO "ping6 binary/symlink is missing, using workaround. Please, report missing ping6 to your distribution."
1052		export _tst_net_ping6_warn_printed=1
1053	fi
1054fi
1055