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