1#!/bin/bash
2
3# Kernel configuration options.
4OPTIONS=" DEBUG_SPINLOCK DEBUG_ATOMIC_SLEEP DEBUG_MUTEXES DEBUG_RT_MUTEXES"
5OPTIONS="$OPTIONS IPV6 IPV6_ROUTER_PREF IPV6_MULTIPLE_TABLES IPV6_ROUTE_INFO"
6OPTIONS="$OPTIONS TUN SYN_COOKIES IP_ADVANCED_ROUTER IP_MULTIPLE_TABLES"
7OPTIONS="$OPTIONS NETFILTER NETFILTER_ADVANCED NETFILTER_XTABLES"
8OPTIONS="$OPTIONS NETFILTER_XT_MARK NETFILTER_XT_TARGET_MARK"
9OPTIONS="$OPTIONS IP_NF_IPTABLES IP_NF_MANGLE IP_NF_FILTER"
10OPTIONS="$OPTIONS IP6_NF_IPTABLES IP6_NF_MANGLE IP6_NF_FILTER INET6_IPCOMP"
11OPTIONS="$OPTIONS IPV6_PRIVACY IPV6_OPTIMISTIC_DAD"
12OPTIONS="$OPTIONS CONFIG_IPV6_ROUTE_INFO CONFIG_IPV6_ROUTER_PREF"
13OPTIONS="$OPTIONS CONFIG_NETFILTER_XT_TARGET_NFLOG"
14OPTIONS="$OPTIONS CONFIG_NETFILTER_XT_MATCH_QUOTA"
15OPTIONS="$OPTIONS CONFIG_NETFILTER_XT_MATCH_QUOTA2"
16OPTIONS="$OPTIONS CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG"
17OPTIONS="$OPTIONS CONFIG_INET_UDP_DIAG CONFIG_INET_DIAG_DESTROY"
18OPTIONS="$OPTIONS IP_SCTP INET_SCTP_DIAG"
19OPTIONS="$OPTIONS CONFIG_IP_NF_TARGET_REJECT CONFIG_IP_NF_TARGET_REJECT_SKERR"
20OPTIONS="$OPTIONS CONFIG_IP6_NF_TARGET_REJECT CONFIG_IP6_NF_TARGET_REJECT_SKERR"
21OPTIONS="$OPTIONS BPF_SYSCALL XFRM_USER CRYPTO_CBC CRYPTO_CTR"
22OPTIONS="$OPTIONS CRYPTO_HMAC CRYPTO_AES CRYPTO_SHA1 CRYPTO_SHA256 CRYPTO_SHA12"
23OPTIONS="$OPTIONS CRYPTO_USER INET_AH INET_ESP INET_XFRM_MODE"
24OPTIONS="$OPTIONS TRANSPORT INET_XFRM_MODE_TUNNEL INET6_AH INET6_ESP"
25OPTIONS="$OPTIONS INET6_XFRM_MODE_TRANSPORT INET6_XFRM_MODE_TUNNEL"
26OPTIONS="$OPTIONS CRYPTO_SHA256 CRYPTO_SHA512 CRYPTO_AES_X86_64"
27OPTIONS="$OPTIONS CRYPTO_ECHAINIV"
28
29# For 3.1 kernels, where devtmpfs is not on by default.
30OPTIONS="$OPTIONS DEVTMPFS DEVTMPFS_MOUNT"
31
32# These two break the flo kernel due to differences in -Werror on recent GCC.
33DISABLE_OPTIONS=" CONFIG_REISERFS_FS CONFIG_ANDROID_PMEM"
34# This one breaks the fugu kernel due to a nonexistent sem_wait_array.
35DISABLE_OPTIONS="$DISABLE_OPTIONS CONFIG_SYSVIPC"
36
37# How many TAP interfaces to create to provide the VM with real network access
38# via the host. This requires privileges (e.g., root access) on the host.
39#
40# This is not needed to run the tests, but can be used, for example, to allow
41# the VM to update system packages, or to write tests that need access to a
42# real network. The VM does not set up networking by default, but it contains a
43# DHCP client and has the ability to use IPv6 autoconfiguration. This script
44# does not perform any host-level setup beyond configuring tap interfaces;
45# configuring IPv4 NAT and/or IPv6 router advertisements or ND proxying must
46# be done separately.
47NUMTAPINTERFACES=0
48
49# The root filesystem disk image we'll use.
50ROOTFS=net_test.rootfs.20150203
51COMPRESSED_ROOTFS=$ROOTFS.xz
52URL=https://dl.google.com/dl/android/$COMPRESSED_ROOTFS
53
54# Parse arguments and figure out which test to run.
55J=${J:-64}
56MAKE="make"
57OUT_DIR=$(readlink -f ${OUT_DIR:-.})
58KERNEL_DIR=$(readlink -f ${KERNEL_DIR:-.})
59if [ "$OUT_DIR" != "$KERNEL_DIR" ]; then
60    MAKE="$MAKE O=$OUT_DIR"
61fi
62SCRIPT_DIR=$(dirname $(readlink -f $0))
63CONFIG_SCRIPT=${KERNEL_DIR}/scripts/config
64CONFIG_FILE=${OUT_DIR}/.config
65consolemode=
66testmode=
67blockdevice=ubda
68nobuild=0
69norun=0
70
71while [ -n "$1" ]; do
72  if [ "$1" = "--builder" ]; then
73    consolemode="con=null,fd:1"
74    testmode=builder
75    shift
76  elif [ "$1" == "--readonly" ]; then
77    blockdevice="${blockdevice}r"
78    shift
79  elif [ "$1" == "--nobuild" ]; then
80    nobuild=1
81    shift
82  elif [ "$1" == "--norun" ]; then
83    norun=1
84    shift
85  else
86    test=$1
87    break  # Arguments after the test file are passed to the test itself.
88  fi
89done
90
91# Check that test file exists and is readable
92test_file=$SCRIPT_DIR/$test
93if [[ ! -e $test_file ]]; then
94  echo "test file '${test_file}' does not exist"
95  exit 1
96fi
97
98if [[ ! -x $test_file ]]; then
99  echo "test file '${test_file}' is not executable"
100  exit 1
101fi
102
103# Collect trailing arguments to pass to $test
104test_args=${@:2}
105
106function isRunningTest() {
107  [[ -n "$test" ]] && ! (( norun ))
108}
109
110function isBuildOnly() {
111  [[ -z "$test" ]] && (( norun )) && ! (( nobuild ))
112}
113
114if ! isRunningTest && ! isBuildOnly; then
115  echo "Usage:" >&2
116  echo "  $0 [--builder] [--readonly] [--nobuild] <test>" >&2
117  echo "  $0 --norun" >&2
118  exit 1
119fi
120
121cd $OUT_DIR
122echo Running tests from: `pwd`
123
124set -e
125
126# Check if we need to uncompress the disk image.
127# We use xz because it compresses better: to 42M vs 72M (gzip) / 62M (bzip2).
128cd $SCRIPT_DIR
129if [ ! -f $ROOTFS ]; then
130  echo "Deleting $COMPRESSED_ROOTFS" >&2
131  rm -f $COMPRESSED_ROOTFS
132  echo "Downloading $URL" >&2
133  wget -nv $URL
134  echo "Uncompressing $COMPRESSED_ROOTFS" >&2
135  unxz $COMPRESSED_ROOTFS
136fi
137echo "Using $ROOTFS"
138cd -
139
140# If network access was requested, create NUMTAPINTERFACES tap interfaces on
141# the host, and prepare UML command line params to use them. The interfaces are
142# called <user>TAP0, <user>TAP1, on the host, and eth0, eth1, ..., in the VM.
143if (( $NUMTAPINTERFACES > 0 )); then
144  user=${USER:0:10}
145  tapinterfaces=
146  netconfig=
147  for id in $(seq 0 $(( NUMTAPINTERFACES - 1 )) ); do
148    tap=${user}TAP$id
149    tapinterfaces="$tapinterfaces $tap"
150    mac=$(printf fe:fd:00:00:00:%02x $id)
151    netconfig="$netconfig eth$id=tuntap,$tap,$mac"
152  done
153
154  for tap in $tapinterfaces; do
155    if ! ip link list $tap > /dev/null; then
156      echo "Creating tap interface $tap" >&2
157      sudo tunctl -u $USER -t $tap
158      sudo ip link set $tap up
159    fi
160  done
161fi
162
163if [ -n "$KERNEL_BINARY" ]; then
164  nobuild=1
165else
166  KERNEL_BINARY=./linux
167fi
168
169if ((nobuild == 0)); then
170  # Exporting ARCH=um SUBARCH=x86_64 doesn't seem to work, as it "sometimes"
171  # (?) results in a 32-bit kernel.
172
173  # If there's no kernel config at all, create one or UML won't work.
174  [ -f $CONFIG_FILE ] || (cd $KERNEL_DIR && $MAKE defconfig ARCH=um SUBARCH=x86_64)
175
176  # Enable the kernel config options listed in $OPTIONS.
177  cmdline=${OPTIONS// / -e }
178  $CONFIG_SCRIPT --file $CONFIG_FILE $cmdline
179
180  # Disable the kernel config options listed in $DISABLE_OPTIONS.
181  cmdline=${DISABLE_OPTIONS// / -d }
182  $CONFIG_SCRIPT --file $CONFIG_FILE $cmdline
183
184  # olddefconfig doesn't work on old kernels.
185  if ! $MAKE olddefconfig ARCH=um SUBARCH=x86_64 CROSS_COMPILE= ; then
186    cat >&2 << EOF
187
188Warning: "make olddefconfig" failed.
189Perhaps this kernel is too old to support it.
190You may get asked lots of questions.
191Keep enter pressed to accept the defaults.
192
193EOF
194  fi
195
196  # Compile the kernel.
197  $MAKE -j$J linux ARCH=um SUBARCH=x86_64 CROSS_COMPILE=
198fi
199
200if (( norun == 1 )); then
201  exit 0
202fi
203
204# Get the absolute path to the test file that's being run.
205dir=/host$SCRIPT_DIR
206
207# Start the VM.
208exec $KERNEL_BINARY umid=net_test $blockdevice=$SCRIPT_DIR/$ROOTFS \
209    mem=512M init=/sbin/net_test.sh net_test=$dir/$test \
210    net_test_args=\"$test_args\" \
211    net_test_mode=$testmode $netconfig $consolemode >&2
212