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