• 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-2023 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:H:d: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		d) 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)) -d $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
866tst_netload_compare()
867{
868	local base_time=$1
869	local new_time=$2
870	local threshold_low=$3
871	local threshold_hi=$4
872
873	if [ -z "$base_time" -o -z "$new_time" -o -z "$threshold_low" ]; then
874		tst_brk_ TBROK "tst_netload_compare: invalid argument(s)"
875	fi
876
877	local res=$(((base_time - new_time) * 100 / base_time))
878	local msg="performance result is ${res}%"
879
880	if [ "$res" -lt "$threshold_low" ]; then
881		tst_res_ TFAIL "$msg < threshold ${threshold_low}%"
882		return
883	fi
884
885	[ "$threshold_hi" ] && [ "$res" -gt "$threshold_hi" ] && \
886		tst_res_ TWARN "$msg > threshold ${threshold_hi}%"
887
888	tst_res_ TPASS "$msg, in range [${threshold_low}:${threshold_hi}]%"
889}
890
891tst_ping_opt_unsupported()
892{
893	ping $@ 2>&1 | grep -qE "(invalid|unrecognized) option"
894}
895
896# tst_ping -c COUNT -s MESSAGE_SIZES -p PATTERN -I IFACE -H HOST
897# Check icmp connectivity
898# IFACE: source interface name or IP address
899# HOST: destination IPv4 or IPv6 address
900# MESSAGE_SIZES: message size array
901tst_ping()
902{
903	# The max number of ICMP echo request
904	local ping_count="${PING_MAX:-500}"
905	local flood_opt="-f"
906	local pattern_opt
907	local msg_sizes
908	local src_iface="$(tst_iface)"
909	local dst_addr="$(tst_ipaddr rhost)"
910	local cmd="ping"
911	local ret=0
912	local opts
913
914	local OPTIND
915	while getopts c:s:p:I:H: opt; do
916		case "$opt" in
917		c) ping_count="$OPTARG";;
918		s) msg_sizes="$OPTARG";;
919		p) pattern_opt="-p $OPTARG";;
920		I) src_iface="$OPTARG";;
921		H) dst_addr="$OPTARG";;
922		*) tst_brk_ TBROK "tst_ping: unknown option: $OPTARG";;
923		esac
924	done
925
926	echo "$dst_addr" | grep -q ':' && cmd="ping6"
927	tst_require_cmds $cmd
928
929	if tst_ping_opt_unsupported $flood_opt; then
930		flood_opt="-i 0.01"
931		[ "$pattern_opt" ] && pattern_opt="-p aa"
932
933		tst_ping_opt_unsupported -i $pattern_opt && \
934			tst_brk_ TCONF "unsupported ping version (old busybox?)"
935	fi
936
937	# ping cmd use 56 as default message size
938	for size in ${msg_sizes:-"56"}; do
939		EXPECT_PASS $cmd -I $src_iface -c $ping_count -s $size \
940			$flood_opt $pattern_opt $dst_addr \>/dev/null
941		ret=$?
942		[ "$ret" -ne 0 ] && break
943	done
944	return $ret
945}
946
947# tst_icmp -t TIMEOUT -s MESSAGE_SIZE_ARRAY OPTS
948# TIMEOUT: total time for the test in seconds
949# OPTS: additional options for ns-icmpv4|6-sender tool
950tst_icmp()
951{
952	local timeout=1
953	local msg_sizes=56
954	local opts=
955	local num=
956	local ret=0
957
958	OPTIND=0
959	while getopts :t:s: opt; do
960		case "$opt" in
961		t) timeout="$OPTARG" ;;
962		s) msg_sizes="$OPTARG" ;;
963		*) opts="-$OPTARG $opts" ;;
964		esac
965	done
966	OPTIND=0
967
968	local num=$(echo "$msg_sizes" | wc -w)
969	timeout="$(($timeout / $num))"
970	[ "$timeout" -eq 0 ] && timeout=1
971
972	opts="${opts}-I $(tst_iface) -S $(tst_ipaddr) -D $(tst_ipaddr rhost) "
973	opts="${opts}-M $(tst_hwaddr rhost) -t $timeout"
974
975	for size in $msg_sizes; do
976		ns-icmpv${TST_IPVER}_sender -s $size $opts
977		ret=$?
978		if [ $ret -eq 0 ]; then
979			tst_res_ TPASS "'ns-icmpv${TST_IPVER}_sender -s $size $opts' pass"
980		else
981			tst_res_ TFAIL "'ns-icmpv${TST_IPVER}_sender -s $size $opts' fail"
982			break
983		fi
984	done
985	return $ret
986}
987
988# tst_set_sysctl NAME VALUE [safe]
989# It can handle netns case when sysctl not namespaceified.
990tst_set_sysctl()
991{
992	local name="$1"
993	local value="$2"
994	local safe=
995	[ "$3" = "safe" ] && safe="-s"
996
997	local rparam=
998	[ "$TST_USE_NETNS" = "yes" ] && rparam="-i -r '-e'"
999
1000	tst_net_run $safe -q $rparam "sysctl" "-q -w $name=$value"
1001}
1002
1003tst_cleanup_rhost()
1004{
1005	tst_rhost_run -c "rm -rf $TST_TMPDIR"
1006}
1007
1008tst_default_max_pkt()
1009{
1010	local mtu="$(cat /sys/class/net/$(tst_iface)/mtu)"
1011
1012	echo "$((mtu + mtu / 10))"
1013}
1014
1015# Setup LTP network.
1016#
1017# Used tools:
1018# * tst_net_ip_prefix
1019# Strip prefix from IP address and save both If no prefix found sets
1020# default prefix.
1021# * tst_net_iface_prefix reads prefix and interface from rtnetlink.
1022# If nothing found sets default prefix value.
1023# * tst_net_vars exports environment variables related to test links and
1024# networks that aren't reachable through the test links.
1025#
1026# For full list of exported environment variables see:
1027# tst_net_ip_prefix -h
1028# tst_net_iface_prefix -h
1029# tst_net_vars -h
1030tst_net_setup_network()
1031{
1032	tst_require_cmds tst_net_iface_prefix tst_net_ip_prefix tst_net_vars
1033
1034	eval $(tst_net_ip_prefix $IPV4_LHOST || echo "exit $?")
1035	eval $(tst_net_ip_prefix -r $IPV4_RHOST || echo "exit $?")
1036
1037	[ "$TST_NET_IPV6_ENABLED" = 1 ] && tst_net_detect_ipv6 rhost
1038
1039	if [ "$TST_NET_IPV6_ENABLED" = 1 ]; then
1040		eval $(tst_net_ip_prefix $IPV6_LHOST || echo "exit $?")
1041		eval $(tst_net_ip_prefix -r $IPV6_RHOST || echo "exit $?")
1042	fi
1043
1044	tst_net_use_netns && init_ltp_netspace
1045
1046	eval $(tst_net_iface_prefix $IPV4_LHOST || echo "exit $?")
1047	eval $(tst_rhost_run -c 'tst_net_iface_prefix -r '$IPV4_RHOST \
1048		|| echo "exit $?")
1049	eval $(tst_net_vars $IPV4_LHOST/$IPV4_LPREFIX \
1050		$IPV4_RHOST/$IPV4_RPREFIX || echo "exit $?")
1051
1052	if [ "$TST_NET_IPV6_ENABLED" = 1 ]; then
1053		tst_net_check_ifaces_ipv6
1054		eval $(tst_net_iface_prefix $IPV6_LHOST || echo "exit $?")
1055		eval $(tst_rhost_run -c 'tst_net_iface_prefix -r '$IPV6_RHOST \
1056			|| echo "exit $?")
1057		eval $(tst_net_vars $IPV6_LHOST/$IPV6_LPREFIX \
1058			$IPV6_RHOST/$IPV6_RPREFIX || echo "exit $?")
1059	fi
1060
1061	tst_res_ TINFO "Network config (local -- remote):"
1062	tst_res_ TINFO "$LHOST_IFACES -- $RHOST_IFACES"
1063	tst_res_ TINFO "$IPV4_LHOST/$IPV4_LPREFIX -- $IPV4_RHOST/$IPV4_RPREFIX"
1064	tst_res_ TINFO "$IPV6_LHOST/$IPV6_LPREFIX -- $IPV6_RHOST/$IPV6_RPREFIX"
1065
1066	if [ -n "$TST_USE_LEGACY_API" ]; then
1067		[ "$TST_IPV6" ] && tst_net_require_ipv6
1068		tst_net_remote_tmpdir
1069	fi
1070}
1071
1072[ -n "$TST_USE_LEGACY_API" ] && . test.sh || . tst_test.sh
1073
1074if [ -n "$TST_USE_LEGACY_API" ]; then
1075	tst_net_read_opts "$@"
1076else
1077	if [ "$TST_PARSE_ARGS_CALLER" = "$TST_PARSE_ARGS" ]; then
1078		tst_res_ TWARN "TST_PARSE_ARGS_CALLER same as TST_PARSE_ARGS, unset it ($TST_PARSE_ARGS)"
1079		unset TST_PARSE_ARGS_CALLER
1080	fi
1081	if [ "$TST_SETUP_CALLER" = "$TST_SETUP" ]; then
1082		tst_res_ TWARN "TST_SETUP_CALLER same as TST_SETUP, unset it ($TST_SETUP)"
1083		unset TST_SETUP_CALLER
1084	fi
1085	if [ "$TST_USAGE_CALLER" = "$TST_USAGE" ]; then
1086		tst_res_ TWARN "TST_USAGE_CALLER same as TST_USAGE, unset it ($TST_USAGE)"
1087		unset TST_USAGE_CALLER
1088	fi
1089fi
1090
1091# detect IPv6 support on lhost for tests which don't use test links
1092tst_net_detect_ipv6
1093
1094[ -n "$TST_NET_SKIP_VARIABLE_INIT" ] && return 0
1095
1096# Management Link
1097[ -z "$RHOST" ] && TST_USE_NETNS="yes"
1098export RHOST="$RHOST"
1099export PASSWD="${PASSWD:-}"
1100# Don't use it in new tests, use tst_rhost_run() from tst_net.sh instead.
1101export LTP_RSH="${LTP_RSH:-ssh -nq}"
1102
1103# Test Links
1104# IPV{4,6}_{L,R}HOST can be set with or without prefix (e.g. IP or IP/prefix),
1105# but if you use IP/prefix form, /prefix will be removed by tst_net_vars.
1106IPV4_LHOST="${IPV4_LHOST:-10.0.0.2/24}"
1107IPV4_RHOST="${IPV4_RHOST:-10.0.0.1/24}"
1108IPV6_LHOST="${IPV6_LHOST:-fd00:1:1:1::2/64}"
1109IPV6_RHOST="${IPV6_RHOST:-fd00:1:1:1::1/64}"
1110
1111tst_net_setup_network
1112
1113# More information about network parameters can be found
1114# in the following document: testcases/network/stress/README
1115
1116export TST_NET_DATAROOT="$LTPROOT/testcases/bin/datafiles"
1117
1118export TST_NETLOAD_CLN_REQUESTS="${TST_NETLOAD_CLN_REQUESTS:-10000}"
1119export TST_NETLOAD_CLN_NUMBER="${TST_NETLOAD_CLN_NUMBER:-2}"
1120export TST_NETLOAD_BINDTODEVICE="${TST_NETLOAD_BINDTODEVICE-1}"
1121export TST_NETLOAD_RUN_COUNT="${TST_NETLOAD_RUN_COUNT:-5}"
1122export HTTP_DOWNLOAD_DIR="${HTTP_DOWNLOAD_DIR:-/var/www/html}"
1123export FTP_DOWNLOAD_DIR="${FTP_DOWNLOAD_DIR:-/var/ftp}"
1124export FTP_UPLOAD_DIR="${FTP_UPLOAD_DIR:-/var/ftp/pub}"
1125export FTP_UPLOAD_URLDIR="${FTP_UPLOAD_URLDIR:-pub}"
1126
1127# network/stress tests require additional parameters
1128export NS_DURATION="${NS_DURATION:-10}"
1129export NS_TIMES="${NS_TIMES:-10}"
1130export CONNECTION_TOTAL="${CONNECTION_TOTAL:-10}"
1131export IP_TOTAL="${IP_TOTAL:-100}"
1132export IP_TOTAL_FOR_TCPIP="${IP_TOTAL_FOR_TCPIP:-100}"
1133export ROUTE_TOTAL="${ROUTE_TOTAL:-100}"
1134export MTU_CHANGE_TIMES="${MTU_CHANGE_TIMES:-100}"
1135export IF_UPDOWN_TIMES="${IF_UPDOWN_TIMES:-100}"
1136export DOWNLOAD_BIGFILESIZE="${DOWNLOAD_BIGFILESIZE:-2147483647}"
1137export DOWNLOAD_REGFILESIZE="${DOWNLOAD_REGFILESIZE:-1048576}"
1138export UPLOAD_BIGFILESIZE="${UPLOAD_BIGFILESIZE:-2147483647}"
1139export UPLOAD_REGFILESIZE="${UPLOAD_REGFILESIZE:-1024}"
1140export MCASTNUM_NORMAL="${MCASTNUM_NORMAL:-20}"
1141export MCASTNUM_HEAVY="${MCASTNUM_HEAVY:-4000}"
1142export ROUTE_CHANGE_IP="${ROUTE_CHANGE_IP:-100}"
1143export ROUTE_CHANGE_NETLINK="${ROUTE_CHANGE_NETLINK:-10000}"
1144
1145# Warning: make sure to set valid interface names and IP addresses below.
1146# Set names for test interfaces, e.g. "eth0 eth1"
1147# This is fallback for LHOST_IFACES in case tst_net_vars finds nothing or we
1148# want to use more ifaces.
1149export LHOST_IFACES="${LHOST_IFACES:-eth0}"
1150export RHOST_IFACES="${RHOST_IFACES:-eth0}"
1151# Maximum payload size for 'virt' performance tests, by default eqauls to 1.1 * MTU
1152export TST_NET_MAX_PKT="${TST_NET_MAX_PKT:-$(tst_default_max_pkt)}"
1153# Set corresponding HW addresses, e.g. "00:00:00:00:00:01 00:00:00:00:00:02"
1154export LHOST_HWADDRS="${LHOST_HWADDRS:-$(tst_get_hwaddrs lhost)}"
1155export RHOST_HWADDRS="${RHOST_HWADDRS:-$(tst_get_hwaddrs rhost)}"
1156
1157export NS_ICMPV4_SENDER_DATA_MAXSIZE=1472
1158export NS_ICMPV6_SENDER_DATA_MAXSIZE=1452
1159
1160if [ -z "$TST_USE_LEGACY_API" ] && ! tst_cmd_available ping6; then
1161	ping6()
1162	{
1163		ping -6 $@
1164	}
1165	if [ -z "$_tst_net_ping6_warn_printed" ]; then
1166		tst_res_ TINFO "ping6 binary/symlink is missing, using workaround. Please, report missing ping6 to your distribution."
1167		export _tst_net_ping6_warn_printed=1
1168	fi
1169fi
1170