diff --git a/tests/TestSuite_tso.py b/tests/TestSuite_tso.py
index a8292d8c..6b19aa5f 100755
--- a/tests/TestSuite_tso.py
+++ b/tests/TestSuite_tso.py
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
+# Copyright(c) 2010-2023 Intel Corporation
 #
 
 """
@@ -13,18 +13,335 @@ import re
 import time
 
 import framework.utils as utils
-from framework.packet import Packet
+import tests.offload_common as offload
+from framework.packet import Packet, Raw, randstring
 from framework.pktgen import PacketGeneratorHelper
+from framework.pmd_output import PmdOutput
 from framework.settings import HEADER_SIZE
-from framework.test_case import TestCase
+from framework.test_case import (
+    TestCase,
+    check_supported_nic,
+    skip_unsupported,
+    skip_unsupported_host_driver,
+    skip_unsupported_nic,
+    skip_unsupported_pkg,
+)
 
 DEFAULT_MUT = 1500
+
+TX_INTERVAL = 0.01
+
+TSO_TX_REPEAT = 10
 TSO_MTU = 9000
+TSO_SEGMENT_LENGTH = 800
+TSO_PAYLOAD_SIZE_LIST = [128, 800, 801, 1700, 2500, 8500]
+
+TSO_NON_TUNNEL_PACKETS = [
+    func(offload.TSO_INNER_PACKET_PART[_type] / Raw(randstring(_payload_size)))
+    for _type in [
+        "IP/TCP",
+        "IPv6/TCP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+TSO_TUNNEL_PACKETS = [
+    func(
+        offload.OUTER_PACKET_PART[_o_type]
+        / offload.TSO_INNER_PACKET_PART[_i_type]
+        / Raw(randstring(_payload_size))
+        if _o_type
+        else offload.TSO_INNER_PACKET_PART[_i_type]
+    )
+    for _o_type in [
+        "IP/VXLAN",
+        "IPv6/VXLAN",
+        "IP/NVGRE",
+        "IPv6/NVGRE",
+    ]
+    for _i_type in [
+        "IP/TCP",
+        "IPv6/TCP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+TSO_TUNNEL_COMMONPKG_PACKETS = [
+    func(
+        offload.OUTER_PACKET_PART[_o_type]
+        / offload.TSO_INNER_PACKET_PART[_i_type]
+        / Raw(randstring(_payload_size))
+        if _o_type
+        else offload.TSO_INNER_PACKET_PART[_i_type]
+    )
+    for _o_type in [
+        "IP/VXLAN",
+        "IPv6/VXLAN",
+        "IP/VXLAN-GPE",
+        "IPv6/VXLAN-GPE",
+        "IP/VXLAN-GPE/Ether",
+        "IPv6/VXLAN-GPE/Ether",
+        "IP/GRE",
+        "IPv6/GRE",
+        "IP/GRE/Ether",
+        "IPv6/GRE/Ether",
+        "IP/NVGRE",
+        "IPv6/NVGRE",
+        "IP/GTPU",
+        "IPv6/GTPU",
+    ]
+    for _i_type in [
+        "IP/TCP",
+        "IPv6/TCP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+UFO_NON_TUNNEL_PACKETS = [
+    func(offload.TSO_INNER_PACKET_PART[_type] / Raw(randstring(_payload_size)))
+    for _type in [
+        "IP/UDP",
+        "IPv6/UDP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+UFO_TUNNEL_PACKETS = [
+    func(
+        offload.OUTER_PACKET_PART[_o_type]
+        / offload.TSO_INNER_PACKET_PART[_i_type]
+        / Raw(randstring(_payload_size))
+        if _o_type
+        else offload.TSO_INNER_PACKET_PART[_i_type]
+    )
+    for _o_type in [
+        "IP/VXLAN",
+        "IPv6/VXLAN",
+        "IP/NVGRE",
+        "IPv6/NVGRE",
+    ]
+    for _i_type in [
+        "IP/UDP",
+        "IPv6/UDP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+UFO_TUNNEL_COMMONPKG_PACKETS = [
+    func(
+        offload.OUTER_PACKET_PART[_o_type]
+        / offload.TSO_INNER_PACKET_PART[_i_type]
+        / Raw(randstring(_payload_size))
+        if _o_type
+        else offload.TSO_INNER_PACKET_PART[_i_type]
+    )
+    for _o_type in [
+        "IP/VXLAN",
+        "IPv6/VXLAN",
+        "IP/VXLAN-GPE",
+        "IPv6/VXLAN-GPE",
+        "IP/VXLAN-GPE/Ether",
+        "IPv6/VXLAN-GPE/Ether",
+        "IP/GRE",
+        "IPv6/GRE",
+        "IP/GRE/Ether",
+        "IPv6/GRE/Ether",
+        "IP/NVGRE",
+        "IPv6/NVGRE",
+        "IP/GTPU",
+        "IPv6/GTPU",
+    ]
+    for _i_type in [
+        "IP/UDP",
+        "IPv6/UDP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+TSO_VLAN_NON_TUNNEL_PACKETS = [
+    func(offload.TSO_INNER_PACKET_PART[_type] / Raw(randstring(_payload_size)))
+    for _type in [
+        "VLAN/IP/TCP",
+        "VLAN/IPv6/TCP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+TSO_VLAN_TUNNEL_PACKETS = [
+    func(
+        offload.OUTER_PACKET_PART[_o_type]
+        / offload.TSO_INNER_PACKET_PART[_i_type]
+        / Raw(randstring(_payload_size))
+        if _o_type
+        else offload.TSO_INNER_PACKET_PART[_i_type]
+    )
+    for _o_type in [
+        "VLAN/IP/VXLAN",
+        "VLAN/IPv6/VXLAN",
+        "VLAN/IP/NVGRE",
+        "VLAN/IPv6/NVGRE",
+    ]
+    for _i_type in [
+        "IP/TCP",
+        "IPv6/TCP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+TSO_VLAN_TUNNEL_COMMONPKG_PACKETS = [
+    func(
+        offload.OUTER_PACKET_PART[_o_type]
+        / offload.TSO_INNER_PACKET_PART[_i_type]
+        / Raw(randstring(_payload_size))
+        if _o_type
+        else offload.TSO_INNER_PACKET_PART[_i_type]
+    )
+    for _o_type in [
+        "VLAN/IP/VXLAN",
+        "VLAN/IPv6/VXLAN",
+        "VLAN/IP/VXLAN-GPE",
+        "VLAN/IPv6/VXLAN-GPE",
+        "VLAN/IP/VXLAN-GPE/Ether",
+        "VLAN/IPv6/VXLAN-GPE/Ether",
+        "VLAN/IP/GRE",
+        "VLAN/IPv6/GRE",
+        "VLAN/IP/GRE/Ether",
+        "VLAN/IPv6/GRE/Ether",
+        "VLAN/IP/NVGRE",
+        "VLAN/IPv6/NVGRE",
+        "VLAN/IP/GTPU",
+        "VLAN/IPv6/GTPU",
+    ]
+    for _i_type in [
+        "IP/TCP",
+        "IPv6/TCP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+UFO_VLAN_NON_TUNNEL_PACKETS = [
+    func(offload.TSO_INNER_PACKET_PART[_type] / Raw(randstring(_payload_size)))
+    for _type in [
+        "VLAN/IP/UDP",
+        "VLAN/IPv6/UDP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+UFO_VLAN_TUNNEL_PACKETS = [
+    func(
+        offload.OUTER_PACKET_PART[_o_type]
+        / offload.TSO_INNER_PACKET_PART[_i_type]
+        / Raw(randstring(_payload_size))
+        if _o_type
+        else offload.TSO_INNER_PACKET_PART[_i_type]
+    )
+    for _o_type in [
+        "VLAN/IP/VXLAN",
+        "VLAN/IPv6/VXLAN",
+        "VLAN/IP/NVGRE",
+        "VLAN/IPv6/NVGRE",
+    ]
+    for _i_type in [
+        "IP/UDP",
+        "IPv6/UDP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
+
+UFO_VLAN_TUNNEL_COMMONPKG_PACKETS = [
+    func(
+        offload.OUTER_PACKET_PART[_o_type]
+        / offload.TSO_INNER_PACKET_PART[_i_type]
+        / Raw(randstring(_payload_size))
+        if _o_type
+        else offload.TSO_INNER_PACKET_PART[_i_type]
+    )
+    for _o_type in [
+        "VLAN/IP/VXLAN",
+        "VLAN/IPv6/VXLAN",
+        "VLAN/IP/VXLAN-GPE",
+        "VLAN/IPv6/VXLAN-GPE",
+        "VLAN/IP/VXLAN-GPE/Ether",
+        "VLAN/IPv6/VXLAN-GPE/Ether",
+        "VLAN/IP/GRE",
+        "VLAN/IPv6/GRE",
+        "VLAN/IP/GRE/Ether",
+        "VLAN/IPv6/GRE/Ether",
+        "VLAN/IP/NVGRE",
+        "VLAN/IPv6/NVGRE",
+        "VLAN/IP/GTPU",
+        "VLAN/IPv6/GTPU",
+    ]
+    for _i_type in [
+        "IP/UDP",
+        "IPv6/UDP",
+    ]
+    for func in [
+        offload.get_packet_with_bad_no_checksum,
+        offload.get_packet_with_bad_all_checksum,
+    ]
+    for _payload_size in TSO_PAYLOAD_SIZE_LIST
+    for _ in range(TSO_TX_REPEAT)
+]
 
 
 class TestTSO(TestCase):
-    dut_ports = []
-
     def set_up_all(self):
         """
         Run at the start of each test suite.
