get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/75209/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 75209,
    "url": "http://patchwork.dpdk.org/api/patches/75209/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dts/patch/20200805135231.1579592-1-ohilyard@iol.unh.edu/",
    "project": {
        "id": 3,
        "url": "http://patchwork.dpdk.org/api/projects/3/?format=api",
        "name": "DTS",
        "link_name": "dts",
        "list_id": "dts.dpdk.org",
        "list_email": "dts@dpdk.org",
        "web_url": "",
        "scm_url": "git://dpdk.org/tools/dts",
        "webscm_url": "http://git.dpdk.org/tools/dts/",
        "list_archive_url": "https://inbox.dpdk.org/dts",
        "list_archive_url_format": "https://inbox.dpdk.org/dts/{}",
        "commit_url_format": ""
    },
    "msgid": "<20200805135231.1579592-1-ohilyard@iol.unh.edu>",
    "list_archive_url": "https://inbox.dpdk.org/dts/20200805135231.1579592-1-ohilyard@iol.unh.edu",
    "date": "2020-08-05T13:52:30",
    "name": "linux kernel modules: add tests",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "33e628a150beeb7d9e2f2d121dcd8afea23a4e41",
    "submitter": {
        "id": 1829,
        "url": "http://patchwork.dpdk.org/api/people/1829/?format=api",
        "name": "Owen Hilyard",
        "email": "ohilyard@iol.unh.edu"
    },
    "delegate": null,
    "mbox": "http://patchwork.dpdk.org/project/dts/patch/20200805135231.1579592-1-ohilyard@iol.unh.edu/mbox/",
    "series": [
        {
            "id": 11504,
            "url": "http://patchwork.dpdk.org/api/series/11504/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dts/list/?series=11504",
            "date": "2020-08-05T13:52:30",
            "name": "linux kernel modules: add tests",
            "version": 1,
            "mbox": "http://patchwork.dpdk.org/series/11504/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/75209/comments/",
    "check": "pending",
    "checks": "http://patchwork.dpdk.org/api/patches/75209/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dts-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 87ADFA053A;\n\tWed,  5 Aug 2020 15:52:44 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 41CD71B203;\n\tWed,  5 Aug 2020 15:52:44 +0200 (CEST)",
            "from mail-lj1-f193.google.com (mail-lj1-f193.google.com\n [209.85.208.193]) by dpdk.org (Postfix) with ESMTP id 636C72C28\n for <dts@dpdk.org>; Wed,  5 Aug 2020 15:52:43 +0200 (CEST)",
            "by mail-lj1-f193.google.com with SMTP id t23so24259746ljc.3\n for <dts@dpdk.org>; Wed, 05 Aug 2020 06:52:43 -0700 (PDT)",
            "from ohilyard-Alienware-m17.iol.unh.edu\n ([2606:4100:3880:1254::1033])\n by smtp.gmail.com with ESMTPSA id t18sm1136103lfb.69.2020.08.05.06.52.38\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Wed, 05 Aug 2020 06:52:40 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu;\n s=unh-iol;\n h=from:to:cc:subject:date:message-id:mime-version\n :content-transfer-encoding;\n bh=5dRKQykwgxamftlQRJCSfBRMeUqA97Pz/Vp9wJIDfik=;\n b=QxHOfmIlq6/JgjVNKnV3YG+Mv+SSGfcPJRStWFB/tOe99EYs5fAXZouKscpnVUSyUq\n IdSSTfdOtg0b8xTWOMRLQ7boY/tA1eq5JgVk7ybxifx+WUO3o3mSEFlfhIhfm4GFIgbn\n S5VCQu1a3j9DKp+VgcI+I88fZ3mRjVUIxZAIg=",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20161025;\n h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version\n :content-transfer-encoding;\n bh=5dRKQykwgxamftlQRJCSfBRMeUqA97Pz/Vp9wJIDfik=;\n b=Co2fK2jq++jPdeSRP36wlsaOCIzEWv/ox3KRvMTBL5CDdN4AVdCA9ZqmXUx1tjRZ/D\n LtcOzQR7weyPCl89TmclD8RuYfgTI8MwK3tfoUiABFE8JCyVp/C2wUDxswDfoRWGAosn\n QRq0J1RCv9kDJe5HaQC1s1MaqSZDz+ZOmaSKpJttHAvvLGqAZbIZiEUfOAijub7DlVEw\n OQe12EYhLCYe+P9QI7eZ+dgUlp23BXCSdtPVtOU4BNZ+54rR6ZGpkuEPqOXy9vuXm7+Q\n NT8HEuohomKW7pOJbnpFk5hDU1JikYSZiTvmXITTvzCsZWkkbdEKlrnu7On02cy9dx08\n vj+Q==",
        "X-Gm-Message-State": "AOAM53219VJwl6JwuaZadwDP3jKoq1ZkuyWxlSzsVQRmVJub6DH29uGh\n NET/8UPVtUqFVIqqhLnxJPPGgWv0whggMwX+Ilo4/MULWBbgqfpFjfctdegtNcSef0H/3pcFS6q\n Uo19grqZtuEM6qeD7bjTN8M4fA0eLY+xPcf0re9rt6Vc5AH/YnioEeHt7JA==",
        "X-Google-Smtp-Source": "\n ABdhPJwOhGvsalkHga4rqrE5fjYHgnB/8nyYl4edzrlkGdXLFaGpGv28Jqu8WSpYS9+pGwxaL3Nokw==",
        "X-Received": "by 2002:a2e:8e28:: with SMTP id r8mr1381422ljk.290.1596635561371;\n Wed, 05 Aug 2020 06:52:41 -0700 (PDT)",
        "From": "Owen Hilyard <ohilyard@iol.unh.edu>",
        "To": "dts@dpdk.org",
        "Cc": "nhorman@tuxdriver.com, jerinj@marvell.com, skori@marvell.com,\n anatoly.burakov@intel.com, ferruh.yigit@intel.com, lijuan.tu@intel.com,\n lylavoie@iol.unh.edu, Owen Hilyard <ohilyard@iol.unh.edu>",
        "Date": "Wed,  5 Aug 2020 09:52:30 -0400",
        "Message-Id": "<20200805135231.1579592-1-ohilyard@iol.unh.edu>",
        "X-Mailer": "git-send-email 2.25.1",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UFT-8",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dts] [PATCH] linux kernel modules: add tests",
        "X-BeenThere": "dts@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "test suite reviews and discussions <dts.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dts>,\n <mailto:dts-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dts/>",
        "List-Post": "<mailto:dts@dpdk.org>",
        "List-Help": "<mailto:dts-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dts>,\n <mailto:dts-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dts-bounces@dpdk.org",
        "Sender": "\"dts\" <dts-bounces@dpdk.org>"
    },
    "content": "add vfio-pci test suite\nadd igb_uio test suite\nadd uio_pci_generic test suite\nadd test suite documentation\nadd new setting UNPRIVILEGED_USERNAME\nadd check for file existence when getting dpdk pids\n        dpdk processes run in memory will not create the expected files\nadd return to DPDKdut.bind_interfaces_linux to allow for error checking\n\nSigned-off-by: Owen Hilyard <ohilyard@iol.unh.edu>\n---\n framework/crb.py                       |  40 +++---\n framework/project_dpdk.py              |   2 +-\n framework/settings.py                  |   2 +\n test_plans/linux_modules_test_plan.rst | 158 ++++++++++++++++++++++\n tests/TestSuite_linux_modules.py       | 173 +++++++++++++++++++++++++\n 5 files changed, 356 insertions(+), 19 deletions(-)\n create mode 100644 test_plans/linux_modules_test_plan.rst\n create mode 100644 tests/TestSuite_linux_modules.py",
    "diff": "diff --git a/framework/crb.py b/framework/crb.py\nindex a47de2c..d456fab 100644\n--- a/framework/crb.py\n+++ b/framework/crb.py\n@@ -499,27 +499,31 @@ class Crb(object):\n         pids = []\n         pid_reg = r'p(\\d+)'\n         for config_file in file_directorys:\n-            cmd = 'lsof -Fp %s' % config_file\n-            out = self.send_expect(cmd, \"# \", 20, alt_session)\n-            if len(out):\n-                lines = out.split('\\r\\n')\n-                for line in lines:\n-                    m = re.match(pid_reg, line)\n-                    if m:\n-                        pids.append(m.group(1))\n-            for pid in pids:\n-                self.send_expect('kill -9 %s' % pid, '# ', 20, alt_session)\n-                self.get_session_output(timeout=2)\n+            # Covers case where the process is run as a unprivileged user and does not generate the file\n+            if os.path.isfile(config_file):\n+                cmd = 'lsof -Fp %s' % config_file\n+                out = self.send_expect(cmd, \"# \", 20, alt_session)\n+                if len(out):\n+                    lines = out.split('\\r\\n')\n+                    for line in lines:\n+                        m = re.match(pid_reg, line)\n+                        if m:\n+                            pids.append(m.group(1))\n+                for pid in pids:\n+                    self.send_expect('kill -9 %s' % pid, '# ', 20, alt_session)\n+                    self.get_session_output(timeout=2)\n \n         hugepage_info = ['/var/run/dpdk/%s/hugepage_info' % file_prefix for file_prefix in prefix_list]\n         for hugepage in hugepage_info:\n-            cmd = 'lsof -Fp %s' % hugepage\n-            out = self.send_expect(cmd, \"# \", 20, alt_session)\n-            if len(out) and \"No such file or directory\" not in out:\n-                self.logger.warning(\"There are some dpdk process not free hugepage\")\n-                self.logger.warning(\"**************************************\")\n-                self.logger.warning(out)\n-                self.logger.warning(\"**************************************\")\n+            # Covers case where the process is run as a unprivileged user and does not generate the file\n+            if os.path.isfile(hugepage):\n+                cmd = 'lsof -Fp %s' % hugepage\n+                out = self.send_expect(cmd, \"# \", 20, alt_session)\n+                if len(out) and \"No such file or directory\" not in out:\n+                    self.logger.warning(\"There are some dpdk process not free hugepage\")\n+                    self.logger.warning(\"**************************************\")\n+                    self.logger.warning(out)\n+                    self.logger.warning(\"**************************************\")\n \n         # remove directory\n         directorys = ['/var/run/dpdk/%s' % file_prefix for file_prefix in prefix_list]\ndiff --git a/framework/project_dpdk.py b/framework/project_dpdk.py\nindex 040d070..03ace46 100644\n--- a/framework/project_dpdk.py\n+++ b/framework/project_dpdk.py\n@@ -434,7 +434,7 @@ class DPDKdut(Dut):\n             current_nic += 1\n \n         bind_script_path = self.get_dpdk_bind_script()\n-        self.send_expect('%s --force %s' % (bind_script_path, binding_list), '# ')\n+        return self.send_expect('%s --force %s' % (bind_script_path, binding_list), '# ')\n \n     def unbind_interfaces_linux(self, nics_to_bind=None):\n         \"\"\"\ndiff --git a/framework/settings.py b/framework/settings.py\nindex f91452d..850fa89 100644\n--- a/framework/settings.py\n+++ b/framework/settings.py\n@@ -197,6 +197,8 @@ SCAPY2IXIA = [\n \n USERNAME = 'root'\n \n+# A user used to test functionality for a non-root user\n+UNPRIVILEGED_USERNAME = 'dtsunprivilegedtester'\n \n \"\"\"\n Helpful header sizes.\ndiff --git a/test_plans/linux_modules_test_plan.rst b/test_plans/linux_modules_test_plan.rst\nnew file mode 100644\nindex 0000000..c7bb2d0\n--- /dev/null\n+++ b/test_plans/linux_modules_test_plan.rst\n@@ -0,0 +1,158 @@\n+.. # BSD LICENSE\n+    #\n+    # Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+    # Copyright © 2018[, 2019] The University of New Hampshire. All rights reserved.\n+    # All rights reserved.\n+    #\n+    # Redistribution and use in source and binary forms, with or without\n+    # modification, are permitted provided that the following conditions\n+    # are met:\n+    #\n+    #   * Redistributions of source code must retain the above copyright\n+    #     notice, this list of conditions and the following disclaimer.\n+    #   * Redistributions in binary form must reproduce the above copyright\n+    #     notice, this list of conditions and the following disclaimer in\n+    #     the documentation and/or other materials provided with the\n+    #     distribution.\n+    #   * Neither the name of Intel Corporation nor the names of its\n+    #     contributors may be used to endorse or promote products derived\n+    #     from this software without specific prior written permission.\n+    #\n+    # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+    # \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+    # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+    # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+    # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+    # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+    # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+    # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+    # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+    # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+    # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+\n+==================\n+Linux Driver Tests\n+==================\n+\n+This file contains multiple test suites to avoid a single unsupported\n+kernel module causing the entire test suite to fail. These test suites\n+cover a variety of kernel modules and are built to check their function\n+both in use as root and as an unprivileged user. All of the test suites\n+run the same tests. In the documentation for test cases, <MODULE> will\n+represent the name of the module being tested. <DEV INTERFACE> will\n+represent the character interface under /dev/ for the interface.\n+\n+Prerequisites\n+=============\n+\n+There are two prerequisites. First, all of the drivers that you wish\n+to test must be compiled and installed so that they are available through\n+modprobe. Secondly, there should be a user on the dut which has the same\n+password as the primary account for dts. This account will be used as the\n+unprivileged user, but it still should have permission to lock at least\n+1 GiB of memory to ensure that it can lock all of the process memory.\n+\n+Test Suites\n+===========\n+\n+There is 1 test suite per module, the modules are as follows:\n+\n+    * VFIO-PCI\n+    * UIO PCI GENERIC\n+    * IGB UIO\n+\n+Test Case: TX RX\n+====================\n+This test case runs as root and is designed to check the basic functioning\n+of the module. It checks whether packets can be sent and received.\n+\n+Remove old module ::\n+\n+    # rmmod <MODULE>\n+\n+Add the new one ::\n+\n+    # modprobe <MODULE>\n+\n+Bind the interface to the driver ::\n+\n+    # usertools/dpdk-devbind.py --force --bind=<MODULE> xxxx:xx:xx.x\n+\n+Start testpmd in a loop configuration ::\n+\n+    # x86_64-native-linux-gcc/app/testpmd  -l 1,2 -n 4 -w xxxx:xx:xx.x \\\n+       -- -i --port-topology=loop\n+\n+Start packet forwarding ::\n+\n+    testpmd> start\n+\n+Start a packet capture on the tester::\n+\n+    # tcpdump -i (interface) ether src (tester mac address)\n+\n+Send some packets to the dut and check that they are properly sent back into\n+the packet capture on the tester.\n+\n+Test Case: TX RX Userspace\n+====================\n+This test case runs as the unprivileged user and is designed to check the\n+basic functioning of the module. It checks whether packets can be sent\n+and received when running dpdk applications as a normal user. # means\n+that a command is run as root. $ means that a command is run as the user.\n+The igb_uio module requires that the iova mode is in virtual address mode,\n+which can be done by adding the flag \"--iova-mode va\" as an eal option to\n+testpmd.\n+\n+Remove old module ::\n+\n+    # rmmod <MODULE>\n+\n+Add the new one ::\n+\n+    # modprobe <MODULE>\n+\n+Bind the interface to the driver ::\n+\n+    # usertools/dpdk-devbind.py --force --bind=<MODULE> xxxx:xx:xx.x\n+\n+Grant permissions for all users to access the new character device ::\n+\n+    # setfacl -m u:dtsunprivilegedtester:rwx <DEV INTERFACE>\n+\n+Start testpmd in a loop configuration ::\n+\n+    $ x86_64-native-linux-gcc/app/testpmd  -l 1,2 -n 4 -w xxxx:xx:xx.x --in-memory \\\n+       -- -i --port-topology=loop\n+\n+Start packet forwarding ::\n+\n+    testpmd> start\n+\n+Start a packet capture on the tester::\n+\n+    # tcpdump -i (interface) ether src (tester mac address)\n+\n+Send some packets to the dut and check that they are properly sent back into\n+the packet capture on the tester.\n+\n+Test Case: Hello World\n+====================\n+This is a more basic test of functionality as a normal user than the\n+TX RX Userspace case. It simply involves running a short, hello-world-like\n+program on each core before shutting down. # means that a command is run\n+as root. $ means that a command is run as the user. The igb_uio module\n+requires that the iova mode is in virtual address mode, which can be done\n+by adding the flag \"--iova-mode va\" as an eal option to the hello world\n+application.\n+\n+Compile the application ::\n+\n+    # cd $RTE_SDK/examples/helloworld && make\n+\n+Run the application ::\n+\n+    $ $RTE_SDK/examples/helloworld/build/helloworld-shared --in-memory\n+\n+Check for any error states or reported errors.\n+\ndiff --git a/tests/TestSuite_linux_modules.py b/tests/TestSuite_linux_modules.py\nnew file mode 100644\nindex 0000000..7cb479d\n--- /dev/null\n+++ b/tests/TestSuite_linux_modules.py\n@@ -0,0 +1,173 @@\n+# BSD LICENSE\n+#\n+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+# Copyright © 2018[, 2019] The University of New Hampshire. All rights reserved.\n+# All rights reserved.\n+#\n+# Redistribution and use in source and binary forms, with or without\n+# modification, are permitted provided that the following conditions\n+# are met:\n+#\n+#   * Redistributions of source code must retain the above copyright\n+#     notice, this list of conditions and the following disclaimer.\n+#   * Redistributions in binary form must reproduce the above copyright\n+#     notice, this list of conditions and the following disclaimer in\n+#     the documentation and/or other materials provided with the\n+#     distribution.\n+#   * Neither the name of Intel Corporation nor the names of its\n+#     contributors may be used to endorse or promote products derived\n+#     from this software without specific prior written permission.\n+#\n+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+\n+\"\"\"\n+DPDK Test suite.\n+Linux Kernel Modules example.\n+\"\"\"\n+import os\n+import time\n+\n+from pmd_output import PmdOutput\n+from test_case import TestCase\n+\n+from framework import settings\n+\n+ETHER_HEADER_LEN = 18\n+IP_HEADER_LEN = 20\n+ETHER_STANDARD_MTU = 1518\n+ETHER_JUMBO_FRAME_MTU = 9000\n+\n+\n+# A class like this is used because doing inheritance normally breaks the test case discovery process\n+class LinuxModulesHelperMethods:\n+    driver: str\n+    dev_interface: str\n+    additional_eal_options: str\n+\n+    def set_up_all(self):\n+        \"\"\"\n+        Prerequisite steps for each test suit.\n+        \"\"\"\n+        self.dut_ports = self.dut.get_ports()\n+        self.pmdout = PmdOutput(self.dut)\n+        pci_address = self.dut.ports_info[self.dut_ports[0]]['pci']\n+        self.old_driver = settings.get_nic_driver(pci_address)\n+        out = self.dut.bind_interfaces_linux(driver=self.driver)\n+        self.verify(\"bind failed\" not in out, f\"Failed to bind {self.driver}\")\n+        self.verify(\"not loaded\" not in out, f\"{self.driver} was not loaded\")\n+\n+    def send_scapy_packet(self, port_id: int, packet: str):\n+        itf = self.tester.get_interface(port_id)\n+\n+        self.tester.scapy_foreground()\n+        self.tester.scapy_append(f'sendp({packet}, iface=\"{itf}\")')\n+        return self.tester.scapy_execute()\n+\n+    def tear_down(self):\n+        self.dut.kill_all()\n+\n+    def run_example_program_in_userspace(self, directory: str, program: str):\n+        \"\"\"\n+        A function to run a given example program as an unprivileged user.\n+        @param directory: The directory under examples where the app is\n+        @param program: the name of the binary to run\n+        \"\"\"\n+        out: str = self.dut.build_dpdk_apps(f\"$RTE_SDK/examples/{directory}\")\n+        self.verify(\"Error\" not in out, \"Compilation error\")\n+        self.verify(\"No such\" not in out, \"Compilation error\")\n+\n+        program_build_location = f\"$RTE_SDK/examples/{directory}/build/{program}\"\n+        program_user_location = f\"/tmp/dut/bin/{program}\"\n+\n+        self.dut.send_expect(f\"chmod +x {program_build_location}\", \"# \")\n+        self.dut.send_expect(\"mkdir -p /tmp/dut/bin/\", \"# \")\n+        user_home_dir = self.dut.send_expect(f\"cp {program_build_location} {program_user_location}\", \"# \")\n+\n+        self.dut.alt_session.send_expect(f\"su {settings.UNPRIVILEGED_USERNAME}\", \"# \")\n+        self.dut.alt_session.send_expect(f\"{program_user_location} --in-memory {self.additional_eal_options}\", \"# \")\n+        out: str = self.dut.alt_session.send_expect(\"echo $?\", \"# \")\n+        self.dut.alt_session.send_expect(\"exit\", \"# \")  # Return to root session\n+        self.verify(out.strip() == \"0\", f\"{program} exited in an error state\")\n+\n+    def tx_rx_test_helper(self, pmdout, param=\"\", eal_param=\"\"):\n+        pmdout.start_testpmd(\"Default\", param=f\"--port-topology=loop {param}\",\n+                             eal_param=f\"{eal_param} {self.additional_eal_options}\")\n+        pmdout.execute_cmd(\"start\")\n+        dut_mac = self.dut.get_mac_address(self.dut_ports[0])\n+        tester_mac = self.tester.get_mac(self.tester.get_local_port(self.dut_ports[0]))\n+        iface = self.tester.get_interface(self.dut_ports[0])\n+        pcap_path: str = f\"/tmp/tester/test-{self.driver}.pcap\"\n+        self.tester.send_expect(f\"tcpdump -i {iface} -w /tmp/tester/test-{self.driver}.pcap ether src {tester_mac} &\",\n+                                \"# \")\n+        self.tester.send_expect(f\"TCPDUMP_PID=$!\", \"# \")\n+        self.send_scapy_packet(self.dut_ports[0],\n+                               f\"[Ether(dst='{dut_mac}', src='{tester_mac}')/IP()/TCP()/('a') for i in range(20)]\")\n+        time.sleep(.1)\n+        self.tester.send_expect(\"kill -SIGINT $TCPDUMP_PID\", \"# \")\n+        os.system(f\"mkdir -p {settings.FOLDERS['Output']}/tmp/pcap/\")\n+        self.tester.session.copy_file_from(pcap_path, dst=os.path.join(settings.FOLDERS['Output'], \"tmp/pcap/\"))\n+        out: str = self.tester.send_expect(f\"tcpdump -r /tmp/tester/test-{self.driver}.pcap\", \"# \")\n+        self.verify(len(out.splitlines()) >= 20, \"Not all packets were received by the tester.\")\n+        pmdout.quit()\n+\n+    #\n+    #\n+    #\n+    # Test cases.\n+    #\n+\n+    def tear_down_all(self):\n+        \"\"\"\n+        When the case of this test suite finished, the environment should\n+        clear up.\n+        \"\"\"\n+        self.dut.bind_interfaces_linux(driver=self.old_driver)\n+        self.dut.kill_all()\n+\n+    def test_tx_rx(self):\n+        \"\"\"\n+        Preforms the testing that needs to be done as root.\n+        @param driver: The driver to test\n+        \"\"\"\n+        self.tx_rx_test_helper(self.pmdout)\n+\n+    def test_helloworld(self):\n+        self.run_example_program_in_userspace(\"helloworld\", \"helloworld-shared\")\n+\n+    def test_tx_rx_userspace(self):\n+        app_path = self.dut.apps_name['test-pmd']\n+        self.dut.send_expect(f\"chmod +rx {app_path}\", \"#\")\n+        path = self.dut.send_expect(\"pwd\", \"#\")\n+        self.dut.alt_session.send_expect(f\"su {settings.UNPRIVILEGED_USERNAME}\", \"#\")\n+        self.dut.alt_session.send_expect(f\"cd {path}\", \"#\")\n+        self.dut.send_expect(f\"setfacl -m u:{settings.UNPRIVILEGED_USERNAME}:rwx {self.dev_interface}\", \"#\")\n+        self.tx_rx_test_helper(PmdOutput(self.dut, session=self.dut.alt_session), eal_param=\"--in-memory\")\n+        self.dut.alt_session.send_expect(f\"exit\", \"#\")\n+\n+\n+class TestVfio(LinuxModulesHelperMethods, TestCase):\n+    driver = \"vfio-pci\"\n+    dev_interface = \"/dev/vfio/*\"\n+    additional_eal_options = \"\"\n+\n+\n+class TestIgbuio(LinuxModulesHelperMethods, TestCase):\n+    driver = \"igb_uio\"\n+    dev_interface = \"/dev/uio*\"\n+    additional_eal_options = \"--iova-mode va\"\n+\n+\n+class TestUioPciGeneric(LinuxModulesHelperMethods, TestCase):\n+    driver = \"uio_pci_generic\"\n+    dev_interface = \"/dev/uio*\"\n+    additional_eal_options = \"\"\n",
    "prefixes": []
}