diff options
| author | Harshavardhan Unnibhavi <harshanavkis@gmail.com> | 2025-09-01 12:46:16 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-01 12:46:16 -0700 |
| commit | c59353c0f45703cfdb5178db1fcafbe001828b2f (patch) | |
| tree | f4c328b2caa8984c5731e96e4df855cf620ccf45 /archive/2025 | |
| parent | 73e505f04d17eba36c41fce7b48bc4d6884b8fd0 (diff) | |
| parent | 02fe788ec1936497a75ecf42714c217df9308a4c (diff) | |
| download | research-work-archive-artifacts-c59353c0f45703cfdb5178db1fcafbe001828b2f.tar.gz research-work-archive-artifacts-c59353c0f45703cfdb5178db1fcafbe001828b2f.zip | |
Merge pull request #8 from maxjae/bsc_jaecklein_sec_netw_acc
Add bsc_jaecklein
Diffstat (limited to 'archive/2025')
8 files changed, 590 insertions, 0 deletions
diff --git a/archive/2025/README.md b/archive/2025/README.md index 2b08f8b4e..8d21fcd6e 100644 --- a/archive/2025/README.md +++ b/archive/2025/README.md @@ -8,6 +8,7 @@ | Anders Choi | Airlift: A Binary Lifter Based on a Machine-Readable Architecture Specification | MA | Martin Fink | [Source](/archive/2025/summer/msc_choi) | Dominik Kreutzer | vDPDK: A Para-Virtualized DPDK Device Model for vMux | MA | Peter Okelmann, Masanori Misono | [Source](/archive/2025/summer/msc_kreutzer) | | Christian Karidas | Tamperproof Logging System for GDPR-compliant Key-Value Stores | BA | Dimitrios Stavrakakis | [Source](/archive/2025/summer/bsc_karidas/) | +| Maximilian Jäcklein | Protecting H/W and S/W Interactions for Network-Attached Accelerators | BA | Harshavardhan Unnibhavi | [Source](/archive/2025/summer/bsc_jaecklein) | ## Winter semester diff --git a/archive/2025/summer/bsc_jaecklein/LICENSE b/archive/2025/summer/bsc_jaecklein/LICENSE new file mode 100644 index 000000000..22cce7ae7 --- /dev/null +++ b/archive/2025/summer/bsc_jaecklein/LICENSE @@ -0,0 +1,8 @@ +Copyright 2025 Maximilian Jäcklein + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/archive/2025/summer/bsc_jaecklein/README.md b/archive/2025/summer/bsc_jaecklein/README.md new file mode 100755 index 000000000..2b4168a57 --- /dev/null +++ b/archive/2025/summer/bsc_jaecklein/README.md @@ -0,0 +1,191 @@ +# Protecting H/W and S/W Intercations for Network-Attached Accelerators + +This file explains how to run the software part (CVM + Shared Memory + Device Emulation) for the network-attached accelerator. + +The implementation can be divided by the transportation method into Network and **Same Host** setup. The first runs a network stack (**RDMA**, **Ethernet**, or **TCP**) to connect the hosts of the Shared Memory and the Device Emulation. The latter runs all applications on one host, thus no data has to travel the network. + +All four types of transportation implement a **secure** version, where all data concerning MMIO and DMA is going through a authenticated Encryption procedure, and a **non-secure** version, which removes those security measures and operates on plaintext. + +The explanation is structured as follows. First, a describtion on how to initially set up the (C)VM (QEMU + Kernel). This has to only be done once. Next, the building instructions for the four different transportation types. Last, the instructions on how to run the system. + +To get the necessary repositories: + +```bash +git clone https://github.com/maxjae/jigsaw-overall.git +cd ./jigsaw-overall +direnv allow +git clone https://github.com/maxjae/spdm-linux.git +git clone https://github.com/maxjae/qemu.git +``` + +## VM Setup + +The virtual machine is hosted with QEMU and a custom kernel to accommodate for the changes to the communication layer. To run the VM in a confidential version, the extensions of AMD SEV are used. Further, there are some basic driver modules for testing and evaluation. + +### QEMU + +```bash +cd qemu +git checkout disagg-fake-device +mkdir build +cd build +../configure --target-list=x86_64-softmmu --enable-kvm +make -j$(nproc) +``` + +### Kernel + +Change to the custom kernel: + +```bash +cd spdm-linux +``` + +The code base offers two different branches for the secure and non-secure version of the communication. This is independent of the VM itself and only changes the MMIO and DMA communication. + +```bash +git checkout disagg-secure +``` + +**or**: + +```bash +git checkout disagg-non_secure +``` + +Get the custom config file and build: + +```bash +cp linux-disagg-shmem-config .config +make olddefconfig +make -j$(nproc) +``` + +### Miscellaneous + +#### Image + +To run the VM, a image is needed. You can follow the instructions from here: <https://nixos.wiki/wiki/Kernel_Debugging_with_QEMU>. + +#### Driver Modules + +Some test drivers and evaluation modules are in the `spdm-linux/qemu_edu` directory. To copy the build modules into your image you can use the provided script: + +```bash +./copy-modules.sh <path of image> +``` + +#### OVMF + +Running a **confidential** VM requires a suitable OVMF. The provided QEMU script also uses this to run the non-confidential VM, even if it is not strictly necessary. For now, you can use this rather weird approach to create an `OVMF.fd` file. This file can later be used when running the qemu script. + +```bash +git clone --recursive https://github.com/dimstav23/GDPRuler.git +cd GDPRuler && git checkout dev +git submodule update --init --recursive +nix develop +cd CVM_setup/AMDSEV +bash build.sh ovmf +cp ./usr/local/share/qemu/OVMF.fd <path of jigsaw-overall repo> +``` + +## Remaining System + +The `jigsaw-overall` repository offers 8 different branches for each pair of {RDMA, Ethernet, TCP, Same Host} and {secure, non-secure}. The Same Host setup requires no second sever (i.e., the device emulation runs on the same host as the CVM). This also means that for the {RDMA, Eternet, TCP} setups, a second `jigsaw-overall` repository has to be cloned on another server. + +So, follow either "Network Setups" **or** "Same Host Setup". + +### Network Setups + +On the CVM server: + +```bash +git checkout (rdma|tcp|ethernet)(-non_secure)? +cd src/proxy +make +``` + +The device emulation runs on a different server: + +```bash +git clone https://github.com/maxjae/jigsaw-overall.git +cd ./jigsaw-overall +direnv allow +git checkout (rdma|tcp|ethernet)(-non_secure)? +cd src/edu_simple +make +``` + +### Same Host Setups + +Run this on the same server as the CVM. + +```bash +git checkout same-host-simple-device(-non_secure)? +cd src/edu-simple +make +``` + +## Running the system + +The different applications have to be started in a specific order: + +1. Device emulation +2. Proxy (not for Same Host) +3. CVM + +### Device and (Proxy) + +Again, there is difference between the Same Host setups and the rest. Either follow "RDMA, TCP, Ethernet" **or** "Same Host". + +#### RDMA, TCP, Ethernet + +On the non-CVM server: + +```bash +cd src/edu_simple +./bin/edu_device_emulation +``` + +The execution will print a usage message on how to specify the different command line options. This differs for the network types. + +On the CVM server: + +```bash +cd src/proxy +./bin/proxy +``` + +The execution will print a usage message on how to specify the different command line options. This differs for the network types. + +#### Same Host + +```bash +cd src/edu_simple +./bin/edu_device_emulation +``` + +### CVM + +The jigsaw-overall repo provides the `qemu-run.sh` script to start the CVM: + +```bash +sudo ./qemu-run <Type of VM: [VM|CVM]> <path of image file> <path of OVMF.fd> +``` + +The type argument specifies if the VM uses SEV extensions (option "CVM") or just a plain VM (option "VM"). + +### Running modules + +Inside the CVM, the modules can now be run with: + +```bash +cd /modules +insmod ./<name of module>.ko +rmmod ./<name of module>.ko +``` + +## Note + +- As the evaluation works with 8 KiB payload, the link has to be able to support this. This is especially relevant for the **Ethernet** setup. Therefore, you have to increase the MTU for your network interfaces to a value higher than the standard 1500 Bytes. We used 9000 Bytes for the MTU of both NICs. (e.g., use the `ip` command) +- To run the **RDMA** setup the NICs have to support this. To check for available RDMA devices and their corresponding interface link name, use `rdma link`. diff --git a/archive/2025/summer/bsc_jaecklein/benchmark_scripts/bounce-buffer.expect b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/bounce-buffer.expect new file mode 100755 index 000000000..46b45d863 --- /dev/null +++ b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/bounce-buffer.expect @@ -0,0 +1,75 @@ +#!/usr/bin/env expect + +# 10^6 is max as we only have 1MB buffer and kmalloc also does not like bigger ones +# Size of DMA buffers +#set sizeList { 1 10 100 1000 10000 100000 200000 300000 400000 500000 600000 700000 800000 900000 1000000 } +#set sizeList {4 64 128 256 512 1024 4096 8192 16384 32768 65536 131072 262144 524288 786432 1040384 } +set sizeList {4 32 64 128 256 512 1024 2048 4096 8192 } + +if { $argc < 5 } { + puts "Usage: programm-path <Name of module> <output file> <output prefix> <number of retries> <number of operations for each insmod>" + exit 1 +} + +lassign $argv module filename prefix retries nr_ops + +set file [open $filename "a"] + +# This file writing is copied from https://stackoverflow.com/a/67265956 +proc writeToFile {string file pre} { + puts $file "$pre$string" +} + +set timeout 30 + +spawn sudo ../qemu/build/qemu-system-x86_64 \ + -m 8G \ + -object memory-backend-memfd,id=sysmem-file,size=8G \ + -numa node,memdev=sysmem-file \ + -smp 8 \ + -kernel ../spdm-linux/arch/x86/boot/bzImage \ + -append "console=ttyS0 root=/dev/sda rw earlyprintk=serial net.ifnames=0 nokaslr" \ + -drive file=../qemu-image.img,format=raw \ + -object memory-backend-file,size=1M,share=on,mem-path=/dev/shm/ivshmem,id=hostmem \ + -device ivshmem-plain,memdev=hostmem \ + -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 \ + -net nic,model=e1000 \ + -enable-kvm \ + -nographic \ + -cpu EPYC-v4,+vpclmulqdq \ + -no-reboot \ + -machine q35,confidential-guest-support=sev0 \ + -bios ../OVMF.fd \ + -device disagg-fake-pci,bar-size=1048576 \ + -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,policy=0x30000 + +# workaround to send a key-hit to the vm +# requires as it does not show login prompt otherwise (also not working with sleep) +expect { + timeout { + send "\r" + } +} + +expect "login:" { send "root\r" } +expect "Password:" { send "test\r" } +expect "#" { send "cd /modules\r" } + +foreach size $sizeList { + set i 0 + while { $i < $retries } { + expect "#" { send "insmod $module.ko dma_size=$size count_ops=$nr_ops\r" } + set n 0 + while { $n < $nr_ops } { + expect -re "time measured: (.+) end" { writeToFile $expect_out(1,string) $file $prefix } + incr n + } + expect "#" { send "rmmod $module.ko\r" } + incr i + } +} + +expect "#" { send "shutdown -h now\r" } +expect eof + +close $file diff --git a/archive/2025/summer/bsc_jaecklein/benchmark_scripts/crypto.expect b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/crypto.expect new file mode 100755 index 000000000..a2908c976 --- /dev/null +++ b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/crypto.expect @@ -0,0 +1,75 @@ +#!/usr/bin/env expect + +# 10^6 is max as we only have 1MB buffer and kmalloc also does not like bigger ones +# Size of DMA buffers +#set sizeList { 1 10 100 1000 10000 100000 200000 300000 400000 500000 600000 700000 800000 900000 1000000 } +#set sizeList {4 64 128 256 512 1024 4096 8192 16384 32768 65536 131072 262144 524288 786432 1040384 } +set sizeList {4 32 64 128 256 512 1024 2048 4096 8192 } + +if { $argc < 6 } { + puts "Usage: programm-path <Name of module> <output file> <output prefix> <number of retries> <number of operations for each insmod> <crypto type>" + exit 1 +} + +lassign $argv module filename prefix retries nr_ops crypto + +set file [open $filename "a"] + +# This file writing is copied from https://stackoverflow.com/a/67265956 +proc writeToFile {string file pre} { + puts $file "$pre$string" +} + +set timeout 30 + +spawn sudo ../qemu/build/qemu-system-x86_64 \ + -m 8G \ + -object memory-backend-memfd,id=sysmem-file,size=8G \ + -numa node,memdev=sysmem-file \ + -smp 8 \ + -kernel ../spdm-linux/arch/x86/boot/bzImage \ + -append "console=ttyS0 root=/dev/sda rw earlyprintk=serial net.ifnames=0 nokaslr" \ + -drive file=../qemu-image.img,format=raw \ + -object memory-backend-file,size=1M,share=on,mem-path=/dev/shm/ivshmem,id=hostmem \ + -device ivshmem-plain,memdev=hostmem \ + -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 \ + -net nic,model=e1000 \ + -enable-kvm \ + -nographic \ + -cpu EPYC-v4,+vpclmulqdq \ + -bios ../OVMF.fd \ + -no-reboot \ + -machine q35,confidential-guest-support=sev0 \ + -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,policy=0x30000 \ + -device disagg-fake-pci,bar-size=1048576 + +# workaround to send a key-hit to the vm +# requires as it does not show login prompt otherwise (also not working with sleep) +expect { + timeout { + send "\r" + } +} + +expect "login:" { send "root\r" } +expect "Password:" { send "test\r" } +expect "#" { send "cd /modules\r" } + +foreach size $sizeList { + set i 0 + while { $i < $retries } { + expect "#" { send "insmod $module.ko write_size=$size count_ops=$nr_ops crypto=$crypto\r" } + set n 0 + while { $n < $nr_ops } { + expect -re "time measured: (.+) end" { writeToFile $expect_out(1,string) $file $prefix } + incr n + } + expect "#" { send "rmmod $module.ko\r" } + incr i + } +} + +expect "#" { send "shutdown -h now\r" } +expect eof + +close $file diff --git a/archive/2025/summer/bsc_jaecklein/benchmark_scripts/dma.expect b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/dma.expect new file mode 100755 index 000000000..63b395a83 --- /dev/null +++ b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/dma.expect @@ -0,0 +1,88 @@ +#!/usr/bin/env expect + +# 10^6 is max as we only have 1MB buffer and kmalloc also does not like bigger ones +# Size of DMA buffers +#set sizeList { 1 10 100 1000 10000 100000 200000 300000 400000 500000 600000 700000 800000 900000 1000000 } +#set sizeList {4 64 128 256 512 1024 4096 8192 16384 32768 65536 131072 262144 524288 786432 1040384 } +set sizeList {4 32 64 128 256 512 1024 2048 4096 8192 } + +if { $argc < 5 } { + puts "Usage: programm-path <Name of module> <output file> <output prefix> <number of retries> <number of operations for each insmod>" + exit 1 +} + +lassign $argv module filename prefix retries nr_ops + +set file [open $filename "a"] + +# This file writing is copied from https://stackoverflow.com/a/67265956 +proc writeToFile {string file pre} { + puts $file "$pre$string" +} + +set timeout 30 + +spawn sudo ../qemu/build/qemu-system-x86_64 \ + -m 8G \ + -object memory-backend-memfd,id=sysmem-file,size=8G \ + -numa node,memdev=sysmem-file \ + -smp 8 \ + -kernel ../spdm-linux/arch/x86/boot/bzImage \ + -append "console=ttyS0 root=/dev/sda rw earlyprintk=serial net.ifnames=0 nokaslr" \ + -drive file=../qemu-image.img,format=raw \ + -object memory-backend-file,size=1M,share=on,mem-path=/dev/shm/ivshmem,id=hostmem \ + -device ivshmem-plain,memdev=hostmem \ + -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 \ + -net nic,model=e1000 \ + -enable-kvm \ + -nographic \ + -cpu EPYC-v4,+vpclmulqdq \ + -bios ../OVMF.fd \ + -no-reboot \ + -machine q35,confidential-guest-support=sev0 \ + -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,policy=0x30000 \ + -device disagg-fake-pci,bar-size=1048576 + + + + +# workaround to send a key-hit to the vm +# requires as it does not show login prompt otherwise (also not working with sleep) +expect { + timeout { + send "\r" + } +} + +expect "login:" { send "root\r" } +expect "Password:" { send "test\r" } +expect "#" { send "cd /modules\r" } + +foreach size $sizeList { + set i 0 + while { $i < $retries } { + expect "#" { send "insmod benchmark-dma_to_device.ko dma_size=$size count_ops=$nr_ops\r" } + expect -re "time measured: (.+) end" { writeToFile $expect_out(1,string) $file "$prefix;To device;" } + expect "#" { send "rmmod benchmark-dma_to_device.ko\r" } + incr i + } + + puts stderr "$size" +} + +foreach size $sizeList { + set i 0 + while { $i < $retries } { + expect "#" { send "insmod benchmark-dma_from_device.ko dma_size=$size count_ops=$nr_ops\r" } + expect -re "time measured: (.+) end" { writeToFile $expect_out(1,string) $file "$prefix;From device;" } + expect "#" { send "rmmod benchmark-dma_from_device.ko\r" } + incr i + } + + puts stderr "$size" +} + +expect "#" { send "shutdown -h now\r" } +expect eof + +close $file diff --git a/archive/2025/summer/bsc_jaecklein/benchmark_scripts/mmio-pie.expect b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/mmio-pie.expect new file mode 100755 index 000000000..08b1af5be --- /dev/null +++ b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/mmio-pie.expect @@ -0,0 +1,79 @@ +#!/usr/bin/env expect + +set sizeList { 1 2 4 8 } + +if { $argc < 5 } { + puts "Usage: programm-path <Name of module> <output file> <output prefix> <number of retries> <number of operations for each insmod>" + exit 1 +} + +lassign $argv module filename prefix retries nr_ops + +set file [open $filename "a"] + +# This file writing is copied from https://stackoverflow.com/a/67265956 +proc writeToFile {string file pre} { + puts $file "$pre$string" +} + +set timeout 30 + +spawn sudo ../qemu/build/qemu-system-x86_64 \ + -m 8G \ + -object memory-backend-memfd,id=sysmem-file,size=8G \ + -numa node,memdev=sysmem-file \ + -smp 8 \ + -kernel ../spdm-linux/arch/x86/boot/bzImage \ + -append "console=ttyS0 root=/dev/sda rw earlyprintk=serial net.ifnames=0 nokaslr" \ + -drive file=../qemu-image.img,format=raw \ + -object memory-backend-file,size=1M,share=on,mem-path=/dev/shm/ivshmem,id=hostmem \ + -device ivshmem-plain,memdev=hostmem \ + -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 \ + -net nic,model=e1000 \ + -enable-kvm \ + -nographic \ + -cpu EPYC-v4,+vpclmulqdq \ + -no-reboot \ + -machine q35,confidential-guest-support=sev0 \ + -bios ../OVMF.fd \ + -device disagg-fake-pci,bar-size=1048576 \ + -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,policy=0x30000 + +# workaround to send a key-hit to the vm +# requires as it does not show login prompt otherwise (also not working with sleep) +expect { + timeout { + send "\r" + } +} + +expect "login:" { send "root\r" } +expect "Password:" { send "test\r" } +expect "#" { send "cd /modules\r" } + +foreach size $sizeList { + set i 0 + while { $i < $retries } { + expect "#" { send "insmod $module.ko mmio_size=$size count_ops=$nr_ops\r" } + set n 0 + while { $n < 1 } { + set p 0 + while { $p < 4 } { + expect -re "time measured pie: (.+) end" { writeToFile $expect_out(1,string) $file $prefix } + incr p + } +# expect -re "time measured: (.+) end" { writeToFile $expect_out(1,string) $file $prefix } + incr n + } + expect "#" { send "rmmod $module.ko\r" } + + puts stderr "$size: $i" + incr i + } +} + +expect "#" { send "shutdown -h now\r" } +expect eof + +close $file + diff --git a/archive/2025/summer/bsc_jaecklein/benchmark_scripts/mmio.expect b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/mmio.expect new file mode 100755 index 000000000..d3b03c55e --- /dev/null +++ b/archive/2025/summer/bsc_jaecklein/benchmark_scripts/mmio.expect @@ -0,0 +1,73 @@ +#!/usr/bin/env expect + +set sizeList { 1 2 4 8 } + +if { $argc < 5 } { + puts "Usage: programm-path <Name of module> <output file> <output prefix> <number of retries> <number of operations for each insmod>" + exit 1 +} + +lassign $argv module filename prefix retries nr_ops + +set file [open $filename "a"] + +# This file writing is copied from https://stackoverflow.com/a/67265956 +proc writeToFile {string file pre} { + puts $file "$pre$string" +} + +set timeout 30 + +spawn sudo ../qemu/build/qemu-system-x86_64 \ + -m 8G \ + -object memory-backend-memfd,id=sysmem-file,size=8G \ + -numa node,memdev=sysmem-file \ + -smp 8 \ + -kernel ../spdm-linux/arch/x86/boot/bzImage \ + -append "console=ttyS0 root=/dev/sda rw earlyprintk=serial net.ifnames=0 nokaslr" \ + -drive file=../qemu-image.img,format=raw \ + -object memory-backend-file,size=1M,share=on,mem-path=/dev/shm/ivshmem,id=hostmem \ + -device ivshmem-plain,memdev=hostmem \ + -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 \ + -net nic,model=e1000 \ + -enable-kvm \ + -nographic \ + -cpu EPYC-v4,+vpclmulqdq \ + -no-reboot \ + -machine q35,confidential-guest-support=sev0 \ + -bios ../OVMF.fd \ + -device disagg-fake-pci,bar-size=1048576 \ + -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,policy=0x30000 + +# workaround to send a key-hit to the vm +# requires as it does not show login prompt otherwise (also not working with sleep) +expect { + timeout { + send "\r" + } +} + +expect "login:" { send "root\r" } +expect "Password:" { send "test\r" } +expect "#" { send "cd /modules\r" } + +foreach size $sizeList { + set i 0 + while { $i < $retries } { + expect "#" { send "insmod $module.ko mmio_size=$size count_ops=$nr_ops\r" } + set n 0 + + expect -re "time measured: (.+) end" { writeToFile $expect_out(1,string) $file $prefix } + + expect "#" { send "rmmod $module.ko\r" } + + puts stderr "$size: $i" + incr i + } +} + +expect "#" { send "shutdown -h now\r" } +expect eof + +close $file + |