]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
build: add some integration tests 0.9.0
authorVincent Bernat <vincent@bernat.im>
Sun, 10 Jan 2016 12:34:32 +0000 (13:34 +0100)
committerVincent Bernat <vincent@bernat.im>
Sun, 10 Jan 2016 12:34:32 +0000 (13:34 +0100)
README.md
tests/Makefile.am
tests/R1.expected [new file with mode: 0644]
tests/integration-tests.in [new file with mode: 0755]

index dde80a97c41f162e22f5f7bcd0e7a2302e976132..fc253ab3b81d61f0fa6cb4cb465522bb38cc599e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -235,6 +235,12 @@ that:
     mv *.pcap inputs
     afl-fuzz -i inputs -o outputs ./decode @@
 
+There is a general test suite with `make check`. It's also possible to
+run integration tests with `./tests/integration-tests`. Those are not
+very flexible and may or may not work depending on your platform. Also
+check the content of `tests/lldpcli.conf`. It's a configuration file
+that should cover all commands present in lldpcli.
+
 Embedding
 ---------
 
index b06d7f81a8b099cf37c612fab896aad7c0478b05..e8c41fc017d3ffa928905eb3a5bcf0ca7533626f 100644 (file)
@@ -52,3 +52,9 @@ decode_SOURCES = decode.c \
 endif
 
 MOSTLYCLEANFILES = *.pcap
