Unfortunately I had to start a new email thread since intel's server didn't like the self-signed certificate on my local mail server. I merged all of the patches into one patch so it's a little easier to review for the second time.
Is the patch based on the latest DTS ? sorry, I can't merge it because of code conflict. Could you please rework it. Btw, all patches, v1/v2... should be based on latest DTS.
Thanks, Lijuan.
> -----Original Message-----
> From: dts <dts-bounces@dpdk.org> On Behalf Of Owen Hilyard
> Sent: 2020年7月20日 22:08
> To: dts@dpdk.org
> Cc: Yigit, Ferruh <ferruh.yigit@intel.com>; arybchenko@solarflare.com;
> olivier.matz@6wind.com; david.marchand@redhat.com;
> ivan.malov@oktetlabs.ru; Richardson, Bruce <bruce.richardson@intel.com>;
> lylavoie@iol.unh.edu; rasland@mellanox.com; j.hendergart@f5.com;
> ohilyard@iol.unh.edu; thomas@monjalon.net
> Subject: [dts] [PATCH] checksum checks: Add hardware offload l3 and l4 cases
>
> add rx and tx l3 test cases
> add tx l4 test case
> add documentation for new test cases
>
> Signed-off-by: Owen Hilyard <ohilyard@iol.unh.edu>
> ---
> test_plans/checksum_offload_test_plan.rst | 122 +++++++-
> tests/TestSuite_checksum_offload.py | 331 +++++++++++++++++++---
> 2 files changed, 412 insertions(+), 41 deletions(-)
>
> diff --git a/test_plans/checksum_offload_test_plan.rst
> b/test_plans/checksum_offload_test_plan.rst
> index 4fd8c5a..de2e1a9 100644
> --- a/test_plans/checksum_offload_test_plan.rst
> +++ b/test_plans/checksum_offload_test_plan.rst
> @@ -221,7 +221,7 @@ combination: good/bad ip checksum + good/bad
> udp/tcp checksum.
>
> Check the Rx checksum flags consistent with expected flags.
>
> -Test Case: Hardware Checksum Check L4
> +Test Case: Hardware Checksum Check L4 RX
> ===========================================
> This test involves testing many different scenarios with a L4 checksum.
> A variety of tunneling protocols, L3 protocols and L4 protocols are combined
> @@ -256,4 +256,122 @@ Send a packet with a bad checksum::
> rx: l2_len=18 ethertype=800 l3_len=20 l4_proto=17 l4_len=8
> flags=PKT_RX_L4_CKSUM_BAD PKT_RX_IP_CKSUM_BAD
> PKT_RX_OUTER_L4_CKSUM_UNKNOWN
> tx: flags=PKT_TX_L4_NO_CKSUM PKT_TX_IPV4
>
> -Verify flags are as expected.
> \ No newline at end of file
> +Verify flags are as expected.
> +
> +Test Case: Hardware Checksum Check L3 RX
> +===========================================
> +This test involves testing L3 checksum hardware offload.
> +Due to the relative dominance of IPv4 and IPv6 as L3 protocols, and
> +IPv6's lack of a checksum, only IPv4's checksum is tested.
> +
> +Setup the ``csum`` forwarding mode::
> +
> + testpmd> set fwd csum
> + Set csum packet forwarding mode
> +
> +Start the packet forwarding::
> +
> + testpmd> start
> + csum packet forwarding - CRC stripping disabled - packets/burst=32
> + nb forwarding cores=1 - nb forwarding ports=10
> + RX queues=1 - RX desc=128 - RX free threshold=64
> + RX threshold registers: pthresh=8 hthresh=8 wthresh=4
> + TX queues=1 - TX desc=512 - TX free threshold=0
> + TX threshold registers: pthresh=32 hthresh=8 wthresh=8
> +
> +Send a packet with a good checksum::
> +
> + port=0, mbuf=0x2269df8780, pkt_len=96, nb_segs=1:
> + rx: l2_len=18 ethertype=800 l3_len=20 l4_proto=17 l4_len=8
> flags=PKT_RX_L4_CKSUM_GOOD PKT_RX_IP_CKSUM_GOOD
> PKT_RX_OUTER_L4_CKSUM_UNKNOWN
> + tx: flags=PKT_TX_L4_NO_CKSUM PKT_TX_IPV4
> +
> +Send a packet with a bad checksum::
> +
> + port=0, mbuf=0x2269df7e40, pkt_len=96, nb_segs=1:
> + rx: l2_len=18 ethertype=800 l3_len=20 l4_proto=17 l4_len=8
> flags=PKT_RX_L4_CKSUM_BAD PKT_RX_IP_CKSUM_BAD
> PKT_RX_OUTER_L4_CKSUM_UNKNOWN
> + tx: flags=PKT_TX_L4_NO_CKSUM PKT_TX_IPV4
> +
> +Verify flags are as expected.
> +
> +Test Case: Hardware Checksum Check L4 TX
> +===========================================
> +This test involves testing many different scenarios with a L4 checksum.
> +A variety of tunneling protocols, L3 protocols and L4 protocols are
> +combined to test as many scenarios as possible. Currently, UDP, TCP and
> +SCTP are used as L4 protocols, with IP and IPv6 being used at level 3.
> +The tested tunneling protocols are VXLAN and GRE. This test is used to
> +determine whether the hardware offloading of checksums works properly.
> +
> +Setup the ``csum`` forwarding mode::
> +
> + testpmd> set fwd csum
> + Set csum packet forwarding mode
> +
> +Start the packet forwarding::
> +
> + testpmd> start
> + csum packet forwarding - CRC stripping disabled - packets/burst=32
> + nb forwarding cores=1 - nb forwarding ports=10
> + RX queues=1 - RX desc=128 - RX free threshold=64
> + RX threshold registers: pthresh=8 hthresh=8 wthresh=4
> + TX queues=1 - TX desc=512 - TX free threshold=0
> + TX threshold registers: pthresh=32 hthresh=8 wthresh=8
> +
> +
> +Start a packet capture on the tester in the backround::
> +
> + # tcpdump -i <iface> -s 65535 -w
> + /tmp/tester/test_hardware_checksum_check_l4_tx_capture.pcap &
> +
> +Send a packet with a good checksum::
> +
> + port=0, mbuf=0x2269df8780, pkt_len=96, nb_segs=1:
> + rx: l2_len=18 ethertype=800 l3_len=20 l4_proto=17 l4_len=8
> flags=PKT_RX_L4_CKSUM_GOOD PKT_RX_IP_CKSUM_GOOD
> PKT_RX_OUTER_L4_CKSUM_UNKNOWN
> + tx: flags=PKT_TX_L4_NO_CKSUM PKT_TX_IPV4
> +
> +Send a packet with a bad checksum::
> +
> + port=0, mbuf=0x2269df7e40, pkt_len=96, nb_segs=1:
> + rx: l2_len=18 ethertype=800 l3_len=20 l4_proto=17 l4_len=8
> flags=PKT_RX_L4_CKSUM_BAD PKT_RX_IP_CKSUM_GOOD
> PKT_RX_OUTER_L4_CKSUM_UNKNOWN
> + tx: flags=PKT_TX_L4_NO_CKSUM PKT_TX_IPV4
> +
> +Inspect the pcap file from the packet capture and verify the checksums.
> +
> +Test Case: Hardware Checksum Check L3 TX
> +===========================================
> +This test involves testing L3 checksum hardware offload.
> +Due to the relative dominance of IPv4 and IPv6 as L3 protocols, and
> +IPv6's lack of a checksum, only IPv4's checksum is tested.
> +
> +Setup the ``csum`` forwarding mode::
> +
> + testpmd> set fwd csum
> + Set csum packet forwarding mode
> +
> +Start the packet forwarding::
> +
> + testpmd> start
> + csum packet forwarding - CRC stripping disabled - packets/burst=32
> + nb forwarding cores=1 - nb forwarding ports=10
> + RX queues=1 - RX desc=128 - RX free threshold=64
> + RX threshold registers: pthresh=8 hthresh=8 wthresh=4
> + TX queues=1 - TX desc=512 - TX free threshold=0
> + TX threshold registers: pthresh=32 hthresh=8 wthresh=8
> +
> +
> +Start a packet capture on the tester in the backround::
> +
> + # tcpdump -i <iface> -s 65535 -w
> + /tmp/tester/test_hardware_checksum_check_l3_tx_capture.pcap &
> +
> +Send a packet with a good checksum with a 1 in it's payload::
> +
> + port=0, mbuf=0x2269df8780, pkt_len=96, nb_segs=1:
> + rx: l2_len=18 ethertype=800 l3_len=20 l4_proto=17 l4_len=8
> flags=PKT_RX_L4_CKSUM_GOOD PKT_RX_IP_CKSUM_GOOD
> PKT_RX_OUTER_L4_CKSUM_UNKNOWN
> + tx: flags=PKT_TX_L4_NO_CKSUM PKT_TX_IPV4
> +
> +Send a packet with a bad checksum with a 0 in it's payload::
> +
> + port=0, mbuf=0x2269df7e40, pkt_len=96, nb_segs=1:
> + rx: l2_len=18 ethertype=800 l3_len=20 l4_proto=17 l4_len=8
> flags=PKT_RX_L4_CKSUM_GOOD PKT_RX_IP_CKSUM_BAD
> PKT_RX_OUTER_L4_CKSUM_UNKNOWN
> + tx: flags=PKT_TX_L4_NO_CKSUM PKT_TX_IPV4
> +
> +Inspect the pcap file from the packet capture and verify the checksums.
> diff --git a/tests/TestSuite_checksum_offload.py
> b/tests/TestSuite_checksum_offload.py
> index 9ff5a41..c4a877d 100644
> --- a/tests/TestSuite_checksum_offload.py
> +++ b/tests/TestSuite_checksum_offload.py
> @@ -47,8 +47,18 @@ import time
>
> from rst import RstReport
> import utils
> -
> +from exception import VerifyFailure
> +from pktgen import PacketGeneratorHelper from scapy.layers.inet import
> +UDP, TCP, IP from scapy.layers.inet6 import IPv6 from scapy.layers.l2
> +import Ether, GRE from scapy.layers.sctp import SCTP from
> +scapy.layers.vxlan import VXLAN from scapy.packet import Raw from
> +scapy.utils import wrpcap, rdpcap from test_capabilities import
> +DRIVER_TEST_LACK_CAPA
> from test_case import TestCase
> +
> from framework.pmd_output import PmdOutput from test_capabilities import
> DRIVER_TEST_LACK_CAPA from pktgen import PacketGeneratorHelper @@ -
> 57,6 +67,33 @@ import packet
>
> from settings import FOLDERS
>
> +l3_proto_classes = [
> + IP,
> + IPv6
> +]
> +
> +l4_proto_classes = [
> + UDP,
> + TCP,
> + SCTP
> +]
> +
> +tunnelling_proto_classes = [
> + VXLAN,
> + GRE,
> +]
> +
> +l3_protos = [
> + "IP",
> + "IPv6"
> +]
> +
> +l4_protos = [
> + "UDP",
> + "TCP",
> + "SCTP",
> +]
> +
>
> class TestChecksumOffload(TestCase):
>
> @@ -79,8 +116,6 @@ class TestChecksumOffload(TestCase):
> cur_path = os.path.dirname(
> os.path.dirname(os.path.realpath(__file__)))
> self.output_path = os.sep.join([cur_path, self.logger.log_path])
> - # create an instance to set stream field setting
> - self.pktgen_helper = PacketGeneratorHelper()
>
> def set_up(self):
> """
> @@ -243,7 +278,6 @@ class TestChecksumOffload(TestCase):
> def send_pkt_expect_good_bad_from_flag(self, pkt_str: str, flag: str,
> test_name: str, should_pass: bool = True):
> self.pmdout.get_output(timeout=5) # Remove any old output
> self.scapy_exec(f"sendp({pkt_str}, iface=iface)")
> - time.sleep(1)
> testpmd_output: str = self.pmdout.get_output(timeout=5)
> self.verify(flag in testpmd_output,
> f"Flag {flag[:-1]} not found for test {test_name}, please run
> test_rx_checksum_valid_flags.") @@ -269,11 +303,147 @@ class
> TestChecksumOffload(TestCase):
>
> return None
>
> - def scapy_exec(self, cmd: str):
> - return self.tester.send_expect(cmd, ">>>")
> + def validate_checksum(self, pkt, layer) -> bool:
> + """
> + @param pkt: The packet to validate the checksum of.
> + @return: Whether the checksum was valid.
> + """
> + if pkt is None:
> + return False
> +
> + csum = pkt[layer].chksum
> + del pkt[layer].chksum
> + # Converting it to raw will calculate the checksum
> + return layer(Raw(pkt[layer])).chksum == csum
>
> - def scapy_send_append(self, packet: str):
> - return self.tester.scapy_append(f'sendp({packet}, iface=iface)')
> + def scapy_exec(self, cmd: str, timeout=1) -> str:
> + return self.tester.send_expect(cmd, ">>>", timeout=timeout)
> +
> + def get_packets(self, dut_mac, tester_mac):
> + eth = Ether(dst=dut_mac, src=tester_mac)
> + packets = []
> + checksum_options = ({}, {'chksum': 0xf},)
> + # Untunneled
> + for l3 in l3_proto_classes:
> + for l4 in l4_proto_classes:
> + for chksum in checksum_options:
> + # The packet's data can be used to identify how the packet was
> constructed so avoid any issues with
> + # ordering
> + pkt = eth / l3() / l4(**chksum) / (
> + f'UNTUNNELED,{l3.__name__},{l4.__name__},{" " if
> len(chksum.values()) == 0 else chksum["chksum"]}'
> + )
> +
> + # Prevents the default behavior which adds DNS headers
> + if l4 == UDP:
> + pkt[UDP].dport, pkt[UDP].sport = 1001, 1001
> +
> + packets.append(pkt)
> +
> + # Tunneled
> + # VXLAN
> + for l3 in l3_proto_classes:
> + for l4 in l4_proto_classes:
> + for outer_arg in checksum_options:
> + for inner_arg in checksum_options:
> + pkt = eth / l3() / UDP(**outer_arg) / VXLAN() / Ether() / l3() /
> l4(**inner_arg) / (
> + f'VXLAN,{l3.__name__},{l4.__name__},'
> + f'{" " if len(outer_arg.values()) == 0 else outer_arg["chksum"]},'
> + f'{" " if len(inner_arg.values()) == 0 else inner_arg["chksum"]}'
> + )
> + # Prevents the default behavior which adds DNS headers
> + if l4 == UDP:
> + pkt[VXLAN][UDP].dport,
> + pkt[VXLAN][UDP].sport = 1001, 1001
> +
> + packets.append(pkt)
> + # GRE
> + for l3 in l3_proto_classes:
> + for l4 in l4_proto_classes:
> + for chksum in checksum_options:
> + pkt = eth / l3() / GRE() / l3() / l4(**chksum) / (
> + f'GRE,{l3.__name__},{l4.__name__},{" " if len(chksum.values()) ==
> 0 else chksum["chksum"]}'
> + )
> +
> + # Prevents the default behavior which adds DNS headers
> + if l4 == UDP:
> + pkt[GRE][UDP].dport, pkt[GRE][UDP].sport =
> + 1001, 1001
> +
> + packets.append(pkt)
> +
> + return packets
> +
> + def replay_pcap_file_on_tester(self, iface, packet_file_path):
> + self.tester.send_expect("scapy", ">>>")
> + self.scapy_exec(f"packets = rdpcap('{packet_file_path}')")
> + self.scapy_exec(f"sendp(packets, iface={iface})")
> + self.tester.send_expect("quit()", "# ")
> +
> + def validate_packet_list_checksums(self, packets):
> + name_to_class_dict = {
> + 'UDP': UDP,
> + 'TCP': TCP,
> + 'SCTP': SCTP,
> + 'IP': IP,
> + 'IPv6': IPv6,
> + 'VXLAN': VXLAN,
> + 'GRE': GRE,
> + }
> +
> + error_messages = []
> +
> + untunnelled_error_message = f"Invalid untunneled checksum state
> for %s/%s with a %s checksum."
> +
> + vxlan_error_message = f"Invalid VXLAN tunnelled %s checksum state
> for %s/%s" \
> + f" with a %s inner checksum and a %s outer checksum."
> +
> + gre_error_message = f"Invalid GRE tunnelled checksum state for %s/%s
> with a %s checksum."
> +
> + for packet in packets:
> + payload: str
> + # try:
> + payload = packet[Raw].load.decode('utf-8').split(",")
> + # # This error usually happens with tunneling protocols, and means that
> an additional cast is needed
> + # except UnicodeDecodeError:
> + # for proto in tunnelling_proto_classes:
> +
> + l3 = name_to_class_dict[payload[1]]
> + l4 = name_to_class_dict[payload[2]]
> + if payload[0] == "UNTUNNELED":
> + chksum_should_be_valid = payload[3] == " "
> + if self.validate_checksum(packet, l4) != chksum_should_be_valid:
> + error_messages.append(
> + untunnelled_error_message % (
> + l3.__name__, l4.__name__, 'valid' if chksum_should_be_valid
> == '' else 'invalid'
> + )
> + )
> + elif payload[0] == "VXLAN":
> + outer_chksum_should_be_valid = payload[3] == " "
> + inner_chksum_should_be_valid = payload[4] == " "
> + if self.validate_checksum(packet[VXLAN], l4) !=
> inner_chksum_should_be_valid:
> + error_messages.append(
> + vxlan_error_message % (
> + "inner", l4.__name__, l3.__name__,
> + 'valid' if inner_chksum_should_be_valid == '' else 'invalid',
> + 'valid' if outer_chksum_should_be_valid == '' else 'invalid'
> + )
> + )
> + if self.validate_checksum(packet, l4) !=
> outer_chksum_should_be_valid:
> + error_messages.append(
> + vxlan_error_message % (
> + "outer", l3.__name__, l4.__name__,
> + 'valid' if inner_chksum_should_be_valid == '' else 'invalid',
> + 'valid' if outer_chksum_should_be_valid == '' else 'invalid'
> + )
> + )
> + elif payload[0] == "GRE":
> + chksum_should_be_valid = payload[3] == " "
> + if self.validate_checksum(packet, l4) != chksum_should_be_valid:
> + error_messages.append(
> + gre_error_message % (
> + l3.__name__, l4.__name__, 'valid' if chksum_should_be_valid
> == '' else 'invalid'
> + )
> + )
> +
> + return error_messages
>
> #
> #
> @@ -448,6 +618,9 @@ class TestChecksumOffload(TestCase):
>
> # clear streams before add new streams
> self.tester.pktgen.clear_streams()
> + # create an instance to set stream field setting
> + # Moved here because it messes with the ability of the functional tests
> to use scapy.
> + self.pktgen_helper = PacketGeneratorHelper()
> # run packet generator
> streams = self.pktgen_helper.prepare_stream_from_tginput(tgenInput,
> 100,
> None, self.tester.pktgen) @@ -511,53 +684,93 @@ class
> TestChecksumOffload(TestCase):
> self.dut.send_expect("quit", "#", 10)
> self.result_table_print()
>
> - def test_hardware_checksum_check_ip(self):
> + def test_hardware_checksum_check_ip_rx(self):
> self.dut.send_expect("start", "testpmd>")
> + self.tester.send_expect("scapy", ">>>")
> self.checksum_enablehw(self.dut_ports[0])
> + self.dut.send_expect("start", "testpmd>")
>
> verification_errors: List[VerifyFailure] = []
>
> - # untunnelled
> - vf =
> self.try_helper_hardware_checksum_check_catch_failure('Ether(dst="%s",
> src="%s")/IP(%s)/UDP()/("X"*50)',
> - "PKT_RX_IP_CKSUM_")
> - if vf is not None:
> - verification_errors.append(vf)
> + iface =
> self.tester.get_interface(self.tester.get_local_port(self.dut_ports[0]))
> + dut_mac = self.dut.get_mac_address(self.dut_ports[0])
> + tester_mac =
> + self.tester.get_mac(self.tester.get_local_port(self.dut_ports[0]))
>
> - # tunneled inner
> - vf = self.try_helper_hardware_checksum_check_catch_failure(
> - 'Ether(dst="%s", src="%s")/IP()/UDP()/IP(%s)/("X"*50)',
> - "PKT_RX_OUTER_IP_CKSUM_")
> - if vf is not None:
> - verification_errors.append(vf)
> + self.scapy_exec(f"eth = Ether(dst='{dut_mac}', src='{tester_mac}')")
> + self.scapy_exec(f"iface = '{iface}'")
>
> - # tunneled outer
> - vf = self.try_helper_hardware_checksum_check_catch_failure(
> - 'Ether(dst="%s", src="%s")/IP()/UDP()/IP(%s)/("X"*50)',
> - "PKT_RX_OUTER_IP_CKSUM_")
> - if vf is not None:
> - verification_errors.append(vf)
> + # Untunnelled
> + for l4 in l4_protos:
> + for chksum in "", "chksum=0xf":
> + vf = self.send_pkt_expect_good_bad_from_flag_catch_failure(
> + f"eth/IP({chksum})/{l4}()/(X'*50)",
> + "PKT_RX_IP_CKSUM_", f"{l4}",
> + should_pass=(chksum == ""))
> + if vf is not None:
> + verification_errors.append(vf)
>
> - self.verify(len(verification_errors) == 0, "\n".join(verification_errors))
> + for err in verification_errors:
> + self.logger.error(str(err))
> + self.verify(len(verification_errors) == 0, "See previous
> + output")
>
> + self.tester.send_expect("quit()", "# ")
> self.dut.send_expect("stop", "testpmd>")
>
> - def test_hardware_checksum_check_l4(self):
> + def test_hardware_checksum_check_ip_tx(self):
> self.checksum_enablehw(self.dut_ports[0])
> self.dut.send_expect("start", "testpmd>")
>
> verification_errors: List[VerifyFailure] = []
>
> - l3_protos: List[str] = [
> - "IP",
> - "IPv6"
> - ]
> + iface =
> self.tester.get_interface(self.tester.get_local_port(self.dut_ports[0]))
> + dut_mac = self.dut.get_mac_address(self.dut_ports[0])
> + tester_mac =
> self.tester.get_mac(self.tester.get_local_port(self.dut_ports[0]))
> + eth = Ether(dst=dut_mac, src=tester_mac)
>
> - l4_protos: List[str] = [
> - "UDP",
> - "TCP",
> - "SCTP",
> + checksum_options = ({}, {'chksum': 0xf},)
> +
> + packets = [
> + eth / IP(**chksum) / TCP() / Raw(load=str(int(len(chksum)
> + != 1))) for chksum in checksum_options
> ]
>
> + capture_file_name =
> "test_hardware_checksum_check_l3_tx_capture.pcap"
> +
> + packet_file_path =
> "/tmp/test_hardware_checksum_check_l3_tx_packets.pcap"
> + capture_file_path = "/tmp/tester/" + capture_file_name
> +
> + self.tester.send_expect(f"tcpdump -i {iface} -s 65535 -w
> + {capture_file_path} &", "# ")
> +
> + wrpcap(packet_file_path, packets)
> + self.tester.session.copy_file_to(packet_file_path,
> + packet_file_path)
> +
> + self.replay_pcap_file_on_tester(iface, packet_file_path)
> +
> + self.tester.session.copy_file_from(packet_file_path,
> + "output/tmp/pcap/" + capture_file_name)
> +
> + captured_packets = rdpcap("output/tmp/pcap/" +
> + capture_file_name)
> +
> + self.verify(len(packets) == len(captured_packets), "Not all
> + packets were received")
> +
> + error_messages = []
> + for pkt in captured_packets:
> + should_pass = pkt[TCP].payload.build() == b'1'
> + if not (self.validate_checksum(pkt, IP) == should_pass):
> + error_messages.append(f"A packet was marked as having a"
> + f"{' valid' if should_pass == '' else 'n invalid'}"
> + f" checksum when it should have
> + had the opposite.")
> +
> + self.dut.send_expect("stop", "testpmd>")
> + if len(error_messages) != 0:
> + for error_msg in error_messages:
> + self.logger.error(error_msg)
> + self.verify(False, "See prior output")
> +
> + def test_hardware_checksum_check_l4_rx(self):
> + self.checksum_enablehw(self.dut_ports[0])
> + self.dut.send_expect("start", "testpmd>")
> +
> + verification_errors: List[VerifyFailure] = []
> +
> iface =
> self.tester.get_interface(self.tester.get_local_port(self.dut_ports[0]))
> dut_mac = self.dut.get_mac_address(self.dut_ports[0])
> tester_mac =
> self.tester.get_mac(self.tester.get_local_port(self.dut_ports[0]))
> @@ -589,7 +802,7 @@ class TestChecksumOffload(TestCase):
> should_pass = outer_arg == ""
> vf = self.send_pkt_expect_good_bad_from_flag_catch_failure(
> f"eth/{l3}()/{l4}({outer_arg})/VXLAN()/{l3}()/"
> - f"{l4}({inner_arg})/('X'*50)",
> + f"{l4}(chksum={inner_arg})/('X'*50)",
> flag, f"{l3}/{l4}/VXLAN/{l3}/{l4}",
> should_pass=should_pass)
>
> @@ -602,8 +815,7 @@ class TestChecksumOffload(TestCase):
> for inner_arg in "", "chksum=0xf":
> should_pass: bool = inner_arg == ""
> vf = self.send_pkt_expect_good_bad_from_flag_catch_failure(
> - f"eth/{l3}()/GRE()/{l3}()/"
> - f"{l4}({inner_arg})/('X'*50)",
> +
> + f"eth/{l3}()/GRE()/{l3}()/{l4}({inner_arg})/('X'*50)",
> "PKT_RX_L4_CKSUM_", f"{l3}/GRE/{l3}/{l4}",
> should_pass=should_pass)
>
> @@ -615,6 +827,8 @@ class TestChecksumOffload(TestCase):
> # updated this test case can easily take advantage of the new functionality.
>
> # # GENEVE
> + # # This import is over here so that it is not forgotten when the update
> happens
> + # from scapy.contrib.geneve import GENEVE
> # for l3_outer in l3_protos:
> # for l4_outer in l4_protos:
> # for l3_inner in l3_protos:
> @@ -638,7 +852,46 @@ class TestChecksumOffload(TestCase):
> self.logger.error(str(err))
> self.verify(len(verification_errors) == 0, "See previous output")
>
> + self.tester.send_expect("quit", "#")
> + self.dut.send_expect("stop", "testpmd>")
> +
> + def test_hardware_checksum_check_l4_tx(self):
> + self.checksum_enablehw(self.dut_ports[0])
> + self.dut.send_expect("start", "testpmd>")
> +
> + verification_errors: List[VerifyFailure] = []
> +
> + iface =
> self.tester.get_interface(self.tester.get_local_port(self.dut_ports[0]))
> + dut_mac = self.dut.get_mac_address(self.dut_ports[0])
> + tester_mac =
> + self.tester.get_mac(self.tester.get_local_port(self.dut_ports[0]))
> +
> + packets = self.get_packets(dut_mac, tester_mac)
> +
> + capture_file_name =
> "test_hardware_checksum_check_l4_tx_capture.pcap"
> +
> + packet_file_path =
> "/tmp/test_hardware_checksum_check_l4_tx_packets.pcap"
> + capture_file_path = "/tmp/tester/" + capture_file_name
> +
> + self.tester.send_expect(f"tcpdump -i {iface} -s 65535 -w
> + {capture_file_path} &", "# ")
> +
> + wrpcap(packet_file_path, packets)
> + self.tester.session.copy_file_to(packet_file_path,
> + packet_file_path)
> +
> + self.replay_pcap_file_on_tester(iface, packet_file_path)
> +
> + self.tester.session.copy_file_from(packet_file_path,
> + "output/tmp/pcap/" + capture_file_name)
> +
> + captured_packets = rdpcap("output/tmp/pcap/" +
> + capture_file_name)
> +
> + self.verify(len(packets) == len(captured_packets), "Not all
> + packets were received")
> +
> + error_messages =
> + self.validate_packet_list_checksums(captured_packets)
> +
> self.dut.send_expect("stop", "testpmd>")
> + if len(error_messages) != 0:
> + for error_msg in error_messages:
> + self.logger.error(error_msg)
> + self.verify(False, "See prior output")
>
> def tear_down(self):
> """
> --
> 2.25.1