@@ -34,6 +351,60 @@ class TestTSO(TestCase):
 
         # Verify that enough ports are available
         self.verify(len(self.dut_ports) >= 2, "Insufficient ports for testing")
+        self.dut_pci = [
+            self.dut.ports_info[self.dut_ports[0]]["pci"],
+            self.dut.ports_info[self.dut_ports[1]]["pci"],
+        ]
+        self.tester_ports = [
+            self.tester.get_local_port(self.dut_ports[0]),
+            self.tester.get_local_port(self.dut_ports[1]),
+        ]
+        self.tester_intf = [
+            self.tester.get_interface(self.tester_ports[0]),
+            self.tester.get_interface(self.tester_ports[1]),
+        ]
+
+        # supported packets
+        self.packets_tso_non_tunnel = []
+        self.packets_tso_tunnel = []
+        self.support_rx_tunnel = False
+        if self.kdriver in {"ice"}:
+            self.packets_tso_non_tunnel.extend(TSO_NON_TUNNEL_PACKETS)
+            self.packets_tso_non_tunnel.extend(UFO_NON_TUNNEL_PACKETS)
+            self.packets_tso_non_tunnel.extend(TSO_VLAN_NON_TUNNEL_PACKETS)
+            self.packets_tso_non_tunnel.extend(UFO_VLAN_NON_TUNNEL_PACKETS)
+        elif self.kdriver in {"i40e"}:
+            self.packets_tso_non_tunnel.extend(TSO_NON_TUNNEL_PACKETS)
+            self.packets_tso_non_tunnel.extend(TSO_VLAN_NON_TUNNEL_PACKETS)
+        else:
+            self.packets_tso_non_tunnel.extend(TSO_NON_TUNNEL_PACKETS)
+        if (
+            self.kdriver in {"ice"}
+            and self.pkg
+            and self.pkg.get("type")
+            and "comm" in self.pkg.get("type")
+        ):
+            self.packets_tso_tunnel.extend(TSO_TUNNEL_COMMONPKG_PACKETS)
+            self.packets_tso_tunnel.extend(UFO_TUNNEL_COMMONPKG_PACKETS)
+            self.packets_tso_tunnel.extend(TSO_VLAN_TUNNEL_COMMONPKG_PACKETS)
+            self.packets_tso_tunnel.extend(UFO_VLAN_TUNNEL_COMMONPKG_PACKETS)
+            self.support_rx_tunnel = True
+        elif self.kdriver in {"ice"}:
+            self.packets_tso_tunnel.extend(TSO_TUNNEL_PACKETS)
+            self.packets_tso_tunnel.extend(UFO_TUNNEL_PACKETS)
+            self.packets_tso_tunnel.extend(TSO_VLAN_TUNNEL_PACKETS)
+            self.packets_tso_tunnel.extend(UFO_VLAN_TUNNEL_PACKETS)
+            self.support_rx_tunnel = True
+        elif self.kdriver in {"i40e"}:
+            self.packets_tso_tunnel.extend(TSO_TUNNEL_PACKETS)
+            self.packets_tso_tunnel.extend(TSO_VLAN_TUNNEL_PACKETS)
+            self.support_rx_tunnel = True
+        else:
+            self.packets_tso_tunnel.extend(TSO_TUNNEL_PACKETS)
+            self.support_rx_tunnel = True
+
+        self.bind_nic_driver(self.dut_ports, "vfio-pci")
+        self.pmdout: PmdOutput = PmdOutput(self.dut)
 
         # Verify that enough threads are available
         self.portMask = utils.create_mask([self.dut_ports[0], self.dut_ports[1]])
@@ -77,232 +448,144 @@ class TestTSO(TestCase):
         """
         pass
 
-    def tcpdump_start_sniffing(self, ifaces=[]):
-        """
-        Starts tcpdump in the background to sniff the tester interface where
-        the packets are transmitted to and from the self.dut.
-        All the captured packets are going to be stored in a file for a
-        post-analysis.
-        """
-
-        for iface in ifaces:
-            command = (
-                "tcpdump -w /tmp/tcpdump_{0}.pcap -i {0} 2>tcpdump_{0}.out &"
-            ).format(iface)
-            del_cmd = ("rm -f /tmp/tcpdump_{0}.pcap").format(iface)
-            self.tester.send_expect(del_cmd, "#")
-            self.tester.send_expect(command, "#")
-
-    def tcpdump_stop_sniff(self):
-        """
-        Stops the tcpdump process running in the background.
-        """
-        self.tester.send_expect("killall tcpdump", "#")
-        time.sleep(1)
-        self.tester.send_expect('echo "Cleaning buffer"', "#")
-        time.sleep(1)
-
-    def tcpdump_command(self, command):
-        """
-        Sends a tcpdump related command and returns an integer from the output
-        """
-
-        result = self.tester.send_expect(command, "#")
-        return int(result.strip())
-
-    def number_of_packets(self, iface):
-        """
-        By reading the file generated by tcpdump it counts how many packets were
-        forwarded by the sample app and received in the self.tester. The sample app
-        will add a known MAC address for the test to look for.
-        """
-
-        command = (
-            "tcpdump -A -nn -e -v -r /tmp/tcpdump_{iface}.pcap 2>/dev/null | "
-            + 'grep -c "seq"'
+    def test_tso_non_tunnel(self):
+        offload.execute_test_tso(
+            case=self,
+            testpmd=self.pmdout,
+            tester=self.tester,
+            tester_tx_interface=self.tester_intf[0],
+            tester_rx_interface=self.tester_intf[1],
+            testpmd_port_0=self.dut_pci[0],
+            testpmd_port_1=self.dut_pci[1],
+            testpmd_enable_dcf_0=False,
+            testpmd_enable_dcf_1=False,
+            testpmd_bitwidth=None,
+            testpmd_log_level={"ice": 7, "iavf": 8},
+            testpmd_other_eal_param="",
+            testpmd_param=" --enable-rx-cksum --max-pkt-len=%d " % TSO_MTU,
+            testpmd_commands=[
+                "set verbose 1",
+                "set fwd csum",
+                "csum mac-swap off 0",
+                "csum mac-swap off 1",
+                "set promisc 0 on",
+                "set promisc 1 on",
+                "port stop all",
+                "csum set ip hw 1",
+                "csum set udp hw 1",
+                "csum set tcp hw 1",
+                "csum set sctp hw 1",
+                "csum set outer-ip hw 1",
+                "csum set outer-udp hw 1",
+                "csum parse-tunnel on 1",
+                "rx_vxlan_port add 4789 0",
+                "tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "port start all",
+            ],
+            packets=self.packets_tso_non_tunnel + self.packets_tso_tunnel,
+            packet_interval=TX_INTERVAL,
+            packet_mtu=TSO_MTU,
+            segment_length=TSO_SEGMENT_LENGTH,
+            support_rx_tunnel=self.support_rx_tunnel,
+            support_seg_non_tunnel=True,
+            support_seg_tunnel=False,
+            support_tso=True,
+            support_ufo=True,
         )
-        return self.tcpdump_command(command.format(**locals()))
-
-    def tcpdump_scanner(self, scanner):
-        """
-        Execute scanner to return results
-        """
-        scanner_result = self.tester.send_expect(scanner, "#", 60)
-        fially_result = re.findall(r"length( \d+)", scanner_result)
-        return list(fially_result)
 
-    def number_of_bytes(self, iface):
-        """
-        Get the length of loading_sizes
-        """
-        scanner = 'tcpdump  -vv -r /tmp/tcpdump_{iface}.pcap 2>/dev/null | grep "seq"  | grep "length"'
-        return self.tcpdump_scanner(scanner.format(**locals()))
-
-    def get_chksum_value_and_verify(self, dump_pcap, Nic_list):
-        packet = Packet()
-        pkts = packet.read_pcapfile(dump_pcap, self.tester)
-        for pkt in pkts:
-            chksum_list_rx = re.findall(r"chksum\s*=\s*(0x\w+)", pkt.show(dump=True))
-            pkt["IP"].chksum = None
-            if "VXLAN" in pkt:
-                pkt["UDP"].chksum = None
-                pkt["VXLAN"]["IP"].chksum = None
-                pkt["VXLAN"]["TCP"].chksum = None
-            elif "GRE" in pkt:
-                pkt["GRE"]["IP"].chksum = None
-                pkt["GRE"]["TCP"].chksum = None
-            chksum_list_good = re.findall(r"chksum\s*=\s*(0x\w+)", pkt.show2(dump=True))
-            if self.nic in Nic_list and "VXLAN" in pkt:
-                self.verify(
-                    chksum_list_rx[0] == chksum_list_good[0]
-                    and chksum_list_rx[2] == chksum_list_good[2]
-                    and chksum_list_rx[3] == chksum_list_good[3],
-                    "The obtained chksum value is incorrect.",
-                )
-            else:
-                self.verify(
-                    chksum_list_rx == chksum_list_good,
-                    "The obtained chksum value is incorrect.",
-                )
-
-    def test_tso(self):
-        """
-        TSO IPv4 TCP, IPv6 TCP
-        """
-        tx_interface = self.tester.get_interface(
-            self.tester.get_local_port(self.dut_ports[0])
-        )
-        rx_interface = self.tester.get_interface(
-            self.tester.get_local_port(self.dut_ports[1])
-        )
-
-        mac = self.dut.get_mac_address(self.dut_ports[0])
-
-        self.tester.send_expect(
-            "ethtool -K %s rx off tx off tso off gso off gro off lro off"
-            % tx_interface,
-            "# ",
+    def test_tso_tunnel(self):
+        offload.execute_test_tso(
+            case=self,
+            testpmd=self.pmdout,
+            tester=self.tester,
+            tester_tx_interface=self.tester_intf[0],
+            tester_rx_interface=self.tester_intf[1],
+            testpmd_port_0=self.dut_pci[0],
+            testpmd_port_1=self.dut_pci[1],
+            testpmd_enable_dcf_0=False,
+            testpmd_enable_dcf_1=False,
+            testpmd_bitwidth=None,
+            testpmd_log_level={"ice": 7, "iavf": 8},
+            testpmd_other_eal_param="",
+            testpmd_param=" --enable-rx-cksum --max-pkt-len=%d " % TSO_MTU,
+            testpmd_commands=[
+                "set verbose 1",
+                "set fwd csum",
+                "csum mac-swap off 0",
+                "csum mac-swap off 1",
+                "set promisc 0 on",
+                "set promisc 1 on",
+                "port stop all",
+                "csum set ip hw 1",
+                "csum set udp hw 1",
+                "csum set tcp hw 1",
+                "csum set sctp hw 1",
+                "csum set outer-ip hw 1",
+                "csum set outer-udp hw 1",
+                "csum parse-tunnel on 1",
+                "rx_vxlan_port add 4789 0",
+                "tunnel_tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "port start all",
+            ],
+            packets=self.packets_tso_non_tunnel + self.packets_tso_tunnel,
+            packet_interval=TX_INTERVAL,
+            packet_mtu=TSO_MTU,
+            segment_length=TSO_SEGMENT_LENGTH,
+            support_rx_tunnel=self.support_rx_tunnel,
+            support_seg_non_tunnel=False,
+            support_seg_tunnel=True,
+            support_tso=True,
+            support_ufo=True,
         )
-        self.tester.send_expect("ip l set %s up" % tx_interface, "# ")
 
-        if self.nic in ["cavium_a063", "cavium_a064"]:
-            cmd = (
-                "%s %s -- -i --rxd=512 --txd=512 --burst=32 --rxfreet=64 --mbcache=128 --portmask=%s --max-pkt-len=%s --txpt=36 --txht=0 --txwt=0 --txfreet=32 --txrst=32 --tx-offloads=0x8000"
-                % (self.path, self.eal_param, self.portMask, TSO_MTU)
-            )
-        else:
-            cmd = (
-                "%s %s -- -i --rxd=512 --txd=512 --burst=32 --rxfreet=64 --mbcache=128 --portmask=%s --max-pkt-len=%s --txpt=36 --txht=0 --txwt=0 --txfreet=32 --txrst=32 "
-                % (self.path, self.eal_param, self.portMask, TSO_MTU)
-            )
-
-        self.dut.send_expect(cmd, "testpmd> ", 120)
-        self.dut.send_expect("set verbose 1", "testpmd> ", 120)
-        self.dut.send_expect("port stop all", "testpmd> ", 120)
-        self.dut.send_expect("csum set ip hw %d" % self.dut_ports[0], "testpmd> ", 120)
-        self.dut.send_expect("csum set udp hw %d" % self.dut_ports[0], "testpmd> ", 120)
-        self.dut.send_expect("csum set tcp hw %d" % self.dut_ports[0], "testpmd> ", 120)
-        if self.nic not in ["cavium_a063", "cavium_a064"]:
-            self.dut.send_expect(
-                "csum set sctp hw %d" % self.dut_ports[0], "testpmd> ", 120
-            )
-            self.dut.send_expect(
-                "csum set outer-ip hw %d" % self.dut_ports[0], "testpmd> ", 120
-            )
-
-        self.dut.send_expect(
-            "csum parse-tunnel on %d" % self.dut_ports[0], "testpmd> ", 120
+    def test_tso_combine(self):
+        offload.execute_test_tso(
+            case=self,
+            testpmd=self.pmdout,
+            tester=self.tester,
+            tester_tx_interface=self.tester_intf[0],
+            tester_rx_interface=self.tester_intf[1],
+            testpmd_port_0=self.dut_pci[0],
+            testpmd_port_1=self.dut_pci[1],
+            testpmd_enable_dcf_0=False,
+            testpmd_enable_dcf_1=False,
+            testpmd_bitwidth=None,
+            testpmd_log_level={"ice": 7, "iavf": 8},
+            testpmd_other_eal_param="",
+            testpmd_param=" --enable-rx-cksum --max-pkt-len=%d " % TSO_MTU,
+            testpmd_commands=[
+                "set verbose 1",
+                "set fwd csum",
+                "csum mac-swap off 0",
+                "csum mac-swap off 1",
+                "set promisc 0 on",
+                "set promisc 1 on",
+                "port stop all",
+                "csum set ip hw 1",
+                "csum set udp hw 1",
+                "csum set tcp hw 1",
+                "csum set sctp hw 1",
+                "csum set outer-ip hw 1",
+                "csum set outer-udp hw 1",
+                "csum parse-tunnel on 1",
+                "rx_vxlan_port add 4789 0",
+                "tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "tunnel_tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "port start all",
+            ],
+            packets=self.packets_tso_non_tunnel + self.packets_tso_tunnel,
+            packet_interval=TX_INTERVAL,
+            packet_mtu=TSO_MTU,
+            segment_length=TSO_SEGMENT_LENGTH,
+            support_rx_tunnel=self.support_rx_tunnel,
+            support_seg_non_tunnel=True,
+            support_seg_tunnel=True,
+            support_tso=True,
+            support_ufo=True,
         )
 
-        self.dut.send_expect("tso set 800 %d" % self.dut_ports[1], "testpmd> ", 120)
-        self.dut.send_expect("set fwd csum", "testpmd> ", 120)
-        self.dut.send_expect("port start all", "testpmd> ", 120)
-        self.dut.send_expect("set promisc all off", "testpmd> ", 120)
-        self.dut.send_expect("start", "testpmd> ")
-
-        self.tester.scapy_foreground()
-        time.sleep(5)
-
-        for loading_size in self.loading_sizes:
-            # IPv4 tcp test
-            self.tcpdump_start_sniffing([tx_interface, rx_interface])
-            out = self.dut.send_expect("clear port stats all", "testpmd> ", 120)
-            self.tester.scapy_append(
-                'sendp([Ether(dst="%s",src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2")/TCP(sport=1021,dport=1021)/("X"*%s)], iface="%s")'
-                % (mac, loading_size, tx_interface)
-            )
-            out = self.tester.scapy_execute()
-            out = self.dut.send_expect("show port stats all", "testpmd> ", 120)
-            print(out)
-            self.tcpdump_stop_sniff()
-            rx_stats = self.number_of_packets(rx_interface)
-            tx_stats = self.number_of_packets(tx_interface)
-            tx_outlist = self.number_of_bytes(rx_interface)
-            self.logger.info(tx_outlist)
-            if loading_size <= 800:
-                self.verify(
-                    rx_stats == tx_stats and int(tx_outlist[0]) == loading_size,
-                    "IPV6 RX or TX packet number not correct",
-                )
-            else:
-                num = int(loading_size / 800)
-                for i in range(num):
-                    self.verify(
-                        int(tx_outlist[i]) == 800,
-                        "the packet segmentation incorrect, %s" % tx_outlist,
-                    )
-                if loading_size % 800 != 0:
-                    self.verify(
-                        int(tx_outlist[num]) == loading_size % 800,
-                        "the packet segmentation incorrect, %s" % tx_outlist,
-                    )
-
-        for loading_size in self.loading_sizes:
-            # IPv6 tcp test
-            self.tcpdump_start_sniffing([tx_interface, rx_interface])
-            out = self.dut.send_expect("clear port stats all", "testpmd> ", 120)
-            self.tester.scapy_append(
-                'sendp([Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="FE80:0:0:0:200:1FF:FE00:200", dst="3555:5555:6666:6666:7777:7777:8888:8888")/TCP(sport=1021,dport=1021)/("X"*%s)], iface="%s")'
-                % (mac, loading_size, tx_interface)
-            )
-            out = self.tester.scapy_execute()
-            out = self.dut.send_expect("show port stats all", "testpmd> ", 120)
-            print(out)
-            self.tcpdump_stop_sniff()
-            rx_stats = self.number_of_packets(rx_interface)
-            tx_stats = self.number_of_packets(tx_interface)
-            tx_outlist = self.number_of_bytes(rx_interface)
-            self.logger.info(tx_outlist)
-            if loading_size <= 800:
-                self.verify(
-                    rx_stats == tx_stats and int(tx_outlist[0]) == loading_size,
-                    "IPV6 RX or TX packet number not correct",
-                )
-            else:
-                num = int(loading_size / 800)
-                for i in range(num):
-                    self.verify(
-                        int(tx_outlist[i]) == 800,
-                        "the packet segmentation incorrect, %s" % tx_outlist,
-                    )
-                if loading_size % 800 != 0:
-                    self.verify(
-                        int(tx_outlist[num]) == loading_size % 800,
-                        "the packet segmentation incorrect, %s" % tx_outlist,
-                    )
-
-    def test_tso_tunneling(self):
-        """
-        TSO tunneling, VXLan testing, Nvgre testing
-        """
-        tx_interface = self.tester.get_interface(
-            self.tester.get_local_port(self.dut_ports[0])
-        )
-        rx_interface = self.tester.get_interface(
-            self.tester.get_local_port(self.dut_ports[1])
-        )
-
-        Nic_list = [
+    @skip_unsupported_nic(
+        [
             "I40E_10G-SFP_X710",
             "I40E_40G-QSFP_A",
             "I40E_40G-QSFP_B",
@@ -310,149 +593,246 @@ class TestTSO(TestCase):
             "I40E_10G-SFP_X722",
             "I40E_10G-10G_BASE_T_X722",
             "I40E_10G-10G_BASE_T_BC",
+            "ICE_100G-E810C_QSFP",
+            "ICE_25G-E810C_SFP",
+            "ICE_25G-E823C_QSFP",
+            "ICE_25G-E810_XXV_SFP",
         ]
-        save_file = "/tmp/save.pcap"
-        dump_pcap = "/tmp/tcpdump_%s.pcap" % rx_interface
-
-        mac = self.dut.get_mac_address(self.dut_ports[0])
-
-        self.tester.send_expect(
-            "ethtool -K %s rx off tx off tso off gso off gro off lro off"
-            % tx_interface,
-            "# ",
+    )
+    def test_tso_vlan_non_tunnel(self):
+        offload.execute_test_tso(
+            case=self,
+            testpmd=self.pmdout,
+            tester=self.tester,
+            tester_tx_interface=self.tester_intf[0],
+            tester_rx_interface=self.tester_intf[1],
+            testpmd_port_0=self.dut_pci[0],
+            testpmd_port_1=self.dut_pci[1],
+            testpmd_enable_dcf_0=False,
+            testpmd_enable_dcf_1=False,
+            testpmd_bitwidth=None,
+            testpmd_log_level={"ice": 7, "iavf": 8},
+            testpmd_other_eal_param="",
+            testpmd_param=" --enable-rx-cksum --max-pkt-len=%d " % TSO_MTU,
+            testpmd_commands=[
+                "set verbose 1",
+                "set fwd csum",
+                "csum mac-swap off 0",
+                "csum mac-swap off 1",
+                "set promisc 0 on",
+                "set promisc 1 on",
+                "port stop all",
+                "csum set ip hw 1",
+                "csum set udp hw 1",
+                "csum set tcp hw 1",
+                "csum set sctp hw 1",
+                "csum set outer-ip hw 1",
+                "csum set outer-udp hw 1",
+                "csum parse-tunnel on 1",
+                "rx_vxlan_port add 4789 0",
+                "tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "vlan set filter on 0",
+                "port start all",
+                "rx_vlan add 100 0",
+            ],
+            packets=TSO_VLAN_NON_TUNNEL_PACKETS
+            + UFO_VLAN_NON_TUNNEL_PACKETS
+            + TSO_VLAN_TUNNEL_PACKETS
+            + UFO_VLAN_TUNNEL_PACKETS,
+            packet_interval=TX_INTERVAL,
+            packet_mtu=TSO_MTU,
+            segment_length=TSO_SEGMENT_LENGTH,
+            support_rx_tunnel=self.support_rx_tunnel,
+            support_seg_non_tunnel=True,
+            support_seg_tunnel=False,
+            support_tso=True,
+            support_ufo=True,
         )
-        self.tester.send_expect("ip l set %s up" % tx_interface, "# ")
 
-        cmd = (
-            "%s %s -- -i --rxd=512 --txd=512 --burst=32 --rxfreet=64 --mbcache=128 --portmask=%s --max-pkt-len=%s --txpt=36 --txht=0 --txwt=0 --txfreet=32 --txrst=32 "
-            % (self.path, self.eal_param, self.portMask, TSO_MTU)
-        )
-        self.dut.send_expect(cmd, "testpmd> ", 120)
-        self.dut.send_expect("set verbose 1", "testpmd> ", 120)
-        self.dut.send_expect("port stop all", "testpmd> ", 120)
-        self.dut.send_expect("csum set ip hw %d" % self.dut_ports[0], "testpmd> ", 120)
-        self.dut.send_expect("csum set udp hw %d" % self.dut_ports[0], "testpmd> ", 120)
-        self.dut.send_expect("csum set tcp hw %d" % self.dut_ports[0], "testpmd> ", 120)
-        self.dut.send_expect(
-            "csum set sctp hw %d" % self.dut_ports[0], "testpmd> ", 120
-        )
-        self.dut.send_expect(
-            "csum set outer-ip hw %d" % self.dut_ports[0], "testpmd> ", 120
-        )
-        if self.nic in Nic_list:
-            self.logger.warning(
-                "Warning: Intel® Ethernet 700 Series not support outer udp."
-            )
-        else:
-            self.dut.send_expect(
-                "csum set outer-udp hw %d" % self.dut_ports[0], "testpmd> ", 120
-            )
-        self.dut.send_expect(
-            "csum parse-tunnel on %d" % self.dut_ports[0], "testpmd> ", 120
+    @skip_unsupported_nic(
+        [
+            "I40E_10G-SFP_X710",
+            "I40E_40G-QSFP_A",
+            "I40E_40G-QSFP_B",
+            "I40E_25G-25G_SFP28",
+            "I40E_10G-SFP_X722",
+            "I40E_10G-10G_BASE_T_X722",
+            "I40E_10G-10G_BASE_T_BC",
+            "ICE_100G-E810C_QSFP",
+            "ICE_25G-E810C_SFP",
+            "ICE_25G-E823C_QSFP",
+            "ICE_25G-E810_XXV_SFP",
+        ]
+    )
+    def test_tso_vlan_tunnel(self):
+        offload.execute_test_tso(
+            case=self,
+            testpmd=self.pmdout,
+            tester=self.tester,
+            tester_tx_interface=self.tester_intf[0],
+            tester_rx_interface=self.tester_intf[1],
+            testpmd_port_0=self.dut_pci[0],
+            testpmd_port_1=self.dut_pci[1],
+            testpmd_enable_dcf_0=False,
+            testpmd_enable_dcf_1=False,
+            testpmd_bitwidth=None,
+            testpmd_log_level={"ice": 7, "iavf": 8},
+            testpmd_other_eal_param="",
+            testpmd_param=" --enable-rx-cksum --max-pkt-len=%d " % TSO_MTU,
+            testpmd_commands=[
+                "set verbose 1",
+                "set fwd csum",
+                "csum mac-swap off 0",
+                "csum mac-swap off 1",
+                "set promisc 0 on",
+                "set promisc 1 on",
+                "port stop all",
+                "csum set ip hw 1",
+                "csum set udp hw 1",
+                "csum set tcp hw 1",
+                "csum set sctp hw 1",
+                "csum set outer-ip hw 1",
+                "csum set outer-udp hw 1",
+                "csum parse-tunnel on 1",
+                "rx_vxlan_port add 4789 0",
+                "tunnel_tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "vlan set filter on 0",
+                "port start all",
+                "rx_vlan add 100 0",
+            ],
+            packets=TSO_VLAN_NON_TUNNEL_PACKETS
+            + UFO_VLAN_NON_TUNNEL_PACKETS
+            + TSO_VLAN_TUNNEL_PACKETS
+            + UFO_VLAN_TUNNEL_PACKETS,
+            packet_interval=TX_INTERVAL,
+            packet_mtu=TSO_MTU,
+            segment_length=TSO_SEGMENT_LENGTH,
+            support_rx_tunnel=self.support_rx_tunnel,
+            support_seg_non_tunnel=False,
+            support_seg_tunnel=True,
+            support_tso=True,
+            support_ufo=True,
         )
 
-        self.dut.send_expect("csum set ip hw %d" % self.dut_ports[1], "testpmd> ", 120)
-        self.dut.send_expect("csum set udp hw %d" % self.dut_ports[1], "testpmd> ", 120)
-        self.dut.send_expect("csum set tcp hw %d" % self.dut_ports[1], "testpmd> ", 120)
-        self.dut.send_expect(
-            "csum set sctp hw %d" % self.dut_ports[1], "testpmd> ", 120
-        )
-        self.dut.send_expect(
-            "csum set outer-ip hw %d" % self.dut_ports[1], "testpmd> ", 120
-        )
-        if self.nic in Nic_list:
-            self.logger.warning(
-                "Warning: Intel® Ethernet 700 Series not support outer udp."
-            )
-        else:
-            self.dut.send_expect(
-                "csum set outer-udp hw %d" % self.dut_ports[1], "testpmd> ", 120
-            )
-        self.dut.send_expect(
-            "csum parse-tunnel on %d" % self.dut_ports[1], "testpmd> ", 120
+    @skip_unsupported_nic(
+        [
+            "I40E_10G-SFP_X710",
+            "I40E_40G-QSFP_A",
+            "I40E_40G-QSFP_B",
+            "I40E_25G-25G_SFP28",
+            "I40E_10G-SFP_X722",
+            "I40E_10G-10G_BASE_T_X722",
+            "I40E_10G-10G_BASE_T_BC",
+            "ICE_100G-E810C_QSFP",
+            "ICE_25G-E810C_SFP",
+            "ICE_25G-E823C_QSFP",
+            "ICE_25G-E810_XXV_SFP",
+        ]
+    )
+    def test_tso_vlan_combine(self):
+        offload.execute_test_tso(
+            case=self,
+            testpmd=self.pmdout,
+            tester=self.tester,
+            tester_tx_interface=self.tester_intf[0],
+            tester_rx_interface=self.tester_intf[1],
+            testpmd_port_0=self.dut_pci[0],
+            testpmd_port_1=self.dut_pci[1],
+            testpmd_enable_dcf_0=False,
+            testpmd_enable_dcf_1=False,
+            testpmd_bitwidth=None,
+            testpmd_log_level={"ice": 7, "iavf": 8},
+            testpmd_other_eal_param="",
+            testpmd_param=" --enable-rx-cksum --max-pkt-len=%d " % TSO_MTU,
+            testpmd_commands=[
+                "set verbose 1",
+                "set fwd csum",
+                "csum mac-swap off 0",
+                "csum mac-swap off 1",
+                "set promisc 0 on",
+                "set promisc 1 on",
+                "port stop all",
+                "csum set ip hw 1",
+                "csum set udp hw 1",
+                "csum set tcp hw 1",
+                "csum set sctp hw 1",
+                "csum set outer-ip hw 1",
+                "csum set outer-udp hw 1",
+                "csum parse-tunnel on 1",
+                "rx_vxlan_port add 4789 0",
+                "tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "tunnel_tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "vlan set filter on 0",
+                "port start all",
+                "rx_vlan add 100 0",
+            ],
+            packets=TSO_VLAN_NON_TUNNEL_PACKETS
+            + UFO_VLAN_NON_TUNNEL_PACKETS
+            + TSO_VLAN_TUNNEL_PACKETS
+            + UFO_VLAN_TUNNEL_PACKETS,
+            packet_interval=TX_INTERVAL,
+            packet_mtu=TSO_MTU,
+            segment_length=TSO_SEGMENT_LENGTH,
+            support_rx_tunnel=self.support_rx_tunnel,
+            support_seg_non_tunnel=True,
+            support_seg_tunnel=True,
+            support_tso=True,
+            support_ufo=True,
         )
 
-        self.dut.send_expect(
-            "tunnel_tso set 800 %d" % self.dut_ports[1], "testpmd> ", 120
+    @check_supported_nic(
+        [
+            "ICE_100G-E810C_QSFP",
+            "ICE_25G-E810C_SFP",
+            "ICE_25G-E823C_QSFP",
+            "ICE_25G-E810_XXV_SFP",
+        ]
+    )
+    def test_tso_combine_avx512(self):
+        offload.execute_test_tso(
+            case=self,
+            testpmd=self.pmdout,
+            tester=self.tester,
+            tester_tx_interface=self.tester_intf[0],
+            tester_rx_interface=self.tester_intf[1],
+            testpmd_port_0=self.dut_pci[0],
+            testpmd_port_1=self.dut_pci[1],
+            testpmd_enable_dcf_0=False,
+            testpmd_enable_dcf_1=False,
+            testpmd_bitwidth=512,
+            testpmd_log_level={"ice": 7, "iavf": 8},
+            testpmd_other_eal_param="",
+            testpmd_param=" --enable-rx-cksum --max-pkt-len=%d " % TSO_MTU,
+            testpmd_commands=[
+                "set verbose 1",
+                "set fwd csum",
+                "csum mac-swap off 0",
+                "csum mac-swap off 1",
+                "set promisc 0 on",
+                "set promisc 1 on",
+                "port stop all",
+                "csum set ip hw 1",
+                "csum set udp hw 1",
+                "csum set tcp hw 1",
+                "csum set sctp hw 1",
+                "csum set outer-ip hw 1",
+                "csum set outer-udp hw 1",
+                "csum parse-tunnel on 1",
+                "rx_vxlan_port add 4789 0",
+                "tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "tunnel_tso set %d 1" % TSO_SEGMENT_LENGTH,
+                "port start all",
+            ],
+            packets=self.packets_tso_non_tunnel + self.packets_tso_tunnel,
+            packet_interval=TX_INTERVAL,
+            packet_mtu=TSO_MTU,
+            segment_length=TSO_SEGMENT_LENGTH,
+            support_rx_tunnel=self.support_rx_tunnel,
+            support_seg_non_tunnel=True,
+            support_seg_tunnel=True,
+            support_tso=True,
+            support_ufo=True,
         )
-        self.dut.send_expect("rx_vxlan_port add 4789 0", "testpmd> ", 120)
-        self.dut.send_expect("set fwd csum", "testpmd> ", 120)
-        self.dut.send_expect("port start all", "testpmd> ", 120)
-        self.dut.send_expect("set promisc all off", "testpmd> ", 120)
-        self.dut.send_expect("start", "testpmd> ")
-
-        self.tester.scapy_foreground()
-        time.sleep(5)
-
-        for loading_size in self.loading_sizes:
-            # Vxlan test
-            self.tcpdump_start_sniffing([tx_interface, rx_interface])
-            out = self.dut.send_expect("clear port stats all", "testpmd> ", 120)
-            self.tester.scapy_append(
-                'sendp([Ether(dst="%s",src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2")/UDP(sport=1021,dport=4789)/VXLAN()/Ether(dst="%s",src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2")/TCP(sport=1021,dport=1021)/("X"*%s)], iface="%s")'
-                % (mac, mac, loading_size, tx_interface)
-            )
-            out = self.tester.scapy_execute()
-            out = self.dut.send_expect("show port stats all", "testpmd> ", 120)
-            print(out)
-            self.tcpdump_stop_sniff()
-            rx_stats = self.number_of_packets(rx_interface)
-            tx_stats = self.number_of_packets(tx_interface)
-            tx_outlist = self.number_of_bytes(rx_interface)
-            self.logger.info(tx_outlist)
-            if loading_size <= 800:
-                self.verify(
-                    rx_stats == tx_stats and int(tx_outlist[0]) == loading_size,
-                    "Vxlan RX or TX packet number not correct",
-                )
-            else:
-                num = int(loading_size / 800)
-                for i in range(num):
-                    self.verify(
-                        int(tx_outlist[i]) == 800,
-                        "the packet segmentation incorrect, %s" % tx_outlist,
-                    )
-                if loading_size % 800 != 0:
-                    self.verify(
-                        int(tx_outlist[num]) == loading_size % 800,
-                        "the packet segmentation incorrect, %s" % tx_outlist,
-                    )
-            self.get_chksum_value_and_verify(dump_pcap, Nic_list)
-
-        for loading_size in self.loading_sizes:
-            # Nvgre test
-            self.tcpdump_start_sniffing([tx_interface, rx_interface])
-            out = self.dut.send_expect("clear port stats all", "testpmd> ", 120)
-            self.tester.scapy_append(
-                'sendp([Ether(dst="%s",src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2",proto=47)/GRE(key_present=1,proto=0x6558,key=0x00001000)/Ether(dst="%s",src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2")/TCP(sport=1021,dport=1021)/("X"*%s)], iface="%s")'
-                % (mac, mac, loading_size, tx_interface)
-            )
-            out = self.tester.scapy_execute()
-            out = self.dut.send_expect("show port stats all", "testpmd> ", 120)
-            print(out)
-            self.tcpdump_stop_sniff()
-            rx_stats = self.number_of_packets(rx_interface)
-            tx_stats = self.number_of_packets(tx_interface)
-            tx_outlist = self.number_of_bytes(rx_interface)
-            self.logger.info(tx_outlist)
-            if loading_size <= 800:
-                self.verify(
-                    rx_stats == tx_stats and int(tx_outlist[0]) == loading_size,
-                    "Nvgre RX or TX packet number not correct",
-                )
-            else:
-                num = int(loading_size / 800)
-                for i in range(num):
-                    self.verify(
-                        int(tx_outlist[i]) == 800,
-                        "the packet segmentation incorrect, %s" % tx_outlist,
-                    )
-                if loading_size % 800 != 0:
-                    self.verify(
-                        int(tx_outlist[num]) == loading_size % 800,
-                        "the packet segmentation incorrect, %s" % tx_outlist,
-                    )
-            self.get_chksum_value_and_verify(dump_pcap, Nic_list)
 
     def test_perf_TSO_2ports(self):
         """
