• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-or-later
3# Copyright (c) Linux Test Project, 2014-2021
4# Copyright (c) 2015 Red Hat, Inc.
5
6TST_CLEANUP=netns_ns_exec_cleanup
7TST_NEEDS_ROOT=1
8TST_NEEDS_CMDS="ip ping"
9TST_NEEDS_DRIVERS="veth"
10. tst_test.sh
11
12# Set to 1 only for test cases using ifconfig (ioctl).
13USE_IFCONFIG=0
14
15# Variables which can be used in test cases (set by netns_setup() function):
16
17# Use in test cases to execute commands inside a namespace. Set to 'ns_exec' or
18# 'ip netns exec' command according to NS_EXEC_PROGRAM argument specified in
19# netns_setup() function call.
20NS_EXEC=
21
22# Set to "net" for ns_create/ns_exec as their options requires
23# to specify a namespace type. Empty for ip command.
24NS_TYPE=
25
26# IP addresses of veth0 (IP0) and veth1 (IP1) devices (ipv4/ipv6 variant
27# is determined according to the IP_VERSION argument specified in netns_setup()
28# function call.
29IP0=
30IP1=
31NETMASK=
32
33# 'ping' or 'ping6' according to the IP_VERSION argument specified
34# in netns_setup() function call.
35tping=
36
37# Network namespaces handles for manipulating and executing commands inside
38# namespaces. For 'ns_exec' handles are PIDs of daemonized processes running
39# in namespaces.
40NS_HANDLE0=
41NS_HANDLE1=
42
43# Adds "inet6 add" to the 'ifconfig' arguments which is required for the ipv6
44# version. Always use with 'ifconfig', even if ipv4 version of a test case is
45# used, in which case IFCONF_IN6_ARG will be empty string. Usage:
46# ifconfig <device> $IFCONF_IN6_ARG IP/NETMASK
47IFCONF_IN6_ARG=
48
49# Sets up global variables which can be used in test cases (documented above),
50# creates two network namespaces and a pair of virtual ethernet devices, each
51# device in one namespace. Each device is then enabled and assigned an IP
52# address according to the function parameters. IFCONF_IN6_ARG variable is set
53# only if ipv6 variant of test case is used (determined by IP_VERSION argument).
54#
55# SYNOPSIS:
56# netns_setup <NS_EXEC_PROGRAM> <IP_VERSION> <COMM_TYPE> <IP4_VETH0>
57#             <IP4_VETH1> <IP6_VETH0> <IP6_VETH1>
58#
59# OPTIONS:
60#	* NS_EXEC_PROGRAM (ns_exec|ip)
61#		Program which will be used to enter and run other commands
62#		inside a network namespace.
63#	* IP_VERSION (ipv4|ipv6)
64#		Version of IP. (ipv4|ipv6)
65#	* COMM_TYPE (netlink|ioctl)
66#		Communication type between kernel and user space
67#		for enabling and assigning IP addresses to the virtual
68#		ethernet devices. Uses 'ip' command for netlink and 'ifconfig'
69#		for ioctl. (If set to ioctl, function also checks the existance
70#		of the 'ifconfig' command.)
71#	* IP4_VETH0, IP4_VETH1
72#		IPv4 addresses for veth0 and veth1 devices.
73#	* IP6_VETH0, IP6_VETH1
74#		IPv6 addresses for veth0 and veth1 devices.
75#
76# On success function returns, on error tst_brk is called and TC is terminated.
77netns_setup()
78{
79	case "$1" in
80	ns_exec)
81		setns_check
82		[ $? -eq 32 ] && tst_brk TCONF "setns not supported"
83
84		NS_TYPE="net"
85		netns_ns_exec_setup
86		TST_CLEANUP=netns_ns_exec_cleanup
87		;;
88	ip)
89		netns_ip_setup
90		TST_CLEANUP=netns_ip_cleanup
91		;;
92	*)
93		tst_brk TBROK \
94		"first argument must be a program used to enter a network namespace (ns_exec|ip)"
95		;;
96	esac
97
98	case "$3" in
99	netlink)
100		;;
101	ioctl)
102		USE_IFCONFIG=1
103		tst_require_cmds ifconfig
104		;;
105	*)
106		tst_brk TBROK \
107		"third argument must be a comm. type between kernel and user space (netlink|ioctl)"
108		;;
109	esac
110
111	if [ -z "$4" ]; then
112		tst_brk TBROK "fourth argument must be the IPv4 address for veth0"
113	fi
114	if [ -z "$5" ]; then
115		tst_brk TBROK "fifth argument must be the IPv4 address for veth1"
116	fi
117	if [ -z "$6" ]; then
118		tst_brk TBROK "sixth argument must be the IPv6 address for veth0"
119	fi
120	if [ -z "$7" ]; then
121		tst_brk TBROK "seventh argument must be the IPv6 address for veth1"
122	fi
123
124	case "$2" in
125	ipv4)
126		IP0=$4
127		IP1=$5
128		tping="ping"
129		NETMASK=24
130		;;
131	ipv6)
132		IFCONF_IN6_ARG="inet6 add"
133		IP0=$6
134		IP1=$7
135
136		if tst_cmd_available ping6; then
137			tping="ping6"
138		else
139			tping="ping -6"
140			tst_res_ TINFO "ping6 binary/symlink is missing, using workaround. Please, report missing ping6 to your distribution."
141		fi
142		NETMASK=64
143		;;
144	*)
145		tst_brk TBROK "second argument must be an ip version (ipv4|ipv6)"
146		;;
147	esac
148
149	netns_set_ip
150}
151
152# Sets up NS_EXEC to use 'ns_exec', creates two network namespaces and stores
153# their handles into NS_HANDLE0 and NS_HANDLE1 variables (in this case handles
154# are PIDs of daemonized processes running in these namespaces). Virtual
155# ethernet device is then created for each namespace.
156netns_ns_exec_setup()
157{
158	local ret
159
160	NS_EXEC="ns_exec"
161
162	NS_HANDLE0=$(ns_create $NS_TYPE)
163	if [ $? -eq 1 ]; then
164		tst_res TINFO "$NS_HANDLE0"
165		tst_brk TBROK "unable to create a new network namespace"
166	fi
167
168	NS_HANDLE1=$(ns_create $NS_TYPE)
169	if [ $? -eq 1 ]; then
170		tst_res TINFO "$NS_HANDLE1"
171		tst_brk TBROK "unable to create a new network namespace"
172	fi
173
174	$NS_EXEC $NS_HANDLE0 $NS_TYPE ip link add veth0 type veth peer name veth1 || \
175		tst_brk TBROK "unable to create veth pair devices"
176
177	$NS_EXEC $NS_HANDLE0 $NS_TYPE ns_ifmove veth1 $NS_HANDLE1
178	ret=$?
179	[ $ret -eq 0 ] && return
180	[ $ret -eq 32 ] && tst_brk TCONF "IFLA_NET_NS_PID not supported"
181
182	tst_brk TBROK "unable to add device veth1 to the separate network namespace"
183}
184
185# Sets up NS_EXEC to use 'ip netns exec', creates two network namespaces
186# and stores their handles into NS_HANDLE0 and NS_HANDLE1 variables. Virtual
187# ethernet device is then created for each namespace.
188netns_ip_setup()
189{
190	ip netns > /dev/null || \
191		tst_brk TCONF "ip without netns support (required iproute2 >= ss111010 - v3.0.0)"
192
193	NS_EXEC="ip netns exec"
194
195	NS_HANDLE0=tst_net_ns0
196	NS_HANDLE1=tst_net_ns1
197
198	ip netns del $NS_HANDLE0 2>/dev/null
199	ip netns del $NS_HANDLE1 2>/dev/null
200
201	ip netns add $NS_HANDLE0 || \
202		tst_brk TBROK "unable to create a new network namespace"
203	ip netns add $NS_HANDLE1 || \
204		tst_brk TBROK "unable to create a new network namespace"
205
206	$NS_EXEC $NS_HANDLE0 ip link add veth0 type veth peer name veth1 || \
207		tst_brk TBROK "unable to create veth pair devices"
208
209	$NS_EXEC $NS_HANDLE0 ip link set veth1 netns $NS_HANDLE1 || \
210		tst_brk TBROK "unable to add device veth1 to the separate network namespace"
211}
212
213# Enables virtual ethernet devices and assigns IP addresses for both
214# of them (IPv4/IPv6 variant is decided by netns_setup() function).
215netns_set_ip()
216{
217	[ "$NS_EXEC" ] || tst_brk TBROK "netns_setup() function must be called first"
218
219	# This applies only for ipv6 variant:
220	# Do not accept Router Advertisements (accept_ra) and do not use
221	# Duplicate Address Detection (accept_dad) which uses Neighbor
222	# Discovery Protocol - the problem is that until DAD can confirm that
223	# there is no other host with the same address, the address is
224	# considered to be "tentative" (attempts to bind() to the address fail
225	# with EADDRNOTAVAIL) which may cause problems for tests using ipv6.
226	echo 0 | $NS_EXEC $NS_HANDLE0 $NS_TYPE \
227		tee /proc/sys/net/ipv6/conf/veth0/accept_dad \
228		/proc/sys/net/ipv6/conf/veth0/accept_ra >/dev/null
229	echo 0 | $NS_EXEC $NS_HANDLE1 $NS_TYPE \
230		tee /proc/sys/net/ipv6/conf/veth1/accept_dad \
231		/proc/sys/net/ipv6/conf/veth1/accept_ra >/dev/null
232
233	case $USE_IFCONFIG in
234	1)
235		$NS_EXEC $NS_HANDLE0 $NS_TYPE ifconfig veth0 $IFCONF_IN6_ARG $IP0/$NETMASK ||
236			tst_brk TBROK "adding address to veth0 failed"
237		$NS_EXEC $NS_HANDLE1 $NS_TYPE ifconfig veth1 $IFCONF_IN6_ARG $IP1/$NETMASK ||
238			tst_brk TBROK "adding address to veth1 failed"
239		$NS_EXEC $NS_HANDLE0 $NS_TYPE ifconfig veth0 up ||
240			tst_brk TBROK "enabling veth0 device failed"
241		$NS_EXEC $NS_HANDLE1 $NS_TYPE ifconfig veth1 up ||
242			tst_brk TBROK "enabling veth1 device failed"
243		;;
244	*)
245		$NS_EXEC $NS_HANDLE0 $NS_TYPE ip address add $IP0/$NETMASK dev veth0 ||
246			tst_brk TBROK "adding address to veth0 failed"
247		$NS_EXEC $NS_HANDLE1 $NS_TYPE ip address add $IP1/$NETMASK dev veth1 ||
248			tst_brk TBROK "adding address to veth1 failed"
249		$NS_EXEC $NS_HANDLE0 $NS_TYPE ip link set veth0 up ||
250			tst_brk TBROK "enabling veth0 device failed"
251		$NS_EXEC $NS_HANDLE1 $NS_TYPE ip link set veth1 up ||
252			tst_brk TBROK "enabling veth1 device failed"
253		;;
254	esac
255}
256
257netns_ns_exec_cleanup()
258{
259	[ "$NS_EXEC" ] || return
260
261	# removes veth0 device (which also removes the paired veth1 device)
262	$NS_EXEC $NS_HANDLE0 $NS_TYPE ip link delete veth0
263
264	kill -9 $NS_HANDLE0 2>/dev/null
265	kill -9 $NS_HANDLE1 2>/dev/null
266}
267
268
269netns_ip_cleanup()
270{
271	[ "$NS_EXEC" ] || return
272
273	# removes veth0 device (which also removes the paired veth1 device)
274	$NS_EXEC $NS_HANDLE0 ip link delete veth0
275
276	ip netns del $NS_HANDLE0 2>/dev/null
277	ip netns del $NS_HANDLE1 2>/dev/null
278}
279