+
+TEMPLATES  = integration-tests
+EXTRA_DIST = integration-tests.in R1.expected
+CLEANFILES = $(TEMPLATES)
+integration-tests: integration-tests.in
+include $(top_srcdir)/edit.am
diff --git a/tests/R1.expected b/tests/R1.expected
new file mode 100644 (file)
index 0000000..fc346a9
--- /dev/null
@@ -0,0 +1,497 @@
+[∗] Waiting for commands.
+[∗] Execute command libtool execute src/daemon/lldpd -M 1 -L $PWD/src/client/lldpcli.
+[∗] End of command: 0.
+[∗] Execute command libtool execute src/client/lldpcli show neighbor detail.
+-------------------------------------------------------------------------------
+LLDP neighbors:
+-------------------------------------------------------------------------------
+Interface:    iface1, via: LLDP, RID: 1, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:b3:3c:2c:36
+    SysName:      R2
+    SysDescr:
+    MgmtIP:       192.0.2.16
+    MgmtIP:       2001:db8::cafe:16
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Station, on
+  Port:        
+    PortID:       mac 50:54:b3:3c:2c:36
+    PortDescr:    iface1
+  LLDP-MED:    
+    Device Type:  Media Endpoint (Class II)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+Interface:    iface1, via: LLDP, RID: 2, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:07:79:57:69
+    SysName:      R3
+    SysDescr:
+    MgmtIP:       192.0.2.17
+    MgmtIP:       2001:db8::cafe:17
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Tel, on
+    Capability:   Station, on
+  Port:        
+    PortID:       mac 50:54:07:79:57:69
+    PortDescr:    iface1
+  LLDP-MED:    
+    Device Type:  Communication Device Endpoint (Class III)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+Interface:    iface2, via: LLDP, RID: 1, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:b3:3c:2c:36
+    SysName:      R2
+    SysDescr:
+    MgmtIP:       192.0.2.16
+    MgmtIP:       2001:db8::cafe:16
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Station, on
+  Port:        
+    PortID:       mac 50:54:0e:ec:6e:77
+    PortDescr:    iface2
+  LLDP-MED:    
+    Device Type:  Media Endpoint (Class II)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+Interface:    iface3, via: LLDP, RID: 1, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:b3:3c:2c:36
+    SysName:      R2
+    SysDescr:
+    MgmtIP:       192.0.2.16
+    MgmtIP:       2001:db8::cafe:16
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Station, on
+  Port:        
+    PortID:       mac 50:54:5e:ed:e2:df
+    PortDescr:    iface3
+  LLDP-MED:    
+    Device Type:  Media Endpoint (Class II)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+Interface:    iface4, via: LLDP, RID: 2, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:07:79:57:69
+    SysName:      R3
+    SysDescr:
+    MgmtIP:       192.0.2.17
+    MgmtIP:       2001:db8::cafe:17
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Tel, on
+    Capability:   Station, on
+  Port:        
+    PortID:       mac 50:54:30:01:78:dd
+    PortDescr:    iface2
+  LLDP-MED:    
+    Device Type:  Communication Device Endpoint (Class III)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+Interface:    iface5, via: LLDP, RID: 2, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:07:79:57:69
+    SysName:      R3
+    SysDescr:
+    MgmtIP:       192.0.2.17
+    MgmtIP:       2001:db8::cafe:17
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Tel, on
+    Capability:   Station, on
+  Port:        
+    PortID:       mac 50:54:ef:f4:f5:bf
+    PortDescr:    iface3
+  LLDP-MED:    
+    Device Type:  Communication Device Endpoint (Class III)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+[∗] End of command: 0.
+[∗] Execute command libtool execute src/client/lldpcli show neighbor detail ports iface2.
+-------------------------------------------------------------------------------
+LLDP neighbors:
+-------------------------------------------------------------------------------
+Interface:    iface2, via: LLDP, RID: 1, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:b3:3c:2c:36
+    SysName:      R2
+    SysDescr:
+    MgmtIP:       192.0.2.16
+    MgmtIP:       2001:db8::cafe:16
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Station, on
+  Port:        
+    PortID:       mac 50:54:0e:ec:6e:77
+    PortDescr:    iface2
+  VLAN:         450 iface2.450
+  VLAN:         451 iface2.451
+  VLAN:         452 iface2.452
+  LLDP-MED:    
+    Device Type:  Media Endpoint (Class II)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+[∗] End of command: 0.
+[∗] Execute command libtool execute src/client/lldpcli show neighbor detail ports iface2.
+-------------------------------------------------------------------------------
+LLDP neighbors:
+-------------------------------------------------------------------------------
+Interface:    iface2, via: LLDP, RID: 1, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:b3:3c:2c:36
+    SysName:      R2
+    SysDescr:
+    MgmtIP:       192.0.2.16
+    MgmtIP:       2001:db8::cafe:16
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Station, on
+  Port:        
+    PortID:       mac 50:54:0e:ec:6e:77
+    PortDescr:    iface2
+  VLAN:         450 iface2.450
+  VLAN:         452 iface2.452
+  LLDP-MED:    
+    Device Type:  Media Endpoint (Class II)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+[∗] End of command: 0.
+[∗] Execute command libtool execute src/client/lldpcli show neighbor detail ports iface4.
+-------------------------------------------------------------------------------
+LLDP neighbors:
+-------------------------------------------------------------------------------
+Interface:    iface4, via: LLDP, RID: 2, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:07:79:57:69
+    SysName:      R3
+    SysDescr:
+    MgmtIP:       192.0.2.17
+    MgmtIP:       2001:db8::cafe:17
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Tel, on
+    Capability:   Station, off
+  Port:        
+    PortID:       mac 50:54:30:01:78:dd
+    PortDescr:    iface2
+    Port is aggregated. PortAggregID: 6
+  LLDP-MED:    
+    Device Type:  Communication Device Endpoint (Class III)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+[∗] End of command: 0.
+[∗] Execute command libtool execute src/client/lldpcli show neighbor detail ports iface5.
+-------------------------------------------------------------------------------
+LLDP neighbors:
+-------------------------------------------------------------------------------
+Interface:    iface5, via: LLDP, RID: 2, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:07:79:57:69
+    SysName:      R3
+    SysDescr:
+    MgmtIP:       192.0.2.17
+    MgmtIP:       2001:db8::cafe:17
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Tel, on
+    Capability:   Station, off
+  Port:        
+    PortID:       mac 50:54:ef:f4:f5:bf
+    PortDescr:    iface3
+    Port is aggregated. PortAggregID: 6
+  LLDP-MED:    
+    Device Type:  Communication Device Endpoint (Class III)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+[∗] End of command: 0.
+[∗] Execute command libtool execute src/client/lldpcli show neighbor detail ports iface4.
+-------------------------------------------------------------------------------
+LLDP neighbors:
+-------------------------------------------------------------------------------
+Interface:    iface4, via: LLDP, RID: 2, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:07:79:57:69
+    SysName:      R3
+    SysDescr:
+    MgmtIP:       192.0.2.17
+    MgmtIP:       2001:db8::cafe:17
+    Capability:   Bridge, off
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Tel, on
+    Capability:   Station, off
+  Port:        
+    PortID:       mac 50:54:30:01:78:dd
+    PortDescr:    iface2
+    Port is aggregated. PortAggregID: 6
+  VLAN:         453 bond0.453
+  LLDP-MED:    
+    Device Type:  Communication Device Endpoint (Class III)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+[∗] End of command: 0.
+[∗] Execute command libtool execute src/client/lldpcli show neighbor detail ports iface3.
+-------------------------------------------------------------------------------
+LLDP neighbors:
+-------------------------------------------------------------------------------
+Interface:    iface3, via: LLDP, RID: 1, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:b3:3c:2c:36
+    SysName:      R2
+    SysDescr:
+    MgmtIP:       192.0.2.16
+    MgmtIP:       2001:db8::cafe:16
+    Capability:   Bridge, on
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Station, off
+  Port:        
+    PortID:       mac 50:54:5e:ed:e2:df
+    PortDescr:    iface3
+  LLDP-MED:    
+    Device Type:  Media Endpoint (Class II)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+-------------------------------------------------------------------------------
+[∗] End of command: 0.
+[∗] Execute command libtool execute src/client/lldpcli show neighbor detail ports iface2.
+-------------------------------------------------------------------------------
+LLDP neighbors:
+-------------------------------------------------------------------------------
+Interface:    iface2, via: LLDP, RID: 1, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:b3:3c:2c:36
+    SysName:      R2
+    SysDescr:
+    MgmtIP:       192.0.2.16
+    MgmtIP:       2001:db8::cafe:16
+    Capability:   Bridge, on
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Station, off
+  Port:        
+    PortID:       mac 50:54:0e:ec:6e:77
+    PortDescr:    iface2
+    MDI Power:    supported: yes, enabled: yes, pair control: yes
+      Device type:  PSE
+      Power pairs:  spare
+      Class:        class 3
+  VLAN:         450 iface2.450
+  VLAN:         452 iface2.452
+  LLDP-MED:    
+    Device Type:  Media Endpoint (Class II)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    LLDP-MED Location Identification: Type: Coordinates, Geoid: WGS84
+      Latitude:     48.58666N
+      Longitude:    2.2013E
+      Altitude:     m 117.46
+    LLDP-MED Location Identification: Type: ELIN
+      ECS ELIN:     911
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+  UnknownTLVs: 
+    TLV:          OUI: 33,44,55, SubType: 44, Len: 5 45,45,45,45,45
+-------------------------------------------------------------------------------
+[∗] End of command: 0.
+[∗] Execute command libtool execute src/client/lldpcli show neighbor detail ports iface2.
+-------------------------------------------------------------------------------
+LLDP neighbors:
+-------------------------------------------------------------------------------
+Interface:    iface2, via: LLDP, RID: 1, Time: 0 day
+  Chassis:     
+    ChassisID:    mac 50:54:b3:3c:2c:36
+    SysName:      R2
+    SysDescr:
+    MgmtIP:       192.0.2.16
+    MgmtIP:       2001:db8::cafe:16
+    Capability:   Bridge, on
+    Capability:   Router, off
+    Capability:   Wlan, off
+    Capability:   Station, off
+  Port:        
+    PortID:       mac 50:54:0e:ec:6e:77
+    PortDescr:    iface2
+    MDI Power:    supported: yes, enabled: yes, pair control: yes
+      Device type:  PSE
+      Power pairs:  spare
+      Class:        class 3
+  VLAN:         450 iface2.450
+  VLAN:         452 iface2.452
+  LLDP-MED:    
+    Device Type:  Media Endpoint (Class II)
+    Capability:   Capabilities
+    Capability:   Policy
+    Capability:   Location
+    Capability:   MDI/PSE
+    Capability:   MDI/PD
+    Capability:   Inventory
+    LLDP-MED Location Identification: Type: Coordinates, Geoid: WGS84
+      Latitude:     48.58666N
+      Longitude:    2.2013E
+      Altitude:     m 117.46
+    LLDP-MED Location Identification: Type: ELIN
+      ECS ELIN:     911
+    Inventory:   
+      Hardware Revision: pc-i440fx
+      Software Revision: 
+      Firmware Revision: 
+      Manufacturer: QEMU
+      Model:        Standard PC (i440FX + PIIX, 1996
+  UnknownTLVs: 
+    TLV:          OUI: 33,44,55, SubType: 44, Len: 5 45,45,45,45,45
+-------------------------------------------------------------------------------
+[∗] End of command: 0.
diff --git a/tests/integration-tests.in b/tests/integration-tests.in
new file mode 100755 (executable)
index 0000000..bf8664f
--- /dev/null
@@ -0,0 +1,547 @@
+#!/bin/sh
+
+# Integration tests for lldpd. Those tests only run on Linux. They
+# spawn several VM and connect them together, then check lldpcli
+# results to see if everything is in order.
+
+# lldpd should be configure with:
+#  ../configure --localstatedir=/var --sysconfdir=/etc --prefix=/usr CFLAGS="-O0 -g"
+
+LABNAME=lldpd
+
+set -e
+
+log_begin_msg () {
+    echo "[…] $1... "
+}
+log_ok_msg () {
+    echo "[✔] $1."
+}
+log_warn_msg () {
+    echo "[⚡] $1!"
+}
+log_error_msg () {
+    echo "[✘] $1!"
+    exit 1
+}
+log_info_msg () {
+    echo "[∗] $1."
+}
+
+check_kernel() {
+    log_begin_msg "Checking kernel version"
+    [ -f "$KERNEL" ] || log_error_msg "Unable to find kernel $KERNEL"
+    [ -r "$KERNEL" ] || log_error_msg "Kernel $KERNEL is not readable.\n    Try \`setfacl -m u:$USER:r $KERNEL'"
+
+    # A recent version of `file` is able to extract the
+    # information. Since it is not widely available, let use some hack
+    # method.
+    VERSION=$(cat <<EOF |
+cat
+gunzip  \\\037\\\213\\\010 xy
+unxz    \\\3757zXZ\\\000   abcde
+bunzip2 BZh                xy
+unlzma  \\\135\\\0\\\0\\\0 xxx
+EOF
+              while read cmd sig1 sig2; do
+                  case $sig1,$sig2 in
+                      ,) poss="0:_" ;;
+                      *) poss=$(tr "${sig1}\n${sig2}" "\n${sig2}=" < "$KERNEL" | grep -abo "^${sig2}" || true) ;;
+                  esac
+                  [ -n "$poss" ] || continue
+                  for pos in $poss; do
+                      pos=${pos%%:*}
+                      tail -c+$pos "$KERNEL" | $cmd 2> /dev/null | strings -20 | \
+                          grep ^Linux.version | head -1
+                  done
+              done | head -1)
+
+    [ -n "$VERSION" ] || log_error_msg "Unable to determine version for $KERNEL"
+    VERSION="${VERSION#Linux version }"
+    VERSION="${VERSION%% *}"
+    log_ok_msg "Found kernel $VERSION"
+
+    log_begin_msg "Check kernel configuration"
+    CONFIG="$(dirname $KERNEL)/config-$VERSION"
+    [ -f "$CONFIG" ] || log_error_msg "Unable to find configuration file $CONFIG"
+    cat <<EOF | while read el; do
+9P_FS=[ym]
+NET_9P=[ym]
+NET_9P_VIRTIO=[ym]
+VIRTIO=[ym]
+VIRTIO_PCI=[ym]
+SERIAL_8250=y
+SERIAL_8250_CONSOLE=y
+TMPFS=y
+BLK_DEV_INITRD=y
+DEVTMPFS=[ym]
+EOF
+        grep -qx "CONFIG_$el" $CONFIG || log_error_msg "Kernel not configured with CONFIG_$el"
+    done
+
+    log_begin_msg "Search for modules"
+    for dir in "$(dirname $KERNEL)/lib/modules/$VERSION" "/lib/modules/$VERSION"; do
+        [ -d $dir ] || continue
+        MODULES="$dir"
+        break
+    done
+    if [ -z "$MODULES" ]; then
+        log_warn_msg "Unable to find module directory"
+    else
+        log_ok_msg "Modules are in $MODULES"
+    fi
+}
+
+check_dependencies() {
+    log_begin_msg "Checking if dependencies are present"
+    for exec in \
+        busybox \
+        qemu-system-x86_64 \
+        tmux vde_switch \
+        start-stop-daemon \
+        $DEPS; do
+        which $exec 2> /dev/null > /dev/null || log_error_msg "$exec is not installed"
+    done
+    log_ok_msg "All dependencies are met"
+}
+
+setup_tmp () {
+    TMP=$(mktemp -d)
+    trap "ret=$? ; cleanup" EXIT
+    log_info_msg "TMP is $TMP"
+}
+
+# Run our lab in tmux
+setup_screen() {
+    if [ -z "$TMUX" ] || [ x"$(tmux list-panes -F '#{session_name}')" != x"$LABNAME" ]; then
+        unset TMUX
+        exec tmux new-session -s "$LABNAME" -n main \
+            "env ROOT=$ROOT VERSION=$VERSION LINUX=$LINUX $PROGNAME $PROGARGS || read"
+    fi
+    sleep 1
+    tmux set-option -q prefix C-b
+    tmux set-option -q set-remain-on-exit on
+    tmux bind-key r respawn-window
+}
+
+# Setup a VDE switch
+setup_switch() {
+    nb=$1 ; shift
+    log_begin_msg "Setup switch $nb"
+    cat <<EOF > "$TMP/switch-$nb.conf"
+plugin/add /usr/lib/vde2/plugins/pdump.so
+pdump/filename $TMP/switch-$nb.pcap
+pdump/buffered 0
+pdump/active 1
+EOF
+    start-stop-daemon -b --no-close --make-pidfile --pidfile "$TMP/switch-$nb.pid" \
+        --start --startas $(which vde_switch) -- \
+        --sock "$TMP/switch-$nb.sock" --mgmt "$TMP/switch-management-$nb.sock" \
+        --rcfile "$TMP/switch-$nb.conf" --hub
+    # Management socket can be used with:
+    #    socat - UNIX-CONNECT:"$TMP/switch-management-$nb.sock"
+    log_ok_msg "Switch $nb started"
+}
+
+setup_initrd () {
+    log_begin_msg "Build initrd"
+    DESTDIR=$TMP/initrd
+    mkdir -p $DESTDIR
+
+    # Copy busybox and eventually insmod
+    bins="busybox"
+    busybox --list | grep -qFx insmod || bins="$bins insmod"
+    for bin in $bins; do
+        install -D "$(which $bin)" ${DESTDIR}/bin/$bin
+        for x in $(ldd "$(which $bin)" 2> /dev/null | sed -e '
+               /\//!d;
+               /linux-gate/d;
+               /=>/ {s/.*=>[[:blank:]]*\([^[:blank:]]*\).*/\1/};
+               s/[[:blank:]]*\([^[:blank:]]*\) (.*)/\1/' 2>/dev/null); do
+            [ -f "${DESTDIR}/$x" ] || install -D "$x" "${DESTDIR}/$x"
+        done
+    done
+
+    # Configure busybox
+    for applet in $(${DESTDIR}/bin/busybox --list); do
+        ln -s busybox ${DESTDIR}/bin/${applet}
+    done
+
+    # Add modules
+    [ -z "$MODULES" ] || {
+        modules="9pnet_virtio 9p virtio_pci $UNION"
+        for mod in $modules; do
+            modprobe --all --set-version="${VERSION}" -d ${MODULES}/../../.. \
+                --ignore-install --quiet --show-depends $mod > /dev/null || {
+                log_warn_msg "Unable to find module $mod"
+                log_begin_msg "Continue building initrd"
+            }
+            modprobe --all --set-version="${VERSION}" -d ${MODULES}/../../.. \
+                --ignore-install --quiet --show-depends $mod |
+            while read prefix kmod options ; do
+                [ "${prefix}" = "insmod" ] || continue
+                grep -qFw "$kmod" ${DESTDIR}/modules 2> /dev/null || {
+                    install -D "$kmod" "${DESTDIR}/${kmod}"
+                    echo $prefix $kmod $options >> ${DESTDIR}/modules
+                }
+            done
+        done
+    }
+
+    # Copy this program
+    cp "$PROGNAME" ${DESTDIR}/init
+
+    # Create /tmp
+    mkdir ${DESTDIR}/tmp
+
+    # Build initrd
+    (cd "${DESTDIR}" && find . | cpio --quiet -R 0:0 -o -H newc | gzip > $TMP/initrd.gz)
+
+    log_ok_msg "initrd built in $TMP/initrd.gz"
+}
+
+random_mac () {
+    # But, not random in fact
+    name=$1
+    net=$2
+    mac=$(echo $name-$net | sha1sum | \
+        awk '{print "50:54:" substr($1,0,2) ":" substr($1, 2, 2) ":" substr($1, 4, 2) ":" substr($1, 6, 2)}')
+    echo $mac
+}
+
+start_vm () {
+    name=$1
+    shift
+
+    netargs=""
+    saveifs="$IFS"
+    IFS=,
+    for net in $NET; do
+        mac=$(random_mac $name $net)
+        netargs="$netargs -net nic,model=virtio,macaddr=$mac,vlan=$net"
+        netargs="$netargs -net vde,sock=$TMP/switch-$net.sock,vlan=$net"
+    done
+    IFS="$saveifs"
+
+    log_info_msg "Start VM $name"
+    # /root is mounted with version 9p2000.u to allow access to /dev,
+    # /sys and to mount new partitions over them. This is not the case
+    # for 9p2000.L.
+    cat <<EOF > "$TMP/vm-$name.exec"
+#!/bin/sh
+        echo
+        exec start-stop-daemon --make-pidfile --pidfile "$TMP/vm-$name.pid" \
+        --start --startas $(which qemu-system-x86_64) -- \
+        -enable-kvm \
+        -nodefconfig -nodefaults \
+        -display none \
+        -m ${MEM:-128M} \
+        \
+        -chardev stdio,id=charserial0,signal=off \
+        -device isa-serial,chardev=charserial0,id=serial0 \
+        -chardev socket,id=charserial1,path=$TMP/vm-$name-serial.pipe,server,nowait \
+        -device isa-serial,chardev=charserial1,id=serial1 \
+        \
+        -chardev socket,id=con0,path=$TMP/vm-$name-console.pipe,server,nowait \
+        -mon chardev=con0,mode=readline,default \
+        \
+        -fsdev local,security_model=passthrough,id=fsdev-root,path=${ROOT} \
+        -device virtio-9p-pci,id=fs-root,fsdev=fsdev-root,mount_tag=rootshare \
+        -fsdev local,security_model=none,id=fsdev-lab,path=${PWD} \
+        -device virtio-9p-pci,id=fs-lab,fsdev=fsdev-lab,mount_tag=labshare \
+        -fsdev local,security_model=none,id=fsdev-tmp,path=${TMP} \
+        -device virtio-9p-pci,id=fs-tmp,fsdev=fsdev-tmp,mount_tag=tmpshare \
+        -fsdev local,security_model=none,id=fsdev-modules,path=${MODULES}/..,readonly \
+        -device virtio-9p-pci,id=fs-modules,fsdev=fsdev-modules,mount_tag=moduleshare \
+        \
+        -gdb unix:$TMP/vm-$name-gdb.pipe,server,nowait \
+        -kernel $KERNEL \
+        -no-reboot \
+        -initrd $TMP/initrd.gz \
+        -append "uts=$name console=ttyS0 panic=1 TERM=$TERM quiet" \
+        $netargs \
+        $@
+EOF
+    log_info_msg "GDB server listening on $TMP/vm-$name-gdb.pipe"
+    log_info_msg "monitor listening on    $TMP/vm-$name-console.pipe"
+    log_info_msg "ttyS1 listening on      $TMP/vm-$name-serial.pipe"
+    chmod +x "$TMP/vm-$name.exec"
+    tmux new-window -n $name "$TMP/vm-$name.exec"
+    tmux select-window -t ":^"
+}
+
+display_help() {
+    cat <<EOF
+
+Some tmux commands (assuming default keybindings) :
+ C-b d     - Detach the lab (resume with "tmux attach -t $LABNAME")
+ C-b w     - Select a window
+ C-b n     - Next window
+ C-b p     - Previous window
+ C-b l     - Last window
+ C-b ?     - Get help
+
+EOF
+}
+
+run() {
+    r=$1
+    shift
+    log_info_msg "$r: execute $*"
+    printf "%s\n" "$*" > $TMP/${r}.command
+    n=0
+    while [ -f $TMP/${r}.command ]; do
+        sleep 1
+        n=$((n + 1))
+        [ $n -le 15 ] || {
+            log_error_msg "Timeout while executing command on $r"
+        }
+    done
+}
+
+process_commands() {
+    cd /mnt/lab
+    log_info_msg "Waiting for commands"
+    cmd=/tmp/lab/${uts}.command
+    set +e
+    while true; do
+        while [ ! -f $cmd ]; do
+            sleep 1
+        done
+        log_info_msg "Execute command $(head -1 $cmd)"
+        sh $cmd
+        log_info_msg "End of command: $?"
+        rm $cmd
+    done
+}
+
+start_tests() {
+    # Start lldpd on each VM
+    run R1 libtool execute src/daemon/lldpd -M 1 -L \$PWD/src/client/lldpcli
+    run R2 libtool execute src/daemon/lldpd -M 2 -L \$PWD/src/client/lldpcli
+    run R3 libtool execute src/daemon/lldpd -M 3 -L \$PWD/src/client/lldpcli
+    sleep 2
+    # Query neighbors
+    run R1 libtool execute src/client/lldpcli show neighbor detail
+    run R2 libtool execute src/client/lldpcli show neighbor detail
+    run R3 libtool execute src/client/lldpcli show neighbor detail
+    # Add some VLAN
+    run R2 ip link add link iface2 name iface2.450 type vlan id 450
+    run R2 ip link set up dev iface2.450
+    run R2 ip link add link iface2 name iface2.451 type vlan id 451
+    run R2 ip link set up dev iface2.451
+    run R2 ip link add link iface2 name iface2.452 type vlan id 452
+    run R2 ip link set up dev iface2.452
+    sleep 2
+    run R1 libtool execute src/client/lldpcli show neighbor detail ports iface2
+    # Remove one
+    run R2 ip link del iface2.451
+    sleep 2
+    run R1 libtool execute src/client/lldpcli show neighbor detail ports iface2
+    # Add a bond
+    run R3 ip link set down dev iface2
+    run R3 ip link set down dev iface3
+    run R3 ip link set iface2 master bond0
+    run R3 ip link set iface3 master bond0
+    run R3 ip link set up dev bond0
+    sleep 2
+    run R1 libtool execute src/client/lldpcli show neighbor detail ports iface4
+    run R1 libtool execute src/client/lldpcli show neighbor detail ports iface5
+    # Add a VLAN on top of bond
+    run R3 ip link add link bond0 name bond0.453 type vlan id 453
+    run R3 ip link set up dev bond0.453
+    sleep 2
+    run R1 libtool execute src/client/lldpcli show neighbor detail ports iface4
+    # Add a bridge
+    run R2 brctl addbr br0
+    run R2 brctl addif br0 iface3
+    run R2 ip link set up dev br0
+    sleep 2
+    run R1 libtool execute src/client/lldpcli show neighbor detail ports iface3
+    # Modify some TLV
+    conf="libtool execute src/client/lldpcli configure ports iface2"
+    run R2 $conf lldp custom-tlv oui 33,44,55 subtype 44 oui-info 45,45,45,45,45
+    run R2 $conf med location elin 911
+    run R2 $conf med location coordinate latitude 48.58667N longitude 2.2014E altitude 117.47 m datum WGS84
+    run R2 $conf med power pd source pse priority high value 5000
+    run R2 $conf dot3 power pse supported enabled paircontrol powerpairs spare class class-3
+    sleep 2
+    run R1 libtool execute src/client/lldpcli show neighbor detail ports iface2
+    # Configuration should stay when port go down and up
+    run R2 ip link set down dev iface2
+    sleep 2
+    run R2 ip link set up dev iface2
+    sleep 5
+    run R1 libtool execute src/client/lldpcli show neighbor detail ports iface2
+}
+
+cleanup() {
+    set +e
+    for pid in $TMP/*.pid; do
+        kill -15 -$(cat $pid) 2> /dev/null || true
+    done
+    sleep 1
+    for pid in $TMP/*.pid; do
+        kill -9 -$(cat $pid) 2> /dev/null || true
+    done
+    rm -rf $TMP
+    tmux kill-session -t $LABNAME
+}
+
+# FSM
+export STATE=${STATE:-BEGIN}
+case $$,$STATE in
+    1,BEGIN)
+        # In initrd
+        log_info_msg "initrd started"
+        hostname ${uts}
+        export PATH=/usr/local/bin:/usr/bin:/bin:/sbin:/usr/local/sbin:/usr/sbin
+        export HOME=/root
+
+        [ ! -f /modules ] || {
+            log_info_msg "Loading modules"
+            . /modules
+        }
+
+        log_begin_msg "Setup root file system"
+        mount -n -t tmpfs tmpfs /tmp -o rw
+        mkdir /tmp/target
+        mkdir /tmp/target/ro
+        mkdir /tmp/target/overlay
+        mount -n -t 9p    rootshare /tmp/target/overlay -o trans=virtio,version=9p2000.u,ro
+        mount -n -t proc  proc /tmp/target/overlay/proc
+        mount -n -t sysfs sys  /tmp/target/overlay/sys
+        log_ok_msg "Root file system setup"
+
+        log_begin_msg "Clean /tmp and /run"
+        for fs in /run /var/run /var/tmp /var/log /tmp /mnt; do
+            if [ -d /tmp/target/overlay$fs ] && [ ! -h /tmp/target/overlay$fs ]; then
+                mount -t tmpfs tmpfs /tmp/target/overlay$fs -o rw,nosuid,nodev
+            fi
+        done
+        log_ok_msg "/tmp, /run and others are clean"
+
+        log_begin_msg "Mount /lib/modules"
+        mount -t 9p moduleshare /tmp/target/overlay/lib/modules -o trans=virtio,version=9p2000.L,access=0,ro || \
+            log_error_msg "Unable to mount /lib/modules"
+        log_ok_msg "/root and /lib/modules mounted"
+
+        log_begin_msg "Mount /mnt/lab"
+        mkdir /tmp/target/overlay/mnt/lab
+        mount -t 9p labshare /tmp/target/overlay/mnt/lab -o trans=virtio,version=9p2000.L,access=any,rw || \
+            log_error_msg "Unable to mount /mnt/lab"
+        log_ok_msg "/mnt/lab mounted"
+
+        log_begin_msg "Mount /tmp/lab"
+        mkdir /tmp/target/overlay/tmp/lab
+        mount -t 9p tmpshare /tmp/target/overlay/tmp/lab -o trans=virtio,version=9p2000.L,access=any,rw || \
+            log_error_msg "Unable to mount /tmp/lab"
+        log_ok_msg "/tmp/lab mounted"
+
+        log_info_msg "Change root"
+        export STATE=CHROOTED
+        exec chroot /tmp/target/overlay /mnt/lab/integration-tests
+        ;;
+
+    1,CHROOTED)
+        log_begin_msg "Starting udev"
+        udev_log=err
+        mount -n -o size=10M,mode=0755 -t devtmpfs devtmpfs /dev
+        udevadm info --cleanup-db
+        for udev in /lib/systemd/systemd-udevd /usr/lib/systemd/systemd-udevd $(command -v udevd 2> /dev/null); do
+            [ ! -x $udev ] || break
+        done
+        $udev --daemon
+        udevadm trigger --action=add
+        udevadm settle
+        log_ok_msg "udev started"
+
+        log_info_msg "Setup interfaces"
+        modprobe dummy 2>/dev/null || true
+        modprobe bonding 2>/dev/null || true
+        sleep 0.5               # Some interfaces may take some time to appear
+        # Rename all interfaces to "predictable" and "non-colliding"
+        # name. We don't have if we have eth* or ens* interfaces. Let
+        # take a totally different naming convention.
+        nb=1
+        for iface in $(echo /sys/bus/virtio/drivers/virtio_net/*/net/*); do
+            ip link set name iface$nb dev ${iface##*/}
+            nb=$((nb + 1))
+        done
+        for intf in /sys/class/net/*; do
+            intf=$(basename $intf)
+            ip a l dev $intf 2> /dev/null >/dev/null || continue
+            ip link set up dev $intf
+        done
+
+        log_info_msg "Setup IP addresses"
+        case $uts in
+            R1)
+                ip -4 addr add 192.0.2.15/24 dev iface1
+                ip -6 addr add 2001:db8::cafe:15/64 dev iface1
+                ;;
+            R2)
+                ip -4 addr add 192.0.2.16/24 dev iface1
+                ip -6 addr add 2001:db8::cafe:16/64 dev iface1
+                ;;
+            R3)
+                ip -4 addr add 192.0.2.17/24 dev iface1
+                ip -6 addr add 2001:db8::cafe:17/64 dev iface1
+                ;;
+        esac
+        process_commands 2>&1 | tee /mnt/lab/${uts}.output
+        ;;
+
+    *,BEGIN)
+        # Initial state
+        [ $(id -u) != 0 ] || {
+            log_error_msg "You should not run this as root"
+            exit 1
+        }
+        PROGNAME="$(readlink -f "$0")"
+        PROGARGS="$@"
+        ROOT="$(readlink -f "${ROOT:-/}")" # Root filesystem
+        KERNEL="$(readlink -f "${1:-/boot/vmlinuz-$(uname -r)}")" # Kernel
+        PATH="$PATH":/usr/local/sbin:/usr/sbin:/sbin
+        [ $# -lt 1 ] || shift
+
+        check_kernel
+        check_dependencies
+        setup_screen
+        setup_tmp
+        setup_initrd
+
+        setup_switch 1
+        setup_switch 2
+        setup_switch 3
+        setup_switch 4
+        setup_switch 5
+        sleep 0.3
+
+        NET=1,2,3,4,5 start_vm  R1
+        NET=1,2,3     start_vm  R2
+        NET=1,4,5     start_vm  R3
+
+        display_help
+        start_tests
+
+        sed \
+            -e 's/^\(Interface:.*, Time: 0 day\).*/\1/' \
+            -e 's/^\(    SysDescr:\).*/\1/' \
+            -e 's/^\(      Hardware Revision: pc-i440fx\).*/\1/' \
+            -e 's/^\(      Software Revision: \).*/\1/' \
+            -e 's/^\(      Firmware Revision: \).*/\1/' \
+            R1.output > R1.output.redacted
+        diff -u ../tests/R1.expected R1.output.redacted || \
+            log_warn_msg "Unexpected differences"
+
+        log_info_msg "End of tests, press enter to exit."
+        read a
+        ;;
+esac
+
+# Local Variables:
+# mode: sh
+# indent-tabs-mode: nil
+# sh-basic-offset: 4
+# End: