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