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