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