xref: /aosp_15_r20/external/ltp/testcases/kernel/containers/netns/netns_lib.sh (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-or-later
3# Copyright (c) 2022 Petr Vorel <[email protected]>
4# Copyright (c) Linux Test Project, 2014-2023
5# Copyright (c) 2015 Red Hat, Inc.
6
7TST_NEEDS_ROOT=1
8TST_NEEDS_CMDS="ip ping"
9TST_NEEDS_DRIVERS="veth"
10
11TST_OPTS="eI"
12TST_PARSE_ARGS="netns_parse_args"
13TST_USAGE="netns_usage"
14TST_SETUP="${TST_SETUP:-netns_setup}"
15TST_CLEANUP="${TST_CLEANUP:-netns_cleanup}"
16
17TST_NET_SKIP_VARIABLE_INIT=1
18
19# from tst_net_vars.c
20IPV4_NET16_UNUSED="10.23"
21IPV6_NET32_UNUSED="fd00:23"
22
23# Set to "net" for tst_ns_create/tst_ns_exec as their options requires
24# to specify a namespace type. Empty for ip command.
25NS_TYPE=
26
27# 'ping' or 'ping6'
28tping=
29
30# Network namespaces handles for manipulating and executing commands inside
31# namespaces. For 'tst_ns_exec' handles are PIDs of daemonized processes running
32# in namespaces.
33NS_HANDLE0=
34NS_HANDLE1=
35
36# Adds "inet6 add" to the 'ifconfig' arguments which is required for the ipv6
37# version. Always use with 'ifconfig', even if ipv4 version of a test case is
38# used, in which case IFCONF_IN6_ARG will be empty string. Usage:
39# ifconfig <device> $IFCONF_IN6_ARG IP/NETMASK
40IFCONF_IN6_ARG=
41
42# Program which will be used to enter and run other commands inside a network namespace.
43# (tst_ns_exec|ip)
44NS_EXEC="ip"
45
46# Communication type between kernel and user space for basic setup: enabling and
47# assigning IP addresses to the virtual ethernet devices. (Uses 'ip' command for
48# netlink and 'ifconfig' for ioctl.)
49# (netlink|ioctl)
50COMM_TYPE="netlink"
51
52do_cleanup=
53
54netns_parse_args()
55{
56	case $1 in
57	e) NS_EXEC="tst_ns_exec" ;;
58	I) COMM_TYPE="ioctl"; tst_require_cmds ifconfig ;;
59	esac
60}
61
62netns_usage()
63{
64	echo "usage: $0 [ -e ] [ -I ]"
65	echo "OPTIONS"
66	echo "-e      Use tst_ns_exec instead of ip"
67	echo "-I      Test ioctl (with ifconfig) instead of netlink (with ip)"
68}
69
70netns_setup()
71{
72	if [ "$NS_EXEC" = "ip" ]; then
73		netns_ip_setup
74	else
75		NS_TYPE="net"
76		netns_ns_exec_setup
77	fi
78
79	IP0=$(tst_ipaddr_un -c 1)
80	IP1=$(tst_ipaddr_un -c 2)
81
82	if [ "$TST_IPV6" ]; then
83		IFCONF_IN6_ARG="inet6 add"
84		NETMASK=64
85	else
86		NETMASK=24
87	fi
88
89	tping=ping$TST_IPV6
90
91	netns_set_ip
92
93	tst_res TINFO "testing netns over $COMM_TYPE with $NS_EXEC $PROG"
94	do_cleanup=1
95}
96
97netns_cleanup()
98{
99	[ "$do_cleanup" ] || return
100
101	if [ "$NS_EXEC" = "ip" ]; then
102		netns_ip_cleanup
103	else
104		netns_ns_exec_cleanup
105	fi
106}
107
108# Sets up NS_EXEC to use 'tst_ns_exec', creates two network namespaces and stores
109# their handles into NS_HANDLE0 and NS_HANDLE1 variables (in this case handles
110# are PIDs of daemonized processes running in these namespaces). Virtual
111# ethernet device is then created for each namespace.
112netns_ns_exec_setup()
113{
114	local ret
115
116	NS_EXEC="tst_ns_exec"
117
118	NS_HANDLE0=$(tst_ns_create $NS_TYPE)
119	if [ $? -eq 1 ]; then
120		tst_res TINFO "$NS_HANDLE0"
121		tst_brk TBROK "unable to create a new network namespace"
122	fi
123
124	NS_HANDLE1=$(tst_ns_create $NS_TYPE)
125	if [ $? -eq 1 ]; then
126		tst_res TINFO "$NS_HANDLE1"
127		tst_brk TBROK "unable to create a new network namespace"
128	fi
129
130	$NS_EXEC $NS_HANDLE0 $NS_TYPE ip link add veth0 type veth peer name veth1 || \
131		tst_brk TBROK "unable to create veth pair devices"
132
133	$NS_EXEC $NS_HANDLE0 $NS_TYPE tst_ns_ifmove veth1 $NS_HANDLE1
134	ret=$?
135	[ $ret -eq 0 ] && return
136	[ $ret -eq 32 ] && tst_brk TCONF "IFLA_NET_NS_PID not supported"
137
138	tst_brk TBROK "unable to add device veth1 to the separate network namespace"
139}
140
141# Sets up NS_EXEC to use 'ip netns exec', creates two network namespaces
142# and stores their handles into NS_HANDLE0 and NS_HANDLE1 variables. Virtual
143# ethernet device is then created for each namespace.
144netns_ip_setup()
145{
146	ip netns > /dev/null || \
147		tst_brk TCONF "ip without netns support (required iproute2 >= ss111010 - v3.0.0)"
148
149	NS_EXEC="ip netns exec"
150
151	NS_HANDLE0=tst_net_ns0
152	NS_HANDLE1=tst_net_ns1
153
154	ip netns del $NS_HANDLE0 2>/dev/null
155	ip netns del $NS_HANDLE1 2>/dev/null
156
157	ROD ip netns add $NS_HANDLE0
158	ROD ip netns add $NS_HANDLE1
159
160	ROD $NS_EXEC $NS_HANDLE0 ip link add veth0 type veth peer name veth1
161	ROD $NS_EXEC $NS_HANDLE0 ip link set veth1 netns $NS_HANDLE1
162}
163
164# Enables virtual ethernet devices and assigns IP addresses for both
165# of them (IPv4/IPv6 variant is decided by netns_setup() function).
166netns_set_ip()
167{
168	local cmd="ip"
169
170	# This applies only for ipv6 variant:
171	# Do not accept Router Advertisements (accept_ra) and do not use
172	# Duplicate Address Detection (accept_dad) which uses Neighbor
173	# Discovery Protocol - the problem is that until DAD can confirm that
174	# there is no other host with the same address, the address is
175	# considered to be "tentative" (attempts to bind() to the address fail
176	# with EADDRNOTAVAIL) which may cause problems for tests using ipv6.
177	if [ "$TST_IPV6" ]; then
178		echo 0 | $NS_EXEC $NS_HANDLE0 $NS_TYPE \
179			tee /proc/sys/net/ipv6/conf/veth0/accept_dad \
180			/proc/sys/net/ipv6/conf/veth0/accept_ra >/dev/null
181		echo 0 | $NS_EXEC $NS_HANDLE1 $NS_TYPE \
182			tee /proc/sys/net/ipv6/conf/veth1/accept_dad \
183			/proc/sys/net/ipv6/conf/veth1/accept_ra >/dev/null
184	fi
185
186	[ "$COMM_TYPE" = "ioctl" ] && cmd="ifconfig"
187
188	if [ "$COMM_TYPE" = "netlink" ]; then
189		ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ip address add $IP0/$NETMASK dev veth0
190		ROD $NS_EXEC $NS_HANDLE1 $NS_TYPE ip address add $IP1/$NETMASK dev veth1
191		ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ip link set veth0 up
192		ROD $NS_EXEC $NS_HANDLE1 $NS_TYPE ip link set veth1 up
193	else
194		ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ifconfig veth0 $IFCONF_IN6_ARG $IP0/$NETMASK
195		ROD $NS_EXEC $NS_HANDLE1 $NS_TYPE ifconfig veth1 $IFCONF_IN6_ARG $IP1/$NETMASK
196		ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ifconfig veth0 up
197		ROD $NS_EXEC $NS_HANDLE1 $NS_TYPE ifconfig veth1 up
198	fi
199}
200
201netns_ns_exec_cleanup()
202{
203	[ "$NS_EXEC" ] || return
204
205	# removes veth0 device (which also removes the paired veth1 device)
206	$NS_EXEC $NS_HANDLE0 $NS_TYPE ip link delete veth0
207
208	kill -9 $NS_HANDLE0 2>/dev/null
209	kill -9 $NS_HANDLE1 2>/dev/null
210}
211
212
213netns_ip_cleanup()
214{
215	[ "$NS_EXEC" ] || return
216
217	# removes veth0 device (which also removes the paired veth1 device)
218	$NS_EXEC $NS_HANDLE0 ip link delete veth0
219
220	ip netns del $NS_HANDLE0 2>/dev/null
221	ip netns del $NS_HANDLE1 2>/dev/null
222}
223
224. tst_net.sh
225