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