mirror of
https://passt.top/passt
synced 2025-05-18 15:45:34 +02:00
rampstream: Add utility to test for corruption of data streams
Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
parent
6f122f0171
commit
a301158456
7 changed files with 267 additions and 4 deletions
1
test/.gitignore
vendored
1
test/.gitignore
vendored
|
@ -8,5 +8,6 @@ QEMU_EFI.fd
|
||||||
*.raw.xz
|
*.raw.xz
|
||||||
*.bin
|
*.bin
|
||||||
nstool
|
nstool
|
||||||
|
rampstream
|
||||||
guest-key
|
guest-key
|
||||||
guest-key.pub
|
guest-key.pub
|
||||||
|
|
|
@ -52,7 +52,8 @@ UBUNTU_IMGS = $(UBUNTU_OLD_IMGS) $(UBUNTU_NEW_IMGS)
|
||||||
|
|
||||||
DOWNLOAD_ASSETS = mbuto podman \
|
DOWNLOAD_ASSETS = mbuto podman \
|
||||||
$(DEBIAN_IMGS) $(FEDORA_IMGS) $(OPENSUSE_IMGS) $(UBUNTU_IMGS)
|
$(DEBIAN_IMGS) $(FEDORA_IMGS) $(OPENSUSE_IMGS) $(UBUNTU_IMGS)
|
||||||
TESTDATA_ASSETS = small.bin big.bin medium.bin
|
TESTDATA_ASSETS = small.bin big.bin medium.bin \
|
||||||
|
rampstream
|
||||||
LOCAL_ASSETS = mbuto.img mbuto.mem.img podman/bin/podman QEMU_EFI.fd \
|
LOCAL_ASSETS = mbuto.img mbuto.mem.img podman/bin/podman QEMU_EFI.fd \
|
||||||
$(DEBIAN_IMGS:%=prepared-%) $(FEDORA_IMGS:%=prepared-%) \
|
$(DEBIAN_IMGS:%=prepared-%) $(FEDORA_IMGS:%=prepared-%) \
|
||||||
$(UBUNTU_NEW_IMGS:%=prepared-%) \
|
$(UBUNTU_NEW_IMGS:%=prepared-%) \
|
||||||
|
@ -85,7 +86,7 @@ podman/bin/podman: pull-podman
|
||||||
guest-key guest-key.pub:
|
guest-key guest-key.pub:
|
||||||
ssh-keygen -f guest-key -N ''
|
ssh-keygen -f guest-key -N ''
|
||||||
|
|
||||||
mbuto.img: passt.mbuto mbuto/mbuto guest-key.pub $(TESTDATA_ASSETS)
|
mbuto.img: passt.mbuto mbuto/mbuto guest-key.pub rampstream-check.sh $(TESTDATA_ASSETS)
|
||||||
./mbuto/mbuto -p ./$< -c lz4 -f $@
|
./mbuto/mbuto -p ./$< -c lz4 -f $@
|
||||||
|
|
||||||
mbuto.mem.img: passt.mem.mbuto mbuto ../passt.avx2
|
mbuto.mem.img: passt.mem.mbuto mbuto ../passt.avx2
|
||||||
|
|
59
test/migrate/rampstream_in
Normal file
59
test/migrate/rampstream_in
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#
|
||||||
|
# PASST - Plug A Simple Socket Transport
|
||||||
|
# for qemu/UNIX domain socket mode
|
||||||
|
#
|
||||||
|
# PASTA - Pack A Subtle Tap Abstraction
|
||||||
|
# for network namespace/tap device mode
|
||||||
|
#
|
||||||
|
# test/migrate/basic - Check basic migration functionality
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 Red Hat GmbH
|
||||||
|
# Author: Stefano Brivio <sbrivio@redhat.com>
|
||||||
|
|
||||||
|
g1tools ip jq dhclient socat cat
|
||||||
|
htools ip jq
|
||||||
|
|
||||||
|
set MAP_HOST4 192.0.2.1
|
||||||
|
set MAP_HOST6 2001:db8:9a55::1
|
||||||
|
set MAP_NS4 192.0.2.2
|
||||||
|
set MAP_NS6 2001:db8:9a55::2
|
||||||
|
set RAMPS 6000000
|
||||||
|
|
||||||
|
test Interface name
|
||||||
|
g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
|
||||||
|
hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
|
||||||
|
hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
|
||||||
|
check [ -n "__IFNAME1__" ]
|
||||||
|
|
||||||
|
test DHCP: address
|
||||||
|
guest1 ip link set dev __IFNAME1__ up
|
||||||
|
guest1 /sbin/dhclient -4 __IFNAME1__
|
||||||
|
g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
|
||||||
|
hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
|
||||||
|
check [ "__ADDR1__" = "__HOST_ADDR__" ]
|
||||||
|
|
||||||
|
test DHCPv6: address
|
||||||
|
# Link is up now, wait for DAD to complete
|
||||||
|
guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
|
||||||
|
guest1 /sbin/dhclient -6 __IFNAME1__
|
||||||
|
# Wait for DAD to complete on the DHCP address
|
||||||
|
guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
|
||||||
|
g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
|
||||||
|
hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
|
||||||
|
check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
|
||||||
|
|
||||||
|
test TCP/IPv4: host > guest
|
||||||
|
g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
|
||||||
|
guest1b socat -u TCP4-LISTEN:10001 EXEC:"rampstream-check.sh __RAMPS__"
|
||||||
|
sleep 1
|
||||||
|
hostb socat -u EXEC:"test/rampstream send __RAMPS__" TCP4:__ADDR1__:10001
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
#mon echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
|
||||||
|
|
||||||
|
hostw
|
||||||
|
|
||||||
|
guest2 cat rampstream.err
|
||||||
|
guest2 [ $(cat rampstream.status) -eq 0 ]
|
55
test/migrate/rampstream_out
Normal file
55
test/migrate/rampstream_out
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#
|
||||||
|
# PASST - Plug A Simple Socket Transport
|
||||||
|
# for qemu/UNIX domain socket mode
|
||||||
|
#
|
||||||
|
# PASTA - Pack A Subtle Tap Abstraction
|
||||||
|
# for network namespace/tap device mode
|
||||||
|
#
|
||||||
|
# test/migrate/basic - Check basic migration functionality
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 Red Hat GmbH
|
||||||
|
# Author: Stefano Brivio <sbrivio@redhat.com>
|
||||||
|
|
||||||
|
g1tools ip jq dhclient socat cat
|
||||||
|
htools ip jq
|
||||||
|
|
||||||
|
set MAP_HOST4 192.0.2.1
|
||||||
|
set MAP_HOST6 2001:db8:9a55::1
|
||||||
|
set MAP_NS4 192.0.2.2
|
||||||
|
set MAP_NS6 2001:db8:9a55::2
|
||||||
|
set RAMPS 6000000
|
||||||
|
|
||||||
|
test Interface name
|
||||||
|
g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
|
||||||
|
hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
|
||||||
|
hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
|
||||||
|
check [ -n "__IFNAME1__" ]
|
||||||
|
|
||||||
|
test DHCP: address
|
||||||
|
guest1 ip link set dev __IFNAME1__ up
|
||||||
|
guest1 /sbin/dhclient -4 __IFNAME1__
|
||||||
|
g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
|
||||||
|
hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
|
||||||
|
check [ "__ADDR1__" = "__HOST_ADDR__" ]
|
||||||
|
|
||||||
|
test DHCPv6: address
|
||||||
|
# Link is up now, wait for DAD to complete
|
||||||
|
guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
|
||||||
|
guest1 /sbin/dhclient -6 __IFNAME1__
|
||||||
|
# Wait for DAD to complete on the DHCP address
|
||||||
|
guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
|
||||||
|
g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
|
||||||
|
hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
|
||||||
|
check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
|
||||||
|
|
||||||
|
test TCP/IPv4: guest > host
|
||||||
|
g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
|
||||||
|
hostb socat -u TCP4-LISTEN:10006 EXEC:"test/rampstream check __RAMPS__"
|
||||||
|
sleep 1
|
||||||
|
guest1b socat -u EXEC:"rampstream send __RAMPS__" TCP4:__MAP_HOST4__:10006
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
mon echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
|
||||||
|
|
||||||
|
hostw
|
|
@ -13,7 +13,8 @@
|
||||||
PROGS="${PROGS:-ash,dash,bash ip mount ls insmod mkdir ln cat chmod lsmod
|
PROGS="${PROGS:-ash,dash,bash ip mount ls insmod mkdir ln cat chmod lsmod
|
||||||
modprobe find grep mknod mv rm umount jq iperf3 dhclient hostname
|
modprobe find grep mknod mv rm umount jq iperf3 dhclient hostname
|
||||||
sed tr chown sipcalc cut socat dd strace ping tail killall sleep sysctl
|
sed tr chown sipcalc cut socat dd strace ping tail killall sleep sysctl
|
||||||
nproc tcp_rr tcp_crr udp_rr which tee seq bc sshd ssh-keygen cmp tcpdump env}"
|
nproc tcp_rr tcp_crr udp_rr which tee seq bc sshd ssh-keygen cmp tcpdump
|
||||||
|
env}"
|
||||||
|
|
||||||
# OpenSSH 9.8 introduced split binaries, with sshd being the daemon, and
|
# OpenSSH 9.8 introduced split binaries, with sshd being the daemon, and
|
||||||
# sshd-session the per-session program. We need the latter as well, and the path
|
# sshd-session the per-session program. We need the latter as well, and the path
|
||||||
|
@ -31,7 +32,7 @@ LINKS="${LINKS:-
|
||||||
|
|
||||||
DIRS="${DIRS} /tmp /usr/sbin /usr/share /var/log /var/lib /etc/ssh /run/sshd /root/.ssh"
|
DIRS="${DIRS} /tmp /usr/sbin /usr/share /var/log /var/lib /etc/ssh /run/sshd /root/.ssh"
|
||||||
|
|
||||||
COPIES="${COPIES} small.bin,/root/small.bin medium.bin,/root/medium.bin big.bin,/root/big.bin"
|
COPIES="${COPIES} small.bin,/root/small.bin medium.bin,/root/medium.bin big.bin,/root/big.bin rampstream,/bin/rampstream rampstream-check.sh,/bin/rampstream-check.sh"
|
||||||
|
|
||||||
FIXUP="${FIXUP}"'
|
FIXUP="${FIXUP}"'
|
||||||
mv /sbin/* /usr/sbin || :
|
mv /sbin/* /usr/sbin || :
|
||||||
|
|
3
test/rampstream-check.sh
Executable file
3
test/rampstream-check.sh
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
(rampstream check "$@" 2>&1; echo $? > rampstream.status) | tee rampstream.err
|
143
test/rampstream.c
Normal file
143
test/rampstream.c
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
/* rampstream - Generate a check and stream of bytes in a ramp pattern
|
||||||
|
*
|
||||||
|
* Copyright Red Hat
|
||||||
|
* Author: David Gibson <david@gibson.dropbear.id.au>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Length of the repeating ramp. This is a deliberately not a "round" number so
|
||||||
|
* that we're very likely to misalign with likely block or chunk sizes of the
|
||||||
|
* transport. That means we'll detect gaps in the stream, even if they occur
|
||||||
|
* neatly on block boundaries. Specifically this is the largest 8-bit prime. */
|
||||||
|
#define RAMPLEN 251
|
||||||
|
|
||||||
|
#define INTERVAL 10000
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0])))
|
||||||
|
|
||||||
|
#define die(...) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, "rampstream: " __VA_ARGS__); \
|
||||||
|
exit(1); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
die("Usage:\n"
|
||||||
|
" rampstream send <number>\n"
|
||||||
|
" Generate a ramp pattern of bytes on stdout, repeated <number>\n"
|
||||||
|
" times\n"
|
||||||
|
" rampstream check <number>\n"
|
||||||
|
" Check a ramp pattern of bytes on stdin, repeater <number>\n"
|
||||||
|
" times\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ramp_send(unsigned long long num, const uint8_t *ramp)
|
||||||
|
{
|
||||||
|
unsigned long long i;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
int off = 0;
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
if (i % INTERVAL == 0)
|
||||||
|
fprintf(stderr, "%llu...\r", i);
|
||||||
|
|
||||||
|
while (off < RAMPLEN) {
|
||||||
|
rc = write(1, ramp + off, RAMPLEN - off);
|
||||||
|
if (rc < 0) {
|
||||||
|
if (errno == EINTR ||
|
||||||
|
errno == EAGAIN ||
|
||||||
|
errno == EWOULDBLOCK)
|
||||||
|
continue;
|
||||||
|
die("Error writing ramp: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
if (rc == 0)
|
||||||
|
die("Zero length write\n");
|
||||||
|
off += rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ramp_check(unsigned long long num, const uint8_t *ramp)
|
||||||
|
{
|
||||||
|
unsigned long long i;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
uint8_t buf[RAMPLEN];
|
||||||
|
int off = 0;
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
if (i % INTERVAL == 0)
|
||||||
|
fprintf(stderr, "%llu...\r", i);
|
||||||
|
|
||||||
|
while (off < RAMPLEN) {
|
||||||
|
rc = read(0, buf + off, RAMPLEN - off);
|
||||||
|
if (rc < 0) {
|
||||||
|
if (errno == EINTR ||
|
||||||
|
errno == EAGAIN ||
|
||||||
|
errno == EWOULDBLOCK)
|
||||||
|
continue;
|
||||||
|
die("Error reading ramp: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
if (rc == 0)
|
||||||
|
die("Unexpected EOF, ramp %llu, byte %d\n",
|
||||||
|
i, off);
|
||||||
|
off += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(buf, ramp, sizeof(buf)) != 0) {
|
||||||
|
int j, k;
|
||||||
|
|
||||||
|
for (j = 0; j < RAMPLEN; j++)
|
||||||
|
if (buf[j] != ramp[j])
|
||||||
|
break;
|
||||||
|
for (k = j; k < RAMPLEN && k < j + 16; k++)
|
||||||
|
fprintf(stderr,
|
||||||
|
"Byte %d: expected 0x%02x, got 0x%02x\n",
|
||||||
|
k, ramp[k], buf[k]);
|
||||||
|
die("Data mismatch, ramp %llu, byte %d\n", i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
const char *subcmd = argv[1];
|
||||||
|
unsigned long long num;
|
||||||
|
uint8_t ramp[RAMPLEN];
|
||||||
|
char *e;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
num = strtoull(argv[2], &e, 0);
|
||||||
|
if (*e || errno)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
/* Initialize the ramp block */
|
||||||
|
for (i = 0; i < RAMPLEN; i++)
|
||||||
|
ramp[i] = i;
|
||||||
|
|
||||||
|
if (strcmp(subcmd, "send") == 0)
|
||||||
|
ramp_send(num, ramp);
|
||||||
|
else if (strcmp(subcmd, "check") == 0)
|
||||||
|
ramp_check(num, ramp);
|
||||||
|
else
|
||||||
|
usage();
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue