mirror of
https://passt.top/passt
synced 2025-05-05 18:28:52 +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
|
||||
*.bin
|
||||
nstool
|
||||
rampstream
|
||||
guest-key
|
||||
guest-key.pub
|
||||
|
|
|
@ -52,7 +52,8 @@ UBUNTU_IMGS = $(UBUNTU_OLD_IMGS) $(UBUNTU_NEW_IMGS)
|
|||
|
||||
DOWNLOAD_ASSETS = mbuto podman \
|
||||
$(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 \
|
||||
$(DEBIAN_IMGS:%=prepared-%) $(FEDORA_IMGS:%=prepared-%) \
|
||||
$(UBUNTU_NEW_IMGS:%=prepared-%) \
|
||||
|
@ -85,7 +86,7 @@ podman/bin/podman: pull-podman
|
|||
guest-key guest-key.pub:
|
||||
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.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
|
||||
modprobe find grep mknod mv rm umount jq iperf3 dhclient hostname
|
||||
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
|
||||
# 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"
|
||||
|
||||
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}"'
|
||||
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