diff --git a/tests/sys/net/Makefile b/tests/sys/net/Makefile index 0a6f2a5ea292..cccabd9fc775 100644 --- a/tests/sys/net/Makefile +++ b/tests/sys/net/Makefile @@ -1,30 +1,33 @@ # $FreeBSD$ PACKAGE= tests TESTSDIR= ${TESTSBASE}/sys/net BINDIR= ${TESTSDIR} ATF_TESTS_C+= if_epair ATF_TESTS_SH+= if_bridge_test ATF_TESTS_SH+= if_clone_test ATF_TESTS_SH+= if_lagg_test ATF_TESTS_SH+= if_tun_test ATF_TESTS_SH+= if_vlan # The tests are written to be run in parallel, but doing so leads to random # panics. I think it's because the kernel's list of interfaces isn't properly # locked. TEST_METADATA+= is_exclusive=true ${PACKAGE}FILES+= \ + dhclient_pcp.conf \ + pcp.py \ stp.py +${PACKAGE}FILESMODE_pcp.py= 0555 ${PACKAGE}FILESMODE_stp.py= 0555 MAN= PROGS+= randsleep WARNS?= 6 .include diff --git a/tests/sys/net/dhclient_pcp.conf b/tests/sys/net/dhclient_pcp.conf new file mode 100644 index 000000000000..fbd86e5bd0f8 --- /dev/null +++ b/tests/sys/net/dhclient_pcp.conf @@ -0,0 +1 @@ +vlan-pcp 6; diff --git a/tests/sys/net/if_vlan.sh b/tests/sys/net/if_vlan.sh index 60b799b25675..2ffc82e017a3 100755 --- a/tests/sys/net/if_vlan.sh +++ b/tests/sys/net/if_vlan.sh @@ -1,42 +1,89 @@ # $FreeBSD$ . $(atf_get_srcdir)/../common/vnet.subr atf_test_case "basic" "cleanup" basic_head() { atf_set descr 'Basic VLAN test' atf_set require.user root } basic_body() { vnet_init epair_vlan=$(vnet_mkepair) vnet_mkjail alcatraz ${epair_vlan}a vnet_mkjail singsing ${epair_vlan}b vlan0=$(jexec alcatraz ifconfig vlan create vlandev ${epair_vlan}a \ vlan 42) jexec alcatraz ifconfig ${epair_vlan}a up jexec alcatraz ifconfig ${vlan0} 10.0.0.1/24 up vlan1=$(jexec singsing ifconfig vlan create vlandev ${epair_vlan}b \ vlan 42) jexec singsing ifconfig ${epair_vlan}b up jexec singsing ifconfig ${vlan1} 10.0.0.2/24 up atf_check -s exit:0 -o ignore jexec singsing ping -c 1 10.0.0.1 } basic_cleanup() { vnet_cleanup } +atf_test_case "bpf_pcp" "cleanup" +bpf_pcp_head() +{ + atf_set descr 'Set VLAN PCP through BPF' + atf_set require.config 'allow_sysctl_side_effects' + atf_set require.user root + atf_set require.progs scapy +} + +bpf_pcp_body() +{ + vnet_init + + epair=$(vnet_mkepair) + + ifconfig ${epair}a up + + vnet_mkjail alcatraz ${epair}b + vlan=$(jexec alcatraz ifconfig vlan create) + jexec alcatraz ifconfig ${vlan} vlan 42 vlandev ${epair}b + jexec alcatraz ifconfig ${vlan} up + jexec alcatraz ifconfig ${epair}b up + + sysctl net.link.vlan.mtag_pcp=1 + + jexec alcatraz dhclient ${vlan} & + atf_check -s exit:1 -o ignore -e ignore $(atf_get_srcdir)/pcp.py \ + --expect-pcp 6 \ + --recvif ${epair}a + + jexec alcatraz killall dhclient + sleep 1 + + jexec alcatraz dhclient -c $(atf_get_srcdir)/dhclient_pcp.conf ${vlan} & + atf_check -s exit:0 -o ignore -e ignore $(atf_get_srcdir)/pcp.py \ + --expect-pcp 6 \ + --recvif ${epair}a +} + +bpf_pcp_cleanup() +{ + sysctl net.link.vlan.mtag_pcp=0 + jexec alcatraz killall dhclient + vnet_cleanup +} + atf_init_test_cases() { atf_add_test_case "basic" + atf_add_test_case "bpf_pcp" } diff --git a/tests/sys/netpfil/common/sniffer.py b/tests/sys/net/pcp.py similarity index 53% copy from tests/sys/netpfil/common/sniffer.py copy to tests/sys/net/pcp.py index 200ac750dd7f..cea88faaf438 100644 --- a/tests/sys/netpfil/common/sniffer.py +++ b/tests/sys/net/pcp.py @@ -1,54 +1,74 @@ -# $FreeBSD$ +#!/usr/bin/env python3 # -# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# SPDX-License-Identifier: BSD-2-Clause # -# Copyright (c) 2017 Kristof Provost +# Copyright (c) 2021 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 threading +import argparse +import logging +logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp +import sys +import os +curdir = os.path.dirname(os.path.realpath(__file__)) +netpfil_common = curdir + "/../netpfil/common" +sys.path.append(netpfil_common) +from sniffer import Sniffer + +def check_pcp(args, packet): + vlan = packet.getlayer(sp.Dot1Q) + + if vlan is None: + return False + + if not packet.getlayer(sp.BOOTP): + return False + + if vlan.prio == int(args.expect_pcp[0]): + return True + + return False + +def main(): + parser = argparse.ArgumentParser("pcp.py", + description="PCP test tool") + parser.add_argument('--recvif', nargs=1, + required=True, + help='The interface where to look for packets to check') + parser.add_argument('--expect-pcp', nargs=1, + help='The expected PCP value on VLAN packets') + + args = parser.parse_args() + + sniffer = Sniffer(args, check_pcp, recvif=args.recvif[0], timeout=20) + + sniffer.join() + + if sniffer.foundCorrectPacket: + sys.exit(0) + + sys.exit(1) -class Sniffer(threading.Thread): - def __init__(self, args, check_function, recvif=None): - threading.Thread.__init__(self) - - self._args = args - if recvif is not None: - self._recvif = recvif - else: - self._recvif = args.recvif[0] - self._check_function = check_function - self.foundCorrectPacket = False - - self.start() - - def _checkPacket(self, packet): - ret = self._check_function(self._args, packet) - if ret: - self.foundCorrectPacket = True - return ret - - def run(self): - self.packets = sp.sniff(iface=self._recvif, - stop_filter=self._checkPacket, timeout=3) +if __name__ == '__main__': + main() diff --git a/tests/sys/netpfil/common/sniffer.py b/tests/sys/netpfil/common/sniffer.py index 200ac750dd7f..a7ebfc122573 100644 --- a/tests/sys/netpfil/common/sniffer.py +++ b/tests/sys/netpfil/common/sniffer.py @@ -1,54 +1,60 @@ # $FreeBSD$ # # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # # Copyright (c) 2017 Kristof Provost # # 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 threading import scapy.all as sp +import sys class Sniffer(threading.Thread): - def __init__(self, args, check_function, recvif=None): + def __init__(self, args, check_function, recvif=None, timeout=3): threading.Thread.__init__(self) self._args = args + self._timeout = timeout if recvif is not None: self._recvif = recvif else: self._recvif = args.recvif[0] self._check_function = check_function self.foundCorrectPacket = False self.start() def _checkPacket(self, packet): ret = self._check_function(self._args, packet) if ret: self.foundCorrectPacket = True return ret def run(self): - self.packets = sp.sniff(iface=self._recvif, - stop_filter=self._checkPacket, timeout=3) + self.packets = [] + try: + self.packets = sp.sniff(iface=self._recvif, + stop_filter=self._checkPacket, timeout=self._timeout) + except Exception as e: + print(e, file=sys.stderr)