aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/ci/Makefile44
-rw-r--r--tests/ci/Makefile.aarch642
-rw-r--r--tests/ci/Makefile.armv72
-rw-r--r--tests/ci/Makefile.powerpc641
-rw-r--r--tests/ci/Makefile.powerpc64le1
-rw-r--r--tests/ci/Makefile.riscv641
-rwxr-xr-xtests/ci/tools/freebsdci9
-rw-r--r--tests/sys/cam/ctl/ctl.subr9
-rw-r--r--tests/sys/fs/fusefs/Makefile3
-rw-r--r--tests/sys/kern/Makefile1
-rw-r--r--tests/sys/kern/exterr_test.c108
-rw-r--r--tests/sys/mac/bsdextended/Makefile1
-rw-r--r--tests/sys/mac/bsdextended/matches_test.sh3
-rw-r--r--tests/sys/mac/portacl/Makefile1
-rwxr-xr-xtests/sys/net/if_bridge_test.sh4
-rw-r--r--tests/sys/net/if_ovpn/if_ovpn.sh258
-rw-r--r--tests/sys/netpfil/common/dummynet.sh4
-rw-r--r--tests/sys/netpfil/pf/Makefile2
-rw-r--r--tests/sys/netpfil/pf/forward.sh4
-rw-r--r--tests/sys/netpfil/pf/icmp.py19
-rw-r--r--tests/sys/netpfil/pf/igmp.py95
-rw-r--r--tests/sys/netpfil/pf/killstate.sh4
-rw-r--r--tests/sys/netpfil/pf/mbuf.sh6
-rw-r--r--tests/sys/netpfil/pf/mld.py95
-rw-r--r--tests/sys/netpfil/pf/nat64.py15
-rw-r--r--tests/sys/netpfil/pf/set_tos.sh4
-rw-r--r--tests/sys/netpfil/pf/table.sh29
27 files changed, 663 insertions, 62 deletions
diff --git a/tests/ci/Makefile b/tests/ci/Makefile
index 44b19663fc49..48e638fdb79c 100644
--- a/tests/ci/Makefile
+++ b/tests/ci/Makefile
@@ -33,11 +33,11 @@ EXTRA_MAKE_FLAGS?=
TARGET= ${MACHINE}
.endif
.if !defined(TARGET_ARCH) || empty(TARGET_ARCH)
-.if ${TARGET} == ${MACHINE}
+. if ${TARGET} == ${MACHINE}
TARGET_ARCH= ${MACHINE_ARCH}
-.else
+. else
TARGET_ARCH= ${TARGET}
-.endif
+. endif
.endif
IMAKE= ${MAKE} TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}
@@ -47,20 +47,20 @@ CROSS_TOOLCHAIN_PARAM= "CROSS_TOOLCHAIN=${CROSS_TOOLCHAIN}"
# Define OSRELEASE by using newvers.sh
.if !defined(OSRELEASE) || empty(OSRELEASE)
-.for _V in TYPE BRANCH REVISION
-. if !defined(${_V}) || empty(${_V})
+. for _V in TYPE BRANCH REVISION
+. if !defined(${_V}) || empty(${_V})
${_V}!= eval $$(awk '/^${_V}=/{print}' ${.CURDIR}/../../sys/conf/newvers.sh); echo $$${_V}
-. endif
-.endfor
-.for _V in ${TARGET_ARCH}
-.if !empty(TARGET:M${_V})
+. endif
+. endfor
+. for _V in ${TARGET_ARCH}
+. if !empty(TARGET:M${_V})
OSRELEASE= ${TYPE}-${REVISION}-${BRANCH}-${TARGET}
VOLUME_LABEL= ${REVISION:C/[.-]/_/g}_${BRANCH:C/[.-]/_/g}_${TARGET}
-.else
+. else
OSRELEASE= ${TYPE}-${REVISION}-${BRANCH}-${TARGET}-${TARGET_ARCH}
VOLUME_LABEL= ${REVISION:C/[.-]/_/g}_${BRANCH:C/[.-]/_/g}_${TARGET_ARCH}
-.endif
-.endfor
+. endif
+. endfor
.endif
.if exists(${.CURDIR}/tools/ci.conf) && !defined(CICONF)
@@ -104,13 +104,13 @@ TIMEOUT_VM=$$((${TIMEOUT_EXPECT} - 120))
. include "${.CURDIR}/Makefile.${TARGET_ARCH}"
.endif
.if ${TARGET_ARCH} != ${MACHINE_ARCH}
-.if ( ${TARGET_ARCH} != "i386" ) || ( ${MACHINE_ARCH} != "amd64" )
+. if ( ${TARGET_ARCH} != "i386" ) || ( ${MACHINE_ARCH} != "amd64" )
QEMUSTATIC=/usr/local/bin/qemu-${QEMU_ARCH}-static
QEMUTGT=portinstall-qemu
-.endif
+. endif
.endif
QEMUTGT?=
-QEMU_DEVICES?=-device virtio-blk,drive=hd0
+QEMU_DEVICES?=
QEMU_EXTRA_PARAM?=
QEMU_MACHINE?=virt
QEMUBIN=/usr/local/bin/qemu-system-${QEMU_ARCH}
@@ -134,7 +134,8 @@ METAMODE?=-DWITH_META_MODE
.endif
CLEANFILES+= ${.OBJDIR}/${CIIMAGE} ${.OBJDIR}/ci.img ${META_TAR}
-CLEANDIRS+= ${.OBJDIR}/ci-buildimage
+IMAGEDIR= ${.OBJDIR}/ci-buildimage
+CLEANDIRS+= ${IMAGEDIR}
portinstall: portinstall-pkg portinstall-qemu portinstall-expect portinstall-${TARGET_ARCH:tl} .PHONY
@@ -157,7 +158,7 @@ portinstall-expect: portinstall-pkg .PHONY
.endif
beforeclean: .PHONY
- chflags -R noschg ${.OBJDIR}/${.TARGET}
+ chflags -R noschg ${IMAGEDIR}
.include <bsd.obj.mk>
clean: beforeclean .PHONY
@@ -205,6 +206,7 @@ ci-create-meta: .PHONY
ci-extract-meta: .PHONY
tar xfv ${META_TAR} -C ${META_DIROUT}
+ rm -rf ${META_TAR} ${META_DIR}
@echo "Extracted kyua reports to ${META_DIROUT}"
ci-runtest: ci-buildimage-${TARGET_ARCH:tl} portinstall .PHONY
@@ -235,8 +237,10 @@ ci-runtest: ci-buildimage-${TARGET_ARCH:tl} portinstall .PHONY
-nographic \
-no-reboot \
${QEMU_EXTRA_PARAM} \
- -drive if=none,file=${CIDISK},format=raw,id=hd0 \
- -drive if=none,file=${META_TAR},format=raw,id=hd1 \
+ -device virtio-blk,drive=hd0 \
+ -device virtio-blk,drive=hd1 \
+ -blockdev driver=raw,node-name=hd0,file.driver=file,file.filename=${CIDISK} \
+ -blockdev driver=raw,node-name=hd1,file.driver=file,file.filename=${META_TAR} \
${QEMU_DEVICES}
.endif
@@ -254,7 +258,7 @@ ci-checktarget: .PHONY
ci-smoke: ci-set-smoke-var ci-create-meta ci-checktarget .WAIT ci-runtest-${TARGET_ARCH:tl} .PHONY
-ci-full: ci-set-full-var ci-create-meta ci-checktarget .WAIT ci-runtest-${TARGET_ARCH:tl} ci-extract-meta .PHONY
+ci-full: ci-set-full-var ci-create-meta ci-checktarget .WAIT ci-runtest-${TARGET_ARCH:tl} .WAIT ci-extract-meta .PHONY
ci: ci-${CITYPE:tl} .PHONY
diff --git a/tests/ci/Makefile.aarch64 b/tests/ci/Makefile.aarch64
index 9cbec6010a36..5a62e73d8eaa 100644
--- a/tests/ci/Makefile.aarch64
+++ b/tests/ci/Makefile.aarch64
@@ -8,7 +8,7 @@
# CI Makefile for aarch64.
#
QEMU_ARCH=aarch64
-QEMU_DEVICES=-device virtio-blk,drive=hd0 -device ahci,id=ahci
+QEMU_DEVICES=-device ahci,id=ahci
QEMU_EXTRA_PARAM=-bios /usr/local/share/u-boot/u-boot-qemu-arm64/u-boot.bin -cpu cortex-a57
QEMU_MAX_CPU_COUNT=64
QEMU_MAX_MEM_SIZE=64
diff --git a/tests/ci/Makefile.armv7 b/tests/ci/Makefile.armv7
index 21ee6b387b05..3b0d180fa352 100644
--- a/tests/ci/Makefile.armv7
+++ b/tests/ci/Makefile.armv7
@@ -8,7 +8,7 @@
# CI Makefile for armv7.
#
QEMU_ARCH=arm
-QEMU_DEVICES=-device virtio-blk,drive=hd0 -device ahci,id=ahci
+QEMU_DEVICES=-device ahci,id=ahci
QEMU_EXTRA_PARAM=-bios /usr/local/share/u-boot/u-boot-qemu-arm/u-boot.bin
QEMU_MAX_CPU_COUNT=1
QEMU_MAX_MEM_SIZE=3
diff --git a/tests/ci/Makefile.powerpc64 b/tests/ci/Makefile.powerpc64
index 26712b45f30b..d4e8e2cdc778 100644
--- a/tests/ci/Makefile.powerpc64
+++ b/tests/ci/Makefile.powerpc64
@@ -8,7 +8,6 @@
# CI Makefile for powerpc64.
#
QEMU_ARCH=ppc64
-QEMU_DEVICES=-device virtio-blk,drive=hd0
QEMU_EXTRA_PARAM=-vga none -accel tcg,thread=multi
QEMU_MACHINE=pseries,cap-hpt-max-page-size=16M
QEMU_MAX_CPU_COUNT=1
diff --git a/tests/ci/Makefile.powerpc64le b/tests/ci/Makefile.powerpc64le
index 974ab04b8eed..60c255f569fa 100644
--- a/tests/ci/Makefile.powerpc64le
+++ b/tests/ci/Makefile.powerpc64le
@@ -8,7 +8,6 @@
# CI Makefile for powerpc64le.
#
QEMU_ARCH=ppc64
-QEMU_DEVICES=-device virtio-blk,drive=hd0
QEMU_EXTRA_PARAM=-vga none -accel tcg,thread=multi
QEMU_MACHINE=pseries,cap-hpt-max-page-size=16M
QEMU_MAX_CPU_COUNT=1
diff --git a/tests/ci/Makefile.riscv64 b/tests/ci/Makefile.riscv64
index 749df3f0b369..d494fc4f43f5 100644
--- a/tests/ci/Makefile.riscv64
+++ b/tests/ci/Makefile.riscv64
@@ -8,7 +8,6 @@
# CI Makefile for riscv64.
#
QEMU_ARCH=riscv64
-QEMU_DEVICES=-device virtio-blk-device,drive=hd0
QEMU_EXTRA_PARAM=-bios /usr/local/share/opensbi/lp64/generic/firmware/fw_jump.elf -kernel /usr/local/share/u-boot/u-boot-qemu-riscv64/u-boot.bin
QEMU_MAX_CPU_COUNT=16
QEMU_MAX_MEM_SIZE=64
diff --git a/tests/ci/tools/freebsdci b/tests/ci/tools/freebsdci
index 7b4ce9669ab2..51bd19e2967d 100755
--- a/tests/ci/tools/freebsdci
+++ b/tests/ci/tools/freebsdci
@@ -25,9 +25,6 @@
. /etc/rc.subr
-: ${freebsdci_enable:="NO"}
-: ${freebsdci_type:="full"}
-
name="freebsdci"
desc="Run FreeBSD CI"
rcvar=freebsdci_enable
@@ -39,6 +36,11 @@ tardev=/dev/vtbd1
metadir=/meta
istar=$(file -s ${tardev} | grep "POSIX tar archive" | wc -l)
+load_rc_config $name
+: ${freebsdci_enable:="NO"}
+: ${freebsdci_type:="full"}
+PATH="${PATH}:/usr/local/sbin:/usr/local/bin"
+
auto_shutdown()
{
# NOTE: Currently RISC-V kernels lack the ability to
@@ -105,5 +107,4 @@ firstboot_ci_run()
auto_shutdown
}
-load_rc_config $name
run_rc_command "$1"
diff --git a/tests/sys/cam/ctl/ctl.subr b/tests/sys/cam/ctl/ctl.subr
index 5da441b806f0..6cc02d774bdb 100644
--- a/tests/sys/cam/ctl/ctl.subr
+++ b/tests/sys/cam/ctl/ctl.subr
@@ -25,15 +25,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-load_modules() {
- if ! kldstat -q -m ctl; then
- kldload ctl || atf_skip "could not load ctl kernel mod"
- fi
- if ! ctladm port -o on -p 0; then
- atf_skip "could not enable the camsim frontend"
- fi
-}
-
find_device() {
LUN=$1
diff --git a/tests/sys/fs/fusefs/Makefile b/tests/sys/fs/fusefs/Makefile
index b11f11bdfa98..a21512798597 100644
--- a/tests/sys/fs/fusefs/Makefile
+++ b/tests/sys/fs/fusefs/Makefile
@@ -70,7 +70,8 @@ TEST_METADATA.nfs+= required_user="root"
TEST_METADATA.ctl+= is_exclusive="true"
TEST_METADATA.ctl+= required_user="root"
-TEST_METADATA+= timeout=10
+TEST_METADATA+= timeout=10
+TEST_METADATA+= required_kmods="fusefs"
FUSEFS= ${SRCTOP}/sys/fs/fuse
# Suppress warnings that GCC generates for the libc++ and gtest headers.
diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile
index f2c24ad9dec9..336e73f29835 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -17,6 +17,7 @@ ATF_TESTS_C+= kern_copyin
ATF_TESTS_C+= kern_descrip_test
# One test modifies the maxfiles limit, which can cause spurious test failures.
TEST_METADATA.kern_descrip_test+= is_exclusive="true"
+ATF_TESTS_C+= exterr_test
ATF_TESTS_C+= fdgrowtable_test
ATF_TESTS_C+= getdirentries_test
ATF_TESTS_C+= jail_lookup_root
diff --git a/tests/sys/kern/exterr_test.c b/tests/sys/kern/exterr_test.c
new file mode 100644
index 000000000000..17c84c1f8ed4
--- /dev/null
+++ b/tests/sys/kern/exterr_test.c
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (C) 2025 ConnectWise, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/exterrvar.h>
+#include <sys/mman.h>
+
+#include <atf-c.h>
+#include <errno.h>
+#include <exterr.h>
+#include <stdio.h>
+
+ATF_TC(gettext_extended);
+ATF_TC_HEAD(gettext_extended, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Retrieve an extended error message");
+}
+ATF_TC_BODY(gettext_extended, tc)
+{
+ char exterr[UEXTERROR_MAXLEN];
+ int r;
+
+ /*
+ * Use an invalid call to mmap() because it supports extended error
+ * messages, requires no special resources, and does not need root.
+ */
+ ATF_CHECK_ERRNO(ENOTSUP,
+ mmap(NULL, 0, PROT_MAX(PROT_READ) | PROT_WRITE, 0, -1, 0));
+ r = uexterr_gettext(exterr, sizeof(exterr));
+ ATF_CHECK_EQ(0, r);
+ printf("Extended error: %s\n", exterr);
+ /* Note: error string may need to be updated due to kernel changes */
+ ATF_CHECK(strstr(exterr, "prot is not subset of max_prot") != 0);
+}
+
+ATF_TC(gettext_noextended);
+ATF_TC_HEAD(gettext_noextended, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Fail to retrieve an extended error message because none exists");
+}
+ATF_TC_BODY(gettext_noextended, tc)
+{
+ char exterr[UEXTERROR_MAXLEN];
+ int r;
+
+ ATF_CHECK_ERRNO(EINVAL, exterrctl(EXTERRCTL_UD, 0, NULL));
+ r = uexterr_gettext(exterr, sizeof(exterr));
+ ATF_CHECK_EQ(0, r);
+ ATF_CHECK_STREQ(exterr, "");
+}
+
+ATF_TC(gettext_noextended_after_extended);
+ATF_TC_HEAD(gettext_noextended_after_extended, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "uexterr_gettext should not return a stale extended error message");
+}
+ATF_TC_BODY(gettext_noextended_after_extended, tc)
+{
+ char exterr[UEXTERROR_MAXLEN];
+ int r;
+
+ /*
+ * First do something that will create an extended error message, but
+ * ignore it.
+ */
+ ATF_CHECK_ERRNO(ENOTSUP,
+ mmap(NULL, 0, PROT_MAX(PROT_READ) | PROT_WRITE, 0, -1, 0));
+
+ /* Then do something that won't create an extended error message */
+ ATF_CHECK_ERRNO(EINVAL, exterrctl(EXTERRCTL_UD, 0, NULL));
+
+ /* Hopefully we won't see the stale extended error message */
+ r = uexterr_gettext(exterr, sizeof(exterr));
+ ATF_CHECK_EQ(0, r);
+ ATF_CHECK_STREQ(exterr, "");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, gettext_extended);
+ ATF_TP_ADD_TC(tp, gettext_noextended);
+ ATF_TP_ADD_TC(tp, gettext_noextended_after_extended);
+
+ return (atf_no_error());
+}
diff --git a/tests/sys/mac/bsdextended/Makefile b/tests/sys/mac/bsdextended/Makefile
index 69cd27c0e321..cc3a3f8ea534 100644
--- a/tests/sys/mac/bsdextended/Makefile
+++ b/tests/sys/mac/bsdextended/Makefile
@@ -9,5 +9,6 @@ TEST_METADATA.ugidfw_test+= required_user="root"
# Each test case of matches_test reuses the same ruleset number, so they cannot
# be run simultaneously
TEST_METADATA.matches_test+= is_exclusive=true
+TEST_METADATA+= required_kmods="mac_bsdextended"
.include <bsd.test.mk>
diff --git a/tests/sys/mac/bsdextended/matches_test.sh b/tests/sys/mac/bsdextended/matches_test.sh
index 2a28be0f231b..41fa04f221e3 100644
--- a/tests/sys/mac/bsdextended/matches_test.sh
+++ b/tests/sys/mac/bsdextended/matches_test.sh
@@ -12,9 +12,6 @@ gidoutrange="daemon" # We expect $uidinrange in this group
check_ko()
{
- if ! sysctl -N security.mac.bsdextended >/dev/null 2>&1; then
- atf_skip "mac_bsdextended(4) support isn't available"
- fi
if [ $(sysctl -n security.mac.bsdextended.enabled) = "0" ]; then
# The kernel module is loaded but disabled. Enable it for the
# duration of the test.
diff --git a/tests/sys/mac/portacl/Makefile b/tests/sys/mac/portacl/Makefile
index c9fb6bbaae3e..856a85d331d5 100644
--- a/tests/sys/mac/portacl/Makefile
+++ b/tests/sys/mac/portacl/Makefile
@@ -10,6 +10,7 @@ TAP_TESTS_SH+= root_test
.for t in ${TAP_TESTS_SH}
TEST_METADATA.$t+= required_user="root"
TEST_METADATA.$t+= timeout="450"
+TEST_METADATA.$t+= is_exclusive="true"
.endfor
.include <bsd.test.mk>
diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh
index cc0b212aebd2..cd38adea28ad 100755
--- a/tests/sys/net/if_bridge_test.sh
+++ b/tests/sys/net/if_bridge_test.sh
@@ -537,7 +537,7 @@ get_mtu()
{
intf=$1
- ifconfig ${intf} ether | awk '$5 == "mtu" { print $6 }'
+ ifconfig ${intf} | awk '$5 == "mtu" { print $6 }'
}
check_mtu()
@@ -546,7 +546,7 @@ check_mtu()
expected=$2
mtu=$(get_mtu $intf)
- if [ $mtu -ne $expected ];
+ if [ "$mtu" -ne "$expected" ];
then
atf_fail "Expected MTU of $expected on $intf but found $mtu"
fi
diff --git a/tests/sys/net/if_ovpn/if_ovpn.sh b/tests/sys/net/if_ovpn/if_ovpn.sh
index 2138e0f666ec..c42344da1a3b 100644
--- a/tests/sys/net/if_ovpn/if_ovpn.sh
+++ b/tests/sys/net/if_ovpn/if_ovpn.sh
@@ -1149,6 +1149,261 @@ destroy_unused_cleanup()
ovpn_cleanup
}
+atf_test_case "multihome4" "cleanup"
+multihome4_head()
+{
+ atf_set descr 'Test multihome IPv4 with OpenVPN'
+ atf_set require.user root
+ atf_set require.progs openvpn
+}
+
+multihome4_body()
+{
+ pft_init
+ ovpn_init
+
+ l=$(vnet_mkepair)
+
+ vnet_mkjail a ${l}a
+ atf_check jexec a ifconfig ${l}a inet 192.0.2.1/24
+ atf_check jexec a ifconfig ${l}a alias 192.0.2.2/24
+ vnet_mkjail b ${l}b
+ atf_check jexec b ifconfig ${l}b inet 192.0.2.3/24
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore jexec b ping -c 1 192.0.2.1
+ atf_check -s exit:0 -o ignore jexec b ping -c 1 192.0.2.2
+
+ ovpn_start a "
+ dev ovpn0
+ dev-type tun
+ proto udp4
+
+ cipher AES-256-GCM
+ auth SHA256
+
+ multihome
+ server 198.51.100.0 255.255.255.0
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/server.crt
+ key $(atf_get_srcdir)/server.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ mode server
+ script-security 2
+ auth-user-pass-verify /usr/bin/true via-env
+ topology subnet
+
+ keepalive 100 600
+ "
+ ovpn_start b "
+ dev tun0
+ dev-type tun
+
+ client
+
+ remote 192.0.2.2
+ auth-user-pass $(atf_get_srcdir)/user.pass
+
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/client.crt
+ key $(atf_get_srcdir)/client.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ keepalive 100 600
+ "
+
+ # Block packets from the primary address, openvpn should only use the
+ # configured remote address.
+ jexec b pfctl -e
+ pft_set_rules b \
+ "block in quick from 192.0.2.1 to any" \
+ "pass all"
+
+ # Give the tunnel time to come up
+ sleep 10
+
+ atf_check -s exit:0 -o ignore jexec b ping -c 3 198.51.100.1
+}
+
+multihome4_cleanup()
+{
+ ovpn_cleanup
+ pft_cleanup
+}
+
+multihome6_head()
+{
+ atf_set descr 'Test multihome IPv6 with OpenVPN'
+ atf_set require.user root
+ atf_set require.progs openvpn
+}
+
+multihome6_body()
+{
+ ovpn_init
+
+ l=$(vnet_mkepair)
+
+ vnet_mkjail a ${l}a
+ atf_check jexec a ifconfig ${l}a inet6 2001:db8::1/64 no_dad
+ atf_check jexec a ifconfig ${l}a inet6 alias 2001:db8::2/64 no_dad
+ vnet_mkjail b ${l}b
+ atf_check jexec b ifconfig ${l}b inet6 2001:db8::3/64 no_dad
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore jexec b ping6 -c 1 2001:db8::1
+ atf_check -s exit:0 -o ignore jexec b ping6 -c 1 2001:db8::2
+
+ ovpn_start a "
+ dev ovpn0
+ dev-type tun
+ proto udp6
+
+ cipher AES-256-GCM
+ auth SHA256
+
+ multihome
+ server-ipv6 2001:db8:1::/64
+
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/server.crt
+ key $(atf_get_srcdir)/server.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ mode server
+ script-security 2
+ auth-user-pass-verify /usr/bin/true via-env
+ topology subnet
+
+ keepalive 100 600
+ "
+ ovpn_start b "
+ dev tun0
+ dev-type tun
+
+ client
+
+ remote 2001:db8::2
+ auth-user-pass $(atf_get_srcdir)/user.pass
+
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/client.crt
+ key $(atf_get_srcdir)/client.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ keepalive 100 600
+ "
+
+ # Block packets from the primary address, openvpn should only use the
+ # configured remote address.
+ jexec b pfctl -e
+ pft_set_rules b \
+ "block in quick from 2001:db8::1 to any" \
+ "pass all"
+
+ # Give the tunnel time to come up
+ sleep 10
+
+ atf_check -s exit:0 -o ignore jexec b ping6 -c 3 2001:db8:1::1
+ atf_check -s exit:0 -o ignore jexec b ping6 -c 3 -z 16 2001:db8:1::1
+}
+
+multihome6_cleanup()
+{
+ ovpn_cleanup
+}
+
+atf_test_case "float" "cleanup"
+float_head()
+{
+ atf_set descr 'Test peer float notification'
+ atf_set require.user root
+}
+
+float_body()
+{
+ ovpn_init
+
+ l=$(vnet_mkepair)
+
+ vnet_mkjail a ${l}a
+ jexec a ifconfig ${l}a 192.0.2.1/24 up
+ jexec a ifconfig lo0 127.0.0.1/8 up
+ vnet_mkjail b ${l}b
+ jexec b ifconfig ${l}b 192.0.2.2/24 up
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore jexec a ping -c 1 192.0.2.2
+
+ ovpn_start a "
+ dev ovpn0
+ dev-type tun
+ proto udp4
+
+ cipher AES-256-GCM
+ auth SHA256
+
+ local 192.0.2.1
+ server 198.51.100.0 255.255.255.0
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/server.crt
+ key $(atf_get_srcdir)/server.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ mode server
+ script-security 2
+ auth-user-pass-verify /usr/bin/true via-env
+ topology subnet
+
+ keepalive 2 10
+
+ management 192.0.2.1 1234
+ "
+ ovpn_start b "
+ dev tun0
+ dev-type tun
+
+ client
+
+ remote 192.0.2.1
+ auth-user-pass $(atf_get_srcdir)/user.pass
+
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/client.crt
+ key $(atf_get_srcdir)/client.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ keepalive 2 10
+ "
+
+ # Give the tunnel time to come up
+ sleep 10
+
+ atf_check -s exit:0 -o ignore jexec b ping -c 3 198.51.100.1
+
+ # We expect the client on 192.0.2.2
+ if ! echo "status" | jexec a nc -N 192.0.2.1 1234 | grep 192.0.2.2; then
+ atf_fail "Client not found in status list!"
+ fi
+
+ # Now change the client IP
+ jexec b ifconfig ${l}b 192.0.2.3/24 up
+
+ # And wait for keepalives to trigger the float notification
+ sleep 5
+
+ # So the client now has the new address in userspace
+ if ! echo "status" | jexec a nc -N 192.0.2.1 1234 | grep 192.0.2.3; then
+ atf_fail "Client not found in status list!"
+ fi
+}
+
+float_cleanup()
+{
+ ovpn_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "4in4"
@@ -1165,4 +1420,7 @@ atf_init_test_cases()
atf_add_test_case "chacha"
atf_add_test_case "gcm_128"
atf_add_test_case "destroy_unused"
+ atf_add_test_case "multihome4"
+ atf_add_test_case "multihome6"
+ atf_add_test_case "float"
}
diff --git a/tests/sys/netpfil/common/dummynet.sh b/tests/sys/netpfil/common/dummynet.sh
index b77b2df84010..66736fbecdb7 100644
--- a/tests/sys/netpfil/common/dummynet.sh
+++ b/tests/sys/netpfil/common/dummynet.sh
@@ -265,10 +265,6 @@ queue_body()
{
fw=$1
- if [ $fw = "ipfw" ] && [ "$(atf_config_get ci false)" = "true" ]; then
- atf_skip "https://bugs.freebsd.org/264805"
- fi
-
firewall_init $fw
dummynet_init $fw
diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile
index 3adaef09ddbd..404d5adfb07a 100644
--- a/tests/sys/netpfil/pf/Makefile
+++ b/tests/sys/netpfil/pf/Makefile
@@ -58,6 +58,8 @@ ATF_TESTS_SH+= altq \
ATF_TESTS_PYTEST+= frag6.py
ATF_TESTS_PYTEST+= header.py
ATF_TESTS_PYTEST+= icmp.py
+ATF_TESTS_PYTEST+= igmp.py
+ATF_TESTS_PYTEST+= mld.py
ATF_TESTS_PYTEST+= nat64.py
ATF_TESTS_PYTEST+= nat66.py
ATF_TESTS_PYTEST+= return.py
diff --git a/tests/sys/netpfil/pf/forward.sh b/tests/sys/netpfil/pf/forward.sh
index 5d7d48a5dd9a..e9539bc9d278 100644
--- a/tests/sys/netpfil/pf/forward.sh
+++ b/tests/sys/netpfil/pf/forward.sh
@@ -101,10 +101,6 @@ v6_body()
{
pft_init
- if [ "$(atf_config_get ci false)" = "true" ]; then
- atf_skip "https://bugs.freebsd.org/260460"
- fi
-
epair_send=$(vnet_mkepair)
epair_recv=$(vnet_mkepair)
diff --git a/tests/sys/netpfil/pf/icmp.py b/tests/sys/netpfil/pf/icmp.py
index 59f2e8190b30..c5e945d60e99 100644
--- a/tests/sys/netpfil/pf/icmp.py
+++ b/tests/sys/netpfil/pf/icmp.py
@@ -136,8 +136,7 @@ class TestICMP(VnetTestTemplate):
/ sp.ICMP(type='echo-request') \
/ sp.raw(bytes.fromhex('f0') * payload_size)
- p = sp.sr1(packet, iface=self.vnet.iface_alias_map["if1"].name,
- timeout=3)
+ p = sp.sr1(packet, timeout=3)
p.show()
ip = p.getlayer(sp.IP)
@@ -176,6 +175,22 @@ class TestICMP(VnetTestTemplate):
self.check_icmp_echo(sp, 1464)
self.check_icmp_echo(sp, 1468)
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_truncated_opts(self):
+ ToolsHelper.print_output("/sbin/route add default 192.0.2.1")
+
+ # Import in the correct vnet, so at to not confuse Scapy
+ import scapy.all as sp
+
+ packet = sp.IP(dst="198.51.100.2", flags="DF") \
+ / sp.ICMP(type='dest-unreach', length=108) \
+ / sp.IP(src="198.51.100.2", dst="192.0.2.2", len=1000, \
+ ihl=(120 >> 2), options=[ \
+ sp.IPOption_Security(length=100)])
+ packet.show()
+ sp.sr1(packet, timeout=3)
+
class TestICMP_NAT(VnetTestTemplate):
REQUIRED_MODULES = [ "pf" ]
TOPOLOGY = {
diff --git a/tests/sys/netpfil/pf/igmp.py b/tests/sys/netpfil/pf/igmp.py
new file mode 100644
index 000000000000..b339a2825082
--- /dev/null
+++ b/tests/sys/netpfil/pf/igmp.py
@@ -0,0 +1,95 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 Rubicon Communications, LLC (Netgate)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+import pytest
+from utils import DelayedSend
+from atf_python.sys.net.tools import ToolsHelper
+from atf_python.sys.net.vnet import VnetTestTemplate
+
+class TestIGMP(VnetTestTemplate):
+ REQUIRED_MODULES = [ "pf" ]
+ TOPOLOGY = {
+ "vnet1": {"ifaces": ["if1"]},
+ "vnet2": {"ifaces": ["if1"]},
+ "if1": {"prefixes4": [("192.0.2.2/24", "192.0.2.1/24")]},
+ }
+
+ def vnet2_handler(self, vnet):
+ ifname = vnet.iface_alias_map["if1"].name
+ ToolsHelper.print_output("/sbin/pfctl -e")
+ ToolsHelper.pf_rules([
+ "pass",
+ ])
+ ToolsHelper.print_output("/sbin/pfctl -x loud")
+ ToolsHelper.print_output("echo \"j 230.0.0.1 %s\ns 3600\nq\" | /usr/sbin/mtest" % ifname)
+
+ def find_igmp_reply(self, pkt, ifname):
+ pkt.show()
+ s = DelayedSend(pkt)
+
+ found = False
+ packets = self.sp.sniff(iface=ifname, timeout=5)
+ for r in packets:
+ r.show()
+ igmp = r.getlayer(self.sc.igmp.IGMP)
+ if not igmp:
+ continue
+ igmp.show()
+ if not igmp.gaddr == "230.0.0.1":
+ continue
+ found = True
+ return found
+
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_ip_opts(self):
+ """Verify that we allow IGMP packets with IP options"""
+ ifname = self.vnet.iface_alias_map["if1"].name
+
+ # Import in the correct vnet, so at to not confuse Scapy
+ import scapy.all as sp
+ import scapy.contrib as sc
+ import scapy.contrib.igmp
+ self.sp = sp
+ self.sc = sc
+
+ # We allow IGMP packets with the router alert option
+ pkt = sp.IP(dst="224.0.0.1%%%s" % ifname, ttl=1,
+ options=[sp.IPOption_Router_Alert()]) \
+ / sc.igmp.IGMP(type=0x11, mrcode=1)
+ assert self.find_igmp_reply(pkt, ifname)
+
+ # But not with other options
+ pkt = sp.IP(dst="224.0.0.1%%%s" % ifname, ttl=1,
+ options=[sp.IPOption_NOP()]) \
+ / sc.igmp.IGMP(type=0x11, mrcode=1)
+ assert not self.find_igmp_reply(pkt, ifname)
+
+ # Or with the wrong TTL
+ pkt = sp.IP(dst="224.0.0.1%%%s" % ifname, ttl=2,
+ options=[sp.IPOption_Router_Alert()]) \
+ / sc.igmp.IGMP(type=0x11, mrcode=1)
+ assert not self.find_igmp_reply(pkt, ifname)
diff --git a/tests/sys/netpfil/pf/killstate.sh b/tests/sys/netpfil/pf/killstate.sh
index 447a4e388f11..0d98db822535 100644
--- a/tests/sys/netpfil/pf/killstate.sh
+++ b/tests/sys/netpfil/pf/killstate.sh
@@ -117,10 +117,6 @@ v6_body()
{
pft_init
- if [ "$(atf_config_get ci false)" = "true" ]; then
- atf_skip "https://bugs.freebsd.org/260458"
- fi
-
epair=$(vnet_mkepair)
ifconfig ${epair}a inet6 2001:db8::1/64 up no_dad
diff --git a/tests/sys/netpfil/pf/mbuf.sh b/tests/sys/netpfil/pf/mbuf.sh
index d845f793a969..e3f138bb73b9 100644
--- a/tests/sys/netpfil/pf/mbuf.sh
+++ b/tests/sys/netpfil/pf/mbuf.sh
@@ -105,6 +105,12 @@ inet6_in_mbuf_len_body()
epair=$(vnet_mkepair)
ifconfig ${epair}a inet6 2001:db8::1/64 up no_dad
+ # Ensure we don't unintentionally send MLD packets to alcatraz
+ pfctl -e
+ echo "block
+ pass out inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv, echoreq, echorep }
+ " | pfctl -g -f -
+
# Set up a simple jail with one interface
vnet_mkjail alcatraz ${epair}b
jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 up no_dad
diff --git a/tests/sys/netpfil/pf/mld.py b/tests/sys/netpfil/pf/mld.py
new file mode 100644
index 000000000000..d118a34c8a7d
--- /dev/null
+++ b/tests/sys/netpfil/pf/mld.py
@@ -0,0 +1,95 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 Rubicon Communications, LLC (Netgate)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+import pytest
+from utils import DelayedSend
+from atf_python.sys.net.tools import ToolsHelper
+from atf_python.sys.net.vnet import VnetTestTemplate
+
+class TestMLD(VnetTestTemplate):
+ REQUIRED_MODULES = [ "pf" ]
+ TOPOLOGY = {
+ "vnet1": {"ifaces": ["if1"]},
+ "vnet2": {"ifaces": ["if1"]},
+ "if1": {"prefixes6": [("2001:db8::2/64", "2001:db8::1/64")]},
+ }
+
+ def vnet2_handler(self, vnet):
+ ifname = vnet.iface_alias_map["if1"].name
+ #ToolsHelper.print_output("/sbin/pfctl -e")
+ ToolsHelper.pf_rules([
+ "pass",
+ ])
+ ToolsHelper.print_output("/sbin/pfctl -x loud")
+ #ToolsHelper.print_output("echo \"j 230.0.0.1 %s\ns 3600\nq\" | /usr/sbin/mtest" % ifname)
+
+ def find_mld_reply(self, pkt, ifname):
+ pkt.show()
+ s = DelayedSend(pkt)
+
+ found = False
+ packets = self.sp.sniff(iface=ifname, timeout=5)
+ for r in packets:
+ r.show()
+ mld = r.getlayer(self.sp.ICMPv6MLReport2)
+ if not mld:
+ continue
+ mld.show()
+ found = True
+ return found
+
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_router_alert(self):
+ """Verify that we allow MLD packets with router alert extension header"""
+ ifname = self.vnet.iface_alias_map["if1"].name
+ #ToolsHelper.print_output("/sbin/ifconfig %s inet6 -ifdisable" % ifname)
+ ToolsHelper.print_output("/sbin/ifconfig")
+
+ # Import in the correct vnet, so at to not confuse Scapy
+ import scapy.all as sp
+ import scapy.contrib as sc
+ import scapy.contrib.igmp
+ self.sp = sp
+ self.sc = sc
+
+ # A correct MLD query gets a reply
+ pkt = sp.IPv6(src="fe80::1%%%s" % ifname, dst="ff02::1", hlim=1) \
+ / sp.RouterAlert(value=0) \
+ / sp.ICMPv6MLQuery2()
+ assert self.find_mld_reply(pkt, ifname)
+
+ # The wrong extension header does not
+ pkt = sp.IPv6(src="fe80::1%%%s" % ifname, dst="ff02::1", hlim=1) \
+ / sp.IPv6ExtHdrRouting() \
+ / sp.ICMPv6MLQuery2()
+ assert not self.find_mld_reply(pkt, ifname)
+
+ # Neither does an incorrect hop limit
+ pkt = sp.IPv6(src="fe80::1%%%s" % ifname, dst="ff02::1", hlim=2) \
+ / sp.RouterAlert(value=0) \
+ / sp.ICMPv6MLQuery2()
+ assert not self.find_mld_reply(pkt, ifname)
diff --git a/tests/sys/netpfil/pf/nat64.py b/tests/sys/netpfil/pf/nat64.py
index adae2489ce5e..5cc4713a16cc 100644
--- a/tests/sys/netpfil/pf/nat64.py
+++ b/tests/sys/netpfil/pf/nat64.py
@@ -272,3 +272,18 @@ class TestNAT64(VnetTestTemplate):
reply = self.common_test_source_addr(packet)
icmp = reply.getlayer(sp.ICMPv6EchoRequest)
assert icmp
+
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_bad_len(self):
+ """
+ PR 288224: we can panic if the IPv6 plen is longer than the packet length.
+ """
+ ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1")
+ import scapy.all as sp
+
+ packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=2, plen=512) \
+ / sp.ICMPv6EchoRequest() / sp.Raw("foo")
+ reply = sp.sr1(packet, timeout=3)
+ # We don't expect a reply to a corrupted packet
+ assert not reply
diff --git a/tests/sys/netpfil/pf/set_tos.sh b/tests/sys/netpfil/pf/set_tos.sh
index 75b96edbab6e..842377ee97c6 100644
--- a/tests/sys/netpfil/pf/set_tos.sh
+++ b/tests/sys/netpfil/pf/set_tos.sh
@@ -129,10 +129,6 @@ v6_body()
{
pft_init
- if [ "$(atf_config_get ci false)" = "true" ]; then
- atf_skip "https://bugs.freebsd.org/260459"
- fi
-
epair=$(vnet_mkepair)
ifconfig ${epair}a inet6 add 2001:db8:192::1
vnet_mkjail alcatraz ${epair}b
diff --git a/tests/sys/netpfil/pf/table.sh b/tests/sys/netpfil/pf/table.sh
index 78320375db7c..5e5fccdaca20 100644
--- a/tests/sys/netpfil/pf/table.sh
+++ b/tests/sys/netpfil/pf/table.sh
@@ -582,6 +582,34 @@ anchor_cleanup()
pft_cleanup
}
+atf_test_case "flush" "cleanup"
+flush_head()
+{
+ atf_set descr 'Test flushing addresses from tables'
+ atf_set require.user root
+}
+
+flush_body()
+{
+ pft_init
+
+ vnet_mkjail alcatraz
+
+ atf_check -s exit:0 -e match:"1/1 addresses added." \
+ jexec alcatraz pfctl -t foo -T add 1.2.3.4
+ atf_check -s exit:0 -o match:" 1.2.3.4" \
+ jexec alcatraz pfctl -t foo -T show
+ atf_check -s exit:0 -e match:"1 addresses deleted." \
+ jexec alcatraz pfctl -t foo -T flush
+ atf_check -s exit:0 -o not-match:"1.2.3.4" \
+ jexec alcatraz pfctl -t foo -T show
+}
+
+flush_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "v4_counters"
@@ -596,4 +624,5 @@ atf_init_test_cases()
atf_add_test_case "pr259689"
atf_add_test_case "precreate"
atf_add_test_case "anchor"
+ atf_add_test_case "flush"
}