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