]> git.ipfire.org Git - thirdparty/lldpd.git/blame - tests/integration-tests.in
build: ensure "make distcheck" work for any value of sysconfdir
[thirdparty/lldpd.git] / tests / integration-tests.in
CommitLineData
8cd1f2d0
VB
1#!/bin/sh
2
3# Integration tests for lldpd. Those tests only run on Linux. They
4# spawn several VM and connect them together, then check lldpcli
5# results to see if everything is in order.
6
7# lldpd should be configure with:
8# ../configure --localstatedir=/var --sysconfdir=/etc --prefix=/usr CFLAGS="-O0 -g"
9
10LABNAME=lldpd
11
12set -e
13
14log_begin_msg () {
15 echo "[…] $1... "
16}
17log_ok_msg () {
18 echo "[✔] $1."
19}
20log_warn_msg () {
21 echo "[⚡] $1!"
22}
23log_error_msg () {
24 echo "[✘] $1!"
25 exit 1
26}
27log_info_msg () {
28 echo "[∗] $1."
29}
30
31check_kernel() {
32 log_begin_msg "Checking kernel version"
33 [ -f "$KERNEL" ] || log_error_msg "Unable to find kernel $KERNEL"
34 [ -r "$KERNEL" ] || log_error_msg "Kernel $KERNEL is not readable.\n Try \`setfacl -m u:$USER:r $KERNEL'"
35
36 # A recent version of `file` is able to extract the
37 # information. Since it is not widely available, let use some hack
38 # method.
39 VERSION=$(cat <<EOF |
40cat
41gunzip \\\037\\\213\\\010 xy
42unxz \\\3757zXZ\\\000 abcde
43bunzip2 BZh xy
44unlzma \\\135\\\0\\\0\\\0 xxx
45EOF
46 while read cmd sig1 sig2; do
47 case $sig1,$sig2 in
48 ,) poss="0:_" ;;
49 *) poss=$(tr "${sig1}\n${sig2}" "\n${sig2}=" < "$KERNEL" | grep -abo "^${sig2}" || true) ;;
50 esac
51 [ -n "$poss" ] || continue
52 for pos in $poss; do
53 pos=${pos%%:*}
54 tail -c+$pos "$KERNEL" | $cmd 2> /dev/null | strings -20 | \
55 grep ^Linux.version | head -1
56 done
57 done | head -1)
58
59 [ -n "$VERSION" ] || log_error_msg "Unable to determine version for $KERNEL"
60 VERSION="${VERSION#Linux version }"
61 VERSION="${VERSION%% *}"
62 log_ok_msg "Found kernel $VERSION"
63
64 log_begin_msg "Check kernel configuration"
65 CONFIG="$(dirname $KERNEL)/config-$VERSION"
66 [ -f "$CONFIG" ] || log_error_msg "Unable to find configuration file $CONFIG"
67 cat <<EOF | while read el; do
689P_FS=[ym]
69NET_9P=[ym]
70NET_9P_VIRTIO=[ym]
71VIRTIO=[ym]
72VIRTIO_PCI=[ym]
73SERIAL_8250=y
74SERIAL_8250_CONSOLE=y
75TMPFS=y
76BLK_DEV_INITRD=y
77DEVTMPFS=[ym]
78EOF
79 grep -qx "CONFIG_$el" $CONFIG || log_error_msg "Kernel not configured with CONFIG_$el"
80 done
81
82 log_begin_msg "Search for modules"
83 for dir in "$(dirname $KERNEL)/lib/modules/$VERSION" "/lib/modules/$VERSION"; do
84 [ -d $dir ] || continue
85 MODULES="$dir"
86 break
87 done
88 if [ -z "$MODULES" ]; then
89 log_warn_msg "Unable to find module directory"
90 else
91 log_ok_msg "Modules are in $MODULES"
92 fi
93}
94
95check_dependencies() {
96 log_begin_msg "Checking if dependencies are present"
97 for exec in \
98 busybox \
99 qemu-system-x86_64 \
583c9a26 100 vde_switch \
1e860d82
VB
101 ip \
102 brctl; do
8cd1f2d0
VB
103 which $exec 2> /dev/null > /dev/null || log_error_msg "$exec is not installed"
104 done
105 log_ok_msg "All dependencies are met"
106}
107
108setup_tmp () {
109 TMP=$(mktemp -d)
110 trap "ret=$? ; cleanup" EXIT
111 log_info_msg "TMP is $TMP"
112}
113
8cd1f2d0
VB
114# Setup a VDE switch
115setup_switch() {
116 nb=$1 ; shift
117 log_begin_msg "Setup switch $nb"
118 cat <<EOF > "$TMP/switch-$nb.conf"
119plugin/add /usr/lib/vde2/plugins/pdump.so
120pdump/filename $TMP/switch-$nb.pcap
121pdump/buffered 0
122pdump/active 1
123EOF
583c9a26 124 vde_switch \
8cd1f2d0 125 --sock "$TMP/switch-$nb.sock" --mgmt "$TMP/switch-management-$nb.sock" \
583c9a26 126 --rcfile "$TMP/switch-$nb.conf" --hub --daemon --pidfile "$TMP/switch-$nb.pid"
8cd1f2d0
VB
127 # Management socket can be used with:
128 # socat - UNIX-CONNECT:"$TMP/switch-management-$nb.sock"
129 log_ok_msg "Switch $nb started"
130}
131
132setup_initrd () {
133 log_begin_msg "Build initrd"
134 DESTDIR=$TMP/initrd
135 mkdir -p $DESTDIR
136
137 # Copy busybox and eventually insmod
138 bins="busybox"
139 busybox --list | grep -qFx insmod || bins="$bins insmod"
140 for bin in $bins; do
141 install -D "$(which $bin)" ${DESTDIR}/bin/$bin
142 for x in $(ldd "$(which $bin)" 2> /dev/null | sed -e '
143 /\//!d;
144 /linux-gate/d;
145 /=>/ {s/.*=>[[:blank:]]*\([^[:blank:]]*\).*/\1/};
146 s/[[:blank:]]*\([^[:blank:]]*\) (.*)/\1/' 2>/dev/null); do
147 [ -f "${DESTDIR}/$x" ] || install -D "$x" "${DESTDIR}/$x"
148 done
149 done
150
151 # Configure busybox
152 for applet in $(${DESTDIR}/bin/busybox --list); do
153 ln -s busybox ${DESTDIR}/bin/${applet}
154 done
155
156 # Add modules
157 [ -z "$MODULES" ] || {
158 modules="9pnet_virtio 9p virtio_pci $UNION"
159 for mod in $modules; do
160 modprobe --all --set-version="${VERSION}" -d ${MODULES}/../../.. \
161 --ignore-install --quiet --show-depends $mod > /dev/null || {
162 log_warn_msg "Unable to find module $mod"
163 log_begin_msg "Continue building initrd"
164 }
165 modprobe --all --set-version="${VERSION}" -d ${MODULES}/../../.. \
166 --ignore-install --quiet --show-depends $mod |
167 while read prefix kmod options ; do
168 [ "${prefix}" = "insmod" ] || continue
169 grep -qFw "$kmod" ${DESTDIR}/modules 2> /dev/null || {
170 install -D "$kmod" "${DESTDIR}/${kmod}"
171 echo $prefix $kmod $options >> ${DESTDIR}/modules
172 }
173 done
174 done
175 }
176
177 # Copy this program
178 cp "$PROGNAME" ${DESTDIR}/init
179
180 # Create /tmp
181 mkdir ${DESTDIR}/tmp
182
183 # Build initrd
184 (cd "${DESTDIR}" && find . | cpio --quiet -R 0:0 -o -H newc | gzip > $TMP/initrd.gz)
185
186 log_ok_msg "initrd built in $TMP/initrd.gz"
187}
188
189random_mac () {
190 # But, not random in fact
191 name=$1
192 net=$2
193 mac=$(echo $name-$net | sha1sum | \
194 awk '{print "50:54:" substr($1,0,2) ":" substr($1, 2, 2) ":" substr($1, 4, 2) ":" substr($1, 6, 2)}')
195 echo $mac
196}
197
198start_vm () {
199 name=$1
200 shift
201
202 netargs=""
203 saveifs="$IFS"
204 IFS=,
205 for net in $NET; do
206 mac=$(random_mac $name $net)
207 netargs="$netargs -net nic,model=virtio,macaddr=$mac,vlan=$net"
208 netargs="$netargs -net vde,sock=$TMP/switch-$net.sock,vlan=$net"
209 done
210 IFS="$saveifs"
211
212 log_info_msg "Start VM $name"
213 # /root is mounted with version 9p2000.u to allow access to /dev,
214 # /sys and to mount new partitions over them. This is not the case
215 # for 9p2000.L.
583c9a26 216 qemu-system-x86_64 \
8cd1f2d0
VB
217 -enable-kvm \
218 -nodefconfig -nodefaults \
219 -display none \
220 -m ${MEM:-128M} \
221 \
583c9a26 222 -chardev file,id=charserial0,path=$name.console \
8cd1f2d0 223 -device isa-serial,chardev=charserial0,id=serial0 \
8cd1f2d0
VB
224 \
225 -fsdev local,security_model=passthrough,id=fsdev-root,path=${ROOT} \
226 -device virtio-9p-pci,id=fs-root,fsdev=fsdev-root,mount_tag=rootshare \
583c9a26 227 -fsdev local,security_model=none,id=fsdev-lab,path=@top_builddir@ \
8cd1f2d0
VB
228 -device virtio-9p-pci,id=fs-lab,fsdev=fsdev-lab,mount_tag=labshare \
229 -fsdev local,security_model=none,id=fsdev-tmp,path=${TMP} \
230 -device virtio-9p-pci,id=fs-tmp,fsdev=fsdev-tmp,mount_tag=tmpshare \
231 -fsdev local,security_model=none,id=fsdev-modules,path=${MODULES}/..,readonly \
232 -device virtio-9p-pci,id=fs-modules,fsdev=fsdev-modules,mount_tag=moduleshare \
233 \
8cd1f2d0
VB
234 -kernel $KERNEL \
235 -no-reboot \
236 -initrd $TMP/initrd.gz \
237 -append "uts=$name console=ttyS0 panic=1 TERM=$TERM quiet" \
238 $netargs \
583c9a26
VB
239 $@ &
240 echo $! > "$TMP/vm-$name.pid"
8cd1f2d0
VB
241}
242
243run() {
244 r=$1
245 shift
246 log_info_msg "$r: execute $*"
247 printf "%s\n" "$*" > $TMP/${r}.command
248 n=0
249 while [ -f $TMP/${r}.command ]; do
03fc915d 250 sleep 0.1
8cd1f2d0 251 n=$((n + 1))
03fc915d 252 [ $n -le 150 ] || {
8cd1f2d0
VB
253 log_error_msg "Timeout while executing command on $r"
254 }
255 done
256}
257
258process_commands() {
259 cd /mnt/lab
260 log_info_msg "Waiting for commands"
261 cmd=/tmp/lab/${uts}.command
262 set +e
263 while true; do
264 while [ ! -f $cmd ]; do
265 sleep 1
266 done
267 log_info_msg "Execute command $(head -1 $cmd)"
268 sh $cmd
269 log_info_msg "End of command: $?"
270 rm $cmd
271 done
272}
273
274start_tests() {
a403df66
VB
275 # Set the environment
276 run R2 ip link set dev iface2 alias "SecondInterface"
8cd1f2d0 277 # Start lldpd on each VM
1884258d
VB
278 run R1 ./libtool execute src/daemon/lldpd -M 1 -L \$PWD/src/client/lldpcli
279 run R2 ./libtool execute src/daemon/lldpd -M 2 -L \$PWD/src/client/lldpcli
280 run R3 ./libtool execute src/daemon/lldpd -M 3 -L \$PWD/src/client/lldpcli
8cd1f2d0
VB
281 sleep 2
282 # Query neighbors
1884258d
VB
283 run R1 ./libtool execute src/client/lldpcli show neighbor detail
284 run R2 ./libtool execute src/client/lldpcli show neighbor detail
285 run R3 ./libtool execute src/client/lldpcli show neighbor detail
8cd1f2d0
VB
286 # Add some VLAN
287 run R2 ip link add link iface2 name iface2.450 type vlan id 450
288 run R2 ip link set up dev iface2.450
289 run R2 ip link add link iface2 name iface2.451 type vlan id 451
290 run R2 ip link set up dev iface2.451
291 run R2 ip link add link iface2 name iface2.452 type vlan id 452
292 run R2 ip link set up dev iface2.452
293 sleep 2
1884258d 294 run R1 ./libtool execute src/client/lldpcli show neighbor detail ports iface2
8cd1f2d0
VB
295 # Remove one
296 run R2 ip link del iface2.451
297 sleep 2
1884258d 298 run R1 ./libtool execute src/client/lldpcli show neighbor detail ports iface2
8cd1f2d0
VB
299 # Add a bond
300 run R3 ip link set down dev iface2
301 run R3 ip link set down dev iface3
302 run R3 ip link set iface2 master bond0
303 run R3 ip link set iface3 master bond0
304 run R3 ip link set up dev bond0
305 sleep 2
1884258d
VB
306 run R1 ./libtool execute src/client/lldpcli show neighbor detail ports iface4
307 run R1 ./libtool execute src/client/lldpcli show neighbor detail ports iface5
8cd1f2d0
VB
308 # Add a VLAN on top of bond
309 run R3 ip link add link bond0 name bond0.453 type vlan id 453
310 run R3 ip link set up dev bond0.453
311 sleep 2
1884258d 312 run R1 ./libtool execute src/client/lldpcli show neighbor detail ports iface4
8cd1f2d0
VB
313 # Add a bridge
314 run R2 brctl addbr br0
315 run R2 brctl addif br0 iface3
316 run R2 ip link set up dev br0
317 sleep 2
1884258d 318 run R1 ./libtool execute src/client/lldpcli show neighbor detail ports iface3
8cd1f2d0 319 # Modify some TLV
1884258d 320 conf="./libtool execute src/client/lldpcli configure ports iface2"
8cd1f2d0
VB
321 run R2 $conf lldp custom-tlv oui 33,44,55 subtype 44 oui-info 45,45,45,45,45
322 run R2 $conf med location elin 911
323 run R2 $conf med location coordinate latitude 48.58667N longitude 2.2014E altitude 117.47 m datum WGS84
324 run R2 $conf med power pd source pse priority high value 5000
325 run R2 $conf dot3 power pse supported enabled paircontrol powerpairs spare class class-3
326 sleep 2
1884258d 327 run R1 ./libtool execute src/client/lldpcli show neighbor detail ports iface2
8cd1f2d0
VB
328 # Configuration should stay when port go down and up
329 run R2 ip link set down dev iface2
330 sleep 2
331 run R2 ip link set up dev iface2
332 sleep 5
1884258d 333 run R1 ./libtool execute src/client/lldpcli show neighbor detail ports iface2
8cd1f2d0
VB
334}
335
336cleanup() {
337 set +e
338 for pid in $TMP/*.pid; do
339 kill -15 -$(cat $pid) 2> /dev/null || true
340 done
341 sleep 1
342 for pid in $TMP/*.pid; do
343 kill -9 -$(cat $pid) 2> /dev/null || true
344 done
345 rm -rf $TMP
8cd1f2d0
VB
346}
347
348# FSM
349export STATE=${STATE:-BEGIN}
350case $$,$STATE in
351 1,BEGIN)
352 # In initrd
353 log_info_msg "initrd started"
354 hostname ${uts}
355 export PATH=/usr/local/bin:/usr/bin:/bin:/sbin:/usr/local/sbin:/usr/sbin
356 export HOME=/root
357
358 [ ! -f /modules ] || {
359 log_info_msg "Loading modules"
360 . /modules
361 }
362
363 log_begin_msg "Setup root file system"
364 mount -n -t tmpfs tmpfs /tmp -o rw
365 mkdir /tmp/target
366 mkdir /tmp/target/ro
367 mkdir /tmp/target/overlay
368 mount -n -t 9p rootshare /tmp/target/overlay -o trans=virtio,version=9p2000.u,ro
369 mount -n -t proc proc /tmp/target/overlay/proc
370 mount -n -t sysfs sys /tmp/target/overlay/sys
371 log_ok_msg "Root file system setup"
372
373 log_begin_msg "Clean /tmp and /run"
374 for fs in /run /var/run /var/tmp /var/log /tmp /mnt; do
375 if [ -d /tmp/target/overlay$fs ] && [ ! -h /tmp/target/overlay$fs ]; then
376 mount -t tmpfs tmpfs /tmp/target/overlay$fs -o rw,nosuid,nodev
377 fi
378 done
379 log_ok_msg "/tmp, /run and others are clean"
380
381 log_begin_msg "Mount /lib/modules"
382 mount -t 9p moduleshare /tmp/target/overlay/lib/modules -o trans=virtio,version=9p2000.L,access=0,ro || \
383 log_error_msg "Unable to mount /lib/modules"
384 log_ok_msg "/root and /lib/modules mounted"
385
386 log_begin_msg "Mount /mnt/lab"
387 mkdir /tmp/target/overlay/mnt/lab
388 mount -t 9p labshare /tmp/target/overlay/mnt/lab -o trans=virtio,version=9p2000.L,access=any,rw || \
389 log_error_msg "Unable to mount /mnt/lab"
390 log_ok_msg "/mnt/lab mounted"
391
392 log_begin_msg "Mount /tmp/lab"
393 mkdir /tmp/target/overlay/tmp/lab
394 mount -t 9p tmpshare /tmp/target/overlay/tmp/lab -o trans=virtio,version=9p2000.L,access=any,rw || \
395 log_error_msg "Unable to mount /tmp/lab"
396 log_ok_msg "/tmp/lab mounted"
397
398 log_info_msg "Change root"
399 export STATE=CHROOTED
583c9a26 400 exec chroot /tmp/target/overlay /mnt/lab/tests/integration-tests
8cd1f2d0
VB
401 ;;
402
403 1,CHROOTED)
404 log_begin_msg "Starting udev"
405 udev_log=err
406 mount -n -o size=10M,mode=0755 -t devtmpfs devtmpfs /dev
407 udevadm info --cleanup-db
408 for udev in /lib/systemd/systemd-udevd /usr/lib/systemd/systemd-udevd $(command -v udevd 2> /dev/null); do
409 [ ! -x $udev ] || break
410 done
411 $udev --daemon
412 udevadm trigger --action=add
413 udevadm settle
414 log_ok_msg "udev started"
415
416 log_info_msg "Setup interfaces"
417 modprobe dummy 2>/dev/null || true
418 modprobe bonding 2>/dev/null || true
419 sleep 0.5 # Some interfaces may take some time to appear
420 # Rename all interfaces to "predictable" and "non-colliding"
421 # name. We don't have if we have eth* or ens* interfaces. Let
422 # take a totally different naming convention.
423 nb=1
424 for iface in $(echo /sys/bus/virtio/drivers/virtio_net/*/net/*); do
425 ip link set name iface$nb dev ${iface##*/}
426 nb=$((nb + 1))
427 done
428 for intf in /sys/class/net/*; do
429 intf=$(basename $intf)
430 ip a l dev $intf 2> /dev/null >/dev/null || continue
431 ip link set up dev $intf
432 done
433
434 log_info_msg "Setup IP addresses"
435 case $uts in
436 R1)
437 ip -4 addr add 192.0.2.15/24 dev iface1
438 ip -6 addr add 2001:db8::cafe:15/64 dev iface1
439 ;;
440 R2)
441 ip -4 addr add 192.0.2.16/24 dev iface1
442 ip -6 addr add 2001:db8::cafe:16/64 dev iface1
443 ;;
444 R3)
445 ip -4 addr add 192.0.2.17/24 dev iface1
446 ip -6 addr add 2001:db8::cafe:17/64 dev iface1
447 ;;
448 esac
a9bec94d 449 rtmon file /mnt/lab/tests/${uts}.rtmon &
583c9a26 450 process_commands 2>&1 | tee /mnt/lab/tests/${uts}.output
8cd1f2d0
VB
451 ;;
452
453 *,BEGIN)
454 # Initial state
455 [ $(id -u) != 0 ] || {
456 log_error_msg "You should not run this as root"
457 exit 1
458 }
459 PROGNAME="$(readlink -f "$0")"
460 PROGARGS="$@"
461 ROOT="$(readlink -f "${ROOT:-/}")" # Root filesystem
462 KERNEL="$(readlink -f "${1:-/boot/vmlinuz-$(uname -r)}")" # Kernel
463 PATH="$PATH":/usr/local/sbin:/usr/sbin:/sbin
464 [ $# -lt 1 ] || shift
583c9a26 465 chmod +x "$PROGNAME"
8cd1f2d0
VB
466
467 check_kernel
468 check_dependencies
8cd1f2d0
VB
469 setup_tmp
470 setup_initrd
471
472 setup_switch 1
473 setup_switch 2
474 setup_switch 3
475 setup_switch 4
476 setup_switch 5
477 sleep 0.3
478
479 NET=1,2,3,4,5 start_vm R1
480 NET=1,2,3 start_vm R2
481 NET=1,4,5 start_vm R3
482
8cd1f2d0
VB
483 start_tests
484
485 sed \
486 -e 's/^\(Interface:.*, Time: 0 day\).*/\1/' \
487 -e 's/^\( SysDescr:\).*/\1/' \
488 -e 's/^\( Hardware Revision: pc-i440fx\).*/\1/' \
489 -e 's/^\( Software Revision: \).*/\1/' \
490 -e 's/^\( Firmware Revision: \).*/\1/' \
1884258d 491 -e 's/command \.\/libtool /command libtool /' \
8cd1f2d0 492 R1.output > R1.output.redacted
583c9a26 493 diff -u @srcdir@/R1.expected R1.output.redacted || \
a9bec94d 494 log_error_msg "Unexpected differences"
8cd1f2d0 495
583c9a26 496 log_info_msg "End of tests"
8cd1f2d0
VB
497 ;;
498esac
499
500# Local Variables:
501# mode: sh
502# indent-tabs-mode: nil
503# sh-basic-offset: 4
504# End: