--- /dev/null
+# $OpenBSD: Makefile,v 1.1 2021/02/05 14:12:17 bluhm Exp $
+
+# Copyright (c) 2021 Alexander Bluhm <bluhm@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# Setup two pair(4) and one lo(4) interface in different routing
+# domains and with different interface MTU.
+
+# pair1 with MTU 8000 <-> pair2 <-> loopback3
+
+# Both pairs are patched. Between pair2 and loopback3 pf switches
+# the routing table. Do extensive ping tests to check that packets
+# get through. Use tcpbench for TCP path MTU discovery. The jumbo
+# frames with MTU 8000 together with switching the routing domain
+# trigger unusual code paths in the kernel.
+
+# This test uses routing domain 11, 12, 13.
+# Adjust it here, if you want to use something else.
+N1 = 11
+N2 = 12
+N3 = 13
+NUMS = ${N1} ${N2} ${N3}
+PAIRS = ${N1} ${N2}
+IP_${N1} = 169.254.1.${N1}
+IP6_${N1} = fc00:0:0:1::${N1}
+IP_${N2} = 169.254.1.${N2}
+IP6_${N2} = fc00:0:0:1::${N2}
+IP_${N3} = 169.254.0.${N3}
+IP6_${N3} = fc00::${N3}
+
+.include <bsd.own.mk>
+
+.if ! (make(clean) || make(cleandir) || make(obj))
+
+SYSCTL_FORWARDING != sysctl net.inet.ip.forwarding
+SYSCTL_FORWARDING6 != sysctl net.inet6.ip6.forwarding
+.if ${SYSCTL_FORWARDING:C/.*=//} != 1 || ${SYSCTL_FORWARDING6:C/.*=//} != 1
+regress:
+ @echo sysctl: "${SYSCTL_FORWARDING}" "${SYSCTL_FORWARDING6}"
+ @echo Set sysctl to 1 to run this regress.
+ @echo SKIPPED
+.endif
+
+PF_STATUS != ${SUDO} pfctl -si | sed -n 's/^Status: \([^ ]*\) .*/\1/p'
+.if empty(PF_STATUS:MEnabled)
+regress:
+ @echo pf status: "${PF_STATUS}"
+ @echo Enable pf to run this regress.
+ @echo SKIPPED
+.endif
+
+PF_SKIP != ${SUDO} pfctl -sI -v | sed -n 's/ (skip)//p'
+.if ! empty(PF_SKIP:Mlo*:Nlo0)
+regress:
+ @echo pf skip: "${PF_SKIP}"
+ @echo Do not set skip on interface lo or lo$N.
+ @echo SKIPPED
+.endif
+
+PF_ANCHOR != ${SUDO} pfctl -sr | sed -n 's/^anchor "\([^"]*\)" all$$/\1/p'
+.if empty(PF_ANCHOR:Mregress)
+regress:
+ @echo pf anchor: "${PF_ANCHOR}"
+ @echo Need anchor '"regress"' in pf.conf to load additional rules.
+ @echo SKIPPED
+.endif
+
+.endif
+
+.PHONY: ifconfig unconfig pfctl
+
+REGRESS_SETUP_ONCE += ifconfig
+ifconfig: unconfig
+ # Create and configure pflog and loopback interfaces.
+.for n in ${NUMS}
+ ${SUDO} ifconfig lo$n rdomain $n
+ ${SUDO} ifconfig lo$n inet 127.0.0.1/8
+ ${SUDO} ifconfig lo$n inet6 ::1/128
+ ${SUDO} route -n -T $n add -inet 169.254.0.0/16 127.0.0.1
+ ${SUDO} route -n -T $n add -inet6 fc00::/48 ::1
+.endfor
+.for n in ${PAIRS}
+ ${SUDO} ifconfig pair$n rdomain $n
+ ${SUDO} ifconfig pair$n inet ${IP_$n}/24
+ ${SUDO} ifconfig pair$n inet6 ${IP6_$n}/64
+.endfor
+ ${SUDO} ifconfig pair${N1} patch pair${N2}
+ ${SUDO} ifconfig lo${N3} inet ${IP_${N3}}/24 alias
+ ${SUDO} ifconfig lo${N3} inet6 ${IP6_${N3}}/64
+ ${SUDO} ifconfig pair${N1} mtu 8000
+ ${SUDO} route -n -T ${N1} add -inet ${IP_${N3}} ${IP_${N2}}
+ ${SUDO} route -n -T ${N1} add -inet6 ${IP6_${N3}} ${IP6_${N2}}
+ # Wait until IPv6 addresses are no longer tentative.
+ for i in `jot 50`; do\
+ if ! { ifconfig pair${N1}; ifconfig pair${N2}; ifconfig lo${N3}; }\
+ | fgrep -q tentative; then\
+ break;\
+ fi;\
+ sleep .1;\
+ done
+ ! { ifconfig pair${N1}; ifconfig pair${N2}; ifconfig lo${N3};}\
+ | fgrep tentative
+
+REGRESS_CLEANUP += unconfig
+unconfig:
+ # Destroy interfaces.
+ -${SUDO} route -n -T ${N1} delete -inet ${IP_${N3}}
+ -${SUDO} route -n -T ${N1} delete -inet6 ${IP6_${N3}}
+ -${SUDO} ifconfig lo${N3} inet ${IP_${N3}} delete
+ -${SUDO} ifconfig lo${N3} inet6 ${IP6_${N3}} delete
+.for n in ${PAIRS}
+ -${SUDO} ifconfig pair$n destroy
+.endfor
+.for n in ${NUMS}
+ -${SUDO} route -n -T $n delete -inet 169.254.0.0/16
+ -${SUDO} route -n -T $n delete -inet6 fc00::/48
+ -${SUDO} ifconfig lo$n inet 127.0.0.1 delete
+ -${SUDO} ifconfig lo$n inet6 ::1 delete
+.endfor
+ rm -f stamp-ifconfig
+
+addr.py: Makefile
+ # Create python include file containing the addresses.
+ rm -f $@ $@.tmp
+.for var in N1 N2 N3
+ echo '${var}="${${var}}"' >>$@.tmp
+ echo 'LO_${var}="lo${${var}}"' >>$@.tmp
+ echo 'PAIR_${var}="pair${${var}}"' >>$@.tmp
+ echo 'IP_${var}="${IP_${${var}}}"' >>$@.tmp
+ echo 'IP6_${var}="${IP6_${${var}}}"' >>$@.tmp
+.endfor
+ mv $@.tmp $@
+
+REGRESS_SETUP_ONCE += pfctl
+pfctl: addr.py pf.conf
+ # Load the pf rules into the kernel.
+ cat addr.py ${.CURDIR}/pf.conf | /sbin/pfctl -n -f -
+ cat addr.py ${.CURDIR}/pf.conf | ${SUDO} pfctl -a regress -f -
+
+.for f in 1 2 3
+.for t in 1 2 3
+REGRESS_TARGETS += run-ping-$f-$t
+run-ping-$f-$t:
+ ping -c 1 -w 1 -n -V ${N$f} -I ${IP_${N$f}} ${IP_${N$t}}
+
+REGRESS_TARGETS += run-ping6-$f-$t
+run-ping6-$f-$t:
+ ping6 -c 1 -w 1 -n -V ${N$f} -I ${IP6_${N$f}} ${IP6_${N$t}}
+
+REGRESS_TARGETS += run-tcpbench-$f-$t
+run-tcpbench-$f-$t:
+ rm -f nc.log
+ nc -v -l -V ${N$t} ${IP_${N$t}} 12345 >/dev/null 2>nc.log &
+ # Wait until nc is listening.
+ for i in `jot 30`; do\
+ if fgrep -q Listening nc.log; then break; fi; sleep .1; done
+ fgrep Listening nc.log
+ # Test that path MTU dicovery is working.
+ tcpbench -t 5 -V ${N$f} -b ${IP_${N$f}} ${IP_${N$t}}
+ route -T ${N$f} -n get ${IP_${N$t}}
+.endfor
+.endfor
+
+CLEANFILES += addr.py *.pyc *.log stamp-*
+
+.include <bsd.regress.mk>