xref: /dpdk/dts/tests/TestSuite_vlan.py (revision e41fe1f8df707c7de026eae6b529126469bb955f)
1# SPDX-License-Identifier: BSD-3-Clause
2# Copyright(c) 2024 University of New Hampshire
3
4"""Test the support of VLAN Offload Features by Poll Mode Drivers.
5
6This test suite verifies that VLAN filtering, stripping, and header insertion all
7function as expected. When a VLAN ID is in the filter list, all packets with that
8ID should be forwarded and all others should be dropped. While stripping is enabled,
9packets sent with a VLAN ID should have the ID removed and then be forwarded.
10Additionally, when header insertion is enabled packets without a
11VLAN ID should have a specified ID inserted and then be forwarded.
12
13"""
14
15from scapy.layers.l2 import Dot1Q, Ether  # type: ignore[import-untyped]
16from scapy.packet import Raw  # type: ignore[import-untyped]
17
18from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell
19from framework.test_suite import TestSuite, func_test
20from framework.testbed_model.capability import NicCapability, TopologyType, requires
21
22
23@requires(NicCapability.RX_OFFLOAD_VLAN_FILTER)
24@requires(topology_type=TopologyType.two_links)
25class TestVlan(TestSuite):
26    """DPDK VLAN test suite.
27
28    Ensures VLAN packet reception, stripping, and insertion on the Poll Mode Driver
29    when the appropriate conditions are met. The suite contains four test cases:
30
31    1. VLAN reception no stripping - verifies that a VLAN packet with a tag
32    within the filter list is received.
33    2. VLAN reception stripping - verifies that a VLAN packet with a tag
34    within the filter list is received without the VLAN tag.
35    3. VLAN no reception - verifies that a VLAN packet with a tag not within
36    the filter list is dropped.
37    4. VLAN insertion - verifies that a non VLAN packet is received with a VLAN
38    tag when insertion is enabled.
39    """
40
41    def send_vlan_packet_and_verify(self, should_receive: bool, strip: bool, vlan_id: int) -> None:
42        """Generate a VLAN packet, send and verify packet with same payload is received on the dut.
43
44        Args:
45            should_receive: Indicate whether the packet should be successfully received.
46            strip: If :data:`False`, will verify received packets match the given VLAN ID,
47                otherwise verifies that the received packet has no VLAN ID
48                (as it has been stripped off.)
49            vlan_id: Expected VLAN ID.
50        """
51        packet = Ether() / Dot1Q(vlan=vlan_id) / Raw(load="xxxxx")
52        received_packets = self.send_packet_and_capture(packet)
53        test_packet = None
54        for packet in received_packets:
55            if hasattr(packet, "load") and b"xxxxx" in packet.load:
56                test_packet = packet
57                break
58        if should_receive:
59            self.verify(
60                test_packet is not None, "Packet was dropped when it should have been received"
61            )
62            if test_packet is not None:
63                if strip:
64                    self.verify(
65                        not test_packet.haslayer(Dot1Q), "VLAN tag was not stripped successfully"
66                    )
67                else:
68                    self.verify(
69                        test_packet.vlan == vlan_id,
70                        "The received tag did not match the expected tag",
71                    )
72        else:
73            self.verify(
74                test_packet is None,
75                "Packet was received when it should have been dropped",
76            )
77
78    def send_packet_and_verify_insertion(self, expected_id: int) -> None:
79        """Generate a packet with no VLAN tag, send and verify on the dut.
80
81        Args:
82            expected_id: The VLAN id that is being inserted through tx_offload configuration.
83        """
84        packet = Ether() / Raw(load="xxxxx")
85        received_packets = self.send_packet_and_capture(packet)
86        test_packet = None
87        for packet in received_packets:
88            if hasattr(packet, "load") and b"xxxxx" in packet.load:
89                test_packet = packet
90                break
91        self.verify(test_packet is not None, "Packet was dropped when it should have been received")
92        if test_packet is not None:
93            self.verify(test_packet.haslayer(Dot1Q), "The received packet did not have a VLAN tag")
94            self.verify(
95                test_packet.vlan == expected_id, "The received tag did not match the expected tag"
96            )
97
98    def vlan_setup(self, testpmd: TestPmdShell, port_id: int, filtered_id: int) -> None:
99        """Setup method for all test cases.
100
101        Args:
102            testpmd: Testpmd shell session to send commands to.
103            port_id: Number of port to use for setup.
104            filtered_id: ID to be added to the VLAN filter list.
105
106        Returns:
107            TestPmdShell: Testpmd session being configured.
108        """
109        testpmd.set_forward_mode(SimpleForwardingModes.mac)
110        testpmd.set_promisc(port_id, False)
111        testpmd.set_vlan_filter(port=port_id, enable=True)
112        testpmd.rx_vlan(vlan=filtered_id, port=port_id, add=True)
113
114    @func_test
115    def test_vlan_receipt_no_stripping(self) -> None:
116        """Verify packets are received with their VLAN IDs when stripping is disabled.
117
118        Test:
119            Create an interactive testpmd shell and verify a VLAN packet.
120        """
121        with TestPmdShell(node=self.sut_node) as testpmd:
122            self.vlan_setup(testpmd=testpmd, port_id=0, filtered_id=1)
123            testpmd.start()
124            self.send_vlan_packet_and_verify(True, strip=False, vlan_id=1)
125
126    @requires(NicCapability.RX_OFFLOAD_VLAN_STRIP)
127    @func_test
128    def test_vlan_receipt_stripping(self) -> None:
129        """Ensure VLAN packet received with no tag when receipts and header stripping are enabled.
130
131        Test:
132            Create an interactive testpmd shell and verify a VLAN packet.
133        """
134        with TestPmdShell(node=self.sut_node) as testpmd:
135            self.vlan_setup(testpmd=testpmd, port_id=0, filtered_id=1)
136            testpmd.set_vlan_strip(port=0, enable=True)
137            testpmd.start()
138            self.send_vlan_packet_and_verify(should_receive=True, strip=True, vlan_id=1)
139
140    @func_test
141    def test_vlan_no_receipt(self) -> None:
142        """Ensure VLAN packet dropped when filter is on and sent tag not in the filter list.
143
144        Test:
145            Create an interactive testpmd shell and verify a VLAN packet.
146        """
147        with TestPmdShell(node=self.sut_node) as testpmd:
148            self.vlan_setup(testpmd=testpmd, port_id=0, filtered_id=1)
149            testpmd.start()
150            self.send_vlan_packet_and_verify(should_receive=False, strip=False, vlan_id=2)
151
152    @func_test
153    def test_vlan_header_insertion(self) -> None:
154        """Ensure that VLAN packet is received with the correct inserted VLAN tag.
155
156        Test:
157            Create an interactive testpmd shell and verify a non-VLAN packet.
158        """
159        with TestPmdShell(node=self.sut_node) as testpmd:
160            testpmd.set_forward_mode(SimpleForwardingModes.mac)
161            testpmd.set_promisc(port=0, enable=False)
162            testpmd.stop_all_ports()
163            testpmd.tx_vlan_set(port=1, enable=True, vlan=51)
164            testpmd.start_all_ports()
165            testpmd.start()
166            self.send_packet_and_verify_insertion(expected_id=51)
167